diff --git a/atlas/root/distribution.json b/atlas/root/distribution.json index ae4b38b..0076b5b 100644 --- a/atlas/root/distribution.json +++ b/atlas/root/distribution.json @@ -487,13 +487,13 @@ } }, { - "id": "fr.surviepote:nosingleplayer:1.1.9@jar", + "id": "fr.surviepote:nosingleplayer:1.2.0@jar", "name": "NoSingleplayer (SurviePote)", "type": "FabricMod", "artifact": { - "size": 3639116, - "url": "https://git.kisakay.com/k/mc/raw/branch/main/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.1.9.jar", - "MD5": "d9666a2698e9bcb3d69e03097dc081b4" + "size": 870981, + "url": "https://git.kisakay.com/k/mc/raw/branch/main/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.2.0.jar", + "MD5": "107e3b749568d916e556479efbbda3c6" }, "required": { "value": false @@ -615,16 +615,6 @@ "value": false } }, - { - "id": "generated.fabricmod:spatial:gui-1.8+26.3-fabric@jar", - "name": "Spatial", - "type": "FabricMod", - "artifact": { - "size": 276562, - "url": "https://git.kisakay.com/k/mc/raw/branch/main/atlas/root/servers/SurviePote-26.3/fabricmods/required/spatial-gui-1.8+26.3-fabric.jar", - "MD5": "80fcb9b1ed083b8515fa78e6a5cd86a4" - } - }, { "id": "com.jaquadro.minecraft:storagedrawers:26.3.0.1@jar", "name": "Storage Drawers", diff --git a/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.1.9.jar b/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.1.9.jar deleted file mode 100644 index 6c47547..0000000 Binary files a/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.1.9.jar and /dev/null differ diff --git a/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.2.0.jar b/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.2.0.jar new file mode 100644 index 0000000..9b8fd53 Binary files /dev/null and b/atlas/root/servers/SurviePote-26.3/fabricmods/optionalon/nosingleplayer-1.2.0.jar differ diff --git a/atlas/root/servers/SurviePote-26.3/fabricmods/required/spatial-gui-1.8+26.3-fabric.jar b/atlas/root/servers/SurviePote-26.3/fabricmods/required/spatial-gui-1.8+26.3-fabric.jar deleted file mode 100644 index 3569c4f..0000000 Binary files a/atlas/root/servers/SurviePote-26.3/fabricmods/required/spatial-gui-1.8+26.3-fabric.jar and /dev/null differ diff --git a/mods/nosingleplayer/gradle.properties b/mods/nosingleplayer/gradle.properties index 4a289e5..23fc081 100644 --- a/mods/nosingleplayer/gradle.properties +++ b/mods/nosingleplayer/gradle.properties @@ -5,7 +5,7 @@ loader_version=0.20.0 loom_version=1.19.1 # Mod Properties -mod_version=1.1.9 +mod_version=1.2.0 maven_group=fr.surviepote archives_base_name=nosingleplayer diff --git a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/ModTextures.java b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/ModTextures.java index 2df0ca7..2f1d032 100644 --- a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/ModTextures.java +++ b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/ModTextures.java @@ -1,69 +1,74 @@ package fr.surviepote.nosingleplayer; -import com.mojang.blaze3d.platform.NativeImage; -import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.renderpearl.api.textures.FilterMode; -import java.io.IOException; -import java.io.InputStream; import java.util.HashMap; import java.util.Map; import net.minecraft.client.Minecraft; -import net.minecraft.client.renderer.texture.DynamicTexture; +import net.minecraft.client.renderer.texture.TextureContents; import net.minecraft.resources.Identifier; /** - * Chargement des textures du mod. + * Enregistrement des textures du mod dans le TextureManager de MC. * - *
MC 26.3 n'expose plus les ressources des mods au ResourceManager : les packs ne - * sont lus que depuis des dossiers, pas depuis les jars du classpath. Une texture - * référencée par son Identifier est donc introuvable (placeholder magenta). On lit - * donc le PNG directement dans le jar du mod et on enregistre une DynamicTexture dans - * le TextureManager. + *
IMPORTANT : l'enregistrement doit être fait sur le thread de rendu mais
+ * en dehors de l'extraction du rendu (ex. dans {@code TitleScreen.init}).
+ * Créer une ressource GPU pendant l'enregistrement des commandes d'une frame
+ * invalide le frame entier sur les backends à command encoder (Vulkan/NVIDIA) :
+ * résultat, un menu titre entièrement noir. D'où le try/catch + le repli sur le
+ * panorama vanilla dans TitleScreenRenderMixin.
*/
public final class ModTextures {
- private static final Map MC 26.3 n'expose plus les ressources des mods au ResourceManager : les packs ne
+ * sont lus que depuis des dossiers, pas depuis les jars du classpath. Une texture
+ * référencée par son Identifier est donc introuvable (placeholder magenta). On lit
+ * donc le PNG directement dans le jar du mod et on l'enregistre via le mécanisme
+ * officiel {@link ReloadableTexture} : c'est MC qui crée la texture GPU ET le
+ * sampler, exactement comme pour ses propres textures. Aucun sampler custom, aucun
+ * upload manuel => compatible avec tous les backends (OpenGL, Vulkan) et tous les
+ * pilotes (Mesa, NVIDIA, AMD, Intel).
+ */
+public class SurviePoteTexture extends ReloadableTexture {
+
+ private final String resourcePath;
+ private final boolean blur;
+
+ private int width;
+ private int height;
+
+ public SurviePoteTexture(Identifier id, String resourcePath, boolean blur) {
+ super(id);
+ this.resourcePath = resourcePath;
+ this.blur = blur;
+ }
+
+ @Override
+ public TextureContents loadContents(ResourceManager resourceManager) throws IOException {
+ try (InputStream in = SurviePoteTexture.class.getResourceAsStream(this.resourcePath)) {
+ if (in == null) {
+ throw new IOException("Texture introuvable dans le jar : " + this.resourcePath);
+ }
+ NativeImage image = NativeImage.read(in);
+ this.width = image.getWidth();
+ this.height = image.getHeight();
+ // blur=true => filtrage linéaire (image agrandie/réduite),
+ // clamp=true => pas de répétition sur les bords.
+ return new TextureContents(image,
+ new TextureMetadataSection(this.blur, true, MipmapStrategy.AUTO, 0.0f));
+ }
+ }
+
+ public int getWidth() {
+ return this.width;
+ }
+
+ public int getHeight() {
+ return this.height;
+ }
+}
diff --git a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/DiscordButton.java b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/DiscordButton.java
index 9eea142..50a9da8 100644
--- a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/DiscordButton.java
+++ b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/DiscordButton.java
@@ -33,7 +33,7 @@ public class DiscordButton extends AbstractButton {
super(x, y, width, height, Component.literal(label));
this.action = action;
// La texture doit être enregistrée avant le premier rendu.
- ModTextures.get(TEXTURE, TEXTURE_PATH, "SurviePote Discord", false);
+ ModTextures.register(TEXTURE, TEXTURE_PATH, false);
}
@Override
diff --git a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/IconButton.java b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/IconButton.java
index 3c75882..abc2e5f 100644
--- a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/IconButton.java
+++ b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/gui/IconButton.java
@@ -30,7 +30,7 @@ public class IconButton extends AbstractButton {
this.texture = texture;
this.action = action;
// La texture doit être enregistrée avant le premier rendu.
- ModTextures.get(texture, resourcePath, message.getString(), false);
+ ModTextures.register(texture, resourcePath, false);
}
@Override
diff --git a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/mixin/TitleScreenRenderMixin.java b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/mixin/TitleScreenRenderMixin.java
index 67591ce..e8ec69e 100644
--- a/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/mixin/TitleScreenRenderMixin.java
+++ b/mods/nosingleplayer/src/main/java/fr/surviepote/nosingleplayer/mixin/TitleScreenRenderMixin.java
@@ -11,12 +11,13 @@ import net.minecraft.client.gui.components.LogoRenderer;
import net.minecraft.client.gui.components.SplashRenderer;
import net.minecraft.client.gui.screens.TitleScreen;
import net.minecraft.client.renderer.RenderPipelines;
-import net.minecraft.client.renderer.texture.DynamicTexture;
import net.minecraft.resources.Identifier;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(TitleScreen.class)
public abstract class TitleScreenRenderMixin {
@@ -25,7 +26,7 @@ public abstract class TitleScreenRenderMixin {
private static final Identifier SURVIEPOTE_BACKGROUND = Identifier.fromNamespaceAndPath(
"nosingleplayer", "textures/gui/background.png");
- // Le PNG est lu directement dans le jar du mod (voir surviepote$loadBackground).
+ // Le PNG est lu directement dans le jar du mod (voir ModTextures).
@Unique
private static final String SURVIEPOTE_BACKGROUND_RESOURCE =
"/assets/nosingleplayer/textures/gui/background.png";
@@ -39,22 +40,26 @@ public abstract class TitleScreenRenderMixin {
@Unique
private static final String DISABLE_CUSTOM_TITLE_PROPERTY = "surviepote.customTitle";
- @Unique
- private static DynamicTexture surviepote$background;
-
- @Unique
- private static int surviepote$backgroundWidth;
-
- @Unique
- private static int surviepote$backgroundHeight;
-
- // Le fond custom a déjà échoué : on ne réessaie plus (le menu reste noir sinon).
- @Unique
- private static boolean surviepote$backgroundFailed;
-
@Unique
private static boolean surviepote$gpuLogged;
+ /**
+ * Enregistre le fond custom AVANT le premier rendu du menu.
+ *
+ * La texture GPU doit être créée hors de l'extraction du rendu : la créer
+ * pendant l'enregistrement des commandes de la frame invalide le frame entier
+ * sur les backends à command encoder (Vulkan) => menu titre entièrement noir
+ * (le PC affected est sous Windows + NVIDIA, qui utilise le backend Vulkan).
+ */
+ @Inject(method = "init", at = @At("HEAD"))
+ private void surviepote$registerBackground(CallbackInfo ci) {
+ try {
+ ModTextures.register(SURVIEPOTE_BACKGROUND, SURVIEPOTE_BACKGROUND_RESOURCE, true);
+ } catch (Throwable t) {
+ NoSingleplayer.LOGGER.error("[SurviePote] Enregistrement du fond custom impossible.", t);
+ }
+ }
+
// Pas de panorama dynamique : fond statique custom à la place.
// Note : extractPanorama est déclarée dans Screen (héritée), on redirige donc
// l'APPEL dans TitleScreen plutôt que la méthode elle-même.
@@ -68,11 +73,11 @@ public abstract class TitleScreenRenderMixin {
// écran 100 % noir (sans boutons). D'où les garde-fous ci-dessous.
surviepote$logGpuOnce();
- // Menu vanilla si le fond custom a déjà échoué, ou si l'utilisateur a forcé
- // -Dsurviepote.customTitle=false (option de diagnostic).
+ // Menu vanilla si l'utilisateur a forcé -Dsurviepote.customTitle=false,
+ // ou si le fond custom n'est pas (ou plus) enregistré.
final boolean customEnabled = !"false".equalsIgnoreCase(
System.getProperty(DISABLE_CUSTOM_TITLE_PROPERTY, "true"));
- if (surviepote$backgroundFailed || !customEnabled) {
+ if (!customEnabled || !ModTextures.isRegistered(SURVIEPOTE_BACKGROUND)) {
surviepote$vanillaPanorama(self, extractor, partialTick);
return;
}
@@ -80,41 +85,39 @@ public abstract class TitleScreenRenderMixin {
try {
int w = Minecraft.getInstance().getWindow().getGuiScaledWidth();
int h = Minecraft.getInstance().getWindow().getGuiScaledHeight();
-
- surviepote$loadBackground();
- if (surviepote$background == null) {
+ int texW = ModTextures.getWidth(SURVIEPOTE_BACKGROUND);
+ int texH = ModTextures.getHeight(SURVIEPOTE_BACKGROUND);
+ if (texW <= 0 || texH <= 0 || w <= 0 || h <= 0) {
surviepote$vanillaPanorama(self, extractor, partialTick);
return;
}
float screenAspect = (float) w / (float) h;
- float texAspect = (float) surviepote$backgroundWidth / (float) surviepote$backgroundHeight;
+ float texAspect = (float) texW / (float) texH;
int u, v, srcW, srcH;
if (screenAspect > texAspect) {
// Écran plus large que l'image : on rogne en haut/bas.
- srcW = surviepote$backgroundWidth;
- srcH = Math.round(surviepote$backgroundWidth / screenAspect);
+ srcW = texW;
+ srcH = Math.round(texW / screenAspect);
u = 0;
- v = (surviepote$backgroundHeight - srcH) / 2;
+ v = (texH - srcH) / 2;
} else {
// Écran plus haut que l'image : on rogne à gauche/droite.
- srcH = surviepote$backgroundHeight;
- srcW = Math.round(surviepote$backgroundHeight * screenAspect);
- u = (surviepote$backgroundWidth - srcW) / 2;
+ srcH = texH;
+ srcW = Math.round(texH * screenAspect);
+ u = (texW - srcW) / 2;
v = 0;
}
// Surcharge complète : (u, v) = origine dans la texture, (w, h) = taille à
// l'écran, (srcW, srcH) = taille de la région source dans la texture.
- // L'overload court réutilise w/h comme région source (=> zoom sur un coin).
extractor.blit(RenderPipelines.GUI_TEXTURED, SURVIEPOTE_BACKGROUND,
0, 0, (float) u, (float) v,
w, h, srcW, srcH,
- surviepote$backgroundWidth, surviepote$backgroundHeight, -1);
+ texW, texH, -1);
} catch (Throwable t) {
// Repli : on bascule sur le panorama vanilla pour ne pas laisser un écran noir.
- surviepote$backgroundFailed = true;
NoSingleplayer.LOGGER.error("[SurviePote] Échec du fond custom, repli sur le panorama vanilla.", t);
surviepote$vanillaPanorama(self, extractor, partialTick);
}
@@ -149,29 +152,6 @@ public abstract class TitleScreenRenderMixin {
}
}
- /**
- * MC 26.3 n'expose plus les ressources des mods au ResourceManager : les packs
- * ne sont lus que depuis des dossiers, pas depuis les jars du classpath. Une
- * texture référencée par son Identifier est donc introuvable (placeholder
- * magenta). Le PNG est donc lu dans le jar du mod (voir ModTextures).
- */
- @Unique
- private static void surviepote$loadBackground() {
- DynamicTexture texture = ModTextures.get(SURVIEPOTE_BACKGROUND, SURVIEPOTE_BACKGROUND_RESOURCE,
- "SurviePote Background", true);
- if (texture == null) {
- surviepote$background = null;
- return;
- }
- if (surviepote$background != texture) {
- surviepote$background = texture;
- surviepote$backgroundWidth = texture.getPixels().getWidth();
- surviepote$backgroundHeight = texture.getPixels().getHeight();
- NoSingleplayer.LOGGER.info("[SurviePote] Fond chargé : {}x{}",
- surviepote$backgroundWidth, surviepote$backgroundHeight);
- }
- }
-
// Pas de texte de version ("26.3 mc") en bas à gauche.
@Redirect(method = "extractRenderState",
at = @At(value = "INVOKE",
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_0.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_0.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_0.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_1.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_1.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_1.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_2.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_2.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_2.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_3.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_3.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_3.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_4.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_4.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_4.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_5.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_5.png
deleted file mode 100644
index 95b6b72..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_5.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_overlay.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_overlay.png
deleted file mode 100644
index 80ded22..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/background/panorama_overlay.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/minecraft.png b/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/minecraft.png
deleted file mode 100644
index 80ded22..0000000
Binary files a/mods/nosingleplayer/src/main/resources/assets/minecraft/textures/gui/title/minecraft.png and /dev/null differ
diff --git a/mods/nosingleplayer/src/main/resources/assets/nosingleplayer/textures/gui/background.png b/mods/nosingleplayer/src/main/resources/assets/nosingleplayer/textures/gui/background.png
index 1c6a65e..045d27f 100644
Binary files a/mods/nosingleplayer/src/main/resources/assets/nosingleplayer/textures/gui/background.png and b/mods/nosingleplayer/src/main/resources/assets/nosingleplayer/textures/gui/background.png differ
diff --git a/server/mods/SOURCE.md b/server/mods/SOURCE.md
index ba9e723..5d67214 100644
--- a/server/mods/SOURCE.md
+++ b/server/mods/SOURCE.md
@@ -63,8 +63,7 @@ Tri effectué par inspection réelle de `fabric.mod.json` (`environment` + `entr
| Mod | raison |
| --- | --- |
-| spatial-gui-1.8+26.3-fabric.jar | `environment: client` (lib GUI, dépend de yet_another_config_lib_v3) |
-| yet_another_config_lib_v3-3.9.7+26.3-fabric.jar | entrypoint `client` uniquement (lib de config) |
+| yet_another_config_lib_v3-3.9.7+26.3-fabric.jar | entrypoint `client` uniquement (lib de config ; utilisée par le bridge YACL de PatPat, avec fallback cloth-config) |
## Exclus (15) — client-only, NE PAS copier sur le serveur
@@ -94,3 +93,9 @@ Notes :
`atlas/.../fabricmods/required/` clients, et config `config/immersiveores/`). Voir `quarantine/README.md`.
- `simplebackpacks-fabric-26.3-5.2.1.jar` : datapack cassé (recipes/advancements) → `Failed to load
registries` → crash serveur ET client. Voir `quarantine/README.md`. Retiré partout.
+- `spatial-gui-1.8+26.3-fabric.jar` : `environment: client` — GUI d'inventaire en plan 3D, retirée
+ du pack le 20/10/2026 (guère aesthetic + instabilité). Retiré de `atlas/.../fabricmods/required/`
+ (clients) et de `distribution.json`. `yet_another_config_lib_v3` est conservée (bridge YACL de
+ PatPat, fallback `cloth-config` sinon). À retirer aussi de Prism
+ (`~/.local/share/PrismLauncher/instances/26.3/minecraft/mods/`) et de l'instance Helios locale
+ (`~/.surviepote/common/mods/.../spatial/` + `config/spatial-gui.json5`).
diff --git a/sync-mods.sh b/sync-mods.sh
index d54d201..1702e04 100755
--- a/sync-mods.sh
+++ b/sync-mods.sh
@@ -16,10 +16,11 @@ SERVER_EXCLUDE=(
)
# Mods à exclure de l'ATLAS (= clients) : client-only purs + mods cassés
# (simplebackpacks, ImmersiveOres — voir quarantine/README.md).
+# spatial-gui : retiré du pack le 20/10/2026 (GUI 3D disgracieuse) — voir server/mods/SOURCE.md.
ATLAS_EXCLUDE=(
sodium-fabric iris-fabric continuity- dynamic-fps- fast-ip-ping modmenu- morechathistory-
capes- chat_heads- skinlayers3d waveycapes xaerominimap xaeroworldmap
- appleskin- vanillarice- simplebackpacks- ImmersiveOres-26.3
+ appleskin- vanillarice- simplebackpacks- ImmersiveOres-26.3 spatial-gui-
)
excluded() { local f="$1"; shift; for p in "$@"; do [[ "$f" == "$p"* ]] && return 0; done; return 1; }
@@ -46,6 +47,8 @@ done
# Nettoyage : simplebackpacks et ImmersiveOres ne doivent être ni serveur ni atlas
rm -f "$SRV_MODS"/simplebackpacks-*.jar "$ATLAS_MODS"/simplebackpacks-*.jar
rm -f "$SRV_MODS"/ImmersiveOres-*.jar "$ATLAS_MODS"/ImmersiveOres-*.jar server/mods-client-only/ImmersiveOres-*.jar
+# spatial-gui : retiré du pack le 20/10/2026 (client-only, jamais sur le serveur).
+rm -f "$SRV_MODS"/spatial-gui-*.jar "$ATLAS_MODS"/spatial-gui-*.jar
[ -f quarantine/simplebackpacks-fabric-26.3-5.2.1.jar ] || echo "NOTE: simplebackpacks en quarantaine (voir quarantine/README.md)"
echo "== resourcepack/shader (Prism -> atlas files/) =="