package net.minecraft.client.renderer.block.model; import com.google.common.annotations.VisibleForTesting; import com.google.gson.Gson; import com.google.gson.GsonBuilder; 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.io.Reader; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.List; import net.fabricmc.api.EnvType; import net.fabricmc.api.Environment; import net.minecraft.client.renderer.texture.TextureAtlas; import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.ResolvableModel; import net.minecraft.client.resources.model.SimpleBakedModel; import net.minecraft.client.resources.model.UnbakedModel; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.GsonHelper; import org.jetbrains.annotations.Nullable; @Environment(EnvType.CLIENT) public class BlockModel implements UnbakedModel { @VisibleForTesting static final Gson GSON = new GsonBuilder() .registerTypeAdapter(BlockModel.class, new BlockModel.Deserializer()) .registerTypeAdapter(BlockElement.class, new BlockElement.Deserializer()) .registerTypeAdapter(BlockElementFace.class, new BlockElementFace.Deserializer()) .registerTypeAdapter(BlockFaceUV.class, new BlockFaceUV.Deserializer()) .registerTypeAdapter(ItemTransform.class, new ItemTransform.Deserializer()) .registerTypeAdapter(ItemTransforms.class, new ItemTransforms.Deserializer()) .create(); private final List elements; @Nullable private final UnbakedModel.GuiLight guiLight; @Nullable private final Boolean hasAmbientOcclusion; @Nullable private final ItemTransforms transforms; @VisibleForTesting private final TextureSlots.Data textureSlots; @Nullable private UnbakedModel parent; @Nullable private final ResourceLocation parentLocation; public static BlockModel fromStream(Reader reader) { return GsonHelper.fromJson(GSON, reader, BlockModel.class); } public BlockModel( @Nullable ResourceLocation parentLocation, List elements, TextureSlots.Data textureSlots, @Nullable Boolean hasAmbientOcclusion, @Nullable UnbakedModel.GuiLight guiLight, @Nullable ItemTransforms transforms ) { this.elements = elements; this.hasAmbientOcclusion = hasAmbientOcclusion; this.guiLight = guiLight; this.textureSlots = textureSlots; this.parentLocation = parentLocation; this.transforms = transforms; } @Nullable @Override public Boolean getAmbientOcclusion() { return this.hasAmbientOcclusion; } @Nullable @Override public UnbakedModel.GuiLight getGuiLight() { return this.guiLight; } @Override public void resolveDependencies(ResolvableModel.Resolver resolver) { if (this.parentLocation != null) { this.parent = resolver.resolve(this.parentLocation); } } @Nullable @Override public UnbakedModel getParent() { return this.parent; } @Override public TextureSlots.Data getTextureSlots() { return this.textureSlots; } @Nullable @Override public ItemTransforms getTransforms() { return this.transforms; } @Override public BakedModel bake( TextureSlots textureSlots, ModelBaker baker, ModelState modelState, boolean hasAmbientOcclusion, boolean useBlockLight, ItemTransforms transforms ) { return this.elements.isEmpty() && this.parent != null ? this.parent.bake(textureSlots, baker, modelState, hasAmbientOcclusion, useBlockLight, transforms) : SimpleBakedModel.bakeElements(this.elements, textureSlots, baker.sprites(), modelState, hasAmbientOcclusion, useBlockLight, true, transforms); } @Nullable @VisibleForTesting List getElements() { return this.elements; } @Nullable @VisibleForTesting ResourceLocation getParentLocation() { return this.parentLocation; } @Environment(EnvType.CLIENT) public static class Deserializer implements JsonDeserializer { public BlockModel deserialize(JsonElement json, Type type, JsonDeserializationContext context) throws JsonParseException { JsonObject jsonObject = json.getAsJsonObject(); List list = this.getElements(context, jsonObject); String string = this.getParentName(jsonObject); TextureSlots.Data data = this.getTextureMap(jsonObject); Boolean boolean_ = this.getAmbientOcclusion(jsonObject); ItemTransforms itemTransforms = null; if (jsonObject.has("display")) { JsonObject jsonObject2 = GsonHelper.getAsJsonObject(jsonObject, "display"); itemTransforms = context.deserialize(jsonObject2, ItemTransforms.class); } UnbakedModel.GuiLight guiLight = null; if (jsonObject.has("gui_light")) { guiLight = UnbakedModel.GuiLight.getByName(GsonHelper.getAsString(jsonObject, "gui_light")); } ResourceLocation resourceLocation = string.isEmpty() ? null : ResourceLocation.parse(string); return new BlockModel(resourceLocation, list, data, boolean_, guiLight, itemTransforms); } private TextureSlots.Data getTextureMap(JsonObject json) { if (json.has("textures")) { JsonObject jsonObject = GsonHelper.getAsJsonObject(json, "textures"); return TextureSlots.parseTextureMap(jsonObject, TextureAtlas.LOCATION_BLOCKS); } else { return TextureSlots.Data.EMPTY; } } private String getParentName(JsonObject json) { return GsonHelper.getAsString(json, "parent", ""); } @Nullable protected Boolean getAmbientOcclusion(JsonObject json) { return json.has("ambientocclusion") ? GsonHelper.getAsBoolean(json, "ambientocclusion") : null; } protected List getElements(JsonDeserializationContext context, JsonObject json) { if (!json.has("elements")) { return List.of(); } else { List list = new ArrayList(); for (JsonElement jsonElement : GsonHelper.getAsJsonArray(json, "elements")) { list.add((BlockElement)context.deserialize(jsonElement, BlockElement.class)); } return list; } } } }