From d2abbb3155e8718d58923832ffe8b9b16bded84f Mon Sep 17 00:00:00 2001 From: koka Date: Mon, 31 Aug 2026 04:01:46 +0200 Subject: [PATCH 1/7] fix(anotherworld): require a vault before raiding --- CHANGELOG.md | 8 ++++++++ anotherworld/build.gradle | 7 +++++-- .../anotherworld/vault/VaultData.java | 12 +++++++++++- .../vault/VaultDrillingService.java | 11 +++++++++++ .../anotherworld/vault/VaultRulesSmoke.java | 10 ++++++++++ build.gradle | 17 ++++++++--------- gradle.properties | 2 +- 7 files changed, 54 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8739dce..66a3da1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,14 @@ 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. +## Non distribué + +Module modifié : **Another World `0.0.0-alpha.56`**. Le pack public reste temporairement en `26.2.0-alpha.222` jusqu'à la publication. + +- exige que l'attaquant possède son propre coffre-fort actif avant de pouvoir lancer ou achever le forage d'un autre coffre-fort ; +- refuse aussi le crédit du butin côté données si le coffre-fort de l'attaquant disparaît pendant le forage, sans changer les données v4 ni les sauvegardes existantes ; +- ajoute le refus explicite en français, anglais et russe. + ## `26.2.0-alpha.222` Modules modifiés : **Red-Stoner `0.0.0-alpha.13`** et **Sanctuary `0.0.0-alpha.124`**. Les huit autres modules conservent leur version issue de l'alpha.221. diff --git a/anotherworld/build.gradle b/anotherworld/build.gradle index 2b9d65b..1e2226e 100644 --- a/anotherworld/build.gradle +++ b/anotherworld/build.gradle @@ -1647,6 +1647,7 @@ tasks.register("generateAnotherWorldResources") { "message.anotherworld.safe_vault.empty_before_break": "Videz le coffre-fort et attendez la fin du forage avant de le démonter.", "message.anotherworld.safe_vault.drill_own": "Vous ne pouvez pas forer votre propre coffre-fort.", "message.anotherworld.safe_vault.inactive": "Ce coffre-fort n’est pas actif.", + "message.anotherworld.safe_vault.raid_requires_vault": "Vous devez posséder un coffre-fort actif pour en braquer un autre.", "message.anotherworld.safe_vault.empty": "Ce coffre-fort est vide.", "message.anotherworld.safe_vault.owner_offline": "Le propriétaire doit être connecté pour que le coffre-fort soit attaquable.", "message.anotherworld.safe_vault.protected": "Ce coffre-fort reste protégé pendant environ %s minute(s).", @@ -1671,6 +1672,7 @@ tasks.register("generateAnotherWorldResources") { "message.anotherworld.safe_vault.empty_before_break": "Опустошите сейф и дождитесь окончания сверления перед разборкой.", "message.anotherworld.safe_vault.drill_own": "Нельзя сверлить собственный сейф.", "message.anotherworld.safe_vault.inactive": "Этот сейф не активен.", + "message.anotherworld.safe_vault.raid_requires_vault": "Чтобы ограбить чужой сейф, у вас должен быть собственный активный сейф.", "message.anotherworld.safe_vault.empty": "Этот сейф пуст.", "message.anotherworld.safe_vault.owner_offline": "Владелец должен быть в сети, чтобы атаковать сейф.", "message.anotherworld.safe_vault.protected": "Сейф защищён ещё примерно %s минут(ы).", @@ -1695,6 +1697,7 @@ tasks.register("generateAnotherWorldResources") { "message.anotherworld.safe_vault.empty_before_break": "Empty the safe and wait for drilling to end before dismantling it.", "message.anotherworld.safe_vault.drill_own": "You cannot drill your own safe.", "message.anotherworld.safe_vault.inactive": "This safe is not active.", + "message.anotherworld.safe_vault.raid_requires_vault": "You must own an active safe before raiding another one.", "message.anotherworld.safe_vault.empty": "This safe is empty.", "message.anotherworld.safe_vault.owner_offline": "The owner must be online before the safe can be raided.", "message.anotherworld.safe_vault.protected": "This safe remains protected for about %s minute(s).", @@ -1953,7 +1956,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.55" + if (project.version.toString() != "0.0.0-alpha.56" || 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 +3273,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.55" + if (project.version.toString() != "0.0.0-alpha.56" || 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" diff --git a/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultData.java b/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultData.java index 3303d7d..978f5e1 100644 --- a/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultData.java +++ b/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultData.java @@ -113,6 +113,12 @@ public final class VaultData extends SavedData { && address.pos() == center.asLong() && address.owner().equals(ownerId)); } + public boolean hasRegisteredVault(UUID owner) { + if (owner == null) return false; + String ownerId = owner.toString(); + return vaults.stream().anyMatch(address -> address.owner().equals(ownerId)); + } + public void unregisterNear(ServerLevel level, BlockPos member) { String dimension = dimension(level); boolean changed = vaults.removeIf(address -> { @@ -163,7 +169,7 @@ public final class VaultData extends SavedData { /** 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; + if (!canReceiveRaidLoot(owner, attacker, hasRegisteredVault(attacker))) return 0L; Account source = accounts.get(owner); if (source == null) return 0L; Account target = accounts.computeIfAbsent(attacker, ignored -> new Account()); @@ -180,6 +186,10 @@ public final class VaultData extends SavedData { return total; } + static boolean canReceiveRaidLoot(UUID owner, UUID attacker, boolean attackerHasRegisteredVault) { + return owner != null && attacker != null && !owner.equals(attacker) && attackerHasRegisteredVault; + } + public long protectionRemaining(UUID owner, long gameTime) { Account account = accounts.get(owner); return account == null ? 0L : Math.max(0L, account.protectedUntil - gameTime); diff --git a/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultDrillingService.java b/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultDrillingService.java index 74d71b8..f079ced 100644 --- a/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultDrillingService.java +++ b/anotherworld/src/main/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultDrillingService.java @@ -48,6 +48,10 @@ public final class VaultDrillingService { attacker.sendSystemMessage(Component.translatable("message.anotherworld.safe_vault.inactive")); return false; } + if (!data.hasRegisteredVault(attacker.getUUID())) { + attacker.sendSystemMessage(Component.translatable("message.anotherworld.safe_vault.raid_requires_vault")); + return false; + } if (!data.hasContents(formed.owner())) { attacker.sendSystemMessage(Component.translatable("message.anotherworld.safe_vault.empty")); return false; @@ -104,6 +108,13 @@ public final class VaultDrillingService { attacker.stopUsingItem(); return; } + if (!VaultData.get(level.getServer()).hasRegisteredVault(attacker.getUUID())) { + cancel(attacker, false); + attacker.sendOverlayMessage(Component.translatable( + "message.anotherworld.safe_vault.raid_requires_vault")); + attacker.stopUsingItem(); + return; + } int elapsed = session.elapsedTicks() + 1; Session progressed = session.withElapsed(elapsed); diff --git a/anotherworld/src/test/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultRulesSmoke.java b/anotherworld/src/test/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultRulesSmoke.java index 34a8c0f..7ee23fd 100644 --- a/anotherworld/src/test/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultRulesSmoke.java +++ b/anotherworld/src/test/java/fr/koka99cab/sanctuary26/anotherworld/vault/VaultRulesSmoke.java @@ -1,5 +1,7 @@ package fr.koka99cab.sanctuary26.anotherworld.vault; +import java.util.UUID; + public final class VaultRulesSmoke { private VaultRulesSmoke() { } @@ -55,6 +57,14 @@ public final class VaultRulesSmoke { 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"); + UUID owner = UUID.fromString("00000000-0000-0000-0000-000000000001"); + UUID attacker = UUID.fromString("00000000-0000-0000-0000-000000000002"); + require(!VaultData.canReceiveRaidLoot(owner, attacker, false), + "an attacker without a registered vault cannot receive raid loot"); + require(VaultData.canReceiveRaidLoot(owner, attacker, true), + "an attacker with a registered vault can receive raid loot"); + require(!VaultData.canReceiveRaidLoot(owner, owner, true), + "a vault owner cannot receive loot from their own vault"); 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}) { diff --git a/build.gradle b/build.gradle index cb566af..d460f76 100644 --- a/build.gradle +++ b/build.gradle @@ -3488,7 +3488,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.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || rootProject.redstoner_version != "0.0.0-alpha.13" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version || migration.source?.pack_version != "26.2.0-alpha.191" @@ -4739,7 +4739,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.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || rootProject.itsalive_version != "0.0.0-alpha.36" || rootProject.iliketomoveit_version != "0.0.0-alpha.16" || rootProject.sanctuary_version != "0.0.0-alpha.124" @@ -4899,7 +4899,7 @@ tasks.register("verifySafeVaultFeature") { image == null || image.width != size[0] || image.height != size[1] }.keySet() if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || rootProject.sanctuary_version != "0.0.0-alpha.124" || migration.schema_version != 1 || migration.source?.pack_version != "26.2.0-alpha.201" @@ -5091,7 +5091,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.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || 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" @@ -5137,7 +5137,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.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || 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" @@ -5191,7 +5191,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.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || 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" @@ -5249,7 +5249,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.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || 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" @@ -5301,7 +5301,7 @@ tasks.register("verifySafeVaultUnlimitedAlpha207Release") { def packwizIndex = file("pack/packwiz/index.toml").text def jeiFiles = prism.files.findAll { it.path == "mods/jei-26.2-fabric-30.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.anotherworld_version != "0.0.0-alpha.55" + || rootProject.anotherworld_version != "0.0.0-alpha.56" || migration.source?.pack_version != "26.2.0-alpha.206" || migration.source?.modules != [anotherworld: "0.0.0-alpha.54"] || migration.target?.pack_version != "26.2.0-alpha.207" @@ -6943,7 +6943,6 @@ tasks.register("verifyAlpha222Release") { || jeiFiles[0].hashes?.sha1 != "c2f2c6b5822a560fe9872921b908ffc2f3297d00" || jeiFiles[0].hashes?.sha512 != "c62a3e264d4b0ec398b9aa717a4832eecb8663bbcec4483dc58a9999d5e4e55ca4f5bca285a0d4a003220c698c3e87c8a3294366e085e72545e4afe84aec92c7" || !changelog.contains("## `26.2.0-alpha.222`") - || changelog.contains("## Non distribué") || !readme.contains("Version courante du pack distribué : **`26.2.0-alpha.222`**")) { throw new GradleException("The alpha.222 terminal-search and quest-tracker release is incomplete") } diff --git a/gradle.properties b/gradle.properties index 03e3b5e..0545575 100644 --- a/gradle.properties +++ b/gradle.properties @@ -16,7 +16,7 @@ ambiance_version=0.0.0-alpha.22 ambiance_lifecycle=active redstoner_version=0.0.0-alpha.13 redstoner_lifecycle=active -anotherworld_version=0.0.0-alpha.55 +anotherworld_version=0.0.0-alpha.56 anotherworld_lifecycle=active itsalive_version=0.0.0-alpha.36 itsalive_lifecycle=active -- 2.54.0 From 233ca449351643a051d96430939b0cba09f8fd47 Mon Sep 17 00:00:00 2001 From: koka Date: Mon, 31 Aug 2026 04:10:42 +0200 Subject: [PATCH 2/7] fix(sanctuary): replace impossible phantom quests --- CHANGELOG.md | 4 ++- build.gradle | 29 +++++++++--------- gradle.properties | 2 +- sanctuary/build.gradle | 22 +++++++------- .../sanctuary/shop/QuestBoardData.java | 26 +++++++++++++--- .../sanctuary/shop/QuestBoardGenerator.java | 30 +++++++++++++++---- .../sanctuary/shop/QuestBoardModelSmoke.java | 10 +++++++ 7 files changed, 86 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 66a3da1..05e1281 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,13 @@ Ce journal suit les **versions du modpack**. Lorsqu'un seul module change, sa ve ## Non distribué -Module modifié : **Another World `0.0.0-alpha.56`**. Le pack public reste temporairement en `26.2.0-alpha.222` jusqu'à la publication. +Modules modifiés : **Another World `0.0.0-alpha.56`** et **Sanctuary `0.0.0-alpha.125`**. Le pack public reste temporairement en `26.2.0-alpha.222` jusqu'à la publication. - exige que l'attaquant possède son propre coffre-fort actif avant de pouvoir lancer ou achever le forage d'un autre coffre-fort ; - refuse aussi le crédit du butin côté données si le coffre-fort de l'attaquant disparaît pendant le forage, sans changer les données v4 ni les sauvegardes existantes ; - ajoute le refus explicite en français, anglais et russe. +- remplace les quêtes saphir de Phantoms, désactivés dans Sanctuary, par les fantômes disponibles d’It's Alive ; +- migre automatiquement les contrats Phantom déjà sauvegardés vers `itsalive:ghost` en conservant leur progression, leur réservation et leur récompense ; les données du panneau de quêtes passent de v1 à v2 tandis que les données Sanctuary v11 et le protocole 22 restent inchangés. ## `26.2.0-alpha.222` diff --git a/build.gradle b/build.gradle index d460f76..ba58dc1 100644 --- a/build.gradle +++ b/build.gradle @@ -3438,7 +3438,7 @@ tasks.register("verifyProgressivePauseMenuRelease") { "sanctuary/src/main/resources/assets/sanctuary/lang/${locale}.json"))] } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || rootProject.onlyfun_version != "0.0.0-alpha.25" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version || migration.source?.modules != [sanctuary: "0.0.0-alpha.108", onlyfun: "0.0.0-alpha.17"] @@ -4279,7 +4279,7 @@ tasks.register("verifyShopPricingLayoutRelease") { def index = new JsonSlurper().parse(file("pack/prism/modrinth.index.json")) if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.onlyfun_version != "0.0.0-alpha.25" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version || migration.source?.pack_version != "26.2.0-alpha.192" || migration.target?.pack_version != "26.2.0-alpha.193" @@ -4373,7 +4373,7 @@ tasks.register("verifyShopCsvBossGatesRelease") { def offerCatalog = file("sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.onlyfun_version != "0.0.0-alpha.25" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || release.pack_version != rootProject.pack_version || index.versionId != rootProject.pack_version || migration.source?.pack_version != "26.2.0-alpha.194" || migration.source?.modules != [onlyfun: "0.0.0-alpha.18", sanctuary: "0.0.0-alpha.110"] @@ -4465,7 +4465,7 @@ tasks.register("verifyQuestRequestsCauldronBatchesRelease") { def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.itsalive_version != "0.0.0-alpha.36" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.196" || migration.target?.pack_version != "26.2.0-alpha.197" || migration.target?.modules != [itsalive: "0.0.0-alpha.29", sanctuary: "0.0.0-alpha.113"] @@ -4565,7 +4565,7 @@ tasks.register("verifyQuestRequestContractsRelease") { def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.itsalive_version != "0.0.0-alpha.36" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.198" || migration.source?.modules?.sanctuary != "0.0.0-alpha.114" || migration.target?.pack_version != "26.2.0-alpha.199" @@ -4685,7 +4685,7 @@ tasks.register("verifyQuestRequestEscrowRelease") { def packwizIndex = file("pack/packwiz/index.toml").text def sanctuaryManifest = new JsonSlurper().parse(file("sanctuary/src/main/resources/fabric.mod.json")) if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.200" || migration.source?.modules?.sanctuary != "0.0.0-alpha.115" || migration.target?.pack_version != "26.2.0-alpha.201" @@ -4742,7 +4742,7 @@ tasks.register("verifyWaystoneShopCulinaryAlpha202Release") { || rootProject.anotherworld_version != "0.0.0-alpha.56" || rootProject.itsalive_version != "0.0.0-alpha.36" || rootProject.iliketomoveit_version != "0.0.0-alpha.16" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.201" || migration.source?.modules != [ itsalive: "0.0.0-alpha.30", @@ -4900,7 +4900,7 @@ tasks.register("verifySafeVaultFeature") { }.keySet() if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.anotherworld_version != "0.0.0-alpha.56" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.schema_version != 1 || migration.source?.pack_version != "26.2.0-alpha.201" || migration.target?.pack_version != "26.2.0-alpha.202" @@ -5759,7 +5759,7 @@ tasks.register("verifyAlpha210Release") { it.path == "mods/jei-26.2-fabric-30.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || rootProject.onlyfun_version != "0.0.0-alpha.25" || rootProject.iliketomoveit_version != currentModules.iliketomoveit || rootProject.itsalive_version != "0.0.0-alpha.36" @@ -5858,7 +5858,7 @@ tasks.register("verifyAlpha211Release") { onlyfun: "0.0.0-alpha.25", ambiance: "0.0.0-alpha.22", iliketomoveit: "0.0.0-alpha.16"] - def workspaceModules = currentModules + def workspaceModules = currentModules + [sanctuary: "0.0.0-alpha.125"] def expectedDataVersions = [ambiance: 2, itsalive: 3, onlyfun: 2, ouch: 1, sanctuary: 11] def expectedProtocols = [ambiance: 6, itsalive: 4, onlyfun: 3, ouch: 1, sanctuary: 22] def manifests = expectedTarget.collectEntries { id, version -> @@ -5956,7 +5956,7 @@ tasks.register("verifyAlpha212Release") { it.path == "mods/jei-26.2-fabric-30.29.0.196.jar" } if (rootProject.pack_version != "26.2.0-alpha.222" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.211" || migration.source?.modules != [sanctuary: "0.0.0-alpha.119"] || migration.target?.pack_version != "26.2.0-alpha.212" @@ -6449,7 +6449,7 @@ tasks.register("verifyAlpha218Release") { || currentModules.findAll { id, version -> id != "redstoner" && id != "sanctuary" }.any { id, version -> rootProject.property("${id}_version") != version } - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.217" || migration.source?.modules != sourceModules || migration.target?.pack_version != "26.2.0-alpha.218" @@ -6533,6 +6533,7 @@ tasks.register("verifyAlpha219Release") { sanctuary: "0.0.0-alpha.122", iliketomoveit: "0.0.0-alpha.16", ambiance: "0.0.0-alpha.21"] def currentModules = targetModules + [ ambiance: "0.0.0-alpha.22", sanctuary: "0.0.0-alpha.124"] + def workspaceModules = currentModules + [sanctuary: "0.0.0-alpha.125"] def requiredJars = currentModules.collect { id, version -> "file = \"mods/${id}-${version}.jar\"" } @@ -6548,7 +6549,7 @@ tasks.register("verifyAlpha219Release") { exclude "**/build/**", "**/.gradle/**", "**/.git/**" }.files if (rootProject.pack_version != "26.2.0-alpha.222" - || currentModules.any { id, version -> rootProject.property("${id}_version") != version } + || workspaceModules.any { id, version -> rootProject.property("${id}_version") != version } || migration.source?.pack_version != "26.2.0-alpha.218" || migration.source?.modules != sourceModules || migration.target?.pack_version != "26.2.0-alpha.219" @@ -6857,7 +6858,7 @@ tasks.register("verifyAlpha222Release") { } if (rootProject.pack_version != "26.2.0-alpha.222" || rootProject.redstoner_version != "0.0.0-alpha.13" - || rootProject.sanctuary_version != "0.0.0-alpha.124" + || rootProject.sanctuary_version != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.221" || migration.source?.modules != [ redstoner: "0.0.0-alpha.12", sanctuary: "0.0.0-alpha.122"] diff --git a/gradle.properties b/gradle.properties index 0545575..5986244 100644 --- a/gradle.properties +++ b/gradle.properties @@ -28,7 +28,7 @@ iliketomoveit_version=0.0.0-alpha.16 iliketomoveit_lifecycle=active onlyfun_version=0.0.0-alpha.25 onlyfun_lifecycle=active -sanctuary_version=0.0.0-alpha.124 +sanctuary_version=0.0.0-alpha.125 sanctuary_lifecycle=active pack_version=26.2.0-alpha.222 maven_group=fr.koka99cab.sanctuary26 diff --git a/sanctuary/build.gradle b/sanctuary/build.gradle index 6d82037..73e835a 100644 --- a/sanctuary/build.gradle +++ b/sanctuary/build.gradle @@ -151,7 +151,7 @@ tasks.register("verifyBlackMarket") { def questData = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java").text def quests = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardService.java").text def inventoryView = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/api/inventory/SanctuaryPlayerInventoryView.java").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || !data.contains('SAVE_KEY = "black_market"') || !data.contains("DATA_VERSION = 2") || !data.contains("ItemStack.CODEC.fieldOf(\"item\")") || !data.contains("replaceListing") || !service.contains("LISTING_FEE_RUBIES = 1") || !service.contains("COMMISSION_PERCENT = 5") @@ -2850,7 +2850,7 @@ tasks.register("verifyShopCurrencyRowsRelease") { "src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/BlackMarketService.java").text def shop = file( "src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopService.java").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.modules?.sanctuary != "0.0.0-alpha.117" || migration.shop_currency_inventory?.all_unlocked_rows_counted != true || migration.shop_currency_inventory?.overflow_rows_counted != true @@ -3016,7 +3016,7 @@ tasks.register("verifyProgressivePauseMenu") { "pack/migrations/26.2.0-alpha.190-progressive-pause-menu-to-alpha.191.json")) def pauseMenu = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/PauseScreenMixin.java").text def costs = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/progression/SanctuaryProgressionCosts.java").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.pack_version != "26.2.0-alpha.191" || migration.target?.modules?.sanctuary != "0.0.0-alpha.109" || migration.pause_menu?.progression_full_width != true @@ -3054,7 +3054,7 @@ tasks.register("verifyShopPricingLayout") { "pack/migrations/26.2.0-alpha.192-shop-pricing-layout-to-alpha.193.json")) def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryShopScreen.java").text def progression = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopProgression.java").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.modules?.sanctuary != "0.0.0-alpha.110" || migration.shop_layout?.locked_offer_buttons != 6 || migration.shop_layout?.button_slots != [4, 5, 6, 7, 8, 9] @@ -3085,7 +3085,7 @@ tasks.register("verifyShopCsvBossGates") { "pack/migrations/26.2.0-alpha.194-shop-csv-boss-gates-to-alpha.195.json")) def provider = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopCatalogProvider.java").text def catalog = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/ShopOfferCatalog.java").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.pack_version != "26.2.0-alpha.195" || migration.target?.modules?.sanctuary != "0.0.0-alpha.111" || migration.compatibility?.sanctuary_data_version != 11 @@ -3116,7 +3116,7 @@ tasks.register("verifyDeliveryBoxOrientation") { def blockstate = new JsonSlurper().parse( file("src/main/resources/assets/sanctuary/blockstates/delivery_box.json")) def expectedVariants = ["facing=north", "facing=east", "facing=south", "facing=west"].toSet() - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.modules?.sanctuary != "0.0.0-alpha.112" || migration.mailbox?.id != "sanctuary:delivery_box" || migration.mailbox?.horizontal_facing != true @@ -3144,7 +3144,7 @@ tasks.register("verifyInventoryShiftClick") { def mixin = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/AbstractContainerMenuMixin.java").text def screen = file("src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/AbstractContainerScreenMixin.java").text def gui = file("INVENTORY_GUI.md").text - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || !transfer.contains("shouldAppendOverflow") || !transfer.contains("isVanillaStorageRange") || !transfer.contains("hotbarStart") @@ -3190,7 +3190,7 @@ tasks.register("verifyQuestRequests") { new JsonSlurper().parse(file("src/main/resources/data/sanctuary/loot_table/blocks/${path}.json")) .pools[0].entries[0].name } - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.modules?.sanctuary != "0.0.0-alpha.113" || migration.quest_requests?.save_key != "quest_requests" || migration.quest_requests?.data_version != 1 @@ -3248,7 +3248,7 @@ tasks.register("verifyQuestRequestContracts") { def locales = ["fr_fr", "en_us", "ru_ru"].collectEntries { locale -> [(locale): new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${locale}.json"))] } - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.198" || migration.source?.modules?.sanctuary != "0.0.0-alpha.114" || migration.target?.pack_version != "26.2.0-alpha.199" @@ -3317,7 +3317,7 @@ tasks.register("verifyQuestRequestEscrow") { def locales = ["fr_fr", "en_us", "ru_ru"].collectEntries { locale -> [(locale): new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${locale}.json"))] } - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.source?.pack_version != "26.2.0-alpha.200" || migration.source?.modules?.sanctuary != "0.0.0-alpha.115" || migration.target?.pack_version != "26.2.0-alpha.201" @@ -3389,7 +3389,7 @@ tasks.register("verifyAlphaIndev") { def locales = ["fr_fr", "en_us", "ru_ru"].collect { new JsonSlurper().parse(file("src/main/resources/assets/sanctuary/lang/${it}.json")) } - if (project.version.toString() != "0.0.0-alpha.124" + if (project.version.toString() != "0.0.0-alpha.125" || migration.target?.modules?.sanctuary != "0.0.0-alpha.122" || migration.alpha_world?.dimension != "sanctuary:alpha" || migration.alpha_world?.legacy_dimension != "portals:alpha" diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java index 4737b1b..bde3fd5 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardData.java @@ -17,7 +17,8 @@ import net.minecraft.world.level.saveddata.SavedDataType; /** Server-authoritative state for physical, renewable quest signs. */ public final class QuestBoardData extends SavedData { public static final String SAVE_KEY = "black_market_quests"; - public static final int DATA_VERSION = 1; + private static final int LEGACY_DATA_VERSION = 1; + public static final int DATA_VERSION = 2; private static final int MAX_AUDIT_ENTRIES = 4096; private static final Codec OBJECTIVE_CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -66,7 +67,7 @@ public final class QuestBoardData extends SavedData { Codec.STRING.optionalFieldOf("detail", "").forGetter(AuditEntry::detail) ).apply(instance, AuditEntry::new)); private static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - Codec.INT.optionalFieldOf("data_version", DATA_VERSION).forGetter(data -> data.dataVersion), + Codec.INT.optionalFieldOf("data_version", LEGACY_DATA_VERSION).forGetter(data -> data.dataVersion), BOARD_CODEC.listOf().optionalFieldOf("boards", List.of()).forGetter(data -> data.boards), AUDIT_CODEC.listOf().optionalFieldOf("audit", List.of()).forGetter(data -> data.audit) ).apply(instance, QuestBoardData::new)); @@ -79,7 +80,7 @@ public final class QuestBoardData extends SavedData { public QuestBoardData() { this(DATA_VERSION, List.of(), List.of()); } private QuestBoardData(int dataVersion, List boards, List audit) { - this.dataVersion = DATA_VERSION; + this.dataVersion = Math.max(LEGACY_DATA_VERSION, dataVersion); this.boards = new ArrayList<>(boards); this.audit = new ArrayList<>(audit.stream().skip(Math.max(0, audit.size() - MAX_AUDIT_ENTRIES)).toList()); } @@ -88,10 +89,27 @@ public final class QuestBoardData extends SavedData { ServerLevel overworld = server.getLevel(Level.OVERWORLD); if (overworld == null) throw new IllegalStateException("Overworld unavailable for quest-board data"); QuestBoardData data = overworld.getDataStorage().computeIfAbsent(TYPE); - if (data.dataVersion < DATA_VERSION) { data.dataVersion = DATA_VERSION; data.setDirty(); } + if (data.migrateToCurrent()) data.setDirty(); return data; } + private boolean migrateToCurrent() { + if (dataVersion >= DATA_VERSION) return false; + if (dataVersion < 2) { + for (int index = 0; index < boards.size(); index++) { + Board board = boards.get(index); + Contract contract = board.contract().orElse(null); + if (contract == null) continue; + Objective migrated = QuestBoardGenerator.migrateUnavailableTarget(contract.objective()); + if (migrated != contract.objective()) { + boards.set(index, board.withContract(Optional.of(contract.withObjective(migrated)))); + } + } + } + dataVersion = DATA_VERSION; + return true; + } + public List boards() { return List.copyOf(boards); } public Optional board(String id) { return boards.stream().filter(value -> value.id.equals(id)).findFirst(); } public Optional boardAt(String dimension, long pos) { diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java index 3090e05..a7bfdea 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestBoardGenerator.java @@ -46,7 +46,7 @@ final class QuestBoardGenerator { private static final List