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 de6818c..60519d0 100644 Binary files a/mods/sanctuary/src/main/resources/assets/sanctuary/textures/item/golden_wrench.png and b/mods/sanctuary/src/main/resources/assets/sanctuary/textures/item/golden_wrench.png differ diff --git a/mods/sanctuary/src/main/resources/sanctuary.mixins.json b/mods/sanctuary/src/main/resources/sanctuary.mixins.json index 1bb3500..1502a94 100644 --- a/mods/sanctuary/src/main/resources/sanctuary.mixins.json +++ b/mods/sanctuary/src/main/resources/sanctuary.mixins.json @@ -184,6 +184,7 @@ "NaturalSnowEditMixin" ], "client": [ + "client.PackSelectionScreenMixin", "client.FourneauFireMixin", "client.BoatPassengerPickMixin", "client.PreloadScreenMixin", diff --git a/packwiz/pack.toml b/packwiz/pack.toml index 4c83ffd..6da47ae 100644 --- a/packwiz/pack.toml +++ b/packwiz/pack.toml @@ -1,6 +1,6 @@ name = "Sanctuary" author = "KOKA99CAB" -version = "beta.120" +version = "beta.121" pack-format = "packwiz:1.1.0" [index] diff --git a/ressources-pack/README.md b/ressources-pack/README.md index 9be6670..4c36ad3 100644 --- a/ressources-pack/README.md +++ b/ressources-pack/README.md @@ -3,11 +3,18 @@ Sources des resource packs propres à Sanctuary. Le nom de ce dossier existant est conservé ; le dossier installé dans Minecraft s'appelle `resourcepacks/`. +Le bouton **Personnaliser Sanctuary**, dans Options → Packs de ressources, +crée maintenant une copie personnelle complète `resourcepacks/Sanctuary-Custom/`. +Elle réunit les assets du mod et ceux du pack intégré ; les mises à jour ne +l'écrasent jamais. Le [guide du template](template/README.md) détaille les chemins +à modifier. `./gradlew assembleResourceTemplate` produit le ZIP complet. +Voir le [ticket beta.121](../docs/resourcepack-template-beta121.md). + Les exports ZIP à la racine restent locaux et ignorés par Git. Les dossiers décompressés contiennent les sources versionnées. [`sanctuary/`](sanctuary/README.md) est la base modifiable pour Minecraft -26.3 : pack beta.090 versionné, embarqué et activé par défaut dans le mod. +26.3 : pack beta.121 versionné, embarqué et activé par défaut dans le mod. Il comprend les menus, 47 cœurs vanilla et les nouveaux dessins de faim et de saturation fournis par le créateur. Les manifests `sanctuary/releases/` fixent les empreintes de chaque révision. diff --git a/ressources-pack/sanctuary/README.md b/ressources-pack/sanctuary/README.md index a9a7ee6..036f259 100644 --- a/ressources-pack/sanctuary/README.md +++ b/ressources-pack/sanctuary/README.md @@ -5,7 +5,15 @@ Le manifeste déclare le format de ressources **97.1**, relevé dans le client exact utilisé par Sanctuary. Les menus, le panorama et les textures Sanctuary déjà présents sont conservés. -## Version beta.090 +## Version beta.121 + +La révision [beta.121](releases/beta.121.json) ajoute la clé dorée fournie par +le créateur, octet pour octet. Les autres textures et le format 97.1 restent +identiques. Le [template personnel](../template/README.md) exporte également +les ressources récentes du mod : blocs, items, modèles, sons et traductions. +Il se crée depuis l'écran des packs ou avec `assembleResourceTemplate`. + +## Version beta.090 (historique) La révision [beta.090](releases/beta.090.json) déclare Minecraft 26.3 finale, sans changer le format 97.1 ni les images. Le manifeste beta.070 et son @@ -26,7 +34,7 @@ bulles de respiration proviennent du jeu. La source unique est ce dossier. Gradle le copie dans le mod sous `resourcepacks/textures/` et produit le même contenu dans -`build/Sanctuary-Resource-Pack-beta.090.zip`. L’identifiant stable du pack +`build/Sanctuary-Resource-Pack-beta.121.zip`. L’identifiant stable du pack est `sanctuary:textures`. Son numéro graphique est indépendant des correctifs de code : `resource_pack_version` dans `gradle.properties` ne change qu’avec une nouvelle révision du pack. @@ -41,7 +49,7 @@ de `pack.mcmeta` et `resource_pack_version`. Ne pas réécrire un ancien manifes Le contrôle refuse un fichier ajouté, oublié ou modifié sans mise à jour de révision. Ne pas éditer les copies générées dans `build/`. -**English:** This source is the beta.090 built-in pack for Minecraft 26.3, enabled by default and +**English:** This source is the beta.121 built-in pack for Minecraft 26.3, enabled by default and still user-disableable. Incoming PNGs are preserved exactly. `releases/` tracks immutable file hashes; the mod and standalone ZIP consume this same source. Keep a new release manifest whenever changing the graphics. diff --git a/ressources-pack/sanctuary/assets/sanctuary/textures/item/golden_wrench.png b/ressources-pack/sanctuary/assets/sanctuary/textures/item/golden_wrench.png new file mode 100644 index 0000000..60519d0 Binary files /dev/null and b/ressources-pack/sanctuary/assets/sanctuary/textures/item/golden_wrench.png differ 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] + } +}