mirror of
https://github.com/xSquishyLiam/mc-GeyserModelEnginePackGenerator-extension.git
synced 2025-12-20 15:29:24 +00:00
more of a cleanup
This commit is contained in:
@@ -10,24 +10,14 @@ import org.geysermc.geyser.api.extension.Extension;
|
|||||||
import org.geysermc.geyser.api.pack.PackCodec;
|
import org.geysermc.geyser.api.pack.PackCodec;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
import re.imc.geysermodelenginepackgenerator.managers.ConfigManager;
|
import re.imc.geysermodelenginepackgenerator.managers.ConfigManager;
|
||||||
import re.imc.geysermodelenginepackgenerator.generator.Entity;
|
import re.imc.geysermodelenginepackgenerator.managers.resourcepack.ResourcePackManager;
|
||||||
import re.imc.geysermodelenginepackgenerator.util.ZipUtil;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.util.zip.ZipOutputStream;
|
|
||||||
|
|
||||||
public class GeyserModelEnginePackGenerator implements Extension {
|
public class GeyserModelEnginePackGenerator implements Extension {
|
||||||
|
|
||||||
private static GeyserModelEnginePackGenerator extension;
|
private static GeyserModelEnginePackGenerator extension;
|
||||||
|
|
||||||
private File source;
|
|
||||||
|
|
||||||
private Path generatedPackZip;
|
|
||||||
|
|
||||||
private ConfigManager configManager;
|
private ConfigManager configManager;
|
||||||
|
private ResourcePackManager resourcePackManager;
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
public void onLoad(GeyserPreInitializeEvent event) {
|
public void onLoad(GeyserPreInitializeEvent event) {
|
||||||
@@ -35,9 +25,7 @@ public class GeyserModelEnginePackGenerator implements Extension {
|
|||||||
|
|
||||||
loadManagers();
|
loadManagers();
|
||||||
|
|
||||||
source = dataFolder().resolve("input").toFile();
|
resourcePackManager.loadPack();
|
||||||
source.mkdirs();
|
|
||||||
loadConfig();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Subscribe
|
@Subscribe
|
||||||
@@ -49,43 +37,34 @@ public class GeyserModelEnginePackGenerator implements Extension {
|
|||||||
.description("GeyserModelPackGenerator Reload Command")
|
.description("GeyserModelPackGenerator Reload Command")
|
||||||
.permission("geysermodelenginepackgenerator.admin")
|
.permission("geysermodelenginepackgenerator.admin")
|
||||||
.executor((source, command, args) -> {
|
.executor((source, command, args) -> {
|
||||||
loadConfig();
|
resourcePackManager.loadPack();
|
||||||
source.sendMessage("GeyserModelEnginePackGenerator reloaded!");
|
source.sendMessage("GeyserModelEnginePackGenerator reloaded!");
|
||||||
})
|
})
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void loadConfig() {
|
@Subscribe
|
||||||
File generatedPack = dataFolder().resolve("generated_pack").toFile();
|
public void onPackLoad(GeyserDefineResourcePacksEvent event) {
|
||||||
|
if (!extension.getConfigManager().getConfig().getBoolean("options.resource-pack.auto-load")) return;
|
||||||
|
|
||||||
GeneratorMain.startGenerate(source, generatedPack);
|
ResourcePack resourcePack = ResourcePack.create(PackCodec.path(resourcePackManager.getGeneratedPackZipPath()));
|
||||||
|
event.register(resourcePack);
|
||||||
generatedPackZip = dataFolder().resolve("generated_pack.zip");
|
|
||||||
|
|
||||||
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(generatedPackZip))) {
|
|
||||||
ZipUtil.compressFolder(generatedPack, null, zipOutputStream);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Entity entity : GeneratorMain.entityMap.values()) {
|
|
||||||
entity.register();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadManagers() {
|
private void loadManagers() {
|
||||||
this.configManager = new ConfigManager();
|
this.configManager = new ConfigManager();
|
||||||
}
|
this.resourcePackManager = new ResourcePackManager(this);
|
||||||
|
|
||||||
@Subscribe
|
|
||||||
public void onPackLoad(GeyserDefineResourcePacksEvent event) {
|
|
||||||
if (!configManager.getConfig().getBoolean("options.resource-pack.auto-load")) return;
|
|
||||||
|
|
||||||
ResourcePack resourcePack = ResourcePack.create(PackCodec.path(generatedPackZip));
|
|
||||||
event.register(resourcePack);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static GeyserModelEnginePackGenerator getExtension() {
|
public static GeyserModelEnginePackGenerator getExtension() {
|
||||||
return extension;
|
return extension;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ConfigManager getConfigManager() {
|
||||||
|
return configManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackManager getResourcePackManager() {
|
||||||
|
return resourcePackManager;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import com.google.gson.JsonArray;
|
|||||||
import com.google.gson.JsonElement;
|
import com.google.gson.JsonElement;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
import re.imc.geysermodelenginepackgenerator.GeneratorMain;
|
import re.imc.geysermodelenginepackgenerator.GeyserModelEnginePackGenerator;
|
||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -111,7 +111,7 @@ public class Animation {
|
|||||||
|
|
||||||
if (i == 0) return;
|
if (i == 0) return;
|
||||||
|
|
||||||
GeneratorMain.entityMap.get(modelId).setHasHeadAnimation(true);
|
GeyserModelEnginePackGenerator.getExtension().getResourcePackManager().getEntityCache().get(modelId).setHasHeadAnimation(true);
|
||||||
|
|
||||||
object.add("bones", bones);
|
object.add("bones", bones);
|
||||||
json.get("animations").getAsJsonObject().add("animation." + modelId + ".look_at_target", object);
|
json.get("animations").getAsJsonObject().add("animation." + modelId + ".look_at_target", object);
|
||||||
|
|||||||
@@ -1,119 +1,216 @@
|
|||||||
package re.imc.geysermodelenginepackgenerator;
|
package re.imc.geysermodelenginepackgenerator.managers.resourcepack;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.GsonBuilder;
|
import com.google.gson.GsonBuilder;
|
||||||
import com.google.gson.JsonParser;
|
import com.google.gson.JsonParser;
|
||||||
|
import re.imc.geysermodelenginepackgenerator.GeyserModelEnginePackGenerator;
|
||||||
import re.imc.geysermodelenginepackgenerator.generator.*;
|
import re.imc.geysermodelenginepackgenerator.generator.*;
|
||||||
|
import re.imc.geysermodelenginepackgenerator.util.ZipUtil;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
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.util.*;
|
import java.util.*;
|
||||||
import java.util.zip.ZipEntry;
|
import java.util.zip.ZipEntry;
|
||||||
import java.util.zip.ZipFile;
|
import java.util.zip.ZipFile;
|
||||||
import java.util.zip.ZipInputStream;
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
public class GeneratorMain {
|
public class ResourcePackManager {
|
||||||
|
|
||||||
public static final Map<String, Entity> entityMap = new HashMap<>();
|
private final GeyserModelEnginePackGenerator extension;
|
||||||
public static final Map<String, Animation> animationMap = new HashMap<>();
|
|
||||||
public static final Map<String, Geometry> geometryMap = new HashMap<>();
|
|
||||||
public static final Map<String, Map<String, Texture>> textureMap = new HashMap<>();
|
|
||||||
public static final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
private final File inputFolder;
|
||||||
File source = new File(args.length > 0 ? args[0] : "input");
|
private final File generatedPack;
|
||||||
|
|
||||||
File output = new File("output");
|
private Path generatedPackZipPath;
|
||||||
|
|
||||||
startGenerate(source, output);
|
private final HashMap<String, Entity> entityCache = new HashMap<>();
|
||||||
|
private final HashMap<String, Animation> animationCache = new HashMap<>();
|
||||||
|
private final HashMap<String, Geometry> geometryCache = new HashMap<>();
|
||||||
|
private final HashMap<String, Map<String, Texture>> textureCache = new HashMap<>();
|
||||||
|
|
||||||
|
private final Gson GSON = new GsonBuilder().setPrettyPrinting().create();
|
||||||
|
|
||||||
|
public ResourcePackManager(GeyserModelEnginePackGenerator extension) {
|
||||||
|
this.extension = extension;
|
||||||
|
|
||||||
|
this.inputFolder = extension.dataFolder().resolve("input").toFile();
|
||||||
|
inputFolder.mkdirs();
|
||||||
|
|
||||||
|
this.generatedPack = extension.dataFolder().resolve("generated_pack").toFile();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void loadPack() {
|
||||||
|
generateResourcePack(inputFolder, generatedPack);
|
||||||
|
|
||||||
public static void generateFromZip(String currentPath, String modelId, ZipFile zip) {
|
generatedPackZipPath = extension.dataFolder().resolve("generated_pack.zip");
|
||||||
Entity entity = new Entity(modelId);
|
|
||||||
if (entityMap.containsKey(modelId)) return;
|
|
||||||
|
|
||||||
ModelConfig modelConfig = new ModelConfig();
|
try (ZipOutputStream zipOutputStream = new ZipOutputStream(Files.newOutputStream(generatedPackZipPath))) {
|
||||||
ZipEntry textureConfigFile = null;
|
ZipUtil.compressFolder(generatedPack, null, zipOutputStream);
|
||||||
|
} catch (IOException err) {
|
||||||
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
throw new RuntimeException(err);
|
||||||
ZipEntry entry = it.next();
|
|
||||||
if (entry.getName().endsWith("config.json")) {
|
|
||||||
textureConfigFile = entry;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (textureConfigFile != null) {
|
for (Entity entity : entityCache.values()) {
|
||||||
|
entity.register();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void generateResourcePack(File inputFolder, File output) {
|
||||||
|
generateFromFolder("", inputFolder, true);
|
||||||
|
|
||||||
|
File animationsFolder = new File(output, "animations");
|
||||||
|
File entityFolder = new File(output, "entity");
|
||||||
|
File modelsFolder = new File(output, "models/entity");
|
||||||
|
File texturesFolder = new File(output, "textures/entity");
|
||||||
|
File animationControllersFolder = new File(output, "animation_controllers");
|
||||||
|
File renderControllersFolder = new File(output, "render_controllers");
|
||||||
|
File materialsFolder = new File(output, "materials");
|
||||||
|
|
||||||
|
File manifestFile = new File(output, "manifest.json");
|
||||||
|
|
||||||
|
output.mkdirs();
|
||||||
|
if (!manifestFile.exists()) {
|
||||||
try {
|
try {
|
||||||
modelConfig = GSON.fromJson(new InputStreamReader(zip.getInputStream(textureConfigFile)), ModelConfig.class);
|
Files.writeString(manifestFile.toPath(), PackManifest.generate(), StandardCharsets.UTF_8);
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
boolean canAdd = false;
|
|
||||||
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
animationsFolder.mkdirs();
|
||||||
ZipEntry e = it.next();
|
entityFolder.mkdirs();
|
||||||
if (e.getName().endsWith(".png")) {
|
modelsFolder.mkdirs();
|
||||||
String[] path = e.getName().split("/");
|
texturesFolder.mkdirs();
|
||||||
String textureName = path[path.length - 1].replace(".png", "");
|
animationControllersFolder.mkdirs();
|
||||||
Set<String> bindingBones = new HashSet<>();
|
renderControllersFolder.mkdirs();
|
||||||
bindingBones.add("*");
|
materialsFolder.mkdirs();
|
||||||
if (modelConfig.getBingingBones().containsKey(textureName)) {
|
|
||||||
bindingBones = modelConfig.getBingingBones().get(textureName);
|
File materialFile = new File(materialsFolder, "entity.material");
|
||||||
|
|
||||||
|
if (!materialFile.exists()) {
|
||||||
|
try {
|
||||||
|
Files.writeString(materialFile.toPath(), Material.TEMPLATE, StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Animation> entry : animationCache.entrySet()) {
|
||||||
|
Entity entity = entityCache.get(entry.getKey());
|
||||||
|
Geometry geo = geometryCache.get(entry.getKey());
|
||||||
|
|
||||||
|
if (geo != null) entry.getValue().addHeadBind(geo);
|
||||||
|
|
||||||
|
Path path = animationsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation.json");
|
||||||
|
Path pathController = animationControllersFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation_controllers.json");
|
||||||
|
|
||||||
|
pathController.toFile().getParentFile().mkdirs();
|
||||||
|
path.toFile().getParentFile().mkdirs();
|
||||||
|
|
||||||
|
if (path.toFile().exists()) continue;
|
||||||
|
|
||||||
|
AnimationController controller = new AnimationController();
|
||||||
|
controller.load(entry.getValue(), entity);
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
||||||
|
Files.writeString(pathController, controller.getJson().toString(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Geometry> entry : geometryCache.entrySet()) {
|
||||||
|
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 = entityCache.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 err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Map<String, Texture> map = textureMap.computeIfAbsent(modelId, s -> new HashMap<>());
|
|
||||||
try {
|
|
||||||
map.put(textureName, new Texture(modelId, currentPath, bindingBones, zip.getInputStream(e).readAllBytes()));
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
entity.setTextureMap(map);
|
|
||||||
if (modelConfig.getBingingBones().isEmpty()) modelConfig.getBingingBones().put(textureName, Set.of("*"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.getName().endsWith(".json")) {
|
if (path.toFile().exists()) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Map.Entry<String, Map<String, Texture>> textures : textureCache.entrySet()) {
|
||||||
|
for (Map.Entry<String, Texture> 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 {
|
try {
|
||||||
InputStream stream = zip.getInputStream(e);
|
if (entry.getValue().getImage() != null) Files.write(path, entry.getValue().getImage());
|
||||||
String json = new String(stream.readAllBytes());
|
|
||||||
if (isAnimationFile(json)) {
|
|
||||||
Animation animation = new Animation();
|
|
||||||
animation.setPath(currentPath);
|
|
||||||
animation.setModelId(modelId);
|
|
||||||
|
|
||||||
animation.load(json);
|
|
||||||
animationMap.put(modelId, animation);
|
|
||||||
entity.setAnimation(animation);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isGeometryFile(json)) {
|
|
||||||
Geometry geometry = new Geometry();
|
|
||||||
geometry.load(json);
|
|
||||||
geometry.setPath(currentPath);
|
|
||||||
geometry.setModelId(modelId);
|
|
||||||
geometryMap.put(modelId, geometry);
|
|
||||||
entity.setGeometry(geometry);
|
|
||||||
canAdd = true;
|
|
||||||
}
|
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canAdd) {
|
for (Map.Entry<String, Entity> entry : entityCache.entrySet()) {
|
||||||
entity.setModelConfig(modelConfig);
|
Entity entity = entry.getValue();
|
||||||
entity.setPath(currentPath);
|
entity.modify();
|
||||||
entityMap.put(modelId, entity);
|
|
||||||
|
Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json");
|
||||||
|
entityPath.toFile().getParentFile().mkdirs();
|
||||||
|
|
||||||
|
if (entityPath.toFile().exists()) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.writeString(entityPath, entity.getJson().toString(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render controller part
|
||||||
|
|
||||||
|
String id = entity.getModelId();
|
||||||
|
if (!geometryCache.containsKey(id)) continue;
|
||||||
|
RenderController controller = new RenderController(id, geometryCache.get(id).getBones(), entity);
|
||||||
|
entity.setRenderController(controller);
|
||||||
|
Path renderPath = new File(renderControllersFolder, "controller.render." + id + ".json").toPath();
|
||||||
|
if (renderPath.toFile().exists()) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
Files.writeString(renderPath, controller.generate(), StandardCharsets.UTF_8);
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void generateFromFolder(String currentPath, File folder, boolean root) {
|
||||||
|
|
||||||
public static void generateFromFolder(String currentPath, File folder, boolean root) {
|
|
||||||
if (folder.listFiles() == null) return;
|
if (folder.listFiles() == null) return;
|
||||||
|
|
||||||
String modelId = root ? "" : folder.getName().toLowerCase();
|
String modelId = root ? "" : folder.getName().toLowerCase();
|
||||||
@@ -130,30 +227,30 @@ public class GeneratorMain {
|
|||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean canAdd = false;
|
boolean canAdd = false;
|
||||||
for (File e : folder.listFiles()) {
|
for (File file : folder.listFiles()) {
|
||||||
if (e.isDirectory()) {
|
if (file.isDirectory()) generateFromFolder(currentPath + (root ? "" : folder.getName() + "/"), file, false);
|
||||||
generateFromFolder(currentPath + (root ? "" : folder.getName() + "/"), e, false);
|
|
||||||
}
|
if (file.getName().endsWith(".zip")) {
|
||||||
if (e.getName().endsWith(".zip")) {
|
|
||||||
try {
|
try {
|
||||||
generateFromZip(currentPath, e.getName().replace(".zip", "").toLowerCase(Locale.ROOT), new ZipFile(e));
|
generateFromZip(currentPath, file.getName().replace(".zip", "").toLowerCase(Locale.ROOT), new ZipFile(file));
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (entityMap.containsKey(modelId)) continue;
|
if (entityCache.containsKey(modelId)) continue;
|
||||||
|
|
||||||
if (e.getName().endsWith(".png")) {
|
if (file.getName().endsWith(".png")) {
|
||||||
String textureName = e.getName().replace(".png", "");
|
String textureName = file.getName().replace(".png", "");
|
||||||
Set<String> bindingBones = new HashSet<>();
|
Set<String> bindingBones = new HashSet<>();
|
||||||
bindingBones.add("*");
|
bindingBones.add("*");
|
||||||
if (modelConfig.getBingingBones().containsKey(textureName)) bindingBones = modelConfig.getBingingBones().get(textureName);
|
if (modelConfig.getBingingBones().containsKey(textureName)) bindingBones = modelConfig.getBingingBones().get(textureName);
|
||||||
|
|
||||||
Map<String, Texture> map = textureMap.computeIfAbsent(modelId, s -> new HashMap<>());
|
Map<String, Texture> map = textureCache.computeIfAbsent(modelId, s -> new HashMap<>());
|
||||||
try {
|
try {
|
||||||
map.put(textureName, new Texture(modelId, currentPath, bindingBones, Files.readAllBytes(e.toPath())));
|
map.put(textureName, new Texture(modelId, currentPath, bindingBones, Files.readAllBytes(file.toPath())));
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
@@ -165,16 +262,16 @@ public class GeneratorMain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.getName().endsWith(".json")) {
|
if (file.getName().endsWith(".json")) {
|
||||||
try {
|
try {
|
||||||
String json = Files.readString(e.toPath());
|
String json = Files.readString(file.toPath());
|
||||||
if (isAnimationFile(json)) {
|
if (isAnimationFile(json)) {
|
||||||
Animation animation = new Animation();
|
Animation animation = new Animation();
|
||||||
animation.setPath(currentPath);
|
animation.setPath(currentPath);
|
||||||
animation.setModelId(modelId);
|
animation.setModelId(modelId);
|
||||||
|
|
||||||
animation.load(json);
|
animation.load(json);
|
||||||
animationMap.put(modelId, animation);
|
animationCache.put(modelId, animation);
|
||||||
entity.setAnimation(animation);
|
entity.setAnimation(animation);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +280,7 @@ public class GeneratorMain {
|
|||||||
geometry.load(json);
|
geometry.load(json);
|
||||||
geometry.setPath(currentPath);
|
geometry.setPath(currentPath);
|
||||||
geometry.setModelId(modelId);
|
geometry.setModelId(modelId);
|
||||||
geometryMap.put(modelId, geometry);
|
geometryCache.put(modelId, geometry);
|
||||||
entity.setGeometry(geometry);
|
entity.setGeometry(geometry);
|
||||||
canAdd = true;
|
canAdd = true;
|
||||||
}
|
}
|
||||||
@@ -220,181 +317,93 @@ public class GeneratorMain {
|
|||||||
|
|
||||||
entity.setModelConfig(modelConfig);
|
entity.setModelConfig(modelConfig);
|
||||||
entity.setPath(currentPath);
|
entity.setPath(currentPath);
|
||||||
entityMap.put(modelId, entity);
|
entityCache.put(modelId, entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void startGenerate(File source, File output) {
|
public void generateFromZip(String currentPath, String modelId, ZipFile zip) {
|
||||||
generateFromFolder("", source, true);
|
Entity entity = new Entity(modelId);
|
||||||
|
if (entityCache.containsKey(modelId)) return;
|
||||||
|
|
||||||
File animationsFolder = new File(output, "animations");
|
ModelConfig modelConfig = new ModelConfig();
|
||||||
File entityFolder = new File(output, "entity");
|
ZipEntry textureConfigFile = null;
|
||||||
File modelsFolder = new File(output, "models/entity");
|
|
||||||
File texturesFolder = new File(output, "textures/entity");
|
|
||||||
File animationControllersFolder = new File(output, "animation_controllers");
|
|
||||||
File renderControllersFolder = new File(output, "render_controllers");
|
|
||||||
File materialsFolder = new File(output, "materials");
|
|
||||||
|
|
||||||
File manifestFile = new File(output, "manifest.json");
|
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
||||||
|
ZipEntry entry = it.next();
|
||||||
|
if (entry.getName().endsWith("config.json")) {
|
||||||
|
textureConfigFile = entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
output.mkdirs();
|
if (textureConfigFile != null) {
|
||||||
if (!manifestFile.exists()) {
|
|
||||||
try {
|
try {
|
||||||
Files.writeString(manifestFile.toPath(),
|
modelConfig = GSON.fromJson(new InputStreamReader(zip.getInputStream(textureConfigFile)), ModelConfig.class);
|
||||||
PackManifest.generate(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean canAdd = false;
|
||||||
|
for (Iterator<? extends ZipEntry> it = zip.entries().asIterator(); it.hasNext(); ) {
|
||||||
|
ZipEntry e = it.next();
|
||||||
|
if (e.getName().endsWith(".png")) {
|
||||||
|
String[] path = e.getName().split("/");
|
||||||
|
String textureName = path[path.length - 1].replace(".png", "");
|
||||||
|
Set<String> bindingBones = new HashSet<>();
|
||||||
|
bindingBones.add("*");
|
||||||
|
|
||||||
animationsFolder.mkdirs();
|
if (modelConfig.getBingingBones().containsKey(textureName)) {
|
||||||
entityFolder.mkdirs();
|
bindingBones = modelConfig.getBingingBones().get(textureName);
|
||||||
modelsFolder.mkdirs();
|
|
||||||
texturesFolder.mkdirs();
|
|
||||||
animationControllersFolder.mkdirs();
|
|
||||||
renderControllersFolder.mkdirs();
|
|
||||||
materialsFolder.mkdirs();
|
|
||||||
|
|
||||||
File materialFile = new File(materialsFolder, "entity.material");
|
|
||||||
|
|
||||||
if (!materialFile.exists()) {
|
|
||||||
try {
|
|
||||||
Files.writeString(materialFile.toPath(),
|
|
||||||
Material.TEMPLATE, StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, Animation> entry : animationMap.entrySet()) {
|
|
||||||
Entity entity = entityMap.get(entry.getKey());
|
|
||||||
Geometry geo = geometryMap.get(entry.getKey());
|
|
||||||
if (geo != null) {
|
|
||||||
entry.getValue().addHeadBind(geo);
|
|
||||||
}
|
|
||||||
Path path = animationsFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation.json");
|
|
||||||
Path pathController = animationControllersFolder.toPath().resolve(entry.getValue().getPath() + entry.getKey() + ".animation_controllers.json");
|
|
||||||
|
|
||||||
pathController.toFile().getParentFile().mkdirs();
|
|
||||||
path.toFile().getParentFile().mkdirs();
|
|
||||||
|
|
||||||
if (path.toFile().exists()) continue;
|
|
||||||
|
|
||||||
AnimationController controller = new AnimationController();
|
|
||||||
controller.load(entry.getValue(), entity);
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
|
||||||
Files.writeString(pathController, controller.getJson().toString(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, Geometry> entry : geometryMap.entrySet()) {
|
|
||||||
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<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 err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
Map<String, Texture> map = textureCache.computeIfAbsent(modelId, s -> new HashMap<>());
|
||||||
|
|
||||||
if (path.toFile().exists()) continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.writeString(path, GSON.toJson(entry.getValue().getJson()), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Map.Entry<String, Map<String, Texture>> textures : textureMap.entrySet()) {
|
|
||||||
|
|
||||||
for (Map.Entry<String, Texture> 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 {
|
try {
|
||||||
if (entry.getValue().getImage() != null) Files.write(path, entry.getValue().getImage());
|
map.put(textureName, new Texture(modelId, currentPath, bindingBones, zip.getInputStream(e).readAllBytes()));
|
||||||
|
} catch (IOException err) {
|
||||||
|
throw new RuntimeException(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
entity.setTextureMap(map);
|
||||||
|
if (modelConfig.getBingingBones().isEmpty()) modelConfig.getBingingBones().put(textureName, Set.of("*"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e.getName().endsWith(".json")) {
|
||||||
|
try {
|
||||||
|
InputStream stream = zip.getInputStream(e);
|
||||||
|
String json = new String(stream.readAllBytes());
|
||||||
|
if (isAnimationFile(json)) {
|
||||||
|
Animation animation = new Animation();
|
||||||
|
animation.setPath(currentPath);
|
||||||
|
animation.setModelId(modelId);
|
||||||
|
|
||||||
|
animation.load(json);
|
||||||
|
animationCache.put(modelId, animation);
|
||||||
|
entity.setAnimation(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isGeometryFile(json)) {
|
||||||
|
Geometry geometry = new Geometry();
|
||||||
|
geometry.load(json);
|
||||||
|
geometry.setPath(currentPath);
|
||||||
|
geometry.setModelId(modelId);
|
||||||
|
geometryCache.put(modelId, geometry);
|
||||||
|
entity.setGeometry(geometry);
|
||||||
|
canAdd = true;
|
||||||
|
}
|
||||||
} catch (IOException err) {
|
} catch (IOException err) {
|
||||||
throw new RuntimeException(err);
|
throw new RuntimeException(err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, Entity> entry : entityMap.entrySet()) {
|
if (canAdd) {
|
||||||
Entity entity = entry.getValue();
|
entity.setModelConfig(modelConfig);
|
||||||
entity.modify();
|
entity.setPath(currentPath);
|
||||||
|
entityCache.put(modelId, entity);
|
||||||
Path entityPath = entityFolder.toPath().resolve(entity.getPath() + entry.getKey() + ".entity.json");
|
|
||||||
entityPath.toFile().getParentFile().mkdirs();
|
|
||||||
|
|
||||||
if (entityPath.toFile().exists()) continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.writeString(entityPath, entity.getJson().toString(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render controller part
|
|
||||||
|
|
||||||
String id = entity.getModelId();
|
|
||||||
if (!geometryMap.containsKey(id)) continue;
|
|
||||||
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()) continue;
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.writeString(renderPath, controller.generate(), StandardCharsets.UTF_8);
|
|
||||||
} catch (IOException err) {
|
|
||||||
throw new RuntimeException(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
File controller = new File(animationControllersFolder, "modelengine.animation_controller.json");
|
|
||||||
if (!controller.exists()) {
|
|
||||||
try {
|
|
||||||
Files.writeString(controller.toPath(), AnimationController.TEMPLATE);
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isGeometryFile(String json) {
|
private boolean isGeometryFile(String json) {
|
||||||
try {
|
try {
|
||||||
return JsonParser.parseString(json).getAsJsonObject().has("minecraft:geometry");
|
return JsonParser.parseString(json).getAsJsonObject().has("minecraft:geometry");
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
@@ -402,11 +411,35 @@ public class GeneratorMain {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAnimationFile(String json) {
|
private boolean isAnimationFile(String json) {
|
||||||
try {
|
try {
|
||||||
return JsonParser.parseString(json).getAsJsonObject().has("animations");
|
return JsonParser.parseString(json).getAsJsonObject().has("animations");
|
||||||
} catch (Throwable ignored) {
|
} catch (Throwable ignored) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File getInputFolder() {
|
||||||
|
return inputFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Path getGeneratedPackZipPath() {
|
||||||
|
return generatedPackZipPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Entity> getEntityCache() {
|
||||||
|
return entityCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Animation> getAnimationCache() {
|
||||||
|
return animationCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Geometry> getGeometryCache() {
|
||||||
|
return geometryCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HashMap<String, Map<String, Texture>> getTextureCache() {
|
||||||
|
return textureCache;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ import org.spongepowered.configurate.serialize.SerializationException;
|
|||||||
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
import org.spongepowered.configurate.yaml.YamlConfigurationLoader;
|
||||||
import re.imc.geysermodelenginepackgenerator.GeyserModelEnginePackGenerator;
|
import re.imc.geysermodelenginepackgenerator.GeyserModelEnginePackGenerator;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
@@ -126,6 +127,10 @@ public class FileConfiguration {
|
|||||||
return node != null && node.raw() instanceof Boolean;
|
return node != null && node.raw() instanceof Boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public File toFile() {
|
||||||
|
return this.dataDirectory.resolve(configFile).toFile();
|
||||||
|
}
|
||||||
|
|
||||||
private CommentedConfigurationNode getInternal(String path) {
|
private CommentedConfigurationNode getInternal(String path) {
|
||||||
CommentedConfigurationNode node = toSplitRoot(path, this.configurationNode);
|
CommentedConfigurationNode node = toSplitRoot(path, this.configurationNode);
|
||||||
if (node.virtual()) return null;
|
if (node.virtual()) return null;
|
||||||
|
|||||||
Reference in New Issue
Block a user