Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26f2c2a006 | ||
|
|
72f609f77c | ||
|
|
5f2b17c792 | ||
|
|
075214029e | ||
|
|
bb418632f2 | ||
|
|
833a05129c | ||
|
|
8ab2fc727e | ||
|
|
ea80f4a6f4 | ||
|
|
2d96d9077b | ||
|
|
77fa9c5d21 | ||
|
|
63938d708e |
@@ -8,12 +8,29 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
|
||||
|
||||
## Non publié
|
||||
|
||||
Issue [#169](https://git.botsu.net/koka/sanctuary/issues/169) — catalogue du Shop.
|
||||
Aucun changement non publié.
|
||||
|
||||
## `26.2.0-alpha.244`
|
||||
|
||||
Pull request intégrée : [#176](https://git.botsu.net/koka/sanctuary/pulls/176).
|
||||
|
||||
- ajoute huit feux d’artifice à portraits : ChrisM, Kaninscheun, Poupoutain, lBeast, CreveForest, SacDChips, Vaselline et Duncan ;
|
||||
- dessine pour chacun un visage 8×8 et sa capuche en particules orientées vers le joueur, en taille normale ou agrandie ;
|
||||
- ajoute les huit recettes sans forme, les objets, les textures et les traductions EN/FR/RU correspondantes ;
|
||||
- conserve le feu d’artifice Nourra et son identifiant existant ;
|
||||
- conserve les sauvegardes, les données OnlyFun v2 et le protocole réseau 3 ; OnlyFun passe à `0.0.0-alpha.29`.
|
||||
|
||||
## `26.2.0-alpha.243`
|
||||
|
||||
Pull requests intégrées : [#172](https://git.botsu.net/koka/sanctuary/pulls/172), [#173](https://git.botsu.net/koka/sanctuary/pulls/173) et [#174](https://git.botsu.net/koka/sanctuary/pulls/174).
|
||||
|
||||
- ajoute une barre de recherche dans l’onglet catalogue, avec repli des accents et filtrage local ;
|
||||
- permet de choisir la grille du catalogue : **3×3**, **4×4** ou **5×5** maximum, mémorisée entre les sessions ;
|
||||
- affiche le numéro de page du catalogue (`2/5`) à côté de la navigation ;
|
||||
- conserve la grille 3×3 et les neuf emplacements des ventes flash.
|
||||
- conserve la grille 3×3 et les neuf emplacements des ventes flash ;
|
||||
- resynchronise le texte des panneaux de quêtes après une rotation survenue hors chunk et garantit qu’un rafraîchissement opérateur génère un nouveau contrat ;
|
||||
- ajoute le feu d’artifice Nourra, dont l’explosion dessine le visage et la capuche du skin en particules, en taille normale ou agrandie ;
|
||||
- conserve les sauvegardes et les protocoles réseau existants ; Sanctuary passe à `0.0.0-alpha.140` et OnlyFun à `0.0.0-alpha.28`.
|
||||
|
||||
## `26.2.0-alpha.242`
|
||||
|
||||
|
||||
@@ -22,7 +22,11 @@ Licence : **GNU GPL 3.0 or Later** (`GPL-3.0-or-later`)
|
||||
|
||||
Les descriptions FR/EN/RU sont déclarées dans chaque `fabric.mod.json` et dans les fichiers de langue. Les images fournies servent d'icônes Fabric de leur module.
|
||||
|
||||
Version courante du pack distribué : **`26.2.0-alpha.242`**. Cette release conserve les dix modules Sanctuary, notamment Another World **`0.0.0-alpha.58`**, Sanctuary **`0.0.0-alpha.139`** et Red-Stoner **`0.0.0-alpha.20`**, garde ZEVENT entièrement retiré et met à jour MyDisplay **`1.0.0`** vers le quatrième build fourni, avec WaterMedia **`3.0.0.23`** et WaterMedia Binaries **`3.0.0.6`**.
|
||||
Version courante du pack distribué : **`26.2.0-alpha.244`**. Cette release conserve les dix modules Sanctuary, notamment Another World **`0.0.0-alpha.58`**, Sanctuary **`0.0.0-alpha.140`**, OnlyFun **`0.0.0-alpha.29`** et Red-Stoner **`0.0.0-alpha.20`**, garde ZEVENT entièrement retiré et met à jour MyDisplay **`1.0.0`** vers le quatrième build fourni, avec WaterMedia **`3.0.0.23`** et WaterMedia Binaries **`3.0.0.6`**.
|
||||
|
||||
L’alpha.244 intègre la PR #176. OnlyFun ajoute huit feux d’artifice à portraits pour ChrisM, Kaninscheun, Poupoutain, lBeast, CreveForest, SacDChips, Vaselline et Duncan. Chaque explosion reproduit le visage et la capuche de son skin en particules orientées vers le joueur, en taille normale ou agrandie. Les recettes, objets, textures et traductions EN/FR/RU sont inclus, tandis que Nourra, les sauvegardes et le protocole restent compatibles.
|
||||
|
||||
L’alpha.243 intègre les PR #172, #173 et #174. Le catalogue du Shop gagne une recherche tolérante aux accents, des grilles 3×3, 4×4 et 5×5 mémorisées ainsi qu’un compteur de pages, sans modifier les ventes flash. Les panneaux de quêtes resynchronisent leur texte après une rotation hors chunk et les rafraîchissements opérateur produisent bien un nouveau contrat. OnlyFun ajoute enfin le feu d’artifice Nourra, dont l’explosion dessine le visage et la capuche du skin en particules. Les sauvegardes et protocoles restent compatibles.
|
||||
|
||||
L’alpha.242 remplace le troisième JAR MyDisplay par `mydisplay-1.0.0-sanctuary-4.jar`. Cette révision actualise exclusivement le pipeline client de performance, de session et de lecture WaterMedia, sans changer les blocs, les données ni le protocole réseau. Le manifeste reste compatible avec le serveur dédié, les traductions EN/FR/RU sont alignées, les écrans déjà placés restent compatibles et le nom distinct force Packwiz à retirer le build précédent.
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ masterkey_version=0.0.0-alpha.9
|
||||
masterkey_lifecycle=active
|
||||
iliketomoveit_version=0.0.0-alpha.18
|
||||
iliketomoveit_lifecycle=active
|
||||
onlyfun_version=0.0.0-alpha.27
|
||||
onlyfun_version=0.0.0-alpha.29
|
||||
onlyfun_lifecycle=active
|
||||
sanctuary_version=0.0.0-alpha.139
|
||||
sanctuary_version=0.0.0-alpha.140
|
||||
sanctuary_lifecycle=active
|
||||
pack_version=26.2.0-alpha.242
|
||||
pack_version=26.2.0-alpha.244
|
||||
maven_group=fr.koka99cab.sanctuary26
|
||||
|
||||
@@ -0,0 +1,174 @@
|
||||
from pathlib import Path
|
||||
|
||||
from PIL import Image
|
||||
|
||||
TRANSPARENT = -1
|
||||
PEOPLE = [
|
||||
("chrism", "ChrisM", "red_dye"),
|
||||
("kaninscheun", "Kaninscheun", "yellow_dye"),
|
||||
("poupoutain", "Poupoutain", "light_gray_dye"),
|
||||
("lbeast", "lBeast", "brown_dye"),
|
||||
("creveforest", "CreveForest", "green_dye"),
|
||||
("sacdchips", "SacDChips", "orange_dye"),
|
||||
("vaselline", "Vaselline", "white_dye"),
|
||||
("duncan", "Duncan", "pink_dye"),
|
||||
]
|
||||
ROOT = Path(__file__).resolve().parents[2]
|
||||
|
||||
|
||||
def rgb(pixel):
|
||||
red, green, blue, _alpha = pixel
|
||||
return (red << 16) | (green << 8) | blue
|
||||
|
||||
|
||||
def extract(path):
|
||||
image = Image.open(path).convert("RGBA")
|
||||
face = []
|
||||
hood = []
|
||||
hood_top = []
|
||||
inner_top = []
|
||||
for y in range(8, 16):
|
||||
for x in range(8, 16):
|
||||
face.append(rgb(image.getpixel((x, y))))
|
||||
for y in range(8, 16):
|
||||
for x in range(40, 48):
|
||||
red, green, blue, alpha = image.getpixel((x, y))
|
||||
hood.append(TRANSPARENT if alpha < 128 else (red << 16) | (green << 8) | blue)
|
||||
for y in range(6, 8):
|
||||
for x in range(8, 16):
|
||||
inner_top.append(rgb(image.getpixel((x, y))))
|
||||
for y in range(6, 8):
|
||||
for x in range(40, 48):
|
||||
red, green, blue, alpha = image.getpixel((x, y))
|
||||
if alpha < 128:
|
||||
hood_top.append(inner_top[(y - 6) * 8 + (x - 40)])
|
||||
else:
|
||||
hood_top.append((red << 16) | (green << 8) | blue)
|
||||
return face, hood, hood_top
|
||||
|
||||
|
||||
def fmt(values):
|
||||
lines = []
|
||||
for index in range(0, len(values), 8):
|
||||
chunk = values[index:index + 8]
|
||||
parts = ["-1" if value == TRANSPARENT else f"0x{value:06X}" for value in chunk]
|
||||
comma = "," if index + 8 < len(values) else ""
|
||||
lines.append("\t\t" + ", ".join(parts) + comma)
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
NOURRA_FACE = [
|
||||
0x000000, 0x020202, 0x0A0A0A, 0x111111, 0x111111, 0x0A0A0A, 0x020202, 0x000000,
|
||||
0x020202, 0x0A0A0A, 0x111111, 0x181818, 0x181818, 0x111111, 0x0A0A0A, 0x020202,
|
||||
0x0A0A0A, 0x111111, 0x181818, 0x212121, 0x212121, 0x181818, 0x111111, 0x0A0A0A,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0x111111,
|
||||
0x111111, 0x000000, 0x000000, 0xFFF0E1, 0xFFF0E1, 0x000000, 0x000000, 0x111111,
|
||||
0x0A0A0A, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFFF0E1, 0x4A9DFC, 0xFFFFFF, 0x0A0A0A,
|
||||
0x020202, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFDE8D7, 0x4A9DFC, 0xFFFFFF, 0x020202,
|
||||
0x000000, 0xF0C6A5, 0xF7D5B9, 0xFCE1CA, 0xFCE1CA, 0xF7D5B9, 0xF0C6A5, 0x000000,
|
||||
]
|
||||
NOURRA_HOOD = [
|
||||
0x000000, 0x0D0D0D, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0x0D0D0D, 0x000000,
|
||||
0x0D0D0D, 0x707070, 0xD8D8D8, 0xE5E5E5, 0xE5E5E5, 0xD8D8D8, 0x707070, 0x0D0D0D,
|
||||
0xCBCBCB, 0xD8D8D8, 0xFFFFFF, 0x212121, 0x212121, 0x181818, 0xD8D8D8, 0xCBCBCB,
|
||||
0xD8D8D8, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0xD8D8D8,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, TRANSPARENT, TRANSPARENT, TRANSPARENT, 0x111111,
|
||||
0x0A0A0A, 0x111111, 0x181818, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
|
||||
0x020202, 0x0A0A0A, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
|
||||
TRANSPARENT, 0x020202, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
|
||||
]
|
||||
NOURRA_TOP = [
|
||||
0xBEBEBE, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xBEBEBE,
|
||||
0xB8B8B8, 0xB8B8B8, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xB8B8B8, 0xB8B8B8,
|
||||
]
|
||||
|
||||
|
||||
def main():
|
||||
entries = [("nourra", NOURRA_FACE, NOURRA_HOOD, NOURRA_TOP)]
|
||||
for ident, _display, _dye in PEOPLE:
|
||||
face, hood, top = extract(ROOT / "art" / "skins" / f"{ident}.png")
|
||||
entries.append((ident, face, hood, top))
|
||||
print(ident, "hood opaque", sum(1 for value in hood if value != TRANSPARENT))
|
||||
|
||||
out = ROOT / "src" / "main" / "java" / "fr" / "koka99cab" / "sanctuary26" / "onlyfun" / "item" / "SkinFacePortrait.java"
|
||||
chunks = [
|
||||
"package fr.koka99cab.sanctuary26.onlyfun.item;\n\n",
|
||||
"import net.minecraft.world.item.ItemStack;\n\n",
|
||||
"/** Baked 8x8 inner face, hood overlay and hood-top strip for each skin firework. */\n",
|
||||
"public enum SkinFacePortrait {\n",
|
||||
]
|
||||
for index, (ident, face, hood, top) in enumerate(entries):
|
||||
comma = "," if index + 1 < len(entries) else ";"
|
||||
chunks.append(
|
||||
f"\t{ident.upper()}(\"{ident}\", new int[] {{\n{fmt(face)}\n\t}}, new int[] {{\n{fmt(hood)}\n\t}}, new int[] {{\n{fmt(top)}\n\t}}){comma}\n"
|
||||
)
|
||||
chunks.append("""
|
||||
public static final int WIDTH = 8;
|
||||
public static final int HEIGHT = 8;
|
||||
public static final int TRANSPARENT = -1;
|
||||
|
||||
private final String id;
|
||||
private final int[] face;
|
||||
private final int[] hood;
|
||||
private final int[] hoodTop;
|
||||
|
||||
SkinFacePortrait(String id, int[] face, int[] hood, int[] hoodTop) {
|
||||
this.id = id;
|
||||
this.face = face;
|
||||
this.hood = hood;
|
||||
this.hoodTop = hoodTop;
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String itemId() {
|
||||
return id + \"_firework\";
|
||||
}
|
||||
|
||||
public int[] face() {
|
||||
return face;
|
||||
}
|
||||
|
||||
public int[] hood() {
|
||||
return hood;
|
||||
}
|
||||
|
||||
public int[] hoodTop() {
|
||||
return hoodTop;
|
||||
}
|
||||
|
||||
public int opaqueHoodPixels() {
|
||||
int count = 0;
|
||||
for (int color : hood) {
|
||||
if (color != TRANSPARENT) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int[] portrait() {
|
||||
int[] pixels = new int[WIDTH * (HEIGHT + 2)];
|
||||
System.arraycopy(hoodTop, 0, pixels, 0, hoodTop.length);
|
||||
for (int index = 0; index < face.length; index++) {
|
||||
pixels[hoodTop.length + index] = hood[index] == TRANSPARENT ? face[index] : hood[index];
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
public int portraitHeight() {
|
||||
return HEIGHT + hoodTop.length / WIDTH;
|
||||
}
|
||||
|
||||
public static SkinFacePortrait of(ItemStack stack) {
|
||||
if (stack.isEmpty() || !(stack.getItem() instanceof SkinFaceFireworkItem item)) return null;
|
||||
return item.portrait();
|
||||
}
|
||||
}
|
||||
""")
|
||||
out.write_text("".join(chunks), encoding="utf-8")
|
||||
print("wrote", out)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 3.0 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 933 B |
|
After Width: | Height: | Size: 2.4 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
@@ -0,0 +1,47 @@
|
||||
from pathlib import Path
|
||||
|
||||
IDS = [
|
||||
("chrism", "red_dye"),
|
||||
("kaninscheun", "yellow_dye"),
|
||||
("poupoutain", "light_gray_dye"),
|
||||
("lbeast", "brown_dye"),
|
||||
("creveforest", "green_dye"),
|
||||
("sacdchips", "orange_dye"),
|
||||
("vaselline", "white_dye"),
|
||||
("duncan", "pink_dye"),
|
||||
]
|
||||
ROOT = Path(__file__).resolve().parents[2] / "src" / "main" / "resources"
|
||||
|
||||
|
||||
def main():
|
||||
for ident, dye in IDS:
|
||||
(ROOT / "assets" / "onlyfun" / "items" / f"{ident}_firework.json").write_text(
|
||||
'{\n\t"model": {\n\t\t"type": "minecraft:model",\n\t\t"model": "onlyfun:item/%s_firework"\n\t}\n}\n' % ident,
|
||||
encoding="utf-8",
|
||||
)
|
||||
(ROOT / "assets" / "onlyfun" / "models" / "item" / f"{ident}_firework.json").write_text(
|
||||
'{\n\t"parent": "minecraft:item/generated",\n\t"textures": {\n\t\t"layer0": "onlyfun:item/%s_firework"\n\t}\n}\n' % ident,
|
||||
encoding="utf-8",
|
||||
)
|
||||
(ROOT / "data" / "onlyfun" / "recipe" / f"{ident}_firework.json").write_text(
|
||||
"""{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:%s",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:%s_firework"
|
||||
}
|
||||
}
|
||||
""" % (dye, ident),
|
||||
encoding="utf-8",
|
||||
)
|
||||
print("wrote", ident)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
|
After Width: | Height: | Size: 641 B |
@@ -0,0 +1,102 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.client;
|
||||
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFacePortrait;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.mixin.client.ParticleLifetimeAccessor;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import net.minecraft.core.particles.ColorParticleOption;
|
||||
import net.minecraft.core.particles.DustParticleOptions;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
/** Paints the baked skin as a firework burst of coloured sparks, facing the player. */
|
||||
public final class SkinFaceFireworkClient {
|
||||
public static final double PIXEL = 1.85D;
|
||||
public static final double LARGE_PIXEL = 2.7D;
|
||||
public static final float SPARK_SIZE = 3.6F;
|
||||
public static final float LARGE_SPARK_SIZE = 5.15F;
|
||||
public static final int SPARK_LIFETIME_TICKS = 38;
|
||||
private static final int SUBPIXELS = 2;
|
||||
|
||||
private SkinFaceFireworkClient() {
|
||||
}
|
||||
|
||||
public static void explode(FireworkRocketEntity rocket) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
if (minecraft.level == null || minecraft.particleEngine == null) return;
|
||||
Vec3 origin = rocket.position();
|
||||
RandomSource random = rocket.level().getRandom();
|
||||
minecraft.level.playLocalSound(origin.x, origin.y, origin.z,
|
||||
SoundEvents.FIREWORK_ROCKET_BLAST, SoundSource.AMBIENT,
|
||||
20.0F, 0.95F + random.nextFloat() * 0.1F, true);
|
||||
minecraft.level.addParticle(ColorParticleOption.create(ParticleTypes.FLASH, 0xFFFFFFFF),
|
||||
origin.x, origin.y, origin.z, 0.0D, 0.0D, 0.0D);
|
||||
Vec3 look = facing(minecraft, origin);
|
||||
Vec3 right = look.cross(new Vec3(0.0D, 1.0D, 0.0D));
|
||||
if (right.lengthSqr() < 1.0E-6D) right = new Vec3(1.0D, 0.0D, 0.0D);
|
||||
right = right.normalize();
|
||||
Vec3 up = new Vec3(0.0D, 1.0D, 0.0D);
|
||||
SkinFacePortrait portrait = SkinFacePortrait.of(rocket.getItem());
|
||||
if (portrait == null) return;
|
||||
int[] pixels = portrait.portrait();
|
||||
int width = SkinFacePortrait.WIDTH;
|
||||
int height = portrait.portraitHeight();
|
||||
boolean large = largeBurst(rocket);
|
||||
double pixel = burstPixel(large);
|
||||
float sparkSize = burstSparkSize(large);
|
||||
double midX = (width - 1) / 2.0D;
|
||||
double midY = (height - 1) / 2.0D;
|
||||
double step = 1.0D / SUBPIXELS;
|
||||
for (int row = 0; row < height; row++) {
|
||||
for (int col = 0; col < width; col++) {
|
||||
int color = visibleSpark(pixels[row * width + col]);
|
||||
DustParticleOptions dust = new DustParticleOptions(color, sparkSize);
|
||||
for (int subY = 0; subY < SUBPIXELS; subY++) {
|
||||
for (int subX = 0; subX < SUBPIXELS; subX++) {
|
||||
double px = (col - midX) + (subX + 0.5D) * step - 0.5D;
|
||||
double py = (midY - row) - (subY + 0.5D) * step + 0.5D;
|
||||
Vec3 offset = right.scale(px * pixel).add(up.scale(py * pixel));
|
||||
Vec3 pos = origin.add(offset);
|
||||
Vec3 velocity = offset.scale(0.05D);
|
||||
Particle spark = minecraft.particleEngine.createParticle(
|
||||
dust, pos.x, pos.y, pos.z, velocity.x, velocity.y, velocity.z);
|
||||
if (spark != null) {
|
||||
((ParticleLifetimeAccessor) spark).onlyfun$setLifetime(SPARK_LIFETIME_TICKS);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean largeBurst(FireworkRocketEntity rocket) {
|
||||
return (rocket.getUUID().getLeastSignificantBits() & 1L) != 0L;
|
||||
}
|
||||
|
||||
public static double burstPixel(boolean large) {
|
||||
return large ? LARGE_PIXEL : PIXEL;
|
||||
}
|
||||
|
||||
public static float burstSparkSize(boolean large) {
|
||||
return large ? LARGE_SPARK_SIZE : SPARK_SIZE;
|
||||
}
|
||||
|
||||
private static Vec3 facing(Minecraft minecraft, Vec3 origin) {
|
||||
Vec3 camera = minecraft.gameRenderer.mainCamera().position();
|
||||
Vec3 horizontal = new Vec3(origin.x - camera.x, 0.0D, origin.z - camera.z);
|
||||
if (horizontal.lengthSqr() < 1.0E-4D) return new Vec3(0.0D, 0.0D, 1.0D);
|
||||
return horizontal.normalize();
|
||||
}
|
||||
|
||||
private static int visibleSpark(int rgb) {
|
||||
int red = rgb >> 16 & 0xFF;
|
||||
int green = rgb >> 8 & 0xFF;
|
||||
int blue = rgb & 0xFF;
|
||||
if (red + green + blue < 24) return 0x2A2A2A;
|
||||
return rgb;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.item;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.FireworkRocketItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
|
||||
/** Firework rocket that bursts into the baked Nourra skin face. */
|
||||
public final class NourraFireworkItem extends FireworkRocketItem {
|
||||
public NourraFireworkItem(Properties properties) {
|
||||
super(properties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, TooltipContext context, TooltipDisplay display,
|
||||
Consumer<Component> tooltip, TooltipFlag flag) {
|
||||
tooltip.accept(Component.translatable("tooltip.onlyfun.nourra_firework").withStyle(ChatFormatting.AQUA));
|
||||
super.appendHoverText(stack, context, display, tooltip, flag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.item;
|
||||
|
||||
import java.util.List;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.Fireworks;
|
||||
|
||||
/**
|
||||
* Baked Nourra head (NameMC 6166a439e9354904): inner face, hood overlay, hood top.
|
||||
* Other skin fireworks reuse the same flight rules via {@link SkinFacePortrait}.
|
||||
*/
|
||||
public final class SkinFaceFireworkExplosions {
|
||||
public static final int WIDTH = 8;
|
||||
public static final int HEIGHT = 8;
|
||||
public static final int TRANSPARENT = -1;
|
||||
/** Inner head front, top-left origin, row-major RGB. */
|
||||
public static final int[] FACE = {
|
||||
0x000000, 0x020202, 0x0A0A0A, 0x111111, 0x111111, 0x0A0A0A, 0x020202, 0x000000,
|
||||
0x020202, 0x0A0A0A, 0x111111, 0x181818, 0x181818, 0x111111, 0x0A0A0A, 0x020202,
|
||||
0x0A0A0A, 0x111111, 0x181818, 0x212121, 0x212121, 0x181818, 0x111111, 0x0A0A0A,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0x111111,
|
||||
0x111111, 0x000000, 0x000000, 0xFFF0E1, 0xFFF0E1, 0x000000, 0x000000, 0x111111,
|
||||
0x0A0A0A, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFFF0E1, 0x4A9DFC, 0xFFFFFF, 0x0A0A0A,
|
||||
0x020202, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFDE8D7, 0x4A9DFC, 0xFFFFFF, 0x020202,
|
||||
0x000000, 0xF0C6A5, 0xF7D5B9, 0xFCE1CA, 0xFCE1CA, 0xF7D5B9, 0xF0C6A5, 0x000000
|
||||
};
|
||||
/** Hat/hood overlay on the front; {@link #TRANSPARENT} keeps the inner face visible. */
|
||||
public static final int[] HOOD = {
|
||||
0x000000, 0x0D0D0D, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0x0D0D0D, 0x000000,
|
||||
0x0D0D0D, 0x707070, 0xD8D8D8, 0xE5E5E5, 0xE5E5E5, 0xD8D8D8, 0x707070, 0x0D0D0D,
|
||||
0xCBCBCB, 0xD8D8D8, 0xFFFFFF, 0x212121, 0x212121, 0x181818, 0xD8D8D8, 0xCBCBCB,
|
||||
0xD8D8D8, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0xD8D8D8,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, TRANSPARENT, TRANSPARENT, TRANSPARENT, 0x111111,
|
||||
0x0A0A0A, 0x111111, 0x181818, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
|
||||
0x020202, 0x0A0A0A, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT,
|
||||
TRANSPARENT, 0x020202, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT, TRANSPARENT
|
||||
};
|
||||
/** Front edge of the hood top (skin overlay top rows closest to the face). */
|
||||
public static final int[] HOOD_TOP = {
|
||||
0xBEBEBE, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xBEBEBE,
|
||||
0xB8B8B8, 0xB8B8B8, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xB8B8B8, 0xB8B8B8
|
||||
};
|
||||
/** Vanilla flight 3 minus half a gunpowder step, so the burst sits between 2 and 3. */
|
||||
public static final int LIFETIME_TRIM_TICKS = 5;
|
||||
|
||||
private SkinFaceFireworkExplosions() {
|
||||
}
|
||||
|
||||
public static Fireworks defaultFireworks() {
|
||||
return new Fireworks(3, List.of());
|
||||
}
|
||||
|
||||
public static int midFlightLifetime(int vanillaLifetime) {
|
||||
return Math.max(1, vanillaLifetime - LIFETIME_TRIM_TICKS);
|
||||
}
|
||||
|
||||
public static boolean isSkinFaceRocket(ItemStack stack) {
|
||||
return SkinFacePortrait.of(stack) != null;
|
||||
}
|
||||
|
||||
public static int opaqueHoodPixels() {
|
||||
int count = 0;
|
||||
for (int color : HOOD) {
|
||||
if (color != TRANSPARENT) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
/** Hood top (2 rows) then the 8×8 face with the hood overlay composited. */
|
||||
public static int[] portrait() {
|
||||
return SkinFacePortrait.NOURRA.portrait();
|
||||
}
|
||||
|
||||
public static int portraitHeight() {
|
||||
return SkinFacePortrait.NOURRA.portraitHeight();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.item;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.FireworkRocketItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
|
||||
/** Firework rocket that bursts into a baked skin face. */
|
||||
public final class SkinFaceFireworkItem extends FireworkRocketItem {
|
||||
private final SkinFacePortrait portrait;
|
||||
|
||||
public SkinFaceFireworkItem(SkinFacePortrait portrait, Properties properties) {
|
||||
super(properties);
|
||||
this.portrait = portrait;
|
||||
}
|
||||
|
||||
public SkinFacePortrait portrait() {
|
||||
return portrait;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(ItemStack stack, TooltipContext context, TooltipDisplay display,
|
||||
Consumer<Component> tooltip, TooltipFlag flag) {
|
||||
tooltip.accept(Component.translatable("tooltip.onlyfun.skin_face_firework").withStyle(ChatFormatting.AQUA));
|
||||
super.appendHoverText(stack, context, display, tooltip, flag);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,269 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.item;
|
||||
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
/** Baked 8x8 inner face, hood overlay and hood-top strip for each skin firework. */
|
||||
public enum SkinFacePortrait {
|
||||
NOURRA("nourra", new int[] {
|
||||
0x000000, 0x020202, 0x0A0A0A, 0x111111, 0x111111, 0x0A0A0A, 0x020202, 0x000000,
|
||||
0x020202, 0x0A0A0A, 0x111111, 0x181818, 0x181818, 0x111111, 0x0A0A0A, 0x020202,
|
||||
0x0A0A0A, 0x111111, 0x181818, 0x212121, 0x212121, 0x181818, 0x111111, 0x0A0A0A,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0x111111,
|
||||
0x111111, 0x000000, 0x000000, 0xFFF0E1, 0xFFF0E1, 0x000000, 0x000000, 0x111111,
|
||||
0x0A0A0A, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFFF0E1, 0x4A9DFC, 0xFFFFFF, 0x0A0A0A,
|
||||
0x020202, 0xFFFFFF, 0x4A9DFC, 0xFDE8D7, 0xFDE8D7, 0x4A9DFC, 0xFFFFFF, 0x020202,
|
||||
0x000000, 0xF0C6A5, 0xF7D5B9, 0xFCE1CA, 0xFCE1CA, 0xF7D5B9, 0xF0C6A5, 0x000000
|
||||
}, new int[] {
|
||||
0x000000, 0x0D0D0D, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0x0D0D0D, 0x000000,
|
||||
0x0D0D0D, 0x707070, 0xD8D8D8, 0xE5E5E5, 0xE5E5E5, 0xD8D8D8, 0x707070, 0x0D0D0D,
|
||||
0xCBCBCB, 0xD8D8D8, 0xFFFFFF, 0x212121, 0x212121, 0x181818, 0xD8D8D8, 0xCBCBCB,
|
||||
0xD8D8D8, 0x181818, 0x212121, 0x2B2B2B, 0x2B2B2B, 0x212121, 0x181818, 0xD8D8D8,
|
||||
0x111111, 0x181818, 0x212121, 0x2B2B2B, -1, -1, -1, 0x111111,
|
||||
0x0A0A0A, 0x111111, 0x181818, -1, -1, -1, -1, -1,
|
||||
0x020202, 0x0A0A0A, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0x020202, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0xBEBEBE, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xBEBEBE,
|
||||
0xB8B8B8, 0xB8B8B8, 0xCBCBCB, 0xD8D8D8, 0xD8D8D8, 0xCBCBCB, 0xB8B8B8, 0xB8B8B8
|
||||
}),
|
||||
CHRISM("chrism", new int[] {
|
||||
0xF59589, 0xF89C90, 0xFEA398, 0xFEA398, 0xFCA297, 0xF89B8F, 0xF2978B, 0xF49488,
|
||||
0xF59589, 0xFB9D91, 0xFA9D92, 0xFCA095, 0xFCA095, 0xFCA095, 0xF89B8F, 0xF49488,
|
||||
0xF59589, 0xFB9A8E, 0xFD9E93, 0xFDA196, 0xFDA196, 0xFD9E93, 0xFB9A8E, 0xFF988B,
|
||||
0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E,
|
||||
0xFE8B7E, 0x000000, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0x000000, 0xFD8B7D,
|
||||
0xF67D70, 0xF68375, 0xFA897C, 0xFE8B7E, 0xFE8B7E, 0xFE8B7E, 0xF68375, 0xF67D70,
|
||||
0x000000, 0xFFFFFF, 0x000000, 0x000000, 0x000000, 0x000000, 0xFFFFFF, 0x000000,
|
||||
0xEE6858, 0x000000, 0x000000, 0xFF1408, 0xFC0C00, 0x000000, 0x000000, 0xEE6858
|
||||
}, new int[] {
|
||||
0xFF8071, 0xFF8274, 0xFF796A, 0xFA7B6C, 0xFE7E70, 0xF97769, 0xFB7F70, 0xFF7A6B,
|
||||
0xF56E5E, 0xFF9185, 0xFF8375, 0xFF9084, 0xFB8A7E, 0xFE9286, 0xFF8B7E, 0xF68274,
|
||||
0xFA7263, 0xFF9488, 0xFE9084, 0xFE8C80, 0xFF9286, 0xF77F72, 0xF89084, 0xF97465,
|
||||
0xFF8273, 0xFF8E82, 0xFA8D81, 0xF68477, 0xF69186, 0xFF8F83, 0xFD9286, 0xFF7767,
|
||||
0xFF8173, 0xFB887B, 0xFC9084, 0xFF9083, 0xFF978B, 0xFF8375, 0xF48A7E, 0xFF8173,
|
||||
0xFD7D6E, -1, 0xF5897D, 0xFF8C7F, 0xF3877A, 0xFF897C, -1, 0xFF7060,
|
||||
0xFC7667, 0xFF897B, 0xFF9488, -1, -1, 0xF37F72, 0xF89186, 0xFD7566,
|
||||
0xFF8375, 0xFF7F70, 0xF88072, 0xF88173, 0xFC7869, 0xFF8173, 0xFF8678, 0xFF7C6D
|
||||
}, new int[] {
|
||||
0xF97566, 0xFF8C7F, 0xF4867A, 0xFF877A, 0xF4786A, 0xFF8678, 0xF97E70, 0xFF7F71,
|
||||
0xFF897B, 0xFB7566, 0xFF8C7F, 0xF77F72, 0xF77769, 0xFF7C6E, 0xF88578, 0xF87B6D
|
||||
}),
|
||||
KANINSCHEUN("kaninscheun", new int[] {
|
||||
0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D,
|
||||
0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xFFCC66, 0xEAD900, 0xEDDF2D,
|
||||
0xEAD900, 0xEDDF2D, 0xEAD900, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xEDDF2D,
|
||||
0xEAD900, 0x000000, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0x000000, 0xEDDF2D,
|
||||
0xEAD900, 0x000000, 0x000000, 0xFFCC66, 0xFFCC66, 0x000000, 0x000000, 0xEDDF2D,
|
||||
0xEAD900, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xFFCC66, 0xEDDF2D,
|
||||
0xEAD900, 0xFFCC66, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xFFCC66, 0xEDDF2D,
|
||||
0xEAD900, 0xEAD900, 0xEDDF2D, 0xFFCC66, 0xFFCC66, 0xEAD900, 0xEAD900, 0xEDDF2D
|
||||
}, new int[] {
|
||||
-1, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, -1,
|
||||
0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900,
|
||||
0xEDDF2D, 0xEAD900, 0xEDDF2D, -1, -1, -1, 0xEDDF2D, 0xEAD900,
|
||||
0xEDDF2D, 0xEAD900, -1, -1, -1, -1, -1, 0xEAD900,
|
||||
0xEDDF2D, -1, -1, -1, -1, -1, -1, 0xEAD900,
|
||||
0xEDDF2D, -1, -1, -1, -1, -1, -1, 0xEAD900,
|
||||
0xEDDF2D, -1, -1, -1, -1, -1, -1, 0xEAD900,
|
||||
-1, 0xEAD900, -1, -1, -1, -1, 0xEDDF2D, -1
|
||||
}, new int[] {
|
||||
0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900,
|
||||
0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900, 0xEDDF2D, 0xEAD900
|
||||
}),
|
||||
POUPOUTAIN("poupoutain", new int[] {
|
||||
0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x342404, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0x342404, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x342404, 0xE0DFDE, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0xE7E6E4, 0x4B5456,
|
||||
0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456
|
||||
}, new int[] {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456, 0x4B5456,
|
||||
0x414B4C, 0x414B4C, 0x414B4C, 0x414B4C, 0x414B4C, 0x414B4C, 0x414B4C, 0x414B4C
|
||||
}),
|
||||
LBEAST("lbeast", new int[] {
|
||||
0x8A6C30, 0x8A6B31, 0x644B1A, 0x5D4B1E, 0x896F37, 0x80672A, 0x614B1A, 0x4C3910,
|
||||
0x957538, 0x816C34, 0x6D5521, 0x715B20, 0xA88C44, 0x9C7E3B, 0x7F6625, 0x7D6325,
|
||||
0xB59F6D, 0xC1AC74, 0xC8B378, 0xD0BB7C, 0xD9C382, 0xE7CF8A, 0xD2BC7E, 0xC6A574,
|
||||
0xB39C6C, 0x2B2324, 0x2B2324, 0xD5BA80, 0xD7BE80, 0x2B2324, 0x2B2324, 0xCBA977,
|
||||
0xDCC285, 0xBAA0A6, 0x42597E, 0xF1D491, 0xD7BD7F, 0x42597E, 0xBAA0A6, 0xECC48B,
|
||||
0xEACC8C, 0xFAF3F5, 0x87A6D2, 0xFDDB98, 0xDCBE81, 0x87A6D2, 0xFAF3F5, 0xF1C88E,
|
||||
0xE4C082, 0xF6D695, 0xFBDD96, 0xFBE197, 0xFBE197, 0xFDDC95, 0xF6D695, 0xEBC288,
|
||||
0xE9C183, 0xEFC68A, 0xF6D695, 0xFDDC94, 0xFBE197, 0xF6D695, 0xF4C98C, 0xDFB67D
|
||||
}, new int[] {
|
||||
0x7E652E, 0xC5A253, 0xC5A253, 0xBB984A, 0xD0A64E, 0xBB984A, 0xC5A253, 0x715B29,
|
||||
0x947438, 0xEAC269, 0x96772C, 0xB69045, 0xD0A64E, 0xBB984A, 0xC5A253, 0x7E652E,
|
||||
0xB49043, 0xD0A64E, -1, 0xD0A64E, 0xE4C368, 0xBB984A, 0xD0A64E, 0x8A6E32,
|
||||
0x96772C, -1, -1, -1, -1, 0xBB9853, 0xD1AD5C, 0xB18D46,
|
||||
0xD0A64E, -1, -1, -1, -1, -1, -1, 0x9C7D39,
|
||||
-1, -1, -1, -1, -1, -1, -1, 0x9C7D39,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0x846932, 0x907336, 0xA18340, 0xAE8E45, 0xAE8E45, 0x886F36, 0x7B6431, 0x6E5A2C,
|
||||
0x7A6029, 0x886F36, 0x95793B, 0xA18340, 0xA18340, 0x95793B, 0x886F36, 0x7B6431
|
||||
}),
|
||||
CREVEFOREST("creveforest", new int[] {
|
||||
0x2D4C54, 0x2D4C54, 0x2D4C54, 0x2D4C54, 0x355C5E, 0x2D4C54, 0x2D4C54, 0x2D4C54,
|
||||
0x2D4C54, 0x2D4C54, 0x355C5E, 0x355C5E, 0x355C5E, 0x355C5E, 0x2D4C54, 0x2D4C54,
|
||||
0x2D4C54, 0x355C5E, 0x79A88F, 0x8FC49B, 0x79A88F, 0x79A88F, 0x355C5E, 0x2D4C54,
|
||||
0x355C5E, 0x79A88F, 0x8FC49B, 0x9ED69C, 0x8FC49B, 0x8FC49B, 0x79A88F, 0x355C5E,
|
||||
0x355C5E, 0x1E2E33, 0x1E2E33, 0xB7E8A9, 0x9ED69C, 0x1E2E33, 0x1E2E33, 0x355C5E,
|
||||
0x1E2E33, 0x9BB0AC, 0x344C46, 0xD3F5BA, 0xB7E8A9, 0x344C46, 0x9BB0AC, 0x1E2E33,
|
||||
0x2D4C54, 0xEBEBEB, 0x79B8AB, 0xD3F5BA, 0xB7E8A9, 0x79B8AB, 0xEBEBEB, 0x355C5E,
|
||||
0x2D4C54, 0x8FC49B, 0xB7E8A9, 0x9ED69C, 0xB7E8A9, 0xB7E8A9, 0x8FC49B, 0x355C5E
|
||||
}, new int[] {
|
||||
-1, 0x549C62, 0x4D8C64, 0x4D8C64, 0x549C62, 0x3D785D, 0x4D8C64, -1,
|
||||
0x549C62, 0x549C62, 0x4D8C64, 0x4D8C64, 0x4D8C64, 0x3D785D, 0x4D8C64, 0x549C62,
|
||||
0x4D8C64, 0x4D8C64, 0x3D785D, 0x3D785D, 0x3D785D, 0x355C5E, 0x3D785D, 0x4D8C64,
|
||||
0x3D785D, 0x3D785D, 0x355C5E, -1, 0x355C5E, 0x2D4C54, 0x355C5E, 0x3D785D,
|
||||
0x3D785D, -1, 0x2D4C54, -1, -1, -1, 0x355C5E, 0x3D785D,
|
||||
0x355C5E, -1, -1, -1, -1, -1, -1, 0x355C5E,
|
||||
0x2D4C54, -1, -1, -1, -1, -1, -1, 0x2D4C54,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0x355C5E, 0x355C5E, 0x355C5E, 0x355C5E, 0x3D785D, 0x355C5E, 0x2D4C54, 0x355C5E,
|
||||
0x2D4C54, 0x549C62, 0x4D8C64, 0x4D8C64, 0x549C62, 0x3D785D, 0x4D8C64, 0x355C5E
|
||||
}),
|
||||
SACDCHIPS("sacdchips", new int[] {
|
||||
0x3E1A05, 0x421D05, 0x391904, 0x421C06, 0x391904, 0x632C08, 0x3D1B05, 0x552607,
|
||||
0x421D05, 0x421D05, 0x391904, 0xF1DACD, 0xF2DDD1, 0xEFD7C9, 0xEED4C5, 0x632C08,
|
||||
0xEBCCBA, 0xECCFBE, 0xEDD1C1, 0xE7C3AE, 0xEDD1C1, 0xEED4C5, 0xF2DDD1, 0xECCFBE,
|
||||
0xECCFBE, 0x341704, 0x341704, 0xE7C3AE, 0xEBCCBA, 0x341704, 0x341704, 0xF1DACD,
|
||||
0xEBCCBA, 0xEEEEEE, 0x602F10, 0xEDD1C1, 0xF2DDD1, 0x602F10, 0xEEEEEE, 0xEDD1C1,
|
||||
0xE7C3AE, 0xEDD1C1, 0xE7C3AE, 0xF2DDD1, 0xF1DACD, 0xEDD1C1, 0xE7C3AE, 0xEDD1C1,
|
||||
0xE6C0AA, 0xECCFBE, 0xEBCCBA, 0x000000, 0x000000, 0xEDD1C1, 0xEAC9B6, 0xEBCCBA,
|
||||
0xEAC9B6, 0xECCFBE, 0xF2DDD1, 0xECCFBE, 0xEAC9B6, 0xF1DACD, 0xECCFBE, 0xF1DACD
|
||||
}, new int[] {
|
||||
-1, 0x180A02, 0x261003, 0x2B1204, 0x341604, 0x210E03, 0x2F1404, -1,
|
||||
-1, -1, -1, 0x2B1204, 0x210E03, 0x471E06, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, 0x261003, 0x180A02, 0x210E03, 0x1D0C02, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0x3E1A05, 0x3E1A05, 0x210E03, 0x1D0C02, 0x341604, 0x180A02, 0x2F1404, 0x1D0C02,
|
||||
0x391805, 0x421C06, 0x421C06, 0x3E1A05, 0x471E06, 0x1D0C02, 0x341604, 0x341604
|
||||
}),
|
||||
VASELLINE("vaselline", new int[] {
|
||||
0xEBE176, 0xEBE176, 0xEBE176, 0xE8DC5F, 0xE8DC5F, 0xE8DC5F, 0xEBE176, 0xEBE176,
|
||||
0xEBE176, 0xE8DC5F, 0xE8D7B1, 0xE8D7B1, 0xE8D7B1, 0xE8D7B1, 0xE8DC5F, 0xEBE176,
|
||||
0xE8DC5F, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xE8DC5F,
|
||||
0xE8DC5F, 0xFFFFFF, 0x6F9EE8, 0xE8D7B1, 0xE8D7B1, 0x6F9EE8, 0xFFFFFF, 0xE8DC5F,
|
||||
0xE8DC5F, 0xE8D7B1, 0xE8D7B1, 0xEEE1C5, 0xEEE1C5, 0xE8D7B1, 0xE8D7B1, 0xE8DC5F,
|
||||
0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5,
|
||||
0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xE2CD9D, 0xE2CD9D, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5,
|
||||
0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5, 0xEEE1C5
|
||||
}, new int[] {
|
||||
0xEBE176, 0xEBE176, 0xE8DC5F, 0xE8DC5F, 0xE8DC5F, 0xE8DC5F, 0xEBE176, 0xEBE176,
|
||||
0xEBE176, 0xE8DC5F, -1, -1, -1, -1, 0xE8DC5F, 0xEBE176,
|
||||
0xEBE176, -1, -1, -1, -1, -1, -1, 0xE8DC5F,
|
||||
0xE8DC5F, -1, -1, -1, -1, -1, -1, 0xE8DC5F,
|
||||
0xE8DC5F, -1, -1, -1, -1, -1, -1, 0xE8DC5F,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0xEBE176, 0xE8DC5F, 0xE8DC5F, 0xEBE176, 0xEBE176, 0xE8DC5F, 0xE8DC5F, 0xE8DC5F,
|
||||
0xEBE176, 0xEBE176, 0xEBE176, 0xEBE176, 0xEBE176, 0xEBE176, 0xEBE176, 0xEBE176
|
||||
}),
|
||||
DUNCAN("duncan", new int[] {
|
||||
0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330,
|
||||
0xFFD6AE, 0xFFD7AE, 0xFFD7AE, 0xFFD6AE, 0xFFD6AE, 0xFED7AE, 0xFFD7AF, 0xFFD7AE,
|
||||
0xFFD7AE, 0xAD3B11, 0xAC3A10, 0xFFD7AE, 0xFFD7AE, 0xAD3B10, 0xAC3B11, 0xFFD6AF,
|
||||
0xFED6AF, 0xFEFFFF, 0x783018, 0xFFD7AE, 0xFFD7AE, 0xFEFFFE, 0x793019, 0xFFD6AF,
|
||||
0xFFD6AE, 0x783018, 0x010000, 0xFFD7AF, 0xFED7AE, 0x010100, 0x783018, 0xFFD7AF,
|
||||
0xFED7AF, 0xFFD7AE, 0xFFD7AF, 0xFED6AF, 0xFED7AE, 0xFED7AE, 0xFED7AF, 0xFFD6AE,
|
||||
0xFED7AE, 0xFED7AF, 0xFED7AE, 0xCB97A0, 0xCB96A0, 0xFED7AE, 0xFFD7AE, 0xFFD6AE,
|
||||
0xFFD7AE, 0xFED7AE, 0xFFD7AE, 0xFFD7AF, 0xFFD7AE, 0xFFD7AE, 0xFFD7AE, 0xFED7AE
|
||||
}, new int[] {
|
||||
0x9D5330, 0xBC5D30, 0x9D5330, 0x88492A, 0x9D5330, 0x9D5330, 0x88492A, 0x9D5330,
|
||||
0x9D5330, -1, 0x88492A, -1, -1, 0xBC5D30, -1, 0x9D5330,
|
||||
-1, 0xE6AB35, 0xE7AA34, -1, -1, 0xE6AA34, 0xE7AA34, -1,
|
||||
0xE6AB34, -1, -1, 0xE7AB35, 0xE7AB35, -1, -1, 0xE6AB35,
|
||||
0xE7AB35, -1, -1, 0xE6AB35, 0xE6AA34, -1, -1, 0xE6AB35,
|
||||
-1, 0xE6AB34, 0xE6AB35, -1, -1, 0xE6AB35, 0xE6AB34, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1
|
||||
}, new int[] {
|
||||
0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330, 0x88492A, 0x9D5330, 0x9D5330, 0x88492A,
|
||||
0x9D5330, 0x9D5330, 0x9D5330, 0xBC5D30, 0x9D5330, 0x9D5330, 0x9D5330, 0x9D5330
|
||||
});
|
||||
|
||||
public static final int WIDTH = 8;
|
||||
public static final int HEIGHT = 8;
|
||||
public static final int TRANSPARENT = -1;
|
||||
|
||||
private final String id;
|
||||
private final int[] face;
|
||||
private final int[] hood;
|
||||
private final int[] hoodTop;
|
||||
|
||||
SkinFacePortrait(String id, int[] face, int[] hood, int[] hoodTop) {
|
||||
this.id = id;
|
||||
this.face = face;
|
||||
this.hood = hood;
|
||||
this.hoodTop = hoodTop;
|
||||
}
|
||||
|
||||
public String id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String itemId() {
|
||||
return id + "_firework";
|
||||
}
|
||||
|
||||
public int[] face() {
|
||||
return face;
|
||||
}
|
||||
|
||||
public int[] hood() {
|
||||
return hood;
|
||||
}
|
||||
|
||||
public int[] hoodTop() {
|
||||
return hoodTop;
|
||||
}
|
||||
|
||||
public int opaqueHoodPixels() {
|
||||
int count = 0;
|
||||
for (int color : hood) {
|
||||
if (color != TRANSPARENT) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
public int[] portrait() {
|
||||
int[] pixels = new int[WIDTH * (HEIGHT + 2)];
|
||||
System.arraycopy(hoodTop, 0, pixels, 0, hoodTop.length);
|
||||
for (int index = 0; index < face.length; index++) {
|
||||
pixels[hoodTop.length + index] = hood[index] == TRANSPARENT ? face[index] : hood[index];
|
||||
}
|
||||
return pixels;
|
||||
}
|
||||
|
||||
public int portraitHeight() {
|
||||
return HEIGHT + hoodTop.length / WIDTH;
|
||||
}
|
||||
|
||||
public static SkinFacePortrait of(ItemStack stack) {
|
||||
if (stack.isEmpty()) return null;
|
||||
if (stack.getItem() instanceof SkinFaceFireworkItem item) return item.portrait();
|
||||
if (stack.getItem() instanceof NourraFireworkItem) return NOURRA;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.mixin;
|
||||
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFaceFireworkExplosions;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FireworkRocketEntity.class)
|
||||
public abstract class FireworkRocketLifetimeMixin {
|
||||
@Shadow
|
||||
private int life;
|
||||
@Shadow
|
||||
private int lifetime;
|
||||
|
||||
@Inject(method = "tick", at = @At("HEAD"))
|
||||
private void onlyfun$midFlightLifetime(CallbackInfo callback) {
|
||||
if (this.life != 0) return;
|
||||
FireworkRocketEntity rocket = (FireworkRocketEntity) (Object) this;
|
||||
if (!SkinFaceFireworkExplosions.isSkinFaceRocket(rocket.getItem())) return;
|
||||
this.lifetime = SkinFaceFireworkExplosions.midFlightLifetime(this.lifetime);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.mixin.client;
|
||||
|
||||
import fr.koka99cab.sanctuary26.onlyfun.client.SkinFaceFireworkClient;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFaceFireworkExplosions;
|
||||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(FireworkRocketEntity.class)
|
||||
public abstract class FireworkRocketEntityMixin {
|
||||
@Inject(method = "handleEntityEvent", at = @At("HEAD"), cancellable = true)
|
||||
private void onlyfun$drawSkinFace(byte id, CallbackInfo callback) {
|
||||
if (id != 17) return;
|
||||
FireworkRocketEntity rocket = (FireworkRocketEntity) (Object) this;
|
||||
if (!rocket.level().isClientSide()) return;
|
||||
if (!SkinFaceFireworkExplosions.isSkinFaceRocket(rocket.getItem())) return;
|
||||
SkinFaceFireworkClient.explode(rocket);
|
||||
callback.cancel();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.mixin.client;
|
||||
|
||||
import net.minecraft.client.particle.Particle;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
|
||||
@Mixin(Particle.class)
|
||||
public interface ParticleLifetimeAccessor {
|
||||
@Accessor("lifetime")
|
||||
void onlyfun$setLifetime(int lifetime);
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
public final class OnlyFunCreativeTab {
|
||||
@@ -28,6 +29,10 @@ public final class OnlyFunCreativeTab {
|
||||
output.accept(OnlyFunRegistries.CAPE_LOOTBOX);
|
||||
output.accept(OnlyFunRegistries.SPAWN_EGG_LOOTBOX);
|
||||
output.accept(OnlyFunRegistries.ANOMALY_LOOTBOX);
|
||||
output.accept(OnlyFunRegistries.NOURRA_FIREWORK);
|
||||
for (Item firework : OnlyFunRegistries.skinFireworks()) {
|
||||
if (firework != OnlyFunRegistries.NOURRA_FIREWORK) output.accept(firework);
|
||||
}
|
||||
output.accept(AbjectionRegistries.SHIT_BALL);
|
||||
output.accept(AbjectionRegistries.SHIT_CUBE_ITEM);
|
||||
})
|
||||
|
||||
@@ -3,6 +3,10 @@ package fr.koka99cab.sanctuary26.onlyfun.registry;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.OnlyFunMod;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.block.LuckyBlockBlock;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.LootboxItem;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.NourraFireworkItem;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFaceFireworkExplosions;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFaceFireworkItem;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFacePortrait;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.loot.OnlyFunGenerator;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.loot.OnlyFunSource;
|
||||
import java.util.function.Function;
|
||||
@@ -32,6 +36,17 @@ public final class OnlyFunRegistries {
|
||||
public static final Item CAPE_LOOTBOX = registerLootbox("cape_lootbox", OnlyFunSource.CAPE_LOOTBOX);
|
||||
public static final Item SPAWN_EGG_LOOTBOX = registerLootbox("spawn_egg_lootbox", OnlyFunSource.SPAWN_EGG_LOOTBOX);
|
||||
public static final Item ANOMALY_LOOTBOX = registerLootbox("anomaly_lootbox", OnlyFunSource.ANOMALY_LOOTBOX);
|
||||
public static final Item NOURRA_FIREWORK = registerItem("nourra_firework",
|
||||
properties -> new NourraFireworkItem(properties.stacksTo(64)
|
||||
.component(DataComponents.FIREWORKS, SkinFaceFireworkExplosions.defaultFireworks())));
|
||||
public static final Item CHRISM_FIREWORK = registerSkinFirework(SkinFacePortrait.CHRISM);
|
||||
public static final Item KANINSCHEUN_FIREWORK = registerSkinFirework(SkinFacePortrait.KANINSCHEUN);
|
||||
public static final Item POUPOUTAIN_FIREWORK = registerSkinFirework(SkinFacePortrait.POUPOUTAIN);
|
||||
public static final Item LBEAST_FIREWORK = registerSkinFirework(SkinFacePortrait.LBEAST);
|
||||
public static final Item CREVEFOREST_FIREWORK = registerSkinFirework(SkinFacePortrait.CREVEFOREST);
|
||||
public static final Item SACDCHIPS_FIREWORK = registerSkinFirework(SkinFacePortrait.SACDCHIPS);
|
||||
public static final Item VASELLINE_FIREWORK = registerSkinFirework(SkinFacePortrait.VASELLINE);
|
||||
public static final Item DUNCAN_FIREWORK = registerSkinFirework(SkinFacePortrait.DUNCAN);
|
||||
private static boolean initialized;
|
||||
|
||||
private OnlyFunRegistries() {
|
||||
@@ -47,6 +62,13 @@ public final class OnlyFunRegistries {
|
||||
};
|
||||
}
|
||||
|
||||
public static Item[] skinFireworks() {
|
||||
return new Item[] {
|
||||
NOURRA_FIREWORK, CHRISM_FIREWORK, KANINSCHEUN_FIREWORK, POUPOUTAIN_FIREWORK,
|
||||
LBEAST_FIREWORK, CREVEFOREST_FIREWORK, SACDCHIPS_FIREWORK, VASELLINE_FIREWORK, DUNCAN_FIREWORK
|
||||
};
|
||||
}
|
||||
|
||||
public static void initialize() {
|
||||
if (initialized) {
|
||||
return;
|
||||
@@ -61,6 +83,16 @@ public final class OnlyFunRegistries {
|
||||
OnlyFunMod.LOGGER.debug("[{}] Item and block registries initialized.", OnlyFunMod.DISPLAY_NAME);
|
||||
}
|
||||
|
||||
private static Item registerSkinFirework(SkinFacePortrait portrait) {
|
||||
return registerItem(portrait.itemId(), properties -> new SkinFaceFireworkItem(portrait,
|
||||
properties.stacksTo(64).component(DataComponents.FIREWORKS, SkinFaceFireworkExplosions.defaultFireworks())));
|
||||
}
|
||||
|
||||
private static Item registerItem(String path, Function<Item.Properties, Item> factory) {
|
||||
ResourceKey<Item> key = ResourceKey.create(Registries.ITEM, OnlyFunMod.id(path));
|
||||
return Registry.register(BuiltInRegistries.ITEM, key, factory.apply(new Item.Properties().setId(key)));
|
||||
}
|
||||
|
||||
private static Item registerLootbox(String path, OnlyFunSource source) {
|
||||
ResourceKey<Item> key = ResourceKey.create(Registries.ITEM, OnlyFunMod.id(path));
|
||||
return Registry.register(BuiltInRegistries.ITEM, key,
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/chrism_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/creveforest_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/duncan_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/kaninscheun_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/lbeast_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/nourra_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/poupoutain_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/sacdchips_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"model": {
|
||||
"type": "minecraft:model",
|
||||
"model": "onlyfun:item/vaselline_firework"
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,17 @@
|
||||
"item.onlyfun.cape_lootbox": "Cape Lootbox",
|
||||
"item.onlyfun.spawn_egg_lootbox": "Spawn Egg Lootbox",
|
||||
"item.onlyfun.anomaly_lootbox": "Anomaly Lootbox",
|
||||
"item.onlyfun.nourra_firework": "Nourra Firework",
|
||||
"item.onlyfun.chrism_firework": "ChrisM Firework",
|
||||
"item.onlyfun.kaninscheun_firework": "Kaninscheun Firework",
|
||||
"item.onlyfun.poupoutain_firework": "Poupoutain Firework",
|
||||
"item.onlyfun.lbeast_firework": "lBeast Firework",
|
||||
"item.onlyfun.creveforest_firework": "CreveForest Firework",
|
||||
"item.onlyfun.sacdchips_firework": "SacDChips Firework",
|
||||
"item.onlyfun.vaselline_firework": "Vaselline Firework",
|
||||
"item.onlyfun.duncan_firework": "Duncan Firework",
|
||||
"tooltip.onlyfun.nourra_firework": "The burst paints the skin face, at normal or larger size.",
|
||||
"tooltip.onlyfun.skin_face_firework": "The burst paints the skin face, at normal or larger size.",
|
||||
"item.onlyfun.quality_gear": "Quality Gear",
|
||||
"item.onlyfun.impossible_tool": "Impossible Tool",
|
||||
"item.onlyfun.impossible_book": "Impossible Book",
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
"item.onlyfun.cape_lootbox": "Lootbox de capes",
|
||||
"item.onlyfun.spawn_egg_lootbox": "Lootbox d'œufs",
|
||||
"item.onlyfun.anomaly_lootbox": "Lootbox anomalie",
|
||||
"item.onlyfun.nourra_firework": "Feu d'artifice Nourra",
|
||||
"item.onlyfun.chrism_firework": "Feu d'artifice ChrisM",
|
||||
"item.onlyfun.kaninscheun_firework": "Feu d'artifice Kaninscheun",
|
||||
"item.onlyfun.poupoutain_firework": "Feu d'artifice Poupoutain",
|
||||
"item.onlyfun.lbeast_firework": "Feu d'artifice lBeast",
|
||||
"item.onlyfun.creveforest_firework": "Feu d'artifice CreveForest",
|
||||
"item.onlyfun.sacdchips_firework": "Feu d'artifice SacDChips",
|
||||
"item.onlyfun.vaselline_firework": "Feu d'artifice Vaselline",
|
||||
"item.onlyfun.duncan_firework": "Feu d'artifice Duncan",
|
||||
"tooltip.onlyfun.nourra_firework": "L'explosion dessine le visage, en taille normale ou plus grande.",
|
||||
"tooltip.onlyfun.skin_face_firework": "L'explosion dessine le visage, en taille normale ou plus grande.",
|
||||
"item.onlyfun.quality_gear": "Équipement de qualité",
|
||||
"item.onlyfun.impossible_tool": "Outil impossible",
|
||||
"item.onlyfun.impossible_book": "Livre impossible",
|
||||
|
||||
@@ -6,6 +6,17 @@
|
||||
"item.onlyfun.cape_lootbox": "Лутбокс плащей",
|
||||
"item.onlyfun.spawn_egg_lootbox": "Лутбокс яиц призыва",
|
||||
"item.onlyfun.anomaly_lootbox": "Лутбокс-аномалия",
|
||||
"item.onlyfun.nourra_firework": "Фейерверк Нурры",
|
||||
"item.onlyfun.chrism_firework": "Фейерверк ChrisM",
|
||||
"item.onlyfun.kaninscheun_firework": "Фейерверк Kaninscheun",
|
||||
"item.onlyfun.poupoutain_firework": "Фейерверк Poupoutain",
|
||||
"item.onlyfun.lbeast_firework": "Фейерверк lBeast",
|
||||
"item.onlyfun.creveforest_firework": "Фейерверк CreveForest",
|
||||
"item.onlyfun.sacdchips_firework": "Фейерверк SacDChips",
|
||||
"item.onlyfun.vaselline_firework": "Фейерверк Vaselline",
|
||||
"item.onlyfun.duncan_firework": "Фейерверк Duncan",
|
||||
"tooltip.onlyfun.nourra_firework": "Взрыв рисует лицо скина обычного или увеличенного размера.",
|
||||
"tooltip.onlyfun.skin_face_firework": "Взрыв рисует лицо скина обычного или увеличенного размера.",
|
||||
"item.onlyfun.quality_gear": "Качественное снаряжение",
|
||||
"item.onlyfun.impossible_tool": "Невозможный инструмент",
|
||||
"item.onlyfun.impossible_book": "Невозможная книга",
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/chrism_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/creveforest_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/duncan_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/kaninscheun_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/lbeast_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/nourra_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/poupoutain_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/sacdchips_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"parent": "minecraft:item/generated",
|
||||
"textures": {
|
||||
"layer0": "onlyfun:item/vaselline_firework"
|
||||
}
|
||||
}
|
||||
|
After Width: | Height: | Size: 246 B |
|
After Width: | Height: | Size: 261 B |
|
After Width: | Height: | Size: 247 B |
|
After Width: | Height: | Size: 197 B |
|
After Width: | Height: | Size: 359 B |
|
After Width: | Height: | Size: 280 B |
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 317 B |
|
After Width: | Height: | Size: 209 B |
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:red_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:chrism_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:green_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:creveforest_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:pink_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:duncan_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:yellow_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:kaninscheun_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:brown_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:lbeast_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:light_blue_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:nourra_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:light_gray_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:poupoutain_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:orange_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:sacdchips_firework"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"type": "minecraft:crafting_shapeless",
|
||||
"category": "misc",
|
||||
"ingredients": [
|
||||
"minecraft:firework_rocket",
|
||||
"minecraft:white_dye",
|
||||
"minecraft:paper"
|
||||
],
|
||||
"result": {
|
||||
"count": 1,
|
||||
"id": "onlyfun:vaselline_firework"
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,13 @@
|
||||
"fr.koka99cab.sanctuary26.onlyfun.client.OnlyFunClient"
|
||||
]
|
||||
},
|
||||
"mixins": [
|
||||
"onlyfun.mixins.json",
|
||||
{
|
||||
"config": "onlyfun.client.mixins.json",
|
||||
"environment": "client"
|
||||
}
|
||||
],
|
||||
"depends": {
|
||||
"fabricloader": ">=0.19.3",
|
||||
"minecraft": "~26.2",
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "fr.koka99cab.sanctuary26.onlyfun.mixin.client",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"client": [
|
||||
"FireworkRocketEntityMixin",
|
||||
"ParticleLifetimeAccessor"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"required": true,
|
||||
"package": "fr.koka99cab.sanctuary26.onlyfun.mixin",
|
||||
"compatibilityLevel": "JAVA_25",
|
||||
"mixins": [
|
||||
"FireworkRocketLifetimeMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.item;
|
||||
|
||||
import fr.koka99cab.sanctuary26.onlyfun.client.SkinFaceFireworkClient;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.server.Bootstrap;
|
||||
import net.minecraft.world.item.component.Fireworks;
|
||||
|
||||
/** Executable check for baked skin-face firework portraits. */
|
||||
public final class SkinFaceFireworkSmoke {
|
||||
private SkinFaceFireworkSmoke() {
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
SharedConstants.tryDetectVersion();
|
||||
Bootstrap.bootStrap();
|
||||
verify();
|
||||
}
|
||||
|
||||
public static void verify() {
|
||||
require(SkinFacePortrait.values().length == 9, "Skin firework roster drifted");
|
||||
require(SkinFacePortrait.WIDTH == 8 && SkinFacePortrait.HEIGHT == 8,
|
||||
"Face grid is no longer 8×8");
|
||||
for (SkinFacePortrait portrait : SkinFacePortrait.values()) {
|
||||
require(portrait.face().length == 64, portrait.id() + " face palette length drifted");
|
||||
require(portrait.hood().length == 64, portrait.id() + " hood overlay length drifted");
|
||||
require(portrait.hoodTop().length == 16, portrait.id() + " hood top strip length drifted");
|
||||
int[] pixels = portrait.portrait();
|
||||
require(pixels.length == 80 && portrait.portraitHeight() == 10,
|
||||
portrait.id() + " portrait grid drifted");
|
||||
require(portrait.itemId().equals(portrait.id() + "_firework"),
|
||||
portrait.id() + " item id drifted");
|
||||
}
|
||||
require(SkinFacePortrait.NOURRA.face()[5 * 8 + 2] == 0x4A9DFC
|
||||
&& SkinFacePortrait.NOURRA.face()[5 * 8 + 5] == 0x4A9DFC,
|
||||
"Blue eyes are missing from the Nourra face");
|
||||
require(SkinFacePortrait.NOURRA.face()[4 * 8 + 3] == 0xFFF0E1,
|
||||
"Skin tone is missing from the baked Nourra face");
|
||||
require(SkinFacePortrait.NOURRA.hood()[2] == 0xCBCBCB,
|
||||
"Hood overlay is missing from the top of the Nourra face");
|
||||
require(SkinFacePortrait.NOURRA.hood()[5 * 8 + 2] == 0x181818,
|
||||
"Nourra hood no longer covers the left eye");
|
||||
require(SkinFacePortrait.NOURRA.hood()[5 * 8 + 5] == SkinFacePortrait.TRANSPARENT,
|
||||
"Nourra hood opening no longer leaves the right eye visible");
|
||||
require(SkinFacePortrait.NOURRA.opaqueHoodPixels() == 43,
|
||||
"Opaque Nourra hood pixel count drifted");
|
||||
int[] nourra = SkinFacePortrait.NOURRA.portrait();
|
||||
require(nourra[16 + 5 * 8 + 5] == 0x4A9DFC,
|
||||
"Right eye is missing from the composited Nourra portrait");
|
||||
require(nourra[2] == 0xD8D8D8,
|
||||
"Hood top is missing from the Nourra portrait");
|
||||
require(SkinFacePortrait.CHRISM.face()[6 * 8 + 1] == 0xFFFFFF,
|
||||
"ChrisM eyes are missing from the baked face");
|
||||
require(SkinFacePortrait.DUNCAN.face().length == 64,
|
||||
"Duncan face is missing");
|
||||
Fireworks fireworks = SkinFaceFireworkExplosions.defaultFireworks();
|
||||
require(fireworks.flightDuration() == 3 && fireworks.explosions().isEmpty(),
|
||||
"Default firework burst contract changed");
|
||||
require(SkinFaceFireworkExplosions.LIFETIME_TRIM_TICKS == 5
|
||||
&& SkinFaceFireworkExplosions.midFlightLifetime(45) == 40,
|
||||
"Mid-flight lifetime trim drifted");
|
||||
require(SkinFaceFireworkClient.PIXEL == 1.85D, "Portrait scale drifted");
|
||||
require(SkinFaceFireworkClient.LARGE_PIXEL == 2.7D, "Large portrait scale drifted");
|
||||
require(SkinFaceFireworkClient.burstPixel(false) == SkinFaceFireworkClient.PIXEL
|
||||
&& SkinFaceFireworkClient.burstSparkSize(false) == SkinFaceFireworkClient.SPARK_SIZE,
|
||||
"Normal burst scale drifted");
|
||||
require(SkinFaceFireworkClient.burstPixel(true) == SkinFaceFireworkClient.LARGE_PIXEL
|
||||
&& SkinFaceFireworkClient.burstSparkSize(true) == SkinFaceFireworkClient.LARGE_SPARK_SIZE,
|
||||
"Large burst scale drifted");
|
||||
require(SkinFaceFireworkClient.SPARK_LIFETIME_TICKS == 38, "Spark lifetime drifted");
|
||||
System.out.println("Only Fun skin fireworks: 9 baked faces with hood overlay ready.");
|
||||
}
|
||||
|
||||
private static void require(boolean condition, String message) {
|
||||
if (!condition) throw new IllegalStateException(message);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package fr.koka99cab.sanctuary26.onlyfun.loot;
|
||||
|
||||
import fr.koka99cab.sanctuary26.onlyfun.item.SkinFaceFireworkSmoke;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.shop.OnlyFunShopCatalogSmoke;
|
||||
import fr.koka99cab.sanctuary26.onlyfun.world.CobbleDungeonPlacementSmoke;
|
||||
import java.util.EnumMap;
|
||||
@@ -18,6 +19,7 @@ public final class OnlyFunGeneratorSmoke {
|
||||
Bootstrap.bootStrap();
|
||||
OnlyFunShopCatalogSmoke.verify();
|
||||
CobbleDungeonPlacementSmoke.verify();
|
||||
SkinFaceFireworkSmoke.verify();
|
||||
OnlyFunGenerator.initialize();
|
||||
require(OnlyFunGenerator.ANOMALY_DENOMINATOR == 256, "Anomaly odds changed from 1/256");
|
||||
require(OnlyFunGenerator.PITY_START == 24, "Pity threshold changed");
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"status": "released",
|
||||
"source": {
|
||||
"pack_version": "26.2.0-alpha.242",
|
||||
"modules": {
|
||||
"sanctuary": "0.0.0-alpha.139",
|
||||
"onlyfun": "0.0.0-alpha.27"
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"pack_version": "26.2.0-alpha.243",
|
||||
"modules": {
|
||||
"sanctuary": "0.0.0-alpha.140",
|
||||
"onlyfun": "0.0.0-alpha.28"
|
||||
}
|
||||
},
|
||||
"integrated_pull_requests": [172, 173, 174],
|
||||
"shop_catalog": {
|
||||
"local_search": true,
|
||||
"accent_folding": true,
|
||||
"grid_sizes": [3, 4, 5],
|
||||
"grid_preference_persisted": true,
|
||||
"page_counter": true,
|
||||
"flash_sales_unchanged": true
|
||||
},
|
||||
"quest_board": {
|
||||
"stale_sign_resynchronized_after_unloaded_rotation": true,
|
||||
"operator_refresh_rerolls_contract": true,
|
||||
"displayed_contract_matches_claimed_contract": true
|
||||
},
|
||||
"nourra_firework": {
|
||||
"registry_id": "onlyfun:nourra_firework",
|
||||
"skin_face_and_hood_particles": true,
|
||||
"normal_and_large_bursts": true,
|
||||
"vanilla_colored_burst_suppressed": true,
|
||||
"languages": ["en_us", "fr_fr", "ru_ru"]
|
||||
},
|
||||
"compatibility": {
|
||||
"existing_saves_supported": true,
|
||||
"world_reset_required": false,
|
||||
"save_migration_required": false,
|
||||
"persistent_data_formats_changed": false,
|
||||
"network_protocols_changed": false,
|
||||
"sanctuary_data_version": 15,
|
||||
"sanctuary_network_protocol": 24,
|
||||
"onlyfun_data_version": 2,
|
||||
"onlyfun_network_protocol": 3,
|
||||
"client_server_update_required": true
|
||||
},
|
||||
"distribution": {
|
||||
"pack_release_updated": true,
|
||||
"packwiz_index_refreshed": true,
|
||||
"prism_modrinth_index_updated": true,
|
||||
"shared_client_server_mrpack": true,
|
||||
"distributed_module_count": 10
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"status": "released",
|
||||
"source": {
|
||||
"pack_version": "26.2.0-alpha.243",
|
||||
"modules": {
|
||||
"onlyfun": "0.0.0-alpha.28"
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"pack_version": "26.2.0-alpha.244",
|
||||
"modules": {
|
||||
"onlyfun": "0.0.0-alpha.29"
|
||||
}
|
||||
},
|
||||
"integrated_pull_requests": [176],
|
||||
"skin_fireworks": {
|
||||
"existing_portrait_preserved": "onlyfun:nourra_firework",
|
||||
"new_portraits": [
|
||||
"onlyfun:chrism_firework",
|
||||
"onlyfun:kaninscheun_firework",
|
||||
"onlyfun:poupoutain_firework",
|
||||
"onlyfun:lbeast_firework",
|
||||
"onlyfun:creveforest_firework",
|
||||
"onlyfun:sacdchips_firework",
|
||||
"onlyfun:vaselline_firework",
|
||||
"onlyfun:duncan_firework"
|
||||
],
|
||||
"portrait_size": [8, 8],
|
||||
"hood_overlay": true,
|
||||
"camera_facing_particles": true,
|
||||
"normal_and_large_bursts": true,
|
||||
"shapeless_recipes": {
|
||||
"chrism": "minecraft:red_dye",
|
||||
"kaninscheun": "minecraft:yellow_dye",
|
||||
"poupoutain": "minecraft:light_gray_dye",
|
||||
"lbeast": "minecraft:brown_dye",
|
||||
"creveforest": "minecraft:green_dye",
|
||||
"sacdchips": "minecraft:orange_dye",
|
||||
"vaselline": "minecraft:white_dye",
|
||||
"duncan": "minecraft:pink_dye"
|
||||
},
|
||||
"languages": ["en_us", "fr_fr", "ru_ru"]
|
||||
},
|
||||
"compatibility": {
|
||||
"existing_saves_supported": true,
|
||||
"world_reset_required": false,
|
||||
"save_migration_required": false,
|
||||
"persistent_data_formats_changed": false,
|
||||
"network_protocols_changed": false,
|
||||
"onlyfun_data_version": 2,
|
||||
"onlyfun_network_protocol": 3,
|
||||
"client_server_update_required": true
|
||||
},
|
||||
"distribution": {
|
||||
"pack_release_updated": true,
|
||||
"packwiz_index_refreshed": true,
|
||||
"prism_modrinth_index_updated": true,
|
||||
"shared_client_server_mrpack": true,
|
||||
"distributed_module_count": 10
|
||||
}
|
||||
}
|
||||
@@ -57,8 +57,8 @@ hash = "a5538de6d9c38cf37ff0882451fd025c8a24c7cb250482baa4ca5918d1129b06"
|
||||
metafile = true
|
||||
|
||||
[[files]]
|
||||
file = "mods/onlyfun-0.0.0-alpha.27.jar"
|
||||
hash = "dcd5003390c132f3421c12550f851846548b4d1cc541d3ada0deb35c65bb3f54"
|
||||
file = "mods/onlyfun-0.0.0-alpha.29.jar"
|
||||
hash = "c55a23de665475c95c3e5fe085097e3a09bfdf389ca61575161377482deb292a"
|
||||
|
||||
[[files]]
|
||||
file = "mods/ouch-0.0.0-alpha.11.jar"
|
||||
@@ -69,8 +69,8 @@ file = "mods/redstoner-0.0.0-alpha.20.jar"
|
||||
hash = "39f0cba6213e4efcd40b8b72cf7812b56315e1d637803a87a2672b00bc4ee4a0"
|
||||
|
||||
[[files]]
|
||||
file = "mods/sanctuary-0.0.0-alpha.139.jar"
|
||||
hash = "22a37980bd7b121cbfe65e853a6c6a9f8549bbf4af9b4fdd5f22dbd04df273b0"
|
||||
file = "mods/sanctuary-0.0.0-alpha.140.jar"
|
||||
hash = "f13f793dea9300543280eb761862c45e9ad86a299c4d1efa11eb7af83d2b7891"
|
||||
|
||||
[[files]]
|
||||
file = "mods/simple-voice-chat.pw.toml"
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
name = "Sanctuary 26.2"
|
||||
author = "KOKA99CAB"
|
||||
version = "26.2.0-alpha.242"
|
||||
version = "26.2.0-alpha.244"
|
||||
pack-format = "packwiz:1.1.0"
|
||||
|
||||
[index]
|
||||
file = "index.toml"
|
||||
hash-format = "sha256"
|
||||
hash = "0a55cea4e39c4df93a2d52133295afdf55798e23516f1209cab56d50e5339051"
|
||||
hash = "e31218336db4e25008fa5203ab85cbb85172d0b21425b77ec5bfb20949d5ea3e"
|
||||
|
||||
[versions]
|
||||
fabric = "0.19.3"
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"game": "minecraft",
|
||||
"name": "Sanctuary 26.2",
|
||||
"summary": "Sanctuary 26.2 — progression, exploration, worldgen and multiplayer systems by KOKA99CAB.",
|
||||
"versionId": "26.2.0-alpha.242",
|
||||
"versionId": "26.2.0-alpha.244",
|
||||
"files": [
|
||||
{
|
||||
"path": "mods/fabric-api-0.159.0+26.2.jar",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"pack_version": "26.2.0-alpha.242",
|
||||
"pack_version": "26.2.0-alpha.244",
|
||||
"release_channel": "alpha",
|
||||
"minecraft_version": "26.2",
|
||||
"fabric_loader_version": "0.19.3",
|
||||
@@ -9,7 +9,7 @@
|
||||
"project_id": "FgOqyAXd",
|
||||
"project_slug": "sanctuary-koka99",
|
||||
"project_url": "https://modrinth.com/modpack/sanctuary-koka99",
|
||||
"primary_file": "sanctuary-26.2.0-alpha.242.mrpack",
|
||||
"primary_file": "sanctuary-26.2.0-alpha.244.mrpack",
|
||||
"shared_client_server_pack": true,
|
||||
"update_owner": "packwiz-installer",
|
||||
"check_on_launch": true,
|
||||
|
||||
@@ -223,7 +223,7 @@ tasks.register("verifyBlackMarket") {
|
||||
def questData = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java").text
|
||||
def quests = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardService.java").text
|
||||
def inventoryView = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| !data.contains('SAVE_KEY = "black_market"') || !data.contains("DATA_VERSION = 2")
|
||||
|| !data.contains("ItemStack.CODEC.fieldOf(\"item\")") || !data.contains("replaceListing")
|
||||
|| !service.contains("LISTING_FEE_RUBIES = 1") || !service.contains("COMMISSION_PERCENT = 5")
|
||||
@@ -252,7 +252,9 @@ tasks.register("verifyBlackMarket") {
|
||||
|| !quests.contains("SanctuaryRegistries.questBoardTier")
|
||||
|| quests.contains("activationTier(")
|
||||
|| quests.contains("QuestBoardTier.ACTIVATION_COST")
|
||||
|| !quests.contains("addTreasury(claim.depositCurrency(), claim.depositAmount())")) {
|
||||
|| !quests.contains("addTreasury(claim.depositCurrency(), claim.depositAmount())")
|
||||
|| !quests.contains("shouldRewriteSign")
|
||||
|| !quests.contains("syncLoadedSigns")) {
|
||||
throw new GradleException("The physical Black Market escrow/delivery contract is incomplete")
|
||||
}
|
||||
}
|
||||
@@ -2940,7 +2942,7 @@ tasks.register("verifyShopCurrencyRowsRelease") {
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java").text
|
||||
def shop = file(
|
||||
"src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.117"
|
||||
|| migration.shop_currency_inventory?.all_unlocked_rows_counted != true
|
||||
|| migration.shop_currency_inventory?.overflow_rows_counted != true
|
||||
@@ -3106,7 +3108,7 @@ tasks.register("verifyProgressivePauseMenu") {
|
||||
"pack/migrations/26.2.0-alpha.190-progressive-pause-menu-to-alpha.191.json"))
|
||||
def pauseMenu = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/PauseScreenMixin.java").text
|
||||
def costs = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/progression/SanctuaryProgressionCosts.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.191"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.109"
|
||||
|| migration.pause_menu?.progression_full_width != true
|
||||
@@ -3144,7 +3146,7 @@ tasks.register("verifyShopPricingLayout") {
|
||||
"pack/migrations/26.2.0-alpha.192-shop-pricing-layout-to-alpha.193.json"))
|
||||
def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryShopScreen.java").text
|
||||
def progression = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopProgression.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.110"
|
||||
|| migration.shop_layout?.locked_offer_buttons != 6
|
||||
|| migration.shop_layout?.button_slots != [4, 5, 6, 7, 8, 9]
|
||||
@@ -3175,7 +3177,7 @@ tasks.register("verifyShopCsvBossGates") {
|
||||
"pack/migrations/26.2.0-alpha.194-shop-csv-boss-gates-to-alpha.195.json"))
|
||||
def provider = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopCatalogProvider.java").text
|
||||
def catalog = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.195"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.111"
|
||||
|| migration.compatibility?.sanctuary_data_version != 11
|
||||
@@ -3206,7 +3208,7 @@ tasks.register("verifyDeliveryBoxOrientation") {
|
||||
def blockstate = new JsonSlurper().parse(
|
||||
file("src/main/resources/assets/sanctuary/blockstates/delivery_box.json"))
|
||||
def expectedVariants = ["facing=north", "facing=east", "facing=south", "facing=west"].toSet()
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.112"
|
||||
|| migration.mailbox?.id != "sanctuary:delivery_box"
|
||||
|| migration.mailbox?.horizontal_facing != true
|
||||
@@ -3234,7 +3236,7 @@ tasks.register("verifyInventoryShiftClick") {
|
||||
def mixin = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/AbstractContainerMenuMixin.java").text
|
||||
def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/AbstractContainerScreenMixin.java").text
|
||||
def gui = file("INVENTORY_GUI.md").text
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| !transfer.contains("shouldAppendOverflow")
|
||||
|| !transfer.contains("isVanillaStorageRange")
|
||||
|| !transfer.contains("hotbarStart")
|
||||
@@ -3280,7 +3282,7 @@ tasks.register("verifyQuestRequests") {
|
||||
new JsonSlurper().parse(file("src/main/resources/data/sanctuary/loot_table/blocks/${path}.json"))
|
||||
.pools[0].entries[0].name
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.113"
|
||||
|| migration.quest_requests?.save_key != "quest_requests"
|
||||
|| migration.quest_requests?.data_version != 1
|
||||
@@ -3342,7 +3344,7 @@ tasks.register("verifyQuestRequestContracts") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collectEntries { locale ->
|
||||
[(locale): new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${locale}.json"))]
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.198"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.114"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.199"
|
||||
@@ -3411,7 +3413,7 @@ tasks.register("verifyQuestRequestEscrow") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collectEntries { locale ->
|
||||
[(locale): new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${locale}.json"))]
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.200"
|
||||
|| migration.source?.modules?.sanctuary != "0.0.0-alpha.115"
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.201"
|
||||
@@ -3490,7 +3492,7 @@ tasks.register("verifyCraftableBannerCape") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collect {
|
||||
new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${it}.json"))
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.130"
|
||||
|| migration.white_cape?.crafting_material_count != 6
|
||||
|| migration.white_cape?.maximum_pattern_layers != 6
|
||||
@@ -3542,7 +3544,7 @@ tasks.register("verifyFinalSanctuaryTickets") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collect {
|
||||
new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${it}.json"))
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| !capeRenderer.contains("SHIELD_FACE_WIDTH = 12.0F")
|
||||
|| !capeRenderer.contains("SHIELD_FACE_HEIGHT = 22.0F")
|
||||
|| !capeRenderer.contains("CAPE_WIDTH / SHIELD_FACE_WIDTH")
|
||||
@@ -3596,7 +3598,7 @@ tasks.register("verifyAlphaIndev") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collect {
|
||||
new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${it}.json"))
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.target?.modules?.sanctuary != "0.0.0-alpha.122"
|
||||
|| migration.alpha_world?.dimension != "sanctuary:alpha"
|
||||
|| migration.alpha_world?.legacy_dimension != "portals:alpha"
|
||||
@@ -3656,7 +3658,7 @@ tasks.register("verifyBackroom") {
|
||||
def locales = ["fr_fr", "en_us", "ru_ru"].collect {
|
||||
new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${it}.json"))
|
||||
}
|
||||
if (project.version.toString() != "0.0.0-alpha.139"
|
||||
if (project.version.toString() != "0.0.0-alpha.140"
|
||||
|| migration.source_data_version != 13 || migration.target_data_version != 14
|
||||
|| migration.integration_modules?.anotherworld?.source != "0.0.0-alpha.56"
|
||||
|| migration.integration_modules?.anotherworld?.target != "0.0.0-alpha.57"
|
||||
|
||||
@@ -75,9 +75,12 @@ final class QuestBoardGenerator {
|
||||
private QuestBoardGenerator() {}
|
||||
|
||||
static QuestBoardData.Contract generate(MinecraftServer server, String boardId, QuestBoardTier tier, long now) {
|
||||
long day = Math.floorDiv(now, 86_400_000L);
|
||||
long seed = boardId.hashCode() * 0x9E3779B97F4A7C15L ^ day * 0xD1B54A32D192ED03L ^ tier.ordinal();
|
||||
RandomSource random = RandomSource.create(seed);
|
||||
return generate(server, boardId, tier, now, Math.floorDiv(now, 86_400_000L));
|
||||
}
|
||||
|
||||
static QuestBoardData.Contract generate(MinecraftServer server, String boardId, QuestBoardTier tier,
|
||||
long now, long salt) {
|
||||
RandomSource random = RandomSource.create(contractSeed(boardId, tier, salt));
|
||||
List<Template> pool = switch (tier) {
|
||||
case EMERALD -> EASY;
|
||||
case RUBY -> MEDIUM;
|
||||
@@ -93,6 +96,10 @@ final class QuestBoardGenerator {
|
||||
java.util.Optional.empty(), now);
|
||||
}
|
||||
|
||||
static long contractSeed(String boardId, QuestBoardTier tier, long salt) {
|
||||
return boardId.hashCode() * 0x9E3779B97F4A7C15L ^ salt * 0xD1B54A32D192ED03L ^ tier.ordinal();
|
||||
}
|
||||
|
||||
static long nextRefreshAt(String boardId, long now) {
|
||||
LocalDate tomorrow = Instant.ofEpochMilli(now).atZone(ZoneOffset.UTC).toLocalDate().plusDays(1);
|
||||
long midnight = tomorrow.atStartOfDay(ZoneOffset.UTC).toInstant().toEpochMilli();
|
||||
|
||||
@@ -262,17 +262,17 @@ public final class QuestBoardService {
|
||||
}
|
||||
|
||||
private static void tick(MinecraftServer server) {
|
||||
QuestBoardData data = QuestBoardData.get(server);
|
||||
syncLoadedSigns(server, data);
|
||||
if (++tickCounter < 20) return;
|
||||
tickCounter = 0;
|
||||
long now = System.currentTimeMillis();
|
||||
QuestBoardData data = QuestBoardData.get(server);
|
||||
for (QuestBoardData.Board board : data.boards()) {
|
||||
ServerLevel level = level(server, board.dimension());
|
||||
BlockPos pos = BlockPos.of(board.pos());
|
||||
if (level != null && level.isLoaded(pos) && !(level.getBlockEntity(pos) instanceof SignBlockEntity)) {
|
||||
removeBoard(server, data, board, "server", "sign_missing", true); continue;
|
||||
}
|
||||
if (level != null && level.isLoaded(pos) && refreshedSignLayouts.add(board.id())) refreshSign(server, board);
|
||||
QuestBoardData.Contract contract = board.contract().orElse(null);
|
||||
if (contract != null && contract.claim().isPresent() && now >= contract.claim().get().deadlineAt()) {
|
||||
QuestBoardData.Claim claim = contract.claim().get();
|
||||
@@ -288,18 +288,41 @@ public final class QuestBoardService {
|
||||
}
|
||||
if (!board.frozen() && now >= board.nextRefreshAt()
|
||||
&& (contract == null || contract.claim().isEmpty())) {
|
||||
QuestBoardData.Contract generated = QuestBoardGenerator.generate(server, board.id(), board.questTier(), now);
|
||||
QuestBoardData.Board refreshed = board.withContract(Optional.of(generated),
|
||||
QuestBoardGenerator.nextRefreshAt(board.id(), now));
|
||||
QuestBoardData.Board latest = data.board(board.id()).orElse(null);
|
||||
if (latest == null || latest.frozen()
|
||||
|| latest.contract().flatMap(QuestBoardData.Contract::claim).isPresent()) continue;
|
||||
QuestBoardData.Contract generated = QuestBoardGenerator.generate(server, board.id(), latest.questTier(), now);
|
||||
QuestBoardData.Board refreshed = latest.withContract(Optional.of(generated),
|
||||
QuestBoardGenerator.nextRefreshAt(latest.id(), now));
|
||||
data.replace(refreshed);
|
||||
data.audit(new QuestBoardData.AuditEntry(now, "refresh", "server", board.id(), generated.id(), "daily"));
|
||||
data.audit(new QuestBoardData.AuditEntry(now, "refresh", "server", latest.id(), generated.id(), "daily"));
|
||||
refreshSign(server, refreshed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void syncLoadedSigns(MinecraftServer server, QuestBoardData data) {
|
||||
for (QuestBoardData.Board board : data.boards()) {
|
||||
ServerLevel level = level(server, board.dimension());
|
||||
BlockPos pos = BlockPos.of(board.pos());
|
||||
boolean loaded = level != null && level.isLoaded(pos);
|
||||
if (!shouldRewriteSign(refreshedSignLayouts, board.id(), loaded)) continue;
|
||||
refreshSign(server, board);
|
||||
}
|
||||
}
|
||||
|
||||
/** A loaded board whose layout was forgotten (chunk unload or failed write) must be rewritten. */
|
||||
static boolean shouldRewriteSign(Set<String> syncedLayouts, String boardId, boolean chunkLoaded) {
|
||||
if (!chunkLoaded) {
|
||||
syncedLayouts.remove(boardId);
|
||||
return false;
|
||||
}
|
||||
return syncedLayouts.add(boardId);
|
||||
}
|
||||
|
||||
private static void removeBoard(MinecraftServer server, QuestBoardData data, QuestBoardData.Board board,
|
||||
String actor, String reason, boolean refundDeposit) {
|
||||
refreshedSignLayouts.remove(board.id());
|
||||
if (!data.remove(board)) return;
|
||||
long now = System.currentTimeMillis();
|
||||
board.contract().flatMap(QuestBoardData.Contract::claim).ifPresent(claim -> {
|
||||
@@ -330,7 +353,8 @@ public final class QuestBoardService {
|
||||
QuestBoardData.Board board = resolve(data, id);
|
||||
if (board == null || board.contract().flatMap(QuestBoardData.Contract::claim).isPresent()) return false;
|
||||
long now = System.currentTimeMillis();
|
||||
QuestBoardData.Contract contract = QuestBoardGenerator.generate(server, board.id(), board.questTier(), now);
|
||||
QuestBoardData.Contract contract = QuestBoardGenerator.generate(server, board.id(), board.questTier(), now,
|
||||
now ^ UUID.randomUUID().getMostSignificantBits());
|
||||
QuestBoardData.Board updated = board.withContract(Optional.of(contract), QuestBoardGenerator.nextRefreshAt(board.id(), now));
|
||||
data.replace(updated);
|
||||
data.audit(new QuestBoardData.AuditEntry(now, "operator_refresh", actor, board.id(), contract.id(), ""));
|
||||
@@ -338,11 +362,15 @@ public final class QuestBoardService {
|
||||
return true;
|
||||
}
|
||||
|
||||
static void refreshSign(MinecraftServer server, QuestBoardData.Board board) {
|
||||
static boolean refreshSign(MinecraftServer server, QuestBoardData.Board board) {
|
||||
ServerLevel level = level(server, board.dimension());
|
||||
BlockPos pos = BlockPos.of(board.pos());
|
||||
if (level != null && level.isLoaded(pos) && level.getBlockEntity(pos) instanceof SignBlockEntity sign)
|
||||
if (level != null && level.isLoaded(pos) && level.getBlockEntity(pos) instanceof SignBlockEntity sign) {
|
||||
writeSign(level, sign, board);
|
||||
return true;
|
||||
}
|
||||
refreshedSignLayouts.remove(board.id());
|
||||
return false;
|
||||
}
|
||||
|
||||
private static void writeSign(ServerLevel level, SignBlockEntity sign, QuestBoardData.Board board) {
|
||||
@@ -370,6 +398,7 @@ public final class QuestBoardService {
|
||||
sign.setWaxed(true);
|
||||
sign.setChanged();
|
||||
level.sendBlockUpdated(sign.getBlockPos(), sign.getBlockState(), sign.getBlockState(), 3);
|
||||
refreshedSignLayouts.add(board.id());
|
||||
}
|
||||
|
||||
private static void inspect(ServerPlayer player, QuestBoardData.Board board) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package fr.koka99cab.sanctuary26.sanctuary.shop;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
|
||||
@@ -39,6 +41,25 @@ public final class QuestBoardModelSmoke {
|
||||
long refresh = QuestBoardGenerator.nextRefreshAt("board", now);
|
||||
require(refresh > now && refresh - now < 28L * 60L * 60L * 1_000L,
|
||||
"Daily refresh escaped its UTC window");
|
||||
long day = Math.floorDiv(now, 86_400_000L);
|
||||
require(QuestBoardGenerator.contractSeed("board", QuestBoardTier.RUBY, day)
|
||||
== QuestBoardGenerator.contractSeed("board", QuestBoardTier.RUBY, day),
|
||||
"Daily contracts on the same UTC day must stay deterministic");
|
||||
require(QuestBoardGenerator.contractSeed("board", QuestBoardTier.RUBY, day)
|
||||
!= QuestBoardGenerator.contractSeed("board", QuestBoardTier.RUBY, now),
|
||||
"An operator refresh must not reuse the daily seed");
|
||||
Set<String> layouts = new HashSet<>();
|
||||
require(!QuestBoardService.shouldRewriteSign(layouts, "board", false),
|
||||
"An unloaded board must not rewrite its sign");
|
||||
require(layouts.isEmpty(), "Unloading must forget the cached sign layout");
|
||||
require(QuestBoardService.shouldRewriteSign(layouts, "board", true),
|
||||
"The first load after a rotation must rewrite the sign from saved data");
|
||||
require(!QuestBoardService.shouldRewriteSign(layouts, "board", true),
|
||||
"A still-loaded board must not rewrite its sign every tick");
|
||||
require(!QuestBoardService.shouldRewriteSign(layouts, "board", false),
|
||||
"Leaving the chunk must forget the layout without rewriting");
|
||||
require(QuestBoardService.shouldRewriteSign(layouts, "board", true),
|
||||
"Returning after an unloaded daily refresh must rewrite the new contract");
|
||||
}
|
||||
|
||||
private static void require(boolean value, String message) {
|
||||
|
||||