mirror of
https://github.com/GeyserExtensionists/GeyserModelEnginePackGenerator.git
synced 2025-12-19 15:09:18 +00:00
Merge pull request #3 from GeyserExtensionists/flipbook-texture
multi texture support
This commit is contained in:
19
pom.xml
19
pom.xml
@@ -35,6 +35,10 @@
|
|||||||
<enabled>true</enabled>
|
<enabled>true</enabled>
|
||||||
</snapshots>
|
</snapshots>
|
||||||
</repository>
|
</repository>
|
||||||
|
<repository>
|
||||||
|
<id>jitpack.io</id>
|
||||||
|
<url>https://jitpack.io</url>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
@@ -62,5 +66,20 @@
|
|||||||
<scope>system</scope>
|
<scope>system</scope>
|
||||||
<systemPath>${project.basedir}/libs/geyserutils-geyser-1.0-SNAPSHOT.jar</systemPath>
|
<systemPath>${project.basedir}/libs/geyserutils-geyser-1.0-SNAPSHOT.jar</systemPath>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>me.rochblondiaux</groupId>
|
||||||
|
<artifactId>blockbenchmodelreader</artifactId>
|
||||||
|
<version>1.2</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.GeyserMC.PackConverter</groupId>
|
||||||
|
<artifactId>bedrock-pack-schema</artifactId>
|
||||||
|
<version>3d8150474d</version>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.GeyserMC.PackConverter</groupId>
|
||||||
|
<artifactId>pack-schema-api</artifactId>
|
||||||
|
<version>3d8150474d</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</project>
|
</project>
|
||||||
@@ -5,22 +5,21 @@ import com.google.gson.GsonBuilder;
|
|||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import re.imc.geysermodelenginepackgenerator.generator.*;
|
import re.imc.geysermodelenginepackgenerator.generator.*;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
import java.io.FileWriter;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.StandardCopyOption;
|
import java.nio.file.StandardCopyOption;
|
||||||
import java.util.HashMap;
|
import java.util.*;
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class GeneratorMain {
|
public class GeneratorMain {
|
||||||
public static final Map<String, Entity> entityMap = new HashMap<>();
|
public static final Map<String, Entity> entityMap = new HashMap<>();
|
||||||
public static final Map<String, Animation> animationMap = new HashMap<>();
|
public static final Map<String, Animation> animationMap = new HashMap<>();
|
||||||
public static final Map<String, Geometry> geometryMap = new HashMap<>();
|
public static final Map<String, Geometry> geometryMap = new HashMap<>();
|
||||||
public static final Map<String, Texture> textureMap = new HashMap<>();
|
public static final Map<String, Map<String, Texture>> textureMap = new HashMap<>();
|
||||||
public static final Gson GSON = new GsonBuilder().setPrettyPrinting()
|
public static final Gson GSON = new GsonBuilder().setPrettyPrinting()
|
||||||
.create();
|
.create();
|
||||||
|
|
||||||
@@ -40,13 +39,36 @@ public class GeneratorMain {
|
|||||||
String modelId = folder.getName().toLowerCase();
|
String modelId = folder.getName().toLowerCase();
|
||||||
|
|
||||||
Entity entity = new Entity(modelId);
|
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;
|
boolean canAdd = false;
|
||||||
for (File e : folder.listFiles()) {
|
for (File e : folder.listFiles()) {
|
||||||
if (e.isDirectory()) {
|
if (e.isDirectory()) {
|
||||||
generateFromFolder(currentPath + folder.getName() + "/", e);
|
generateFromFolder(currentPath + folder.getName() + "/", e);
|
||||||
}
|
}
|
||||||
if (e.getName().endsWith(".png")) {
|
if (e.getName().endsWith(".png")) {
|
||||||
textureMap.put(modelId, new Texture(modelId, currentPath, e.toPath()));
|
String textureName = e.getName().replace(".png", "");
|
||||||
|
Set<String> bindingBones = new HashSet<>();
|
||||||
|
bindingBones.add("*");
|
||||||
|
if (modelConfig.getBingingBones().containsKey(textureName)) {
|
||||||
|
bindingBones = modelConfig.getBingingBones().get(textureName);
|
||||||
|
}
|
||||||
|
Map<String, Texture> 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")) {
|
if (e.getName().endsWith(".json")) {
|
||||||
try {
|
try {
|
||||||
@@ -76,19 +98,30 @@ public class GeneratorMain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (canAdd) {
|
if (canAdd) {
|
||||||
File config = new File(folder, "config.properties");
|
// old config
|
||||||
|
File oldConfig = new File(folder, "config.properties");
|
||||||
|
Properties old = new Properties();
|
||||||
try {
|
try {
|
||||||
if (config.exists()) {
|
if (oldConfig.exists()) {
|
||||||
entity.getConfig().load(new FileReader(config));
|
old.load(new FileReader(oldConfig));
|
||||||
} else {
|
modelConfig.setMaterial(old.getProperty("material", "entity_alphatest_change_color"));
|
||||||
entity.getConfig().setProperty("head-rotation", "true");
|
modelConfig.setEnableBlendTransition(Boolean.parseBoolean(old.getProperty("blend-transition", "true")));
|
||||||
entity.getConfig().setProperty("material", "entity_alphatest_change_color");
|
modelConfig.setEnableHeadRotation(Boolean.parseBoolean(old.getProperty("head-rotation", "true")));
|
||||||
entity.getConfig().setProperty("blend-transition", "true");
|
shouldOverrideConfig = true;
|
||||||
entity.getConfig().store(new FileWriter(config), "");
|
oldConfig.delete();
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
|
if (shouldOverrideConfig) {
|
||||||
|
try {
|
||||||
|
Files.writeString(textureConfigFile.toPath(), GSON.toJson(modelConfig));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
ex.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
entity.setModelConfig(modelConfig);
|
||||||
entity.setPath(currentPath);
|
entity.setPath(currentPath);
|
||||||
entityMap.put(modelId, entity);
|
entityMap.put(modelId, entity);
|
||||||
}
|
}
|
||||||
@@ -136,6 +169,15 @@ public class GeneratorMain {
|
|||||||
materialsFolder.mkdirs();
|
materialsFolder.mkdirs();
|
||||||
|
|
||||||
File materialFile = new File(materialsFolder, "entity.material");
|
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<String, Animation> entry : animationMap.entrySet()) {
|
for (Map.Entry<String, Animation> entry : animationMap.entrySet()) {
|
||||||
Entity entity = entityMap.get(entry.getKey());
|
Entity entity = entityMap.get(entry.getKey());
|
||||||
@@ -168,34 +210,67 @@ public class GeneratorMain {
|
|||||||
entry.getValue().modify();
|
entry.getValue().modify();
|
||||||
Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".geo.json");
|
Path path = modelsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".geo.json");
|
||||||
path.toFile().getParentFile().mkdirs();
|
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<String, Texture> 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()) {
|
if (path.toFile().exists()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Texture> entry : textureMap.entrySet()) {
|
for (Map.Entry<String, Map<String, Texture>> textures : textureMap.entrySet()) {
|
||||||
Path path = texturesFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".png");
|
|
||||||
path.toFile().getParentFile().mkdirs();
|
|
||||||
|
|
||||||
if (path.toFile().exists()) {
|
for (Map.Entry<String, Texture> entry : textures.getValue().entrySet()) {
|
||||||
continue;
|
Path path = texturesFolder.toPath().resolve(entry.getValue().getPath() + textures.getKey() + "/" + entry.getKey() + ".png");
|
||||||
}
|
path.toFile().getParentFile().mkdirs();
|
||||||
try {
|
|
||||||
Files.copy(entry.getValue().getOriginalPath(), path, StandardCopyOption.REPLACE_EXISTING);
|
if (path.toFile().exists()) {
|
||||||
} catch (IOException e) {
|
continue;
|
||||||
e.printStackTrace();
|
}
|
||||||
|
try {
|
||||||
|
Files.copy(entry.getValue().getOriginalPath(), path, StandardCopyOption.REPLACE_EXISTING);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Entity> entry : entityMap.entrySet()) {
|
for (Map.Entry<String, Entity> entry : entityMap.entrySet()) {
|
||||||
Entity entity = entry.getValue();
|
Entity entity = entry.getValue();
|
||||||
entity.getConfig().setProperty("render_controller", "controller.render." + entry.getKey());
|
|
||||||
entity.modify();
|
entity.modify();
|
||||||
|
|
||||||
Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json");
|
Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json");
|
||||||
@@ -213,7 +288,7 @@ public class GeneratorMain {
|
|||||||
|
|
||||||
String id = entity.getModelId();
|
String id = entity.getModelId();
|
||||||
if (!geometryMap.containsKey(id)) continue;
|
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);
|
entity.setRenderController(controller);
|
||||||
Path renderPath = new File(renderControllersFolder, "controller.render." + id + ".json").toPath();
|
Path renderPath = new File(renderControllersFolder, "controller.render." + id + ".json").toPath();
|
||||||
if (renderPath.toFile().exists()) {
|
if (renderPath.toFile().exists()) {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ public class AnimationController {
|
|||||||
animationControllers.add("controller.animation." + animation.modelId + "." + id, controller);
|
animationControllers.add("controller.animation." + animation.modelId + "." + id, controller);
|
||||||
i++;
|
i++;
|
||||||
if (entity != null) {
|
if (entity != null) {
|
||||||
boolean blend = Boolean.parseBoolean(entity.getConfig().getProperty("blend-transition", "true"));
|
boolean blend = entity.getModelConfig().isEnableBlendTransition();
|
||||||
if (!blend) {
|
if (!blend) {
|
||||||
for (Map.Entry<String, JsonElement> states : controller.get("states").getAsJsonObject().entrySet()) {
|
for (Map.Entry<String, JsonElement> states : controller.get("states").getAsJsonObject().entrySet()) {
|
||||||
states.getValue().getAsJsonObject().remove("blend_transition");
|
states.getValue().getAsJsonObject().remove("blend_transition");
|
||||||
|
|||||||
@@ -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<Bone> children = new HashSet<>();
|
||||||
|
Set<Bone> allChildren = new HashSet<>();
|
||||||
|
}
|
||||||
@@ -8,11 +8,8 @@ import lombok.Getter;
|
|||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import me.zimzaza4.geyserutils.geyser.GeyserUtils;
|
import me.zimzaza4.geyserutils.geyser.GeyserUtils;
|
||||||
import re.imc.geysermodelenginepackgenerator.GeneratorMain;
|
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.*;
|
||||||
import java.util.Properties;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -26,13 +23,13 @@ public class Entity {
|
|||||||
"description": {
|
"description": {
|
||||||
"identifier": "modelengine:%entity_id%",
|
"identifier": "modelengine:%entity_id%",
|
||||||
"materials": {
|
"materials": {
|
||||||
"default": "%material%"
|
"default": "%material%",
|
||||||
|
"anim": "entity_alphatest_anim_change_color_one_sided"
|
||||||
},
|
},
|
||||||
"textures": {
|
"textures": {
|
||||||
"default": "%texture%"
|
|
||||||
},
|
},
|
||||||
"geometry": {
|
"geometry": {
|
||||||
"default": "%geometry%"
|
|
||||||
},
|
},
|
||||||
"animations": {
|
"animations": {
|
||||||
"look_at_target": "%look_at_target%"
|
"look_at_target": "%look_at_target%"
|
||||||
@@ -43,7 +40,6 @@ public class Entity {
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"render_controllers": [
|
"render_controllers": [
|
||||||
"%render_controller%"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -54,21 +50,14 @@ public class Entity {
|
|||||||
String modelId;
|
String modelId;
|
||||||
JsonObject json;
|
JsonObject json;
|
||||||
boolean hasHeadAnimation = false;
|
boolean hasHeadAnimation = false;
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
Animation animation;
|
Animation animation;
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
Geometry geometry;
|
Geometry geometry;
|
||||||
|
|
||||||
@Setter
|
|
||||||
@Getter
|
|
||||||
RenderController renderController;
|
RenderController renderController;
|
||||||
|
|
||||||
String path;
|
String path;
|
||||||
|
Map<String, Texture> textureMap = new HashMap<>();
|
||||||
|
ModelConfig modelConfig;
|
||||||
|
|
||||||
|
|
||||||
Properties config = new Properties();
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -79,14 +68,40 @@ public class Entity {
|
|||||||
public void modify() {
|
public void modify() {
|
||||||
|
|
||||||
json = new JsonParser().parse(TEMPLATE.replace("%entity_id%", modelId)
|
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("%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("%look_at_target%", modelConfig.isEnableHeadRotation() ? "animation." + modelId + ".look_at_target" : "animation.none")
|
||||||
.replace("%material%", config.getProperty("material", "entity_alphatest_change_color"))
|
.replace("%material%", modelConfig.getMaterial())).getAsJsonObject();
|
||||||
.replace("%render_controller%", config.getProperty("render_controller", "controller.render.default"))).getAsJsonObject();
|
|
||||||
|
|
||||||
JsonObject description = json.get("minecraft:client_entity").getAsJsonObject().get("description").getAsJsonObject();
|
JsonObject description = json.get("minecraft:client_entity").getAsJsonObject().get("description").getAsJsonObject();
|
||||||
JsonObject jsonAnimations = description.get("animations").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<String, String> 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();
|
JsonArray animate = description.get("scripts").getAsJsonObject().get("animate").getAsJsonArray();
|
||||||
|
|
||||||
if (animation != null) {
|
if (animation != null) {
|
||||||
@@ -106,8 +121,10 @@ public class Entity {
|
|||||||
if (geometry == null) {
|
if (geometry == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (int i = 0; i < Math.ceil(geometry.getBones().size() / 24f); i++) {
|
if (!modelConfig.isDisablePartVisibility()) {
|
||||||
GeyserUtils.addProperty(id, "modelengine:bone" + i, Integer.class);
|
for (int i = 0; i < Math.ceil(geometry.getBones().size() / 24f); i++) {
|
||||||
|
GeyserUtils.addProperty(id, "modelengine:bone" + i, Integer.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (animation != null) {
|
if (animation != null) {
|
||||||
|
|||||||
@@ -5,6 +5,8 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
import org.geysermc.geyser.api.extension.ExtensionLogger;
|
||||||
|
import re.imc.geysermodelenginepackgenerator.ExtensionMain;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -16,17 +18,27 @@ public class Geometry {
|
|||||||
|
|
||||||
|
|
||||||
String modelId;
|
String modelId;
|
||||||
|
String geometryId;
|
||||||
JsonObject json;
|
JsonObject json;
|
||||||
Set<String> bones = new HashSet<>();
|
Map<String, Bone> bones = new HashMap<>();
|
||||||
|
|
||||||
String path;
|
String path;
|
||||||
public void load(String json) {
|
public void load(String json) {
|
||||||
this.json = new JsonParser().parse(json).getAsJsonObject();
|
this.json = new JsonParser().parse(json).getAsJsonObject();
|
||||||
}
|
}
|
||||||
public void setId(String id) {
|
public void setId(String id) {
|
||||||
|
geometryId = id;
|
||||||
getInternal().get("description").getAsJsonObject().addProperty("identifier", 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() {
|
public JsonObject getInternal() {
|
||||||
return json.get("minecraft:geometry").getAsJsonArray().get(0)
|
return json.get("minecraft:geometry").getAsJsonArray().get(0)
|
||||||
.getAsJsonObject();
|
.getAsJsonObject();
|
||||||
@@ -41,6 +53,7 @@ public class Geometry {
|
|||||||
if (element.isJsonObject()) {
|
if (element.isJsonObject()) {
|
||||||
String name = element.getAsJsonObject().get("name").getAsString().toLowerCase(Locale.ROOT);
|
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().remove("name");
|
||||||
|
|
||||||
element.getAsJsonObject().addProperty("name", name);
|
element.getAsJsonObject().addProperty("name", name);
|
||||||
@@ -51,10 +64,27 @@ public class Geometry {
|
|||||||
name.startsWith("b_") ||
|
name.startsWith("b_") ||
|
||||||
name.startsWith("ob_")) {
|
name.startsWith("ob_")) {
|
||||||
iterator.remove();
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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<String, Set<String>> bingingBones = new HashMap<>();
|
||||||
|
@SerializedName("anim_textures")
|
||||||
|
Map<String, AnimTextureOptions> animTextures = new HashMap<>();
|
||||||
|
@SerializedName("texture_materials")
|
||||||
|
Map<String, String> textureMaterials = new HashMap<>();
|
||||||
|
@SerializedName("per_texture_uv_size")
|
||||||
|
Map<String, Integer[]> perTextureUvSize;
|
||||||
|
@SerializedName("disable_part_visibility")
|
||||||
|
boolean disablePartVisibility;
|
||||||
|
|
||||||
|
public Map<String, String> getTextureMaterials() {
|
||||||
|
return textureMaterials != null ? textureMaterials : Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Map<String, Integer[]> getPerTextureUvSize() {
|
||||||
|
return perTextureUvSize != null ? perTextureUvSize : Map.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
public static class AnimTextureOptions {
|
||||||
|
float fps;
|
||||||
|
int frames;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,7 +2,6 @@ package re.imc.geysermodelenginepackgenerator.generator;
|
|||||||
|
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import re.imc.geysermodelenginepackgenerator.GeneratorMain;
|
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@@ -10,11 +9,13 @@ public class RenderController {
|
|||||||
|
|
||||||
public static final Set<String> NEED_REMOVE_WHEN_SORT = Set.of("pbody_", "plarm_", "prarm_", "plleg_", "prleg_", "phead_", "p_");
|
public static final Set<String> NEED_REMOVE_WHEN_SORT = Set.of("pbody_", "plarm_", "prarm_", "plleg_", "prleg_", "phead_", "p_");
|
||||||
String modelId;
|
String modelId;
|
||||||
Set<String> bones;
|
Map<String, Bone> bones;
|
||||||
|
Entity entity;
|
||||||
|
|
||||||
public RenderController(String modelId, Set<String> bones) {
|
public RenderController(String modelId, Map<String, Bone> bones, Entity entity) {
|
||||||
this.modelId = modelId;
|
this.modelId = modelId;
|
||||||
this.bones = bones;
|
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
|
// 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();
|
JsonObject renderControllers = new JsonObject();
|
||||||
root.add("render_controllers", renderControllers);
|
root.add("render_controllers", renderControllers);
|
||||||
|
|
||||||
JsonObject controller = new JsonObject();
|
Set<Bone> processedBones = new HashSet<>();
|
||||||
renderControllers.add("controller.render." + modelId, controller);
|
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<String> uvBonesId = entity.getModelConfig().bingingBones.get(key);
|
||||||
|
|
||||||
JsonArray materials = new JsonArray();
|
if (uvBonesId == null) {
|
||||||
JsonObject materialItem = new JsonObject();
|
if (!singleTexture) {
|
||||||
materialItem.addProperty("*", "Material.default");
|
continue;
|
||||||
materials.add(materialItem);
|
} else {
|
||||||
controller.add("materials", materials);
|
uvBonesId = new HashSet<>();
|
||||||
|
uvBonesId.add("*");
|
||||||
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<String> sorted = new ArrayList<>(bones);
|
|
||||||
Map<String, String> originalId = new HashMap<>();
|
|
||||||
ListIterator<String> 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);
|
ModelConfig.AnimTextureOptions anim = entity.getModelConfig().getAnimTextures().get(key);
|
||||||
originalId.put(s, o);
|
|
||||||
|
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<String> sorted = new ArrayList<>(bones.keySet());
|
||||||
|
Map<String, String> originalId = new HashMap<>();
|
||||||
|
ListIterator<String> 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<String> 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();
|
return root.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import lombok.AllArgsConstructor;
|
|||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -12,8 +14,8 @@ import java.nio.file.Path;
|
|||||||
public class Texture {
|
public class Texture {
|
||||||
|
|
||||||
String modelId;
|
String modelId;
|
||||||
|
|
||||||
String path;
|
String path;
|
||||||
|
Set<String> bindingBones;
|
||||||
Path originalPath;
|
Path originalPath;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user