diff --git a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch index 9fe92b8df9..34c1029311 100644 --- a/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/ItemBlockRenderTypes.java.patch @@ -34,21 +34,26 @@ public static RenderType getMovingBlockRenderType(BlockState p_109294_) { Block block = p_109294_.getBlock(); if (block instanceof LeavesBlock) { -@@ -376,6 +_,8 @@ +@@ -376,11 +_,14 @@ } } -+ /** @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(); -@@ -390,12 +_,77 @@ + } + ++ /* Forge: Use {@link net.minecraft.client.resources.model.BakedModel#getRenderPasses(ItemStack, boolean)} and {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(ItemStack, boolean)}. */ + public static RenderType getRenderType(ItemStack p_363859_) { + if (p_363859_.getItem() instanceof BlockItem blockitem) { + Block block = blockitem.getBlock(); +@@ -390,12 +_,81 @@ } } -+ /** @deprecated Forge: Use {@link net.minecraft.client.resources.model.BakedModel#getRenderPasses(ItemStack, boolean)} and {@link net.minecraft.client.resources.model.BakedModel#getRenderTypes(ItemStack, boolean)}. */ -+ @Deprecated // Note: this method does NOT support model-based render types ++ // Note: this method does NOT support model-based render types public static RenderType getRenderLayer(FluidState p_109288_) { - RenderType rendertype = TYPE_BY_FLUID.get(p_109288_.getType()); + RenderType rendertype = FLUID_RENDER_TYPES.get(net.minecraftforge.registries.ForgeRegistries.FLUIDS.getDelegateOrThrow(p_109288_.getType())); @@ -59,6 +64,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 +85,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(forRemoval = true, since = "1.21.4") + public static net.minecraftforge.client.ChunkRenderTypeSet getRenderLayers(BlockState state) { + Block block = state.getBlock(); + if (block instanceof LeavesBlock) { @@ -86,20 +96,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(forRemoval = true, since = "1.21.4") + 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(forRemoval = true, since = "1.21.4") + 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(forRemoval = true, since = "1.21.4") + 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/renderer/block/model/BlockModel.java.patch b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch index 2e1d224909..51a7aa0972 100644 --- a/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch +++ b/patches/minecraft/net/minecraft/client/renderer/block/model/BlockModel.java.patch @@ -24,13 +24,13 @@ + if (this.customData.getCustomGeometry() != null) + return this.customData.getCustomGeometry().bake(customData, p_378458_, p_378598_, p_111453_); + -+ var wrapped = net.minecraftforge.client.ForgeHooksClient.wrapRenderType(p_378458_, this.customData.getRenderType()); ++ var wrapped = net.minecraftforge.client.ForgeHooksClient.wrapRenderType(p_378458_, this.customData.getRenderType(), this.customData.getRenderTypeFast()); + return this.elements.isEmpty() && this.parent != null - ? this.parent.bake(p_378598_, p_378458_, p_111453_, p_111455_, p_377435_, p_378085_) - : SimpleBakedModel.bakeElements(this.elements, p_378598_, p_378458_.sprites(), p_111453_, p_111455_, p_377435_, true, p_378085_); + ? this.parent.bake(p_378598_, wrapped, p_111453_, p_111455_, p_377435_, p_378085_) -+ : SimpleBakedModel.bakeElements(this.elements, p_378598_, p_378458_.sprites(), p_111453_, p_111455_, p_377435_, true, p_378085_, wrapped.renderType()); ++ : SimpleBakedModel.bakeElements(this.elements, p_378598_, p_378458_.sprites(), p_111453_, p_111455_, p_377435_, true, p_378085_, wrapped.renderType(), wrapped.renderTypeFast()); } @Nullable diff --git a/patches/minecraft/net/minecraft/client/resources/model/ModelBaker.java.patch b/patches/minecraft/net/minecraft/client/resources/model/ModelBaker.java.patch index f1acbd833c..d7b8d48e66 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/ModelBaker.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/ModelBaker.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/client/resources/model/ModelBaker.java +++ b/net/minecraft/client/resources/model/ModelBaker.java -@@ -13,4 +_,10 @@ +@@ -13,4 +_,16 @@ @VisibleForDebug ModelDebugName rootName(); @@ -9,5 +9,11 @@ + @org.jetbrains.annotations.Nullable + default net.minecraftforge.client.RenderTypeGroup renderType() { + return null; ++ } ++ ++ /** Forge: Return the fast graphics render type to use when baking this model, its a dirty hack to pass down this value to parents */ ++ @org.jetbrains.annotations.Nullable ++ default net.minecraftforge.client.RenderTypeGroup renderTypeFast() { ++ return null; + } } 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 16097bb78a..0aebcc93ab 100644 --- a/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch +++ b/patches/minecraft/net/minecraft/client/resources/model/SimpleBakedModel.java.patch @@ -1,104 +1,147 @@ --- a/net/minecraft/client/resources/model/SimpleBakedModel.java +++ b/net/minecraft/client/resources/model/SimpleBakedModel.java -@@ -29,6 +_,17 @@ +@@ -29,7 +_,26 @@ private final boolean usesBlockLight; private final TextureAtlasSprite particleIcon; private 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; -+ /* -+ protected final List itemRenderTypes; -+ protected final List fabulousItemRenderTypes; -+ */ ++ /** Forge: Block render types to be used with {@linkplain net.minecraft.client.GraphicsStatus#FAST fast graphics} */ ++ protected final net.minecraftforge.client.ChunkRenderTypeSet blockRenderTypesFast; ++ /** 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_, -@@ -37,7 +_,8 @@ + Map> p_119490_, +@@ -37,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_; -@@ -46,6 +_,15 @@ +@@ -46,6 +_,20 @@ 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.isRenderingCutout = hasRenderTypes && (renderTypes.block() == net.minecraft.client.renderer.RenderType.cutout() || renderTypes.block() == net.minecraft.client.renderer.RenderType.cutoutMipped()); + } + + public static BakedModel bakeElements(List p_377425_, TextureSlots p_378525_, SpriteGetter p_375793_, ModelState p_376680_, boolean p_375745_, boolean p_376866_, boolean p_376846_, ItemTransforms p_376883_) { + return bakeElements(p_377425_, p_378525_, p_375793_, p_376680_, p_375745_, p_376866_, p_376846_, p_376883_, null); ++ } ++ ++ public static BakedModel bakeElements(List p_377425_, TextureSlots p_378525_, SpriteGetter p_375793_, ModelState p_376680_, boolean p_375745_, boolean p_376866_, boolean p_376846_, ItemTransforms p_376883_, @Nullable net.minecraftforge.client.RenderTypeGroup renderType) { ++ return bakeElements(p_377425_, p_378525_, p_375793_, p_376680_, p_375745_, p_376866_, p_376846_, p_376883_, renderType, null); } public static BakedModel bakeElements( -@@ -56,7 +_,8 @@ +@@ -56,7 +_,9 @@ boolean p_375745_, boolean p_376866_, boolean p_376846_, - ItemTransforms p_376883_ + ItemTransforms p_376883_, -+ @Nullable net.minecraftforge.client.RenderTypeGroup renderType ++ @Nullable net.minecraftforge.client.RenderTypeGroup renderType, ++ @Nullable net.minecraftforge.client.RenderTypeGroup renderTypeFast ) { TextureAtlasSprite textureatlassprite = findSprite(p_375793_, p_378525_, "particle"); SimpleBakedModel.Builder simplebakedmodel$builder = new SimpleBakedModel.Builder(p_375745_, p_376866_, p_376846_, p_376883_) -@@ -77,6 +_,9 @@ +@@ -77,6 +_,13 @@ } } -+ if (renderType != null) -+ simplebakedmodel$builder.renderTypes(renderType); ++ if (renderType != null && !renderType.isEmpty()) { ++ if (renderTypeFast != null && !renderTypeFast.isEmpty()) ++ simplebakedmodel$builder.renderTypes(renderType, renderTypeFast); ++ else ++ simplebakedmodel$builder.renderTypes(renderType); ++ } + return simplebakedmodel$builder.build(); } -@@ -123,6 +_,27 @@ +@@ -123,6 +_,19 @@ return this.transforms; } ++ private static final net.minecraftforge.client.ChunkRenderTypeSet SOLID_BLOCK = net.minecraftforge.client.ChunkRenderTypeSet.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); -+ } -+ */ + @OnlyIn(Dist.CLIENT) public static class Builder { private final ImmutableList.Builder unculledFaces = ImmutableList.builder(); -@@ -164,13 +_,19 @@ +@@ -164,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; + } + @@ -109,7 +152,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/ForgeHooksClient.java b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java index e52852a2a3..d962042996 100644 --- a/src/main/java/net/minecraftforge/client/ForgeHooksClient.java +++ b/src/main/java/net/minecraftforge/client/ForgeHooksClient.java @@ -906,6 +906,11 @@ public class ForgeHooksClient { model.customData.setRenderTypeHint(ResourceLocation.parse(renderTypeHintName)); } + if (json.has("render_type_fast")) { + var renderTypeHintName = GsonHelper.getAsString(json, "render_type_fast"); + model.customData.setRenderTypeFastHint(ResourceLocation.parse(renderTypeHintName)); + } + if (json.has("visibility")) { var visibility = GsonHelper.getAsJsonObject(json, "visibility"); for (var part : visibility.entrySet()) @@ -922,8 +927,18 @@ public class ForgeHooksClient { return new WrapedModelBaker(parent, group); } + public static ModelBaker wrapRenderType(ModelBaker parent, RenderTypeGroup group, RenderTypeGroup groupFast) { + if (group == null || group == RenderTypeGroup.EMPTY || parent.renderType() != null) + return parent; + return new WrapedModelBaker(parent, group, groupFast); + } + // a record for performance reasons - private record WrapedModelBaker(ModelBaker parent, RenderTypeGroup group) implements ModelBaker { + private record WrapedModelBaker(ModelBaker parent, RenderTypeGroup group, RenderTypeGroup renderTypeFast) implements ModelBaker { + private WrapedModelBaker(ModelBaker parent, RenderTypeGroup group) { + this(parent, group, RenderTypeGroup.EMPTY); + } + @Override public RenderTypeGroup renderType() { return group; diff --git a/src/main/java/net/minecraftforge/client/model/CompositeModel.java b/src/main/java/net/minecraftforge/client/model/CompositeModel.java index 39fa470c0e..c6bc4e19c6 100644 --- a/src/main/java/net/minecraftforge/client/model/CompositeModel.java +++ b/src/main/java/net/minecraftforge/client/model/CompositeModel.java @@ -198,6 +198,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; @@ -208,23 +209,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; } } @@ -234,20 +244,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 5d89c7de5b..a2b835fcd4 100644 --- a/src/main/java/net/minecraftforge/client/model/EmptyModel.java +++ b/src/main/java/net/minecraftforge/client/model/EmptyModel.java @@ -17,6 +17,7 @@ import net.minecraft.client.resources.model.Material; import net.minecraft.client.resources.model.ModelBaker; import net.minecraft.client.resources.model.ModelState; import net.minecraft.client.resources.model.SimpleBakedModel; +import net.minecraftforge.client.RenderTypeGroup; import net.minecraftforge.client.model.geometry.IGeometryBakingContext; import net.minecraftforge.client.model.geometry.IGeometryLoader; import net.minecraftforge.client.model.geometry.IUnbakedGeometry; @@ -49,7 +50,7 @@ public class EmptyModel extends SimpleUnbakedGeometry { private static final Material MISSING_TEXTURE = new Material(TextureAtlas.LOCATION_BLOCKS, 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/IModelBuilder.java b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java index 443569117e..c79f2ee8db 100644 --- a/src/main/java/net/minecraftforge/client/model/IModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/IModelBuilder.java @@ -46,6 +46,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()}. @@ -66,9 +78,16 @@ public interface IModelBuilder> { 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.builder.renderTypes(renderTypes); + this.builder.renderTypes(renderTypes, 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 09325827c2..b7011d0346 100644 --- a/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java +++ b/src/main/java/net/minecraftforge/client/model/ItemLayerModel.java @@ -37,10 +37,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 0d25253562..9066656f3f 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/BlockStateProvider.java @@ -257,6 +257,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) @@ -388,6 +424,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); @@ -402,6 +470,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 -> { @@ -539,6 +614,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); } @@ -563,6 +664,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); @@ -579,6 +696,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; @@ -620,6 +745,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), @@ -632,6 +773,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) @@ -684,6 +831,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); @@ -702,6 +865,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(); @@ -741,6 +913,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); @@ -765,6 +953,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; @@ -831,6 +1031,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); @@ -845,6 +1061,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 2511d7721e..de5007af61 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelBuilder.java @@ -65,6 +65,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; @@ -154,12 +155,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"); @@ -167,16 +173,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 951bf626c8..1ad1026d87 100644 --- a/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java +++ b/src/main/java/net/minecraftforge/client/model/generators/ModelProvider.java @@ -372,7 +372,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 c5e5182e43..e97c686c13 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 @@ -39,6 +39,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) @@ -121,6 +122,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. * @@ -150,6 +168,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) { @@ -176,6 +213,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 1a84a1484c..3f440a2eed 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/BlockGeometryBakingContext.java @@ -35,6 +35,8 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext { private Transformation rootTransform; @Nullable private ResourceLocation renderTypeHint; + @Nullable + private ResourceLocation renderTypeFastHint; private boolean gui3d = true; @ApiStatus.Internal @@ -111,10 +113,23 @@ public class BlockGeometryBakingContext implements IGeometryBakingContext { return pctx == null ? null: pctx.getRenderTypeHint(); } + @Nullable + @Override + public ResourceLocation getRenderTypeFastHint() { + if (renderTypeFastHint != null) + return renderTypeFastHint; + var pctx = parentContext(); + return pctx == null ? null: pctx.getRenderTypeFastHint(); + } + public void setRenderTypeHint(ResourceLocation renderTypeHint) { this.renderTypeHint = renderTypeHint; } + public void setRenderTypeFastHint(ResourceLocation renderTypeFastHint) { + this.renderTypeFastHint = renderTypeFastHint; + } + public void setGui3d(boolean gui3d) { this.gui3d = gui3d; } @@ -124,6 +139,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 fd9b73cdfc..065c32162b 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/IGeometryBakingContext.java @@ -53,6 +53,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. * @@ -76,4 +83,12 @@ public interface IGeometryBakingContext { 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 590a9bacef..95386a8d72 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/SimpleUnbakedGeometry.java @@ -23,7 +23,7 @@ public abstract class SimpleUnbakedGeometry> var particle = baker.sprites().maybeMissing(textures, "particle"); IModelBuilder builder = IModelBuilder.of(context.useAmbientOcclusion(), context.useBlockLight(), context.isGui3d(), - context.getTransforms(), particle, context.getRenderType()); + context.getTransforms(), particle, context.getRenderType(), context.getRenderTypeFast()); addQuads(context, builder, baker, textures, 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 bdb9b7293e..260d2b5868 100644 --- a/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java +++ b/src/main/java/net/minecraftforge/client/model/geometry/StandaloneGeometryBakingContext.java @@ -28,6 +28,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( @@ -36,6 +38,17 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { ItemTransforms transforms, Transformation rootTransform, @Nullable ResourceLocation renderTypeHint, BiPredicate visibilityTest + ) { + this(isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, null, visibilityTest); + } + + private StandaloneGeometryBakingContext( + boolean isGui3d, + boolean useBlockLight, boolean useAmbientOcclusion, + ItemTransforms transforms, Transformation rootTransform, + @Nullable ResourceLocation renderTypeHint, + @Nullable ResourceLocation renderTypeFastHint, + BiPredicate visibilityTest ) { this.isGui3d = isGui3d; this.useBlockLight = useBlockLight; @@ -43,6 +56,7 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { this.transforms = transforms; this.rootTransform = rootTransform; this.renderTypeHint = renderTypeHint; + this.renderTypeFastHint = renderTypeFastHint; this.visibilityTest = visibilityTest; } @@ -77,6 +91,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); @@ -98,6 +118,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() { } @@ -109,6 +131,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; } @@ -142,6 +165,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; @@ -149,7 +178,7 @@ public class StandaloneGeometryBakingContext implements IGeometryBakingContext { } public StandaloneGeometryBakingContext build() { - return new StandaloneGeometryBakingContext(isGui3d, useBlockLight, useAmbientOcclusion, transforms, rootTransform, renderTypeHint, visibilityTest); + return new StandaloneGeometryBakingContext(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/items/old_leaves.json b/src/test/generated/model_render_type/assets/model_render_type/items/old_leaves.json new file mode 100644 index 0000000000..3515428b0d --- /dev/null +++ b/src/test/generated/model_render_type/assets/model_render_type/items/old_leaves.json @@ -0,0 +1,6 @@ +{ + "model": { + "type": "minecraft:model", + "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/cutout_block.json b/src/test/generated/model_render_type/assets/model_render_type/models/block/cutout_block.json index 595d5110f6..fc44df711c 100644 --- a/src/test/generated/model_render_type/assets/model_render_type/models/block/cutout_block.json +++ b/src/test/generated/model_render_type/assets/model_render_type/models/block/cutout_block.json @@ -1,6 +1,7 @@ { "parent": "minecraft:block/cross", "render_type": "minecraft:cutout", + "render_type_fast": "minecraft:solid", "textures": { "cross": "minecraft:block/acacia_sapling" } 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/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java index d5a82fcbb5..7110283d9d 100644 --- a/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java +++ b/src/test/java/net/minecraftforge/debug/client/ModelRenderLayerTest.java @@ -5,6 +5,7 @@ package net.minecraftforge.debug.client; +import net.minecraft.ChatFormatting; import net.minecraft.client.Minecraft; import net.minecraft.client.data.models.BlockModelGenerators; import net.minecraft.client.data.models.ItemModelGenerators; @@ -12,13 +13,16 @@ import net.minecraft.client.data.models.model.ItemModelUtils; import net.minecraft.client.data.models.model.ModelLocationUtils; import net.minecraft.client.data.models.model.ModelTemplates; import net.minecraft.client.data.models.model.TextureMapping; +import net.minecraft.client.renderer.ItemBlockRenderTypes; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.resources.model.BakedModel; import net.minecraft.client.resources.model.ModelResourceLocation; import net.minecraft.core.registries.Registries; import net.minecraft.data.CachedOutput; import net.minecraft.data.DataProvider; import net.minecraft.data.PackOutput; import net.minecraft.gametest.framework.GameTest; +import net.minecraft.gametest.framework.GameTestAssertException; import net.minecraft.gametest.framework.GameTestHelper; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.item.BlockItem; @@ -26,12 +30,14 @@ 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.SaplingBlock; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.grower.TreeGrower; 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.ChunkRenderTypeSet; import net.minecraftforge.client.model.data.ModelData; import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -72,8 +78,28 @@ public class ModelRenderLayerTest extends BaseTestMod { ) ); + 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 ITEM = ITEMS.register(BLOCK_NAME, () -> new BlockItem(BLOCK.get(), new Item.Properties().setId(ITEMS.key(BLOCK_NAME)))); + 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)))); private static ResourceLocation rl(String path) { return ResourceLocation.fromNamespaceAndPath(MODID, path); @@ -97,15 +123,45 @@ public class ModelRenderLayerTest extends BaseTestMod { var key = new ModelResourceLocation(rl(BLOCK_NAME), "stage=0"); var model = manager.getModel(key); - if (model == manager.getMissingModel()) - helper.fail("Failed to retreive " + key + " block model"); + helper.fail("Failed to retreive block model for" + key); var state = BLOCK.get().defaultBlockState(); 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); - if (!layer.contains(RenderType.cutout())) - helper.fail("Block model does not have cutout layer"); + helper.assertTrue(layer.contains(RenderType.cutout()), "Block model does not contain the correct render type for fancy graphics. Expected: cutout"); + + 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(); + } + + @GameTest(template = "forge:empty3x3x3") + public static void old_leaves_render_type(GameTestHelper helper) { + var manager = Minecraft.getInstance().getModelManager(); + + var key = rl(OLD_LEAVES_NAME); + var models = manager.getModels().entrySet().stream().filter(ml -> ml.getKey().id().equals(key)).map(Map.Entry::getValue).findAny(); + var model = models.orElseThrow(() -> new GameTestAssertException("Failed to retrieve any block models for " + key)); + + var state = OLD_LEAVES.get().defaultBlockState(); + 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(); } @@ -127,16 +183,29 @@ public class ModelRenderLayerTest extends BaseTestMod { return new BlockModelGenerators(blocks, items, models) { @Override public void run() { + // CUTOUT BLOCK var textures = PlantType.NOT_TINTED.getTextureMapping(Blocks.ACACIA_SAPLING); var cutout = PlantType.NOT_TINTED.getCross().create(BLOCK.get(), textures, (name, model) -> { var json = model.get().getAsJsonObject(); json.addProperty("render_type", "minecraft:cutout"); + json.addProperty("render_type_fast", "minecraft:solid"); this.modelOutput.accept(name, () -> json); }); this.blockStateOutput.accept(createSimpleBlock(BLOCK.get(), cutout)); var item = ModelTemplates.FLAT_ITEM.create(ITEM.get(), TextureMapping.layer0(Blocks.ACACIA_SAPLING), this.modelOutput); this.itemModelOutput.accept(ITEM.get(), ItemModelUtils.plainModel(item)); + + + // OLD LEAVES + var oldLeavesCutout = ModelTemplates.LEAVES.create(OLD_LEAVES.get(), TextureMapping.cube(Blocks.OAK_LEAVES), (name, model) -> { + var json = model.get().getAsJsonObject(); + json.addProperty("render_type", "minecraft:cutout_mipped"); + this.modelOutput.accept(name, () -> json); + }); + this.blockStateOutput.accept(createSimpleBlock(OLD_LEAVES.get(), oldLeavesCutout)); + + this.itemModelOutput.accept(OLD_LEAVES_ITEM.get(), ItemModelUtils.plainModel(oldLeavesCutout)); } }; }