1
0
mirror of https://github.com/GeyserMC/PackConverter.git synced 2025-12-19 14:59:21 +00:00

Add very basic model conversion

This commit is contained in:
RednedEpic
2023-06-25 18:31:33 -05:00
parent 63a5d4f43b
commit 7fedbb44fe
3 changed files with 316 additions and 2 deletions

View File

@@ -7,7 +7,7 @@ dependencies {
}
application {
mainClass.set("org.geysermc.pack.converter.boostrap.Main")
mainClass.set("org.geysermc.pack.converter.bootstrap.Main")
}
tasks.withType<com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar> {

View File

@@ -0,0 +1,232 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/PackConverter
*
*/
package org.geysermc.pack.converter.converter.model;
import com.google.auto.service.AutoService;
import net.kyori.adventure.key.Key;
import org.geysermc.pack.bedrock.resource.BedrockResourcePack;
import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.Geometry;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Bones;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.Description;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.Cubes;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.Uv;
import org.geysermc.pack.bedrock.resource.models.entity.modelentity.geometry.bones.cubes.uv.*;
import org.geysermc.pack.converter.PackConversionContext;
import org.geysermc.pack.converter.converter.BaseConverter;
import org.geysermc.pack.converter.converter.Converter;
import org.geysermc.pack.converter.data.BaseConversionData;
import org.jetbrains.annotations.NotNull;
import team.unnamed.creative.ResourcePack;
import team.unnamed.creative.base.CubeFace;
import team.unnamed.creative.base.Vector4Float;
import team.unnamed.creative.model.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@AutoService(Converter.class)
public class ModelConverter extends BaseConverter {
private static final String FORMAT_VERSION = "1.12.0";
private static final String GEOMETRY_FORMAT = "geometry.%s";
private static final float[] ELEMENT_OFFSET = new float[] { 8, 0, 8 };
@Override
public void convert(@NotNull PackConversionContext<BaseConversionData> context) throws Exception {
ResourcePack javaPack = context.javaResourcePack();
BedrockResourcePack bedrockPack = context.bedrockResourcePack();
Collection<Model> models = javaPack.models();
for (Model model : models) {
List<Element> elements = model.elements();
if (elements.isEmpty()) {
continue;
}
ModelTextures modelTextures = model.textures();
if (modelTextures == null) {
continue;
}
Collection<ModelTexture> textures = modelTextures.variables().values();
if (textures.isEmpty()) {
continue;
}
String value = model.key().value();
context.debug("Converting model " + model.key().key() + ":" + value);
// TODO: Combine textures into one texture
ModelTexture modelTexture = textures.iterator().next();
ModelEntity modelEntity = new ModelEntity();
modelEntity.formatVersion(FORMAT_VERSION);
Geometry geometry = new Geometry();
String namespace = model.key().namespace();
String fileName = value.substring(value.lastIndexOf('/') + 1);
String geoName = (namespace.equals(Key.MINECRAFT_NAMESPACE) ? "" : namespace + ".") + fileName;
// TODO: Don't hardcode all this
Description description = new Description();
description.identifier(String.format(GEOMETRY_FORMAT, geoName));
description.textureWidth(16);
description.textureHeight(16);
description.visibleBoundsWidth(2);
description.visibleBoundsHeight(2);
description.visibleBoundsOffset(new float[] { 0.0f, 0.25f, 0.0f });
geometry.description(description);
List<Bones> bones = new ArrayList<>();
// TODO: Should each element be its own bone rather
// than its own cube in the same bone?
int i = 0;
for (Element element : elements) {
float[] from = element.from().toArray();
float[] to = element.to().toArray();
Bones bone = new Bones();
bone.name("bone_" + i++);
bone.pivot(new float[] { 0, 0, 0 });
Cubes cube = new Cubes();
cube.origin(new float[] { ELEMENT_OFFSET[0] - to[0], from[1], from[2] - ELEMENT_OFFSET[2] });
cube.size(new float[] { to[0] - from[0], to[1] - from[1], to[2] - from[2] });
ElementRotation elementRotation = element.rotation();
if (elementRotation != null) {
float[] origin = elementRotation.origin().toArray();
cube.pivot(new float[] { ELEMENT_OFFSET[0] - origin[0], ELEMENT_OFFSET[1] - origin[1], origin[2] - ELEMENT_OFFSET[2] });
float angle = elementRotation.angle();
float[] rotation = new float[3];
switch (elementRotation.axis()) {
case X -> rotation[0] = -angle;
case Y -> rotation[1] = -angle;
case Z -> rotation[2] = -angle;
}
cube.rotation(rotation);
}
Uv uv = new Uv();
for (Map.Entry<CubeFace, ElementFace> entry : element.faces().entrySet()) {
CubeFace face = entry.getKey();
ElementFace elementFace = entry.getValue();
if (elementFace.uv() == null) {
continue;
}
// The Java pack lib we use does this weird thing where it
// divides the UV by 16, so we need to multiply it by 16
applyUv(uv, face, elementFace.uv().multiply(ElementFace.MINECRAFT_UV_UNIT));
}
cube.uv(uv);
bone.cubes(List.of(cube));
bones.add(bone);
}
geometry.bones(bones);
modelEntity.geometry(List.of(geometry));
if (model.key().namespace().contains("entity")) {
bedrockPack.addEntityModel(modelEntity, fileName + ".json");
} else {
// Bedrock only has a concept of entity or block models
bedrockPack.addBlockModel(modelEntity, fileName + ".json");
}
}
}
private static void applyUv(Uv uv, CubeFace face, Vector4Float faceUv) {
float[] uvs;
float[] uvSize;
// These values are flipped for some reason
if (face == CubeFace.DOWN || face == CubeFace.UP) {
uvs = new float[] { faceUv.x2(), faceUv.y2() };
uvSize = new float[] { faceUv.x() - faceUv.x2(), faceUv.y() - faceUv.y2() };
} else {
uvs = new float[] { faceUv.x(), faceUv.y() };
uvSize = new float[] { faceUv.x2() - faceUv.x(), faceUv.y2() - faceUv.y() };
}
switch (face) {
case NORTH -> {
North north = new North();
north.uv(uvs);
north.uvSize(uvSize);
uv.north(north);
}
case SOUTH -> {
South south = new South();
south.uv(uvs);
south.uvSize(uvSize);
uv.south(south);
}
case EAST -> {
East east = new East();
east.uv(uvs);
east.uvSize(uvSize);
uv.east(east);
}
case WEST -> {
West west = new West();
west.uv(uvs);
west.uvSize(uvSize);
uv.west(west);
}
case UP -> {
Up up = new Up();
up.uv(uvs);
up.uvSize(uvSize);
uv.up(up);
}
case DOWN -> {
Down down = new Down();
down.uv(uvs);
down.uvSize(uvSize);
uv.down(down);
}
}
}
}

View File

@@ -29,6 +29,7 @@ package org.geysermc.pack.bedrock.resource;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import org.geysermc.pack.bedrock.resource.attachables.Attachables;
import org.geysermc.pack.bedrock.resource.models.entity.ModelEntity;
import org.geysermc.pack.bedrock.resource.render_controllers.RenderControllers;
import org.geysermc.pack.bedrock.resource.sounds.SoundDefinitions;
import org.geysermc.pack.bedrock.resource.sounds.sounddefinitions.Sounds;
@@ -72,6 +73,9 @@ public class BedrockResourcePack {
private Languages languages;
private Map<String, RenderControllers> renderControllers;
private Map<String, ModelEntity> blockModels;
private Map<String, ModelEntity> entityModels;
public BedrockResourcePack(@NotNull Path directory) {
this(directory, null, null, null);
}
@@ -196,6 +200,44 @@ public class BedrockResourcePack {
this.renderControllers = renderControllers;
}
/**
* Get the block models of the resource pack.
*
* @return the block models of the resource pack
*/
@Nullable
public Map<String, ModelEntity> blockModels() {
return this.blockModels;
}
/**
* Set the block models of the resource pack.
*
* @param blockModels the block models of the resource pack
*/
public void blockModels(@Nullable Map<String, ModelEntity> blockModels) {
this.blockModels = blockModels;
}
/**
* Get the entity models of the resource pack.
*
* @return the entity models of the resource pack
*/
@Nullable
public Map<String, ModelEntity> entityModels() {
return this.entityModels;
}
/**
* Set the entity models of the resource pack.
*
* @param entityModels the entity models of the resource pack
*/
public void entityModels(@Nullable Map<String, ModelEntity> entityModels) {
this.entityModels = entityModels;
}
/**
* Get the sound definitions of the resource pack.
*
@@ -296,7 +338,7 @@ public class BedrockResourcePack {
* @param renderController the data of the render controller
* @param location the location of the final json
*/
public void addRenderController(RenderControllers renderController, String location) {
public void addRenderController(@NotNull RenderControllers renderController, String location) {
if (this.renderControllers == null) {
this.renderControllers = new HashMap<>();
}
@@ -304,6 +346,34 @@ public class BedrockResourcePack {
this.renderControllers.put(location, renderController);
}
/**
* Add a block model to the resource pack.
*
* @param model the data of the block model
* @param location the location of the final json
*/
public void addBlockModel(@NotNull ModelEntity model, @NotNull String location) {
if (this.blockModels == null) {
this.blockModels = new HashMap<>();
}
this.blockModels.put("models/blocks/" + location, model);
}
/**
* Add an entity model to the resource pack.
*
* @param model the data of the entity model
* @param location the location of the final json
*/
public void addEntityModel(@NotNull ModelEntity model, @NotNull String location) {
if (this.entityModels == null) {
this.entityModels = new HashMap<>();
}
this.entityModels.put("models/entity/" + location, model);
}
/**
* Add a sound to the resource pack with the default options set.
*
@@ -395,6 +465,18 @@ public class BedrockResourcePack {
}
}
if (this.blockModels != null) {
for (Map.Entry<String, ModelEntity> blockModel : this.blockModels.entrySet()) {
exportJson(GSON, this.directory.resolve(blockModel.getKey()), blockModel.getValue());
}
}
if (this.entityModels != null) {
for (Map.Entry<String, ModelEntity> entityModel : this.entityModels.entrySet()) {
exportJson(GSON, this.directory.resolve(entityModel.getKey()), entityModel.getValue());
}
}
if (this.soundDefinitions != null) {
exportJson(GSON, this.directory.resolve("sounds/sound_definitions.json"), this.soundDefinitions);
}