fix(anotherworld): coffre-fort creux 3×3×3 #23

Merged
koka merged 1 commits from fix/safe-vault-3x3x3 into main 2026-08-27 15:50:21 +00:00
16 changed files with 323 additions and 93 deletions
+11
View File
@@ -6,6 +6,17 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve
- Depuis `26.2.0-alpha.6`, le pack et les modules ont des versions indépendantes. I Like To Move It et Only Fun deviennent les cinquième et sixième modules actifs dans l'alpha 46.
- Les versions ci-dessous ont été reconstituées à partir des JAR archivés, des packs locaux et du code source actuel. Les dates n'étant pas enregistrées de manière fiable, elles ne sont pas inventées.
## En développement — coffre-fort creux 3 × 3 × 3
Module modifié : **Another World `0.0.0-alpha.53`**. Le pack distribué reste en **`26.2.0-alpha.204`**.
- remplace le mur de neuf Safe Blocks par une coque creuse de 26 blocs disposés en 3 × 3 × 3 ;
- laisse le bloc central entièrement libre afin de pouvoir y cacher nimporte quel bloc ;
- refuse les murs 3 × 3, les cubes pleins et toute structure à laquelle un Safe Block supplémentaire est attaché ;
- répartit les textures 48×48 sur chacune des faces extérieures du cube, avec la façade, le dessus, le dessous et les côtés/arrière ;
- conserve les anciennes valeurs de blockstate pour permettre le chargement et le démontage des murs existants, qui doivent être reconstruits en cube ;
- préserve les comptes, les 27 emplacements de stockage, les soldes et le protocole réseau ; Another World passe à la donnée v4 et `safe_vaults` à la donnée v3.
## `26.2.0-alpha.204`
Module modifié : **Another World `0.0.0-alpha.52`**. Les neuf autres modules conservent leur version issue de lalpha.203.
+4 -2
View File
@@ -22,7 +22,9 @@ 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.204`**. Another World passe en **`0.0.0-alpha.52`** ; les neuf autres modules conservent leur version de lalpha.203.
Version courante du pack distribué : **`26.2.0-alpha.204`**. Dans le workspace, la correction cubique du Safe Block porte Another World en développement à **`0.0.0-alpha.53`** sans produire une nouvelle version du pack.
Another World alpha.53 exige une coque creuse de **3 × 3 × 3**, soit 26 Safe Blocks appartenant au même joueur. Le centre est libre et peut contenir un bloc caché. Les quatre images 48×48 se répartissent sur les faces extérieures du cube : façade, dessus, dessous et côtés/arrière. Un ancien mur 3 × 3 ne sactive plus et doit être démonté puis reconstruit ; les comptes et soldes existants restent conservés.
Lalpha.204 finalise le Safe Block vertical et actualise JEI en **`30.27.0.188`** : sa texture individuelle 16×16 est chargée avant formation, les structures incomplètes 3 × 1 sont refusées et le CTM 48×48 exige les neuf blocs. Linterface monétaire affiche désormais correctement l’émeraude et place linventaire étendu sous les trois lignes de monnaie.
@@ -30,7 +32,7 @@ Lalpha.203 porte Another World en **`0.0.0-alpha.51`** et JEI en **`30.27.0.1
Lalpha.202 permet de descendre par un ascenseur de Waystones vers l’étage immédiatement inférieur encore inconnu, sans ouvrir la montée ni les trajets ordinaires aux destinations non découvertes. Le Shop et le marché noir comptent et consomment désormais les rubis et saphirs de toutes les rangées débloquées, y compris loverflow. Le livre culinaire peut enfin être posé sur un pupitre vanilla pour partager le catalogue de recettes de son propriétaire ; retiré du pupitre, il redevient personnel.
Le coffre-fort joueur utilise neuf blocs Another World disposés en mur vertical de 3 × 3. Il conserve les rubis, saphirs et émeraudes dans un compte lié au joueur et les rend disponibles aux transactions du Shop même lorsque la structure est déchargée. Une foreuse en titane maintenue pendant 60 secondes permet de piller 20 % du contenu dun propriétaire connecté, qui reçoit immédiatement une alerte ; une réussite consomme la foreuse et protège ensuite le coffre pendant 24 heures.
Le coffre-fort joueur utilise 26 blocs Another World disposés en coque creuse de 3 × 3 × 3 autour dun centre libre. Il conserve les rubis, saphirs et émeraudes dans un compte lié au joueur et les rend disponibles aux transactions du Shop même lorsque la structure est déchargée. Une foreuse en titane maintenue pendant 60 secondes permet de piller 20 % du contenu dun propriétaire connecté, qui reçoit immédiatement une alerte ; une réussite consomme la foreuse et protège ensuite le coffre pendant 24 heures.
Lalpha.201 rend les demandes communautaires réellement terminables. Le demandeur dépose la récompense lors de la publication, le preneur confirme sans commande après avoir lu les détails, KILL progresse automatiquement, BRING livre les objets au demandeur et PAY est confirmé par le joueur désigné. La récompense séquestrée est ensuite expédiée une seule fois dans la Mailbox du preneur. Le pseudonyme conserve la couleur du joueur et le panneau rose adopte une palette plus claire et poudrée.
+28 -15
View File
@@ -9,7 +9,7 @@ sourceSets.main.resources.srcDir(generatedResources)
tasks.register("vaultRulesSmoke", JavaExec) {
group = "verification"
description = "Checks the 3x3 vault, one-minute raid, 20% loot and 24-hour protection rules."
description = "Checks the hollow 3x3x3 vault, one-minute raid, 20% loot and 24-hour protection rules."
dependsOn tasks.named("testClasses")
classpath = sourceSets.test.runtimeClasspath
mainClass = "fr.koka99cab.sanctuary26.anotherworld.vault.VaultRulesSmoke"
@@ -177,13 +177,24 @@ tasks.register("generateAnotherWorldResources") {
// Mirror, creative-only rainbow blocks, gems and first-pass metal art.
simpleBlock("mirror", "minecraft:block/cube_all", "anotherworld:block/mirror_glass")
def vaultParts = [
def vaultFaceParts = [
[id: "bottom_left", column: 0, row: 0], [id: "bottom_center", column: 1, row: 0],
[id: "bottom_right", column: 2, row: 0], [id: "middle_left", column: 0, row: 1],
[id: "center", column: 1, row: 1], [id: "middle_right", column: 2, row: 1],
[id: "top_left", column: 0, row: 2], [id: "top_center", column: 1, row: 2],
[id: "top_right", column: 2, row: 2]
]
def vaultParts = []
[[prefix: "back", depth: 0], [prefix: null, depth: 1], [prefix: "front", depth: 2]].each { layer ->
vaultFaceParts.each { facePart ->
vaultParts.add([
id: layer.prefix == null ? facePart.id : "${layer.prefix}_${facePart.id}",
column: facePart.column,
row: facePart.row,
depth: layer.depth
])
}
}
def safeMultipart = [[when: [formed: "false"], apply: [model: "anotherworld:block/safe_block_unformed"]]]
[north: 0, east: 90, south: 180, west: 270].each { facing, rotation ->
vaultParts.each { part ->
@@ -203,8 +214,10 @@ tasks.register("generateAnotherWorldResources") {
vaultParts.each { part ->
def frontUv = segmentUv(part.column as int, part.row as int)
def backUv = segmentUv(2 - (part.column as int), part.row as int)
def sideUv = segmentUv(1, part.row as int)
def topUv = segmentUv(part.column as int, 1)
def westUv = segmentUv(2 - (part.depth as int), part.row as int)
def eastUv = segmentUv(part.depth as int, part.row as int)
def topUv = segmentUv(part.column as int, part.depth as int)
def bottomUv = segmentUv(part.column as int, 2 - (part.depth as int))
writeJson("assets/anotherworld/models/block/safe_block/${part.id}.json", [
textures: [
particle: "anotherworld:block/safe_vault/front",
@@ -214,12 +227,12 @@ tasks.register("generateAnotherWorldResources") {
side: "anotherworld:block/safe_vault/side"
],
elements: [[from: [0, 0, 0], to: [16, 16, 16], faces: [
down: [uv: topUv, texture: "#bottom", cullface: "down"],
down: [uv: bottomUv, texture: "#bottom", cullface: "down"],
up: [uv: topUv, texture: "#top", cullface: "up"],
north: [uv: frontUv, texture: "#front", cullface: "north"],
south: [uv: backUv, texture: "#side", cullface: "south"],
west: [uv: sideUv, texture: "#side", cullface: "west"],
east: [uv: sideUv, texture: "#side", cullface: "east"]
west: [uv: westUv, texture: "#side", cullface: "west"],
east: [uv: eastUv, texture: "#side", cullface: "east"]
]]]
])
}
@@ -1622,9 +1635,9 @@ tasks.register("generateAnotherWorldResources") {
"container.anotherworld.safe_vault": "Coffre-fort",
"tooltip.anotherworld.titanium_drill.use": "Maintenir sur un coffre-fort ennemi pour le forer.",
"tooltip.anotherworld.titanium_drill.consumed": "Consommée après un pillage réussi.",
"message.anotherworld.safe_vault.incomplete": "Le coffre-fort exige exactement 9 blocs appartenant au même joueur, posés en mur vertical de 3 × 3.",
"message.anotherworld.safe_vault.incomplete": "Le coffre-fort exige exactement 26 blocs appartenant au même joueur, disposés en coque creuse de 3 × 3 × 3 avec un centre libre.",
"message.anotherworld.safe_vault.locked": "Ce coffre-fort appartient à un autre joueur.",
"message.anotherworld.safe_vault.formed": "Coffre-fort vertical 3 × 3 lié à vous en %s, %s, %s.",
"message.anotherworld.safe_vault.formed": "Coffre-fort creux 3 × 3 × 3 lié à vous en %s, %s, %s.",
"message.anotherworld.safe_vault.deposit_failed": "Impossible de déposer %s : inventaire vide ou coffre-fort plein.",
"message.anotherworld.safe_vault.withdraw_failed": "Impossible de retirer %s : solde vide ou inventaire plein.",
"message.anotherworld.safe_vault.already_owned": "Vous possédez déjà un coffre-fort actif.",
@@ -1646,9 +1659,9 @@ tasks.register("generateAnotherWorldResources") {
"container.anotherworld.safe_vault": "Сейф",
"tooltip.anotherworld.titanium_drill.use": "Удерживайте на чужом сейфе, чтобы просверлить его.",
"tooltip.anotherworld.titanium_drill.consumed": "Расходуется после успешного ограбления.",
"message.anotherworld.safe_vault.incomplete": "Сейф требует вертикальную стену 3 × 3 из 9 блоков одного владельца.",
"message.anotherworld.safe_vault.incomplete": "Сейф требует полую оболочку 3 × 3 × 3 из 26 блоков одного владельца со свободным центром.",
"message.anotherworld.safe_vault.locked": "Этот сейф принадлежит другому игроку.",
"message.anotherworld.safe_vault.formed": "Вертикальный сейф 3 × 3 привязан к вам в точке %s, %s, %s.",
"message.anotherworld.safe_vault.formed": "Полый сейф 3 × 3 × 3 привязан к вам в точке %s, %s, %s.",
"message.anotherworld.safe_vault.deposit_failed": "Не удалось внести %s: предметов нет или сейф заполнен.",
"message.anotherworld.safe_vault.withdraw_failed": "Не удалось забрать %s: баланс пуст или инвентарь заполнен.",
"message.anotherworld.safe_vault.already_owned": "У вас уже есть активный сейф.",
@@ -1670,9 +1683,9 @@ tasks.register("generateAnotherWorldResources") {
"container.anotherworld.safe_vault": "Safe",
"tooltip.anotherworld.titanium_drill.use": "Hold on an enemy safe to drill it.",
"tooltip.anotherworld.titanium_drill.consumed": "Consumed after a successful raid.",
"message.anotherworld.safe_vault.incomplete": "A safe requires an upright 3 × 3 wall of exactly 9 blocks owned by one player.",
"message.anotherworld.safe_vault.incomplete": "A safe requires a hollow 3 × 3 × 3 shell of exactly 26 blocks owned by one player, with a free center.",
"message.anotherworld.safe_vault.locked": "This safe belongs to another player.",
"message.anotherworld.safe_vault.formed": "Upright 3 × 3 safe linked to you at %s, %s, %s.",
"message.anotherworld.safe_vault.formed": "Hollow 3 × 3 × 3 safe linked to you at %s, %s, %s.",
"message.anotherworld.safe_vault.deposit_failed": "Could not deposit %s: none available or the safe is full.",
"message.anotherworld.safe_vault.withdraw_failed": "Could not withdraw %s: the balance is empty or inventory is full.",
"message.anotherworld.safe_vault.already_owned": "You already own an active safe.",
@@ -1938,7 +1951,7 @@ tasks.register("verifyAnotherWorldCatalog") {
"src/main/resources/assets/redstoner/textures/item/weather_gauge.png",
"src/main/resources/data/redstoner/recipe/weather_gauge.json"
]
if (project.version.toString() != "0.0.0-alpha.52"
if (project.version.toString() != "0.0.0-alpha.53"
|| sulfurMigration.target?.modules?.anotherworld != "0.0.0-alpha.44"
|| sulfurMigration.sulfur_caves?.sanctuary?.dripstone_cell_period != 2
|| !javaText.contains('Identifier.parse("sanctuary:sulfur_caves")')
@@ -3255,7 +3268,7 @@ tasks.register("verifyClimateBiomeMixer") {
"pack/migrations/26.2.0-alpha.188-beta-climate-provinces-to-alpha.189.json"))
def mixer = file(
"src/main/java/fr/koka99cab/sanctuary26/anotherworld/mixin/MultiNoiseBiomeSourceParameterListPresetMixin.java").text
if (project.version.toString() != "0.0.0-alpha.52"
if (project.version.toString() != "0.0.0-alpha.53"
|| migration.source?.pack_version != "26.2.0-alpha.188"
|| migration.target?.pack_version != "26.2.0-alpha.189"
|| migration.target?.modules?.anotherworld != "0.0.0-alpha.48"
@@ -108,7 +108,7 @@ public final class SafeVaultBlock extends BaseEntityBlock {
player.sendSystemMessage(Component.translatable("message.anotherworld.safe_vault.locked"));
return InteractionResult.CONSUME;
}
if (level.getBlockEntity(formed.center()) instanceof SafeVaultBlockEntity controller) {
if (level.getBlockEntity(formed.controller()) instanceof SafeVaultBlockEntity controller) {
player.openMenu(controller);
return InteractionResult.SUCCESS_SERVER;
}
@@ -3,6 +3,7 @@ package fr.koka99cab.sanctuary26.anotherworld.block.entity;
import fr.koka99cab.sanctuary26.anotherworld.registry.AnotherWorldBlockEntities;
import fr.koka99cab.sanctuary26.anotherworld.vault.VaultData;
import fr.koka99cab.sanctuary26.anotherworld.vault.SafeVaultMenu;
import fr.koka99cab.sanctuary26.anotherworld.vault.VaultStructure;
import java.util.UUID;
import net.minecraft.core.BlockPos;
import net.minecraft.core.UUIDUtil;
@@ -54,7 +55,10 @@ public final class SafeVaultBlockEntity extends BlockEntity implements MenuProvi
@Override
public AbstractContainerMenu createMenu(int containerId, Inventory inventory, Player player) {
if (owner == null || !owner.equals(player.getUUID()) || !(level instanceof ServerLevel serverLevel)) return null;
VaultStructure.Formed formed = VaultStructure.find(serverLevel, getBlockPos())
.filter(candidate -> candidate.owner().equals(owner)).orElse(null);
if (formed == null || !formed.controller().equals(getBlockPos())) return null;
return new SafeVaultMenu(containerId, inventory, VaultData.get(serverLevel.getServer()),
serverLevel, getBlockPos(), owner);
serverLevel, formed.center(), owner);
}
}
@@ -104,7 +104,7 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
return false;
}
return vaultData.isRegistered(serverLevel, center, owner)
&& VaultStructure.find(serverLevel, center)
&& VaultStructure.findAtCenter(serverLevel, center)
.filter(formed -> formed.center().equals(center) && formed.owner().equals(owner)).isPresent();
}
@@ -26,7 +26,7 @@ import net.minecraft.world.level.saveddata.SavedDataType;
/** Global player-linked vault inventory, available to the Shop even when its structure is unloaded. */
public final class VaultData extends SavedData {
public static final String SAVE_KEY = "safe_vaults";
public static final int DATA_VERSION = 2;
public static final int DATA_VERSION = 3;
private static final Identifier RUBY = Identifier.fromNamespaceAndPath("anotherworld", "ruby");
private static final Identifier SAPPHIRE = Identifier.fromNamespaceAndPath("anotherworld", "sapphire");
private static final Identifier EMERALD = Identifier.withDefaultNamespace("emerald");
@@ -294,7 +294,7 @@ public final class VaultData extends SavedData {
|| player.distanceToSqr(center.getX() + 0.5D, center.getY() + 0.5D, center.getZ() + 0.5D) > 64.0D)
return false;
return data.isRegistered(level, center, owner)
&& VaultStructure.find(level, center).filter(formed -> formed.center().equals(center)).isPresent();
&& VaultStructure.findAtCenter(level, center).filter(formed -> formed.center().equals(center)).isPresent();
}
@Override public void clearContent() { data.items(owner).clear(); setChanged(); }
@Override public boolean canPlaceItem(int slot, ItemStack stack) { return isCurrency(stack); }
@@ -2,26 +2,46 @@ package fr.koka99cab.sanctuary26.anotherworld.vault;
import net.minecraft.util.StringRepresentable;
/** Stable position of one segment in the front-facing 3x3 vault wall. */
/** Stable position of one segment in the front-facing 3x3x3 vault cube. */
public enum VaultPart implements StringRepresentable {
BOTTOM_LEFT("bottom_left", 0, 0),
BOTTOM_CENTER("bottom_center", 1, 0),
BOTTOM_RIGHT("bottom_right", 2, 0),
MIDDLE_LEFT("middle_left", 0, 1),
CENTER("center", 1, 1),
MIDDLE_RIGHT("middle_right", 2, 1),
TOP_LEFT("top_left", 0, 2),
TOP_CENTER("top_center", 1, 2),
TOP_RIGHT("top_right", 2, 2);
BACK_BOTTOM_LEFT("back_bottom_left", 0, 0, 0),
BACK_BOTTOM_CENTER("back_bottom_center", 1, 0, 0),
BACK_BOTTOM_RIGHT("back_bottom_right", 2, 0, 0),
BACK_MIDDLE_LEFT("back_middle_left", 0, 1, 0),
BACK_CENTER("back_center", 1, 1, 0),
BACK_MIDDLE_RIGHT("back_middle_right", 2, 1, 0),
BACK_TOP_LEFT("back_top_left", 0, 2, 0),
BACK_TOP_CENTER("back_top_center", 1, 2, 0),
BACK_TOP_RIGHT("back_top_right", 2, 2, 0),
BOTTOM_LEFT("bottom_left", 0, 0, 1),
BOTTOM_CENTER("bottom_center", 1, 0, 1),
BOTTOM_RIGHT("bottom_right", 2, 0, 1),
MIDDLE_LEFT("middle_left", 0, 1, 1),
CENTER("center", 1, 1, 1),
MIDDLE_RIGHT("middle_right", 2, 1, 1),
TOP_LEFT("top_left", 0, 2, 1),
TOP_CENTER("top_center", 1, 2, 1),
TOP_RIGHT("top_right", 2, 2, 1),
FRONT_BOTTOM_LEFT("front_bottom_left", 0, 0, 2),
FRONT_BOTTOM_CENTER("front_bottom_center", 1, 0, 2),
FRONT_BOTTOM_RIGHT("front_bottom_right", 2, 0, 2),
FRONT_MIDDLE_LEFT("front_middle_left", 0, 1, 2),
FRONT_CENTER("front_center", 1, 1, 2),
FRONT_MIDDLE_RIGHT("front_middle_right", 2, 1, 2),
FRONT_TOP_LEFT("front_top_left", 0, 2, 2),
FRONT_TOP_CENTER("front_top_center", 1, 2, 2),
FRONT_TOP_RIGHT("front_top_right", 2, 2, 2);
private final String serializedName;
private final int column;
private final int row;
private final int depth;
VaultPart(String serializedName, int column, int row) {
VaultPart(String serializedName, int column, int row, int depth) {
this.serializedName = serializedName;
this.column = column;
this.row = row;
this.depth = depth;
}
public int column() {
@@ -32,11 +52,15 @@ public enum VaultPart implements StringRepresentable {
return row;
}
public static VaultPart at(int column, int row) {
public int depth() {
return depth;
}
public static VaultPart at(int column, int row, int depth) {
for (VaultPart part : values()) {
if (part.column == column && part.row == row) return part;
if (part.column == column && part.row == row && part.depth == depth) return part;
}
throw new IllegalArgumentException("Invalid vault part: " + column + ", " + row);
throw new IllegalArgumentException("Invalid vault part: " + column + ", " + row + ", " + depth);
}
@Override
@@ -3,9 +3,14 @@ package fr.koka99cab.sanctuary26.anotherworld.vault;
/** Pure balancing rules shared by runtime code and smoke tests. */
public final class VaultRules {
public static final int STRUCTURE_WIDTH = 3;
public static final int STRUCTURE_DEPTH = 3;
public static final int STRUCTURE_RADIUS = 1;
public static final int STRUCTURE_BLOCKS = STRUCTURE_WIDTH * STRUCTURE_WIDTH;
public static final int COMPLETE_STRUCTURE_MASK = (1 << STRUCTURE_BLOCKS) - 1;
public static final int STRUCTURE_POSITIONS = STRUCTURE_WIDTH * STRUCTURE_WIDTH * STRUCTURE_DEPTH;
public static final int STRUCTURE_BLOCKS = STRUCTURE_POSITIONS - 1;
public static final int CENTER_PART_INDEX = STRUCTURE_RADIUS * STRUCTURE_WIDTH * STRUCTURE_WIDTH
+ STRUCTURE_RADIUS * STRUCTURE_WIDTH + STRUCTURE_RADIUS;
public static final int FULL_STRUCTURE_MASK = (1 << STRUCTURE_POSITIONS) - 1;
public static final int COMPLETE_STRUCTURE_MASK = FULL_STRUCTURE_MASK & ~(1 << CENTER_PART_INDEX);
public static final int STORAGE_SLOTS = 27;
public static final int CURRENCY_SLOTS = 3;
public static final int BUTTONS_PER_CURRENCY = 4;
@@ -30,6 +35,14 @@ public final class VaultRules {
return partMask == COMPLETE_STRUCTURE_MASK;
}
public static int partIndex(int column, int row, int depth) {
if (column < 0 || column >= STRUCTURE_WIDTH || row < 0 || row >= STRUCTURE_WIDTH
|| depth < 0 || depth >= STRUCTURE_DEPTH) {
throw new IllegalArgumentException("Invalid vault coordinates: " + column + ", " + row + ", " + depth);
}
return depth * STRUCTURE_WIDTH * STRUCTURE_WIDTH + row * STRUCTURE_WIDTH + column;
}
public static int buttonCurrency(int buttonId) {
return validButton(buttonId) ? buttonId / BUTTONS_PER_CURRENCY : -1;
}
@@ -61,15 +61,18 @@ public final class VaultService {
net.minecraft.core.BlockPos center = VaultStructure.centerFor(pos, state);
var facing = state.getValue(SafeVaultBlock.FACING);
var width = facing.getClockWise();
for (int column = 0; column < VaultRules.STRUCTURE_WIDTH; column++) {
for (int row = 0; row < VaultRules.STRUCTURE_WIDTH; row++) {
var member = center.relative(width, column - VaultRules.STRUCTURE_RADIUS)
.above(row - VaultRules.STRUCTURE_RADIUS);
BlockState memberState = level.getBlockState(member);
if (!memberState.is(AnotherWorldBlocks.SAFE_BLOCK)) continue;
level.setBlock(member, memberState
.setValue(SafeVaultBlock.FORMED, false)
.setValue(SafeVaultBlock.PART, VaultPart.CENTER), Block.UPDATE_CLIENTS);
for (int depth = 0; depth < VaultRules.STRUCTURE_DEPTH; depth++) {
for (int column = 0; column < VaultRules.STRUCTURE_WIDTH; column++) {
for (int row = 0; row < VaultRules.STRUCTURE_WIDTH; row++) {
var member = center.relative(width, column - VaultRules.STRUCTURE_RADIUS)
.above(row - VaultRules.STRUCTURE_RADIUS)
.relative(facing, depth - VaultRules.STRUCTURE_RADIUS);
BlockState memberState = level.getBlockState(member);
if (!memberState.is(AnotherWorldBlocks.SAFE_BLOCK)) continue;
level.setBlock(member, memberState
.setValue(SafeVaultBlock.FORMED, false)
.setValue(SafeVaultBlock.PART, VaultPart.CENTER), Block.UPDATE_CLIENTS);
}
}
}
}
@@ -12,7 +12,7 @@ import net.minecraft.core.Direction;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.Level;
/** Detects one isolated, upright 3x3 vault wall owned by a single player. */
/** Detects one isolated, hollow 3x3x3 vault cube owned by a single player. */
public final class VaultStructure {
private VaultStructure() {
}
@@ -29,41 +29,66 @@ public final class VaultStructure {
offsetWidth <= VaultRules.STRUCTURE_RADIUS; offsetWidth++) {
for (int offsetY = -VaultRules.STRUCTURE_RADIUS;
offsetY <= VaultRules.STRUCTURE_RADIUS; offsetY++) {
BlockPos center = member.relative(width, -offsetWidth).below(offsetY);
Formed formed = validate(level, center, facing);
if (formed != null && formed.contains(member)) return Optional.of(formed);
for (int offsetDepth = -VaultRules.STRUCTURE_RADIUS;
offsetDepth <= VaultRules.STRUCTURE_RADIUS; offsetDepth++) {
BlockPos center = member.relative(width, -offsetWidth).below(offsetY)
.relative(facing, -offsetDepth);
Formed formed = validate(level, center, facing);
if (formed != null && formed.contains(member)) return Optional.of(formed);
}
}
}
}
return Optional.empty();
}
public static Optional<Formed> findAtCenter(Level level, BlockPos center) {
if (level == null || center == null) return Optional.empty();
for (Direction direction : Direction.Plane.HORIZONTAL) {
Optional<Formed> formed = find(level, center.relative(direction))
.filter(candidate -> candidate.center().equals(center));
if (formed.isPresent()) return formed;
}
return Optional.empty();
}
private static Formed validate(Level level, BlockPos center, Direction facing) {
UUID owner = null;
List<BlockPos> members = new ArrayList<>(VaultRules.STRUCTURE_BLOCKS);
int partMask = 0;
Direction width = facing.getClockWise();
for (int column = 0; column < VaultRules.STRUCTURE_WIDTH; column++) {
for (int row = 0; row < VaultRules.STRUCTURE_WIDTH; row++) {
BlockPos pos = center.relative(width, column - VaultRules.STRUCTURE_RADIUS)
.above(row - VaultRules.STRUCTURE_RADIUS);
if (!level.getBlockState(pos).is(AnotherWorldBlocks.SAFE_BLOCK)
|| !(level.getBlockEntity(pos) instanceof SafeVaultBlockEntity blockEntity)
|| blockEntity.owner() == null) return null;
if (owner == null) owner = blockEntity.owner();
else if (!owner.equals(blockEntity.owner())) return null;
members.add(pos.immutable());
partMask |= 1 << (row * VaultRules.STRUCTURE_WIDTH + column);
for (int depth = 0; depth < VaultRules.STRUCTURE_DEPTH; depth++) {
for (int column = 0; column < VaultRules.STRUCTURE_WIDTH; column++) {
for (int row = 0; row < VaultRules.STRUCTURE_WIDTH; row++) {
BlockPos pos = center.relative(width, column - VaultRules.STRUCTURE_RADIUS)
.above(row - VaultRules.STRUCTURE_RADIUS)
.relative(facing, depth - VaultRules.STRUCTURE_RADIUS);
if (column == VaultRules.STRUCTURE_RADIUS && row == VaultRules.STRUCTURE_RADIUS
&& depth == VaultRules.STRUCTURE_RADIUS) {
if (level.getBlockState(pos).is(AnotherWorldBlocks.SAFE_BLOCK)) return null;
continue;
}
if (!level.getBlockState(pos).is(AnotherWorldBlocks.SAFE_BLOCK)
|| !(level.getBlockEntity(pos) instanceof SafeVaultBlockEntity blockEntity)
|| blockEntity.owner() == null) return null;
if (owner == null) owner = blockEntity.owner();
else if (!owner.equals(blockEntity.owner())) return null;
members.add(pos.immutable());
partMask |= 1 << VaultRules.partIndex(column, row, depth);
}
}
}
if (!VaultRules.isCompleteStructureMask(partMask)) return null;
// Reject ambiguous 3x4/4x3 walls: a vault is one discrete upright 3x3 structure.
// Reject attached Safe Blocks: a vault is one discrete 3x3x3 cube.
for (int widthOffset = -2; widthOffset <= 2; widthOffset++) {
for (int yOffset = -2; yOffset <= 2; yOffset++) {
if (Math.abs(widthOffset) <= 1 && Math.abs(yOffset) <= 1) continue;
if (level.getBlockState(center.relative(width, widthOffset).above(yOffset))
.is(AnotherWorldBlocks.SAFE_BLOCK)) return null;
for (int depthOffset = -2; depthOffset <= 2; depthOffset++) {
if (Math.abs(widthOffset) <= 1 && Math.abs(yOffset) <= 1
&& Math.abs(depthOffset) <= 1) continue;
if (level.getBlockState(center.relative(width, widthOffset).above(yOffset)
.relative(facing, depthOffset)).is(AnotherWorldBlocks.SAFE_BLOCK)) return null;
}
}
}
return new Formed(center.immutable(), owner, List.copyOf(members), facing);
@@ -73,7 +98,9 @@ public final class VaultStructure {
VaultPart part = state.getValue(SafeVaultBlock.PART);
Direction width = state.getValue(SafeVaultBlock.FACING).getClockWise();
return member.relative(width, VaultRules.STRUCTURE_RADIUS - part.column())
.below(part.row() - VaultRules.STRUCTURE_RADIUS).immutable();
.below(part.row() - VaultRules.STRUCTURE_RADIUS)
.relative(state.getValue(SafeVaultBlock.FACING), VaultRules.STRUCTURE_RADIUS - part.depth())
.immutable();
}
public record Formed(BlockPos center, UUID owner, List<BlockPos> members, Direction facing) {
@@ -86,7 +113,13 @@ public final class VaultStructure {
int column = (pos.getX() - center.getX()) * width.getStepX()
+ (pos.getZ() - center.getZ()) * width.getStepZ() + VaultRules.STRUCTURE_RADIUS;
int row = pos.getY() - center.getY() + VaultRules.STRUCTURE_RADIUS;
return VaultPart.at(column, row);
int depth = (pos.getX() - center.getX()) * facing.getStepX()
+ (pos.getZ() - center.getZ()) * facing.getStepZ() + VaultRules.STRUCTURE_RADIUS;
return VaultPart.at(column, row, depth);
}
public BlockPos controller() {
return center.relative(facing, VaultRules.STRUCTURE_RADIUS).immutable();
}
}
}
@@ -37,7 +37,7 @@
"sanctuary26": {
"system_type": "gameplay-system",
"namespace": "anotherworld",
"data_version": 3,
"data_version": 4,
"network_protocol": 1,
"lifecycle": "${lifecycle}",
"pack_version": "${pack_version}",
@@ -6,18 +6,36 @@ public final class VaultRulesSmoke {
public static void main(String[] args) {
require(VaultRules.STRUCTURE_WIDTH == 3, "vault width");
require(VaultRules.STRUCTURE_BLOCKS == 9, "upright vault wall");
require(!VaultRules.isCompleteStructureMask(0b000_000_111),
"horizontal 3x1 must stay unformed");
require(!VaultRules.isCompleteStructureMask(0b001_001_001),
"vertical 3x1 must stay unformed");
require(VaultRules.isCompleteStructureMask(0b111_111_111),
"only all nine parts form the vault");
require(VaultRules.STRUCTURE_DEPTH == 3, "vault depth");
require(VaultRules.STRUCTURE_POSITIONS == 27, "vault cube positions");
require(VaultRules.STRUCTURE_BLOCKS == 26, "hollow vault shell");
require(VaultRules.CENTER_PART_INDEX == VaultRules.partIndex(1, 1, 1), "free center index");
require(Integer.bitCount(VaultRules.COMPLETE_STRUCTURE_MASK) == VaultRules.STRUCTURE_BLOCKS,
"26 required shell positions");
require(!VaultRules.isCompleteStructureMask((1 << 9) - 1),
"3x3 wall must stay unformed");
require(!VaultRules.isCompleteStructureMask(VaultRules.FULL_STRUCTURE_MASK),
"solid cube must stay unformed");
require(VaultRules.isCompleteStructureMask(VaultRules.COMPLETE_STRUCTURE_MASK),
"only the complete 26-block shell forms the vault");
require(VaultRules.STORAGE_SLOTS == 27, "vault capacity");
require(VaultRules.CURRENCY_SLOTS == 3, "currency controls");
require(VaultPart.at(0, 0) == VaultPart.BOTTOM_LEFT, "bottom-left CTM part");
require(VaultPart.at(1, 1) == VaultPart.CENTER, "center CTM part");
require(VaultPart.at(2, 2) == VaultPart.TOP_RIGHT, "top-right CTM part");
require(VaultPart.at(0, 0, 0) == VaultPart.BACK_BOTTOM_LEFT, "back-bottom-left CTM part");
require(VaultPart.at(1, 1, 1) == VaultPart.CENTER, "center CTM part");
require(VaultPart.at(2, 2, 2) == VaultPart.FRONT_TOP_RIGHT, "front-top-right CTM part");
boolean[] seenParts = new boolean[VaultRules.STRUCTURE_POSITIONS];
for (int depth = 0; depth < VaultRules.STRUCTURE_DEPTH; depth++) {
for (int row = 0; row < VaultRules.STRUCTURE_WIDTH; row++) {
for (int column = 0; column < VaultRules.STRUCTURE_WIDTH; column++) {
int index = VaultRules.partIndex(column, row, depth);
require(!seenParts[index], "unique cube part index");
seenParts[index] = true;
VaultPart part = VaultPart.at(column, row, depth);
require(part.column() == column && part.row() == row && part.depth() == depth,
"cube part coordinates");
}
}
}
require(VaultRules.buttonCurrency(0) == 0 && VaultRules.buttonCurrency(11) == 2,
"button currency routing");
require(VaultRules.buttonAmount(0) == 64 && VaultRules.buttonAmount(1) == 1
+80 -13
View File
@@ -1815,7 +1815,7 @@ tasks.register("verifyWorkspace") {
|| terramixMigration.compatibility?.new_registry_ids != 100
|| terramixMigration.compatibility?.worldgen_changed != true
|| terramixMigration.compatibility?.save_migration_required != false
|| anotherWorldManifest?.custom?.sanctuary26?.data_version != 3
|| anotherWorldManifest?.custom?.sanctuary26?.data_version < 3
|| anotherWorldManifest?.custom?.sanctuary26?.network_protocol != 1
|| sanctuaryManifest?.custom?.sanctuary26?.data_version < 9
) {
@@ -3478,7 +3478,7 @@ tasks.register("verifyMirrorLavenderDrawerRelease") {
"redstoner/src/main/java/fr/koka99cab/sanctuary26/redstoner/registry/RedStonerRegistries.java").text
def drawerRecipe = file("redstoner/src/main/resources/data/redstoner/recipe/drawer.json")
if (rootProject.pack_version != "26.2.0-alpha.204"
|| rootProject.anotherworld_version != "0.0.0-alpha.52"
|| rootProject.anotherworld_version != "0.0.0-alpha.53"
|| rootProject.redstoner_version != "0.0.0-alpha.10"
|| release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version
|| migration.source?.pack_version != "26.2.0-alpha.191"
@@ -4585,7 +4585,7 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") {
def sanctuaryManifest = new JsonSlurper().parse(file(
"sanctuary/src/main/resources/fabric.mod.json"))
if (rootProject.pack_version != "26.2.0-alpha.204"
|| rootProject.anotherworld_version != "0.0.0-alpha.52"
|| rootProject.anotherworld_version != "0.0.0-alpha.53"
|| rootProject.itsalive_version != "0.0.0-alpha.31"
|| rootProject.iliketomoveit_version != "0.0.0-alpha.14"
|| rootProject.sanctuary_version != "0.0.0-alpha.117"
@@ -4639,15 +4639,17 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") {
tasks.register("verifySafeVaultFeature") {
group = "verification"
description = "Checks the current upright 3x3 safe, custom currency interface, drill and Shop contract."
description = "Checks the current hollow 3x3x3 safe, custom currency interface, drill and Shop contract."
dependsOn ":anotherworld:generateAnotherWorldResources"
inputs.file(file("pack/migrations/anotherworld-safe-vault-data-v2.json"))
inputs.file(file("pack/migrations/anotherworld-safe-vault-data-v3.json"))
inputs.file(file("pack/migrations/anotherworld-safe-vault-fix-alpha52.json"))
inputs.file(file("pack/migrations/anotherworld-safe-vault-cube-alpha53.json"))
inputs.file(file("anotherworld/src/main/resources/fabric.mod.json"))
inputs.file(file("sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryCurrencyStorage.java"))
inputs.files(fileTree("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault") { include "*.java" })
inputs.file(file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/block/SafeVaultBlock.java"))
inputs.file(file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/block/entity/SafeVaultBlockEntity.java"))
inputs.file(file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/client/SafeVaultScreen.java"))
inputs.files(fileTree("anotherworld/src/main/resources/assets/anotherworld/textures/block/safe_vault") { include "*.png" })
inputs.file(file("anotherworld/src/main/resources/assets/anotherworld/textures/block/safe_block.png"))
@@ -4657,12 +4659,14 @@ tasks.register("verifySafeVaultFeature") {
def migration = new JsonSlurper().parse(file("pack/migrations/anotherworld-safe-vault-data-v2.json"))
def interfaceMigration = new JsonSlurper().parse(file("pack/migrations/anotherworld-safe-vault-data-v3.json"))
def fixMigration = new JsonSlurper().parse(file("pack/migrations/anotherworld-safe-vault-fix-alpha52.json"))
def cubeMigration = new JsonSlurper().parse(file("pack/migrations/anotherworld-safe-vault-cube-alpha53.json"))
def manifest = new JsonSlurper().parse(file("anotherworld/src/main/resources/fabric.mod.json"))
def rules = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultRules.java").text
def data = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultData.java").text
def structure = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultStructure.java").text
def menu = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/SafeVaultMenu.java").text
def block = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/block/SafeVaultBlock.java").text
def controller = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/block/entity/SafeVaultBlockEntity.java").text
def screen = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/client/SafeVaultScreen.java").text
def currencyApi = file("sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryCurrencyStorage.java").text
def generated = file("anotherworld/build/generated/resources")
@@ -4671,6 +4675,38 @@ tasks.register("verifySafeVaultFeature") {
def safeBlockState = new JsonSlurper().parse(new File(generated, "assets/anotherworld/blockstates/safe_block.json"))
def safeUnformedModel = new JsonSlurper().parse(new File(generated, "assets/anotherworld/models/block/safe_block_unformed.json"))
def safeItemModel = new JsonSlurper().parse(new File(generated, "assets/anotherworld/models/item/safe_block.json"))
def safeFormedModels = fileTree(new File(generated, "assets/anotherworld/models/block/safe_block")) {
include "*.json"
}.files
def safeModelsById = safeFormedModels.collectEntries { modelFile ->
[(modelFile.name.substring(0, modelFile.name.length() - 5)): new JsonSlurper().parse(modelFile)]
}
def normalizedUv = { uv ->
uv.collect { value -> Math.round((value as double) * 1_000_000D) }.join(":")
}
def expectedSurfaceUvs = (0..2).collectMany { column ->
(0..2).collect { row ->
normalizedUv([
column * 16.0D / 3.0D, (2 - row) * 16.0D / 3.0D,
(column + 1) * 16.0D / 3.0D, (3 - row) * 16.0D / 3.0D
])
}
}.toSet()
def basePartName = { id -> id.replaceFirst(/^(back_|front_)/, "") }
def surfaceUvSets = [
front: safeModelsById.findAll { id, model -> id.startsWith("front_") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.north.uv) }.toSet(),
back: safeModelsById.findAll { id, model -> id.startsWith("back_") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.south.uv) }.toSet(),
west: safeModelsById.findAll { id, model -> basePartName(id).endsWith("_left") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.west.uv) }.toSet(),
east: safeModelsById.findAll { id, model -> basePartName(id).endsWith("_right") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.east.uv) }.toSet(),
top: safeModelsById.findAll { id, model -> basePartName(id).startsWith("top_") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.up.uv) }.toSet(),
bottom: safeModelsById.findAll { id, model -> basePartName(id).startsWith("bottom_") }.values()
.collect { model -> normalizedUv(model.elements[0].faces.down.uv) }.toSet()
]
def requiredTextures = [
"block/safe_vault/bottom.png": [48, 48], "block/safe_vault/front.png": [48, 48],
"block/safe_vault/side.png": [48, 48], "block/safe_vault/top.png": [48, 48],
@@ -4682,7 +4718,7 @@ tasks.register("verifySafeVaultFeature") {
image == null || image.width != size[0] || image.height != size[1]
}.keySet()
if (rootProject.pack_version != "26.2.0-alpha.204"
|| rootProject.anotherworld_version != "0.0.0-alpha.52"
|| rootProject.anotherworld_version != "0.0.0-alpha.53"
|| rootProject.sanctuary_version != "0.0.0-alpha.117"
|| migration.schema_version != 1
|| migration.source?.pack_version != "26.2.0-alpha.201"
@@ -4735,25 +4771,56 @@ tasks.register("verifySafeVaultFeature") {
|| fixMigration.compatibility?.registry_ids_changed != false
|| fixMigration.compatibility?.saved_currency_balances_preserved != true
|| fixMigration.compatibility?.pack_release_updated != true
|| cubeMigration.source?.pack_version != "26.2.0-alpha.204"
|| cubeMigration.source?.modules != [anotherworld: "0.0.0-alpha.52"]
|| cubeMigration.target?.pack_version != "26.2.0-alpha.204"
|| cubeMigration.target?.modules != [anotherworld: "0.0.0-alpha.53"]
|| cubeMigration.safe_vault_structure?.source_footprint != "3x3_upright_wall"
|| cubeMigration.safe_vault_structure?.target_footprint != "3x3x3_hollow_cube"
|| cubeMigration.safe_vault_structure?.blocks_required != 26
|| cubeMigration.safe_vault_structure?.center_must_be_safe_block != false
|| cubeMigration.safe_vault_structure?.hidden_center_block_allowed != true
|| cubeMigration.safe_vault_structure?.solid_cube_accepted != false
|| cubeMigration.safe_vault_structure?.connected_texture_positions != 26
|| cubeMigration.safe_vault_structure?.surface_texture_grid != "3x3"
|| cubeMigration.compatibility?.anotherworld_source_data_version != 3
|| cubeMigration.compatibility?.anotherworld_target_data_version != 4
|| cubeMigration.compatibility?.vault_source_data_version != 2
|| cubeMigration.compatibility?.vault_target_data_version != 3
|| cubeMigration.compatibility?.anotherworld_network_protocol != 1
|| cubeMigration.compatibility?.saved_currency_balances_preserved != true
|| cubeMigration.compatibility?.legacy_3x3_wall_requires_rebuild != true
|| cubeMigration.compatibility?.registry_ids_changed != false
|| cubeMigration.compatibility?.pack_release_updated != false
|| manifest.depends?.sanctuary != ">=0.0.0-alpha.117"
|| manifest.custom?.sanctuary26?.data_version != 3
|| manifest.custom?.sanctuary26?.data_version != 4
|| !file("build.gradle").text.contains('implementation project(":sanctuary")')
|| !currencyApi.contains("public interface Provider")
|| !currencyApi.contains("countAdditional") || !currencyApi.contains("removeAdditional")
|| !rules.contains("STRUCTURE_WIDTH = 3") || !rules.contains("COMPLETE_STRUCTURE_MASK")
|| !rules.contains("STRUCTURE_WIDTH = 3") || !rules.contains("STRUCTURE_DEPTH = 3")
|| !rules.contains("STRUCTURE_POSITIONS = STRUCTURE_WIDTH * STRUCTURE_WIDTH * STRUCTURE_DEPTH")
|| !rules.contains("STRUCTURE_BLOCKS = STRUCTURE_POSITIONS - 1")
|| !rules.contains("FULL_STRUCTURE_MASK & ~(1 << CENTER_PART_INDEX)")
|| !rules.contains("COMPLETE_STRUCTURE_MASK")
|| !rules.contains("CURRENCY_SLOTS = 3")
|| !rules.contains("BUTTONS_PER_CURRENCY = 4") || !rules.contains("RAID_DURATION_TICKS = 60 * 20")
|| !rules.contains("RAID_LOOT_PERCENT = 20") || !rules.contains("24L * 60L * 60L * 20L")
|| !data.contains('SAVE_KEY = "safe_vaults"') || !data.contains("DATA_VERSION = 2")
|| !structure.contains("upright 3x3") || !structure.contains(".above(row - VaultRules.STRUCTURE_RADIUS)")
|| !data.contains('SAVE_KEY = "safe_vaults"') || !data.contains("DATA_VERSION = 3")
|| !structure.contains("hollow 3x3x3") || !structure.contains(".above(row - VaultRules.STRUCTURE_RADIUS)")
|| !structure.contains(".relative(facing, depth - VaultRules.STRUCTURE_RADIUS)")
|| !structure.contains("findAtCenter") || !structure.contains("controller()")
|| !structure.contains("isCompleteStructureMask(partMask)")
|| !block.contains("BooleanProperty FORMED") || !block.contains("EnumProperty<VaultPart> PART")
|| !block.contains("formed.controller()")
|| !controller.contains("VaultStructure.find") || !controller.contains("formed.center()")
|| !menu.contains("clickMenuButton") || !menu.contains("SanctuaryPlayerInventoryView.unlockedRows")
|| !menu.contains("PLAYER_INVENTORY_Y = 108")
|| !screen.contains("handleInventoryButtonClick") || !screen.contains('" ×64", " ×1", "+ ×1", "+ ×64"')
|| screen.contains("inventoryLabelY =")
|| safeBlockState.multipart?.size() != 37
|| safeBlockState.multipart?.count { it.when?.formed == "true" } != 36
|| safeBlockState.multipart?.size() != 109
|| safeBlockState.multipart?.count { it.when?.formed == "true" } != 108
|| safeFormedModels.size() != 27
|| surfaceUvSets.any { face, uvs -> uvs != expectedSurfaceUvs }
|| safeUnformedModel.textures?.all != "anotherworld:block/safe_block"
|| safeItemModel.parent != "anotherworld:block/safe_block_unformed"
|| safeRecipe.pattern != ["GGG", "GCG", "GGG"]
@@ -4780,7 +4847,7 @@ tasks.register("verifySafeVaultInterfaceAlpha203Release") {
def packwizIndex = file("pack/packwiz/index.toml").text
def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.27.0.188.jar" }
if (rootProject.pack_version != "26.2.0-alpha.204"
|| rootProject.anotherworld_version != "0.0.0-alpha.52"
|| rootProject.anotherworld_version != "0.0.0-alpha.53"
|| migration.source?.pack_version != "26.2.0-alpha.202"
|| migration.source?.modules != [anotherworld: "0.0.0-alpha.50"]
|| migration.target?.pack_version != "26.2.0-alpha.203"
@@ -4826,7 +4893,7 @@ tasks.register("verifySafeVaultFixAlpha204Release") {
def packwizIndex = file("pack/packwiz/index.toml").text
def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.27.0.188.jar" }
if (rootProject.pack_version != "26.2.0-alpha.204"
|| rootProject.anotherworld_version != "0.0.0-alpha.52"
|| rootProject.anotherworld_version != "0.0.0-alpha.53"
|| migration.source?.pack_version != "26.2.0-alpha.203"
|| migration.source?.modules != [anotherworld: "0.0.0-alpha.51"]
|| migration.target?.pack_version != "26.2.0-alpha.204"
+1 -1
View File
@@ -16,7 +16,7 @@ ambiance_version=0.0.0-alpha.12
ambiance_lifecycle=active
redstoner_version=0.0.0-alpha.10
redstoner_lifecycle=active
anotherworld_version=0.0.0-alpha.52
anotherworld_version=0.0.0-alpha.53
anotherworld_lifecycle=active
itsalive_version=0.0.0-alpha.31
itsalive_lifecycle=active
@@ -0,0 +1,42 @@
{
"schema_version": 1,
"source": {
"pack_version": "26.2.0-alpha.204",
"modules": {
"anotherworld": "0.0.0-alpha.52"
}
},
"target": {
"pack_version": "26.2.0-alpha.204",
"modules": {
"anotherworld": "0.0.0-alpha.53"
}
},
"safe_vault_structure": {
"source_footprint": "3x3_upright_wall",
"target_footprint": "3x3x3_hollow_cube",
"blocks_required": 26,
"center_must_be_safe_block": false,
"hidden_center_block_allowed": true,
"solid_cube_accepted": false,
"connected_texture_positions": 26,
"surface_texture_grid": "3x3",
"surface_textures": [
"anotherworld:block/safe_vault/front",
"anotherworld:block/safe_vault/side",
"anotherworld:block/safe_vault/top",
"anotherworld:block/safe_vault/bottom"
]
},
"compatibility": {
"anotherworld_source_data_version": 3,
"anotherworld_target_data_version": 4,
"vault_source_data_version": 2,
"vault_target_data_version": 3,
"anotherworld_network_protocol": 1,
"saved_currency_balances_preserved": true,
"legacy_3x3_wall_requires_rebuild": true,
"registry_ids_changed": false,
"pack_release_updated": false
}
}