feat(anotherworld): rendre le coffre-fort illimité #30
@@ -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 à soldes illimités
|
||||
|
||||
Module modifié : **Another World `0.0.0-alpha.55`**. Le pack distribué reste en **`26.2.0-alpha.206`** jusqu’à la prochaine release.
|
||||
|
||||
- remplace les 27 piles du coffre-fort par trois soldes 64 bits séparés pour les rubis, saphirs et émeraudes ;
|
||||
- migre automatiquement chaque pile existante vers son solde correspondant dans `safe_vaults` v4, sans changer les IDs ni exiger de nouveau monde ;
|
||||
- synchronise les soldes 64 bits avec l’interface et les affiche sous forme compacte au-delà de 999 ;
|
||||
- conserve l’accès du Shop aux monnaies stockées et borne son API historique 32 bits sans limiter le solde réel ;
|
||||
- crédite directement les 20 % pillés dans le coffre-fort de l’attaquant afin d’éviter de générer un nombre non borné d’objets ;
|
||||
- porte Another World en donnée v5 et protocole réseau 2 ; Packwiz sera actualisé lors de la prochaine version distribuée.
|
||||
|
||||
## `26.2.0-alpha.206`
|
||||
|
||||
Module modifié : **Another World `0.0.0-alpha.54`**. Les neuf autres modules conservent leur version issue de l’alpha.205.
|
||||
|
||||
@@ -24,6 +24,8 @@ Les descriptions FR/EN/RU sont déclarées dans chaque `fabric.mod.json` et dans
|
||||
|
||||
Version courante du pack distribué : **`26.2.0-alpha.206`**. Cette release distribue Another World **`0.0.0-alpha.54`** avec les colonnes A et C corrigées sur la façade et le dos du coffre-fort.
|
||||
|
||||
Dans le workspace en développement, Another World **`0.0.0-alpha.55`** rend le stockage du coffre-fort pratiquement illimité : rubis, saphirs et émeraudes utilisent chacun un solde 64 bits. Les 27 anciennes piles sont additionnées automatiquement lors du chargement, le Shop continue de consommer directement ces soldes et les 20 % pillés sont crédités dans le coffre-fort de l’attaquant sans créer des millions d’entités ou de piles d’objets.
|
||||
|
||||
L’alpha.206 exige une coque creuse de **3 × 3 × 3**, soit 26 Safe Blocks appartenant au même joueur, et conserve JEI en **`30.27.0.189`**. 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. Les colonnes extrêmes de la façade et du dos sont désormais orientées correctement. Un ancien mur 3 × 3 ne s’active plus et doit être démonté puis reconstruit ; les comptes et soldes existants restent conservés.
|
||||
|
||||
L’alpha.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. L’interface monétaire affiche désormais correctement l’émeraude et place l’inventaire étendu sous les trois lignes de monnaie.
|
||||
|
||||
@@ -1640,7 +1640,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"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 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.deposit_failed": "Impossible de déposer %s : aucun exemplaire disponible dans votre inventaire.",
|
||||
"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.",
|
||||
"message.anotherworld.safe_vault.break_not_owner": "Seul le propriétaire peut démonter ce bloc de coffre-fort.",
|
||||
@@ -1656,7 +1656,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"message.anotherworld.safe_vault.drilling_progress": "Forage : %s %%",
|
||||
"message.anotherworld.safe_vault.drilling_cancelled": "Forage interrompu.",
|
||||
"message.anotherworld.safe_vault.raided_owner": "%s a pillé %s gemme(s) dans votre coffre-fort.",
|
||||
"message.anotherworld.safe_vault.raided": "Pillage réussi : %s gemme(s) récupérée(s)."
|
||||
"message.anotherworld.safe_vault.raided": "Pillage réussi : %s gemme(s) créditée(s) dans votre coffre-fort."
|
||||
] : locale == "ru_ru" ? [
|
||||
"container.anotherworld.safe_vault": "Сейф",
|
||||
"tooltip.anotherworld.titanium_drill.use": "Удерживайте на чужом сейфе, чтобы просверлить его.",
|
||||
@@ -1664,7 +1664,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"message.anotherworld.safe_vault.incomplete": "Сейф требует полую оболочку 3 × 3 × 3 из 26 блоков одного владельца со свободным центром.",
|
||||
"message.anotherworld.safe_vault.locked": "Этот сейф принадлежит другому игроку.",
|
||||
"message.anotherworld.safe_vault.formed": "Полый сейф 3 × 3 × 3 привязан к вам в точке %s, %s, %s.",
|
||||
"message.anotherworld.safe_vault.deposit_failed": "Не удалось внести %s: предметов нет или сейф заполнен.",
|
||||
"message.anotherworld.safe_vault.deposit_failed": "Не удалось внести %s: в инвентаре нет доступных предметов.",
|
||||
"message.anotherworld.safe_vault.withdraw_failed": "Не удалось забрать %s: баланс пуст или инвентарь заполнен.",
|
||||
"message.anotherworld.safe_vault.already_owned": "У вас уже есть активный сейф.",
|
||||
"message.anotherworld.safe_vault.break_not_owner": "Разобрать этот блок может только владелец.",
|
||||
@@ -1680,7 +1680,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"message.anotherworld.safe_vault.drilling_progress": "Сверление: %s %%",
|
||||
"message.anotherworld.safe_vault.drilling_cancelled": "Сверление прервано.",
|
||||
"message.anotherworld.safe_vault.raided_owner": "%s похитил(а) %s драгоценностей из вашего сейфа.",
|
||||
"message.anotherworld.safe_vault.raided": "Ограбление удалось: получено %s драгоценностей."
|
||||
"message.anotherworld.safe_vault.raided": "Ограбление удалось: %s драгоценностей зачислено в ваш сейф."
|
||||
] : [
|
||||
"container.anotherworld.safe_vault": "Safe",
|
||||
"tooltip.anotherworld.titanium_drill.use": "Hold on an enemy safe to drill it.",
|
||||
@@ -1688,7 +1688,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"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": "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.deposit_failed": "Could not deposit %s: none are available in your inventory.",
|
||||
"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.",
|
||||
"message.anotherworld.safe_vault.break_not_owner": "Only the owner may dismantle this safe block.",
|
||||
@@ -1704,7 +1704,7 @@ tasks.register("generateAnotherWorldResources") {
|
||||
"message.anotherworld.safe_vault.drilling_progress": "Drilling: %s %%",
|
||||
"message.anotherworld.safe_vault.drilling_cancelled": "Drilling interrupted.",
|
||||
"message.anotherworld.safe_vault.raided_owner": "%s stole %s gem item(s) from your safe.",
|
||||
"message.anotherworld.safe_vault.raided": "Raid successful: recovered %s gem item(s)."
|
||||
"message.anotherworld.safe_vault.raided": "Raid successful: %s gem item(s) credited to your safe."
|
||||
]
|
||||
lang.putAll(vaultText)
|
||||
def tagTranslations = locale == "fr_fr" ? [
|
||||
@@ -1953,7 +1953,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.54"
|
||||
if (project.version.toString() != "0.0.0-alpha.55"
|
||||
|| sulfurMigration.target?.modules?.anotherworld != "0.0.0-alpha.44"
|
||||
|| sulfurMigration.sulfur_caves?.sanctuary?.dripstone_cell_period != 2
|
||||
|| !javaText.contains('Identifier.parse("sanctuary:sulfur_caves")')
|
||||
@@ -3270,7 +3270,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.54"
|
||||
if (project.version.toString() != "0.0.0-alpha.55"
|
||||
|| 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"
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ public final class SafeVaultScreen extends AbstractContainerScreen<SafeVaultMenu
|
||||
graphics.outline(x, y, 18, 18, 0xFF373737);
|
||||
graphics.fill(x + 1, y + 1, x + 17, y + 17, 0xFF8B8B8B);
|
||||
graphics.item(new ItemStack(SafeVaultMenu.currency(currency)), x + 1, y + 1);
|
||||
Component balance = Component.literal(Integer.toString(menu.balance(currency)));
|
||||
Component balance = Component.literal(VaultRules.formatBalance(menu.balance(currency)));
|
||||
graphics.text(font, balance, x + 17 - font.width(balance), y + 9, 0xFFFFFFFF, true);
|
||||
}
|
||||
}
|
||||
|
||||
+14
-9
@@ -34,7 +34,7 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
|
||||
private final BlockPos center;
|
||||
|
||||
public SafeVaultMenu(int containerId, Inventory inventory) {
|
||||
this(containerId, inventory, new SimpleContainerData(VaultRules.CURRENCY_SLOTS),
|
||||
this(containerId, inventory, new SimpleContainerData(VaultRules.BALANCE_DATA_SLOTS),
|
||||
null, null, null, null);
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
|
||||
private SafeVaultMenu(int containerId, Inventory inventory, ContainerData balances,
|
||||
VaultData vaultData, ServerLevel serverLevel, BlockPos center, UUID owner) {
|
||||
super(AnotherWorldMenus.SAFE_VAULT, containerId);
|
||||
checkContainerDataCount(balances, VaultRules.CURRENCY_SLOTS);
|
||||
checkContainerDataCount(balances, VaultRules.BALANCE_DATA_SLOTS);
|
||||
this.balances = balances;
|
||||
this.vaultData = vaultData;
|
||||
this.serverLevel = serverLevel;
|
||||
@@ -58,8 +58,10 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
|
||||
addDataSlots(balances);
|
||||
}
|
||||
|
||||
public int balance(int currency) {
|
||||
return currency >= 0 && currency < VaultRules.CURRENCY_SLOTS ? balances.get(currency) : 0;
|
||||
public long balance(int currency) {
|
||||
if (currency < 0 || currency >= VaultRules.CURRENCY_SLOTS) return 0L;
|
||||
int base = currency * VaultRules.BALANCE_WORDS_PER_CURRENCY;
|
||||
return VaultRules.balanceFromWords(balances.get(base), balances.get(base + 1));
|
||||
}
|
||||
|
||||
public static Item currency(int currency) {
|
||||
@@ -110,16 +112,16 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
|
||||
|
||||
private int deposit(ServerPlayer player, Item item, int requested) {
|
||||
int available = countPlayerItem(player, item);
|
||||
int amount = Math.min(requested, Math.min(available, vaultData.capacity(owner, item)));
|
||||
int amount = Math.min(requested, available);
|
||||
if (amount <= 0) return 0;
|
||||
int removed = removePlayerItem(player, item, amount);
|
||||
int stored = vaultData.add(owner, item, removed);
|
||||
int stored = (int) vaultData.add(owner, item, removed);
|
||||
if (stored < removed) insertPlayerItem(player, item, removed - stored);
|
||||
return stored;
|
||||
}
|
||||
|
||||
private int withdraw(ServerPlayer player, Item item, int requested) {
|
||||
int amount = Math.min(requested,
|
||||
int amount = (int) Math.min(requested,
|
||||
Math.min(vaultData.count(owner, item), playerCapacity(player, item)));
|
||||
if (amount <= 0) return 0;
|
||||
int removed = vaultData.remove(owner, item, amount);
|
||||
@@ -184,12 +186,15 @@ public final class SafeVaultMenu extends AbstractContainerMenu {
|
||||
|
||||
private record VaultBalanceData(VaultData data, UUID owner) implements ContainerData {
|
||||
@Override public int get(int index) {
|
||||
return index >= 0 && index < CURRENCIES.size() ? data.count(owner, CURRENCIES.get(index)) : 0;
|
||||
if (index < 0 || index >= VaultRules.BALANCE_DATA_SLOTS) return 0;
|
||||
int currency = index / VaultRules.BALANCE_WORDS_PER_CURRENCY;
|
||||
int word = index % VaultRules.BALANCE_WORDS_PER_CURRENCY;
|
||||
return VaultRules.balanceWord(data.count(owner, CURRENCIES.get(currency)), word);
|
||||
}
|
||||
@Override public void set(int index, int value) {
|
||||
}
|
||||
@Override public int getCount() {
|
||||
return VaultRules.CURRENCY_SLOTS;
|
||||
return VaultRules.BALANCE_DATA_SLOTS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+98
-139
@@ -9,28 +9,27 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.NonNullList;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.Identifier;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.ContainerHelper;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import net.minecraft.world.level.saveddata.SavedDataType;
|
||||
|
||||
/** Global player-linked vault inventory, available to the Shop even when its structure is unloaded. */
|
||||
/** Global player-linked unlimited currency balances, available even when the vault is unloaded. */
|
||||
public final class VaultData extends SavedData {
|
||||
public static final String SAVE_KEY = "safe_vaults";
|
||||
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");
|
||||
public static final int DATA_VERSION = 4;
|
||||
private static final List<Identifier> CURRENCIES = List.of(
|
||||
Identifier.fromNamespaceAndPath("anotherworld", "ruby"),
|
||||
Identifier.fromNamespaceAndPath("anotherworld", "sapphire"),
|
||||
Identifier.withDefaultNamespace("emerald")
|
||||
);
|
||||
|
||||
/** Legacy v3 slot format, retained only so existing worlds migrate monotonically. */
|
||||
private static final Codec<StoredSlot> SLOT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.INT.fieldOf("slot").forGetter(StoredSlot::slot),
|
||||
ItemStack.CODEC.fieldOf("item").forGetter(StoredSlot::item)
|
||||
@@ -38,6 +37,9 @@ public final class VaultData extends SavedData {
|
||||
private static final Codec<StoredAccount> ACCOUNT_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
Codec.STRING.fieldOf("owner").forGetter(StoredAccount::owner),
|
||||
SLOT_CODEC.listOf().optionalFieldOf("items", List.of()).forGetter(StoredAccount::items),
|
||||
Codec.LONG.optionalFieldOf("rubies", 0L).forGetter(StoredAccount::rubies),
|
||||
Codec.LONG.optionalFieldOf("sapphires", 0L).forGetter(StoredAccount::sapphires),
|
||||
Codec.LONG.optionalFieldOf("emeralds", 0L).forGetter(StoredAccount::emeralds),
|
||||
Codec.LONG.optionalFieldOf("protected_until", 0L).forGetter(StoredAccount::protectedUntil)
|
||||
).apply(instance, StoredAccount::new));
|
||||
private static final Codec<VaultAddress> ADDRESS_CODEC = RecordCodecBuilder.create(instance -> instance.group(
|
||||
@@ -66,13 +68,13 @@ public final class VaultData extends SavedData {
|
||||
for (StoredAccount stored : accounts == null ? List.<StoredAccount>of() : accounts) {
|
||||
try {
|
||||
UUID owner = UUID.fromString(stored.owner());
|
||||
NonNullList<ItemStack> items = NonNullList.withSize(VaultRules.STORAGE_SLOTS, ItemStack.EMPTY);
|
||||
Account account = new Account(stored.rubies(), stored.sapphires(), stored.emeralds(),
|
||||
stored.protectedUntil());
|
||||
for (StoredSlot slot : stored.items()) {
|
||||
if (slot.slot() >= 0 && slot.slot() < items.size() && isCurrency(slot.item())) {
|
||||
items.set(slot.slot(), slot.item().copy());
|
||||
}
|
||||
int currency = currencyIndex(slot.item());
|
||||
if (currency >= 0) account.add(currency, slot.item().getCount());
|
||||
}
|
||||
this.accounts.put(owner, new Account(items, Math.max(0L, stored.protectedUntil())));
|
||||
this.accounts.put(owner, account);
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
AnotherWorldMod.LOGGER.warn("[Vault] Ignored account with invalid owner {}.", stored.owner());
|
||||
}
|
||||
@@ -123,86 +125,59 @@ public final class VaultData extends SavedData {
|
||||
if (changed) setDirty();
|
||||
}
|
||||
|
||||
public Container container(UUID owner, ServerLevel level, BlockPos center) {
|
||||
accounts.computeIfAbsent(owner, ignored -> new Account());
|
||||
return new VaultContainer(this, owner, level, center.immutable());
|
||||
public long count(UUID owner, Item item) {
|
||||
int currency = currencyIndex(item);
|
||||
Account account = accounts.get(owner);
|
||||
return currency < 0 || account == null ? 0L : account.balance(currency);
|
||||
}
|
||||
|
||||
public int count(UUID owner, Item item) {
|
||||
if (!isCurrency(item)) return 0;
|
||||
Account account = accounts.get(owner);
|
||||
if (account == null) return 0;
|
||||
long count = 0L;
|
||||
for (ItemStack stack : account.items) if (stack.is(item)) count += stack.getCount();
|
||||
return (int) Math.min(Integer.MAX_VALUE, count);
|
||||
public int countCapped(UUID owner, Item item) {
|
||||
return (int) Math.min(Integer.MAX_VALUE, count(owner, item));
|
||||
}
|
||||
|
||||
public int remove(UUID owner, Item item, int amount) {
|
||||
if (!isCurrency(item) || amount <= 0) return 0;
|
||||
return (int) remove(owner, item, (long) amount);
|
||||
}
|
||||
|
||||
public long remove(UUID owner, Item item, long amount) {
|
||||
int currency = currencyIndex(item);
|
||||
Account account = accounts.get(owner);
|
||||
if (account == null) return 0;
|
||||
int remaining = amount;
|
||||
for (ItemStack stack : account.items) {
|
||||
if (remaining <= 0) break;
|
||||
if (!stack.is(item)) continue;
|
||||
int removed = Math.min(remaining, stack.getCount());
|
||||
stack.shrink(removed);
|
||||
remaining -= removed;
|
||||
}
|
||||
if (remaining != amount) setDirty();
|
||||
return amount - remaining;
|
||||
if (currency < 0 || account == null || amount <= 0L) return 0L;
|
||||
long removed = account.remove(currency, amount);
|
||||
if (removed > 0L) setDirty();
|
||||
return removed;
|
||||
}
|
||||
|
||||
public int capacity(UUID owner, Item item) {
|
||||
if (!isCurrency(item)) return 0;
|
||||
long capacity = 0L;
|
||||
for (ItemStack stack : items(owner)) {
|
||||
if (stack.isEmpty()) capacity += item.getDefaultMaxStackSize();
|
||||
else if (stack.is(item)) capacity += Math.max(0, stack.getMaxStackSize() - stack.getCount());
|
||||
}
|
||||
return (int) Math.min(Integer.MAX_VALUE, capacity);
|
||||
}
|
||||
|
||||
public int add(UUID owner, Item item, int amount) {
|
||||
if (!isCurrency(item) || amount <= 0) return 0;
|
||||
NonNullList<ItemStack> stored = items(owner);
|
||||
int remaining = amount;
|
||||
for (ItemStack stack : stored) {
|
||||
if (remaining <= 0) break;
|
||||
if (!stack.is(item) || stack.getCount() >= stack.getMaxStackSize()) continue;
|
||||
int inserted = Math.min(remaining, stack.getMaxStackSize() - stack.getCount());
|
||||
stack.grow(inserted);
|
||||
remaining -= inserted;
|
||||
}
|
||||
for (int slot = 0; slot < stored.size() && remaining > 0; slot++) {
|
||||
if (!stored.get(slot).isEmpty()) continue;
|
||||
int inserted = Math.min(remaining, item.getDefaultMaxStackSize());
|
||||
stored.set(slot, new ItemStack(item, inserted));
|
||||
remaining -= inserted;
|
||||
}
|
||||
if (remaining != amount) setDirty();
|
||||
return amount - remaining;
|
||||
public long add(UUID owner, Item item, long amount) {
|
||||
int currency = currencyIndex(item);
|
||||
if (currency < 0 || amount <= 0L) return 0L;
|
||||
long added = accounts.computeIfAbsent(owner, ignored -> new Account()).add(currency, amount);
|
||||
if (added > 0L) setDirty();
|
||||
return added;
|
||||
}
|
||||
|
||||
public boolean hasContents(UUID owner) {
|
||||
Account account = accounts.get(owner);
|
||||
return account != null && account.items.stream().anyMatch(stack -> !stack.isEmpty());
|
||||
return account != null && account.hasContents();
|
||||
}
|
||||
|
||||
public List<ItemStack> raidLoot(UUID owner) {
|
||||
List<ItemStack> loot = new ArrayList<>();
|
||||
for (Identifier id : List.of(RUBY, SAPPHIRE, EMERALD)) {
|
||||
Item item = BuiltInRegistries.ITEM.getOptional(id).orElse(null);
|
||||
if (item == null) continue;
|
||||
int amount = VaultRules.raidLoot(count(owner, item));
|
||||
int removed = remove(owner, item, amount);
|
||||
while (removed > 0) {
|
||||
int stackSize = Math.min(removed, item.getDefaultMaxStackSize());
|
||||
loot.add(new ItemStack(item, stackSize));
|
||||
removed -= stackSize;
|
||||
}
|
||||
/** Transfers the exact 20% raid share into the attacker's unlimited balances without item spam. */
|
||||
public long transferRaid(UUID owner, UUID attacker) {
|
||||
if (owner == null || attacker == null || owner.equals(attacker)) return 0L;
|
||||
Account source = accounts.get(owner);
|
||||
if (source == null) return 0L;
|
||||
Account target = accounts.computeIfAbsent(attacker, ignored -> new Account());
|
||||
long total = 0L;
|
||||
for (int currency = 0; currency < VaultRules.CURRENCY_SLOTS; currency++) {
|
||||
long requested = VaultRules.raidLoot(source.balance(currency));
|
||||
long accepted = Math.min(requested, VaultRules.MAX_BALANCE - target.balance(currency));
|
||||
long removed = source.remove(currency, accepted);
|
||||
long added = target.add(currency, removed);
|
||||
if (added < removed) source.add(currency, removed - added);
|
||||
total = VaultRules.saturatingAdd(total, added);
|
||||
}
|
||||
return List.copyOf(loot);
|
||||
if (total > 0L) setDirty();
|
||||
return total;
|
||||
}
|
||||
|
||||
public long protectionRemaining(UUID owner, long gameTime) {
|
||||
@@ -217,90 +192,74 @@ public final class VaultData extends SavedData {
|
||||
}
|
||||
|
||||
public static boolean isCurrency(ItemStack stack) {
|
||||
return stack != null && !stack.isEmpty() && isCurrency(stack.getItem());
|
||||
return stack != null && !stack.isEmpty() && currencyIndex(stack) >= 0;
|
||||
}
|
||||
|
||||
public static boolean isCurrency(Item item) {
|
||||
if (item == null) return false;
|
||||
Identifier id = BuiltInRegistries.ITEM.getKey(item);
|
||||
return RUBY.equals(id) || SAPPHIRE.equals(id) || EMERALD.equals(id);
|
||||
}
|
||||
|
||||
private NonNullList<ItemStack> items(UUID owner) {
|
||||
return accounts.computeIfAbsent(owner, ignored -> new Account()).items;
|
||||
return currencyIndex(item) >= 0;
|
||||
}
|
||||
|
||||
private List<StoredAccount> storedAccounts() {
|
||||
List<StoredAccount> stored = new ArrayList<>();
|
||||
accounts.forEach((owner, account) -> {
|
||||
List<StoredSlot> slots = new ArrayList<>();
|
||||
for (int index = 0; index < account.items.size(); index++) {
|
||||
ItemStack stack = account.items.get(index);
|
||||
if (!stack.isEmpty()) slots.add(new StoredSlot(index, stack));
|
||||
}
|
||||
stored.add(new StoredAccount(owner.toString(), List.copyOf(slots), account.protectedUntil));
|
||||
});
|
||||
accounts.forEach((owner, account) -> stored.add(new StoredAccount(owner.toString(), List.of(),
|
||||
account.balance(0), account.balance(1), account.balance(2), account.protectedUntil)));
|
||||
return List.copyOf(stored);
|
||||
}
|
||||
|
||||
private static int currencyIndex(ItemStack stack) {
|
||||
return stack == null || stack.isEmpty() ? -1 : currencyIndex(stack.getItem());
|
||||
}
|
||||
|
||||
private static int currencyIndex(Item item) {
|
||||
if (item == null) return -1;
|
||||
return CURRENCIES.indexOf(BuiltInRegistries.ITEM.getKey(item));
|
||||
}
|
||||
|
||||
private static String dimension(ServerLevel level) {
|
||||
return level.dimension().identifier().toString();
|
||||
}
|
||||
|
||||
private static final class Account {
|
||||
private final NonNullList<ItemStack> items;
|
||||
private final long[] balances = new long[VaultRules.CURRENCY_SLOTS];
|
||||
private long protectedUntil;
|
||||
private Account() { this(NonNullList.withSize(VaultRules.STORAGE_SLOTS, ItemStack.EMPTY), 0L); }
|
||||
private Account(NonNullList<ItemStack> items, long protectedUntil) {
|
||||
this.items = items;
|
||||
this.protectedUntil = protectedUntil;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class VaultContainer implements Container {
|
||||
private final VaultData data;
|
||||
private final UUID owner;
|
||||
private final ServerLevel level;
|
||||
private final BlockPos center;
|
||||
|
||||
private VaultContainer(VaultData data, UUID owner, ServerLevel level, BlockPos center) {
|
||||
this.data = data;
|
||||
this.owner = owner;
|
||||
this.level = level;
|
||||
this.center = center;
|
||||
private Account() {
|
||||
this(0L, 0L, 0L, 0L);
|
||||
}
|
||||
|
||||
@Override public int getContainerSize() { return VaultRules.STORAGE_SLOTS; }
|
||||
@Override public boolean isEmpty() { return data.items(owner).stream().allMatch(ItemStack::isEmpty); }
|
||||
@Override public ItemStack getItem(int slot) { return data.items(owner).get(slot); }
|
||||
@Override public ItemStack removeItem(int slot, int amount) {
|
||||
ItemStack removed = ContainerHelper.removeItem(data.items(owner), slot, amount);
|
||||
if (!removed.isEmpty()) setChanged();
|
||||
private Account(long rubies, long sapphires, long emeralds, long protectedUntil) {
|
||||
balances[0] = Math.max(0L, rubies);
|
||||
balances[1] = Math.max(0L, sapphires);
|
||||
balances[2] = Math.max(0L, emeralds);
|
||||
this.protectedUntil = Math.max(0L, protectedUntil);
|
||||
}
|
||||
|
||||
private long balance(int currency) {
|
||||
return balances[currency];
|
||||
}
|
||||
|
||||
private long add(int currency, long amount) {
|
||||
if (amount <= 0L) return 0L;
|
||||
long previous = balances[currency];
|
||||
balances[currency] = VaultRules.saturatingAdd(previous, amount);
|
||||
return balances[currency] - previous;
|
||||
}
|
||||
|
||||
private long remove(int currency, long amount) {
|
||||
if (amount <= 0L) return 0L;
|
||||
long removed = Math.min(amount, balances[currency]);
|
||||
balances[currency] -= removed;
|
||||
return removed;
|
||||
}
|
||||
@Override public ItemStack removeItemNoUpdate(int slot) {
|
||||
ItemStack removed = ContainerHelper.takeItem(data.items(owner), slot);
|
||||
if (!removed.isEmpty()) setChanged();
|
||||
return removed;
|
||||
|
||||
private boolean hasContents() {
|
||||
for (long balance : balances) if (balance > 0L) return true;
|
||||
return false;
|
||||
}
|
||||
@Override public void setItem(int slot, ItemStack stack) {
|
||||
if (stack != null && !stack.isEmpty() && !isCurrency(stack)) return;
|
||||
data.items(owner).set(slot, stack == null ? ItemStack.EMPTY : stack);
|
||||
setChanged();
|
||||
}
|
||||
@Override public void setChanged() { data.setDirty(); }
|
||||
@Override public boolean stillValid(Player player) {
|
||||
if (player == null || !player.getUUID().equals(owner)
|
||||
|| 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.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); }
|
||||
}
|
||||
|
||||
private record StoredSlot(int slot, ItemStack item) {}
|
||||
private record StoredAccount(String owner, List<StoredSlot> items, long protectedUntil) {}
|
||||
private record StoredAccount(String owner, List<StoredSlot> items, long rubies, long sapphires,
|
||||
long emeralds, long protectedUntil) {}
|
||||
private record VaultAddress(String dimension, long pos, String owner) {}
|
||||
}
|
||||
|
||||
+2
-5
@@ -3,7 +3,6 @@ package fr.koka99cab.sanctuary26.anotherworld.vault;
|
||||
import fr.koka99cab.sanctuary26.anotherworld.AnotherWorldMod;
|
||||
import fr.koka99cab.sanctuary26.anotherworld.registry.AnotherWorldItems;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents;
|
||||
@@ -125,14 +124,12 @@ public final class VaultDrillingService {
|
||||
private static void complete(ServerPlayer attacker, ServerLevel level, Session session,
|
||||
VaultStructure.Formed formed) {
|
||||
VaultData data = VaultData.get(level.getServer());
|
||||
List<ItemStack> loot = data.raidLoot(session.owner());
|
||||
if (loot.isEmpty()) {
|
||||
long total = data.transferRaid(session.owner(), attacker.getUUID());
|
||||
if (total <= 0L) {
|
||||
cancel(attacker, true);
|
||||
attacker.stopUsingItem();
|
||||
return;
|
||||
}
|
||||
int total = loot.stream().mapToInt(ItemStack::getCount).sum();
|
||||
loot.forEach(stack -> attacker.getInventory().placeItemBackInInventory(stack));
|
||||
data.protectAfterRaid(session.owner(), level.getServer().overworld().getGameTime());
|
||||
ItemStack drill = attacker.getItemInHand(session.hand());
|
||||
if (!attacker.hasInfiniteMaterials()) drill.shrink(1);
|
||||
|
||||
+43
-4
@@ -11,9 +11,11 @@ public final class VaultRules {
|
||||
+ 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 BALANCE_WORDS_PER_CURRENCY = 2;
|
||||
public static final int BALANCE_DATA_SLOTS = CURRENCY_SLOTS * BALANCE_WORDS_PER_CURRENCY;
|
||||
public static final int BUTTONS_PER_CURRENCY = 4;
|
||||
public static final long MAX_BALANCE = Long.MAX_VALUE;
|
||||
public static final int RAID_DURATION_TICKS = 60 * 20;
|
||||
public static final int RAID_LOOT_PERCENT = 20;
|
||||
public static final long RAID_PROTECTION_TICKS = 24L * 60L * 60L * 20L;
|
||||
@@ -21,10 +23,47 @@ public final class VaultRules {
|
||||
private VaultRules() {
|
||||
}
|
||||
|
||||
public static int raidLoot(int stored) {
|
||||
public static long raidLoot(long stored) {
|
||||
if (stored <= 0) return 0;
|
||||
long rounded = ((long) stored * RAID_LOOT_PERCENT + 99L) / 100L;
|
||||
return (int) Math.min(stored, Math.max(1L, rounded));
|
||||
long rounded = stored / 100L * RAID_LOOT_PERCENT
|
||||
+ (stored % 100L * RAID_LOOT_PERCENT + 99L) / 100L;
|
||||
return Math.min(stored, Math.max(1L, rounded));
|
||||
}
|
||||
|
||||
public static long saturatingAdd(long current, long added) {
|
||||
if (current < 0L || added <= 0L) return Math.max(0L, current);
|
||||
return added > MAX_BALANCE - current ? MAX_BALANCE : current + added;
|
||||
}
|
||||
|
||||
public static int balanceWord(long balance, int word) {
|
||||
long safe = Math.clamp(balance, 0L, MAX_BALANCE);
|
||||
return switch (word) {
|
||||
case 0 -> (int) safe;
|
||||
case 1 -> (int) (safe >>> 32);
|
||||
default -> 0;
|
||||
};
|
||||
}
|
||||
|
||||
public static long balanceFromWords(int low, int high) {
|
||||
return Math.max(0L, ((long) high << 32) | Integer.toUnsignedLong(low));
|
||||
}
|
||||
|
||||
public static String formatBalance(long balance) {
|
||||
long safe = Math.max(0L, balance);
|
||||
if (safe < 1_000L) return Long.toString(safe);
|
||||
long[] units = {1_000L, 1_000_000L, 1_000_000_000L, 1_000_000_000_000L,
|
||||
1_000_000_000_000_000L};
|
||||
String[] suffixes = {"K", "M", "B", "T", "Q"};
|
||||
int unitIndex = units.length - 1;
|
||||
while (unitIndex > 0 && safe < units[unitIndex]) unitIndex--;
|
||||
long unit = units[unitIndex];
|
||||
long whole = safe / unit;
|
||||
if (whole >= 1_000L) return safe / 1_000_000_000_000_000_000L + "E18";
|
||||
if (whole < 10L) {
|
||||
long tenth = safe % unit * 10L / unit;
|
||||
if (tenth > 0L) return whole + "." + tenth + suffixes[unitIndex];
|
||||
}
|
||||
return whole + suffixes[unitIndex];
|
||||
}
|
||||
|
||||
public static int progressPercent(int elapsedTicks) {
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ public final class VaultService {
|
||||
initialized = true;
|
||||
SanctuaryCurrencyStorage.register(AnotherWorldMod.id("safe_vault"), new SanctuaryCurrencyStorage.Provider() {
|
||||
@Override public int count(ServerPlayer player, net.minecraft.world.item.Item item) {
|
||||
return VaultData.get(player.level().getServer()).count(player.getUUID(), item);
|
||||
return VaultData.get(player.level().getServer()).countCapped(player.getUUID(), item);
|
||||
}
|
||||
@Override public int remove(ServerPlayer player, net.minecraft.world.item.Item item, int amount) {
|
||||
return VaultData.get(player.level().getServer()).remove(player.getUUID(), item, amount);
|
||||
|
||||
@@ -37,8 +37,8 @@
|
||||
"sanctuary26": {
|
||||
"system_type": "gameplay-system",
|
||||
"namespace": "anotherworld",
|
||||
"data_version": 4,
|
||||
"network_protocol": 1,
|
||||
"data_version": 5,
|
||||
"network_protocol": 2,
|
||||
"lifecycle": "${lifecycle}",
|
||||
"pack_version": "${pack_version}",
|
||||
"descriptions": {
|
||||
|
||||
+14
-2
@@ -18,8 +18,9 @@ public final class VaultRulesSmoke {
|
||||
"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(VaultRules.BALANCE_DATA_SLOTS == 6, "64-bit balance synchronization");
|
||||
require(VaultRules.MAX_BALANCE == Long.MAX_VALUE, "unlimited practical balance");
|
||||
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");
|
||||
@@ -51,7 +52,18 @@ public final class VaultRulesSmoke {
|
||||
require(VaultRules.raidLoot(1) == 1, "minimum loot");
|
||||
require(VaultRules.raidLoot(5) == 1, "exact 20 percent");
|
||||
require(VaultRules.raidLoot(64) == 13, "rounded 20 percent");
|
||||
require(VaultRules.raidLoot(Integer.MAX_VALUE) == 429_496_730, "bounded large balance");
|
||||
require(VaultRules.raidLoot(Integer.MAX_VALUE) == 429_496_730L, "32-bit balance raid");
|
||||
require(VaultRules.raidLoot(Long.MAX_VALUE) == 1_844_674_407_370_955_162L,
|
||||
"64-bit balance raid without overflow");
|
||||
require(VaultRules.saturatingAdd(Long.MAX_VALUE - 2L, 10L) == Long.MAX_VALUE,
|
||||
"balance saturation without overflow");
|
||||
for (long balance : new long[] {0L, Integer.MAX_VALUE, (long) Integer.MAX_VALUE + 1L, Long.MAX_VALUE}) {
|
||||
require(VaultRules.balanceFromWords(VaultRules.balanceWord(balance, 0),
|
||||
VaultRules.balanceWord(balance, 1)) == balance, "64-bit balance synchronization round trip");
|
||||
}
|
||||
require(VaultRules.formatBalance(999L).equals("999"), "small balance display");
|
||||
require(VaultRules.formatBalance(1_500L).equals("1.5K"), "compact balance display");
|
||||
require(VaultRules.formatBalance(1_000_000L).equals("1M"), "million balance display");
|
||||
require(VaultRules.progressPercent(0) == 0, "initial progress");
|
||||
require(VaultRules.progressPercent(600) == 50, "half progress");
|
||||
require(VaultRules.progressPercent(1_200) == 100, "complete progress");
|
||||
|
||||
+56
-11
@@ -1816,7 +1816,7 @@ tasks.register("verifyWorkspace") {
|
||||
|| terramixMigration.compatibility?.worldgen_changed != true
|
||||
|| terramixMigration.compatibility?.save_migration_required != false
|
||||
|| anotherWorldManifest?.custom?.sanctuary26?.data_version < 3
|
||||
|| anotherWorldManifest?.custom?.sanctuary26?.network_protocol != 1
|
||||
|| anotherWorldManifest?.custom?.sanctuary26?.network_protocol < 1
|
||||
|| sanctuaryManifest?.custom?.sanctuary26?.data_version < 9
|
||||
) {
|
||||
throw new GradleException("The alpha.145 native Terramix contract is incomplete")
|
||||
@@ -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.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| 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.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| 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,13 +4639,14 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") {
|
||||
|
||||
tasks.register("verifySafeVaultFeature") {
|
||||
group = "verification"
|
||||
description = "Checks the current hollow 3x3x3 safe, custom currency interface, drill and Shop contract."
|
||||
description = "Checks the current hollow 3x3x3 safe, unlimited balances, 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("pack/migrations/anotherworld-safe-vault-ctm-columns-alpha54.json"))
|
||||
inputs.file(file("pack/migrations/anotherworld-safe-vault-unlimited-balances-alpha55.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" })
|
||||
@@ -4662,11 +4663,14 @@ tasks.register("verifySafeVaultFeature") {
|
||||
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 ctmMigration = new JsonSlurper().parse(file("pack/migrations/anotherworld-safe-vault-ctm-columns-alpha54.json"))
|
||||
def unlimitedMigration = new JsonSlurper().parse(file(
|
||||
"pack/migrations/anotherworld-safe-vault-unlimited-balances-alpha55.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 drilling = file("anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultDrillingService.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
|
||||
@@ -4741,7 +4745,7 @@ tasks.register("verifySafeVaultFeature") {
|
||||
image == null || image.width != size[0] || image.height != size[1]
|
||||
}.keySet()
|
||||
if (rootProject.pack_version != "26.2.0-alpha.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| rootProject.sanctuary_version != "0.0.0-alpha.117"
|
||||
|| migration.schema_version != 1
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.201"
|
||||
@@ -4835,8 +4839,36 @@ tasks.register("verifySafeVaultFeature") {
|
||||
|| ctmMigration.compatibility?.saved_currency_balances_preserved != true
|
||||
|| ctmMigration.compatibility?.pack_release_updated != true
|
||||
|| ctmMigration.distribution?.packwiz_index_refreshed != true
|
||||
|| unlimitedMigration.source?.pack_version != "26.2.0-alpha.206"
|
||||
|| unlimitedMigration.source?.modules != [anotherworld: "0.0.0-alpha.54"]
|
||||
|| unlimitedMigration.target?.pack_version != "26.2.0-alpha.206"
|
||||
|| unlimitedMigration.target?.modules != [anotherworld: "0.0.0-alpha.55"]
|
||||
|| unlimitedMigration.safe_vault_balances?.source_storage != "27_item_stacks"
|
||||
|| unlimitedMigration.safe_vault_balances?.target_storage != "three_64_bit_balances"
|
||||
|| unlimitedMigration.safe_vault_balances?.currencies
|
||||
!= ["anotherworld:ruby", "anotherworld:sapphire", "minecraft:emerald"]
|
||||
|| unlimitedMigration.safe_vault_balances?.maximum_balance_per_currency?.toString()
|
||||
!= "9223372036854775807"
|
||||
|| unlimitedMigration.safe_vault_balances?.legacy_stacks_summed_into_balances != true
|
||||
|| unlimitedMigration.safe_vault_balances?.shop_access_when_structure_unloaded != true
|
||||
|| unlimitedMigration.safe_vault_balances?.client_sync_words_per_currency != 2
|
||||
|| unlimitedMigration.raid?.loot_percent != 20
|
||||
|| unlimitedMigration.raid?.loot_credited_to_attacker_safe != true
|
||||
|| unlimitedMigration.raid?.physical_item_spam_avoided != true
|
||||
|| unlimitedMigration.compatibility?.anotherworld_source_data_version != 4
|
||||
|| unlimitedMigration.compatibility?.anotherworld_target_data_version != 5
|
||||
|| unlimitedMigration.compatibility?.vault_source_data_version != 3
|
||||
|| unlimitedMigration.compatibility?.vault_target_data_version != 4
|
||||
|| unlimitedMigration.compatibility?.anotherworld_source_network_protocol != 1
|
||||
|| unlimitedMigration.compatibility?.anotherworld_target_network_protocol != 2
|
||||
|| unlimitedMigration.compatibility?.network_protocol_changed != true
|
||||
|| unlimitedMigration.compatibility?.saved_currency_balances_preserved != true
|
||||
|| unlimitedMigration.compatibility?.registry_ids_changed != false
|
||||
|| unlimitedMigration.compatibility?.pack_release_updated != false
|
||||
|| unlimitedMigration.distribution?.packwiz_index_refreshed != false
|
||||
|| manifest.depends?.sanctuary != ">=0.0.0-alpha.117"
|
||||
|| manifest.custom?.sanctuary26?.data_version != 4
|
||||
|| manifest.custom?.sanctuary26?.data_version != 5
|
||||
|| manifest.custom?.sanctuary26?.network_protocol != 2
|
||||
|| !file("build.gradle").text.contains('implementation project(":sanctuary")')
|
||||
|| !currencyApi.contains("public interface Provider")
|
||||
|| !currencyApi.contains("countAdditional") || !currencyApi.contains("removeAdditional")
|
||||
@@ -4846,9 +4878,18 @@ tasks.register("verifySafeVaultFeature") {
|
||||
|| !rules.contains("FULL_STRUCTURE_MASK & ~(1 << CENTER_PART_INDEX)")
|
||||
|| !rules.contains("COMPLETE_STRUCTURE_MASK")
|
||||
|| !rules.contains("CURRENCY_SLOTS = 3")
|
||||
|| !rules.contains("BALANCE_DATA_SLOTS = CURRENCY_SLOTS * BALANCE_WORDS_PER_CURRENCY")
|
||||
|| !rules.contains("MAX_BALANCE = Long.MAX_VALUE")
|
||||
|| !rules.contains("raidLoot(long stored)")
|
||||
|| !rules.contains("balanceFromWords") || !rules.contains("formatBalance")
|
||||
|| !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 = 3")
|
||||
|| !data.contains('SAVE_KEY = "safe_vaults"') || !data.contains("DATA_VERSION = 4")
|
||||
|| !data.contains('Codec.LONG.optionalFieldOf("rubies", 0L)')
|
||||
|| !data.contains('Codec.LONG.optionalFieldOf("sapphires", 0L)')
|
||||
|| !data.contains('Codec.LONG.optionalFieldOf("emeralds", 0L)')
|
||||
|| !data.contains("for (StoredSlot slot : stored.items())")
|
||||
|| !data.contains("transferRaid(UUID owner, UUID attacker)")
|
||||
|| !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()")
|
||||
@@ -4858,7 +4899,11 @@ tasks.register("verifySafeVaultFeature") {
|
||||
|| !controller.contains("VaultStructure.find") || !controller.contains("formed.center()")
|
||||
|| !menu.contains("clickMenuButton") || !menu.contains("SanctuaryPlayerInventoryView.unlockedRows")
|
||||
|| !menu.contains("PLAYER_INVENTORY_Y = 108")
|
||||
|| !menu.contains("new SimpleContainerData(VaultRules.BALANCE_DATA_SLOTS)")
|
||||
|| !menu.contains("VaultRules.balanceFromWords")
|
||||
|| !drilling.contains("data.transferRaid(session.owner(), attacker.getUUID())")
|
||||
|| !screen.contains("handleInventoryButtonClick") || !screen.contains('"− ×64", "− ×1", "+ ×1", "+ ×64"')
|
||||
|| !screen.contains("VaultRules.formatBalance(menu.balance(currency))")
|
||||
|| screen.contains("inventoryLabelY =")
|
||||
|| safeBlockState.multipart?.size() != 109
|
||||
|| safeBlockState.multipart?.count { it.when?.formed == "true" } != 108
|
||||
@@ -4892,7 +4937,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.189.jar" }
|
||||
if (rootProject.pack_version != "26.2.0-alpha.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| 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"
|
||||
@@ -4938,7 +4983,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.189.jar" }
|
||||
if (rootProject.pack_version != "26.2.0-alpha.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| 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"
|
||||
@@ -4992,7 +5037,7 @@ tasks.register("verifySafeVaultCubeAlpha205Release") {
|
||||
def packwizIndex = file("pack/packwiz/index.toml").text
|
||||
def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.27.0.189.jar" }
|
||||
if (rootProject.pack_version != "26.2.0-alpha.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.204"
|
||||
|| migration.source?.modules != [anotherworld: "0.0.0-alpha.52"]
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.205"
|
||||
@@ -5050,7 +5095,7 @@ tasks.register("verifySafeVaultCtmAlpha206Release") {
|
||||
def packwizIndex = file("pack/packwiz/index.toml").text
|
||||
def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.27.0.189.jar" }
|
||||
if (rootProject.pack_version != "26.2.0-alpha.206"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.54"
|
||||
|| rootProject.anotherworld_version != "0.0.0-alpha.55"
|
||||
|| migration.source?.pack_version != "26.2.0-alpha.205"
|
||||
|| migration.source?.modules != [anotherworld: "0.0.0-alpha.53"]
|
||||
|| migration.target?.pack_version != "26.2.0-alpha.206"
|
||||
|
||||
+1
-1
@@ -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.54
|
||||
anotherworld_version=0.0.0-alpha.55
|
||||
anotherworld_lifecycle=active
|
||||
itsalive_version=0.0.0-alpha.31
|
||||
itsalive_lifecycle=active
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"source": {
|
||||
"pack_version": "26.2.0-alpha.206",
|
||||
"modules": {
|
||||
"anotherworld": "0.0.0-alpha.54"
|
||||
}
|
||||
},
|
||||
"target": {
|
||||
"pack_version": "26.2.0-alpha.206",
|
||||
"modules": {
|
||||
"anotherworld": "0.0.0-alpha.55"
|
||||
}
|
||||
},
|
||||
"safe_vault_balances": {
|
||||
"source_storage": "27_item_stacks",
|
||||
"target_storage": "three_64_bit_balances",
|
||||
"currencies": [
|
||||
"anotherworld:ruby",
|
||||
"anotherworld:sapphire",
|
||||
"minecraft:emerald"
|
||||
],
|
||||
"maximum_balance_per_currency": 9223372036854775807,
|
||||
"legacy_stacks_summed_into_balances": true,
|
||||
"shop_access_when_structure_unloaded": true,
|
||||
"client_sync_words_per_currency": 2
|
||||
},
|
||||
"raid": {
|
||||
"loot_percent": 20,
|
||||
"loot_credited_to_attacker_safe": true,
|
||||
"physical_item_spam_avoided": true
|
||||
},
|
||||
"compatibility": {
|
||||
"anotherworld_source_data_version": 4,
|
||||
"anotherworld_target_data_version": 5,
|
||||
"vault_source_data_version": 3,
|
||||
"vault_target_data_version": 4,
|
||||
"anotherworld_source_network_protocol": 1,
|
||||
"anotherworld_target_network_protocol": 2,
|
||||
"network_protocol_changed": true,
|
||||
"saved_currency_balances_preserved": true,
|
||||
"registry_ids_changed": false,
|
||||
"pack_release_updated": false
|
||||
},
|
||||
"distribution": {
|
||||
"packwiz_index_refreshed": false
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user