diff --git a/src/main/java/thedarkcolour/exdeorum/blockentity/InfestedLeavesBlockEntity.java b/src/main/java/thedarkcolour/exdeorum/blockentity/InfestedLeavesBlockEntity.java index 74b1a4a1..614d19ef 100644 --- a/src/main/java/thedarkcolour/exdeorum/blockentity/InfestedLeavesBlockEntity.java +++ b/src/main/java/thedarkcolour/exdeorum/blockentity/InfestedLeavesBlockEntity.java @@ -66,7 +66,7 @@ public class InfestedLeavesBlockEntity extends EBlockEntity { @Override public void readVisualData(RegistryFriendlyByteBuf buffer) { - buffer.readShort(); + this.progress = buffer.readShort(); } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java index 49c853ee..1384559a 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ClientHandler.java @@ -93,7 +93,7 @@ public class ClientHandler { } private static void registerRenderers(EntityRenderersEvent.RegisterRenderers event) { - event.registerBlockEntityRenderer(EBlockEntities.INFESTED_LEAVES.get(), ctx -> new InfestedLeavesRenderer()); + event.registerBlockEntityRenderer(EBlockEntities.INFESTED_LEAVES.get(), InfestedLeavesRenderer::new); event.registerBlockEntityRenderer(EBlockEntities.BARREL.get(), BarrelRenderer::new); event.registerBlockEntityRenderer(EBlockEntities.LAVA_CRUCIBLE.get(), ctx -> new CrucibleRenderer()); event.registerBlockEntityRenderer(EBlockEntities.WATER_CRUCIBLE.get(), ctx -> new CrucibleRenderer()); diff --git a/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java b/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java index 498b2c35..689a68a3 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ter/InfestedLeavesRenderer.java @@ -19,21 +19,93 @@ package thedarkcolour.exdeorum.client.ter; import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.state.level.CameraRenderState; import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.block.BlockModelRenderState; +import net.minecraft.client.renderer.block.BlockModelResolver; +import net.minecraft.client.renderer.block.model.BlockDisplayContext; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; +import net.minecraft.util.Mth; +import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.state.BlockState; import thedarkcolour.exdeorum.blockentity.InfestedLeavesBlockEntity; +import thedarkcolour.exdeorum.client.RenderUtil; +import thedarkcolour.exdeorum.config.EConfig; -// TODO: port InfestedLeavesRenderer to MC 26.x rendering API (BlockEntityRenderer changed to extract/submit pattern) -public class InfestedLeavesRenderer implements BlockEntityRenderer { - @Override - public BlockEntityRenderState createRenderState() { - return new BlockEntityRenderState(); +public class InfestedLeavesRenderer implements BlockEntityRenderer { + private static final BlockDisplayContext BLOCK_DISPLAY_CONTEXT = BlockDisplayContext.create(); + private final BlockModelResolver blockModelResolver; + + public InfestedLeavesRenderer(BlockEntityRendererProvider.Context context) { + this.blockModelResolver = context.blockModelResolver(); } @Override - public void submit(BlockEntityRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) { - // TODO: implement infested leaves tinting using new 26.x rendering API + public InfestedLeavesRenderState createRenderState() { + return new InfestedLeavesRenderState(); + } + + @Override + public void extractRenderState(InfestedLeavesBlockEntity leaves, InfestedLeavesRenderState state, float partialTicks, net.minecraft.world.phys.Vec3 cameraPosition, net.minecraft.client.renderer.feature.ModelFeatureRenderer.CrumblingOverlay breakProgress) { + BlockEntityRenderer.super.extractRenderState(leaves, state, partialTicks, cameraPosition, breakProgress); + + state.model.clear(); + if (EConfig.CLIENT.useFastInfestedLeaves.get() || RenderUtil.IRIS_ACCESS.areShadersEnabled()) { + return; + } + + var level = leaves.getLevel(); + if (!(level instanceof net.minecraft.client.renderer.block.BlockAndTintGetter getter)) { + return; + } + + BlockState mimic = leaves.getMimic(); + if (mimic == null || mimic.isAir() || mimic.getBlock() == leaves.getBlockState().getBlock()) { + mimic = Blocks.OAK_LEAVES.defaultBlockState(); + } + + this.blockModelResolver.update(state.model, mimic, BLOCK_DISPLAY_CONTEXT); + + int baseColor = 0xFFFFFF; + var tintSource = Minecraft.getInstance().getBlockColors().getTintSource(mimic, 0); + if (tintSource != null) { + var tint = tintSource.colorInWorld(mimic, getter, leaves.getBlockPos()); + if (tint != -1) { + baseColor = tint; + } + } + + float progress = Mth.clamp(leaves.getProgress() / (float) InfestedLeavesBlockEntity.MAX_PROGRESS, 0.0f, 1.0f); + int tintedColor = blendToGray(baseColor, progress); + var tintLayers = state.model.tintLayers(); + for (int i = 0; i < tintLayers.size(); ++i) { + tintLayers.set(i, tintedColor); + } + } + + @Override + public void submit(InfestedLeavesRenderState state, PoseStack stack, SubmitNodeCollector collector, CameraRenderState cameraState) { + if (!state.model.isEmpty()) { + state.model.submitMultiLayer(stack, collector, state.lightCoords, OverlayTexture.NO_OVERLAY, 0); + } + } + + private static int blendToGray(int color, float progress) { + int r = (color >> 16) & 0xFF; + int g = (color >> 8) & 0xFF; + int b = color & 0xFF; + int gray = Math.round(r * 0.3f + g * 0.59f + b * 0.11f); + int blendedR = Math.round(Mth.lerp(progress, r, gray)); + int blendedG = Math.round(Mth.lerp(progress, g, gray)); + int blendedB = Math.round(Mth.lerp(progress, b, gray)); + return (blendedR & 0xFF) << 16 | (blendedG & 0xFF) << 8 | (blendedB & 0xFF); + } + + public static class InfestedLeavesRenderState extends BlockEntityRenderState { + public final BlockModelRenderState model = new BlockModelRenderState(); } } diff --git a/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java b/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java index b3b6bcb5..34d5080b 100644 --- a/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java +++ b/src/main/java/thedarkcolour/exdeorum/client/ter/SieveRenderer.java @@ -80,8 +80,11 @@ public class SieveRenderer implements if (MESH_TEXTURES.containsKey(meshItem)) { state.meshSprite = MESH_TEXTURES.get(meshItem); } else { - Identifier textureLoc = BuiltInRegistries.ITEM.getKey(meshItem).withPrefix("item/mesh/"); - var sprite = RenderUtil.getBlockSprite(textureLoc); + Identifier registryName = BuiltInRegistries.ITEM.getKey(meshItem); + var sprite = RenderUtil.getBlockSprite(registryName.withPrefix("item/mesh/")); + if (RenderUtil.isMissingTexture(sprite)) { + sprite = RenderUtil.getBlockSprite(registryName.withPrefix("item/")); + } MESH_TEXTURES.put(meshItem, sprite); state.meshSprite = sprite; } diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java index 83627156..f6fcedbc 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/SingleIngredientRecipe.java @@ -27,6 +27,8 @@ import net.minecraft.world.item.crafting.RecipeBookCategory; import net.minecraft.world.item.crafting.RecipeInput; import net.minecraft.world.level.Level; +import java.util.List; + /** * Represents a recipe that does not take place in any screen or container. *

@@ -68,7 +70,7 @@ public abstract class SingleIngredientRecipe implements Recipe { @Override public PlacementInfo placementInfo() { - return PlacementInfo.NOT_PLACEABLE; + return PlacementInfo.create(List.of(this.ingredient)); } @Override diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java index e8090154..baff7575 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/BarrelFluidMixingRecipe.java @@ -81,6 +81,11 @@ public record BarrelFluidMixingRecipe( return PlacementInfo.NOT_PLACEABLE; } + @Override + public boolean isSpecial() { + return true; + } + @Override public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.CRAFTING_MISC; diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FluidTransformationRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FluidTransformationRecipe.java index 6ea47e56..ebd21eb7 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FluidTransformationRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/barrel/FluidTransformationRecipe.java @@ -89,6 +89,11 @@ public record FluidTransformationRecipe( return PlacementInfo.NOT_PLACEABLE; } + @Override + public boolean isSpecial() { + return true; + } + @Override public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.CRAFTING_MISC; diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/crook/CrookRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/crook/CrookRecipe.java index 765c9fbe..247c7d44 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/crook/CrookRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/crook/CrookRecipe.java @@ -70,6 +70,11 @@ public record CrookRecipe(BlockPredicate blockPredicate, ItemStackTemplate resul return PlacementInfo.NOT_PLACEABLE; } + @Override + public boolean isSpecial() { + return true; + } + @Override public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.CRAFTING_MISC; diff --git a/src/main/java/thedarkcolour/exdeorum/recipe/crucible/CrucibleHeatRecipe.java b/src/main/java/thedarkcolour/exdeorum/recipe/crucible/CrucibleHeatRecipe.java index 27dd43e9..a2d434e4 100644 --- a/src/main/java/thedarkcolour/exdeorum/recipe/crucible/CrucibleHeatRecipe.java +++ b/src/main/java/thedarkcolour/exdeorum/recipe/crucible/CrucibleHeatRecipe.java @@ -68,6 +68,11 @@ public record CrucibleHeatRecipe(BlockPredicate blockPredicate, int heatValue) i return PlacementInfo.NOT_PLACEABLE; } + @Override + public boolean isSpecial() { + return true; + } + @Override public RecipeBookCategory recipeBookCategory() { return RecipeBookCategories.CRAFTING_MISC; diff --git a/src/main/resources/assets/exdeorum/atlases/blocks.json b/src/main/resources/assets/exdeorum/atlases/blocks.json new file mode 100644 index 00000000..e0bae039 --- /dev/null +++ b/src/main/resources/assets/exdeorum/atlases/blocks.json @@ -0,0 +1,9 @@ +{ + "sources": [ + { + "type": "directory", + "source": "item/mesh", + "prefix": "item/mesh/" + } + ] +}