diff --git a/CHANGELOG.md b/CHANGELOG.md index 8739dce..ce5d328 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,15 @@ 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é : **Sanctuary `0.0.0-alpha.125`**. Le pack public reste temporairement en `26.2.0-alpha.222` jusqu'à la publication. + +- ajoute un style configurable au suivi des quêtes (`N` par défaut), entre le texte transparent et le panneau original de Chris ; +- place automatiquement le style texte sous la hauteur réelle de la colonne gauche du F3 permanent afin que les deux affichages ne se recouvrent pas ; +- nomme et ordonne les contrats suivis par niveau de récompense, rubis puis saphir puis émeraude/autres, au lieu du libellé générique « Contrat du jour » ; +- conserve les données Sanctuary v11, le protocole réseau 22, les IDs et les sauvegardes existantes. + ## `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/build.gradle b/build.gradle index cb566af..e0c0723 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.55" || 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.55" - || 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"] @@ -6921,9 +6922,10 @@ tasks.register("verifyAlpha222Release") { || !questPayload.contains('SanctuaryMod.id("s2c/quest_tracker")') || !questSync.contains("tracksAcceptedRequest(request, playerId)") || !questSync.contains("SOURCE_BOARD") - || !questHud.contains("Transparent, toggleable text overlay") + || !questHud.contains("transparent F3-aligned") || !questHud.contains("entries.isEmpty()) return") - || questHud.contains("graphics.fill(") + || !questHud.contains("renderText(") + || !questHud.contains("renderPanel(") || !sanctuaryClient.contains("GLFW.GLFW_KEY_J") || !sanctuaryClient.contains("QuestTrackerSnapshotPayload.ID") || !questEditor.contains("QuestIdSuggestions.suggest") @@ -6943,7 +6945,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..f7e9639 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..20d92dc 100644 --- a/sanctuary/build.gradle +++ b/sanctuary/build.gradle @@ -76,6 +76,14 @@ tasks.register("questTrackerModelSmoke", JavaExec) { mainClass = "fr.koka99cab.sanctuary26.sanctuary.shop.QuestTrackerModelSmoke" } +tasks.register("questTrackerDisplaySmoke", JavaExec) { + group = "verification" + description = "Checks quest-tracker display modes and permanent-F3 layout." + dependsOn tasks.named("testClasses") + classpath = sourceSets.test.runtimeClasspath + mainClass = "fr.koka99cab.sanctuary26.sanctuary.client.QuestTrackerDisplaySmoke" +} + tasks.register("questIdSuggestionsSmoke", JavaExec) { group = "verification" description = "Checks accent-folded quest-panel item name ranking and inventory pins." @@ -151,7 +159,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 +2858,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 +3024,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 +3062,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 +3093,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 +3124,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 +3152,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 +3198,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 +3256,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 +3325,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 +3397,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" @@ -3421,6 +3429,7 @@ tasks.named("check") { dependsOn tasks.named("celestialGraphSmoke") dependsOn tasks.named("questRequestModelSmoke") dependsOn tasks.named("questTrackerModelSmoke") + dependsOn tasks.named("questTrackerDisplaySmoke") dependsOn tasks.named("questIdSuggestionsSmoke") dependsOn tasks.named("alphaIndevGeneratorSmoke") dependsOn tasks.named("verifyAlphaIndev") diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDebugLayout.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDebugLayout.java new file mode 100644 index 0000000..681e446 --- /dev/null +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDebugLayout.java @@ -0,0 +1,19 @@ +package fr.koka99cab.sanctuary26.sanctuary.client; + +/** Tracks the exact height occupied by the left-hand F3 column. */ +public final class QuestTrackerDebugLayout { + private static final int TOP_MARGIN = 2; + private static final int DEBUG_LINE_HEIGHT = 9; + private static final int GAP = 2; + private static int leftLineCount; + + private QuestTrackerDebugLayout() {} + + public static void captureLeftLines(int count) { + leftLineCount = Math.max(0, count); + } + + static int textTop(boolean debugVisible) { + return debugVisible ? TOP_MARGIN + leftLineCount * DEBUG_LINE_HEIGHT + GAP : TOP_MARGIN; + } +} diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplayMode.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplayMode.java new file mode 100644 index 0000000..f696a14 --- /dev/null +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplayMode.java @@ -0,0 +1,30 @@ +package fr.koka99cab.sanctuary26.sanctuary.client; + +/** Persisted visual styles offered by the quest tracker. */ +enum QuestTrackerDisplayMode { + TEXT("text"), + PANEL("panel"); + + private final String id; + + QuestTrackerDisplayMode(String id) { + this.id = id; + } + + String id() { + return id; + } + + QuestTrackerDisplayMode next() { + return this == TEXT ? PANEL : TEXT; + } + + static QuestTrackerDisplayMode byId(String value) { + if (value != null) { + for (QuestTrackerDisplayMode mode : values()) { + if (mode.id.equalsIgnoreCase(value)) return mode; + } + } + return TEXT; + } +} diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerHud.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerHud.java index 7934e29..d368caa 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerHud.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerHud.java @@ -14,11 +14,21 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.Identifier; import net.minecraft.world.item.ItemStack; -/** Transparent, toggleable text overlay for accepted quests. */ +/** Toggleable quest overlay with transparent F3-aligned and original panel modes. */ final class QuestTrackerHud { - private static final int MAX_WIDTH = 240; - private static final int MARGIN = 2; - private static final int ENTRY_SPACING = 2; + private static final int TEXT_MAX_WIDTH = 240; + private static final int TEXT_MARGIN = 2; + private static final int TEXT_ENTRY_SPACING = 2; + private static final int PANEL_WIDTH = 168; + private static final int PANEL_MARGIN = 6; + private static final int PANEL_HEADER_HEIGHT = 14; + private static final int PANEL_ENTRY_HEIGHT = 22; + private static final int PANEL_EMPTY_HEIGHT = 22; + private static final int PANEL_BACKGROUND = 0xD0181417; + private static final int PANEL_OUTLINE = 0xFFE8A8C3; + private static final int PANEL_TITLE = 0xFFF2C4D7; + private static final int PANEL_MUTED = 0xFF9F8B95; + private static final int PANEL_BAR_BACK = 0xFF3A2A30; private static final int BODY = 0xFFE9DDE2; private QuestTrackerHud() {} @@ -32,29 +42,82 @@ final class QuestTrackerHud { if (client.player == null || client.level == null || client.gui.screen() != null) return; if (!SanctuaryClientQuests.visible()) return; List entries = SanctuaryClientQuests.entries(); + if (SanctuaryClientQuests.displayMode() == QuestTrackerDisplayMode.PANEL) { + renderPanel(graphics, client, entries); + return; + } + renderText(graphics, client, entries); + } + + private static void renderText(GuiGraphicsExtractor graphics, Minecraft client, + List entries) { if (entries.isEmpty()) return; - int width = Math.max(1, Math.min(MAX_WIDTH, graphics.guiWidth() - MARGIN * 2)); - int y = MARGIN; + int width = Math.max(1, Math.min(TEXT_MAX_WIDTH, graphics.guiWidth() - TEXT_MARGIN * 2)); + int y = QuestTrackerDebugLayout.textTop(client.getDebugOverlay().showDebugScreen()); for (QuestTrackerSnapshotPayload.Entry entry : entries) { - drawEntry(graphics, client.font, entry, MARGIN, y, width); - y += client.font.lineHeight * 2 + ENTRY_SPACING; + drawTextEntry(graphics, client.font, entry, TEXT_MARGIN, y, width); + y += client.font.lineHeight * 2 + TEXT_ENTRY_SPACING; } } - private static void drawEntry(GuiGraphicsExtractor graphics, Font font, + private static void drawTextEntry(GuiGraphicsExtractor graphics, Font font, QuestTrackerSnapshotPayload.Entry entry, int x, int y, int width) { int accent = 0xFF000000 | (entry.accent() & 0xFFFFFF); graphics.text(font, ellipsize(font, title(entry), width), x, y, accent, true); - Component progress = Component.translatable("hud.sanctuary.quest_tracker.progress", - action(entry), describeTarget(entry), entry.progress(), entry.required()); + Component progress = progress(entry); graphics.text(font, ellipsize(font, progress, width), x, y + font.lineHeight, BODY, true); } + private static void renderPanel(GuiGraphicsExtractor graphics, Minecraft client, + List entries) { + int height = PANEL_HEADER_HEIGHT + 6 + + (entries.isEmpty() ? PANEL_EMPTY_HEIGHT : entries.size() * PANEL_ENTRY_HEIGHT); + int right = PANEL_MARGIN + PANEL_WIDTH; + int bottom = PANEL_MARGIN + height; + graphics.fill(PANEL_MARGIN, PANEL_MARGIN, right, bottom, PANEL_BACKGROUND); + graphics.outline(PANEL_MARGIN, PANEL_MARGIN, PANEL_WIDTH, height, PANEL_OUTLINE); + graphics.text(client.font, Component.translatable("hud.sanctuary.quest_tracker.title"), + PANEL_MARGIN + 6, PANEL_MARGIN + 4, PANEL_TITLE); + if (entries.isEmpty()) { + graphics.text(client.font, Component.translatable("hud.sanctuary.quest_tracker.empty"), + PANEL_MARGIN + 6, PANEL_MARGIN + PANEL_HEADER_HEIGHT + 4, PANEL_MUTED); + return; + } + int y = PANEL_MARGIN + PANEL_HEADER_HEIGHT + 2; + for (QuestTrackerSnapshotPayload.Entry entry : entries) { + drawPanelEntry(graphics, client.font, entry, PANEL_MARGIN + 6, y, PANEL_WIDTH - 12); + y += PANEL_ENTRY_HEIGHT; + } + } + + private static void drawPanelEntry(GuiGraphicsExtractor graphics, Font font, + QuestTrackerSnapshotPayload.Entry entry, int x, int y, int width) { + int accent = 0xFF000000 | (entry.accent() & 0xFFFFFF); + graphics.text(font, ellipsize(font, title(entry), width), x, y, accent); + graphics.text(font, ellipsize(font, progress(entry), width), x, y + 9, BODY); + int barTop = y + 18; + graphics.fill(x, barTop, x + width, barTop + 2, PANEL_BAR_BACK); + int filled = Math.round(width * Math.min(1.0F, entry.progress() / (float) entry.required())); + if (filled > 0) graphics.fill(x, barTop, x + filled, barTop + 2, accent); + } + private static Component title(QuestTrackerSnapshotPayload.Entry entry) { + if (QuestTrackerSync.SOURCE_BOARD.equals(entry.source())) { + return switch (entry.title()) { + case "ruby", "sapphire", "emerald" -> Component.translatable( + "hud.sanctuary.quest_tracker.reward." + entry.title()); + default -> Component.translatable("hud.sanctuary.quest_tracker.source.board"); + }; + } if (!entry.title().isBlank()) return Component.literal(entry.title()); return Component.translatable("hud.sanctuary.quest_tracker.source." + entry.source()); } + private static Component progress(QuestTrackerSnapshotPayload.Entry entry) { + return Component.translatable("hud.sanctuary.quest_tracker.progress", + action(entry), describeTarget(entry), entry.progress(), entry.required()); + } + private static Component action(QuestTrackerSnapshotPayload.Entry entry) { if (QuestTrackerSync.SOURCE_BOARD.equals(entry.source())) { return Component.translatable("sign.sanctuary.quest_board.action." + entry.action()); diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java index 22a9189..3cc88d3 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClient.java @@ -50,6 +50,7 @@ public final class SanctuaryClient implements ClientModInitializer { private static KeyMapping celestialKey; private static KeyMapping switchHotbarRowKey; private static KeyMapping questTrackerKey; + private static KeyMapping questTrackerModeKey; private static boolean zoomWasHeld; private static boolean smokeScreenOpened; private static boolean inventorySmokeScreenOpened; @@ -99,6 +100,12 @@ public final class SanctuaryClient implements ClientModInitializer { GLFW.GLFW_KEY_J, SANCTUARY_CATEGORY )); + questTrackerModeKey = KeyMappingHelper.registerKeyMapping(new KeyMapping( + "key.sanctuary.quest_tracker_mode", + InputConstants.Type.KEYSYM, + GLFW.GLFW_KEY_N, + SANCTUARY_CATEGORY + )); SanctuaryAtlasOptions.load(); SanctuaryClientQuests.load(); SanctuaryBulkActionsClient.initialize(); @@ -198,6 +205,10 @@ public final class SanctuaryClient implements ClientModInitializer { if (client.player != null && client.level != null && client.gui.screen() == null) toggleQuestTracker(client); } + while (questTrackerModeKey.consumeClick()) { + if (client.player != null && client.level != null && client.gui.screen() == null) + cycleQuestTrackerMode(client); + } while (celestialKey.consumeClick()) { if (client.player != null && client.level != null && client.gui.screen() == null) client.gui.setScreen(new CelestialSkyScreen(null)); @@ -300,6 +311,13 @@ public final class SanctuaryClient implements ClientModInitializer { : "hud.sanctuary.quest_tracker.toggle_off")); } + private static void cycleQuestTrackerMode(Minecraft client) { + QuestTrackerDisplayMode mode = SanctuaryClientQuests.cycleDisplayMode(); + if (client.player == null) return; + client.player.sendOverlayMessage(Component.translatable( + "hud.sanctuary.quest_tracker.mode." + mode.id())); + } + private static void toggleAtlas(Minecraft client) { if (client.gui.screen() instanceof SanctuaryAtlasScreen) { client.gui.setScreen(null); diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClientQuests.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClientQuests.java index d7dc27b..377c2bf 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClientQuests.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/client/SanctuaryClientQuests.java @@ -13,7 +13,7 @@ import java.nio.file.Path; import java.util.List; import net.fabricmc.loader.api.FabricLoader; -/** Client-side quest tracker snapshot and visibility preference. */ +/** Client-side quest tracker snapshot and persisted display preferences. */ final class SanctuaryClientQuests { private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); private static final Path FILE = FabricLoader.getInstance().getConfigDir() @@ -61,6 +61,19 @@ final class SanctuaryClientQuests { return settings.visible; } + static QuestTrackerDisplayMode displayMode() { + load(); + return QuestTrackerDisplayMode.byId(settings.mode); + } + + static QuestTrackerDisplayMode cycleDisplayMode() { + load(); + QuestTrackerDisplayMode mode = displayMode().next(); + settings.mode = mode.id(); + save(); + return mode; + } + private static void save() { try { Files.createDirectories(FILE.getParent()); @@ -75,5 +88,6 @@ final class SanctuaryClientQuests { private static final class Settings { boolean visible = true; + String mode = QuestTrackerDisplayMode.TEXT.id(); } } diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/DebugScreenOverlayMixin.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/DebugScreenOverlayMixin.java new file mode 100644 index 0000000..e7420d7 --- /dev/null +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/mixin/client/DebugScreenOverlayMixin.java @@ -0,0 +1,20 @@ +package fr.koka99cab.sanctuary26.sanctuary.mixin.client; + +import fr.koka99cab.sanctuary26.sanctuary.client.QuestTrackerDebugLayout; +import java.util.List; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.DebugScreenOverlay; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +/** Lets the transparent quest tracker start immediately below the current F3 lines. */ +@Mixin(DebugScreenOverlay.class) +abstract class DebugScreenOverlayMixin { + @Inject(method = "extractLines", at = @At("HEAD")) + private void sanctuary$captureLeftColumn(GuiGraphicsExtractor graphics, List lines, + boolean left, CallbackInfo ci) { + if (left) QuestTrackerDebugLayout.captureLeftLines(lines.size()); + } +} diff --git a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerSync.java b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerSync.java index 9a7c065..56ce1a6 100644 --- a/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerSync.java +++ b/sanctuary/src/main/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerSync.java @@ -3,8 +3,10 @@ package fr.koka99cab.sanctuary26.sanctuary.shop; import fr.koka99cab.sanctuary26.sanctuary.network.QuestTrackerSnapshotPayload; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.UUID; import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.resources.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; @@ -43,29 +45,58 @@ public final class QuestTrackerSync { } private static List entries(ServerPlayer player) { - List entries = new ArrayList<>(); + List entries = new ArrayList<>(); UUID playerId = player.getUUID(); MinecraftServer server = player.level().getServer(); for (QuestRequestData.Request request : QuestRequestData.get(server).requests()) { - if (entries.size() >= QuestTrackerSnapshotPayload.MAX_ENTRIES) break; if (!tracksAcceptedRequest(request, playerId)) continue; - entries.add(new QuestTrackerSnapshotPayload.Entry( + addRanked(entries, new RankedEntry(new QuestTrackerSnapshotPayload.Entry( SOURCE_REQUEST, clip(request.id(), 36), clip(request.objective(), 96), clip(request.action(), 16), clip(request.target(), 64), - request.progress(), request.quantity(), request.ownerColor())); + request.progress(), request.quantity(), request.ownerColor()), + rewardOrder(request.rewardTarget()))); } for (QuestBoardData.Board board : QuestBoardData.get(server).boards()) { - if (entries.size() >= QuestTrackerSnapshotPayload.MAX_ENTRIES) break; QuestBoardData.Contract contract = board.contract().orElse(null); if (contract == null || contract.claim().isEmpty() || !contract.claim().get().playerId().equals(playerId)) continue; QuestBoardData.Objective objective = contract.objective(); - entries.add(new QuestTrackerSnapshotPayload.Entry( - SOURCE_BOARD, clip(board.id(), 36), "", + addRanked(entries, new RankedEntry(new QuestTrackerSnapshotPayload.Entry( + SOURCE_BOARD, clip(board.id(), 36), board.questTier().id(), clip(objective.kind(), 16), clip(objective.target(), 64), - objective.progress(), objective.required(), tierColor(board.questTier()))); + objective.progress(), objective.required(), tierColor(board.questTier())), + rewardOrder(board.questTier()))); } - return entries; + return entries.stream().map(RankedEntry::entry).toList(); + } + + private static void addRanked(List entries, RankedEntry candidate) { + int index = 0; + while (index < entries.size() && entries.get(index).rewardOrder() <= candidate.rewardOrder()) { + index++; + } + entries.add(index, candidate); + if (entries.size() > QuestTrackerSnapshotPayload.MAX_ENTRIES) entries.removeLast(); + } + + static int rewardOrder(QuestBoardTier tier) { + return switch (tier) { + case RUBY -> 0; + case SAPPHIRE -> 1; + case EMERALD -> 2; + }; + } + + static int rewardOrder(String rewardTarget) { + Identifier id = Identifier.tryParse(rewardTarget); + String path = (id == null ? rewardTarget : id.getPath()); + if (path == null) return 3; + path = path.toLowerCase(Locale.ROOT); + if (path.equals("ruby") || path.startsWith("ruby_")) return 0; + if (path.equals("sapphire") || path.equals("saphire") + || path.startsWith("sapphire_") || path.startsWith("saphire_")) return 1; + if (path.equals("emerald") || path.startsWith("emerald_")) return 2; + return 3; } static boolean tracksAcceptedRequest(QuestRequestData.Request request, UUID playerId) { @@ -87,4 +118,6 @@ public final class QuestTrackerSync { if (value == null) return ""; return value.length() <= maximumLength ? value : value.substring(0, maximumLength); } + + private record RankedEntry(QuestTrackerSnapshotPayload.Entry entry, int rewardOrder) {} } diff --git a/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json b/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json index 341de47..fdbed8e 100644 --- a/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json +++ b/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json @@ -244,11 +244,19 @@ "key.sanctuary.zoom": "Telephoto zoom", "key.sanctuary.switch_hotbar_row": "Cycle hotbar row", "key.sanctuary.quest_tracker": "Quest tracker", + "key.sanctuary.quest_tracker_mode": "Quest tracker style", + "hud.sanctuary.quest_tracker.title": "Quests", + "hud.sanctuary.quest_tracker.empty": "No quest in progress", "hud.sanctuary.quest_tracker.toggle_on": "Quest tracker shown", "hud.sanctuary.quest_tracker.toggle_off": "Quest tracker hidden", + "hud.sanctuary.quest_tracker.mode.text": "Quest tracker: F3 text", + "hud.sanctuary.quest_tracker.mode.panel": "Quest tracker: Chris's panel", "hud.sanctuary.quest_tracker.source.request": "Accepted request", "hud.sanctuary.quest_tracker.source.owned": "Your request", - "hud.sanctuary.quest_tracker.source.board": "Daily contract", + "hud.sanctuary.quest_tracker.source.board": "Quest contract", + "hud.sanctuary.quest_tracker.reward.emerald": "Emerald quest", + "hud.sanctuary.quest_tracker.reward.ruby": "Ruby quest", + "hud.sanctuary.quest_tracker.reward.sapphire": "Sapphire quest", "hud.sanctuary.quest_tracker.progress": "%s · %s · %s/%s", "message.sanctuary.zoom": "Zoom · FOV %s", "message.sanctuary.companion.passive_only": "This essence only has a passive power.", diff --git a/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json b/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json index ae46910..840f091 100644 --- a/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json +++ b/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json @@ -244,11 +244,19 @@ "key.sanctuary.zoom": "Zoom téléobjectif", "key.sanctuary.switch_hotbar_row": "Changer de rangée de hotbar", "key.sanctuary.quest_tracker": "Suivi des quêtes", + "key.sanctuary.quest_tracker_mode": "Style du suivi des quêtes", + "hud.sanctuary.quest_tracker.title": "Quêtes", + "hud.sanctuary.quest_tracker.empty": "Aucune quête en cours", "hud.sanctuary.quest_tracker.toggle_on": "Suivi des quêtes affiché", "hud.sanctuary.quest_tracker.toggle_off": "Suivi des quêtes masqué", + "hud.sanctuary.quest_tracker.mode.text": "Suivi des quêtes : texte F3", + "hud.sanctuary.quest_tracker.mode.panel": "Suivi des quêtes : panneau de Chris", "hud.sanctuary.quest_tracker.source.request": "Demande acceptée", "hud.sanctuary.quest_tracker.source.owned": "Votre demande", - "hud.sanctuary.quest_tracker.source.board": "Contrat du jour", + "hud.sanctuary.quest_tracker.source.board": "Contrat de quête", + "hud.sanctuary.quest_tracker.reward.emerald": "Quête émeraude", + "hud.sanctuary.quest_tracker.reward.ruby": "Quête rubis", + "hud.sanctuary.quest_tracker.reward.sapphire": "Quête saphir", "hud.sanctuary.quest_tracker.progress": "%s · %s · %s/%s", "message.sanctuary.zoom": "Zoom · FOV %s", "message.sanctuary.companion.passive_only": "Cette essence ne possède qu'un pouvoir passif.", diff --git a/sanctuary/src/main/resources/assets/sanctuary/lang/ru_ru.json b/sanctuary/src/main/resources/assets/sanctuary/lang/ru_ru.json index 0e47ea1..a8e5f10 100644 --- a/sanctuary/src/main/resources/assets/sanctuary/lang/ru_ru.json +++ b/sanctuary/src/main/resources/assets/sanctuary/lang/ru_ru.json @@ -156,11 +156,19 @@ "key.sanctuary.zoom": "Телефото-зум", "key.sanctuary.switch_hotbar_row": "Сменить ряд панели быстрого доступа", "key.sanctuary.quest_tracker": "Трекер заданий", + "key.sanctuary.quest_tracker_mode": "Стиль трекера заданий", + "hud.sanctuary.quest_tracker.title": "Задания", + "hud.sanctuary.quest_tracker.empty": "Нет активного задания", "hud.sanctuary.quest_tracker.toggle_on": "Трекер заданий показан", "hud.sanctuary.quest_tracker.toggle_off": "Трекер заданий скрыт", + "hud.sanctuary.quest_tracker.mode.text": "Трекер заданий: текст F3", + "hud.sanctuary.quest_tracker.mode.panel": "Трекер заданий: панель Криса", "hud.sanctuary.quest_tracker.source.request": "Принятый запрос", "hud.sanctuary.quest_tracker.source.owned": "Ваш запрос", - "hud.sanctuary.quest_tracker.source.board": "Дневной контракт", + "hud.sanctuary.quest_tracker.source.board": "Контракт задания", + "hud.sanctuary.quest_tracker.reward.emerald": "Изумрудное задание", + "hud.sanctuary.quest_tracker.reward.ruby": "Рубиновое задание", + "hud.sanctuary.quest_tracker.reward.sapphire": "Сапфировое задание", "hud.sanctuary.quest_tracker.progress": "%s · %s · %s/%s", "message.sanctuary.zoom": "Зум · FOV %s", "message.sanctuary.companion.passive_only": "У этой сущности есть только пассивная способность.", diff --git a/sanctuary/src/main/resources/sanctuary.mixins.json b/sanctuary/src/main/resources/sanctuary.mixins.json index c788bf4..be7239a 100644 --- a/sanctuary/src/main/resources/sanctuary.mixins.json +++ b/sanctuary/src/main/resources/sanctuary.mixins.json @@ -25,6 +25,7 @@ "client.CreativeModeInventoryScreenMixin", "client.CreativeSlotWrapperAccessor", "client.CreateWorldScreenWorldTabMixin", + "client.DebugScreenOverlayMixin", "client.GuiGraphicsExtractorMixin", "client.InventoryScreenMixin", "client.JeiBookmarkButtonControllerMixin", diff --git a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplaySmoke.java b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplaySmoke.java new file mode 100644 index 0000000..fd694d5 --- /dev/null +++ b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/client/QuestTrackerDisplaySmoke.java @@ -0,0 +1,25 @@ +package fr.koka99cab.sanctuary26.sanctuary.client; + +/** Checks the persisted display-mode fallback and the F3 column offset. */ +public final class QuestTrackerDisplaySmoke { + private QuestTrackerDisplaySmoke() {} + + public static void main(String[] args) { + require(QuestTrackerDisplayMode.byId(null) == QuestTrackerDisplayMode.TEXT, + "Missing legacy settings must keep the transparent text mode"); + require(QuestTrackerDisplayMode.byId("panel") == QuestTrackerDisplayMode.PANEL, + "Chris's original panel mode must remain selectable"); + require(QuestTrackerDisplayMode.PANEL.next() == QuestTrackerDisplayMode.TEXT, + "Display mode cycling must wrap back to text"); + + QuestTrackerDebugLayout.captureLeftLines(7); + require(QuestTrackerDebugLayout.textTop(false) == 2, + "The tracker must keep its top-left margin when F3 is hidden"); + require(QuestTrackerDebugLayout.textTop(true) == 67, + "The tracker must start below all seven permanent F3 lines"); + } + + private static void require(boolean value, String message) { + if (!value) throw new AssertionError(message); + } +} diff --git a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerModelSmoke.java b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerModelSmoke.java index e02f5d9..4d5686d 100644 --- a/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerModelSmoke.java +++ b/sanctuary/src/test/java/fr/koka99cab/sanctuary26/sanctuary/shop/QuestTrackerModelSmoke.java @@ -28,6 +28,15 @@ public final class QuestTrackerModelSmoke { QuestTrackerSnapshotPayload mixed = new QuestTrackerSnapshotPayload(List.of(owned, board)); require(mixed.entries().get(0).required() == 4 && mixed.entries().get(1).progress() == 2, "Owned and board progress must be preserved"); + require(QuestTrackerSync.rewardOrder("anotherworld:ruby") + < QuestTrackerSync.rewardOrder("anotherworld:sapphire"), + "Ruby rewards must be ordered before sapphire rewards"); + require(QuestTrackerSync.rewardOrder("anotherworld:saphire") + == QuestTrackerSync.rewardOrder(QuestBoardTier.SAPPHIRE), + "The legacy saphire spelling must remain in the sapphire reward group"); + require(QuestTrackerSync.rewardOrder(QuestBoardTier.SAPPHIRE) + < QuestTrackerSync.rewardOrder(QuestBoardTier.EMERALD), + "Sapphire rewards must be ordered before emerald and uncategorized rewards"); require(new QuestTrackerSnapshotPayload(null).entries().isEmpty(), "Null snapshot must become an empty tracker"); UUID owner = UUID.fromString("6c43c35a-3498-41bb-a77e-10c679e635d1");