diff --git a/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java b/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java index 350b819..a548035 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java +++ b/src/main/java/org/geysermc/packgenerator/pack/attachable/BedrockAttachable.java @@ -28,6 +28,11 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf ).apply(instance, BedrockAttachable::new) ); + public void save(Path attachablesDirectory) throws IOException { + // Get a safe attachable path by using Geyser's way of getting icons + CodecUtil.trySaveJson(CODEC, this, attachablesDirectory.resolve(GeyserSingleDefinition.iconFromResourceLocation(info.identifier) + ".json")); + } + public static Builder builder(ResourceLocation identifier) { return new Builder(identifier); } @@ -51,11 +56,6 @@ public record BedrockAttachable(BedrockVersion formatVersion, AttachableInfo inf .build(); } - public void save(Path attachablesPath) throws IOException { - // Get a safe attachable path by using Geyser's way of getting icons - CodecUtil.trySaveJson(CODEC, this, attachablesPath.resolve(GeyserSingleDefinition.iconFromResourceLocation(info.identifier) + ".json")); - } - public static class Builder { private final ResourceLocation identifier; private final EnumMap materials = new EnumMap<>(DisplaySlot.class); diff --git a/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java b/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java index 0a9f75a..89ad066 100644 --- a/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java +++ b/src/main/java/org/geysermc/packgenerator/pack/geometry/BedrockGeometry.java @@ -4,15 +4,22 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.Direction; import net.minecraft.util.ExtraCodecs; +import org.geysermc.packgenerator.CodecUtil; import org.geysermc.packgenerator.pack.BedrockVersion; import org.joml.Vector2f; import org.joml.Vector3f; +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; public record BedrockGeometry(BedrockVersion formatVersion, List definitions) { + public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 21, 0); public static final Vector3f VECTOR3F_ZERO = new Vector3f(); public static final Codec CODEC = RecordCodecBuilder.create(instance -> @@ -22,6 +29,83 @@ public record BedrockGeometry(BedrockVersion formatVersion, List bones = new ArrayList<>(); + + private Optional visibleBoundsWidth = Optional.empty(); + private Optional visibleBoundsHeight = Optional.empty(); + private Optional visibleBoundsOffset = Optional.empty(); + private Optional textureWidth = Optional.empty(); + private Optional textureHeight = Optional.empty(); + + public Builder(String identifier) { + this.identifier = identifier; + } + + public Builder withVisibleBoundsWidth(float visibleBoundsWidth) { + this.visibleBoundsWidth = Optional.of(visibleBoundsWidth); + return this; + } + + public Builder withVisibleBoundsHeight(float visibleBoundsHeight) { + this.visibleBoundsHeight = Optional.of(visibleBoundsHeight); + return this; + } + + public Builder withVisibleBoundsOffset(Vector3f visibleBoundsOffset) { + this.visibleBoundsOffset = Optional.of(visibleBoundsOffset); + return this; + } + + public Builder withTextureWidth(int textureWidth) { + this.textureWidth = Optional.of(textureWidth); + return this; + } + + public Builder withTextureHeight(int textureHeight) { + this.textureHeight = Optional.of(textureHeight); + return this; + } + + public Builder withBone(Bone bone) { + if (bones.stream().anyMatch(existing -> existing.name.equals(bone.name))) { + throw new IllegalArgumentException("Duplicate bone with name " + bone.name); + } + bones.add(bone); + return this; + } + + public Builder withBone(Bone.Builder builder) { + return withBone(builder.build()); + } + + public BedrockGeometry build() { + return BedrockGeometry.of(new GeometryDefinition( + new GeometryInfo(identifier, visibleBoundsWidth, visibleBoundsHeight, visibleBoundsOffset, textureWidth, textureHeight), List.copyOf(bones))); + } + } + public record GeometryDefinition(GeometryInfo info, List bones) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( @@ -58,6 +142,59 @@ public record BedrockGeometry(BedrockVersion formatVersion, List cubes = new ArrayList<>(); + + private Optional parent = Optional.empty(); + private Vector3f pivot = VECTOR3F_ZERO; + private Vector3f rotation = VECTOR3F_ZERO; + private boolean mirror = false; + private float inflate = 0.0F; + + public Builder(String name) { + this.name = name; + } + + public Builder withParent(String parent) { + this.parent = Optional.of(parent); + return this; + } + + public Builder withPivot(Vector3f pivot) { + this.pivot = pivot; + return this; + } + + public Builder withRotation(Vector3f rotation) { + this.rotation = rotation; + return this; + } + + public Builder mirror() { + this.mirror = true; + return this; + } + + public Builder withInflate(float inflate) { + this.inflate = inflate; + return this; + } + + public Builder withCube(Cube cube) { + this.cubes.add(cube); + return this; + } + + public Builder withCube(Cube.Builder builder) { + return withCube(builder.build()); + } + + public Bone build() { + return new Bone(name, parent, pivot, rotation, mirror, inflate, List.copyOf(cubes)); + } + } } public record Cube(Vector3f origin, Vector3f size, Vector3f rotation, Vector3f pivot, float inflate, boolean mirror, @@ -65,8 +202,8 @@ public record BedrockGeometry(BedrockVersion formatVersion, List> FACE_MAP_CODEC = Codec.unboundedMap(Direction.CODEC, Face.CODEC); public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ExtraCodecs.VECTOR3F.fieldOf("origin").forGetter(Cube::origin), - ExtraCodecs.VECTOR3F.fieldOf("size").forGetter(Cube::size), + ExtraCodecs.VECTOR3F.fieldOf("uvOrigin").forGetter(Cube::origin), + ExtraCodecs.VECTOR3F.fieldOf("uvSize").forGetter(Cube::size), ExtraCodecs.VECTOR3F.optionalFieldOf("rotation", VECTOR3F_ZERO).forGetter(Cube::size), ExtraCodecs.VECTOR3F.optionalFieldOf("pivot", VECTOR3F_ZERO).forGetter(Cube::pivot), Codec.FLOAT.optionalFieldOf("inflate", 0.0F).forGetter(Cube::inflate), @@ -74,13 +211,61 @@ public record BedrockGeometry(BedrockVersion formatVersion, List faces = new HashMap<>(); + + private Vector3f rotation = VECTOR3F_ZERO; + private Vector3f pivot = VECTOR3F_ZERO; + private float inflate = 0.0F; + private boolean mirror = false; + + public Builder(Vector3f origin, Vector3f size) { + this.origin = origin; + this.size = size; + } + + public Builder withRotation(Vector3f rotation) { + this.rotation = rotation; + return this; + } + + public Builder withPivot(Vector3f pivot) { + this.pivot = pivot; + return this; + } + + public Builder withInflate(float inflate) { + this.inflate = inflate; + return this; + } + + public Builder mirror() { + this.mirror = true; + return this; + } + + public Builder withFace(Direction direction, Vector2f uvOrigin, Vector2f uvSize) { + if (faces.containsKey(direction)) { + throw new IllegalArgumentException("Already added a face for direction " + direction); + } + faces.put(direction, new Face(uvOrigin, uvSize)); + return this; + } + + public Cube build() { + return new Cube(origin, size, rotation, pivot, inflate, mirror, Map.copyOf(faces)); + } + } } - public record Face(Vector2f origin, Vector2f size) { + public record Face(Vector2f uvOrigin, Vector2f uvSize) { public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( - ExtraCodecs.VECTOR2F.fieldOf("uv").forGetter(Face::origin), - ExtraCodecs.VECTOR2F.fieldOf("uv_size").forGetter(Face::size) + ExtraCodecs.VECTOR2F.fieldOf("uv").forGetter(Face::uvOrigin), + ExtraCodecs.VECTOR2F.fieldOf("uv_size").forGetter(Face::uvSize) ).apply(instance, Face::new) ); }