From 91b3b60ca231b47b28f95cd4e5b185cbbe58155a Mon Sep 17 00:00:00 2001 From: Jonathan Coates Date: Tue, 14 Oct 2025 20:04:31 +0100 Subject: [PATCH] Finish lectern rendering - Register our models via Minecraft's layer system. I confess, I don't fully understand what purpose this really solves (it's not data-driven or anything!), but makes it a bit more consistent with the rest of vanilla's code. - Update the lectern code to submit models correctly. --- buildSrc/build.gradle.kts | 2 +- gradle/libs.versions.toml | 10 +- .../api/client/StandaloneModel.java | 16 ++-- .../computercraft/client/ClientHooks.java | 38 +------- .../computercraft/client/ClientRegistry.java | 17 ++++ .../gui/LookingAtBlockEntityDebugEntry.java | 96 +++++++++++++++++++ .../client/model/LecternBookModel.java | 65 +++++++++++++ .../client/model/LecternPocketModel.java | 85 +++++++++------- .../client/model/LecternPrintoutModel.java | 81 +++++----------- .../LecternPrintoutModelDefinitions.java | 26 +++++ .../client/render/CustomLecternRenderer.java | 56 +++++++---- .../client/render/PocketItemRenderer.java | 21 ++-- .../client/render/SpriteRenderer.java | 3 - .../render/TurtleBlockEntityRenderer.java | 10 +- .../monitor/MonitorBlockEntityRenderer.java | 7 +- .../render/text/FixedWidthFontRenderer.java | 8 +- .../computercraft/data/DataProviders.java | 8 +- .../client/ComputerCraftClient.java | 5 + projects/forge/build.gradle.kts | 4 + .../client/ForgeClientHooks.java | 5 - .../client/ForgeClientRegistry.java | 7 ++ .../dan200/computercraft/ComputerCraft.java | 5 +- .../generic/methods/FluidMethods.java | 8 ++ .../generic/methods/InventoryMethods.java | 8 ++ 24 files changed, 390 insertions(+), 201 deletions(-) create mode 100644 projects/common/src/client/java/dan200/computercraft/client/gui/LookingAtBlockEntityDebugEntry.java create mode 100644 projects/common/src/client/java/dan200/computercraft/client/model/LecternBookModel.java create mode 100644 projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModelDefinitions.java diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 8295d7dcc..d6f634d9e 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -25,7 +25,7 @@ repositories { name = "Fabric" content { includeGroup("net.fabricmc") - includeGroup("net.fabricmc.unpick") + includeGroup("net.fabricmc.unpick") } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 0da3b984a..c689c18e1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -40,8 +40,8 @@ emi = "1.1.7+1.21" fabricPermissions = "0.3.3" iris-fabric = "1.9.1+1.21.7-fabric" iris-forge = "1.9.1+1.21.7-neoforge" -jei = "23.1.0.4" -modmenu = "13.0.2" +jei = "26.0.0.1" +modmenu = "16.0.0-rc.1" moreRed = "6.0.0.3" rei = "18.0.800" sodium-fabric = "mc1.21.6-0.6.13-fabric" @@ -113,9 +113,9 @@ fabric-loader = { module = "net.fabricmc:fabric-loader", version.ref = "fabric-l fabricPermissions = { module = "me.lucko:fabric-permissions-api", version.ref = "fabricPermissions" } iris-fabric = { module = "maven.modrinth:iris", version.ref = "iris-fabric" } iris-forge = { module = "maven.modrinth:iris", version.ref = "iris-forge" } -jei-api = { module = "mezz.jei:jei-1.21.7-common-api", version.ref = "jei" } -jei-fabric = { module = "mezz.jei:jei-1.21.7-fabric", version.ref = "jei" } -jei-forge = { module = "mezz.jei:jei-1.21.7-neoforge", version.ref = "jei" } +jei-api = { module = "mezz.jei:jei-1.21.10-common-api", version.ref = "jei" } +jei-fabric = { module = "mezz.jei:jei-1.21.10-fabric", version.ref = "jei" } +jei-forge = { module = "mezz.jei:jei-1.21.10-neoforge", version.ref = "jei" } mixin = { module = "org.spongepowered:mixin", version.ref = "mixin" } mixinExtra = { module = "io.github.llamalad7:mixinextras-common", version.ref = "mixinExtra" } modmenu = { module = "com.terraformersmc:modmenu", version.ref = "modmenu" } diff --git a/projects/common-api/src/client/java/dan200/computercraft/api/client/StandaloneModel.java b/projects/common-api/src/client/java/dan200/computercraft/api/client/StandaloneModel.java index 27f855fbd..4a3968d14 100644 --- a/projects/common-api/src/client/java/dan200/computercraft/api/client/StandaloneModel.java +++ b/projects/common-api/src/client/java/dan200/computercraft/api/client/StandaloneModel.java @@ -142,19 +142,21 @@ public final class StandaloneModel { /** * Render the model directly. * - * @param transform The current pose stack transformations. - * @param collector The node collector to render to. - * @param light The current light texture coordinate. - * @param overlay The current overlay texture coordinate. - * @param tints The tints for this model. + * @param transform The current pose stack transformations. + * @param collector The node collector to render to. + * @param light The current light texture coordinate. + * @param overlay The current overlay texture coordinate. + * @param tints The tints for this model. + * @param crumblingOverlay The current breaking progress. */ public void submit(PoseStack transform, SubmitNodeCollector collector, int light, int overlay, int @Nullable [] tints, ModelFeatureRenderer.@Nullable CrumblingOverlay crumblingOverlay) { collector.submitCustomGeometry(transform, renderType, (pose, buffer) -> render(pose, buffer, tints, light, overlay)); if (crumblingOverlay != null && renderType.affectsCrumbling()) { + // FIXME: We need a custom hook here, which renders to crumblingBufferSource. Currently the DESTROY_TYPES + // buffer gets flushed before the main model gets rendered. collector.submitCustomGeometry(transform, ModelBakery.DESTROY_TYPES.get(crumblingOverlay.progress()), (pose, buffer) -> - // FIXME: This does not work. Should we have a custom hook for this instead? - render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), tints, light, overlay) + render(pose, new SheetedDecalTextureGenerator(buffer, crumblingOverlay.cameraPose(), 1.0f), null, light, overlay) ); } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/ClientHooks.java b/projects/common/src/client/java/dan200/computercraft/client/ClientHooks.java index 57256ed70..e0a9d4b81 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/ClientHooks.java +++ b/projects/common/src/client/java/dan200/computercraft/client/ClientHooks.java @@ -7,7 +7,6 @@ package dan200.computercraft.client; import com.mojang.blaze3d.audio.Channel; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; -import dan200.computercraft.api.turtle.TurtleSide; import dan200.computercraft.client.pocket.ClientPocketComputers; import dan200.computercraft.client.render.CableHighlightRenderer; import dan200.computercraft.client.render.ExtendedItemFrameRenderState; @@ -22,9 +21,7 @@ import dan200.computercraft.shared.media.items.PrintoutItem; import dan200.computercraft.shared.peripheral.modem.wired.CableBlock; import dan200.computercraft.shared.peripheral.modem.wired.CableModemVariant; import dan200.computercraft.shared.peripheral.modem.wired.CableShapes; -import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity; import dan200.computercraft.shared.pocket.items.PocketComputerItem; -import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; import dan200.computercraft.shared.util.PauseAwareTimer; import dan200.computercraft.shared.util.WorldUtil; import net.minecraft.client.Camera; @@ -41,8 +38,6 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.BlockHitResult; import net.minecraft.world.phys.HitResult; -import java.util.function.Consumer; - /** * Event listeners for client-only code. *

@@ -72,6 +67,7 @@ public final class ClientHooks { } public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) { + // TODO: Reconsider this API once https://github.com/FabricMC/fabric/pull/4906/ is merged. return CableHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit) || MonitorHighlightRenderer.drawHighlight(transform, bufferSource, camera, hit); } @@ -106,38 +102,6 @@ public final class ClientHooks { SpeakerManager.onPlayStreaming(engine, channel, stream); } - /** - * Add additional information about the currently targeted block to the debug screen. - * - * @param addText A callback which adds a single line of text. - */ - public static void addBlockDebugInfo(Consumer addText) { - // TODO(1.21.9): Replacement for this - var minecraft = Minecraft.getInstance(); - if (!minecraft.getDebugOverlay().showDebugScreen() || minecraft.level == null) return; - if (minecraft.hitResult == null || minecraft.hitResult.getType() != HitResult.Type.BLOCK) return; - - var tile = minecraft.level.getBlockEntity(((BlockHitResult) minecraft.hitResult).getBlockPos()); - - if (tile instanceof MonitorBlockEntity monitor) { - addText.accept(""); - addText.accept( - String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight()) - ); - } else if (tile instanceof TurtleBlockEntity turtle) { - addText.accept(""); - addText.accept("Targeted turtle:"); - addText.accept(String.format("Id: %d", turtle.getComputerID())); - addTurtleUpgrade(addText, turtle, TurtleSide.LEFT); - addTurtleUpgrade(addText, turtle, TurtleSide.RIGHT); - } - } - - private static void addTurtleUpgrade(Consumer out, TurtleBlockEntity turtle, TurtleSide side) { - var upgrade = turtle.getAccess().getUpgradeWithData(side); - if (upgrade != null) out.accept(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location())); - } - public static BlockState getBlockBreakingState(BlockState state, BlockPos pos) { // Only apply to cables which have both a cable and modem if (state.getBlock() != ModRegistry.Blocks.CABLE.get() diff --git a/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java b/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java index e1a4b3de6..94aabf0e2 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java +++ b/projects/common/src/client/java/dan200/computercraft/client/ClientRegistry.java @@ -12,6 +12,9 @@ import dan200.computercraft.client.item.colour.PocketComputerLight; import dan200.computercraft.client.item.model.TurtleOverlayModel; import dan200.computercraft.client.item.properties.PocketComputerStateProperty; import dan200.computercraft.client.item.properties.TurtleShowElfOverlay; +import dan200.computercraft.client.model.LecternBookModel; +import dan200.computercraft.client.model.LecternPocketModel; +import dan200.computercraft.client.model.LecternPrintoutModel; import dan200.computercraft.client.platform.ClientPlatformHelper; import dan200.computercraft.client.platform.ModelKey; import dan200.computercraft.client.render.CustomLecternRenderer; @@ -23,11 +26,14 @@ import dan200.computercraft.client.turtle.TurtleUpgradeModelManager; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu; import net.minecraft.client.color.item.ItemTintSource; +import net.minecraft.client.gui.components.debug.DebugScreenEntry; import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState; import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.gui.screens.inventory.MenuAccess; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.BlockEntityRenderers; @@ -51,6 +57,7 @@ import java.util.concurrent.Executor; import java.util.function.BiConsumer; import java.util.function.BiFunction; import java.util.function.Function; +import java.util.function.Supplier; /** * Registers client-side objects, such as {@link BlockEntityRendererProvider}s and @@ -193,6 +200,12 @@ public final class ClientRegistry { register.accept(TurtleShowElfOverlay.ID, TurtleShowElfOverlay.CODEC); } + public static void registerLayerDefinitions(BiConsumer> register) { + register.accept(LecternBookModel.LAYER, LecternBookModel::createLayer); + register.accept(LecternPrintoutModel.LAYER, LecternPrintoutModel::createLayer); + register.accept(LecternPocketModel.LAYER, LecternPocketModel::createLayer); + } + public interface RegisterPictureInPictureRenderer { void register(Class state, Function> factory); } @@ -200,4 +213,8 @@ public final class ClientRegistry { public static void registerPictureInPictureRenderers(RegisterPictureInPictureRenderer register) { register.register(PrintoutScreen.PrintoutRenderState.class, PrintoutScreen.PrintoutPictureRenderer::new); } + + public static void registerDebugScreenEntries(BiConsumer register) { + register.accept(LookingAtBlockEntityDebugEntry.ID, LookingAtBlockEntityDebugEntry.create()); + } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/gui/LookingAtBlockEntityDebugEntry.java b/projects/common/src/client/java/dan200/computercraft/client/gui/LookingAtBlockEntityDebugEntry.java new file mode 100644 index 000000000..4d2c2f787 --- /dev/null +++ b/projects/common/src/client/java/dan200/computercraft/client/gui/LookingAtBlockEntityDebugEntry.java @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.client.gui; + +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.api.turtle.TurtleSide; +import dan200.computercraft.shared.ModRegistry; +import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity; +import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; +import net.minecraft.SharedConstants; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.components.debug.DebugEntryLookingAtBlock; +import net.minecraft.client.gui.components.debug.DebugScreenDisplayer; +import net.minecraft.client.gui.components.debug.DebugScreenEntry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import org.jspecify.annotations.Nullable; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiConsumer; + +/** + * A {@link DebugScreenEntry} that provides information about the currently looked at block entity. + * + * @see DebugEntryLookingAtBlock + */ +public final class LookingAtBlockEntityDebugEntry implements DebugScreenEntry { + public static final ResourceLocation ID = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "looking_at_block_entity"); + + private final Map, BiConsumer, BlockEntity>> blockEntityEmitters = new HashMap<>(); + + private LookingAtBlockEntityDebugEntry() { + } + + @Override + public void display(DebugScreenDisplayer displayer, @Nullable Level level, @Nullable LevelChunk clientChunk, @Nullable LevelChunk serverChunk) { + var entity = Minecraft.getInstance().getCameraEntity(); + var trueLevel = SharedConstants.DEBUG_SHOW_SERVER_DEBUG_VALUES ? level : Minecraft.getInstance().level; + if (entity == null || trueLevel == null) return; + + var hitResult = entity.pick(20.0, 0.0F, false); + if (hitResult.getType() != HitResult.Type.BLOCK) return; + + var blockEntity = trueLevel.getBlockEntity(((BlockHitResult) hitResult).getBlockPos()); + if (blockEntity == null) return; + var emitter = blockEntityEmitters.get(blockEntity.getType()); + if (emitter == null) return; + + List lines = new ArrayList<>(); + emitter.accept(lines, blockEntity); + displayer.addToGroup(ID, lines); + } + + @SuppressWarnings("unchecked") + private LookingAtBlockEntityDebugEntry register(BlockEntityType type, BiConsumer, T> emit) { + blockEntityEmitters.put(type, (BiConsumer, BlockEntity>) emit); + return this; + } + + public static DebugScreenEntry create() { + return new LookingAtBlockEntityDebugEntry() + .register(ModRegistry.BlockEntities.MONITOR_NORMAL.get(), LookingAtBlockEntityDebugEntry::debugMonitor) + .register(ModRegistry.BlockEntities.MONITOR_ADVANCED.get(), LookingAtBlockEntityDebugEntry::debugMonitor) + .register(ModRegistry.BlockEntities.TURTLE_NORMAL.get(), LookingAtBlockEntityDebugEntry::debugTurtle) + .register(ModRegistry.BlockEntities.TURTLE_ADVANCED.get(), LookingAtBlockEntityDebugEntry::debugTurtle); + } + + private static void debugMonitor(List lines, MonitorBlockEntity monitor) { + lines.add( + String.format("Targeted monitor: (%d, %d), %d x %d", monitor.getXIndex(), monitor.getYIndex(), monitor.getWidth(), monitor.getHeight()) + ); + } + + private static void debugTurtle(List lines, TurtleBlockEntity turtle) { + lines.add("Targeted turtle:"); + lines.add(String.format("Id: %d", turtle.getComputerID())); + addTurtleUpgrade(lines, turtle, TurtleSide.LEFT); + addTurtleUpgrade(lines, turtle, TurtleSide.RIGHT); + } + + private static void addTurtleUpgrade(List out, TurtleBlockEntity turtle, TurtleSide side) { + var upgrade = turtle.getAccess().getUpgradeWithData(side); + if (upgrade != null) out.add(String.format("Upgrade[%s]: %s", side, upgrade.holder().key().location())); + } + +} diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/LecternBookModel.java b/projects/common/src/client/java/dan200/computercraft/client/model/LecternBookModel.java new file mode 100644 index 000000000..51226f73b --- /dev/null +++ b/projects/common/src/client/java/dan200/computercraft/client/model/LecternBookModel.java @@ -0,0 +1,65 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.client.model; + +import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.client.render.CustomLecternRenderer; +import dan200.computercraft.shared.media.items.PrintoutItem; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.geom.ModelLayerLocation; +import net.minecraft.client.model.geom.ModelPart; +import net.minecraft.client.model.geom.PartPose; +import net.minecraft.client.model.geom.builders.CubeListBuilder; +import net.minecraft.client.model.geom.builders.LayerDefinition; +import net.minecraft.client.model.geom.builders.MeshDefinition; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Unit; + +import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_HEIGHT; +import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_WIDTH; + +/** + * A model for {@linkplain PrintoutItem printed books} placed on a lectern. + * + * @see CustomLecternRenderer + */ +public final class LecternBookModel extends Model { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_book"), "main"); + + public LecternBookModel(ModelPart root) { + super(root, RenderType::entitySolid); + } + + public static LayerDefinition createLayer() { + var mesh = new MeshDefinition(); + var parts = mesh.getRoot(); + + parts.addOrReplaceChild( + "spine", + CubeListBuilder.create().texOffs(12, 15).addBox(-0.005f, -5.0f, -0.5f, 0, 10, 1.0f), + PartPose.ZERO + ); + + var angle = (float) Math.toRadians(5); + parts.addOrReplaceChild( + "left", + CubeListBuilder.create() + .texOffs(0, 10).addBox(0, -5.0f, -6.0f, 0, 10, 6.0f) + .texOffs(0, 0).addBox(0.005f, -4.0f, -5.0f, 1.0f, 8.0f, 5.0f), + PartPose.offsetAndRotation(-0.005f, 0, -0.5f, 0, -angle, 0) + ); + + parts.addOrReplaceChild( + "right", + CubeListBuilder.create() + .texOffs(14, 10).addBox(0, -5.0f, 0, 0, 10, 6.0f) + .texOffs(0, 0).addBox(0.005f, -4.0f, 0, 1.0f, 8.0f, 5.0f), + PartPose.offsetAndRotation(-0.005f, 0, 0.5f, 0, angle, 0) + ); + + return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT); + } +} diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java index 0fd88a2f5..993a4a819 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java +++ b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPocketModel.java @@ -4,34 +4,43 @@ package dan200.computercraft.client.model; +import com.mojang.blaze3d.vertex.PoseStack; import dan200.computercraft.api.ComputerCraftAPI; +import dan200.computercraft.client.pocket.PocketComputerData; import dan200.computercraft.client.render.CustomLecternRenderer; +import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.pocket.items.PocketComputerItem; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.CubeListBuilder; +import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.model.geom.builders.MeshDefinition; -import net.minecraft.client.renderer.texture.TextureAtlas; +import net.minecraft.client.renderer.LightTexture; +import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.renderer.SubmitNodeCollector; +import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.client.resources.model.Material; +import net.minecraft.client.resources.model.MaterialSet; import net.minecraft.resources.ResourceLocation; +import net.minecraft.util.Unit; +import net.minecraft.world.item.component.DyedItemColor; /** * A model for {@linkplain PocketComputerItem pocket computers} placed on a lectern. * * @see CustomLecternRenderer */ -public class LecternPocketModel { - public static final ResourceLocation TEXTURE_NORMAL = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_normal"); - public static final ResourceLocation TEXTURE_ADVANCED = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_advanced"); - public static final ResourceLocation TEXTURE_COLOUR = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_colour"); - public static final ResourceLocation TEXTURE_FRAME = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_frame"); - public static final ResourceLocation TEXTURE_LIGHT = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/pocket_computer_light"); +public class LecternPocketModel extends Model { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_pocket"), "main"); - private static final Material MATERIAL_NORMAL = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_NORMAL); - private static final Material MATERIAL_ADVANCED = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_ADVANCED); - private static final Material MATERIAL_COLOUR = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_COLOUR); - private static final Material MATERIAL_FRAME = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_FRAME); - private static final Material MATERIAL_LIGHT = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE_LIGHT); + public static final Material MATERIAL_NORMAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_normal")); + public static final Material MATERIAL_ADVANCED = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_advanced")); + public static final Material MATERIAL_COLOUR = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_colour")); + public static final Material MATERIAL_FRAME = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_frame")); + public static final Material MATERIAL_LIGHT = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "pocket_computer_light")); // The size of the terminal within the model. public static final float TERM_WIDTH = 12.0f / 32.0f; @@ -41,13 +50,11 @@ public class LecternPocketModel { private static final int TEXTURE_WIDTH = 48 / 2; private static final int TEXTURE_HEIGHT = 48 / 2; - private final ModelPart root; - - public LecternPocketModel() { - root = buildPages(); + public LecternPocketModel(ModelPart root) { + super(root, RenderType::entityCutout); } - private static ModelPart buildPages() { + public static LayerDefinition createLayer() { var mesh = new MeshDefinition(); var parts = mesh.getRoot(); parts.addOrReplaceChild( @@ -55,29 +62,43 @@ public class LecternPocketModel { CubeListBuilder.create().texOffs(0, 0).addBox(0f, -5.0f, -4.0f, 1f, 10.0f, 8.0f), PartPose.ZERO ); - return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT); + return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT); } /** * Render the pocket computer model. * - * @param poseStack The current pose stack. - * @param bufferSource The buffer source to draw to. - * @param packedLight The current light level. - * @param packedOverlay The overlay texture (used for entity hurt animation). - * @param family The computer family. - * @param frameColour The pocket computer's {@linkplain DyedItemColor colour}. - * @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}. + * @param poseStack The current pose stack. + * @param collector The collector to draw to. + * @param materials The current materials + * @param packedLight The current light level. + * @param family The computer family. + * @param frameColour The pocket computer's {@linkplain DyedItemColor colour}. + * @param lightColour The pocket computer's {@linkplain PocketComputerData#getLightState() light colour}. */ - /* public void render(PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay, ComputerFamily family, int frameColour, int lightColour) { + public void submit( + PoseStack poseStack, SubmitNodeCollector collector, MaterialSet materials, int packedLight, ComputerFamily family, int frameColour, int lightColour + ) { if (frameColour != -1) { - root.render(poseStack, MATERIAL_FRAME.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay); - root.render(poseStack, MATERIAL_COLOUR.buffer(bufferSource, RenderType::entityCutout), packedLight, packedOverlay, frameColour); + collector.submitModel( + this, Unit.INSTANCE, poseStack, MATERIAL_FRAME.renderType(RenderType::entityCutout), + packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(MATERIAL_FRAME), 0, null + ); + collector.submitModel( + this, Unit.INSTANCE, poseStack, MATERIAL_COLOUR.renderType(RenderType::entityCutout), + packedLight, OverlayTexture.NO_OVERLAY, frameColour, materials.get(MATERIAL_COLOUR), 0, null + ); } else { - var buffer = (family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL).buffer(bufferSource, RenderType::entityCutout); - root.render(poseStack, buffer, packedLight, packedOverlay); + var material = family == ComputerFamily.ADVANCED ? MATERIAL_ADVANCED : MATERIAL_NORMAL; + collector.submitModel( + this, Unit.INSTANCE, poseStack, material.renderType(RenderType::entityCutout), + packedLight, OverlayTexture.NO_OVERLAY, -1, materials.get(material), 0, null + ); } - root.render(poseStack, MATERIAL_LIGHT.buffer(bufferSource, RenderType::entityCutout), LightTexture.FULL_BRIGHT, packedOverlay, lightColour); - }*/ + collector.submitModel( + this, Unit.INSTANCE, poseStack, MATERIAL_LIGHT.renderType(RenderType::entityCutout), + LightTexture.FULL_BRIGHT, OverlayTexture.NO_OVERLAY, lightColour, materials.get(MATERIAL_LIGHT), 0, null + ); + } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModel.java b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModel.java index cbb6b245d..d0c7c1f8d 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModel.java +++ b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModel.java @@ -4,54 +4,46 @@ package dan200.computercraft.client.model; -import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.blaze3d.vertex.VertexConsumer; import dan200.computercraft.api.ComputerCraftAPI; import dan200.computercraft.client.render.CustomLecternRenderer; import dan200.computercraft.shared.media.items.PrintoutItem; +import net.minecraft.client.model.Model; +import net.minecraft.client.model.geom.ModelLayerLocation; import net.minecraft.client.model.geom.ModelPart; import net.minecraft.client.model.geom.PartPose; import net.minecraft.client.model.geom.builders.CubeListBuilder; +import net.minecraft.client.model.geom.builders.LayerDefinition; import net.minecraft.client.model.geom.builders.MeshDefinition; import net.minecraft.client.renderer.RenderType; -import net.minecraft.client.renderer.SubmitNodeCollector; -import net.minecraft.client.renderer.texture.TextureAtlas; -import net.minecraft.client.resources.model.Material; import net.minecraft.resources.ResourceLocation; import java.util.List; +import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_HEIGHT; +import static dan200.computercraft.client.model.LecternPrintoutModelDefinitions.TEXTURE_WIDTH; + /** - * A model for {@linkplain PrintoutItem printouts} placed on a lectern. - *

- * This provides two models, {@linkplain #renderPages(PoseStack, VertexConsumer, int, int, int) one for a variable - * number of pages}, and {@linkplain #renderBook(PoseStack, VertexConsumer, int, int) one for books}. + * A model for {@linkplain PrintoutItem printouts} placed on a lectern. This renders a variable number of pages (1-3), + * stored in {@link State#pages}. * * @see CustomLecternRenderer */ -public class LecternPrintoutModel { - public static final ResourceLocation TEXTURE = ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "entity/printout"); - public static final Material MATERIAL = new Material(TextureAtlas.LOCATION_BLOCKS, TEXTURE); - - private static final int TEXTURE_WIDTH = 32; - private static final int TEXTURE_HEIGHT = 32; +public final class LecternPrintoutModel extends Model { + public static final ModelLayerLocation LAYER = new ModelLayerLocation(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "lectern_printout"), "main"); private static final String PAGE_1 = "page_1"; private static final String PAGE_2 = "page_2"; private static final String PAGE_3 = "page_3"; private static final List PAGES = List.of(PAGE_1, PAGE_2, PAGE_3); - private final ModelPart pagesRoot; - private final ModelPart bookRoot; private final ModelPart[] pages; - public LecternPrintoutModel() { - pagesRoot = buildPages(); - bookRoot = buildBook(); - pages = PAGES.stream().map(pagesRoot::getChild).toArray(ModelPart[]::new); + public LecternPrintoutModel(ModelPart root) { + super(root, RenderType::entitySolid); + pages = PAGES.stream().map(root::getChild).toArray(ModelPart[]::new); } - private static ModelPart buildPages() { + public static LayerDefinition createLayer() { var mesh = new MeshDefinition(); var parts = mesh.getRoot(); parts.addOrReplaceChild( @@ -71,49 +63,20 @@ public class LecternPrintoutModel { PartPose.offsetAndRotation(-0.25f, 0, -1.5f, (float) -Math.PI * (2f / 16), 0, 0) ); - return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT); + return LayerDefinition.create(mesh, TEXTURE_WIDTH, TEXTURE_HEIGHT); } - private static ModelPart buildBook() { - var mesh = new MeshDefinition(); - var parts = mesh.getRoot(); - - parts.addOrReplaceChild( - "spine", - CubeListBuilder.create().texOffs(12, 15).addBox(-0.005f, -5.0f, -0.5f, 0, 10, 1.0f), - PartPose.ZERO - ); - - var angle = (float) Math.toRadians(5); - parts.addOrReplaceChild( - "left", - CubeListBuilder.create() - .texOffs(0, 10).addBox(0, -5.0f, -6.0f, 0, 10, 6.0f) - .texOffs(0, 0).addBox(0.005f, -4.0f, -5.0f, 1.0f, 8.0f, 5.0f), - PartPose.offsetAndRotation(-0.005f, 0, -0.5f, 0, -angle, 0) - ); - - parts.addOrReplaceChild( - "right", - CubeListBuilder.create() - .texOffs(14, 10).addBox(0, -5.0f, 0, 0, 10, 6.0f) - .texOffs(0, 0).addBox(0.005f, -4.0f, 0, 1.0f, 8.0f, 5.0f), - PartPose.offsetAndRotation(-0.005f, 0, 0.5f, 0, angle, 0) - ); - - return mesh.getRoot().bake(TEXTURE_WIDTH, TEXTURE_HEIGHT); - } - - public void submitBook(PoseStack poseStack, SubmitNodeCollector collector, int packedLight, int packedOverlay) { - collector.submitModelPart(bookRoot, poseStack, RenderType.entitySolid(LecternPrintoutModel.MATERIAL.texture()), packedLight, packedOverlay, null); - } - - public void renderPages(PoseStack poseStack, VertexConsumer buffer, int packedLight, int packedOverlay, int pageCount) { + @Override + public void setupAnim(State renderState) { + var pageCount = renderState.pages; if (pageCount > pages.length) pageCount = pages.length; + var i = 0; for (; i < pageCount; i++) pages[i].visible = true; for (; i < pages.length; i++) pages[i].visible = false; + } - pagesRoot.render(poseStack, buffer, packedLight, packedOverlay); + public static class State { + public int pages; } } diff --git a/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModelDefinitions.java b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModelDefinitions.java new file mode 100644 index 000000000..f217dd559 --- /dev/null +++ b/projects/common/src/client/java/dan200/computercraft/client/model/LecternPrintoutModelDefinitions.java @@ -0,0 +1,26 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.client.model; + +import dan200.computercraft.api.ComputerCraftAPI; +import net.minecraft.client.renderer.Sheets; +import net.minecraft.client.resources.model.Material; +import net.minecraft.resources.ResourceLocation; + +/** + * Definitions for the lectern printout model. + * + * @see LecternBookModel + * @see LecternPrintoutModel + */ +public final class LecternPrintoutModelDefinitions { + public static final Material MATERIAL = Sheets.BLOCK_ENTITIES_MAPPER.apply(ResourceLocation.fromNamespaceAndPath(ComputerCraftAPI.MOD_ID, "printout")); + + static final int TEXTURE_WIDTH = 32; + static final int TEXTURE_HEIGHT = 32; + + private LecternPrintoutModelDefinitions() { + } +} diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/CustomLecternRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/CustomLecternRenderer.java index c1ddebca3..40ab72fa4 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/CustomLecternRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/CustomLecternRenderer.java @@ -6,17 +6,21 @@ package dan200.computercraft.client.render; import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import dan200.computercraft.client.model.LecternBookModel; import dan200.computercraft.client.model.LecternPocketModel; import dan200.computercraft.client.model.LecternPrintoutModel; +import dan200.computercraft.client.model.LecternPrintoutModelDefinitions; import dan200.computercraft.client.pocket.ClientPocketComputers; import dan200.computercraft.client.render.text.FixedWidthFontRenderer; import dan200.computercraft.core.terminal.Terminal; +import dan200.computercraft.core.util.Colour; import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.lectern.CustomLecternBlockEntity; import dan200.computercraft.shared.media.items.PrintoutData; import dan200.computercraft.shared.media.items.PrintoutItem; import dan200.computercraft.shared.pocket.items.PocketComputerItem; +import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; @@ -25,6 +29,9 @@ import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; import net.minecraft.client.renderer.feature.ModelFeatureRenderer; import net.minecraft.client.renderer.state.CameraRenderState; import net.minecraft.client.renderer.texture.OverlayTexture; +import net.minecraft.client.resources.model.MaterialSet; +import net.minecraft.util.ARGB; +import net.minecraft.util.Unit; import net.minecraft.world.item.component.DyedItemColor; import net.minecraft.world.level.block.LecternBlock; import net.minecraft.world.phys.Vec3; @@ -42,12 +49,16 @@ import static dan200.computercraft.client.render.text.FixedWidthFontRenderer.FON public class CustomLecternRenderer implements BlockEntityRenderer { private static final int POCKET_TERMINAL_RENDER_DISTANCE = 32; + private final MaterialSet materials; private final LecternPrintoutModel printoutModel; + private final LecternBookModel bookModel; private final LecternPocketModel pocketModel; public CustomLecternRenderer(BlockEntityRendererProvider.Context context) { - printoutModel = new LecternPrintoutModel(); - pocketModel = new LecternPocketModel(); + materials = context.materials(); + bookModel = new LecternBookModel(context.bakeLayer(LecternBookModel.LAYER)); + printoutModel = new LecternPrintoutModel(context.bakeLayer(LecternPrintoutModel.LAYER)); + pocketModel = new LecternPocketModel(context.bakeLayer(LecternPocketModel.LAYER)); } @Override @@ -66,7 +77,8 @@ public class CustomLecternRenderer implements BlockEntityRenderer { + var quadEmitter = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer); + FixedWidthFontRenderer.drawTerminal(quadEmitter, marginX, marginY, terminal, marginY, marginY, marginX, marginX); + }); } private enum Type { @@ -139,7 +157,7 @@ public class CustomLecternRenderer implements BlockEntityRenderer { - var quadEmitter = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer); - if (terminal == null) { - FixedWidthFontRenderer.drawEmptyTerminal(quadEmitter, 0, 0, width, height); - } else { + if (terminal == null) { + FixedWidthFontRenderer.drawEmptyTerminal(transform, collector, 0, 0, width, height); + } else { + collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> { + var quadEmitter = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer); FixedWidthFontRenderer.drawTerminal(quadEmitter, MARGIN, MARGIN, terminal, MARGIN, MARGIN, MARGIN, MARGIN); - } - }); + }); + } transform.popPose(); } diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/SpriteRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/SpriteRenderer.java index 10b0fdb3a..170235514 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/SpriteRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/SpriteRenderer.java @@ -10,7 +10,6 @@ import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.renderer.RenderType; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.resources.ResourceLocation; /** @@ -21,8 +20,6 @@ import net.minecraft.resources.ResourceLocation; * sheet. */ public class SpriteRenderer { - public static final ResourceLocation TEXTURE = ResourceLocation.withDefaultNamespace("textures/atlas/gui.png"); - private final PoseStack transform; private final SubmitNodeCollector submit; private final int light; diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/TurtleBlockEntityRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/TurtleBlockEntityRenderer.java index c27797cd7..c415dc26c 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/TurtleBlockEntityRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/TurtleBlockEntityRenderer.java @@ -19,10 +19,8 @@ import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity; import dan200.computercraft.shared.util.Holiday; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.Font; import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.client.renderer.block.model.ItemTransform; -import net.minecraft.client.renderer.blockentity.BlockEntityRenderDispatcher; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.blockentity.state.BlockEntityRenderState; @@ -44,14 +42,10 @@ public class TurtleBlockEntityRenderer implements BlockEntityRenderer { - FixedWidthFontRenderer.drawEmptyTerminal( - new FixedWidthFontRenderer.QuadEmitter(pose.pose(), consumer), - -MARGIN, MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2) - ); - }); + FixedWidthFontRenderer.drawEmptyTerminal(transform, collector, -MARGIN, MARGIN, (float) (xSize + 2 * MARGIN), (float) -(ySize + MARGIN * 2)); } transform.popPose(); diff --git a/projects/common/src/client/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java b/projects/common/src/client/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java index f5dfba6cf..10509d37a 100644 --- a/projects/common/src/client/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java +++ b/projects/common/src/client/java/dan200/computercraft/client/render/text/FixedWidthFontRenderer.java @@ -13,6 +13,7 @@ import dan200.computercraft.core.terminal.TextBuffer; import dan200.computercraft.core.util.Colour; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.RenderType; +import net.minecraft.client.renderer.SubmitNodeCollector; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.ARGB; import org.joml.Matrix4f; @@ -213,8 +214,11 @@ public final class FixedWidthFontRenderer { emitter.poseMatrix().set(transformBackup); } - public static void drawEmptyTerminal(QuadEmitter emitter, float x, float y, float width, float height) { - drawQuad(emitter, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT); + public static void drawEmptyTerminal(PoseStack transform, SubmitNodeCollector collector, float x, float y, float width, float height) { + collector.submitCustomGeometry(transform, FixedWidthFontRenderer.TERMINAL_TEXT, (pose, buffer) -> { + var quadEmitter = new FixedWidthFontRenderer.QuadEmitter(pose.pose(), buffer); + drawQuad(quadEmitter, x, y, 0, width, height, BLACK, LightTexture.FULL_BRIGHT); + }); } public record QuadEmitter(Matrix4f poseMatrix, VertexConsumer consumer) { diff --git a/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java index c54c74d67..8a6a3ffce 100644 --- a/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java +++ b/projects/common/src/datagen/java/dan200/computercraft/data/DataProviders.java @@ -10,7 +10,7 @@ import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; import dan200.computercraft.client.gui.GuiSprites; import dan200.computercraft.client.model.LecternPocketModel; -import dan200.computercraft.client.model.LecternPrintoutModel; +import dan200.computercraft.client.model.LecternPrintoutModelDefinitions; import dan200.computercraft.client.turtle.TurtleOverlay; import dan200.computercraft.data.client.BlockModelProvider; import dan200.computercraft.data.client.ItemModelProvider; @@ -71,9 +71,9 @@ public final class DataProviders { generator.addFromCodec("Block atlases", PackOutput.Target.RESOURCE_PACK, "atlases", SpriteSources.FILE_CODEC, out -> { out.accept(AtlasIds.BLOCKS, makeSprites(Stream.of( - LecternPrintoutModel.TEXTURE, - LecternPocketModel.TEXTURE_NORMAL, LecternPocketModel.TEXTURE_ADVANCED, - LecternPocketModel.TEXTURE_COLOUR, LecternPocketModel.TEXTURE_FRAME, LecternPocketModel.TEXTURE_LIGHT + LecternPrintoutModelDefinitions.MATERIAL.texture(), + LecternPocketModel.MATERIAL_NORMAL.texture(), LecternPocketModel.MATERIAL_ADVANCED.texture(), + LecternPocketModel.MATERIAL_COLOUR.texture(), LecternPocketModel.MATERIAL_FRAME.texture(), LecternPocketModel.MATERIAL_LIGHT.texture() ))); out.accept(AtlasIds.GUI, makeSprites( diff --git a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java index 7a5bf4117..259a87f43 100644 --- a/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java +++ b/projects/fabric/src/client/java/dan200/computercraft/client/ComputerCraftClient.java @@ -24,11 +24,13 @@ import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlu import net.fabricmc.fabric.api.client.model.loading.v1.UnbakedExtraModel; import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; import net.fabricmc.fabric.api.client.rendering.v1.BlockRenderLayerMap; +import net.fabricmc.fabric.api.client.rendering.v1.EntityModelLayerRegistry; import net.fabricmc.fabric.api.client.rendering.v1.SpecialGuiElementRegistry; import net.fabricmc.loader.api.FabricLoader; import net.minecraft.Util; import net.minecraft.client.Minecraft; import net.minecraft.client.color.item.ItemTintSources; +import net.minecraft.client.gui.components.debug.DebugScreenEntries; import net.minecraft.client.gui.render.pip.PictureInPictureRenderer; import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState; import net.minecraft.client.gui.screens.MenuScreens; @@ -62,6 +64,7 @@ public class ComputerCraftClient { ClientRegistry.registerItemColours(ItemTintSources.ID_MAPPER::put); ClientRegistry.registerSelectItemProperties(SelectItemModelProperties.ID_MAPPER::put); ClientRegistry.registerConditionalItemProperties(ConditionalItemModelProperties.ID_MAPPER::put); + ClientRegistry.registerLayerDefinitions((id, factory) -> EntityModelLayerRegistry.registerModelLayer(id, factory::get)); PreparableModelLoadingPlugin.register( (state, executor) -> ClientRegistry.gatherExtraModels(state.resourceManager(), executor), @@ -100,6 +103,8 @@ public class ComputerCraftClient { }); */ + ClientRegistry.registerDebugScreenEntries(DebugScreenEntries::register); + // Register our open folder command ClientCommandRegistrationCallback.EVENT.register((dispatcher, registryAccess) -> dispatcher.register(LiteralArgumentBuilder.literal(ComputerCraft.CLIENT_OPEN_FOLDER) diff --git a/projects/forge/build.gradle.kts b/projects/forge/build.gradle.kts index 0ddaefe3f..39792f7d7 100644 --- a/projects/forge/build.gradle.kts +++ b/projects/forge/build.gradle.kts @@ -53,6 +53,7 @@ neoForge { register("client") { client() + sourceSet = sourceSets.client } register("server") { @@ -77,6 +78,7 @@ neoForge { register("data") { configureForData("computercraft", sourceSets.main.get()) loadedMods = listOf(computercraftDatagen.get()) + sourceSet = sourceSets.datagen } fun RunModel.configureForGameTest() { @@ -87,6 +89,7 @@ neoForge { programArgument("--mixin.config=computercraft-gametest.mixins.json") loadedMods.add(testMod) + sourceSet = sourceSets.testMod jvmArgument("-ea") } @@ -119,6 +122,7 @@ neoForge { register("exampleData") { configureForData("examplemod", sourceSets.examples.get()) loadedMods.add(exampleMod.get()) + sourceSet = sourceSets.examples } } } diff --git a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java index 7699d4b13..4a0503fd8 100644 --- a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java +++ b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientHooks.java @@ -51,11 +51,6 @@ public final class ForgeClientHooks { }*/ } - @SubscribeEvent - public static void onRenderText(CustomizeGuiOverlayEvent.DebugText event) { - ClientHooks.addBlockDebugInfo(event.getRight()::add); - } - @SubscribeEvent public static void onRenderInHand(RenderHandEvent event) { if (ClientHooks.onRenderHeldItem( diff --git a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java index 234d0e99f..8b47a3e7d 100644 --- a/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java +++ b/projects/forge/src/client/java/dan200/computercraft/client/ForgeClientRegistry.java @@ -107,11 +107,18 @@ public final class ForgeClientRegistry { }); } + @SubscribeEvent + public static void registerLayerDefinitions(EntityRenderersEvent.RegisterLayerDefinitions event) { + ClientRegistry.registerLayerDefinitions(event::registerLayerDefinition); + } + @SubscribeEvent public static void registerPictureInPictureRenderers(RegisterPictureInPictureRenderersEvent event) { ClientRegistry.registerPictureInPictureRenderers(event::register); } + // TODO(1.21.10): ClientRegistry.registerDebugScreenEntries once https://github.com/neoforged/NeoForge/pull/2699 is merged + @SubscribeEvent public static void setupClient(FMLClientSetupEvent event) { ClientRegistry.register(); diff --git a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java index 84043e948..eca418f91 100644 --- a/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java +++ b/projects/forge/src/main/java/dan200/computercraft/ComputerCraft.java @@ -12,6 +12,7 @@ import dan200.computercraft.api.network.wired.WiredElementCapability; import dan200.computercraft.api.peripheral.PeripheralCapability; import dan200.computercraft.api.pocket.IPocketUpgrade; import dan200.computercraft.api.turtle.ITurtleUpgrade; +import dan200.computercraft.impl.Peripherals; import dan200.computercraft.impl.PocketUpgrades; import dan200.computercraft.impl.TurtleUpgrades; import dan200.computercraft.shared.CommonHooks; @@ -112,8 +113,8 @@ public final class ComputerCraft { ComputerCraftAPI.registerGenericSource(new FluidMethods()); ComputerCraftAPI.registerGenericSource(new EnergyMethods()); - ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Item.BLOCK); - ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Fluid.BLOCK); + Peripherals.addGenericLookup(InventoryMethods::extractContainer); + Peripherals.addGenericLookup(FluidMethods::extractContainer); ForgeComputerCraftAPI.registerGenericCapability(Capabilities.Energy.BLOCK); ForgeDetailRegistries.FLUID_STACK.addProvider(FluidData::fill); diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java index 80ff039a7..272a520a6 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/FluidMethods.java @@ -10,9 +10,12 @@ import dan200.computercraft.api.lua.LuaFunction; import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.util.CapabilityUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluid; import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.transfer.ResourceHandler; @@ -94,6 +97,11 @@ public final class FluidMethods extends AbstractFluidMethods extractHandler(IPeripheral peripheral) { var object = peripheral.getTarget(); diff --git a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java index 16534f0aa..62c044a44 100644 --- a/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java +++ b/projects/forge/src/main/java/dan200/computercraft/shared/peripheral/generic/methods/InventoryMethods.java @@ -11,10 +11,13 @@ import dan200.computercraft.api.peripheral.IComputerAccess; import dan200.computercraft.api.peripheral.IPeripheral; import dan200.computercraft.shared.platform.ForgeContainerTransfer; import dan200.computercraft.shared.util.CapabilityUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; import net.minecraft.world.Container; import net.minecraft.world.item.Items; import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; import net.neoforged.neoforge.capabilities.Capabilities; import net.neoforged.neoforge.transfer.ResourceHandler; import net.neoforged.neoforge.transfer.item.ItemResource; @@ -120,6 +123,11 @@ public final class InventoryMethods extends AbstractInventoryMethods extractHandler(IPeripheral peripheral) { var object = peripheral.getTarget();