diff --git a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch index 8c657d02ad..67e10c0dab 100644 --- a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch @@ -38,12 +38,12 @@ } } -+ /** @deprecated Forge: Use {@link net.minecraftforge.client.RenderTypeHelper#getEntityRenderType(RenderType, boolean)} while iterating through {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */ ++ /** @deprecated Forge: Use {@link net.minecraftforge.client.RenderTypeHelper#getEntityRenderType(RenderType)} while iterating through {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */ + @Deprecated // Note: this method does NOT support model-based render types public static RenderType getRenderType(BlockState p_364446_) { RenderType rendertype = getChunkRenderType(p_364446_); return rendertype == RenderType.translucent() ? Sheets.translucentItemSheet() : Sheets.cutoutBlockSheet(); -@@ -385,12 +_,77 @@ +@@ -385,12 +_,82 @@ } } @@ -59,6 +59,11 @@ renderCutout = p_109292_; + } + ++ /** Forge: Check if we are running in {@linkplain net.minecraft.client.Minecraft#useFancyGraphics() fancy graphics} to account for fast graphics render types */ ++ public static boolean isFancy() { ++ return renderCutout; ++ } ++ + private static final net.minecraftforge.client.ChunkRenderTypeSet CUTOUT_MIPPED = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.cutoutMipped()); + private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID = net.minecraftforge.client.ChunkRenderTypeSet.of(RenderType.solid()); + private static final Map, net.minecraftforge.client.ChunkRenderTypeSet> BLOCK_RENDER_TYPES = Util.make(new it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap<>(TYPE_BY_BLOCK.size(), 0.5F), map -> { @@ -75,7 +80,7 @@ + }); + + /** @deprecated Use {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)}. */ -+ //@Deprecated(since = "1.19", forRemoval = true) ++ @Deprecated(since = "1.21.4", forRemoval = true) + public static net.minecraftforge.client.ChunkRenderTypeSet getRenderLayers(BlockState state) { + Block block = state.getBlock(); + if (block instanceof LeavesBlock) { @@ -86,20 +91,20 @@ + } + + /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ -+ //@Deprecated(since = "1.19", forRemoval = true) ++ @Deprecated(since = "1.21.4", forRemoval = true) + public static void setRenderLayer(Block block, RenderType type) { + com.google.common.base.Preconditions.checkArgument(type.getChunkLayerId() >= 0, "The argument must be a valid chunk render type returned by RenderType#chunkBufferLayers()."); + setRenderLayer(block, net.minecraftforge.client.ChunkRenderTypeSet.of(type)); + } + + /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ -+ //@Deprecated(since = "1.19", forRemoval = true) ++ @Deprecated(since = "1.21.4", forRemoval = true) + public static synchronized void setRenderLayer(Block block, java.util.function.Predicate predicate) { + setRenderLayer(block, createSetFromPredicate(predicate)); + } + + /** @deprecated Set your render type in your block model's JSON (eg. {@code "render_type": "cutout"}) or override {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(BlockState, net.minecraft.util.RandomSource, net.minecraftforge.client.model.data.ModelData)} */ -+ //@Deprecated(since = "1.19", forRemoval = true) ++ @Deprecated(since = "1.21.4", forRemoval = true) + public static synchronized void setRenderLayer(Block block, net.minecraftforge.client.ChunkRenderTypeSet layers) { + checkClientLoading(); + BLOCK_RENDER_TYPES.put(net.minecraftforge.registries.ForgeRegistries.BLOCKS.getDelegateOrThrow(block), layers); diff --git a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch index 12a2fc2bc1..1f8f88ac68 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch @@ -1,74 +1,142 @@ --- a/net/minecraft/client/resources/model/SimpleBakedModel.java +++ b/net/minecraft/client/resources/model/SimpleBakedModel.java -@@ -25,6 +_,15 @@ +@@ -25,7 +_,32 @@ protected final boolean usesBlockLight; protected final TextureAtlasSprite particleIcon; protected final ItemTransforms transforms; +- ++ /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} */ + protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypes; ++ /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */ ++ protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypesFast; ++ /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} */ + protected final List itemRenderTypes; ++ /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */ ++ protected final List itemRenderTypesFast; ++ /** Forge: Item render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FABULOUS fabulous graphics} */ + protected final List fabulousItemRenderTypes; ++ /** Forge: If this model's {@linkplain #blockRenderTypes block render types} are rendering cutout, to account for older leaves model JSONs */ ++ protected final boolean isRenderingCutout; + -+ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/ ++ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup} **/ + @Deprecated + public SimpleBakedModel(List p_119489_, Map> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_) { + this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, net.minecraftforge.client.RenderTypeGroup.EMPTY); + } - ++ ++ /** @deprecated Forge: Use {@linkplain #SimpleBakedModel(List, Map, boolean, boolean, boolean, TextureAtlasSprite, ItemTransforms, net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) variant with RenderTypeGroup for fast graphics} **/ ++ @Deprecated(forRemoval = true, since = "1.21.4") ++ public SimpleBakedModel(List p_119489_, Map> p_119490_, boolean p_119491_, boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, ItemTransforms p_119495_, net.minecraftforge.client.RenderTypeGroup renderTypes) { ++ this(p_119489_, p_119490_, p_119491_, p_119492_, p_119493_, p_119494_, p_119495_, renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY); ++ } ++ ++ /** Constructor with {@link net.minecraftforge.client.RenderTypeGroup RenderTypeGroup} for fancy and fast graphics. Preferred over {@link net.minecraft.client.renderer.ItemBlockRenderTypes#setRenderLayer(net.minecraft.world.level.block.Block, net.minecraft.client.renderer.RenderType) ItemBlockRenderTypes.setRenderLayer(Block, RenderType)}. */ public SimpleBakedModel( List p_119489_, -@@ -33,7 +_,8 @@ + Map> p_119490_, +@@ -33,7 +_,9 @@ boolean p_119492_, boolean p_119493_, TextureAtlasSprite p_119494_, - ItemTransforms p_119495_ + ItemTransforms p_119495_, -+ net.minecraftforge.client.RenderTypeGroup renderTypes ++ net.minecraftforge.client.RenderTypeGroup renderTypes, ++ net.minecraftforge.client.RenderTypeGroup renderTypesFast ) { this.unculledFaces = p_119489_; this.culledFaces = p_119490_; -@@ -42,6 +_,9 @@ +@@ -42,6 +_,15 @@ this.usesBlockLight = p_119492_; this.particleIcon = p_119494_; this.transforms = p_119495_; -+ this.blockRenderTypes = !renderTypes.isEmpty() ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null; -+ this.itemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entity()) : null; -+ this.fabulousItemRenderTypes = !renderTypes.isEmpty() ? List.of(renderTypes.entityFabulous()) : null; ++ ++ boolean hasRenderTypes = renderTypes != null && !renderTypes.isEmpty(); ++ boolean hasRenderTypesFast = renderTypesFast != null && !renderTypesFast.isEmpty(); ++ this.blockRenderTypes = hasRenderTypes ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypes.block()) : null; ++ this.blockRenderTypesFast = hasRenderTypesFast ? net.minecraftforge.client.ChunkRenderTypeSet.of(renderTypesFast.block()) : null; ++ this.itemRenderTypes = hasRenderTypes ? List.of(renderTypes.entity()) : null; ++ this.itemRenderTypesFast = hasRenderTypesFast ? List.of(renderTypesFast.entity()) : null; ++ this.fabulousItemRenderTypes = hasRenderTypes ? List.of(renderTypes.entityFabulous()) : null; ++ this.isRenderingCutout = hasRenderTypes && (renderTypes.block() == net.minecraft.client.renderer.RenderType.cutout() || renderTypes.block() == net.minecraft.client.renderer.RenderType.cutoutMipped()); } @Override -@@ -79,6 +_,25 @@ +@@ -79,6 +_,38 @@ return this.transforms; } ++ private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID_BLOCK = net.minecraftforge.client.ChunkRenderTypeSet.of(net.minecraft.client.renderer.RenderType.solid()); ++ private static final List SOLID_BLOCK_ITEM = List.of(net.minecraft.client.renderer.RenderType.solid()); ++ + @Override + public net.minecraftforge.client.ChunkRenderTypeSet getRenderTypes(BlockState state, RandomSource rand, net.minecraftforge.client.model.data.ModelData data) { -+ return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data); ++ if (!net.minecraft.client.renderer.ItemBlockRenderTypes.isFancy()) { ++ if (blockRenderTypesFast != null) ++ return blockRenderTypesFast; ++ if (isRenderingCutout && state.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock) ++ return SOLID_BLOCK; ++ } ++ return blockRenderTypes != null ? blockRenderTypes : BakedModel.super.getRenderTypes(state, rand, data); + } + + @Override + public List getRenderTypes(net.minecraft.world.item.ItemStack itemStack, boolean fabulous) { -+ if (!fabulous) { -+ if (itemRenderTypes != null) { -+ return itemRenderTypes; -+ } -+ } else { -+ if (fabulousItemRenderTypes != null) { -+ return fabulousItemRenderTypes; -+ } -+ } -+ return BakedModel.super.getRenderTypes(itemStack, fabulous); ++ if (!fabulous) { ++ if (!net.minecraft.client.renderer.ItemBlockRenderTypes.isFancy()) { ++ if (itemRenderTypesFast != null) ++ return itemRenderTypesFast; ++ if (isRenderingCutout && itemStack.getItem() instanceof net.minecraft.world.item.BlockItem blockItem && blockItem.getBlock() instanceof net.minecraft.world.level.block.LeavesBlock) ++ return SOLID_BLOCK_ITEM; ++ } ++ if (itemRenderTypes != null) ++ return itemRenderTypes; ++ } else { ++ if (fabulousItemRenderTypes != null) ++ return fabulousItemRenderTypes; ++ } ++ return BakedModel.super.getRenderTypes(itemStack, fabulous); + } + @OnlyIn(Dist.CLIENT) public static class Builder { private final ImmutableList.Builder unculledFaces = ImmutableList.builder(); -@@ -124,13 +_,19 @@ +@@ -124,13 +_,50 @@ return this; } + private net.minecraftforge.client.RenderTypeGroup renderTypes = net.minecraftforge.client.RenderTypeGroup.EMPTY; ++ private net.minecraftforge.client.RenderTypeGroup renderTypesFast = net.minecraftforge.client.RenderTypeGroup.EMPTY; ++ ++ /** ++ * Sets the render type to be used for this model, and will be used for any graphics setting. ++ *

++ * If you need to set a specific render type for ++ * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}, consider using ++ * {@link #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) ++ * renderTypes(RenderTypeGroup, RenderTypeGroup)} instead which allows choosing render types for both fancy and ++ * fast graphics. ++ * ++ * @apiNote If this model is for {@linkplain net.minecraft.world.level.block.LeavesBlock leaves} and if the ++ * given render type is either {@linkplain net.minecraft.client.renderer.RenderType#cutout() cutout} or ++ * {@linkplain net.minecraft.client.renderer.RenderType#cutoutMipped() cutout mipped}, it will be overridden ++ * with {@linkplain net.minecraft.client.renderer.RenderType#solid() solid} when fast graphics is enabled. ++ * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup, net.minecraftforge.client.RenderTypeGroup) ++ * renderTypes(RenderTypeGroup, RenderTypeGroup) ++ */ + public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes) { ++ return this.renderTypes(renderTypes, net.minecraftforge.client.RenderTypeGroup.EMPTY); ++ } ++ ++ /** ++ * Sets the render types to be used for this model: one for ++ * {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} and one for ++ * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}. ++ * ++ * @see #renderTypes(net.minecraftforge.client.RenderTypeGroup) ++ */ ++ public SimpleBakedModel.Builder renderTypes(net.minecraftforge.client.RenderTypeGroup renderTypes, net.minecraftforge.client.RenderTypeGroup renderTypesFast) { + this.renderTypes = renderTypes; ++ this.renderTypesFast = renderTypesFast; + return this; + } + @@ -79,7 +147,8 @@ Map> map = Maps.transformValues(this.culledFaces, ImmutableList.Builder::build); return new SimpleBakedModel( - this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms -+ this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.renderTypes ++ // Forge: Account for render types in model JSONs ++ this.unculledFaces.build(), new EnumMap<>(map), this.hasAmbientOcclusion, this.usesBlockLight, this.isGui3d, this.particleIcon, this.transforms, this.renderTypes, this.renderTypesFast ); } } diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java index 806734bd6d..cae962b372 100644 --- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -208,6 +208,7 @@ public class CompositeModel implements IUnbakedGeometry { private final ItemTransforms transforms; private TextureAtlasSprite particle; private RenderTypeGroup lastRenderTypes = RenderTypeGroup.EMPTY; + private RenderTypeGroup lastRenderTypesFast = RenderTypeGroup.EMPTY; private Builder(boolean isAmbientOcclusion, boolean isGui3d, boolean isSideLit, TextureAtlasSprite particle, ItemTransforms transforms) { this.isAmbientOcclusion = isAmbientOcclusion; @@ -218,23 +219,32 @@ public class CompositeModel implements IUnbakedGeometry { } public void addLayer(BakedModel model) { - flushQuads(null); + flushQuads(RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY); children.add(model); } private void addLayer(RenderTypeGroup renderTypes, List quads) { - var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle, renderTypes); + this.addLayer(renderTypes, RenderTypeGroup.EMPTY, quads); + } + + private void addLayer(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, List quads) { + var modelBuilder = IModelBuilder.of(isAmbientOcclusion, isSideLit, isGui3d, transforms, particle, renderTypes, renderTypesFast); quads.forEach(modelBuilder::addUnculledFace); children.add(modelBuilder.build()); } private void flushQuads(RenderTypeGroup renderTypes) { + this.flushQuads(renderTypes, RenderTypeGroup.EMPTY); + } + + private void flushQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast) { if (!Objects.equals(renderTypes, lastRenderTypes)) { if (!quads.isEmpty()) { - addLayer(lastRenderTypes, quads); + addLayer(lastRenderTypes, lastRenderTypesFast, quads); quads.clear(); } lastRenderTypes = renderTypes; + lastRenderTypesFast = renderTypesFast; } } @@ -244,20 +254,28 @@ public class CompositeModel implements IUnbakedGeometry { } public Builder addQuads(RenderTypeGroup renderTypes, BakedQuad... quadsToAdd) { - flushQuads(renderTypes); + return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd); + } + + public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, BakedQuad... quadsToAdd) { + flushQuads(renderTypes, renderTypesFast); Collections.addAll(quads, quadsToAdd); return this; } public Builder addQuads(RenderTypeGroup renderTypes, Collection quadsToAdd) { - flushQuads(renderTypes); + return this.addQuads(renderTypes, RenderTypeGroup.EMPTY, quadsToAdd); + } + + public Builder addQuads(RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast, Collection quadsToAdd) { + flushQuads(renderTypes, renderTypesFast); quads.addAll(quadsToAdd); return this; } public BakedModel build() { if (!quads.isEmpty()) { - addLayer(lastRenderTypes, quads); + addLayer(lastRenderTypes, lastRenderTypesFast, quads); } var childrenBuilder = ImmutableMap.builder(); var itemPassesBuilder = ImmutableList.builder(); diff --git a/src/main/java/net/minecraftforge/client/model/EmptyModel.java b/src/main/java/net/minecraftforge/client/model/EmptyModel.java index 3f0b4c5821..98492e06f0 100644 --- a/src/main/java/net/minecraftforge/client/model/EmptyModel.java +++ b/src/main/java/net/minecraftforge/client/model/EmptyModel.java @@ -50,7 +50,7 @@ public class EmptyModel extends SimpleUnbakedGeometry { private static final Material MISSING_TEXTURE = new Material(InventoryMenu.BLOCK_ATLAS, MissingTextureAtlasSprite.getLocation()); public Baked() { - super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, RenderTypeGroup.EMPTY); + super(List.of(), Map.of(), false, false, false, UnitTextureAtlasSprite.INSTANCE, ItemTransforms.NO_TRANSFORMS, RenderTypeGroup.EMPTY, RenderTypeGroup.EMPTY); } @Override diff --git a/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java index 59999748d9..41991f9c4a 100644 --- a/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java +++ b/src/main/java/net/minecraftforge/client/model/ExtendedBlockModelDeserializer.java @@ -73,6 +73,12 @@ public class ExtendedBlockModelDeserializer extends BlockModel.Deserializer model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName)); } + if (jsonobject.has("render_type_fast")) + { + var renderTypeHintName = GsonHelper.getAsString(jsonobject, "render_type_fast"); + model.customData.setRenderTypeFastHint(ResourceLocation.parse(renderTypeHintName)); + } + if (jsonobject.has("visibility")) { JsonObject visibility = GsonHelper.getAsJsonObject(jsonobject, "visibility"); diff --git a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java index a00dc67e39..ad9c9c335a 100644 --- a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java @@ -32,6 +32,18 @@ public interface IModelBuilder> { return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes); } + static IModelBuilder of( + boolean hasAmbientOcclusion, + boolean usesBlockLight, + boolean isGui3d, + ItemTransforms transforms, + TextureAtlasSprite particle, + RenderTypeGroup renderTypes, + RenderTypeGroup renderTypesFast + ){ + return new Simple(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes, renderTypesFast); + } + /** * Creates a new model builder that collects quads to the provided list, returning * {@linkplain EmptyModel#BAKED an empty model} if you call {@link #build()}. @@ -49,12 +61,20 @@ public interface IModelBuilder> { class Simple implements IModelBuilder { private final SimpleBakedModel.Builder builder; private final RenderTypeGroup renderTypes; + private final RenderTypeGroup renderTypesFast; private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d, ItemTransforms transforms, TextureAtlasSprite particle, RenderTypeGroup renderTypes + ) { + this(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms, particle, renderTypes, RenderTypeGroup.EMPTY); + } + + private Simple(boolean hasAmbientOcclusion, boolean usesBlockLight, boolean isGui3d, + ItemTransforms transforms, TextureAtlasSprite particle, RenderTypeGroup renderTypes, RenderTypeGroup renderTypesFast ) { this.builder = new SimpleBakedModel.Builder(hasAmbientOcclusion, usesBlockLight, isGui3d, transforms).particle(particle); this.renderTypes = renderTypes; + this.renderTypesFast = renderTypesFast; } @Override diff --git a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java index 31f583562b..5e8d072c17 100644 --- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java @@ -39,10 +39,16 @@ public class ItemLayerModel implements IUnbakedGeometry { @Nullable private ImmutableList textures; private final Int2ObjectMap renderTypeNames; + private final Int2ObjectMap renderTypeFastNames; private ItemLayerModel(@Nullable ImmutableList textures, Int2ObjectMap renderTypeNames) { + this(textures, renderTypeNames, new Int2ObjectOpenHashMap<>()); + } + + private ItemLayerModel(@Nullable ImmutableList textures, Int2ObjectMap renderTypeNames, Int2ObjectMap renderTypeFastNames) { this.textures = textures; this.renderTypeNames = renderTypeNames; + this.renderTypeFastNames = renderTypeFastNames; } @Override @@ -69,7 +75,9 @@ public class ItemLayerModel implements IUnbakedGeometry { var quads = UnbakedGeometryHelper.bakeElements(unbaked, $ -> sprite, modelState); var renderTypeName = renderTypeNames.get(i); var renderTypes = renderTypeName != null ? context.getRenderType(renderTypeName) : null; - builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, quads); + var renderTypeFastName = renderTypeFastNames.get(i); + var renderTypesFast = renderTypeFastName != null ? context.getRenderType(renderTypeFastName) : null; + builder.addQuads(renderTypes != null ? renderTypes : normalRenderTypes, renderTypesFast != null ? renderTypesFast : RenderTypeGroup.EMPTY, quads); } return builder.build(); @@ -80,20 +88,27 @@ public class ItemLayerModel implements IUnbakedGeometry { @Override public ItemLayerModel read(JsonObject jsonObject, JsonDeserializationContext deserializationContext) { + var renderTypeNames = readRenderTypeNames(jsonObject, "render_types"); + var renderTypeFastNames = readRenderTypeNames(jsonObject, "render_types_fast"); + return new ItemLayerModel(null, renderTypeNames, renderTypeFastNames); + } + + private static Int2ObjectMap readRenderTypeNames(JsonObject jsonObject, String key) { var renderTypeNames = new Int2ObjectOpenHashMap(); - if (jsonObject.has("render_types")) { - var renderTypes = jsonObject.getAsJsonObject("render_types"); + if (jsonObject.has(key)) { + var renderTypes = jsonObject.getAsJsonObject(key); for (var entry : renderTypes.entrySet()) { var renderType = ResourceLocation.parse(entry.getKey()); for (var layer : entry.getValue().getAsJsonArray()) if (renderTypeNames.put(layer.getAsInt(), renderType) != null) - throw new JsonParseException("Registered duplicate render type for layer " + layer); + throw new JsonParseException("Registered duplicate " + key + " for layer " + layer); } } - return new ItemLayerModel(null, renderTypeNames); + return renderTypeNames; } + @Deprecated(forRemoval = true, since = "1.21.4") protected void readLayerData(JsonObject jsonObject, String name, Int2ObjectOpenHashMap renderTypeNames, Int2ObjectMap layerData, boolean logWarning) { if (!jsonObject.has(name)) return; diff --git a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java index e3e7d64fde..30a144047f 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java @@ -250,6 +250,42 @@ public abstract class BlockStateProvider implements DataProvider { models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType)); } + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast); + } + + public void logBlockWithRenderTypeAndFast(RotatedPillarBlock block, String renderType, String renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast); + } + + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, String renderType, String renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast); + } + + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, String renderType, String renderTypeFast) { + axisBlock(block, + models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast), + models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast)); + } + + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, blockTexture(block), renderType, renderTypeFast); + } + + public void logBlockWithRenderType(RotatedPillarBlock block, ResourceLocation renderType, ResourceLocation renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, blockTexture(block), extend(blockTexture(block), "_top"), renderType, renderTypeFast); + } + + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation baseName, ResourceLocation renderType, ResourceLocation renderTypeFast) { + axisBlockWithRenderTypeAndFast(block, extend(baseName, "_side"), extend(baseName, "_end"), renderType, renderTypeFast); + } + + public void axisBlockWithRenderTypeAndFast(RotatedPillarBlock block, ResourceLocation side, ResourceLocation end, ResourceLocation renderType, ResourceLocation renderTypeFast) { + axisBlock(block, + models().cubeColumn(name(block), side, end).renderType(renderType, renderTypeFast), + models().cubeColumnHorizontal(name(block) + "_horizontal", side, end).renderType(renderType, renderTypeFast)); + } + public void axisBlock(RotatedPillarBlock block, ModelFile vertical, ModelFile horizontal) { getVariantBuilder(block) .partialState().with(RotatedPillarBlock.AXIS, Axis.Y) @@ -381,6 +417,38 @@ public abstract class BlockStateProvider implements DataProvider { stairsBlockInternalWithRenderType(block, name + "_stairs", side, bottom, top, renderType); } + public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, String renderType, String renderTypeFast) { + stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) { + stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) { + stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) { + stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + stairsBlockWithRenderTypeAndFast(block, texture, texture, texture, renderType, renderTypeFast); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + stairsBlockWithRenderTypeAndFast(block, name, texture, texture, texture, renderType, renderTypeFast); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + stairsBlockInternalWithRenderTypeAndFast(block, key(block).toString(), side, bottom, top, renderType, renderTypeFast); + } + + public void stairsBlockWithRenderTypeAndFast(StairBlock block, String name, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + stairsBlockInternalWithRenderTypeAndFast(block, name + "_stairs", side, bottom, top, renderType, renderTypeFast); + } + private void stairsBlockInternal(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top) { ModelFile stairs = models().stairs(baseName, side, bottom, top); ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top); @@ -395,6 +463,13 @@ public abstract class BlockStateProvider implements DataProvider { stairsBlock(block, stairs, stairsInner, stairsOuter); } + private void stairsBlockInternalWithRenderTypeAndFast(StairBlock block, String baseName, ResourceLocation side, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + ModelFile stairs = models().stairs(baseName, side, bottom, top).renderType(renderType, renderTypeFast); + ModelFile stairsInner = models().stairsInner(baseName + "_inner", side, bottom, top).renderType(renderType, renderTypeFast); + ModelFile stairsOuter = models().stairsOuter(baseName + "_outer", side, bottom, top).renderType(renderType, renderTypeFast); + stairsBlock(block, stairs, stairsInner, stairsOuter); + } + public void stairsBlock(StairBlock block, ModelFile stairs, ModelFile stairsInner, ModelFile stairsOuter) { getVariantBuilder(block) .forAllStatesExcept(state -> { @@ -532,6 +607,32 @@ public abstract class BlockStateProvider implements DataProvider { models().fenceSide(name + "_fence_side", texture).renderType(renderType)); } + public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, String renderType, String renderTypeFast) { + String baseName = key(block).toString(); + fourWayBlock(block, + models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast), + models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast)); + } + + public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) { + fourWayBlock(block, + models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast), + models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast)); + } + + public void fenceBlockWithRenderTypeAndFast(FenceBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + String baseName = key(block).toString(); + fourWayBlock(block, + models().fencePost(baseName + "_post", texture).renderType(renderType, renderTypeFast), + models().fenceSide(baseName + "_side", texture).renderType(renderType, renderTypeFast)); + } + + public void fenceBlockWithRenderTypeAndFast(FenceBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + fourWayBlock(block, + models().fencePost(name + "_fence_post", texture).renderType(renderType, renderTypeFast), + models().fenceSide(name + "_fence_side", texture).renderType(renderType, renderTypeFast)); + } + public void fenceGateBlock(FenceGateBlock block, ResourceLocation texture) { fenceGateBlockInternal(block, key(block).toString(), texture); } @@ -556,6 +657,22 @@ public abstract class BlockStateProvider implements DataProvider { fenceGateBlockInternalWithRenderType(block, name + "_fence_gate", texture, renderType); } + public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, String renderType, String renderTypeFast) { + fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) { + fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + fenceGateBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast); + } + + public void fenceGateBlockWithRenderTypeAndFast(FenceGateBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + fenceGateBlockInternalWithRenderTypeAndFast(block, name + "_fence_gate", texture, renderType, renderTypeFast); + } + private void fenceGateBlockInternal(FenceGateBlock block, String baseName, ResourceLocation texture) { ModelFile gate = models().fenceGate(baseName, texture); ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture); @@ -572,6 +689,14 @@ public abstract class BlockStateProvider implements DataProvider { fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen); } + private void fenceGateBlockInternalWithRenderTypeAndFast(FenceGateBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + ModelFile gate = models().fenceGate(baseName, texture).renderType(renderType, renderTypeFast); + ModelFile gateOpen = models().fenceGateOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast); + ModelFile gateWall = models().fenceGateWall(baseName + "_wall", texture).renderType(renderType, renderTypeFast); + ModelFile gateWallOpen = models().fenceGateWallOpen(baseName + "_wall_open", texture).renderType(renderType, renderTypeFast); + fenceGateBlock(block, gate, gateOpen, gateWall, gateWallOpen); + } + public void fenceGateBlock(FenceGateBlock block, ModelFile gate, ModelFile gateOpen, ModelFile gateWall, ModelFile gateWallOpen) { getVariantBuilder(block).forAllStatesExcept(state -> { ModelFile model = gate; @@ -613,6 +738,22 @@ public abstract class BlockStateProvider implements DataProvider { wallBlockInternalWithRenderType(block, name + "_wall", texture, renderType); } + public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, String renderType, String renderTypeFast) { + wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, String renderType, String renderTypeFast) { + wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void wallBlockWithRenderTypeAndFast(WallBlock block, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + wallBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, renderType, renderTypeFast); + } + + public void wallBlockWithRenderTypeAndFast(WallBlock block, String name, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + wallBlockInternalWithRenderTypeAndFast(block, name + "_wall", texture, renderType, renderTypeFast); + } + private void wallBlockInternal(WallBlock block, String baseName, ResourceLocation texture) { wallBlock(block, models().wallPost(baseName + "_post", texture), models().wallSide(baseName + "_side", texture), @@ -625,6 +766,12 @@ public abstract class BlockStateProvider implements DataProvider { models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType)); } + private void wallBlockInternalWithRenderTypeAndFast(WallBlock block, String baseName, ResourceLocation texture, ResourceLocation renderType, ResourceLocation renderTypeFast) { + wallBlock(block, models().wallPost(baseName + "_post", texture).renderType(renderType, renderTypeFast), + models().wallSide(baseName + "_side", texture).renderType(renderType, renderTypeFast), + models().wallSideTall(baseName + "_side_tall", texture).renderType(renderType, renderTypeFast)); + } + public static final ImmutableMap> WALL_PROPS = ImmutableMap.>builder() .put(Direction.EAST, BlockStateProperties.EAST_WALL) .put(Direction.NORTH, BlockStateProperties.NORTH_WALL) @@ -677,6 +824,22 @@ public abstract class BlockStateProvider implements DataProvider { paneBlockInternalWithRenderType(block, name + "_pane", pane, edge, renderType); } + public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) { + paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, String renderType, String renderTypeFast) { + paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) { + paneBlockInternalWithRenderTypeAndFast(block, key(block).toString(), pane, edge, renderType, renderTypeFast); + } + + public void paneBlockWithRenderTypeAndFast(IronBarsBlock block, String name, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) { + paneBlockInternalWithRenderTypeAndFast(block, name + "_pane", pane, edge, renderType, renderTypeFast); + } + private void paneBlockInternal(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge) { ModelFile post = models().panePost(baseName + "_post", pane, edge); ModelFile side = models().paneSide(baseName + "_side", pane, edge); @@ -695,6 +858,15 @@ public abstract class BlockStateProvider implements DataProvider { paneBlock(block, post, side, sideAlt, noSide, noSideAlt); } + private void paneBlockInternalWithRenderTypeAndFast(IronBarsBlock block, String baseName, ResourceLocation pane, ResourceLocation edge, ResourceLocation renderType, ResourceLocation renderTypeFast) { + ModelFile post = models().panePost(baseName + "_post", pane, edge).renderType(renderType, renderTypeFast); + ModelFile side = models().paneSide(baseName + "_side", pane, edge).renderType(renderType, renderTypeFast); + ModelFile sideAlt = models().paneSideAlt(baseName + "_side_alt", pane, edge).renderType(renderType, renderTypeFast); + ModelFile noSide = models().paneNoSide(baseName + "_noside", pane).renderType(renderType, renderTypeFast); + ModelFile noSideAlt = models().paneNoSideAlt(baseName + "_noside_alt", pane).renderType(renderType, renderTypeFast); + paneBlock(block, post, side, sideAlt, noSide, noSideAlt); + } + public void paneBlock(IronBarsBlock block, ModelFile post, ModelFile side, ModelFile sideAlt, ModelFile noSide, ModelFile noSideAlt) { MultiPartBlockStateBuilder builder = getMultipartBuilder(block) .part().modelFile(post).addModel().end(); @@ -734,6 +906,22 @@ public abstract class BlockStateProvider implements DataProvider { doorBlockInternalWithRenderType(block, name + "_door", bottom, top, renderType); } + public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) { + doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, String renderType, String renderTypeFast) { + doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void doorBlockWithRenderTypeAndFast(DoorBlock block, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + doorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), bottom, top, renderType, renderTypeFast); + } + + public void doorBlockWithRenderTypeAndFast(DoorBlock block, String name, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + doorBlockInternalWithRenderTypeAndFast(block, name + "_door", bottom, top, renderType, renderTypeFast); + } + private void doorBlockInternal(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top) { ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top); ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top); @@ -758,6 +946,18 @@ public abstract class BlockStateProvider implements DataProvider { doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen); } + private void doorBlockInternalWithRenderTypeAndFast(DoorBlock block, String baseName, ResourceLocation bottom, ResourceLocation top, ResourceLocation renderType, ResourceLocation renderTypeFast) { + ModelFile bottomLeft = models().doorBottomLeft(baseName + "_bottom_left", bottom, top).renderType(renderType, renderTypeFast); + ModelFile bottomLeftOpen = models().doorBottomLeftOpen(baseName + "_bottom_left_open", bottom, top).renderType(renderType, renderTypeFast); + ModelFile bottomRight = models().doorBottomRight(baseName + "_bottom_right", bottom, top).renderType(renderType, renderTypeFast); + ModelFile bottomRightOpen = models().doorBottomRightOpen(baseName + "_bottom_right_open", bottom, top).renderType(renderType, renderTypeFast); + ModelFile topLeft = models().doorTopLeft(baseName + "_top_left", bottom, top).renderType(renderType, renderTypeFast); + ModelFile topLeftOpen = models().doorTopLeftOpen(baseName + "_top_left_open", bottom, top).renderType(renderType, renderTypeFast); + ModelFile topRight = models().doorTopRight(baseName + "_top_right", bottom, top).renderType(renderType, renderTypeFast); + ModelFile topRightOpen = models().doorTopRightOpen(baseName + "_top_right_open", bottom, top).renderType(renderType, renderTypeFast); + doorBlock(block, bottomLeft, bottomLeftOpen, bottomRight, bottomRightOpen, topLeft, topLeftOpen, topRight, topRightOpen); + } + public void doorBlock(DoorBlock block, ModelFile bottomLeft, ModelFile bottomLeftOpen, ModelFile bottomRight, ModelFile bottomRightOpen, ModelFile topLeft, ModelFile topLeftOpen, ModelFile topRight, ModelFile topRightOpen) { getVariantBuilder(block).forAllStatesExcept(state -> { int yRot = ((int) state.getValue(DoorBlock.FACING).toYRot()) + 90; @@ -824,6 +1024,22 @@ public abstract class BlockStateProvider implements DataProvider { trapdoorBlockInternalWithRenderType(block, name + "_trapdoor", texture, orientable, renderType); } + public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) { + trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, String renderType, String renderTypeFast) { + trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, ResourceLocation.tryParse(renderType), ResourceLocation.tryParse(renderTypeFast)); + } + + public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) { + trapdoorBlockInternalWithRenderTypeAndFast(block, key(block).toString(), texture, orientable, renderType, renderTypeFast); + } + + public void trapdoorBlockWithRenderTypeAndFast(TrapDoorBlock block, String name, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) { + trapdoorBlockInternalWithRenderTypeAndFast(block, name + "_trapdoor", texture, orientable, renderType, renderTypeFast); + } + private void trapdoorBlockInternal(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable) { ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture) : models().trapdoorBottom(baseName + "_bottom", texture); ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture) : models().trapdoorTop(baseName + "_top", texture); @@ -838,6 +1054,13 @@ public abstract class BlockStateProvider implements DataProvider { trapdoorBlock(block, bottom, top, open, orientable); } + private void trapdoorBlockInternalWithRenderTypeAndFast(TrapDoorBlock block, String baseName, ResourceLocation texture, boolean orientable, ResourceLocation renderType, ResourceLocation renderTypeFast) { + ModelFile bottom = orientable ? models().trapdoorOrientableBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast) : models().trapdoorBottom(baseName + "_bottom", texture).renderType(renderType, renderTypeFast); + ModelFile top = orientable ? models().trapdoorOrientableTop(baseName + "_top", texture).renderType(renderType, renderTypeFast) : models().trapdoorTop(baseName + "_top", texture).renderType(renderType, renderTypeFast); + ModelFile open = orientable ? models().trapdoorOrientableOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast) : models().trapdoorOpen(baseName + "_open", texture).renderType(renderType, renderTypeFast); + trapdoorBlock(block, bottom, top, open, orientable); + } + public void trapdoorBlock(TrapDoorBlock block, ModelFile bottom, ModelFile top, ModelFile open, boolean orientable) { getVariantBuilder(block).forAllStatesExcept(state -> { int xRot = 0; diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java index 6237e051cd..489b2bd956 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java @@ -60,6 +60,7 @@ public class ModelBuilder> extends ModelFile { protected final ExistingFileHelper existingFileHelper; protected String renderType = null; + protected String renderTypeFast = null; protected boolean ambientOcclusion = true; protected GuiLight guiLight = null; @@ -149,12 +150,17 @@ public class ModelBuilder> extends ModelFile { } /** - * Set the render type for this model. + * Set the render type for this model. Any render types to be used must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}. + *

+ * Consider using {@linkplain #renderType(String, String)} if you need to set a render type for + * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}. * - * @param renderType the render type. Must be registered via - * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @param renderType the render type * @return this builder - * @throws NullPointerException if {@code renderType} is {@code null} + * + * @throws NullPointerException if {@code renderType} is {@code null} + * @see #renderType(String, String) */ public T renderType(String renderType) { Preconditions.checkNotNull(renderType, "Render type must not be null"); @@ -162,16 +168,55 @@ public class ModelBuilder> extends ModelFile { } /** - * Set the render type for this model. + * Set the render types for this model. Any render types to be used must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}. * - * @param renderType the render type. Must be registered via - * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent} + * @param renderType the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} + * @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} * @return this builder - * @throws NullPointerException if {@code renderType} is {@code null} + * + * @throws NullPointerException if {@code renderType} is {@code null} + */ + public T renderType(String renderType, String renderTypeFast) { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + return renderType(ResourceLocation.parse(renderType), ResourceLocation.parse(renderTypeFast)); + } + + /** + * Set the render type for this model. Any render types to be used must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}. + *

+ * Consider using {@linkplain #renderType(ResourceLocation, ResourceLocation)} if you need to set a render type for + * {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics}. + * + * @param renderType the render type + * @return this builder + * + * @throws NullPointerException if {@code renderType} is {@code null} + * @see #renderType(ResourceLocation, ResourceLocation) */ public T renderType(ResourceLocation renderType) { Preconditions.checkNotNull(renderType, "Render type must not be null"); this.renderType = renderType.toString(); + this.renderTypeFast = null; + return self(); + } + + /** + * Set the render types for this model. Any render types to be used must be registered via + * {@link net.minecraftforge.client.event.RegisterNamedRenderTypesEvent RegisterNamedRenderTypesEvent}. + * + * @param renderType the render type for {@linkplain net.minecraft.client.GraphicsStatus#FANCY fancy graphics} + * @param renderTypeFast the render type for {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} + * @return this builder + * + * @throws NullPointerException if {@code renderType} is {@code null} + */ + public T renderType(ResourceLocation renderType, ResourceLocation renderTypeFast) { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null"); + this.renderType = renderType.toString(); + this.renderTypeFast = renderType.toString(); return self(); } diff --git a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java index 41e7053463..78b9b60ddf 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java @@ -366,7 +366,8 @@ public abstract class ModelProvider> implements DataPr } public T leaves(String name, ResourceLocation texture) { - return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture); + return singleTexture(name, BLOCK_FOLDER + "/leaves", "all", texture) + .renderType("cutout_mipped", "solid"); } /** diff --git a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java index 12aedcfb37..cad4440e4d 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/loaders/ItemLayerModelBuilder.java @@ -34,6 +34,7 @@ public class ItemLayerModelBuilder> extends CustomLoad private final Int2ObjectMap faceData = new Int2ObjectOpenHashMap<>(); private final Map renderTypes = new LinkedHashMap<>(); + private final Map renderTypesFast = new LinkedHashMap<>(); private final IntSet layersWithRenderTypes = new IntOpenHashSet(); protected ItemLayerModelBuilder(T parent, ExistingFileHelper existingFileHelper) @@ -116,6 +117,23 @@ public class ItemLayerModelBuilder> extends CustomLoad return renderType(asLoc, layers); } + public ItemLayerModelBuilder renderType(String renderType, String renderTypeFast, int... layers) + { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null"); + ResourceLocation asLoc; + if (renderType.contains(":")) + asLoc = ResourceLocation.parse(renderType); + else + asLoc = parent.getLocation().withPath(renderType); + ResourceLocation asLocFast; + if (renderTypeFast.contains(":")) + asLocFast = ResourceLocation.parse(renderTypeFast); + else + asLocFast = parent.getLocation().withPath(renderTypeFast); + return renderType(asLoc, asLocFast, layers); + } + /** * Set the render type for a set of layers. * @@ -145,6 +163,25 @@ public class ItemLayerModelBuilder> extends CustomLoad return this; } + public ItemLayerModelBuilder renderType(ResourceLocation renderType, ResourceLocation renderTypeFast, int... layers) + { + Preconditions.checkNotNull(renderType, "Render type must not be null"); + Preconditions.checkNotNull(renderTypeFast, "Fast graphics render type must not be null"); + Preconditions.checkNotNull(layers, "Layers must not be null"); + Preconditions.checkArgument(layers.length > 0, "At least one layer must be specified"); + Preconditions.checkArgument(Arrays.stream(layers).allMatch(i -> i >= 0), "All layers must be >= 0"); + var alreadyAssigned = Arrays.stream(layers).filter(layersWithRenderTypes::contains).toArray(); + Preconditions.checkArgument(alreadyAssigned.length == 0, "Attempted to re-assign layer render types: " + Arrays.toString(alreadyAssigned)); + var renderTypeLayers = renderTypes.computeIfAbsent(renderType, $ -> new IntOpenHashSet()); + var renderTypeFastLayers = renderTypesFast.computeIfAbsent(renderType, $ -> new IntOpenHashSet()); + Arrays.stream(layers).forEach(layer -> { + renderTypeLayers.add(layer); + renderTypeFastLayers.add(layer); + layersWithRenderTypes.add(layer); + }); + return this; + } + @Override public JsonObject toJson(JsonObject json) { @@ -171,6 +208,14 @@ public class ItemLayerModelBuilder> extends CustomLoad }); json.add("render_types", renderTypes); + JsonObject renderTypesFast = new JsonObject(); + this.renderTypesFast.forEach((renderTypeFast, layers) -> { + JsonArray array = new JsonArray(); + layers.intStream().sorted().forEach(array::add); + renderTypesFast.add(renderTypeFast.toString(), array); + }); + json.add("render_types_fast", renderTypesFast); + return json; } } diff --git a/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java index 5c30325a53..fe4f9e7f3f 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java @@ -34,6 +34,8 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext { private Transformation rootTransform; @Nullable private ResourceLocation renderTypeHint; + @Nullable + private ResourceLocation renderTypeFastHint; private boolean gui3d = true; @ApiStatus.Internal @@ -115,10 +117,22 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext { return owner.parent != null ? owner.parent.customData.getRenderTypeHint() : null; } + @Nullable + @Override + public ResourceLocation getRenderTypeFastHint() { + if (renderTypeFastHint != null) + return renderTypeFastHint; + return owner.parent != null ? owner.parent.customData.getRenderTypeFastHint() : null; + } + public void setRenderTypeHint(ResourceLocation renderTypeHint) { this.renderTypeHint = renderTypeHint; } + public void setRenderTypeFastHint(ResourceLocation renderTypeFastHint) { + this.renderTypeFastHint = renderTypeFastHint; + } + public void setGui3d(boolean gui3d) { this.gui3d = gui3d; } @@ -128,6 +142,7 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext { this.rootTransform = other.rootTransform; this.visibilityData.copyFrom(other.visibilityData); this.renderTypeHint = other.renderTypeHint; + this.renderTypeFastHint = other.renderTypeFastHint; this.gui3d = other.gui3d; } diff --git a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java index e5b17e4306..89d58b0193 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java @@ -74,6 +74,13 @@ public interface IGeometryBakingContext { @Nullable ResourceLocation getRenderTypeHint(); + /** + * @return a hint of the {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} render type this model + * should use. Custom loaders may ignore this. + */ + @Nullable + default ResourceLocation getRenderTypeFastHint() { return null; } + /** * Queries the visibility of a component of this model. * @@ -89,4 +96,20 @@ public interface IGeometryBakingContext { default RenderTypeGroup getRenderType(ResourceLocation name) { return NamedRenderTypeManager.get(name); } + + /** + * {@return a {@link RenderTypeGroup} from the {@link #getRenderTypeHint()}, or the empty group if not found.} + */ + default RenderTypeGroup getRenderType() { + var hint = getRenderTypeHint(); + return hint == null ? RenderTypeGroup.EMPTY : getRenderType(hint); + } + + /** + * {@return a {@link RenderTypeGroup} from the {@link #getRenderTypeHint()}, or the empty group if not found.} + */ + default RenderTypeGroup getRenderTypeFast() { + var hint = getRenderTypeFastHint(); + return hint == null ? RenderTypeGroup.EMPTY : getRenderType(hint); + } } diff --git a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java index a81e309d5a..8f870a9b83 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java @@ -25,10 +25,8 @@ public abstract class SimpleUnbakedGeometry> public BakedModel bake(IGeometryBakingContext context, ModelBaker baker, Function spriteGetter, ModelState modelState) { TextureAtlasSprite particle = spriteGetter.apply(context.getMaterial("particle")); - var renderTypeHint = context.getRenderTypeHint(); - var renderTypes = renderTypeHint != null ? context.getRenderType(renderTypeHint) : RenderTypeGroup.EMPTY; IModelBuilder builder = IModelBuilder.of(context.useAmbientOcclusion(), context.useBlockLight(), context.isGui3d(), - context.getTransforms(), particle, renderTypes); + context.getTransforms(), particle, context.getRenderType(), context.getRenderTypeFast()); addQuads(context, builder, baker, spriteGetter, modelState); diff --git a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java index 26931d6094..24ee702e5a 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java @@ -51,6 +51,8 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { private final Transformation rootTransform; @Nullable private final ResourceLocation renderTypeHint; + @Nullable + private final ResourceLocation renderTypeFastHint; private final BiPredicate visibilityTest; private StandaloneGeometryBakingContext( @@ -60,6 +62,18 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { ItemTransforms transforms, Transformation rootTransform, @Nullable ResourceLocation renderTypeHint, BiPredicate visibilityTest + ) { + this(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, null, visibilityTest); + } + + private StandaloneGeometryBakingContext( + ResourceLocation modelName, Predicate materialCheck, + Function materialLookup, boolean isGui3d, + boolean useBlockLight, boolean useAmbientOcclusion, + ItemTransforms transforms, Transformation rootTransform, + @Nullable ResourceLocation renderTypeHint, + @Nullable ResourceLocation renderTypeFastHint, + BiPredicate visibilityTest ) { this.modelName = modelName; this.materialCheck = materialCheck; @@ -70,6 +84,7 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { this.transforms = transforms; this.rootTransform = rootTransform; this.renderTypeHint = renderTypeHint; + this.renderTypeFastHint = renderTypeFastHint; this.visibilityTest = visibilityTest; } @@ -119,6 +134,12 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { return renderTypeHint; } + @Nullable + @Override + public ResourceLocation getRenderTypeFastHint() { + return renderTypeFastHint; + } + @Override public boolean isComponentVisible(String component, boolean fallback) { return visibilityTest.test(component, fallback); @@ -143,6 +164,8 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { private Transformation rootTransform = Transformation.identity(); @Nullable private ResourceLocation renderTypeHint; + @Nullable + private ResourceLocation renderTypeFastHint; private BiPredicate visibilityTest = (c, def) -> def; private Builder() { } @@ -156,6 +179,7 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { this.transforms = parent.getTransforms(); this.rootTransform = parent.getRootTransform(); this.renderTypeHint = parent.getRenderTypeHint(); + this.renderTypeFastHint = parent.getRenderTypeFastHint(); this.visibilityTest = parent::isComponentVisible; } @@ -205,6 +229,12 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { return this; } + public Builder withRenderTypeHint(ResourceLocation renderTypeHint, ResourceLocation renderTypeFastHint) { + this.renderTypeHint = renderTypeHint; + this.renderTypeFastHint = renderTypeFastHint; + return this; + } + @SuppressWarnings("deprecation") public Builder withVisibleComponents(Object2BooleanMap parts) { this.visibilityTest = parts::getOrDefault; @@ -212,7 +242,7 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { } public StandaloneGeometryBakingContext build(ResourceLocation modelName) { - return new StandaloneGeometryBakingContext(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest); + return new StandaloneGeometryBakingContext(modelName, materialCheck, materialLookup, isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, renderTypeFastHint, visibilityTest); } } } diff --git a/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json new file mode 100644 index 0000000000..f182f53462 --- /dev/null +++ b/src/test/generated/model_render_type/assets/model_render_type/blockstates/old_leaves.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "model_render_type:block/old_leaves" + } + } +} \ No newline at end of file diff --git a/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json new file mode 100644 index 0000000000..362976935c --- /dev/null +++ b/src/test/generated/model_render_type/assets/model_render_type/models/block/old_leaves.json @@ -0,0 +1,7 @@ +{ + "parent": "minecraft:block/leaves", + "render_type": "minecraft:cutout_mipped", + "textures": { + "all": "minecraft:block/oak_leaves" + } +} \ No newline at end of file diff --git a/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json new file mode 100644 index 0000000000..806af91bda --- /dev/null +++ b/src/test/generated/model_render_type/assets/model_render_type/models/item/old_leaves.json @@ -0,0 +1,3 @@ +{ + "parent": "model_render_type:block/old_leaves" +} \ No newline at end of file diff --git a/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java new file mode 100644 index 0000000000..09bac16c1c --- /dev/null +++ b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) Forge Development LLC and contributors + * SPDX-License-Identifier: LGPL-2.1-only + */ + +package net.minecraftforge.debug.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.ItemBlockRenderTypes; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.core.registries.Registries; +import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestHelper; +import net.minecraft.world.item.BlockItem; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.LeavesBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.material.MapColor; +import net.minecraft.world.level.material.PushReaction; +import net.minecraftforge.client.model.data.ModelData; +import net.minecraftforge.client.model.generators.BlockStateProvider; +import net.minecraftforge.client.model.generators.ItemModelProvider; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; +import net.minecraftforge.gametest.GameTestHolder; +import net.minecraftforge.registries.DeferredRegister; +import net.minecraftforge.registries.RegistryObject; +import net.minecraftforge.test.BaseTestMod; + +@Mod(ModelRenderLayerTest.MODID) +@GameTestHolder("forge." + ModelRenderLayerTest.MODID) +public class ModelRenderLayerTest extends BaseTestMod { + public static final String MODID = "model_render_type"; + + private static final DeferredRegister BLOCKS = DeferredRegister.create(Registries.BLOCK, MODID); + + private static final String OLD_LEAVES_NAME = "old_leaves"; + private static final BlockBehaviour.StatePredicate FALSE = (state, level, pos) -> false; + public static final RegistryObject OLD_LEAVES = BLOCKS.register(OLD_LEAVES_NAME, + () -> new LeavesBlock( + BlockBehaviour.Properties.of() + .setId(BLOCKS.key(OLD_LEAVES_NAME)) + .mapColor(MapColor.PLANT) + .strength(0.2F) + .randomTicks() + .sound(SoundType.GRASS) + .noOcclusion() + .isSuffocating(FALSE) + .isViewBlocking(FALSE) + .ignitedByLava() + .pushReaction(PushReaction.DESTROY) + .isRedstoneConductor(FALSE) + ) + ); + + private static final DeferredRegister ITEMS = DeferredRegister.create(Registries.ITEM, MODID); + public static final RegistryObject OLD_LEAVES_ITEM = ITEMS.register(OLD_LEAVES_NAME, () -> new BlockItem(OLD_LEAVES.get(), new Item.Properties().setId(ITEMS.key(OLD_LEAVES_NAME)))); + + public ModelRenderLayerTest(FMLJavaModLoadingContext context) { + super(context); + testItem(lookup -> new ItemStack(OLD_LEAVES_ITEM.get())); + } + + @SubscribeEvent + public void runData(GatherDataEvent event) { + event.getGenerator().addProvider(event.includeClient(), new BlockStates(event)); + event.getGenerator().addProvider(event.includeClient(), new ItemModels(event)); + } + + @GameTest(template = "forge:empty3x3x3") + public static void old_leaves_render_type(GameTestHelper helper) { + var manager = Minecraft.getInstance().getModelManager(); + + var state = OLD_LEAVES.get().defaultBlockState(); + var model = manager.getBlockModelShaper().getBlockModel(state); + var random = helper.getLevel().random; + boolean originalRenderState = ItemBlockRenderTypes.isFancy(); + helper.addCleanup(passed -> ItemBlockRenderTypes.setFancy(originalRenderState)); + + ItemBlockRenderTypes.setFancy(true); + var layer = model.getRenderTypes(state, random, ModelData.EMPTY); + helper.assertTrue(layer.contains(RenderType.cutoutMipped()), "Block model does not contain the correct render type for fancy graphics. Expected: cutout_mipped"); + + ItemBlockRenderTypes.setFancy(false); + layer = model.getRenderTypes(state, random, ModelData.EMPTY); + helper.assertTrue(layer.contains(RenderType.solid()), "Block model does not contain the correct render type for fast graphics. Expected: solid"); + + helper.succeed(); + } + + public static class BlockStates extends BlockStateProvider { + public BlockStates(GatherDataEvent event) { + super(event.getGenerator().getPackOutput(), MODID, event.getExistingFileHelper()); + } + + @Override + protected void registerStatesAndModels() { + this.simpleBlock( + OLD_LEAVES.get(), + this.models() + .leaves(OLD_LEAVES_NAME, blockTexture(Blocks.OAK_LEAVES)) + // only define the single render type. this test checks if "solid" is implicitly the fast graphics render type + .renderType("cutout_mipped") + ); + } + + } + private static class ItemModels extends ItemModelProvider { + public ItemModels(GatherDataEvent event) { + super(event.getGenerator().getPackOutput(), MODID, event.getExistingFileHelper()); + } + + @Override + protected void registerModels() { + this.withExistingParent(OLD_LEAVES_NAME, OLD_LEAVES.getKey().location().withPrefix(BLOCK_FOLDER + '/')); + } + } +}