package net.minecraft.client.renderer.block.model; import com.google.common.collect.Maps; import com.google.gson.JsonArray; import com.google.gson.JsonDeserializationContext; import com.google.gson.JsonDeserializer; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParseException; import java.lang.reflect.Type; import java.util.Locale; import java.util.Map; import java.util.Map.Entry; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.core.Direction; import net.minecraft.util.GsonHelper; import net.minecraft.util.Mth; import org.jetbrains.annotations.Nullable; import org.joml.Vector3f; import org.joml.Vector3fc; @Environment(EnvType.CLIENT) public record BlockElement( Vector3fc from, Vector3fc to, Map faces, @Nullable BlockElementRotation rotation, boolean shade, int lightEmission ) { private static final boolean DEFAULT_RESCALE = false; private static final float MIN_EXTENT = -16.0F; private static final float MAX_EXTENT = 32.0F; public BlockElement(Vector3fc from, Vector3fc to, Map faces) { this(from, to, faces, null, true, 0); } @Environment(EnvType.CLIENT) protected static class Deserializer implements JsonDeserializer { private static final boolean DEFAULT_SHADE = true; private static final int DEFAULT_LIGHT_EMISSION = 0; public BlockElement deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); Vector3f vector3f = this.getFrom(jsonObject); Vector3f vector3f2 = this.getTo(jsonObject); BlockElementRotation blockElementRotation = this.getRotation(jsonObject); Map map = this.getFaces(context, jsonObject); if (jsonObject.has("shade") && !GsonHelper.isBooleanValue(jsonObject, "shade")) { throw new JsonParseException("Expected shade to be a Boolean"); } else { boolean bl = GsonHelper.getAsBoolean(jsonObject, "shade", true); int i = 0; if (jsonObject.has("light_emission")) { boolean bl2 = GsonHelper.isNumberValue(jsonObject, "light_emission"); if (bl2) { i = GsonHelper.getAsInt(jsonObject, "light_emission"); } if (!bl2 || i < 0 || i > 15) { throw new JsonParseException("Expected light_emission to be an Integer between (inclusive) 0 and 15"); } } return new BlockElement(vector3f, vector3f2, map, blockElementRotation, bl, i); } } @Nullable private BlockElementRotation getRotation(JsonObject json) { BlockElementRotation blockElementRotation = null; if (json.has("rotation")) { JsonObject jsonObject = GsonHelper.getAsJsonObject(json, "rotation"); Vector3f vector3f = this.getVector3f(jsonObject, "origin"); vector3f.mul(0.0625F); Direction.Axis axis = this.getAxis(jsonObject); float f = this.getAngle(jsonObject); boolean bl = GsonHelper.getAsBoolean(jsonObject, "rescale", false); blockElementRotation = new BlockElementRotation(vector3f, axis, f, bl); } return blockElementRotation; } private float getAngle(JsonObject json) { float f = GsonHelper.getAsFloat(json, "angle"); if (f != 0.0F && Mth.abs(f) != 22.5F && Mth.abs(f) != 45.0F) { throw new JsonParseException("Invalid rotation " + f + " found, only -45/-22.5/0/22.5/45 allowed"); } else { return f; } } private Direction.Axis getAxis(JsonObject json) { String string = GsonHelper.getAsString(json, "axis"); Direction.Axis axis = Direction.Axis.byName(string.toLowerCase(Locale.ROOT)); if (axis == null) { throw new JsonParseException("Invalid rotation axis: " + string); } else { return axis; } } private Map getFaces(JsonDeserializationContext context, JsonObject json) { Map map = this.filterNullFromFaces(context, json); if (map.isEmpty()) { throw new JsonParseException("Expected between 1 and 6 unique faces, got 0"); } else { return map; } } private Map filterNullFromFaces(JsonDeserializationContext context, JsonObject json) { Map map = Maps.newEnumMap(Direction.class); JsonObject jsonObject = GsonHelper.getAsJsonObject(json, "faces"); for (Entry entry : jsonObject.entrySet()) { Direction direction = this.getFacing((String)entry.getKey()); map.put(direction, (BlockElementFace)context.deserialize((JsonElement)entry.getValue(), BlockElementFace.class)); } return map; } private Direction getFacing(String name) { Direction direction = Direction.byName(name); if (direction == null) { throw new JsonParseException("Unknown facing: " + name); } else { return direction; } } private Vector3f getTo(JsonObject json) { Vector3f vector3f = this.getVector3f(json, "to"); if (!(vector3f.x() < -16.0F) && !(vector3f.y() < -16.0F) && !(vector3f.z() < -16.0F) && !(vector3f.x() > 32.0F) && !(vector3f.y() > 32.0F) && !(vector3f.z() > 32.0F)) { return vector3f; } else { throw new JsonParseException("'to' specifier exceeds the allowed boundaries: " + vector3f); } } private Vector3f getFrom(JsonObject json) { Vector3f vector3f = this.getVector3f(json, "from"); if (!(vector3f.x() < -16.0F) && !(vector3f.y() < -16.0F) && !(vector3f.z() < -16.0F) && !(vector3f.x() > 32.0F) && !(vector3f.y() > 32.0F) && !(vector3f.z() > 32.0F)) { return vector3f; } else { throw new JsonParseException("'from' specifier exceeds the allowed boundaries: " + vector3f); } } private Vector3f getVector3f(JsonObject json, String memberName) { JsonArray jsonArray = GsonHelper.getAsJsonArray(json, memberName); if (jsonArray.size() != 3) { throw new JsonParseException("Expected 3 " + memberName + " values, found: " + jsonArray.size()); } else { float[] fs = new float[3]; for (int i = 0; i < fs.length; i++) { fs[i] = GsonHelper.convertToFloat(jsonArray.get(i), memberName + "[" + i + "]"); } return new Vector3f(fs[0], fs[1], fs[2]); } } } }