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

Bedrock geometry builders

This commit is contained in:
Eclipse
2025-07-04 13:48:24 +00:00
parent 947c97f7a9
commit be7afcd935
2 changed files with 195 additions and 10 deletions

View File

@@ -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<DisplaySlot, String> materials = new EnumMap<>(DisplaySlot.class);

View File

@@ -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<GeometryDefinition> definitions) {
public static final BedrockVersion FORMAT_VERSION = BedrockVersion.of(1, 21, 0);
public static final Vector3f VECTOR3F_ZERO = new Vector3f();
public static final Codec<BedrockGeometry> CODEC = RecordCodecBuilder.create(instance ->
@@ -22,6 +29,83 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
).apply(instance, BedrockGeometry::new)
);
public void save(Path geometryDirectory) throws IOException {
CodecUtil.trySaveJson(CODEC, this, geometryDirectory.resolve(definitions.getFirst().info.identifier + ".geo.json"));
}
public static BedrockGeometry of(GeometryDefinition... definitions) {
return new BedrockGeometry(FORMAT_VERSION, Arrays.asList(definitions));
}
public static Builder builder(String identifier) {
return new Builder(identifier);
}
public static Bone.Builder bone(String name) {
return new Bone.Builder(name);
}
public static Cube.Builder cube(Vector3f origin, Vector3f size) {
return new Cube.Builder(origin, size);
}
public static class Builder {
private final String identifier;
private final List<Bone> bones = new ArrayList<>();
private Optional<Float> visibleBoundsWidth = Optional.empty();
private Optional<Float> visibleBoundsHeight = Optional.empty();
private Optional<Vector3f> visibleBoundsOffset = Optional.empty();
private Optional<Integer> textureWidth = Optional.empty();
private Optional<Integer> 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<Bone> bones) {
public static final Codec<GeometryDefinition> CODEC = RecordCodecBuilder.create(instance ->
instance.group(
@@ -58,6 +142,59 @@ public record BedrockGeometry(BedrockVersion formatVersion, List<GeometryDefinit
Cube.CODEC.listOf().optionalFieldOf("cubes", List.of()).forGetter(Bone::cubes)
).apply(instance, Bone::new)
);
public static class Builder {
private final String name;
private final List<Cube> cubes = new ArrayList<>();
private Optional<String> 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<GeometryDefinit
private static final Codec<Map<Direction, Face>> FACE_MAP_CODEC = Codec.unboundedMap(Direction.CODEC, Face.CODEC);
public static final Codec<Cube> 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<GeometryDefinit
FACE_MAP_CODEC.optionalFieldOf("uv", Map.of()).forGetter(Cube::faces)
).apply(instance, Cube::new)
);
public static class Builder {
private final Vector3f origin;
private final Vector3f size;
private final Map<Direction, Face> 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<Face> 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)
);
}