diff --git a/pom.xml b/pom.xml index dcd0771..b5a01fe 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,10 @@ true + + jitpack.io + https://jitpack.io + @@ -62,5 +66,20 @@ system ${project.basedir}/libs/geyserutils-geyser-1.0-SNAPSHOT.jar + + me.rochblondiaux + blockbenchmodelreader + 1.2 + + + com.github.GeyserMC.PackConverter + bedrock-pack-schema + 3d8150474d + + + com.github.GeyserMC.PackConverter + pack-schema-api + 3d8150474d + \ No newline at end of file diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/GeneratorMain.java b/src/main/java/re/imc/geysermodelenginepackgenerator/GeneratorMain.java index 881a388..3ab4e8f 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/GeneratorMain.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/GeneratorMain.java @@ -5,22 +5,21 @@ import com.google.gson.GsonBuilder; import com.google.gson.JsonParser; import re.imc.geysermodelenginepackgenerator.generator.*; +import javax.imageio.ImageIO; import java.io.File; import java.io.FileReader; -import java.io.FileWriter; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; -import java.util.HashMap; -import java.util.Map; +import java.util.*; public class GeneratorMain { public static final Map entityMap = new HashMap<>(); - public static final Map animationMap = new HashMap<>(); - public static final Map geometryMap = new HashMap<>(); - public static final Map textureMap = new HashMap<>(); + public static final Map animationMap = new HashMap<>(); + public static final Map geometryMap = new HashMap<>(); + public static final Map> textureMap = new HashMap<>(); public static final Gson GSON = new GsonBuilder().setPrettyPrinting() .create(); @@ -40,13 +39,36 @@ public class GeneratorMain { String modelId = folder.getName().toLowerCase(); Entity entity = new Entity(modelId); + ModelConfig modelConfig = new ModelConfig(); + boolean shouldOverrideConfig = false; + File textureConfigFile = new File(folder, "config.json"); + if (textureConfigFile.exists()) { + try { + modelConfig = GSON.fromJson(Files.readString(textureConfigFile.toPath()), ModelConfig.class); + } catch (IOException e) { + e.printStackTrace(); + } + } boolean canAdd = false; for (File e : folder.listFiles()) { if (e.isDirectory()) { generateFromFolder(currentPath + folder.getName() + "/", e); } if (e.getName().endsWith(".png")) { - textureMap.put(modelId, new Texture(modelId, currentPath, e.toPath())); + String textureName = e.getName().replace(".png", ""); + Set bindingBones = new HashSet<>(); + bindingBones.add("*"); + if (modelConfig.getBingingBones().containsKey(textureName)) { + bindingBones = modelConfig.getBingingBones().get(textureName); + } + Map map = textureMap.computeIfAbsent(modelId, s -> new HashMap<>()); + map.put(textureName, new Texture(modelId, currentPath, bindingBones, e.toPath())); + entity.setTextureMap(map); + if (modelConfig.getBingingBones().isEmpty()) { + modelConfig.getBingingBones().put(textureName, Set.of("*")); + shouldOverrideConfig = true; + } + } if (e.getName().endsWith(".json")) { try { @@ -76,19 +98,30 @@ public class GeneratorMain { } } if (canAdd) { - File config = new File(folder, "config.properties"); + // old config + File oldConfig = new File(folder, "config.properties"); + Properties old = new Properties(); try { - if (config.exists()) { - entity.getConfig().load(new FileReader(config)); - } else { - entity.getConfig().setProperty("head-rotation", "true"); - entity.getConfig().setProperty("material", "entity_alphatest_change_color"); - entity.getConfig().setProperty("blend-transition", "true"); - entity.getConfig().store(new FileWriter(config), ""); + if (oldConfig.exists()) { + old.load(new FileReader(oldConfig)); + modelConfig.setMaterial(old.getProperty("material", "entity_alphatest_change_color")); + modelConfig.setEnableBlendTransition(Boolean.parseBoolean(old.getProperty("blend-transition", "true"))); + modelConfig.setEnableHeadRotation(Boolean.parseBoolean(old.getProperty("head-rotation", "true"))); + shouldOverrideConfig = true; + oldConfig.delete(); } + } catch (IOException ex) { ex.printStackTrace(); } + if (shouldOverrideConfig) { + try { + Files.writeString(textureConfigFile.toPath(), GSON.toJson(modelConfig)); + } catch (IOException ex) { + ex.printStackTrace(); + } + } + entity.setModelConfig(modelConfig); entity.setPath(currentPath); entityMap.put(modelId, entity); } @@ -136,6 +169,15 @@ public class GeneratorMain { materialsFolder.mkdirs(); File materialFile = new File(materialsFolder, "entity.material"); + + if (!materialFile.exists()) { + try { + Files.writeString(materialFile.toPath(), + Material.TEMPLATE, StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + } for (Map.Entry entry : animationMap.entrySet()) { Entity entity = entityMap.get(entry.getKey()); @@ -168,34 +210,67 @@ public class GeneratorMain { entry.getValue().modify(); Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".geo.json"); path.toFile().getParentFile().mkdirs(); + String id = entry.getValue().getGeometryId(); + + Entity entity = entityMap.get(entry.getKey()); + if (entity != null) { + ModelConfig modelConfig = entity.getModelConfig(); + if (!modelConfig.getPerTextureUvSize().isEmpty()) { + for (Map.Entry textureEntry : entity.getTextureMap().entrySet()) { + String name = textureEntry.getKey(); + + Integer[] size = modelConfig.getPerTextureUvSize().getOrDefault(name, new Integer[]{16, 16}); + String suffix = size[0] + "_" + size[1]; + entry.getValue().setTextureWidth(size[0]); + entry.getValue().setTextureHeight(size[1]); + path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + "_" + suffix + ".geo.json"); + + entry.getValue().setId(id + "_" + suffix); + + if (path.toFile().exists()) { + continue; + } + + try { + Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + } if (path.toFile().exists()) { continue; } + try { - Files.writeString(path, entry.getValue().getJson().toString(), StandardCharsets.UTF_8); + Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8); } catch (IOException e) { e.printStackTrace(); } } - for (Map.Entry entry : textureMap.entrySet()) { - Path path = texturesFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".png"); - path.toFile().getParentFile().mkdirs(); + for (Map.Entry> textures : textureMap.entrySet()) { - if (path.toFile().exists()) { - continue; - } - try { - Files.copy(entry.getValue().getOriginalPath(), path, StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - e.printStackTrace(); + for (Map.Entry entry : textures.getValue().entrySet()) { + Path path = texturesFolder.toPath().resolve(entry.getValue().getPath() + textures.getKey() + "/" + entry.getKey() + ".png"); + path.toFile().getParentFile().mkdirs(); + + if (path.toFile().exists()) { + continue; + } + try { + Files.copy(entry.getValue().getOriginalPath(), path, StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { + e.printStackTrace(); + } } } for (Map.Entry entry : entityMap.entrySet()) { Entity entity = entry.getValue(); - entity.getConfig().setProperty("render_controller", "controller.render." + entry.getKey()); entity.modify(); Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json"); @@ -213,7 +288,7 @@ public class GeneratorMain { String id = entity.getModelId(); if (!geometryMap.containsKey(id)) continue; - RenderController controller = new RenderController(id, geometryMap.get(id).getBones()); + RenderController controller = new RenderController(id, geometryMap.get(id).getBones(), entity); entity.setRenderController(controller); Path renderPath = new File(renderControllersFolder, "controller.render." + id + ".json").toPath(); if (renderPath.toFile().exists()) { diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/AnimationController.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/AnimationController.java index b307016..8daff0e 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/AnimationController.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/AnimationController.java @@ -57,7 +57,7 @@ public class AnimationController { animationControllers.add("controller.animation." + animation.modelId + "." + id, controller); i++; if (entity != null) { - boolean blend = Boolean.parseBoolean(entity.getConfig().getProperty("blend-transition", "true")); + boolean blend = entity.getModelConfig().isEnableBlendTransition(); if (!blend) { for (Map.Entry states : controller.get("states").getAsJsonObject().entrySet()) { states.getValue().getAsJsonObject().remove("blend_transition"); diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Bone.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Bone.java new file mode 100644 index 0000000..c31535d --- /dev/null +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Bone.java @@ -0,0 +1,23 @@ +package re.imc.geysermodelenginepackgenerator.generator; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.jetbrains.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class Bone { + String name; + String parent; + Set children = new HashSet<>(); + Set allChildren = new HashSet<>(); +} diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Entity.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Entity.java index d195564..050b45a 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Entity.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Entity.java @@ -8,11 +8,8 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import me.zimzaza4.geyserutils.geyser.GeyserUtils; -import re.imc.geysermodelenginepackgenerator.GeneratorMain; -import java.util.HashSet; -import java.util.Properties; -import java.util.Set; +import java.util.*; @Getter @Setter @@ -26,13 +23,13 @@ public class Entity { "description": { "identifier": "modelengine:%entity_id%", "materials": { - "default": "%material%" + "default": "%material%", + "anim": "entity_alphatest_anim_change_color_one_sided" }, "textures": { - "default": "%texture%" }, "geometry": { - "default": "%geometry%" + }, "animations": { "look_at_target": "%look_at_target%" @@ -43,7 +40,6 @@ public class Entity { ] }, "render_controllers": [ - "%render_controller%" ] } } @@ -54,21 +50,14 @@ public class Entity { String modelId; JsonObject json; boolean hasHeadAnimation = false; - @Setter - @Getter Animation animation; - - @Setter - @Getter Geometry geometry; - - @Setter - @Getter RenderController renderController; - String path; + Map textureMap = new HashMap<>(); + ModelConfig modelConfig; + - Properties config = new Properties(); @@ -79,14 +68,40 @@ public class Entity { public void modify() { json = new JsonParser().parse(TEMPLATE.replace("%entity_id%", modelId) - .replace("%geometry%", "geometry.modelengine_" + modelId) + .replace("%geometry%", "geometry.meg_" + modelId) .replace("%texture%", "textures/entity/" + path + modelId) - .replace("%look_at_target%", Boolean.parseBoolean(config.getProperty("head-rotation", "true".toLowerCase())) ? "animation." + modelId + ".look_at_target" : "animation.none") - .replace("%material%", config.getProperty("material", "entity_alphatest_change_color")) - .replace("%render_controller%", config.getProperty("render_controller", "controller.render.default"))).getAsJsonObject(); + .replace("%look_at_target%", modelConfig.isEnableHeadRotation() ? "animation." + modelId + ".look_at_target" : "animation.none") + .replace("%material%", modelConfig.getMaterial())).getAsJsonObject(); JsonObject description = json.get("minecraft:client_entity").getAsJsonObject().get("description").getAsJsonObject(); JsonObject jsonAnimations = description.get("animations").getAsJsonObject(); + JsonObject jsonTextures = description.get("textures").getAsJsonObject(); + JsonObject jsonGeometry = description.get("geometry").getAsJsonObject(); + JsonObject jsonMaterials = description.get("materials").getAsJsonObject(); + + JsonArray jsonRenderControllers = description.get("render_controllers").getAsJsonArray(); + + Map materials = getModelConfig().getTextureMaterials(); + materials.forEach(jsonMaterials::addProperty); + + if (modelConfig.getPerTextureUvSize().isEmpty()) { + jsonGeometry.addProperty("default", "geometry.meg_" + modelId); + jsonTextures.addProperty("default", "textures/entity/" + path + modelId + "/" + textureMap.keySet().stream().findFirst().orElse("def")); + } + + for (String name : textureMap.keySet()) { + if (modelConfig.getPerTextureUvSize().containsKey(name)) { + Integer[] size = modelConfig.getPerTextureUvSize().getOrDefault(name, new Integer[]{16, 16}); + String suffix = size[0] + "_" + size[1]; + + jsonGeometry.addProperty("t_" + suffix, "geometry.meg_" + modelId + "_" + suffix); + jsonTextures.addProperty(name, "textures/entity/" + path + modelId + "/" + name); + + } + jsonRenderControllers.add("controller.render." + modelId + "_" + name); + + } + JsonArray animate = description.get("scripts").getAsJsonObject().get("animate").getAsJsonArray(); if (animation != null) { @@ -106,8 +121,10 @@ public class Entity { if (geometry == null) { return; } - for (int i = 0; i < Math.ceil(geometry.getBones().size() / 24f); i++) { - GeyserUtils.addProperty(id, "modelengine:bone" + i, Integer.class); + if (!modelConfig.isDisablePartVisibility()) { + for (int i = 0; i < Math.ceil(geometry.getBones().size() / 24f); i++) { + GeyserUtils.addProperty(id, "modelengine:bone" + i, Integer.class); + } } if (animation != null) { diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Geometry.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Geometry.java index b00bcf3..c7fd0a0 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Geometry.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Geometry.java @@ -5,6 +5,8 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; +import org.geysermc.geyser.api.extension.ExtensionLogger; +import re.imc.geysermodelenginepackgenerator.ExtensionMain; import java.util.*; @@ -16,17 +18,27 @@ public class Geometry { String modelId; + String geometryId; JsonObject json; - Set bones = new HashSet<>(); + Map bones = new HashMap<>(); String path; public void load(String json) { this.json = new JsonParser().parse(json).getAsJsonObject(); } public void setId(String id) { + geometryId = id; getInternal().get("description").getAsJsonObject().addProperty("identifier", id); } + public void setTextureWidth(int w) { + getInternal().get("description").getAsJsonObject().addProperty("texture_width", w); + } + + public void setTextureHeight(int h) { + getInternal().get("description").getAsJsonObject().addProperty("texture_height", h); + } + public JsonObject getInternal() { return json.get("minecraft:geometry").getAsJsonArray().get(0) .getAsJsonObject(); @@ -41,6 +53,7 @@ public class Geometry { if (element.isJsonObject()) { String name = element.getAsJsonObject().get("name").getAsString().toLowerCase(Locale.ROOT); + String parent = element.getAsJsonObject().has("parent") ? element.getAsJsonObject().get("parent").getAsString().toLowerCase() : null; element.getAsJsonObject().remove("name"); element.getAsJsonObject().addProperty("name", name); @@ -51,10 +64,27 @@ public class Geometry { name.startsWith("b_") || name.startsWith("ob_")) { iterator.remove(); - } else bones.add(name); + } else bones.put(name, new Bone(name, parent, new HashSet<>(), new HashSet<>())); + } + + for (Bone bone : bones.values()) { + if (bone.parent != null) { + Bone parent = bones.get(bone.parent); + if (parent != null) { + parent.children.add(bone); + addAllChildren(parent, bone); + } + } } } - setId("geometry.modelengine_" + modelId); + setId("geometry.meg_" + modelId); } + public void addAllChildren(Bone p, Bone c) { + p.allChildren.add(c); + Bone parent = bones.get(p.parent); + if (parent != null) { + addAllChildren(parent, c); + } + } } diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Material.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Material.java new file mode 100644 index 0000000..04df3ba --- /dev/null +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Material.java @@ -0,0 +1,39 @@ +package re.imc.geysermodelenginepackgenerator.generator; + +public class Material { + public static final String TEMPLATE = """ + { + "materials":{ + "version":"1.0.0", + "entity_alphatest_anim_change_color:entity_alphatest_change_color":{ + "+defines":[ + "USE_UV_ANIM" + ] + }, + "entity_change_color_one_sided:entity": { + "+defines": [ + "USE_OVERLAY", + "USE_COLOR_MASK" + ] + }, + "entity_alphatest_change_color_one_sided:entity_change_color_one_sided": { + "+defines": [ "ALPHA_TEST" ], + "+samplerStates": [ + { + "samplerIndex": 1, + "textureWrap": "Repeat" + } + ], + "msaaSupport": "Both" + }, + + "entity_alphatest_anim_change_color_one_sided:entity_alphatest_change_color_one_sided":{ + "+defines":[ + "USE_UV_ANIM" + ] + } + } + } + """; + +} diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/ModelConfig.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/ModelConfig.java new file mode 100644 index 0000000..fd4dace --- /dev/null +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/ModelConfig.java @@ -0,0 +1,52 @@ +package re.imc.geysermodelenginepackgenerator.generator; + +import com.google.gson.annotations.SerializedName; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class ModelConfig { + + @SerializedName("head_rotation") + boolean enableHeadRotation = true; + @SerializedName("material") + String material = "entity_alphatest_change_color_one_sided"; + @SerializedName("blend_transition") + boolean enableBlendTransition = true; + @SerializedName("binding_bones") + Map> bingingBones = new HashMap<>(); + @SerializedName("anim_textures") + Map animTextures = new HashMap<>(); + @SerializedName("texture_materials") + Map textureMaterials = new HashMap<>(); + @SerializedName("per_texture_uv_size") + Map perTextureUvSize; + @SerializedName("disable_part_visibility") + boolean disablePartVisibility; + + public Map getTextureMaterials() { + return textureMaterials != null ? textureMaterials : Map.of(); + } + + public Map getPerTextureUvSize() { + return perTextureUvSize != null ? perTextureUvSize : Map.of(); + } + + @NoArgsConstructor + @AllArgsConstructor + @Getter + @Setter + public static class AnimTextureOptions { + float fps; + int frames; + } +} diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/RenderController.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/RenderController.java index 0f7ecab..8077b78 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/RenderController.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/RenderController.java @@ -2,7 +2,6 @@ package re.imc.geysermodelenginepackgenerator.generator; import com.google.gson.JsonArray; import com.google.gson.JsonObject; -import re.imc.geysermodelenginepackgenerator.GeneratorMain; import java.util.*; @@ -10,11 +9,13 @@ public class RenderController { public static final Set NEED_REMOVE_WHEN_SORT = Set.of("pbody_", "plarm_", "prarm_", "plleg_", "prleg_", "phead_", "p_"); String modelId; - Set bones; + Map bones; + Entity entity; - public RenderController(String modelId, Set bones) { + public RenderController(String modelId, Map bones, Entity entity) { this.modelId = modelId; this.bones = bones; + this.entity = entity; } // look, I'm fine with your other code and stuff, but I ain't using templates for JSON lmao @@ -25,53 +26,137 @@ public class RenderController { JsonObject renderControllers = new JsonObject(); root.add("render_controllers", renderControllers); - JsonObject controller = new JsonObject(); - renderControllers.add("controller.render." + modelId, controller); + Set processedBones = new HashSet<>(); + boolean singleTexture = entity.textureMap.size() == 1 && entity.modelConfig.getPerTextureUvSize().isEmpty(); + for (String key : entity.textureMap.keySet()) { - controller.addProperty("geometry", "Geometry.default"); + // Texture texture = entity.textureMap.get(key); + Set uvBonesId = entity.getModelConfig().bingingBones.get(key); - JsonArray materials = new JsonArray(); - JsonObject materialItem = new JsonObject(); - materialItem.addProperty("*", "Material.default"); - materials.add(materialItem); - controller.add("materials", materials); - - JsonArray textures = new JsonArray(); - textures.add("Texture.default"); - controller.add("textures", textures); - Entity entity = GeneratorMain.entityMap - .get(modelId); - // boolean enable = Boolean.parseBoolean(entity.getConfig().getProperty("enable-part-visibility", "true")); - - // if (enable) { - JsonArray partVisibility = new JsonArray(); - JsonObject visibilityDefault = new JsonObject(); - visibilityDefault.addProperty("*", true); - partVisibility.add(visibilityDefault); - int i = 0; - List sorted = new ArrayList<>(bones); - Map originalId = new HashMap<>(); - ListIterator iterator = sorted.listIterator(); - while (iterator.hasNext()) { - String s = iterator.next(); - String o = s; - for (String r : NEED_REMOVE_WHEN_SORT) { - s = s.replace(r, ""); + if (uvBonesId == null) { + if (!singleTexture) { + continue; + } else { + uvBonesId = new HashSet<>(); + uvBonesId.add("*"); + } } - iterator.set(s); - originalId.put(s, o); + ModelConfig.AnimTextureOptions anim = entity.getModelConfig().getAnimTextures().get(key); + + JsonObject controller = new JsonObject(); + + renderControllers.add("controller.render." + modelId + "_" + key, controller); + + if (!entity.getModelConfig().getPerTextureUvSize().isEmpty()) { + Integer[] size = entity.getModelConfig().getPerTextureUvSize().getOrDefault(key, new Integer[]{16, 16}); + String suffix = "t_" + size[0] + "_" + size[1]; + controller.addProperty("geometry", "Geometry." + suffix); + } else { + controller.addProperty("geometry", "Geometry.default"); + } + JsonArray materials = new JsonArray(); + String material = entity.getModelConfig().getTextureMaterials().get(key); + + + JsonObject materialItem = new JsonObject(); + if (material != null) { + materialItem.addProperty("*", "Material." + material); + } else if (anim != null) { + materialItem.addProperty("*", "Material.anim"); + JsonObject uvAnim = new JsonObject(); + controller.add("uv_anim", uvAnim); + JsonArray offset = new JsonArray(); + offset.add(0.0); + offset.add("math.mod(math.floor(q.life_time * " + anim.fps + ")," + anim.frames + ") / " + anim.frames); + uvAnim.add("offset", offset); + JsonArray scale = new JsonArray(); + scale.add(1.0); + scale.add("1 / " + anim.frames); + uvAnim.add("scale", scale); + } else { + materialItem.addProperty("*", "Material.default"); + } + materials.add(materialItem); + controller.add("materials", materials); + + JsonArray textures = new JsonArray(); + if (singleTexture) { + textures.add("Texture.default"); + } else { + textures.add("Texture." + key); + } + controller.add("textures", textures); + + // if (enable) { + JsonArray partVisibility = new JsonArray(); + JsonObject visibilityDefault = new JsonObject(); + visibilityDefault.addProperty("*", false); + partVisibility.add(visibilityDefault); + int i = 0; + List sorted = new ArrayList<>(bones.keySet()); + Map originalId = new HashMap<>(); + ListIterator iterator = sorted.listIterator(); + while (iterator.hasNext()) { + String s = iterator.next(); + String o = s; + for (String r : NEED_REMOVE_WHEN_SORT) { + s = s.replace(r, ""); + } + iterator.set(s); + originalId.put(s, o); + } + Collections.sort(sorted); + + Set uvAllBones = new HashSet<>(); + for (String uvBone : uvBonesId) { + if (uvBone.equals("*")) { + uvAllBones.addAll(bones.keySet()); + } + if (!bones.containsKey(uvBone.toLowerCase())) { + continue; + } + uvAllBones.add(uvBone.toLowerCase()); + } + + + for (String boneName : sorted) { + boneName = originalId.get(boneName); + JsonObject visibilityItem = new JsonObject(); + Bone bone = bones.get(boneName); + boolean uvParent = false; + for (Bone child : bone.children) { + if (child.getName().startsWith("uv_")) { + if (uvAllBones.contains(child.getName())) { + uvParent = true; + } + } + } + + if (!processedBones.contains(bone) && (uvParent || uvAllBones.contains(boneName) || uvBonesId.contains("*"))) { + int index = i; + if (boneName.startsWith("uv_")) { + index = sorted.indexOf(bone.parent); + } + + int n = (int) Math.pow(2, (index % 24)); + if (entity.modelConfig.isDisablePartVisibility()) { + visibilityItem.addProperty(boneName, true); + } else { + visibilityItem.addProperty(boneName, "math.mod(math.floor(query.property('modelengine:bone" + index / 24 + "') / " + n + "), 2) == 1"); + } + partVisibility.add(visibilityItem); + if (!uvBonesId.contains("*")) { + processedBones.add(bone); + } + } + if (!boneName.startsWith("uv_")) { + i++; + } + } + controller.add("part_visibility", partVisibility); + //} } - Collections.sort(sorted); - for (String bone : sorted) { - bone = originalId.get(bone); - JsonObject visibilityItem = new JsonObject(); - int n = (int) Math.pow(2, (i % 24)); - visibilityItem.addProperty(bone, "math.mod(math.floor(query.property('modelengine:bone" + i / 24 + "') / " + n + "), 2) == 1"); - partVisibility.add(visibilityItem); - i++; - } - controller.add("part_visibility", partVisibility); - //} + return root.toString(); } diff --git a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Texture.java b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Texture.java index c0bd870..8b8ed75 100644 --- a/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Texture.java +++ b/src/main/java/re/imc/geysermodelenginepackgenerator/generator/Texture.java @@ -4,7 +4,9 @@ import lombok.AllArgsConstructor; import lombok.Getter; import lombok.Setter; +import java.awt.image.BufferedImage; import java.nio.file.Path; +import java.util.Set; @Getter @Setter @@ -12,8 +14,8 @@ import java.nio.file.Path; public class Texture { String modelId; - String path; + Set bindingBones; Path originalPath; }