Skip to content

Commit

Permalink
Implement model format for extras
Browse files Browse the repository at this point in the history
  • Loading branch information
Patbox committed Dec 1, 2024
1 parent 25c25ff commit 5cb1f49
Show file tree
Hide file tree
Showing 6 changed files with 201 additions and 4 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ fabric_version=0.110.2+1.21.4

maven_group = eu.pb4

mod_version = 0.11.0
mod_version = 0.11.1

minecraft_version_supported = ">=1.21.4-"

Expand Down
29 changes: 26 additions & 3 deletions polymer-core/src/testmod/java/eu/pb4/polymertest/TestMod.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import eu.pb4.polymer.resourcepack.api.PolymerResourcePackUtils;
import eu.pb4.polymer.resourcepack.extras.api.ResourcePackExtras;
import eu.pb4.polymer.resourcepack.extras.api.format.item.ItemAsset;
import eu.pb4.polymer.resourcepack.extras.api.format.model.Model;
import eu.pb4.polymer.virtualentity.api.tracker.EntityTrackedData;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.ModInitializer;
Expand Down Expand Up @@ -500,14 +501,14 @@ public void onInitialize() {

new Thread(() -> {
var vanillaJar = PolymerCommonUtils.getClientJarRoot();

var itemsBase = vanillaJar.resolve("/assets/minecraft/items/");
var modelsBase = vanillaJar.resolve("/assets/minecraft/models/");

try {
var value = new MutableInt();
var count = new MutableInt();
Files.walk(itemsBase, 1).forEach(path -> {
if (path.equals(itemsBase)) {
Files.walk(itemsBase).forEach(path -> {
if (!path.toString().endsWith(".json")) {
return;
}
count.increment();
Expand All @@ -520,6 +521,28 @@ public void onInitialize() {
e.printStackTrace();
}
});
System.out.println("Parsed " + value + " out of " + count + " item assets!");
} catch (IOException e) {
e.printStackTrace();
}

try {
var value = new MutableInt();
var count = new MutableInt();
Files.walk(modelsBase).forEach(path -> {
if (!path.toString().endsWith(".json")) {
return;
}
count.increment();
try {
var asset = Model.fromJson(Files.readString(path));
//System.out.println(path + ">" + asset);
value.increment();
} catch (Throwable e) {
System.err.println("Error while parsing file: " + path);
e.printStackTrace();
}
});
System.out.println("Parsed " + value + " out of " + count + " models!");
} catch (IOException e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package eu.pb4.polymer.resourcepack.extras.api.format.model;

import com.mojang.serialization.Codec;
import net.minecraft.util.StringIdentifiable;

public enum GuiLight implements StringIdentifiable {
SIDE("side"),
FRONT("front");

public static final Codec<GuiLight> CODEC = StringIdentifiable.createCodec(GuiLight::values);

private final String name;
private GuiLight(String name) {
this.name = name;
}
@Override
public String asString() {
return this.name;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package eu.pb4.polymer.resourcepack.extras.api.format.model;

import com.google.gson.JsonParser;
import com.mojang.serialization.Codec;
import com.mojang.serialization.JsonOps;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.item.ModelTransformationMode;
import net.minecraft.util.Identifier;

import java.util.List;
import java.util.Map;
import java.util.Optional;

public record Model(Optional<Identifier> parent, Optional<List<ModelElement>> elements, Map<String, String> textures,
Map<ModelTransformationMode, ModelTransformation> display,
Optional<GuiLight> guiLight,
boolean ambientOcclusion) {
public static final Codec<Model> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Identifier.CODEC.optionalFieldOf("parent").forGetter(Model::parent),
ModelElement.CODEC.listOf().optionalFieldOf("elements").forGetter(Model::elements),
Codec.unboundedMap(Codec.STRING, Codec.STRING).optionalFieldOf("textures", Map.of()).forGetter(Model::textures),
Codec.unboundedMap(ModelTransformationMode.CODEC, ModelTransformation.CODEC).optionalFieldOf("display", Map.of()).forGetter(Model::display),
GuiLight.CODEC.optionalFieldOf("gui_light").forGetter(Model::guiLight),
Codec.BOOL.optionalFieldOf("ambientocclusion", true).forGetter(Model::ambientOcclusion)
).apply(instance, Model::new));

public Model(Optional<Identifier> parent, Optional<List<ModelElement>> elements, Map<String, String> textures,
Map<ModelTransformationMode, ModelTransformation> display,
Optional<GuiLight> guiLight) {
this(parent, elements, textures, display, guiLight, true);
}

public Model(Optional<Identifier> parent, Optional<List<ModelElement>> elements, Map<String, String> textures,
Map<ModelTransformationMode, ModelTransformation> display) {
this(parent, elements, textures, display, Optional.empty(), true);
}

public Model(Optional<Identifier> parent, Optional<List<ModelElement>> elements, Map<String, String> textures) {
this(parent, elements, textures, Map.of(), Optional.empty(), true);
}

public Model(Identifier parent, Map<String, String> textures) {
this(Optional.of(parent), Optional.empty(), textures, Map.of(), Optional.empty(), true);
}

public Model(List<ModelElement> elements, Map<String, String> textures) {
this(Optional.empty(), Optional.of(elements), textures, Map.of(), Optional.empty(), true);
}

public String toJson() {
return CODEC.encodeStart(JsonOps.INSTANCE, this).getOrThrow().toString();
}

public static Model fromJson(String json) {
return CODEC.decode(JsonOps.INSTANCE, JsonParser.parseString(json)).getOrThrow().getFirst();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package eu.pb4.polymer.resourcepack.extras.api.format.model;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.dynamic.Codecs;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;

import java.util.List;
import java.util.Map;
import java.util.Optional;

public record ModelElement(Vec3d from, Vec3d to, Map<Direction, Face> faces, Optional<Rotation> rotation,
boolean shade, int lightEmission) {
public static final Codec<ModelElement> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Vec3d.CODEC.fieldOf("from").forGetter(ModelElement::from),
Vec3d.CODEC.fieldOf("to").forGetter(ModelElement::to),
Codec.unboundedMap(Direction.CODEC, Face.CODEC).optionalFieldOf("faces", Map.of()).forGetter(ModelElement::faces),
Rotation.CODEC.optionalFieldOf("rotation").forGetter(ModelElement::rotation),
Codec.BOOL.optionalFieldOf("shade", true).forGetter(ModelElement::shade),
Codecs.rangedInt(0, 15).optionalFieldOf("light_emission", 0).forGetter(ModelElement::lightEmission)
).apply(instance, ModelElement::new));

public ModelElement(Vec3d from, Vec3d to, Map<Direction, Face> faces, Optional<Rotation> rotation,
boolean shade) {
this(from, to, faces, rotation, shade, 0);
}
public ModelElement(Vec3d from, Vec3d to, Map<Direction, Face> faces, Optional<Rotation> rotation) {
this(from, to, faces, rotation, true, 0);
}

public ModelElement(Vec3d from, Vec3d to, Map<Direction, Face> faces) {
this(from, to, faces, Optional.empty(), true, 0);
}

public record Rotation(Vec3d origin, Direction.Axis axis, float angle, boolean rescale) {
public static final Codec<Rotation> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Vec3d.CODEC.optionalFieldOf("origin", Vec3d.ZERO).forGetter(Rotation::origin),
Direction.Axis.CODEC.fieldOf("axis").forGetter(Rotation::axis),
Codec.FLOAT.fieldOf("angle").forGetter(Rotation::angle),
Codec.BOOL.optionalFieldOf("rescale", false).forGetter(Rotation::rescale)
).apply(instance, Rotation::new));

public Rotation(Vec3d origin, Direction.Axis axis, float angle) {
this(origin, axis, angle, false);
}

public Rotation(Direction.Axis axis, float angle) {
this(Vec3d.ZERO, axis, angle, false);
}
}

public record Face(List<Float> uv, String texture, Optional<Direction> cullface, int rotation, int tintIndex) {
public static final Codec<Face> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Codec.list(Codec.FLOAT, 4, 4).optionalFieldOf("uv", List.of()).forGetter(Face::uv),
Codec.STRING.optionalFieldOf("texture", "").forGetter(Face::texture),
Direction.CODEC.optionalFieldOf("cullface").forGetter(Face::cullface),
Codec.INT.optionalFieldOf("rotation", 0).forGetter(Face::rotation),
Codec.INT.optionalFieldOf("tintindex", -1).forGetter(Face::tintIndex)
).apply(instance, Face::new));

public Face {
if (uv.size() != 4 && !uv.isEmpty()) {
throw new IllegalArgumentException("uv needs to have either 4 elements or be empty");
}
}

public Face(List<Float> uv, String texture, Optional<Direction> cullface, int rotation) {
this(uv, texture, cullface, rotation, -1);
}

public Face(List<Float> uv, String texture, Optional<Direction> cullface) {
this(uv, texture, cullface, 0, -1);
}

public Face(List<Float> uv, String texture) {
this(uv, texture, Optional.empty(), 0, -1);
}

public Face(String texture) {
this(List.of(), texture, Optional.empty(), 0, -1);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package eu.pb4.polymer.resourcepack.extras.api.format.model;

import com.mojang.serialization.Codec;
import com.mojang.serialization.codecs.RecordCodecBuilder;
import net.minecraft.util.math.Vec3d;

public record ModelTransformation(Vec3d rotation, Vec3d translation, Vec3d scale) {
public static final Codec<ModelTransformation> CODEC = RecordCodecBuilder.create(instance -> instance.group(
Vec3d.CODEC.optionalFieldOf("rotation", Vec3d.ZERO).forGetter(ModelTransformation::rotation),
Vec3d.CODEC.optionalFieldOf("translation", Vec3d.ZERO).forGetter(ModelTransformation::translation),
Vec3d.CODEC.optionalFieldOf("scale", Vec3d.ZERO).forGetter(ModelTransformation::scale)
).apply(instance, ModelTransformation::new));
}

0 comments on commit 5cb1f49

Please sign in to comment.