diff --git a/.gitignore b/.gitignore index b63da45..36ad4c4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ build/ .idea/jarRepositories.xml .idea/compiler.xml .idea/libraries/ +.idea/workspace.xml *.iws *.iml *.ipr @@ -39,4 +40,4 @@ bin/ .vscode/ ### Mac OS ### -.DS_Store \ No newline at end of file +.DS_Store diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/ResourcePackManager.java b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/ResourcePackManager.java index 4a7e1be..5bec955 100644 --- a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/ResourcePackManager.java +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/ResourcePackManager.java @@ -7,6 +7,7 @@ import re.imc.geysermodelengineextension.GeyserModelEngineExtension; import re.imc.geysermodelengineextension.managers.resourcepack.generator.*; import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.TextureData; +import re.imc.geysermodelengineextension.util.ShortHashUtil; import re.imc.geysermodelengineextension.util.ZipUtil; import java.io.*; @@ -61,6 +62,8 @@ public void loadPack() { private void generateResourcePack(File inputFolder, File output) { generateFromFolder("", inputFolder, true); + boolean hashEnabled = extension.getConfigManager().getConfig().getBoolean("options.resource-pack.hash-models-textures", true); + File animationsFolder = new File(output, "animations"); File entityFolder = new File(output, "entity"); File modelsFolder = new File(output, "models/entity"); @@ -130,10 +133,9 @@ private void generateResourcePack(File inputFolder, File output) { } for (Map.Entry entry : geometryCache.entrySet()) { - entry.getValue().modify(); - Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".json"); + entry.getValue().modify(hashEnabled); + Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + (hashEnabled ? ShortHashUtil.hashModelId(entry.getKey()) : entry.getKey()) + ".json"); path.toFile().getParentFile().mkdirs(); - String id = entry.getValue().getGeometryId(); Entity entity = entityCache.get(entry.getKey()); if (entity != null) { @@ -146,9 +148,13 @@ private void generateResourcePack(File inputFolder, File output) { String suffix = size[0] + "_" + size[1]; entry.getValue().setTextureWidth(size[0]); entry.getValue().setTextureHeight(size[1]); - path = modelsFolder.toPath().resolve(entry.getKey() + "_" + suffix + ".json"); - - entry.getValue().setId(id + "_" + suffix); + if (hashEnabled) { + path = modelsFolder.toPath().resolve(ShortHashUtil.hashModelId(entry.getKey() + "_" + suffix) + ".json"); + entry.getValue().setId("geometry." + ShortHashUtil.hashModelId(entry.getKey() + "_" + suffix)); + } else { + path = modelsFolder.toPath().resolve(entry.getKey() + "_" + suffix + ".json"); + entry.getValue().setId("geometry.meg_" + entry.getKey() + "_" + suffix); + } if (path.toFile().exists()) continue; @@ -171,8 +177,10 @@ private void generateResourcePack(File inputFolder, File output) { } for (Map.Entry> textures : textureCache.entrySet()) { + String modelId = textures.getKey(); for (Map.Entry entry : textures.getValue().entrySet()) { - Path path = texturesFolder.toPath().resolve(entry.getKey() + ".png"); + String textureFileName = hashEnabled ? ShortHashUtil.hashTextureName(modelId, entry.getKey()) : entry.getKey(); + Path path = texturesFolder.toPath().resolve(textureFileName + ".png"); path.toFile().getParentFile().mkdirs(); if (path.toFile().exists()) continue; @@ -187,7 +195,7 @@ private void generateResourcePack(File inputFolder, File output) { for (Map.Entry entry : entityCache.entrySet()) { Entity entity = entry.getValue(); - entity.modify(extension.getConfigManager().getConfig().getString("models.namespace")); + entity.modify(extension.getConfigManager().getConfig().getString("models.namespace"), hashEnabled); Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".json"); entityPath.toFile().getParentFile().mkdirs(); @@ -210,7 +218,7 @@ private void generateResourcePack(File inputFolder, File output) { if (renderPath.toFile().exists()) continue; try { - Files.writeString(renderPath, controller.generate(extension.getConfigManager().getConfig().getString("models.namespace")), StandardCharsets.UTF_8); + Files.writeString(renderPath, controller.generate(extension.getConfigManager().getConfig().getString("models.namespace"), hashEnabled), StandardCharsets.UTF_8); } catch (IOException err) { throw new RuntimeException(err); } diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Entity.java b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Entity.java index cc0d2fc..e321c49 100644 --- a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Entity.java +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Entity.java @@ -5,6 +5,7 @@ import com.google.gson.JsonParser; import me.zimzaza4.geyserutils.geyser.GeyserUtils; import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.TextureData; +import re.imc.geysermodelengineextension.util.ShortHashUtil; import java.util.*; @@ -56,11 +57,15 @@ public Entity(String modelId) { this.modelId = modelId; } - public void modify(String namespace) { + public void modify(String namespace, boolean hashEnabled) { + String modelShortName = hashEnabled ? ShortHashUtil.hashModelId(modelId) : modelId; + String geometryId = hashEnabled ? "geometry." + modelShortName : "geometry.meg_" + modelShortName; + String defaultTexturePath = hashEnabled ? "textures/entity/" + ShortHashUtil.hashTextureName(modelId, modelId) : "textures/entity/" + modelId; + this.json = JsonParser.parseString(TEMPLATE.replace("%namespace%", namespace) .replace("%entity_id%", modelId) - .replace("%geometry%", "geometry.meg_" + modelId) - .replace("%texture%", "textures/entity/" + modelId) + .replace("%geometry%", geometryId) + .replace("%texture%", defaultTexturePath) .replace("%look_at_target%", modelConfig.isEnableHeadRotation() ? "animation." + modelId + ".look_at_target" : "animation.none") .replace("%material%", modelConfig.getMaterial())).getAsJsonObject(); @@ -76,8 +81,8 @@ public void modify(String namespace) { materials.forEach(jsonMaterials::addProperty); if (modelConfig.getPerTextureUvSize().isEmpty()) { - jsonGeometry.addProperty(modelId, "geometry.meg_" + modelId); - jsonTextures.addProperty("default", "textures/entity/" + modelId); + jsonGeometry.addProperty(modelShortName, geometryId); + jsonTextures.addProperty("default", defaultTexturePath); } for (String name : textureMap.keySet()) { @@ -87,8 +92,15 @@ public void modify(String namespace) { Integer[] size = modelConfig.getPerTextureUvSize().getOrDefault(name, new Integer[]{16, 16}); String suffix = size[0] + "_" + size[1]; - jsonGeometry.addProperty(modelId + "_" + suffix, "geometry.meg_" + modelId + "_" + suffix); - jsonTextures.addProperty(name, "textures/entity/" + name); + if (hashEnabled) { + String hashedGeoName = ShortHashUtil.hashModelId(modelId + "_" + suffix); + jsonGeometry.addProperty(hashedGeoName, "geometry." + hashedGeoName); + jsonTextures.addProperty(ShortHashUtil.hashTextureName(modelId, name), "textures/entity/" + ShortHashUtil.hashTextureName(modelId, name)); + } else { + String geoName = modelShortName + "_" + suffix; + jsonGeometry.addProperty(geoName, "geometry.meg_" + modelId + "_" + suffix); + jsonTextures.addProperty(name, "textures/entity/" + name); + } } diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Geometry.java b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Geometry.java index 26dff01..9b397db 100644 --- a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Geometry.java +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/Geometry.java @@ -3,6 +3,7 @@ import com.google.gson.*; import re.imc.geysermodelengineextension.GeyserModelEngineExtension; import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.BoneData; +import re.imc.geysermodelengineextension.util.ShortHashUtil; import java.util.*; @@ -36,7 +37,7 @@ public JsonObject getInternal() { return json.get("minecraft:geometry").getAsJsonArray().get(0).getAsJsonObject(); } - public void modify() { + public void modify(boolean hashEnabled) { JsonArray array = getInternal().get("bones").getAsJsonArray(); Iterator iterator = array.iterator(); while(iterator.hasNext()) { @@ -65,7 +66,11 @@ public void modify() { } } - setId("geometry.meg_" + modelId); + if (hashEnabled) { + setId("geometry." + ShortHashUtil.hashModelId(modelId)); + } else { + setId("geometry.meg_" + modelId); + } } private void addAllChildren(BoneData p, BoneData c) { diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/RenderController.java b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/RenderController.java index 8d7401d..f0b7b30 100644 --- a/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/RenderController.java +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/managers/resourcepack/generator/RenderController.java @@ -3,6 +3,7 @@ import com.google.gson.JsonArray; import com.google.gson.JsonObject; import re.imc.geysermodelengineextension.managers.resourcepack.generator.data.BoneData; +import re.imc.geysermodelengineextension.util.ShortHashUtil; import java.util.*; @@ -21,7 +22,7 @@ public RenderController(String modelId, Map bones, Entity enti } // look, I'm fine with your other code and stuff, but I ain't using templates for JSON lmao - public String generate(String namespace) { + public String generate(String namespace, boolean hashEnabled) { List se = new ArrayList<>(bones.keySet()); Collections.sort(se); JsonObject root = new JsonObject(); @@ -56,9 +57,17 @@ public String generate(String namespace) { if (!entity.getModelConfig().getPerTextureUvSize().isEmpty()) { Integer[] size = entity.getModelConfig().getPerTextureUvSize().getOrDefault(key, new Integer[]{16, 16}); String suffix = size[0] + "_" + size[1]; - controller.addProperty("geometry", "Geometry." + modelId + "_" + suffix); + if (hashEnabled) { + controller.addProperty("geometry", "Geometry." + ShortHashUtil.hashModelId(modelId + "_" + suffix)); + } else { + controller.addProperty("geometry", "Geometry." + modelId + "_" + suffix); + } } else { - controller.addProperty("geometry", "Geometry." + modelId); + if (hashEnabled) { + controller.addProperty("geometry", "Geometry." + ShortHashUtil.hashModelId(modelId)); + } else { + controller.addProperty("geometry", "Geometry." + modelId); + } } JsonArray materials = new JsonArray(); @@ -91,7 +100,7 @@ public String generate(String namespace) { if (singleTexture) { textures.add("Texture.default"); } else { - textures.add("Texture." + key); + textures.add("Texture." + (hashEnabled ? ShortHashUtil.hashTextureName(modelId, key) : key)); } controller.add("textures", textures); diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/util/FileConfiguration.java b/geyser/src/main/java/re/imc/geysermodelengineextension/util/FileConfiguration.java index 5bbb0d0..97de902 100644 --- a/geyser/src/main/java/re/imc/geysermodelengineextension/util/FileConfiguration.java +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/util/FileConfiguration.java @@ -115,6 +115,12 @@ public boolean getBoolean(String path) { return node.getBoolean(); } + public boolean getBoolean(String path, boolean def) { + CommentedConfigurationNode node = getInternal(path); + if (node == null) return def; + return node.getBoolean(); + } + public boolean isBoolean(String path) { CommentedConfigurationNode node = getInternal(path); return node != null && node.raw() instanceof Boolean; diff --git a/geyser/src/main/java/re/imc/geysermodelengineextension/util/ShortHashUtil.java b/geyser/src/main/java/re/imc/geysermodelengineextension/util/ShortHashUtil.java new file mode 100644 index 0000000..750b5cf --- /dev/null +++ b/geyser/src/main/java/re/imc/geysermodelengineextension/util/ShortHashUtil.java @@ -0,0 +1,47 @@ +package re.imc.geysermodelengineextension.util; + +import java.math.BigInteger; +import java.security.MessageDigest; + +public class ShortHashUtil { + private static final String CHARS = "0123456789abcdefghijklmnopqrstuvwxyz_"; + private static final int SUFFIX_LEN = 6; + private static final long RADIX = 37; + private static final long SUFFIX_SPACE = (long) Math.pow(RADIX, SUFFIX_LEN); + + public static String hashModelId(String modelId) { + return "gm_" + hash(modelId); + } + + public static String hashTextureName(String modelId, String textureName) { + return "gm_" + hash(modelId + textureName); + } + + public static String hash(String input) { + if (input == null) { + throw new IllegalArgumentException("Input cannot be null"); + } + try { + MessageDigest md = MessageDigest.getInstance("MD5"); + byte[] digest = md.digest(input.getBytes("UTF-8")); + + BigInteger num = new BigInteger(1, digest); + BigInteger totalSpace = BigInteger.valueOf(26).multiply(BigInteger.valueOf(SUFFIX_SPACE)); + BigInteger val = num.mod(totalSpace); + + BigInteger[] divAndRem = val.divideAndRemainder(BigInteger.valueOf(SUFFIX_SPACE)); + int firstIdx = divAndRem[0].intValue(); + long remainder = divAndRem[1].longValue(); + char[] suffix = new char[SUFFIX_LEN]; + for (int i = SUFFIX_LEN - 1; i >= 0; i--) { + suffix[i] = CHARS.charAt((int) (remainder % RADIX)); + remainder /= RADIX; + } + char firstChar = (char) ('a' + firstIdx); + return firstChar + new String(suffix); + } catch (Exception e) { + e.printStackTrace(); + } + return input; + } +} diff --git a/geyser/src/main/resources/Extension/config.yml b/geyser/src/main/resources/Extension/config.yml index 7842024..e60a5f6 100644 --- a/geyser/src/main/resources/Extension/config.yml +++ b/geyser/src/main/resources/Extension/config.yml @@ -5,4 +5,5 @@ options: debug: geometry-bones: false resource-pack: - auto-load: true \ No newline at end of file + auto-load: true + hash-models-textures: true \ No newline at end of file