From d9b3dd6bedf32448f8c6e5bfa4da10cb69968bc7 Mon Sep 17 00:00:00 2001 From: koka Date: Thu, 17 Sep 2026 14:09:11 +0200 Subject: [PATCH] Add editable Sanctuary resource template and new wrench texture (beta.121) --- README.md | 20 +- THIRD_PARTY_NOTICES.md | 9 + build.gradle | 20 +- docs/resourcepack-template-beta121.md | 109 +++++++ gradle.properties | 6 +- mods/sanctuary/build.gradle | 13 + .../ResourceTemplate121ClientChecks.java | 165 ++++++++++ .../client/ResourcePackTemplate.java | 107 +++++++ .../client/PackSelectionScreenMixin.java | 38 +++ .../assets/sanctuary/lang/en_us.json | 8 + .../assets/sanctuary/lang/fr_fr.json | 8 + .../sanctuary/textures/item/golden_wrench.png | Bin 180 -> 196 bytes .../src/main/resources/sanctuary.mixins.json | 1 + packwiz/pack.toml | 2 +- ressources-pack/README.md | 9 +- ressources-pack/sanctuary/README.md | 14 +- .../sanctuary/textures/item/golden_wrench.png | Bin 0 -> 196 bytes ressources-pack/sanctuary/pack.mcmeta | 2 +- .../sanctuary/releases/beta.121.json | 287 ++++++++++++++++++ ressources-pack/template/README.md | 55 ++++ ressources-pack/template/pack.mcmeta | 10 + 21 files changed, 865 insertions(+), 18 deletions(-) create mode 100644 docs/resourcepack-template-beta121.md create mode 100644 mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/ResourceTemplate121ClientChecks.java create mode 100644 mods/sanctuary/src/main/java/fr/koka/sanctuary/client/ResourcePackTemplate.java create mode 100644 mods/sanctuary/src/main/java/fr/koka/sanctuary/mixin/client/PackSelectionScreenMixin.java create mode 100644 ressources-pack/sanctuary/assets/sanctuary/textures/item/golden_wrench.png create mode 100644 ressources-pack/sanctuary/releases/beta.121.json create mode 100644 ressources-pack/template/README.md create mode 100644 ressources-pack/template/pack.mcmeta diff --git a/README.md b/README.md index 5face14..6b091e8 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,11 @@ La [vision complète](docs/vision.md) conserve les intentions ; le L’économie, les claims et les dimensions décrits dans la vision restent à implémenter. -La version **beta.120** étend la clé dorée aux états des blocs : clic gauche -pour choisir une propriété, clic droit pour changer sa valeur, Maj pour inverser. -La terre et les modèles de blocs peuvent aussi tourner leurs textures. -Le [ticket de livraison](docs/golden-wrench-beta120.md) détaille les contrôles, -la compatibilité et la distribution. La release est publiée et l’instance -**Sanctuary Beta** est synchronisée, sauvegardes et réglages conservés. +La version **beta.121** reprend la nouvelle texture de clé dorée et ajoute +**Personnaliser Sanctuary** à l'écran des packs de ressources. Le bouton crée +une copie complète, modifiable, que les mises à jour ne réécrivent jamais. +Le [ticket de livraison](docs/resourcepack-template-beta121.md) détaille le +fonctionnement et les vérifications client et archives réussies. La [livraison précédente](docs/clay-workshop-integration-beta110.md) réunit déjà l’atelier, les œufs et la neige saisonnière dans l’instance **Sanctuary Beta**. Les [synchronisations antérieures](docs/git-sync-beta092.md) restent documentées. @@ -36,6 +35,11 @@ La [carte native beta.005](docs/atlas-beta005.md) prend le relais après l’étude de Xaero et des alternatives libres. +## beta.121 — Texture de clé et pack personnel + +Copie complète des ressources, création depuis le jeu et guide FR/EN inclus. +[Contrat et vérifications](docs/resourcepack-template-beta121.md). + ## beta.120 — Clé dorée et états de blocs Gestes du debug stick, rotation de textures et assemblage des machines conservé. @@ -2134,7 +2138,7 @@ Depuis beta.090, la cible est **Minecraft 26.3 finale**, publiée le 15 septembr | Fabric API | 0.160.5+26.3 | | Fabric Loom | 1.17.20 | | Gradle Wrapper | 9.5.1, distribution vérifiée par SHA-256 | -| Sanctuary / pack | beta.112 | +| Sanctuary / pack | beta.121 | Java 25 et Python 3.11 ou plus récent sont nécessaires. Le script pack utilise uniquement la bibliothèque standard et repère aussi une installation Python @@ -2163,7 +2167,7 @@ décrits dans [Validation](docs/testing.md). Résultats : -- `mods/sanctuary/build/libs/sanctuary-beta.112.jar` : mod à installer avec +- `mods/sanctuary/build/libs/sanctuary-beta.121.jar` : mod à installer avec Fabric API sur la version Minecraft indiquée. - `build/packwiz/` : pack de développement complet, avec le mod construit et l'index vérifié. Voir [Installation packwiz](packwiz/README.md). diff --git a/THIRD_PARTY_NOTICES.md b/THIRD_PARTY_NOTICES.md index 747f161..8f9b411 100644 --- a/THIRD_PARTY_NOTICES.md +++ b/THIRD_PARTY_NOTICES.md @@ -127,3 +127,12 @@ de modèles, butin et états reprennent leurs équivalents natifs 26.3. `tools/generate-colored-bricks.py` documente cette transformation ; `tools/colored-bricks-palette.json` conserve couleurs et empreintes des PNG fournis. Ces ressources dérivées ne sont pas présentées comme des créations originales. + +## Clé dorée beta.121 + +Le PNG 16 × 16 `golden_wrench.png` a été fourni par le créateur de Sanctuary +le 17 septembre 2026. Il est conservé octet pour octet dans le mod, le pack +intégré et le template personnel (SHA-256 +`a97570908db75caf8e6fc2f5ecabf12c54fd99bfea7be634df66c4310dca22af`). +Le template regroupe les ressources client déjà distribuées par Sanctuary ; +leurs crédits et conditions respectives restent applicables. diff --git a/build.gradle b/build.gradle index 032e130..7cc0dcc 100644 --- a/build.gradle +++ b/build.gradle @@ -15,7 +15,7 @@ tasks.register('verifyPack', Exec) { tasks.register('assemblePack', Exec) { group = 'distribution' description = 'Assemble a local packwiz pack including the built Sanctuary mod.' - dependsOn(':sanctuary:build', 'verifyPack', 'assembleResourcePack') + dependsOn(':sanctuary:build', 'verifyPack', 'assembleResourcePack', 'assembleResourceTemplate') commandLine('python3', 'scripts/pack.py', 'assemble') } @@ -46,3 +46,21 @@ tasks.register('assembleTestPack', Exec) { dependsOn('assemblePack', ':sanctuary-test:build') commandLine('python3', 'scripts/test_pack.py') } + +tasks.register('assembleResourceTemplate', Zip) { + group = 'distribution' + description = 'Export all Sanctuary client assets as an editable personal resource pack.' + dependsOn(':sanctuary:processResources', 'verifyResourcePack') + def resources = project(':sanctuary').layout.buildDirectory.dir('resources/main') + // Same precedence as the native exporter: built-in textures override mod defaults. + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + from(resources.map { it.dir('resourcepacks/textures/assets') }) { into 'assets' } + from(resources.map { it.dir('assets') }) { into 'assets' } + from(resources.map { it.dir('resourcepacks/template') }) + from(resources.map { it.file('resourcepacks/textures/pack.png') }) + exclude '**/.DS_Store' + destinationDirectory = layout.buildDirectory + archiveFileName = "Sanctuary-Template-${mod_version}.zip" + preserveFileTimestamps = false + reproducibleFileOrder = true +} diff --git a/docs/resourcepack-template-beta121.md b/docs/resourcepack-template-beta121.md new file mode 100644 index 0000000..4a91a91 --- /dev/null +++ b/docs/resourcepack-template-beta121.md @@ -0,0 +1,109 @@ +# RP-02 — Clé dorée et pack personnel — beta.121 + +Contrat du 17 septembre 2026, branche `codex/resourcepack-template-beta121`. +Le créateur fournit `golden_wrench.png` et valide un bouton qui crée une copie +personnelle complète, modifiable et jamais écrasée par les mises à jour. + +## Résultat + +La clé dorée reprend exactement le PNG fourni, 16 × 16, sans conversion ni +redessin. Le modèle reste un item plat `minecraft:item/handheld`. Empreinte : +`a97570908db75caf8e6fc2f5ecabf12c54fd99bfea7be634df66c4310dca22af`. +Le même fichier est fourni par le mod et par « Textures Sanctuary » ; désactiver +le pack intégré conserve donc aussi la nouvelle clé. + +Dans **Options → Packs de ressources**, **Personnaliser Sanctuary** crée +`resourcepacks/Sanctuary-Custom/`. Le bouton devient **Ouvrir ma copie**. +La copie contient toutes les ressources client de Sanctuary : textures, modèles, +étiquettes d'items, blockstates, sons, shaders, langues et remplacements Minecraft +présents dans le pack intégré. Celui-ci prend priorité sur les assets de base +lors de l'export. Un guide FR/EN, la licence et les crédits accompagnent la copie. + +Le joueur active sa copie avec les commandes natives et la place au-dessus des +packs qu'il veut remplacer. Créer la copie ne change ni l'ordre ni la sélection. +Une modification se recharge avec F3 + T ; désactiver le pack retrouve les +ressources fournies par le mod. L'écran de sélection des datapacks n'est pas modifié. + +La copie est un **instantané**. Elle ne se synchronise pas avec les mises à jour : +les fichiers personnalisés restent toujours intacts. Le guide recommande de +supprimer les fichiers non personnalisés pour laisser les prochaines ressources +du mod s'appliquer. Pour repartir d'un instantané récent, renommer le dossier +existant puis créer une nouvelle copie. Aucun fichier utilisateur n'est écrasé. + +La copie s'effectue hors du fil de rendu, dans un dossier temporaire voisin, +puis le résultat complet rejoint la liste native. Une erreur de copie est +signalée par le bouton et le journal du jeu ; un chemin occupé par un fichier +n'est pas remplacé. Aucune extraction au démarrage ni pendant les mises à jour. + +## Distribution + +`./gradlew assembleResourceTemplate` produit +`build/Sanctuary-Template-beta.121.zip`, un pack personnel complet à décompresser +dans `resourcepacks/Sanctuary-Custom/`. `assemblePack` le produit aussi. +`build/Sanctuary-Resource-Pack-beta.121.zip` reste l'export du pack graphique +intégré ; son manifeste versionné contient 151 fichiers et les images historiques +sont conservées. L'identifiant intégré `sanctuary:textures` reste stable et son +activation reste contrôlée par le joueur. + +Le template ne contient pas tous les assets vanilla ni ceux des autres mods. +Il ne contient pas les recettes, règles serveur ou sauvegardes. Il conserve +les crédits et conditions des ressources d'origine. Aucune génération, aucun +identifiant de bloc et aucun format de sauvegarde ne changent. + +## Vérifications + +Le parcours `ResourceTemplate121ClientChecks` passe en **35 s** sur le client +Minecraft 26.3 macOS, sans ouvrir de monde : + +- Bouton natif et disposition FR/EN aux échelles 2 et 3, captures relues. +- Export complet de **1 202 fichiers**, empreintes identiques aux ressources + sources après application des priorités du pack intégré. +- PNG fourni vérifié par SHA-256 et affiché avec sa transparence. +- Création sans changer la sélection ni l'ordre des packs. +- Modification d'une texture et ajout d'un fichier personnel : aucun octet + réécrit lors d'un second export ni au rechargement des ressources. +- Priorité réelle de la texture personnalisée, puis retour à la clé fournie + après désactivation. Activation et désactivation conservées à la redécouverte. +- Chemin occupé par un fichier refusé sans le modifier ; aucun bouton ajouté + à l'écran des datapacks. + +```sh +./gradlew :sanctuary:runClientGameTest \ + -PsanctuaryClientTests=true -PsanctuaryResourceTemplate121ClientTests=true \ + -PsanctuaryClientNoVsync=true -PsanctuaryQuickTests=true +``` + +Marqueur `TEMPLATE121_PASS` dans `build/template121-client.log` ; captures et +empreintes de la copie dans `build/template121-evidence/`. Le premier essai +avait échoué dans l'aperçu du test qui créait un ItemStack avant connexion à +un monde ; cet aperçu affiche maintenant directement la texture résolue. +Le modèle plat existant n'est pas modifié. Pas d'essai Windows ni d'ouverture +automatisée du gestionnaire de fichiers. Le GameTest serveur dédié reste exclu +conformément au refus antérieur de son EULA. + +`./gradlew check build assemblePack assembleTestPack -x :sanctuary:runGameTest` +passe en **2 min 10 s**, 126 tâches. Les sources JAR correspondent aux sources +Java du dépôt. La comparaison avec beta.120 limite les différences de production +aux deux nouvelles classes, au hook d'interface, aux libellés et aux ressources +prévues (12 entrées). Aucun changement de gameplay, de données serveur ou de +monde. Les packs normal/Test contiennent le même JAR Sanctuary, sans fixture +ni sauvegarde. Le ZIP du template et l'export natif ont exactement les mêmes +1 202 fichiers et empreintes. Le pack intégré conserve ses 151 fichiers vérifiés. + +Reçu : `build/template121-artifact.json`. Artefacts locaux validés : + +- `Sanctuary-beta.121.mrpack` : 10261791 octets, SHA-256 + `040d68f342155120fa21e0ffcdf34aa38e3225c78862960536622de53ed9fd9f`. +- `Sanctuary-Test-beta.121.mrpack` : 10280716 octets, SHA-256 + `7f5bbd4e13aea4c245d072725c094ca64826ee8debc8607623783c114d437685`. +- `Sanctuary-Resource-Pack-beta.121.zip` : 3757952 octets, SHA-256 + `bbf3c18ea6abc64d951911215975cb6c48c7fc5e0246f6e5f5192a3d061c211d`. +- `Sanctuary-Template-beta.121.zip` : 4315131 octets, SHA-256 + `6fad376c53474fa8bcb0a2e6ae4c13ea61ab91bdd78735be443032d485ed541a`. + +JAR Sanctuary : SHA-256 +`4276f4fc9834805e3e6d12cd19adba7837e3007656b77f31d525c7b976f9925d`. + +## Publication et installation + +Artefacts prêts ; publication du canal et synchronisation Prism à effectuer. diff --git a/gradle.properties b/gradle.properties index f2382e2..cb4fd25 100644 --- a/gradle.properties +++ b/gradle.properties @@ -9,8 +9,8 @@ loom_version=1.17.20 fabric_api_version=0.160.5+26.3 # Release counter: beta.001, .002, .003, ... (see docs/versioning.md). -mod_version=beta.120 -pack_version=beta.120 -resource_pack_version=beta.090 +mod_version=beta.121 +pack_version=beta.121 +resource_pack_version=beta.121 maven_group=fr.koka.sanctuary jei_version=30.32.0-sanctuary.3 diff --git a/mods/sanctuary/build.gradle b/mods/sanctuary/build.gradle index 7acd51c..61e9fdd 100644 --- a/mods/sanctuary/build.gradle +++ b/mods/sanctuary/build.gradle @@ -93,6 +93,10 @@ tasks.named('runGameTest') { } tasks.named('processGametestResources') { + def template121Client = providers.gradleProperty('sanctuaryResourceTemplate121ClientTests').map { it.toBoolean() }.getOrElse(false) + inputs.property('sanctuaryResourceTemplate121ClientTests', template121Client) + if (template121Client) filter { line -> line.replace('fr.koka.sanctuary.gametest.SanctuaryClientRenderTests', 'fr.koka.sanctuary.client.ResourceTemplate121ClientChecks') } + def wrench120Client = providers.gradleProperty('sanctuaryWrench120ClientTests').map { it.toBoolean() }.getOrElse(false) inputs.property('sanctuaryWrench120ClientTests', wrench120Client) if (wrench120Client) filter { line -> line.replace('fr.koka.sanctuary.gametest.SanctuaryClientRenderTests', 'fr.koka.sanctuary.client.Wrench120ClientChecks') } @@ -444,6 +448,15 @@ tasks.withType(JavaCompile).configureEach { } processResources { + from(rootProject.file('ressources-pack/template')) { + exclude '**/.DS_Store' + into 'resourcepacks/template' + } + from(rootProject.file('LICENSE')) { + rename { 'LICENSE_sanctuary' } + into 'resourcepacks/template' + } + from(rootProject.file('THIRD_PARTY_NOTICES.md')) { into 'resourcepacks/template' } from(rootProject.file('ressources-pack/sanctuary')) { include 'assets/**', 'pack.mcmeta', 'pack.png' exclude '**/.DS_Store' diff --git a/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/ResourceTemplate121ClientChecks.java b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/ResourceTemplate121ClientChecks.java new file mode 100644 index 0000000..e81c874 --- /dev/null +++ b/mods/sanctuary/src/clientGametest/java/fr/koka/sanctuary/client/ResourceTemplate121ClientChecks.java @@ -0,0 +1,165 @@ +package fr.koka.sanctuary.client; + +import com.mojang.blaze3d.platform.InputConstants; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.MessageDigest; +import java.util.Arrays; +import java.util.HexFormat; +import java.util.List; +import java.util.Map; +import java.util.TreeMap; +import net.fabricmc.fabric.api.client.gametest.v1.FabricClientGameTest; +import net.fabricmc.fabric.api.client.gametest.v1.context.ClientGameTestContext; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphicsExtractor; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.packs.PackSelectionScreen; +import net.minecraft.client.input.KeyEvent; +import net.minecraft.client.renderer.RenderPipelines; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.contents.TranslatableContents; +import net.minecraft.resources.Identifier; +import net.minecraft.server.packs.repository.PackCompatibility; + +/** Native screen/export, complete snapshot, real resource precedence and preservation of edits. */ +public final class ResourceTemplate121ClientChecks implements FabricClientGameTest { + private static final String BUILTIN = "sanctuary:textures"; + private static final String PERSONAL = "file/" + ResourcePackTemplate.FOLDER; + private static final String WRENCH = "sanctuary:textures/item/golden_wrench.png"; + private static final String WRENCH_PATH = "assets/sanctuary/textures/item/golden_wrench.png"; + private static final String WRENCH_SHA = "a97570908db75caf8e6fc2f5ecabf12c54fd99bfea7be634df66c4310dca22af"; + + public void runTest(ClientGameTestContext c) { + try { run(c); } catch (IOException error) { throw new AssertionError(error); } + } + + private void run(ClientGameTestContext c) throws IOException { + var previous = c.computeOnClient(m -> m.gui.screen()); + var packDirectory = c.computeOnClient(Minecraft::getResourcePackDirectory); + var selected = c.computeOnClient(m -> List.copyOf(m.getResourcePackRepository().getSelectedIds())); + var target = packDirectory.resolve(ResourcePackTemplate.FOLDER); + check(!Files.exists(target), "Fresh disposable client directory"); + c.runOnClient(m -> { + check(source(m).equals(BUILTIN), "Built-in pack active"); + check(hash(resource(m, WRENCH)).equals(WRENCH_SHA), "Exact creator PNG active"); + m.getWindow().setWindowed(1280, 800); + }); + for (int scale : new int[]{2, 3}) for (String language : List.of("fr_fr", "en_us")) { + c.runOnClient(m -> { + m.options.guiScale().set(scale); m.resizeGui(); + m.getLanguageManager().setSelected(language); + m.getLanguageManager().onResourceManagerReload(m.getResourceManager()); + screen(m, packDirectory); + var button = button(m, "customize"); + check(button.getX() >= 0 && button.getRight() <= m.gui.screen().width, "Template button fits width"); + check(button.getY() > 60 && button.getBottom() < m.gui.screen().height, "Template button fits height"); + var done = m.gui.screen().children().stream().filter(Button.class::isInstance).map(Button.class::cast) + .filter(b -> key(b, "gui.done")).findFirst().orElseThrow(); + check(done.getY() >= button.getBottom() + 4, "Separate native footer row"); + check(m.font.width(button.getMessage()) < button.getWidth() - 8, "Localized label fits"); + }); + c.waitTicks(3); c.takeScreenshot("template121-create-" + language + "-" + scale); + } + c.runOnClient(m -> button(m, "customize").onPress(new KeyEvent(InputConstants.KEY_RETURN, 0, 0))); + c.waitFor(m -> m.gui.screen().children().stream().filter(Button.class::isInstance).map(Button.class::cast) + .anyMatch(b -> b.active && key(b, "sanctuary.resource_pack.open_copy")), 1200); + c.waitFor(m -> m.getResourcePackRepository().getAvailableIds().contains(PERSONAL), 1200); + c.runOnClient(m -> { + check(List.copyOf(m.getResourcePackRepository().getSelectedIds()).equals(selected), "Creating never changes selection"); + check(m.getResourcePackRepository().getPack(PERSONAL).getCompatibility() == PackCompatibility.COMPATIBLE, + "Template format accepted by exact Minecraft version"); + }); + var mod = FabricLoader.getInstance().getModContainer("sanctuary").orElseThrow(); + Map expected = new TreeMap<>(); + merge(expected, mod.findPath("assets").orElseThrow(), "assets/"); + merge(expected, mod.findPath("resourcepacks/textures/assets").orElseThrow(), "assets/"); + merge(expected, mod.findPath("resourcepacks/template").orElseThrow(), ""); + expected.put("pack.png", hash(Files.readAllBytes(mod.findPath("resourcepacks/textures/pack.png").orElseThrow()))); + check(snapshot(target).equals(expected), "Complete byte-identical snapshot with built-in precedence"); + Files.writeString(packDirectory.getParent().resolve("template121-export-sha256.json"), + new com.google.gson.GsonBuilder().setPrettyPrinting().create().toJson(expected)); + check(expected.containsKey("README.md") && expected.containsKey("LICENSE_sanctuary") + && expected.containsKey("THIRD_PARTY_NOTICES.md"), "Editable copy includes guide and credits"); + check(expected.keySet().stream().noneMatch(p -> p.startsWith("data/") || p.endsWith(".class")), "Client assets only"); + c.waitTicks(4); c.takeScreenshot("template121-copy-ready"); + c.runOnClient(m -> m.gui.setScreen(new Screen(Component.literal("Golden wrench")) { + @Override public void extractRenderState(GuiGraphicsExtractor g, int x, int y, float delta) { + g.fill(0, 0, width, height, 0xff292929); + g.centeredText(font, Component.translatable("item.sanctuary.golden_wrench"), width / 2, 55, 0xffffffff); + g.blit(RenderPipelines.GUI_TEXTURED, Identifier.parse(WRENCH), width / 2 - 48, 85, 0, 0, 96, 96, 16, 16, 16, 16); + } + })); + c.waitTicks(4); c.takeScreenshot("template121-wrench-exact-texture"); + + byte[] replacement = c.computeOnClient(m -> resource(m, "minecraft:textures/item/golden_pickaxe.png")); + Files.write(target.resolve(WRENCH_PATH), replacement); + Files.writeString(target.resolve("my-notes.txt"), "Personal edits must survive all subsequent exports."); + var edited = snapshot(target); + check(ResourcePackTemplate.create(packDirectory).equals(target.toAbsolutePath().normalize()), "Existing copy returned"); + check(snapshot(target).equals(edited), "Second export preserves every edited byte and extra file"); + c.runOnClient(m -> { + var repo = m.getResourcePackRepository(); repo.addPack(PERSONAL); m.options.updateResourcePacks(repo); + }); + c.waitFor(m -> source(m).equals(PERSONAL) && m.gui.overlay() == null, 1200); + c.runOnClient(m -> { + check(Arrays.equals(resource(m, WRENCH), replacement), "Personal edit overrides built-in texture"); + var repo = m.getResourcePackRepository(); repo.reload(); m.options.loadSelectedResourcePacks(repo); + check(repo.getSelectedIds().contains(PERSONAL), "Personal activation persists after rediscovery"); + screen(m, packDirectory); button(m, "open_copy"); + }); + c.waitTicks(3); c.takeScreenshot("template121-personal-active"); + var reload = c.computeOnClient(Minecraft::reloadResourcePacks); + c.waitFor(m -> reload.isDone() && m.gui.overlay() == null, 1200); reload.join(); + check(snapshot(target).equals(edited), "Reload never writes personal assets"); + c.runOnClient(m -> { + check(Arrays.equals(resource(m, WRENCH), replacement), "Reload still uses personal PNG"); + var repo = m.getResourcePackRepository(); repo.removePack(PERSONAL); m.options.updateResourcePacks(repo); + }); + c.waitFor(m -> source(m).equals(BUILTIN) && m.gui.overlay() == null, 1200); + c.runOnClient(m -> { + check(hash(resource(m, WRENCH)).equals(WRENCH_SHA), "Disabling restores creator texture"); + var repo = m.getResourcePackRepository(); repo.reload(); m.options.loadSelectedResourcePacks(repo); + check(!repo.getSelectedIds().contains(PERSONAL), "Explicit opt-out retained"); + }); + + Path collision = Files.createTempDirectory(packDirectory.getParent(), "template121-collision-"); + Files.writeString(collision.resolve(ResourcePackTemplate.FOLDER), "Do not replace this file"); + try { ResourcePackTemplate.create(collision); throw new AssertionError("Existing file must be refused"); } + catch (IOException expectedError) { check(Files.readString(collision.resolve(ResourcePackTemplate.FOLDER)).equals("Do not replace this file"), "Collision leaves file intact"); } + Path datapacks = Files.createTempDirectory(packDirectory.getParent(), "template121-datapacks-"); + c.runOnClient(m -> { + screen(m, datapacks); + check(m.gui.screen().children().stream().filter(Button.class::isInstance).map(Button.class::cast) + .noneMatch(b -> key(b, "sanctuary.resource_pack.customize") || key(b, "sanctuary.resource_pack.open_copy")), "No button in datapack selector"); + m.gui.setScreen(previous); + }); + System.out.println("TEMPLATE121_PASS: " + expected.size() + " exact files; native button FR/EN at scales 2/3; complete copy; edits and selection preserved; actual override, reload and opt-out; collision safe; datapacks untouched"); + } + + private static void screen(Minecraft m, Path directory) { + m.gui.setScreen(new PackSelectionScreen(m.getResourcePackRepository(), repo -> {}, directory, Component.translatable("resourcePack.title"))); + } + private static Button button(Minecraft m, String suffix) { + return m.gui.screen().children().stream().filter(Button.class::isInstance).map(Button.class::cast) + .filter(b -> key(b, "sanctuary.resource_pack." + suffix)).findFirst().orElseThrow(); + } + private static boolean key(Button b, String key) { return b.getMessage().getContents() instanceof TranslatableContents t && t.getKey().equals(key); } + private static String source(Minecraft m) { return m.getResourceManager().getResource(Identifier.parse(WRENCH)).orElseThrow().sourcePackId(); } + private static byte[] resource(Minecraft m, String name) { + try (var in = m.getResourceManager().getResource(Identifier.parse(name)).orElseThrow().open()) { return in.readAllBytes(); } + catch (IOException error) { throw new AssertionError(error); } + } + private static String hash(byte[] bytes) { + try { return HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(bytes)); } + catch (java.security.NoSuchAlgorithmException error) { throw new AssertionError(error); } + } + private static Map snapshot(Path root) throws IOException { Map result = new TreeMap<>(); merge(result, root, ""); return result; } + private static void merge(Map result, Path root, String prefix) throws IOException { + try (var files = Files.walk(root)) { for (Path file : files.filter(Files::isRegularFile).toList()) result.put(prefix + root.relativize(file).toString().replace('\\', '/'), hash(Files.readAllBytes(file))); } + } + private static void check(boolean value, String message) { if (!value) throw new AssertionError(message); } +} diff --git a/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/ResourcePackTemplate.java b/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/ResourcePackTemplate.java new file mode 100644 index 0000000..14e254c --- /dev/null +++ b/mods/sanctuary/src/main/java/fr/koka/sanctuary/client/ResourcePackTemplate.java @@ -0,0 +1,107 @@ +package fr.koka.sanctuary.client; + +import com.mojang.blaze3d.Blaze3D; +import fr.koka.sanctuary.SanctuaryMod; +import java.io.IOException; +import java.nio.file.FileAlreadyExistsException; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.StandardCopyOption; +import java.util.Comparator; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.Tooltip; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Util; + +/** Explicit, one-time export. The player's copy is never a managed mod resource. */ +public final class ResourcePackTemplate { + public static final String FOLDER = "Sanctuary-Custom"; + + private ResourcePackTemplate() {} + + public static Button button(Path packDirectory) { + Path target = packDirectory.resolve(FOLDER); + return Button.builder(label(Files.isDirectory(target, LinkOption.NOFOLLOW_LINKS) + ? "open_copy" : "customize"), button -> { + if (Files.isDirectory(target, LinkOption.NOFOLLOW_LINKS)) { + Blaze3D.openPath(target); + return; + } + button.active = false; + button.setMessage(label("creating")); + Util.ioPool().execute(() -> { + try { + create(packDirectory); + Minecraft.getInstance().execute(() -> { + button.active = true; + button.setMessage(label("open_copy")); + button.setTooltip(Tooltip.create(label("copy_ready"))); + }); + } catch (IOException | RuntimeException error) { + SanctuaryMod.LOGGER.error("Could not create personal Sanctuary resource pack", error); + Minecraft.getInstance().execute(() -> { + button.active = true; + button.setMessage(label("copy_failed")); + button.setTooltip(Tooltip.create(label("copy_failed_help"))); + }); + } + }); + }).width(308).tooltip(Tooltip.create(label("customize_help"))).build(); + } + + /** Returns an existing personal directory untouched, including after mod upgrades. */ + public static synchronized Path create(Path packDirectory) throws IOException { + Path directory = packDirectory.toAbsolutePath().normalize(); + Files.createDirectories(directory); + Path target = directory.resolve(FOLDER); + if (Files.exists(target, LinkOption.NOFOLLOW_LINKS)) return existing(target); + var mod = FabricLoader.getInstance().getModContainer(SanctuaryMod.ID).orElseThrow(); + // Keep incomplete packs outside the directory watched by the native pack screen. + Path staging = Files.createTempDirectory(directory.getParent(), ".sanctuary-template-"); + try { + copyTree(mod.findPath("assets").orElseThrow(), staging.resolve("assets")); + copyTree(mod.findPath("resourcepacks/textures/assets").orElseThrow(), staging.resolve("assets")); + copyTree(mod.findPath("resourcepacks/template").orElseThrow(), staging); + Files.copy(mod.findPath("resourcepacks/textures/pack.png").orElseThrow(), staging.resolve("pack.png")); + try { + Files.move(staging, target); + } catch (FileAlreadyExistsException race) { + return existing(target); + } + return target; + } finally { + if (Files.exists(staging)) { + try (var files = Files.walk(staging)) { + for (Path file : files.sorted(Comparator.reverseOrder()).toList()) Files.delete(file); + } + } + } + } + + private static Path existing(Path target) throws IOException { + if (!Files.isDirectory(target, LinkOption.NOFOLLOW_LINKS)) { + throw new IOException("Personal pack path already exists and is not a directory: " + target); + } + return target; + } + + private static void copyTree(Path source, Path destination) throws IOException { + try (var files = Files.walk(source)) { + for (Path file : files.toList()) { + if (Files.isSymbolicLink(file)) throw new IOException("Unexpected asset symlink: " + file); + // String paths also work when the mod is loaded from a ZIP filesystem. + Path output = destination.resolve(source.relativize(file).toString()).normalize(); + if (!output.startsWith(destination)) throw new IOException("Invalid asset path: " + file); + if (Files.isDirectory(file)) Files.createDirectories(output); + else Files.copy(file, output, StandardCopyOption.REPLACE_EXISTING); + } + } + } + + private static Component label(String key) { + return Component.translatable("sanctuary.resource_pack." + key); + } +} diff --git a/mods/sanctuary/src/main/java/fr/koka/sanctuary/mixin/client/PackSelectionScreenMixin.java b/mods/sanctuary/src/main/java/fr/koka/sanctuary/mixin/client/PackSelectionScreenMixin.java new file mode 100644 index 0000000..9bba497 --- /dev/null +++ b/mods/sanctuary/src/main/java/fr/koka/sanctuary/mixin/client/PackSelectionScreenMixin.java @@ -0,0 +1,38 @@ +package fr.koka.sanctuary.mixin.client; + +import com.llamalad7.mixinextras.injector.wrapoperation.Operation; +import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation; +import fr.koka.sanctuary.client.ResourcePackTemplate; +import java.nio.file.Path; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.layouts.HeaderAndFooterLayout; +import net.minecraft.client.gui.layouts.LayoutElement; +import net.minecraft.client.gui.layouts.LinearLayout; +import net.minecraft.client.gui.screens.packs.PackSelectionScreen; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; + +/** Extra footer row only in resource packs, never in the world datapack selector. */ +@Mixin(PackSelectionScreen.class) +public abstract class PackSelectionScreenMixin { + @Shadow @Final private Path packDir; + + @WrapOperation(method = "init", at = @At(value = "INVOKE", target = + "Lnet/minecraft/client/gui/layouts/HeaderAndFooterLayout;addToFooter(Lnet/minecraft/client/gui/layouts/LayoutElement;)Lnet/minecraft/client/gui/layouts/LayoutElement;")) + private LayoutElement sanctuary$personalPack(HeaderAndFooterLayout layout, LayoutElement nativeButtons, + Operation original) { + if (!packDir.toAbsolutePath().normalize().equals( + Minecraft.getInstance().getResourcePackDirectory().toAbsolutePath().normalize())) { + return original.call(layout, nativeButtons); + } + layout.setFooterHeight(56); + LinearLayout rows = LinearLayout.vertical().spacing(4); + rows.addChild(ResourcePackTemplate.button(packDir)); + rows.addChild(nativeButtons); + original.call(layout, rows); + // Vanilla still adds its Open folder / Done buttons to the original horizontal row. + return nativeButtons; + } +} diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json index e1b0f4c..bda1824 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/en_us.json @@ -1753,6 +1753,14 @@ "sanctuary.preload.cities": "Preparing settlements", "sanctuary.preload.cache_write": "Saving plans", "sanctuary.familiar.dragon.lift": "On your head: hold %s to rise, release to glide.", + "sanctuary.resource_pack.customize": "Customize Sanctuary", + "sanctuary.resource_pack.open_copy": "Open my copy", + "sanctuary.resource_pack.creating": "Creating your copy…", + "sanctuary.resource_pack.customize_help": "Create an editable copy of Sanctuary resources. Enable it and move it to the top of the list. Updates preserve your changes.", + "sanctuary.resource_pack.copy_ready": "Copy ready! Enable Sanctuary-Custom and move it above other packs. Click to open its folder and guide.", + "sanctuary.resource_pack.copy_failed": "Copy failed — retry", + "sanctuary.resource_pack.copy_failed_help": "Check write permissions and the resourcepacks/Sanctuary-Custom path. See the game log for details.", + "sanctuary.resource_pack.custom_description": "Sanctuary — your editable copy", "sanctuary.resource_pack.name": "Sanctuary textures", "sanctuary.resource_pack.description": "Sanctuary textures — %s", "sanctuary.familiar.personality": "Personality: %s", diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json index 3a3b282..705a2f9 100644 --- a/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json +++ b/mods/sanctuary/src/main/resources/assets/sanctuary/lang/fr_fr.json @@ -1753,6 +1753,14 @@ "sanctuary.preload.cities": "Préparation des implantations", "sanctuary.preload.cache_write": "Enregistrement des plans", "sanctuary.familiar.dragon.lift": "Sur la tête : maintenir %s pour monter, relâcher pour planer.", + "sanctuary.resource_pack.customize": "Personnaliser Sanctuary", + "sanctuary.resource_pack.open_copy": "Ouvrir ma copie", + "sanctuary.resource_pack.creating": "Création de la copie…", + "sanctuary.resource_pack.customize_help": "Crée une copie modifiable des ressources de Sanctuary. Activez-la et placez-la en haut de la liste. Vos modifications sont conservées lors des mises à jour.", + "sanctuary.resource_pack.copy_ready": "Copie prête ! Activez Sanctuary-Custom et placez-le au-dessus des autres packs. Cliquez pour ouvrir son dossier et son guide.", + "sanctuary.resource_pack.copy_failed": "Copie impossible — réessayer", + "sanctuary.resource_pack.copy_failed_help": "Vérifiez les droits d’écriture et le chemin resourcepacks/Sanctuary-Custom. Les détails sont dans le journal du jeu.", + "sanctuary.resource_pack.custom_description": "Sanctuary — votre copie modifiable", "sanctuary.resource_pack.name": "Textures Sanctuary", "sanctuary.resource_pack.description": "Textures Sanctuary — %s", "sanctuary.familiar.personality": "Personnalité : %s", diff --git a/mods/sanctuary/src/main/resources/assets/sanctuary/textures/item/golden_wrench.png b/mods/sanctuary/src/main/resources/assets/sanctuary/textures/item/golden_wrench.png index de6818ca0a0e95e45f57a49c8759a0e0c6988c6f..60519d063f230722ac909a864d81ffe4788d650c 100644 GIT binary patch delta 138 zcmdnOc!Y6+gct`i0|SGGE`KnPVk{1FcVbv~PUhuAMcquUk|4iehW{{7*C`SPRAcAq z;us<^b?RAbJ_ZF2=74=s@9GmDv-!%r`8G?)Wgg>+Rf`)hGS%^FEx74tcA;DLS>D;z jM#U9-ew6umPqbt|n#P!AQ1HtIXcB{`tDnm{r-UW|t`9Xl delta 122 zcmV-=0EPd=0ki>-7zqRe0002(-QrS_E-hvObW%=J06^y0W&i*HL`g(JRCwBBzzRY` z1Hd$^kg;kRm=)1s>d;V(CecBZR0#foM4$$6TI+UxOY$Z@}o|KSf*!BrCE7tHV<2I@LR!hoW7o-U3d z5>uz1wdP|`;9w5e7xk__@iCjP%$sksgk0t^o>;ZG@gh?luhxQ_er6ZCWuN7pU2Rlc hvFAsbkM~4N_M>TxSq25aT!1Dqc)I$ztaD0e0sty9LoWaT literal 0 HcmV?d00001 diff --git a/ressources-pack/sanctuary/pack.mcmeta b/ressources-pack/sanctuary/pack.mcmeta index df5f50a..32399a2 100644 --- a/ressources-pack/sanctuary/pack.mcmeta +++ b/ressources-pack/sanctuary/pack.mcmeta @@ -3,7 +3,7 @@ "description": { "translate": "sanctuary.resource_pack.description", "with": [ - "beta.090" + "beta.121" ], "fallback": "Sanctuary textures — %s" }, diff --git a/ressources-pack/sanctuary/releases/beta.121.json b/ressources-pack/sanctuary/releases/beta.121.json new file mode 100644 index 0000000..d5ad924 --- /dev/null +++ b/ressources-pack/sanctuary/releases/beta.121.json @@ -0,0 +1,287 @@ +{ + "version": "beta.121", + "minecraft": "26.3", + "format": [ + 97, + 1 + ], + "builtinId": "sanctuary:textures", + "activation": "DEFAULT_ENABLED", + "files": { + "assets/minecraft/textures/gui/sprites/hud/food_empty.png": "80ea14a291330f3253fa4ba3c7aa5eeea73ac3df71c85eec649ae75762574cd2", + "assets/minecraft/textures/gui/sprites/hud/food_empty_hunger.png": "f9f725d5f76f09c9284ec8ef3eab3bab714b04306ea5b88d2774c6d96c65e525", + "assets/minecraft/textures/gui/sprites/hud/food_full.png": "29f5cddd23a6383973690101b3d1d7ab10e421b8bff8c5359e8d2623576e2f14", + "assets/minecraft/textures/gui/sprites/hud/food_full_hunger.png": "1c1969632df22e5c3be196ace904174e7797222b4d6514f442fcce0cc9fb2361", + "assets/minecraft/textures/gui/sprites/hud/food_half.png": "e5eda03de917caca665dc5ac5210fdf90af745cad0ee17ddccddc4365a7ee55a", + "assets/minecraft/textures/gui/sprites/hud/food_half_hunger.png": "51be68df64c4d01c2dff3c300f9e1833bccbc19007d7a18b567a42160740fa8e", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_full.png": "4afb2035139c659ff7ed2fbf16bb4c4cc12158c664e422cbb964d4c926f40844", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_full_blinking.png": "4afb2035139c659ff7ed2fbf16bb4c4cc12158c664e422cbb964d4c926f40844", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_half.png": "ab37c9a7b3ded346b5ab125a6a87045ff6b599a8e1f1796290aae344d8f6189b", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_half_blinking.png": "ab37c9a7b3ded346b5ab125a6a87045ff6b599a8e1f1796290aae344d8f6189b", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_hardcore_full.png": "aa4a51a65cf6fd6b76dbc040f68b7a90ee70b8b23298d2628a8e0a2ea54d924d", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_hardcore_full_blinking.png": "aa4a51a65cf6fd6b76dbc040f68b7a90ee70b8b23298d2628a8e0a2ea54d924d", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_hardcore_half.png": "f88b24663f7c14e58490e1a8a60f44339f05c284fb89dbbf6da6bd9890291e06", + "assets/minecraft/textures/gui/sprites/hud/heart/absorbing_hardcore_half_blinking.png": "f88b24663f7c14e58490e1a8a60f44339f05c284fb89dbbf6da6bd9890291e06", + "assets/minecraft/textures/gui/sprites/hud/heart/container.png": "b92355b32f566dd5ec209dcf6f25ddd239fdf967a70af42308ef9607aab3b194", + "assets/minecraft/textures/gui/sprites/hud/heart/container_blinking.png": "1b1094514a73d8673110595050003fff6a7da1d33e6457ceeae004634c2c0963", + "assets/minecraft/textures/gui/sprites/hud/heart/container_hardcore.png": "b92355b32f566dd5ec209dcf6f25ddd239fdf967a70af42308ef9607aab3b194", + "assets/minecraft/textures/gui/sprites/hud/heart/container_hardcore_blinking.png": "1b1094514a73d8673110595050003fff6a7da1d33e6457ceeae004634c2c0963", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_full.png": "66a22e5a9c1be724078bf6392970917ce74548a75242cb9a8694a8cc788893ed", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_full_blinking.png": "66a22e5a9c1be724078bf6392970917ce74548a75242cb9a8694a8cc788893ed", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_half.png": "dda4ed21c8f12f4c5f28fea52d19fda8e09451adbb568bdc5aa4b4243cad9795", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_half_blinking.png": "dda4ed21c8f12f4c5f28fea52d19fda8e09451adbb568bdc5aa4b4243cad9795", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_hardcore_full.png": "8b6d31ee17b3eacbbfe69a6c8cf165d5efee9af12aae763a073818bfcc47d2fd", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_hardcore_full_blinking.png": "8b6d31ee17b3eacbbfe69a6c8cf165d5efee9af12aae763a073818bfcc47d2fd", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_hardcore_half.png": "55448c040468dab90f48e03392e90b7f4f635109349c1524619babeb875177ac", + "assets/minecraft/textures/gui/sprites/hud/heart/frozen_hardcore_half_blinking.png": "55448c040468dab90f48e03392e90b7f4f635109349c1524619babeb875177ac", + "assets/minecraft/textures/gui/sprites/hud/heart/full.png": "acb11da7611dc8239d4da2fe500cca2fe88a2c4facccf42fa7207c0e9dba4a16", + "assets/minecraft/textures/gui/sprites/hud/heart/full_blinking.png": "d43889d4c676a6e2498b0510bf4f77c0050b792884952c67475f4bff097a498b", + "assets/minecraft/textures/gui/sprites/hud/heart/half.png": "98d1fca665a309879c19c06b0658ba5407520f13a02d4bf7321b060534491efc", + "assets/minecraft/textures/gui/sprites/hud/heart/half_blinking.png": "f63cf9331c3087e5e403b96e2456721cbbbc4be05b86c3443b863efda40b6c88", + "assets/minecraft/textures/gui/sprites/hud/heart/hardcore_full.png": "0a7788d62fb70523880ca26120add4fb397a35ea70e7deca036c8fc2afcbada7", + "assets/minecraft/textures/gui/sprites/hud/heart/hardcore_full_blinking.png": "d66cf76e587d7bbd435d05d4c8a4f3835a90dbfdd63a5e825066e0cf2de53d52", + "assets/minecraft/textures/gui/sprites/hud/heart/hardcore_half.png": "92dd5fe2e4b355b627cf1340a569923d3cd5d6c3c7963e60e6abee207a1abed5", + "assets/minecraft/textures/gui/sprites/hud/heart/hardcore_half_blinking.png": "380da417eeefbaccf0f9f9bf03efd6d2ae713567ddcd47dfbf2c7298d0c2203b", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_full.png": "5c47760c8770cbed12392e65fdd2a3acd33836a6a8275f6abd4ce9f56ac01e9f", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_full_blinking.png": "bb427c5811d0eaa255f124076e4609333f8301cd5c7094fb344c5480cbb4a995", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_half.png": "7e0d0118a3e3a3d4a11dc1b65a4c66af0abdded95d227e3e2fbd97364b4c7ca6", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_half_blinking.png": "0b90d19c270047be3b1d502c3f2def99f5899ef430ed6bfff45cc35911e75076", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_hardcore_full.png": "8900928082f3ca73c312b8bc78357f283d4101f7dc147f563a09a3ad4c3b8937", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_hardcore_full_blinking.png": "354b9975971caf7f3ac28162b4ced0adc9edf9c11e82797bc13e4d9c5bc566bb", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_hardcore_half.png": "a3462b71265ef37c0bacff741d106c23f341696ab922049933aaa7751e24c33d", + "assets/minecraft/textures/gui/sprites/hud/heart/poisoned_hardcore_half_blinking.png": "b705fe0b9811ded037b08d4a639710e8829a03d373b5e86087323c811f9654e3", + "assets/minecraft/textures/gui/sprites/hud/heart/vehicle_container.png": "b92355b32f566dd5ec209dcf6f25ddd239fdf967a70af42308ef9607aab3b194", + "assets/minecraft/textures/gui/sprites/hud/heart/vehicle_full.png": "7d676dd277663d3d87bdbe52632235946e484301fb47b6f8b27633d2d4efe1e3", + "assets/minecraft/textures/gui/sprites/hud/heart/vehicle_half.png": "e2171726715fba71f86b6fee9714ec8e3e3c08e75beda62bf411b1d363363ae9", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_full.png": "5c5475bdb3a917b6414c1a1ea6400c1f00bdc1e5906d6781d6abbb9411747fa6", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_full_blinking.png": "8d8f5c897fdd6e3f6e9ca1b7c4e55abbf3af9437ea24d094b80ce9e134a1b27d", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_half.png": "a368bc604caa0aab258d1f9d4313db6031c5462361c41578dd718fae3f677a76", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_half_blinking.png": "758ee154d7879a64c6903e0a0ecb9dd068ca16aef225a9ca8055f68d79ff8e17", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_hardcore_full.png": "a6b4b53b39e85e5758b3ed99e4303f4f7f24d530e0f27510daa5b6c456ab725d", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_hardcore_full_blinking.png": "0fd9f717cbad4111e10c0f848af41e7e66c92d3225fd2ef0b0df48fdf397306c", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_hardcore_half.png": "3e069dcbca3a61492c6480a60c985f21ce39bf851ad870f69f8612689e2efd6b", + "assets/minecraft/textures/gui/sprites/hud/heart/withered_hardcore_half_blinking.png": "c9bf1f18f28aad32777dacd1b38ff93263592648bd0a7b9cc2e6633597c625a7", + "assets/minecraft/textures/gui/sprites/server_list/join.png": "cdf278b928ac6ecf32b4c28304dcace1ef9d1df017d6bf22610896a41b71f39e", + "assets/minecraft/textures/gui/sprites/server_list/join_highlighted.png": "e92353fbd181db587f3c5c4e688638709e69487e9c9eae076918489ef8d2f99e", + "assets/minecraft/textures/gui/sprites/server_list/move_down.png": "5443d2f341d7f6ecf00d24759d21b9f11d3c00b6b3464cf3209aad1893fbec35", + "assets/minecraft/textures/gui/sprites/server_list/move_down_highlighted.png": "8bc3722212402866e0b83e30893e5681e0173843140d51d54d0381d81fda0923", + "assets/minecraft/textures/gui/sprites/server_list/move_up.png": "12a353f27c85943b9e6f78b0534ad2f0315f8fc76af8fbdf25f6ddad674566e1", + "assets/minecraft/textures/gui/sprites/server_list/move_up_highlighted.png": "6e0632d7b5cde7be54035ef65a2976f38a960b834ee36e0c7c5450d6f9ffaa4b", + "assets/minecraft/textures/gui/sprites/transferable_list/move_down.png": "829a14cbe49c70284572ba3f6a7fc812b401ed4bac910d46a4b37fa048dc4a0e", + "assets/minecraft/textures/gui/sprites/transferable_list/move_down_highlighted.png": "f0621fda65ad07e989776b554458e941adff9ca7b9f48a64f18840a04e104567", + "assets/minecraft/textures/gui/sprites/transferable_list/move_up.png": "63ffe9417b1ca97d27e6da8bc1d0817b8b282f1489c47a64cba90e9cd6601e81", + "assets/minecraft/textures/gui/sprites/transferable_list/move_up_highlighted.png": "6b7f7ea182728d8ddacd9930f97aa4b6ab69897008eaf655cb4ab00f1b094498", + "assets/minecraft/textures/gui/sprites/transferable_list/select.png": "77979b167e05e92423c35cc3ee72458710e5573833cbdc943ba11d8d50b1b294", + "assets/minecraft/textures/gui/sprites/transferable_list/select_highlighted.png": "2e7fefa4299a08ea3b21d08c23e0fdaa669b25ae24cdce519206abf59e0d68b3", + "assets/minecraft/textures/gui/sprites/transferable_list/unselect.png": "a0b5817ea41b15f72f725101d25581cf1ed5f78069d791d8f679f451e992e840", + "assets/minecraft/textures/gui/sprites/transferable_list/unselect_highlighted.png": "f49ff96621c3e997ef3582a23f8bd727d65d2483e7854545ee87c1ed4d3c3232", + "assets/minecraft/textures/gui/sprites/widget/button.png": "79fbfe504e72598ba5f61a8c8e5fe6dbc3ec6c8a530fd6089efee17f89fb7b10", + "assets/minecraft/textures/gui/sprites/widget/button.png.mcmeta": "ebdf3a9e4f6dfd37d72ad6af4213d9f61fe8f8342e8f12f00bb6888f3ae28acb", + "assets/minecraft/textures/gui/sprites/widget/button_disabled.png": "55f92a6efea542d73ea19ed26147b4ce3aabe405b56e37db0d3cc75dc18a1f47", + "assets/minecraft/textures/gui/sprites/widget/button_disabled.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/button_highlighted.png": "b658d1c9b38057aee2c63f49e19a734763eba720bd88be703ef9835c7f5f7f84", + "assets/minecraft/textures/gui/sprites/widget/button_highlighted.png.mcmeta": "ebdf3a9e4f6dfd37d72ad6af4213d9f61fe8f8342e8f12f00bb6888f3ae28acb", + "assets/minecraft/textures/gui/sprites/widget/checkbox.png": "af426f3d1e5b32f74efc0aa522db6472a18ee4f2d87608acea04d3960168b5d9", + "assets/minecraft/textures/gui/sprites/widget/checkbox_highlighted.png": "57ec86b031c3a480140a60799bde4ca1ba7ab9c14d8a7a37eb48ff64f01e29c6", + "assets/minecraft/textures/gui/sprites/widget/checkbox_selected.png": "6d70776447e4ad66d6606b9f7d670d4aa18238429f9c68db51c7f10be01c12ec", + "assets/minecraft/textures/gui/sprites/widget/checkbox_selected_highlighted.png": "96875351b998a1e7f730c6231ff4638c7df7a80986d7be94511878ec89c8fbfe", + "assets/minecraft/textures/gui/sprites/widget/cross_button.png": "922c64fb3c504e39cbcdf874a0a91ce20b84041724dd8a5ddf318af7d24ca539", + "assets/minecraft/textures/gui/sprites/widget/cross_button_highlighted.png": "016e049e726b24fad10fc9d40c85873af92ef02eec5b4ec9793665b80347e02d", + "assets/minecraft/textures/gui/sprites/widget/locked_button.png": "9bf2c84eed89da70f7757aee27973834ab421d782ee60ea017e833eeceb46f93", + "assets/minecraft/textures/gui/sprites/widget/locked_button_disabled.png": "e77079180fc95b0e75adc280ee0c916f2d315276103a8b88b7440b81e3ea3772", + "assets/minecraft/textures/gui/sprites/widget/locked_button_highlighted.png": "9163318a63b1f5c31b115d644020fbeae5fc3e6fd231f877f4c35a82c4a3c414", + "assets/minecraft/textures/gui/sprites/widget/page_backward.png": "af6220ed0297e43365a402b2e524ca4ce92f3e8f1b7e746e7f23a4ddf7a7b738", + "assets/minecraft/textures/gui/sprites/widget/page_backward_highlighted.png": "ff927d1fd93dbbb226c1693cebd6510ca6a0a1cea526dbf67a7b59c60313af0c", + "assets/minecraft/textures/gui/sprites/widget/page_forward.png": "8a2c12ad9dd5877a764e968aa3015f5a69e31bc55585edd788eac9c15bbaf4b9", + "assets/minecraft/textures/gui/sprites/widget/page_forward_highlighted.png": "eb983beae120839fbb3c8c96c862beb24f97ccd172d1f31b7e44f3a9fa483fe2", + "assets/minecraft/textures/gui/sprites/widget/scroller.png": "066af6679ba68b0e67335cb6ce48ca3e1a058c9b074411573d7ec0418bdea600", + "assets/minecraft/textures/gui/sprites/widget/scroller.png.mcmeta": "f6a77d3537ff679b691e3d4b7bab0a1e076f71d1dec602bd65fa16a505092c53", + "assets/minecraft/textures/gui/sprites/widget/scroller_background.png": "be03c9e0fcabe74d352539157353497497845669491fb5b2ac07ad27116df7f9", + "assets/minecraft/textures/gui/sprites/widget/scroller_background.png.mcmeta": "f6a77d3537ff679b691e3d4b7bab0a1e076f71d1dec602bd65fa16a505092c53", + "assets/minecraft/textures/gui/sprites/widget/slider.png": "55f92a6efea542d73ea19ed26147b4ce3aabe405b56e37db0d3cc75dc18a1f47", + "assets/minecraft/textures/gui/sprites/widget/slider.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/slider_handle.png": "3b22d9afcea59fd265a75ef8ba547b8f56ae8d53ca7675ccb9bc963abfa3cccb", + "assets/minecraft/textures/gui/sprites/widget/slider_handle.png.mcmeta": "9ecf324f340ac117631939372d93ec59043f22d6caec7b7ea7c140b4d8d77c22", + "assets/minecraft/textures/gui/sprites/widget/slider_handle_highlighted.png": "a89e733c03068dad39c642738508b1e41f7c263e56b32939ff26f72db2fedcd6", + "assets/minecraft/textures/gui/sprites/widget/slider_handle_highlighted.png.mcmeta": "9ecf324f340ac117631939372d93ec59043f22d6caec7b7ea7c140b4d8d77c22", + "assets/minecraft/textures/gui/sprites/widget/slider_highlighted.png": "ba0d5d1e9b3bbb1af5311457a45372d2c89b5dac32a74de40815db945b45d2a5", + "assets/minecraft/textures/gui/sprites/widget/slider_highlighted.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/slot_frame.png": "8428676f5a55c8fb1f68d693b8b4e8809f03dfa00b062fd1005a307cff9c0a75", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button.png": "c4b7b0d01cc458e8d623af1b7cab971f98f5fc5f239cb0d1b0e90b7428406688", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button_disabled.png": "0e4e936c191d125ad2abc4d5e253fb9bab7a36d290abd998d752224a70cbff13", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button_highlighted.png": "36c81bc881f23d3d377128022c47e43403fe9848690c430ae8427198be0d6e1d", + "assets/minecraft/textures/gui/sprites/world_list/error.png": "e4e219517e9b8db2b018efc532f08de50b65019eb094aea0a8814f7d5358433d", + "assets/minecraft/textures/gui/sprites/world_list/error_highlighted.png": "37ac98fc99850c78f65ad3dc1b759777db030ca859c8047ffeb453491107b65e", + "assets/minecraft/textures/gui/sprites/world_list/join.png": "cb437430e8122c0f791d9834491e7cee11b3c514b25e809ae7f9578879be1e84", + "assets/minecraft/textures/gui/sprites/world_list/join_highlighted.png": "e92353fbd181db587f3c5c4e688638709e69487e9c9eae076918489ef8d2f99e", + "assets/minecraft/textures/gui/sprites/world_list/marked_join.png": "8732a1c1419bd4046ca8eec12d6c9fdc6ddbd764cce373e12e17a334aed039ed", + "assets/minecraft/textures/gui/sprites/world_list/marked_join_highlighted.png": "23c4e5b123be8b555ba8f130a03acde63e2a6fb48f1c1180a031fb077687b631", + "assets/minecraft/textures/gui/sprites/world_list/warning.png": "e4e219517e9b8db2b018efc532f08de50b65019eb094aea0a8814f7d5358433d", + "assets/minecraft/textures/gui/sprites/world_list/warning_highlighted.png": "49fee0502fab6ea38031664916ba328a1e4d68d8507761ba260efb67e640adde", + "assets/minecraft/textures/gui/title/background/panorama_0.png": "af5f25cd7db1b878806cacfc6eabb6a896e37f41340787db0de79d222ec1dbea", + "assets/minecraft/textures/gui/title/background/panorama_0.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_1.png": "3323296b81ce46d3dff93abc11289657cacaf9183b0f0663a8fa56d38ae436c8", + "assets/minecraft/textures/gui/title/background/panorama_1.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_2.png": "751f2aacfcb382dff3c57be00ece8e3a3cdfe0479374451ecbf70aa95d915b4d", + "assets/minecraft/textures/gui/title/background/panorama_2.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_3.png": "bffc916a16c3709d01e10870c329e8b915807177166f271e91ed72aa591d4f70", + "assets/minecraft/textures/gui/title/background/panorama_3.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_4.png": "d750f000ff1df1680e30c3c2c4e6921bdd5b69911e1d4e8aec527ef58841edce", + "assets/minecraft/textures/gui/title/background/panorama_4.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_5.png": "26f967071cde84299ba747dba7aa2db73784e3d89b158fb9092d0cddd45d215c", + "assets/minecraft/textures/gui/title/background/panorama_5.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/edition.png": "44d032976ac08bb01847de99d62cfea98298825fd75a36dbec319eba76081cbb", + "assets/minecraft/textures/gui/title/minecraft.png": "efee73a6c812c89b2900d41f6446c0f906ccf85136b6c226daf42870a41a5157", + "assets/sanctuary/items/zero_cape.json": "dcdcb599fe8f645ea27429da1c45ac5925b4672578f01cb6b93b2cd03f1f8b7f", + "assets/sanctuary/models/item/zero_cape.json": "2e1c1b1030fd054d60cbc2544041bd80a44ac3f2ea89d098958666b97251b56a", + "assets/sanctuary/textures/entity/cape/zero_cape.png": "f9a76537647989f9a0b6d001e320dac591c359e9e61a31f4ce11c88f207f0ad4", + "assets/sanctuary/textures/gui/aptitudes/familiar.png": "c855f9cddb68cdb4a7110e70af60afbe068bc0176b9b6c69f38e052fcdbfda6c", + "assets/sanctuary/textures/gui/aptitudes/familiarpower.png": "9ee75fd66f68bb2ce7b4158d2511ef3a9cd7a20f2b105520c4a4fcec2fee378b", + "assets/sanctuary/textures/gui/aptitudes/hungerknown.png": "1e5cd57d12592f03dc2d2071a8c2873a30939f07b0db021fcb7fc34468709acc", + "assets/sanctuary/textures/gui/aptitudes/names.png": "77dcea1c72970f87043b551c3506bfec64290b478a4d2981f280079d98158628", + "assets/sanctuary/textures/gui/aptitudes/recipes.png": "88ec437776844c15104e0856af8fd768f511b951c79802a151d6ce4ffbbb4357", + "assets/sanctuary/textures/gui/aptitudes/rest.png": "f343fd835ed20b9feb5195cd3727c0a3882090b33caf08c3f43120b250c8786e", + "assets/sanctuary/textures/gui/aptitudes/sorting.png": "fa6689f4ffdac7ffa58900afc8b264e8106cde7a992167ada7e8debda4d09618", + "assets/sanctuary/textures/gui/aptitudes/swim.png": "1e98150e08f2f47208ac0b14517760bddb55be4c013bfc3693dc474d951a9f9a", + "assets/sanctuary/textures/gui/aptitudes/worldmap.png": "a413da0a34110d4b7d4422ca2f59defc1c6394184186068974a5ff6c68a4e4b0", + "assets/sanctuary/textures/gui/aptitudes/zoom.png": "07e1c2dc51ff86e5f6903a5fc058603a886876600b01d124770336deefffa19f", + "assets/sanctuary/textures/gui/food_details.png": "1ebc30ae7394393b5b7b8a0383102bcd035e5e92a602b89db05eeab66d2ef134", + "assets/sanctuary/textures/gui/inventory/cape.png": "cd32c5f61d088740a11da8dd2767fda11f8db6b1fe65587a7c5b043177befb17", + "assets/sanctuary/textures/gui/inventory/cosmetics.png": "fcb2bca5f01a6fa6028cf6748d06320acb02011d7a7a93103d5ee24be13dca4b", + "assets/sanctuary/textures/gui/inventory/egg.png": "344a8624bd03b45472acb045fa607172d00dae603594bfa5e411d5f126fc0975", + "assets/sanctuary/textures/gui/progression/breathing.png": "2b1bfe8e0a33ae957f87dc4086b848ac26e209a4b90998fce153b2f394201157", + "assets/sanctuary/textures/gui/progression/building.png": "2d143ca35c5eac3d2a07943fe440b6893e189ff2389fd1b300d4f08bd98309ec", + "assets/sanctuary/textures/gui/progression/heart.png": "224b4162d500a632fe6861613026941a7dcd0eee97987e0c92483733f2fa0a1e", + "assets/sanctuary/textures/gui/progression/hunger.png": "9b3cb1e8206e7d17306fd461660b8ba154d729325f17181f6a045c175674ea97", + "assets/sanctuary/textures/gui/progression/inventory.png": "d66b68dda35538639f956d670b3ff25e064b00ab022a6292ce8c0d3e3ab473a3", + "assets/sanctuary/textures/gui/progression/mining.png": "c0134e182d63031ba2b53ab4477f8e1c96352375998c1c0bc54fc452816d2599", + "assets/sanctuary/textures/item/cape/zero_cape.png": "d3386907d5cc90cdf1911c911faa26dbcb6ea16ce0dc7321abb482f3322255fb", + "assets/sanctuary/textures/item/golden_wrench.png": "a97570908db75caf8e6fc2f5ecabf12c54fd99bfea7be634df66c4310dca22af", + "pack.mcmeta": "70189fadacaa715704105dd1adea84bd4b4bd2ec650cf048644ab379707afeaf", + "pack.png": "33adb8f689d55b7bf8d0824b02942ea3823f128b27fab458713ab9582061a1a0" + }, + "import": { + "folder": "Sanctuary-Resource-Pack-base-26-3", + "files": { + "FOOD.md": "e271c13d8044ee54b7bd9f0e34627480dab14df3f91a17e2a6fcb87e8cba0424", + "HUD-SOURCES.json": "40b74fe75a581abdf7c621fbccd44a2acf1a8d2526266bb0b36ff703c404dd3c", + "HUD.md": "300eb32ece21171818d97078cc16e9c341fbf19d84d70d33edc898c8479d7b7b", + "README.md": "8ce801201583de8ac330e64973d61a4eaed4ecb89d58e31318c5d76883f1cc98", + "assets/minecraft/textures/gui/sprites/hud/food_empty.png": "80ea14a291330f3253fa4ba3c7aa5eeea73ac3df71c85eec649ae75762574cd2", + "assets/minecraft/textures/gui/sprites/hud/food_empty_hunger.png": "f9f725d5f76f09c9284ec8ef3eab3bab714b04306ea5b88d2774c6d96c65e525", + "assets/minecraft/textures/gui/sprites/hud/food_full.png": "29f5cddd23a6383973690101b3d1d7ab10e421b8bff8c5359e8d2623576e2f14", + "assets/minecraft/textures/gui/sprites/hud/food_full_hunger.png": "1c1969632df22e5c3be196ace904174e7797222b4d6514f442fcce0cc9fb2361", + "assets/minecraft/textures/gui/sprites/hud/food_half.png": "e5eda03de917caca665dc5ac5210fdf90af745cad0ee17ddccddc4365a7ee55a", + "assets/minecraft/textures/gui/sprites/hud/food_half_hunger.png": "51be68df64c4d01c2dff3c300f9e1833bccbc19007d7a18b567a42160740fa8e", + "assets/minecraft/textures/gui/sprites/server_list/join.png": "cdf278b928ac6ecf32b4c28304dcace1ef9d1df017d6bf22610896a41b71f39e", + "assets/minecraft/textures/gui/sprites/server_list/join_highlighted.png": "e92353fbd181db587f3c5c4e688638709e69487e9c9eae076918489ef8d2f99e", + "assets/minecraft/textures/gui/sprites/server_list/move_down.png": "5443d2f341d7f6ecf00d24759d21b9f11d3c00b6b3464cf3209aad1893fbec35", + "assets/minecraft/textures/gui/sprites/server_list/move_down_highlighted.png": "8bc3722212402866e0b83e30893e5681e0173843140d51d54d0381d81fda0923", + "assets/minecraft/textures/gui/sprites/server_list/move_up.png": "12a353f27c85943b9e6f78b0534ad2f0315f8fc76af8fbdf25f6ddad674566e1", + "assets/minecraft/textures/gui/sprites/server_list/move_up_highlighted.png": "6e0632d7b5cde7be54035ef65a2976f38a960b834ee36e0c7c5450d6f9ffaa4b", + "assets/minecraft/textures/gui/sprites/transferable_list/move_down.png": "829a14cbe49c70284572ba3f6a7fc812b401ed4bac910d46a4b37fa048dc4a0e", + "assets/minecraft/textures/gui/sprites/transferable_list/move_down_highlighted.png": "f0621fda65ad07e989776b554458e941adff9ca7b9f48a64f18840a04e104567", + "assets/minecraft/textures/gui/sprites/transferable_list/move_up.png": "63ffe9417b1ca97d27e6da8bc1d0817b8b282f1489c47a64cba90e9cd6601e81", + "assets/minecraft/textures/gui/sprites/transferable_list/move_up_highlighted.png": "6b7f7ea182728d8ddacd9930f97aa4b6ab69897008eaf655cb4ab00f1b094498", + "assets/minecraft/textures/gui/sprites/transferable_list/select.png": "77979b167e05e92423c35cc3ee72458710e5573833cbdc943ba11d8d50b1b294", + "assets/minecraft/textures/gui/sprites/transferable_list/select_highlighted.png": "2e7fefa4299a08ea3b21d08c23e0fdaa669b25ae24cdce519206abf59e0d68b3", + "assets/minecraft/textures/gui/sprites/transferable_list/unselect.png": "a0b5817ea41b15f72f725101d25581cf1ed5f78069d791d8f679f451e992e840", + "assets/minecraft/textures/gui/sprites/transferable_list/unselect_highlighted.png": "f49ff96621c3e997ef3582a23f8bd727d65d2483e7854545ee87c1ed4d3c3232", + "assets/minecraft/textures/gui/sprites/widget/button.png": "79fbfe504e72598ba5f61a8c8e5fe6dbc3ec6c8a530fd6089efee17f89fb7b10", + "assets/minecraft/textures/gui/sprites/widget/button.png.mcmeta": "ebdf3a9e4f6dfd37d72ad6af4213d9f61fe8f8342e8f12f00bb6888f3ae28acb", + "assets/minecraft/textures/gui/sprites/widget/button_disabled.png": "55f92a6efea542d73ea19ed26147b4ce3aabe405b56e37db0d3cc75dc18a1f47", + "assets/minecraft/textures/gui/sprites/widget/button_disabled.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/button_highlighted.png": "b658d1c9b38057aee2c63f49e19a734763eba720bd88be703ef9835c7f5f7f84", + "assets/minecraft/textures/gui/sprites/widget/button_highlighted.png.mcmeta": "ebdf3a9e4f6dfd37d72ad6af4213d9f61fe8f8342e8f12f00bb6888f3ae28acb", + "assets/minecraft/textures/gui/sprites/widget/checkbox.png": "af426f3d1e5b32f74efc0aa522db6472a18ee4f2d87608acea04d3960168b5d9", + "assets/minecraft/textures/gui/sprites/widget/checkbox_highlighted.png": "57ec86b031c3a480140a60799bde4ca1ba7ab9c14d8a7a37eb48ff64f01e29c6", + "assets/minecraft/textures/gui/sprites/widget/checkbox_selected.png": "6d70776447e4ad66d6606b9f7d670d4aa18238429f9c68db51c7f10be01c12ec", + "assets/minecraft/textures/gui/sprites/widget/checkbox_selected_highlighted.png": "96875351b998a1e7f730c6231ff4638c7df7a80986d7be94511878ec89c8fbfe", + "assets/minecraft/textures/gui/sprites/widget/cross_button.png": "922c64fb3c504e39cbcdf874a0a91ce20b84041724dd8a5ddf318af7d24ca539", + "assets/minecraft/textures/gui/sprites/widget/cross_button_highlighted.png": "016e049e726b24fad10fc9d40c85873af92ef02eec5b4ec9793665b80347e02d", + "assets/minecraft/textures/gui/sprites/widget/locked_button.png": "9bf2c84eed89da70f7757aee27973834ab421d782ee60ea017e833eeceb46f93", + "assets/minecraft/textures/gui/sprites/widget/locked_button_disabled.png": "e77079180fc95b0e75adc280ee0c916f2d315276103a8b88b7440b81e3ea3772", + "assets/minecraft/textures/gui/sprites/widget/locked_button_highlighted.png": "9163318a63b1f5c31b115d644020fbeae5fc3e6fd231f877f4c35a82c4a3c414", + "assets/minecraft/textures/gui/sprites/widget/page_backward.png": "af6220ed0297e43365a402b2e524ca4ce92f3e8f1b7e746e7f23a4ddf7a7b738", + "assets/minecraft/textures/gui/sprites/widget/page_backward_highlighted.png": "ff927d1fd93dbbb226c1693cebd6510ca6a0a1cea526dbf67a7b59c60313af0c", + "assets/minecraft/textures/gui/sprites/widget/page_forward.png": "8a2c12ad9dd5877a764e968aa3015f5a69e31bc55585edd788eac9c15bbaf4b9", + "assets/minecraft/textures/gui/sprites/widget/page_forward_highlighted.png": "eb983beae120839fbb3c8c96c862beb24f97ccd172d1f31b7e44f3a9fa483fe2", + "assets/minecraft/textures/gui/sprites/widget/scroller.png": "066af6679ba68b0e67335cb6ce48ca3e1a058c9b074411573d7ec0418bdea600", + "assets/minecraft/textures/gui/sprites/widget/scroller.png.mcmeta": "f6a77d3537ff679b691e3d4b7bab0a1e076f71d1dec602bd65fa16a505092c53", + "assets/minecraft/textures/gui/sprites/widget/scroller_background.png": "be03c9e0fcabe74d352539157353497497845669491fb5b2ac07ad27116df7f9", + "assets/minecraft/textures/gui/sprites/widget/scroller_background.png.mcmeta": "f6a77d3537ff679b691e3d4b7bab0a1e076f71d1dec602bd65fa16a505092c53", + "assets/minecraft/textures/gui/sprites/widget/slider.png": "55f92a6efea542d73ea19ed26147b4ce3aabe405b56e37db0d3cc75dc18a1f47", + "assets/minecraft/textures/gui/sprites/widget/slider.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/slider_handle.png": "3b22d9afcea59fd265a75ef8ba547b8f56ae8d53ca7675ccb9bc963abfa3cccb", + "assets/minecraft/textures/gui/sprites/widget/slider_handle.png.mcmeta": "9ecf324f340ac117631939372d93ec59043f22d6caec7b7ea7c140b4d8d77c22", + "assets/minecraft/textures/gui/sprites/widget/slider_handle_highlighted.png": "a89e733c03068dad39c642738508b1e41f7c263e56b32939ff26f72db2fedcd6", + "assets/minecraft/textures/gui/sprites/widget/slider_handle_highlighted.png.mcmeta": "9ecf324f340ac117631939372d93ec59043f22d6caec7b7ea7c140b4d8d77c22", + "assets/minecraft/textures/gui/sprites/widget/slider_highlighted.png": "ba0d5d1e9b3bbb1af5311457a45372d2c89b5dac32a74de40815db945b45d2a5", + "assets/minecraft/textures/gui/sprites/widget/slider_highlighted.png.mcmeta": "979a3e114ffb0213932b71873db149c32a8c1c8ba65a4cbe5d30a1f677564fa2", + "assets/minecraft/textures/gui/sprites/widget/slot_frame.png": "8428676f5a55c8fb1f68d693b8b4e8809f03dfa00b062fd1005a307cff9c0a75", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button.png": "c4b7b0d01cc458e8d623af1b7cab971f98f5fc5f239cb0d1b0e90b7428406688", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button_disabled.png": "0e4e936c191d125ad2abc4d5e253fb9bab7a36d290abd998d752224a70cbff13", + "assets/minecraft/textures/gui/sprites/widget/unlocked_button_highlighted.png": "36c81bc881f23d3d377128022c47e43403fe9848690c430ae8427198be0d6e1d", + "assets/minecraft/textures/gui/sprites/world_list/error.png": "e4e219517e9b8db2b018efc532f08de50b65019eb094aea0a8814f7d5358433d", + "assets/minecraft/textures/gui/sprites/world_list/error_highlighted.png": "37ac98fc99850c78f65ad3dc1b759777db030ca859c8047ffeb453491107b65e", + "assets/minecraft/textures/gui/sprites/world_list/join.png": "cb437430e8122c0f791d9834491e7cee11b3c514b25e809ae7f9578879be1e84", + "assets/minecraft/textures/gui/sprites/world_list/join_highlighted.png": "e92353fbd181db587f3c5c4e688638709e69487e9c9eae076918489ef8d2f99e", + "assets/minecraft/textures/gui/sprites/world_list/marked_join.png": "8732a1c1419bd4046ca8eec12d6c9fdc6ddbd764cce373e12e17a334aed039ed", + "assets/minecraft/textures/gui/sprites/world_list/marked_join_highlighted.png": "23c4e5b123be8b555ba8f130a03acde63e2a6fb48f1c1180a031fb077687b631", + "assets/minecraft/textures/gui/sprites/world_list/warning.png": "e4e219517e9b8db2b018efc532f08de50b65019eb094aea0a8814f7d5358433d", + "assets/minecraft/textures/gui/sprites/world_list/warning_highlighted.png": "49fee0502fab6ea38031664916ba328a1e4d68d8507761ba260efb67e640adde", + "assets/minecraft/textures/gui/title/background/panorama_0.png": "af5f25cd7db1b878806cacfc6eabb6a896e37f41340787db0de79d222ec1dbea", + "assets/minecraft/textures/gui/title/background/panorama_0.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_1.png": "3323296b81ce46d3dff93abc11289657cacaf9183b0f0663a8fa56d38ae436c8", + "assets/minecraft/textures/gui/title/background/panorama_1.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_2.png": "751f2aacfcb382dff3c57be00ece8e3a3cdfe0479374451ecbf70aa95d915b4d", + "assets/minecraft/textures/gui/title/background/panorama_2.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_3.png": "bffc916a16c3709d01e10870c329e8b915807177166f271e91ed72aa591d4f70", + "assets/minecraft/textures/gui/title/background/panorama_3.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_4.png": "d750f000ff1df1680e30c3c2c4e6921bdd5b69911e1d4e8aec527ef58841edce", + "assets/minecraft/textures/gui/title/background/panorama_4.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/background/panorama_5.png": "26f967071cde84299ba747dba7aa2db73784e3d89b158fb9092d0cddd45d215c", + "assets/minecraft/textures/gui/title/background/panorama_5.png.mcmeta": "6de2cb00c45ccc7edc47a8ebac73b003af81877efa31c755e2ee89adb97e0f0f", + "assets/minecraft/textures/gui/title/edition.png": "44d032976ac08bb01847de99d62cfea98298825fd75a36dbec319eba76081cbb", + "assets/minecraft/textures/gui/title/minecraft.png": "efee73a6c812c89b2900d41f6446c0f906ccf85136b6c226daf42870a41a5157", + "assets/sanctuary/items/zero_cape.json": "dcdcb599fe8f645ea27429da1c45ac5925b4672578f01cb6b93b2cd03f1f8b7f", + "assets/sanctuary/models/item/zero_cape.json": "2e1c1b1030fd054d60cbc2544041bd80a44ac3f2ea89d098958666b97251b56a", + "assets/sanctuary/textures/entity/cape/zero_cape.png": "f9a76537647989f9a0b6d001e320dac591c359e9e61a31f4ce11c88f207f0ad4", + "assets/sanctuary/textures/gui/aptitudes/familiar.png": "c855f9cddb68cdb4a7110e70af60afbe068bc0176b9b6c69f38e052fcdbfda6c", + "assets/sanctuary/textures/gui/aptitudes/familiarpower.png": "9ee75fd66f68bb2ce7b4158d2511ef3a9cd7a20f2b105520c4a4fcec2fee378b", + "assets/sanctuary/textures/gui/aptitudes/hungerknown.png": "1e5cd57d12592f03dc2d2071a8c2873a30939f07b0db021fcb7fc34468709acc", + "assets/sanctuary/textures/gui/aptitudes/names.png": "77dcea1c72970f87043b551c3506bfec64290b478a4d2981f280079d98158628", + "assets/sanctuary/textures/gui/aptitudes/recipes.png": "88ec437776844c15104e0856af8fd768f511b951c79802a151d6ce4ffbbb4357", + "assets/sanctuary/textures/gui/aptitudes/rest.png": "f343fd835ed20b9feb5195cd3727c0a3882090b33caf08c3f43120b250c8786e", + "assets/sanctuary/textures/gui/aptitudes/sorting.png": "fa6689f4ffdac7ffa58900afc8b264e8106cde7a992167ada7e8debda4d09618", + "assets/sanctuary/textures/gui/aptitudes/swim.png": "1e98150e08f2f47208ac0b14517760bddb55be4c013bfc3693dc474d951a9f9a", + "assets/sanctuary/textures/gui/aptitudes/worldmap.png": "a413da0a34110d4b7d4422ca2f59defc1c6394184186068974a5ff6c68a4e4b0", + "assets/sanctuary/textures/gui/aptitudes/zoom.png": "07e1c2dc51ff86e5f6903a5fc058603a886876600b01d124770336deefffa19f", + "assets/sanctuary/textures/gui/food_details.png": "1ebc30ae7394393b5b7b8a0383102bcd035e5e92a602b89db05eeab66d2ef134", + "assets/sanctuary/textures/gui/inventory/cape.png": "cd32c5f61d088740a11da8dd2767fda11f8db6b1fe65587a7c5b043177befb17", + "assets/sanctuary/textures/gui/inventory/cosmetics.png": "fcb2bca5f01a6fa6028cf6748d06320acb02011d7a7a93103d5ee24be13dca4b", + "assets/sanctuary/textures/gui/inventory/egg.png": "344a8624bd03b45472acb045fa607172d00dae603594bfa5e411d5f126fc0975", + "assets/sanctuary/textures/gui/progression/breathing.png": "2b1bfe8e0a33ae957f87dc4086b848ac26e209a4b90998fce153b2f394201157", + "assets/sanctuary/textures/gui/progression/building.png": "2d143ca35c5eac3d2a07943fe440b6893e189ff2389fd1b300d4f08bd98309ec", + "assets/sanctuary/textures/gui/progression/heart.png": "224b4162d500a632fe6861613026941a7dcd0eee97987e0c92483733f2fa0a1e", + "assets/sanctuary/textures/gui/progression/hunger.png": "9b3cb1e8206e7d17306fd461660b8ba154d729325f17181f6a045c175674ea97", + "assets/sanctuary/textures/gui/progression/inventory.png": "d66b68dda35538639f956d670b3ff25e064b00ab022a6292ce8c0d3e3ab473a3", + "assets/sanctuary/textures/gui/progression/mining.png": "c0134e182d63031ba2b53ab4477f8e1c96352375998c1c0bc54fc452816d2599", + "assets/sanctuary/textures/item/cape/zero_cape.png": "d3386907d5cc90cdf1911c911faa26dbcb6ea16ce0dc7321abb482f3322255fb", + "pack.mcmeta": "62d437b8b38a48162b3602b37d4492e239575099bdd22998ff6930afa41e5f1a", + "pack.png": "33adb8f689d55b7bf8d0824b02942ea3823f128b27fab458713ab9582061a1a0" + } + }, + "changes": [ + "Golden wrench: original creator PNG, unchanged bytes.", + "Editable personal template exports current Sanctuary assets overlaid by the built-in pack." + ], + "golden_wrench_source": { + "file": "golden_wrench.png", + "sha256": "a97570908db75caf8e6fc2f5ecabf12c54fd99bfea7be634df66c4310dca22af", + "size": [ + 16, + 16 + ] + } +} diff --git a/ressources-pack/template/README.md b/ressources-pack/template/README.md new file mode 100644 index 0000000..3b01457 --- /dev/null +++ b/ressources-pack/template/README.md @@ -0,0 +1,55 @@ +# Sanctuary — votre pack personnel / your personal pack + +Cette copie est à vous : Sanctuary ne la réécrit jamais lors d'une mise à jour. +Dans Options → Packs de ressources, activez **Sanctuary-Custom** et placez-le +au-dessus de « Textures Sanctuary » et des autres packs à remplacer. + +1. Modifiez les fichiers dans `assets/`, en gardant leurs noms et chemins. +2. Rechargez avec F3 + T (ou désactivez puis réactivez le pack). +3. Pour revenir à l'apparence fournie par Sanctuary, désactivez votre pack. + +Quelques points de départ : + +| Ressource | Chemin | +| --- | --- | +| Clé dorée | `assets/sanctuary/textures/item/golden_wrench.png` | +| Briques et argiles colorées | `assets/sanctuary/textures/block/` | +| Menus et icônes Sanctuary | `assets/sanctuary/textures/gui/` | +| Vie et faim | `assets/minecraft/textures/gui/sprites/hud/` | +| Modèles des objets | `assets/sanctuary/models/item/` et `assets/sanctuary/items/` | +| Traductions | `assets/sanctuary/lang/fr_fr.json` et `en_us.json` | + +Les PNG peuvent garder la transparence. Préservez les dimensions des atlas de +menus et les découpes utilisées par le jeu. Vous pouvez également ajouter +des remplacements Minecraft dans `assets/minecraft/` ; cette base ne contient +pas toutes les ressources du jeu ni celles des autres mods. + +Cette copie est un instantané complet des ressources Sanctuary à sa création. +**Supprimez de votre copie les fichiers que vous ne personnalisez pas** pour +laisser les prochaines mises à jour du mod s'appliquer à ces ressources. +Pour repartir d'une base récente, renommez votre dossier personnel puis +cliquez de nouveau sur « Personnaliser Sanctuary » : l'ancien reste intact. +Le bouton devient « Ouvrir ma copie » tant que `Sanctuary-Custom` existe. +N'éditez pas directement le JAR du mod. + +Le pack modifie l'apparence, les modèles, les sons et les textes disponibles +dans `assets/` ; les règles de jeu, sauvegardes et recettes côté serveur restent +dans le mod. Les crédits figurent dans `THIRD_PARTY_NOTICES.md`. + +## English + +This is your editable copy. Sanctuary updates never overwrite it. Enable +**Sanctuary-Custom** in Options → Resource Packs and move it above Sanctuary +textures and any other pack you want to override. Edit files under `assets/` +without renaming their resource paths, then reload with F3 + T or toggle the +pack off and on. Disable this pack to return to Sanctuary's supplied appearance. + +The table above lists useful starting paths. Keep GUI atlas dimensions and +sprite layouts intact. You can add Minecraft overrides under `assets/minecraft/`; +this template does not include every vanilla asset or other mods' resources. + +This is a full snapshot of Sanctuary's assets when created. **Delete any files +you do not customize** so future mod updates can supply them. To start a fresh +copy later, rename your existing folder and click “Customize Sanctuary” again. +“Open my copy” opens the existing folder without changing it. Do not edit the +mod JAR. This pack changes client resources, not server gameplay or save data. diff --git a/ressources-pack/template/pack.mcmeta b/ressources-pack/template/pack.mcmeta new file mode 100644 index 0000000..42ce6dc --- /dev/null +++ b/ressources-pack/template/pack.mcmeta @@ -0,0 +1,10 @@ +{ + "pack": { + "description": { + "translate": "sanctuary.resource_pack.custom_description", + "fallback": "Sanctuary — your editable copy" + }, + "min_format": [97, 1], + "max_format": [97, 1] + } +}