1
0
mirror of https://github.com/SquidDev-CC/CC-Tweaked synced 2025-08-29 16:47:56 +00:00

Update to Minecraft 1.26.1

Still one TODO left, but around data fixers, so fairly small.

 - GUI rendering got a big overhaul. I avoided the worst of it with
   9272e2efcd, but things like terminals
   and printouts still require some custom rendering.

 - Item models are now de-duplicated when rendering in the UI, so we
   need to keep track of their identity with
   (appendModelidentityElement). I'm not sure I've got this entirely
   right — whole thing feels unfortunately error-prone.

 - BE serialisation now goes through a Value{Input,Output} class, rather
   than using NBT directly. Fairly simple change, but has changed the
   format of the GameProfile used in turtle's owners. Need a DFU patch
   for this.
This commit is contained in:
Jonathan Coates
2025-06-18 21:18:01 +01:00
parent ec3dd328b3
commit e3fecb013a
63 changed files with 561 additions and 457 deletions

View File

@@ -15,4 +15,4 @@ isUnstable=true
modVersion=1.115.1
# Minecraft properties: We want to configure this here so we can read it in settings.gradle
mcVersion=1.21.5
mcVersion=1.21.6

View File

@@ -7,9 +7,9 @@
# Minecraft
# MC version is specified in gradle.properties, as we need that in settings.gradle.
# Remember to update corresponding versions in fabric.mod.json/neoforge.mods.toml
fabric-api = "0.122.0+1.21.5"
fabric-loader = "0.16.10"
neoForge = "21.5.49-beta"
fabric-api = "0.127.0+1.21.6"
fabric-loader = "0.16.14"
neoForge = "21.6.0-beta"
neoMergeTool = "2.0.0"
mixin = "0.8.5"
parchment = "2025.04.19"
@@ -69,7 +69,7 @@ ideaExt = "1.1.7"
illuaminate = "0.1.0-83-g1131f68"
lwjgl = "3.3.3"
minotaur = "2.8.7"
modDevGradle = "2.0.82"
modDevGradle = "2.0.95"
nullAway = "0.12.7"
shadow = "8.3.1"
spotless = "7.0.2"

View File

@@ -61,6 +61,10 @@ public final class BasicUpgradeModel implements TurtleUpgradeModel {
@Override
public void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
renderer.appendModelIdentityElement(this);
renderer.appendModelIdentityElement(side);
renderer.appendModelIdentityElement(transform);
var layer = renderer.newLayer();
layer.setTransform(transform);
getModel(side).setupItemLayer(layer);

View File

@@ -26,8 +26,11 @@ import net.minecraft.util.Mth;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix4f;
import org.joml.Vector3f;
import org.jspecify.annotations.Nullable;
import java.util.Set;
/**
* A sic {@link TurtleUpgradeModel} that renders the upgrade's {@linkplain ITurtleUpgrade#getUpgradeItem(DataComponentPatch)
* upgrade item}.
@@ -59,9 +62,14 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
@Override
public void renderForItem(UpgradeData<ITurtleUpgrade> upgrade, TurtleSide side, ItemStackRenderState renderer, ItemModelResolver resolver, ItemTransform transform, int seed) {
renderer.appendModelIdentityElement(this);
var childState = new ItemStackRenderState();
resolver.updateForTopItem(childState, upgrade.getUpgradeItem(), ItemDisplayContext.NONE, null, null, seed);
if (!childState.isEmpty()) {
renderer.appendModelIdentityElement(childState.getModelIdentity());
renderer.appendModelIdentityElement(transform);
var layer = renderer.newLayer();
layer.setTransform(transform);
layer.setupSpecialModel(getRenderer(side), childState);
@@ -122,6 +130,10 @@ public final class ItemUpgradeModel implements TurtleUpgradeModel {
poseStack.popPose();
}
@Override
public void getExtents(Set<Vector3f> set) {
}
@Override
public @Nullable ItemStackRenderState extractArgument(ItemStack itemStack) {
return null;

View File

@@ -57,6 +57,9 @@ public interface TurtleUpgradeModel {
/**
* Render this upgrade to an {@link ItemStackRenderState}. This is used for rendering the item form of the upgrade.
* <p>
* Like with {@link ItemModel}, implementations must be careful to call {@link ItemStackRenderState#appendModelIdentityElement}
* where appropriate.
*
* @param upgrade The upgrade being rendered.
* @param side Which side of the turtle (left or right) the upgrade is equipped on.

View File

@@ -23,9 +23,11 @@ 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.render.pip.PictureInPictureRenderer;
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.renderer.MultiBufferSource;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderers;
import net.minecraft.client.renderer.item.ItemModel;
@@ -47,6 +49,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* Registers client-side objects, such as {@link BlockEntityRendererProvider}s and
@@ -188,4 +192,8 @@ public final class ClientRegistry {
public static void registerConditionalItemProperties(BiConsumer<ResourceLocation, MapCodec<? extends ConditionalItemModelProperty>> register) {
register.accept(TurtleShowElfOverlay.ID, TurtleShowElfOverlay.CODEC);
}
public static void registerPictureInPictureRenderers(Consumer<Function<MultiBufferSource.BufferSource, PictureInPictureRenderer<?>>> register) {
register.accept(PrintoutScreen.PrintoutPictureRenderer::new);
}
}

View File

@@ -9,7 +9,7 @@ import dan200.computercraft.client.gui.widgets.TerminalWidget;
import dan200.computercraft.core.util.Nullability;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
@@ -42,11 +42,12 @@ public final class ComputerScreen<T extends AbstractComputerMenu> extends Abstra
var computerTextures = GuiSprites.getComputerTextures(family);
graphics.blitSprite(
RenderType::guiTextured, computerTextures.border(),
RenderPipelines.GUI_TEXTURED, computerTextures.border(),
terminal.getX() - BORDER, terminal.getY() - BORDER, terminal.getWidth() + BORDER * 2, terminal.getHeight() + BORDER * 2
);
graphics.blitSprite(
RenderType::guiTextured, Nullability.assertNonNull(computerTextures.sidebar()),
RenderPipelines.GUI_TEXTURED, Nullability.assertNonNull(computerTextures.sidebar()),
leftPos, topPos + sidebarYOffset, AbstractComputerMenu.SIDEBAR_WIDTH, ComputerSidebar.HEIGHT
);
}

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.diskdrive.DiskDriveMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@@ -24,7 +24,7 @@ public class DiskDriveScreen extends AbstractContainerScreen<DiskDriveMenu> {
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
}
@Override

View File

@@ -9,7 +9,7 @@ import net.minecraft.client.gui.Font;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.toasts.Toast;
import net.minecraft.client.gui.components.toasts.ToastManager;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.util.FormattedCharSequence;
@@ -91,7 +91,7 @@ public class ItemToast implements Toast {
@Override
public void render(GuiGraphics graphics, Font font, long time) {
graphics.blitSprite(RenderType::guiTextured, TEXTURE, 0, 0, width(), height());
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, TEXTURE, 0, 0, width(), height());
var textX = MARGIN;
if (!stack.isEmpty()) {

View File

@@ -108,7 +108,7 @@ public class NoTermComputerScreen<T extends AbstractComputerMenu> extends Screen
var lines = font.split(Component.translatable("gui.computercraft.pocket_computer_overlay"), (int) (width * 0.8));
var y = 10;
for (var line : lines) {
graphics.drawString(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFF, true);
graphics.drawString(font, line, (width / 2) - (font.width(line) / 2), y, 0xFFFFFFFF, true);
y += 9;
}
}

View File

@@ -10,7 +10,7 @@ import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.MultiLineLabel;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jspecify.annotations.Nullable;
@@ -88,13 +88,13 @@ public final class OptionScreen extends Screen {
@Override
public void render(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
// Render the actual texture.
graphics.blit(RenderType::guiTextured, BACKGROUND, x, y, 0, 0, innerWidth, PADDING, 256, 256);
graphics.blit(RenderType::guiTextured, BACKGROUND,
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y, 0, 0, innerWidth, PADDING, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND,
x, y + PADDING, 0, PADDING, innerWidth, innerHeight - PADDING * 2,
innerWidth, PADDING,
256, 256
);
graphics.blit(RenderType::guiTextured, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, x, y + innerHeight - PADDING, 0, 256 - PADDING, innerWidth, PADDING, 256, 256);
assertNonNull(messageRenderer).renderLeftAlignedNoShadow(graphics, x + PADDING, y + PADDING, FONT_HEIGHT, 0x404040);
super.render(graphics, mouseX, mouseY, partialTicks);

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.client.gui;
import dan200.computercraft.shared.peripheral.printer.PrinterMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@@ -24,10 +24,10 @@ public class PrinterScreen extends AbstractContainerScreen<PrinterMenu> {
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos, topPos, 0, 0, imageWidth, imageHeight, 256, 256);
if (getMenu().isPrinting()) {
graphics.blit(RenderType::guiTextured, BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45, 256, 256);
graphics.blit(RenderPipelines.GUI_TEXTURED, BACKGROUND, leftPos + 34, topPos + 21, 176, 0, 25, 45, 256, 256);
}
}

View File

@@ -4,18 +4,27 @@
package dan200.computercraft.client.gui;
import com.mojang.blaze3d.vertex.PoseStack;
import dan200.computercraft.client.render.PrintoutRenderer;
import dan200.computercraft.core.terminal.TextBuffer;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.media.PrintoutMenu;
import dan200.computercraft.shared.media.items.PrintoutData;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.pip.PictureInPictureRenderer;
import net.minecraft.client.gui.render.state.GuiElementRenderState;
import net.minecraft.client.gui.render.state.pip.PictureInPictureRenderState;
import net.minecraft.client.gui.screens.inventory.AbstractContainerScreen;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.network.chat.Component;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerListener;
import net.minecraft.world.item.ItemStack;
import org.joml.Matrix3x2f;
import org.jspecify.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.Objects;
@@ -25,7 +34,7 @@ import static dan200.computercraft.client.render.PrintoutRenderer.*;
/**
* The GUI for printed pages and books.
*
* @see dan200.computercraft.client.render.PrintoutRenderer
* @see PrintoutRenderer
*/
public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu> implements ContainerListener {
private PrintoutInfo printout = PrintoutInfo.DEFAULT;
@@ -113,15 +122,11 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
@Override
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
// Push the printout slightly forward, to avoid clipping into the background.
graphics.pose().pushPose();
graphics.pose().translate(0, 0, 1);
graphics.drawSpecial(bufferSource -> {
drawBorder(graphics.pose(), bufferSource, leftPos, topPos, 0, page, printout.pages(), printout.book(), LightTexture.FULL_BRIGHT);
drawText(graphics.pose(), bufferSource, leftPos + X_TEXT_MARGIN, topPos + Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * page, LightTexture.FULL_BRIGHT, printout.text(), printout.colour());
});
graphics.pose().popPose();
graphics.guiRenderState.submitPicturesInPictureState(new PrintoutRenderState(
leftPos - COVER_SIZE - 32, leftPos + X_SIZE + COVER_SIZE + 32,
topPos - COVER_SIZE, topPos + Y_SIZE + COVER_SIZE,
printout, page, new Matrix3x2f(graphics.pose()), graphics.scissorStack.peek()
));
}
@Override
@@ -146,4 +151,56 @@ public final class PrintoutScreen extends AbstractContainerScreen<PrintoutMenu>
return new PrintoutInfo(pages, book, text, colours);
}
}
public record PrintoutRenderState(
int x0, int x1, int y0, int y1, PrintoutInfo printout, int page, Matrix3x2f pose,
@Nullable ScreenRectangle scissorArea, @Nullable ScreenRectangle bounds
) implements PictureInPictureRenderState {
private PrintoutRenderState(
int x0, int x1, int y0, int y1, PrintoutInfo printout, int page, Matrix3x2f pose, @Nullable ScreenRectangle scissorArea
) {
this(x0, x1, y0, y1, printout, page, pose, scissorArea, PictureInPictureRenderState.getBounds(x0, x1, y0, y1, scissorArea));
}
@Override
public float scale() {
return 1.0f;
}
}
/**
* PIP renderer for printouts.
* <p>
* We prefer using a PIP (rather than a {@link GuiElementRenderState}), as {@link PrintoutRenderer} renders with
* multiple z-levels.
*/
public static final class PrintoutPictureRenderer extends PictureInPictureRenderer<PrintoutRenderState> {
public PrintoutPictureRenderer(MultiBufferSource.BufferSource bufferSource) {
super(bufferSource);
}
@Override
protected void renderToTexture(PrintoutRenderState state, PoseStack pose) {
pose.pushPose();
pose.translate(-0.5f * X_SIZE, -(Y_SIZE + COVER_SIZE), 0);
pose.scale(1.0f, 1.0f, -1.0f);
drawBorder(pose, bufferSource, 0, 0, 0, state.page(), state.printout().pages(), state.printout().book(), LightTexture.FULL_BRIGHT);
drawText(
pose, bufferSource, X_TEXT_MARGIN, Y_TEXT_MARGIN, PrintoutData.LINES_PER_PAGE * state.page(), LightTexture.FULL_BRIGHT,
state.printout().text(), state.printout().colour()
);
pose.popPose();
}
@Override
public Class<PrintoutRenderState> getRenderStateClass() {
return PrintoutRenderState.class;
}
@Override
protected String getTextureLabel() {
return "Printout";
}
}
}

View File

@@ -12,7 +12,7 @@ import dan200.computercraft.shared.computer.core.ComputerFamily;
import dan200.computercraft.shared.computer.inventory.AbstractComputerMenu;
import dan200.computercraft.shared.turtle.inventory.TurtleMenu;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.player.Inventory;
@@ -50,7 +50,7 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
protected void renderBg(GuiGraphics graphics, float partialTicks, int mouseX, int mouseY) {
var advanced = family == ComputerFamily.ADVANCED;
graphics.blit(
RenderType::guiTextured, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL,
RenderPipelines.GUI_TEXTURED, advanced ? BACKGROUND_ADVANCED : BACKGROUND_NORMAL,
leftPos + AbstractComputerMenu.SIDEBAR_WIDTH, topPos, 0, 0,
TEX_WIDTH, TEX_HEIGHT, FULL_TEX_SIZE, FULL_TEX_SIZE
);
@@ -61,14 +61,14 @@ public class TurtleScreen extends AbstractComputerScreen<TurtleMenu> {
var slotX = slot % 4;
var slotY = slot / 4;
graphics.blitSprite(
RenderType::guiTextured, advanced ? SELECTED_ADVANCED : SELECTED_NORMAL,
RenderPipelines.GUI_TEXTURED, advanced ? SELECTED_ADVANCED : SELECTED_NORMAL,
leftPos + TURTLE_START_X - 2 + slotX * 18, topPos + PLAYER_START_Y - 2 + slotY * 18, 22, 22
);
}
// Render sidebar
graphics.blitSprite(
RenderType::guiTextured, Nullability.assertNonNull(GuiSprites.getComputerTextures(family).sidebar()),
RenderPipelines.GUI_TEXTURED, Nullability.assertNonNull(GuiSprites.getComputerTextures(family).sidebar()),
leftPos, topPos + sidebarYOffset, AbstractComputerMenu.SIDEBAR_WIDTH, ComputerSidebar.HEIGHT
);
}

View File

@@ -9,7 +9,7 @@ import net.minecraft.ChatFormatting;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.Button;
import net.minecraft.client.gui.components.Tooltip;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import org.jspecify.annotations.Nullable;
@@ -48,7 +48,7 @@ public class DynamicImageButton extends Button {
setTooltip(message.tooltip());
var texture = this.texture.get(isHoveredOrFocused());
graphics.blitSprite(RenderType::guiTextured, texture, getX(), getY(), width, height);
graphics.blitSprite(RenderPipelines.GUI_TEXTURED, texture, getX(), getY(), width, height);
}
public record HintedMessage(Component message, Tooltip tooltip) {

View File

@@ -4,6 +4,8 @@
package dan200.computercraft.client.gui.widgets;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.vertex.VertexConsumer;
import dan200.computercraft.client.gui.KeyConverter;
import dan200.computercraft.client.render.text.FixedWidthFontRenderer;
import dan200.computercraft.core.terminal.Terminal;
@@ -14,8 +16,16 @@ import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.client.gui.components.AbstractWidget;
import net.minecraft.client.gui.narration.NarratedElementType;
import net.minecraft.client.gui.narration.NarrationElementOutput;
import net.minecraft.client.gui.navigation.ScreenRectangle;
import net.minecraft.client.gui.render.TextureSetup;
import net.minecraft.client.gui.render.state.GuiElementRenderState;
import net.minecraft.client.gui.screens.Screen;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.network.chat.Component;
import org.joml.Matrix3x2f;
import org.joml.Matrix4f;
import org.jspecify.annotations.Nullable;
import org.lwjgl.glfw.GLFW;
import java.util.BitSet;
@@ -254,12 +264,23 @@ public class TerminalWidget extends AbstractWidget {
public void renderWidget(GuiGraphics graphics, int mouseX, int mouseY, float partialTicks) {
if (!visible) return;
graphics.drawSpecial(bufferSource -> {
FixedWidthFontRenderer.drawTerminal(
FixedWidthFontRenderer.toVertexConsumer(graphics.pose(), bufferSource.getBuffer(FixedWidthFontRenderer.TERMINAL_TEXT)),
(float) innerX, (float) innerY, terminal, (float) MARGIN, (float) MARGIN, (float) MARGIN, (float) MARGIN
);
});
var scissor = graphics.scissorStack.peek();
var terminalPose = new Matrix3x2f(graphics.pose());
var terminalTextures = TextureSetup.singleTextureWithLightmap(graphics.minecraft.getTextureManager().getTexture(FixedWidthFontRenderer.FONT).getTextureView());
graphics.guiRenderState.submitGuiElement(new TerminalBackgroundRenderState(
innerX, innerY, terminal, terminalPose, terminalTextures,
maybeIntersect(scissor, new ScreenRectangle(
innerX, innerY, terminal.getWidth() * FONT_WIDTH, terminal.getHeight() * FONT_HEIGHT).transformMaxBounds(graphics.pose())
),
scissor
));
graphics.guiRenderState.submitGuiElement(new TerminalTextRenderState(
innerX, innerY, terminal, terminalPose, terminalTextures,
maybeIntersect(scissor, new ScreenRectangle(getX(), getY(), getWidth(), getHeight()).transformMaxBounds(graphics.pose())),
scissor
));
}
@Override
@@ -274,4 +295,49 @@ public class TerminalWidget extends AbstractWidget {
public static int getHeight(int termHeight) {
return termHeight * FONT_HEIGHT + MARGIN * 2;
}
private static @Nullable ScreenRectangle maybeIntersect(@Nullable ScreenRectangle scissor, ScreenRectangle bounds) {
return scissor == null ? bounds : bounds.intersection(scissor);
}
private record TerminalBackgroundRenderState(
int x, int y, Terminal terminal,
Matrix3x2f pose,
TextureSetup textureSetup,
@Nullable ScreenRectangle bounds,
@Nullable ScreenRectangle scissorArea
) implements GuiElementRenderState {
@Override
public void buildVertices(VertexConsumer vertexConsumer, float z) {
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
FixedWidthFontRenderer.drawTerminalBackground(quads, x, y, terminal, MARGIN, MARGIN, MARGIN, MARGIN);
}
@Override
public RenderPipeline pipeline() {
return RenderPipelines.TEXT;
}
}
private record TerminalTextRenderState(
int x, int y, Terminal terminal, Matrix3x2f pose, TextureSetup textureSetup,
@Nullable ScreenRectangle bounds, @Nullable ScreenRectangle scissorArea
) implements GuiElementRenderState {
@Override
public void buildVertices(VertexConsumer vertexConsumer, float z) {
var quads = new FixedWidthFontRenderer.QuadEmitter(new Matrix4f().mul(pose).translate(0, 0, z), vertexConsumer);
FixedWidthFontRenderer.drawTerminalForeground(quads, x, y, terminal);
FixedWidthFontRenderer.drawCursor(quads, x, y, terminal);
// The GUI renderer requires that the buffer is non-empty. Add a zero-size vertex so we always have something.
for (var i = 0; i < 4; i++) {
vertexConsumer.addVertex(0, 0, z).setColor(0x00ffffff).setUv(0, 0).setLight(LightTexture.FULL_BRIGHT);
}
}
@Override
public RenderPipeline pipeline() {
return RenderPipelines.TEXT;
}
}
}

View File

@@ -39,6 +39,9 @@ public record TurtleOverlayModel(ItemTransforms transforms) implements ItemModel
var overlay = TurtleItem.getOverlay(stack);
if (overlay == null) return;
state.appendModelIdentityElement(this);
state.appendModelIdentityElement(overlay);
var layer = state.newLayer();
TurtleOverlayManager.get(Minecraft.getInstance().getModelManager(), overlay).model().setupItemLayer(layer);
layer.setTransform(transforms().getTransform(context));

View File

@@ -29,7 +29,7 @@ public final class CableHighlightRenderer {
*/
public static boolean drawHighlight(PoseStack transform, MultiBufferSource bufferSource, Camera camera, BlockHitResult hit) {
var pos = hit.getBlockPos();
var world = camera.getEntity().getCommandSenderWorld();
var world = camera.getEntity().level();
var state = world.getBlockState(pos);

View File

@@ -4,8 +4,8 @@
package dan200.computercraft.client.render.monitor;
import com.mojang.blaze3d.buffers.BufferType;
import com.mojang.blaze3d.buffers.BufferUsage;
import com.mojang.blaze3d.buffers.GpuBuffer;
import com.mojang.blaze3d.pipeline.RenderPipeline;
import com.mojang.blaze3d.systems.RenderSystem;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
@@ -19,14 +19,17 @@ import dan200.computercraft.shared.config.Config;
import dan200.computercraft.shared.peripheral.monitor.ClientMonitor;
import dan200.computercraft.shared.peripheral.monitor.MonitorBlockEntity;
import dan200.computercraft.shared.util.DirectionUtil;
import net.minecraft.client.renderer.FogParameters;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderPipelines;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.blockentity.BlockEntityRenderer;
import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider;
import net.minecraft.client.renderer.fog.FogRenderer;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import org.joml.Vector4f;
import org.jspecify.annotations.Nullable;
import org.lwjgl.system.MemoryUtil;
@@ -148,11 +151,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
throw new IllegalStateException("Drew too many vertices. Expected " + maxVertexCount + ", drew " + vertexCountAfterCursor);
}
final int indexAfterBackground, indexAfterForeground, indexAfterCursor;
if (vertexCountAfterCursor == 0) {
// If we have nothing to draw, just mark it as empty. We'll skip drawing in drawWithShader.
indexAfterBackground = indexAfterForeground = indexAfterCursor = 0;
} else {
if (vertexCountAfterCursor != 0) {
renderState.register();
var commandEncoder = RenderSystem.getDevice().createCommandEncoder();
@@ -174,25 +173,19 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
renderState.vertexBuffer = null;
}
renderState.vertexBuffer = RenderSystem.getDevice().createBuffer(
() -> "Monitor at " + monitor.getOrigin().getBlockPos(),
BufferType.VERTICES, BufferUsage.STATIC_WRITE, resultBuffer
() -> "Monitor at " + monitor.getOrigin().getBlockPos(), GpuBuffer.USAGE_VERTEX | GpuBuffer.USAGE_COPY_DST, resultBuffer
);
} else if (!renderState.vertexBuffer.isClosed()) {
commandEncoder.writeToBuffer(renderState.vertexBuffer, resultBuffer, 0);
commandEncoder.writeToBuffer(renderState.vertexBuffer.slice(), resultBuffer);
}
var mode = FixedWidthFontRenderer.TERMINAL_TEXT.mode();
indexAfterBackground = mode.indexCount(vertexCountAfterBackground);
indexAfterForeground = mode.indexCount(vertexCountAfterForeground);
indexAfterCursor = mode.indexCount(vertexCountAfterCursor);
}
renderState.indexAfterForeground = indexAfterForeground;
renderState.indexAfterBackground = indexAfterBackground;
renderState.indexAfterCursor = indexAfterCursor;
renderState.vertexCountAfterBackground = vertexCountAfterBackground;
renderState.vertexCountAfterForeground = vertexCountAfterForeground;
renderState.vertexCountAfterCursor = vertexCountAfterCursor;
}
if (renderState.indexAfterCursor == 0) return;
if (renderState.vertexCountAfterCursor == 0) return;
// Our VBO renders coordinates in monitor-space rather than world space. A full sized monitor (8x6) will
// use positions from (0, 0) to (164*FONT_WIDTH, 81*FONT_HEIGHT) = (984, 729). This is far outside the
@@ -201,20 +194,20 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
// renderer is trying to avoid!). Instead, we just disable fog entirely by setting the fog start to an
// absurdly high value.
var oldFog = RenderSystem.getShaderFog();
RenderSystem.setShaderFog(FogParameters.NO_FOG);
RenderSystem.setShaderFog(Minecraft.getInstance().gameRenderer.fogRenderer.getBuffer(FogRenderer.FogMode.NONE));
// Compose the existing model view matrix with our transformation matrix.
RenderSystem.getModelViewStack().pushMatrix();
RenderSystem.getModelViewStack().mul(matrix);
// Render background geometry
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, 0, renderState.indexAfterBackground);
drawWithShader(renderState, FixedWidthFontRenderer.TERMINAL_TEXT, RenderPipelines.TEXT, 0, renderState.vertexCountAfterBackground);
drawWithShader(
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, renderState.indexAfterBackground,
renderState, FixedWidthFontRenderer.TERMINAL_TEXT_OFFSET, RenderPipelines.TEXT_POLYGON_OFFSET, renderState.vertexCountAfterBackground,
(
FixedWidthFontRenderer.isCursorVisible(terminal) && FrameInfo.getGlobalCursorBlink()
? renderState.indexAfterCursor : renderState.indexAfterForeground
) - renderState.indexAfterBackground
? renderState.vertexCountAfterCursor : renderState.vertexCountAfterForeground
) - renderState.vertexCountAfterBackground
);
// Clear state
@@ -222,21 +215,39 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
RenderSystem.setShaderFog(oldFog);
}
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, int indexOffset, int indexCount) {
private static void drawWithShader(MonitorRenderState renderState, RenderType renderType, RenderPipeline pipeline, int vertexOffset, int vertexCount) {
if (renderState.vertexBuffer == null) {
throw new IllegalStateException("MonitorRenderState has not been initialised");
}
if (indexCount == 0) return;
if (vertexCount == 0) return;
var transforms = RenderSystem.getDynamicUniforms().writeTransform(
RenderSystem.getModelViewMatrix(),
new Vector4f(1.0F, 1.0F, 1.0F, 1.0F),
RenderSystem.getModelOffset(),
RenderSystem.getTextureMatrix(),
RenderSystem.getShaderLineWidth()
);
renderType.setupRenderState();
var autoStorageBuffer = RenderSystem.getSequentialBuffer(renderType.mode());
var indexBuffer = autoStorageBuffer.getBuffer(indexOffset + indexCount);
var indexCount = FixedWidthFontRenderer.TERMINAL_TEXT.mode().indexCount(vertexCount);
var indexBuffer = autoStorageBuffer.getBuffer(indexCount);
var target = Minecraft.getInstance().getMainRenderTarget();
var colourTarget = RenderSystem.outputColorTextureOverride != null ? RenderSystem.outputColorTextureOverride : target.getColorTextureView();
var depthTarget = target.useDepth
? (RenderSystem.outputDepthTextureOverride != null ? RenderSystem.outputDepthTextureOverride : target.getDepthTextureView())
: null;
try (var renderPass = RenderSystem.getDevice().createCommandEncoder().createRenderPass(
renderType.getRenderTarget().getColorTexture(), OptionalInt.empty(), renderType.getRenderTarget().getDepthTexture(), OptionalDouble.empty()
() -> "Monitor", colourTarget, OptionalInt.empty(), depthTarget, OptionalDouble.empty()
)) {
renderPass.setPipeline(renderType.getRenderPipeline());
renderPass.setPipeline(pipeline);
RenderSystem.bindDefaultUniforms(renderPass);
renderPass.setUniform("DynamicTransforms", transforms);
renderPass.setVertexBuffer(0, renderState.vertexBuffer);
renderPass.setIndexBuffer(indexBuffer, autoStorageBuffer.type());
@@ -245,7 +256,7 @@ public class MonitorBlockEntityRenderer implements BlockEntityRenderer<MonitorBl
if (gpuTexture != null) renderPass.bindSampler("Sampler" + j, gpuTexture);
}
renderPass.drawIndexed(indexOffset, indexCount);
renderPass.drawIndexed(vertexOffset, 0, indexCount, 1);
}
renderType.clearRenderState();

View File

@@ -29,7 +29,7 @@ public final class MonitorHighlightRenderer {
// Preserve normal behaviour when crouching.
if (camera.getEntity().isCrouching()) return false;
var world = camera.getEntity().getCommandSenderWorld();
var world = camera.getEntity().level();
var pos = hit.getBlockPos();
if (!(world.getBlockEntity(pos) instanceof MonitorBlockEntity monitor)) return false;

View File

@@ -31,9 +31,9 @@ public final class MonitorRenderState implements ClientMonitor.RenderState {
@Nullable
GpuBuffer vertexBuffer;
int indexAfterBackground;
int indexAfterForeground;
int indexAfterCursor;
int vertexCountAfterBackground;
int vertexCountAfterForeground;
int vertexCountAfterCursor;
void register() {
if (vertexBuffer != null) return;

View File

@@ -33,7 +33,7 @@ import org.joml.Vector3f;
* {@link DirectFixedWidthFontRenderer}.
*/
public final class FixedWidthFontRenderer {
private static final ResourceLocation FONT = ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/term_font.png");
public static final ResourceLocation FONT = ResourceLocation.fromNamespaceAndPath("computercraft", "textures/gui/term_font.png");
/**
* A render type for terminal text.

View File

@@ -48,7 +48,7 @@ public class SpeakerInstance {
// Update the attenuation if the volume has changed: SoundEngine.tickNonPaused updates the volume
// itself, but leaves the attenuation unchanged. We mirror the logic of SoundEngine.play here.
if (volumeChanged) {
channel.linearAttenuation(Math.max(volume, 1) * sound.getSound().getAttenuationDistance());
channel.linearAttenuation(Math.max(volume, 1) * Nullability.assertNonNull(sound.getSound()).getAttenuationDistance());
}
});
}

View File

@@ -62,8 +62,8 @@ public final class DataProviders {
generator.registries(fullRegistryPatch);
generator.add(out -> new RecipeProvider.Runner(out, fullRegistries));
var blockTags = generator.blockTags(TagProvider::blockTags);
generator.itemTags(TagProvider::itemTags, blockTags);
generator.blockTags(TagProvider::blockTags);
generator.itemTags(TagProvider::itemTags);
generator.add(out -> new net.minecraft.data.loot.LootTableProvider(out, Set.of(), LootTableProvider.getTables(), fullRegistries));
@@ -109,7 +109,7 @@ public final class DataProviders {
TagsProvider<Block> blockTags(Consumer<TagProvider.TagConsumer<Block>> tags);
TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks);
TagsProvider<Item> itemTags(Consumer<TagProvider.TagConsumer<Item>> tags);
/**
* Build new dynamic registries and save them to a pack.

View File

@@ -7,13 +7,10 @@ package dan200.computercraft.data;
import dan200.computercraft.api.ComputerCraftTags;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.integration.ExternalModTags;
import dan200.computercraft.shared.util.RegistryHelper;
import net.minecraft.core.Registry;
import net.minecraft.data.tags.ItemTagsProvider;
import net.minecraft.data.tags.TagAppender;
import net.minecraft.data.tags.TagsProvider;
import net.minecraft.tags.BlockTags;
import net.minecraft.tags.ItemTags;
import net.minecraft.tags.TagBuilder;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
@@ -28,14 +25,8 @@ import net.minecraft.world.level.block.Blocks;
*/
class TagProvider {
public static void blockTags(TagConsumer<Block> tags) {
tags.tag(ComputerCraftTags.Blocks.COMPUTER).add(
ModRegistry.Blocks.COMPUTER_NORMAL.get(),
ModRegistry.Blocks.COMPUTER_ADVANCED.get(),
ModRegistry.Blocks.COMPUTER_COMMAND.get()
);
tags.tag(ComputerCraftTags.Blocks.TURTLE).add(ModRegistry.Blocks.TURTLE_NORMAL.get(), ModRegistry.Blocks.TURTLE_ADVANCED.get());
itemAndBlockTags((b, i) -> tags.tag(b));
tags.tag(ComputerCraftTags.Blocks.WIRED_MODEM).add(ModRegistry.Blocks.CABLE.get(), ModRegistry.Blocks.WIRED_MODEM_FULL.get());
tags.tag(ComputerCraftTags.Blocks.MONITOR).add(ModRegistry.Blocks.MONITOR_NORMAL.get(), ModRegistry.Blocks.MONITOR_ADVANCED.get());
tags.tag(ComputerCraftTags.Blocks.PERIPHERAL_HUB_IGNORE).addTag(ComputerCraftTags.Blocks.WIRED_MODEM);
@@ -91,11 +82,9 @@ class TagProvider {
);
}
public static void itemTags(ItemTagConsumer tags) {
tags.copy(ComputerCraftTags.Blocks.COMPUTER, ComputerCraftTags.Items.COMPUTER);
tags.copy(ComputerCraftTags.Blocks.TURTLE, ComputerCraftTags.Items.TURTLE);
public static void itemTags(TagConsumer<Item> tags) {
itemAndBlockTags((b, i) -> tags.tag(i).map(Block::asItem));
tags.tag(ComputerCraftTags.Items.WIRED_MODEM).add(ModRegistry.Items.WIRED_MODEM.get(), ModRegistry.Items.WIRED_MODEM_FULL.get());
tags.copy(ComputerCraftTags.Blocks.MONITOR, ComputerCraftTags.Items.MONITOR);
tags.tag(ComputerCraftTags.Items.DISKS).add(ModRegistry.Items.DISK.get(), ModRegistry.Items.TREASURE_DISK.get());
tags.tag(ComputerCraftTags.Items.POCKET_COMPUTERS).add(ModRegistry.Items.POCKET_COMPUTER_NORMAL.get(), ModRegistry.Items.POCKET_COMPUTER_ADVANCED.get());
@@ -117,37 +106,32 @@ class TagProvider {
.addTag(ItemTags.BOATS);
}
private static void itemAndBlockTags(BlockItemTagConsumer tags) {
tags.tag(ComputerCraftTags.Blocks.COMPUTER, ComputerCraftTags.Items.COMPUTER).add(
ModRegistry.Blocks.COMPUTER_NORMAL.get(),
ModRegistry.Blocks.COMPUTER_ADVANCED.get(),
ModRegistry.Blocks.COMPUTER_COMMAND.get()
);
tags.tag(ComputerCraftTags.Blocks.TURTLE, ComputerCraftTags.Items.TURTLE).add(
ModRegistry.Blocks.TURTLE_NORMAL.get(),
ModRegistry.Blocks.TURTLE_ADVANCED.get()
);
tags.tag(ComputerCraftTags.Blocks.MONITOR, ComputerCraftTags.Items.MONITOR).add(
ModRegistry.Blocks.MONITOR_NORMAL.get(),
ModRegistry.Blocks.MONITOR_ADVANCED.get()
);
}
/**
* A wrapper over {@link TagsProvider}.
*
* @param <T> The type of object we're providing tags for.
*/
public interface TagConsumer<T> {
TagAppender<T> tag(TagKey<T> tag);
TagAppender<T, T> tag(TagKey<T> tag);
}
public record TagAppender<T>(Registry<T> registry, TagBuilder builder) {
public TagAppender<T> add(T object) {
builder.addElement(RegistryHelper.getKeyOrThrow(registry, object));
return this;
}
@SafeVarargs
public final TagAppender<T> add(T... objects) {
for (var object : objects) add(object);
return this;
}
public TagAppender<T> addTag(TagKey<T> tag) {
builder.addTag(tag.location());
return this;
}
}
/**
* A wrapper over {@link ItemTagsProvider}.
*/
public interface ItemTagConsumer extends TagConsumer<Item> {
void copy(TagKey<Block> block, TagKey<Item> item);
private interface BlockItemTagConsumer {
TagAppender<Block, ?> tag(TagKey<Block> blockTag, TagKey<Item> itemTag);
}
}

View File

@@ -12,12 +12,11 @@ import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.brigadier.exceptions.SimpleCommandExceptionType;
import com.mojang.brigadier.suggestion.Suggestions;
import com.mojang.brigadier.suggestion.SuggestionsBuilder;
import com.mojang.serialization.JsonOps;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
import net.minecraft.commands.synchronization.ArgumentTypeInfos;
import net.minecraft.core.RegistryAccess;
import net.minecraft.network.FriendlyByteBuf;
import net.minecraft.network.chat.Component;
import net.minecraft.network.chat.ComponentSerialization;
import java.util.ArrayList;
@@ -136,7 +135,7 @@ public final class RepeatArgumentType<T, U> implements ArgumentType<List<T>> {
public void serializeToJson(RepeatArgumentType.Template arg, JsonObject json) {
json.addProperty("flatten", arg.flatten);
json.add("child", ArgumentUtils.serializeToJson(arg.child));
json.addProperty("error", Component.Serializer.toJson(ArgumentUtils.getMessage(arg.some), RegistryAccess.EMPTY));
json.add("error", ComponentSerialization.CODEC.encodeStart(JsonOps.INSTANCE, ArgumentUtils.getMessage(arg.some)).getOrThrow());
}
}

View File

@@ -20,11 +20,9 @@ import dan200.computercraft.shared.platform.PlatformHelper;
import dan200.computercraft.shared.util.*;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.core.component.DataComponents;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.Container;
import net.minecraft.world.LockCode;
@@ -35,6 +33,8 @@ import net.minecraft.world.level.block.entity.BaseContainerBlockEntity;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jspecify.annotations.Nullable;
import java.util.Objects;
@@ -142,36 +142,36 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
protected abstract void updateBlockState(ComputerState newState);
@Override
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput nbt) {
// Save ID, label and power state
if (computerID >= 0) nbt.putInt(NBT_ID, computerID);
if (label != null) nbt.putString(NBT_LABEL, label);
if (storageCapacity > 0) nbt.putLong(NBT_CAPACITY, storageCapacity);
nbt.putBoolean(NBT_ON, on);
lockCode.addToTag(nbt, registries);
lockCode.addToTag(nbt);
super.saveAdditional(nbt, registries);
super.saveAdditional(nbt);
}
@Override
public final void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
public final void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
if (level != null && level.isClientSide) {
loadClient(nbt, registries);
loadClient(nbt);
} else {
loadServer(nbt, registries);
loadServer(nbt);
}
}
protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
protected void loadServer(ValueInput nbt) {
// Load ID, label and power state
computerID = nbt.getIntOr(NBT_ID, -1);
label = nbt.getStringOr(NBT_LABEL, null);
storageCapacity = nbt.getLongOr(NBT_CAPACITY, -1);
on = startOn = nbt.getBooleanOr(NBT_ON, false);
lockCode = LockCode.fromTag(nbt, registries);
lockCode = LockCode.fromTag(nbt);
}
@Override
@@ -204,12 +204,12 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
@Override
@Deprecated
public void removeComponentsFromTag(CompoundTag tag) {
public void removeComponentsFromTag(ValueOutput tag) {
super.removeComponentsFromTag(tag);
tag.remove(NBT_ID);
tag.remove(NBT_LABEL);
tag.remove(NBT_CAPACITY);
tag.remove(LockCode.TAG_LOCK);
tag.discard(NBT_ID);
tag.discard(NBT_LABEL);
tag.discard(NBT_CAPACITY);
tag.discard(LockCode.TAG_LOCK);
}
protected boolean isPeripheralBlockedOnSide(ComputerSide localSide) {
@@ -391,7 +391,7 @@ public abstract class AbstractComputerBlockEntity extends BlockEntity implements
// Networking stuff
protected void loadClient(CompoundTag nbt, HolderLookup.Provider registries) {
protected void loadClient(ValueInput tag) {
}
protected void transferStateFrom(AbstractComputerBlockEntity copy) {

View File

@@ -13,19 +13,18 @@ import dan200.computercraft.shared.computer.core.ServerComputer;
import dan200.computercraft.shared.computer.core.TerminalSize;
import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory;
import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponentGetter;
import net.minecraft.core.component.DataComponentMap;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jspecify.annotations.Nullable;
public class ComputerBlockEntity extends AbstractComputerBlockEntity {
@@ -40,15 +39,15 @@ public class ComputerBlockEntity extends AbstractComputerBlockEntity {
}
@Override
protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadServer(nbt, registries);
terminalSize = NBTUtil.decodeFrom(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE);
protected void loadServer(ValueInput nbt) {
super.loadServer(nbt);
terminalSize = nbt.read(NBT_TERMINAL_SIZE, TerminalSize.CODEC).orElse(null);
}
@Override
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.saveAdditional(nbt, registries);
NBTUtil.encodeTo(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE, terminalSize);
public void saveAdditional(ValueOutput tag) {
super.saveAdditional(tag);
tag.storeNullable(NBT_TERMINAL_SIZE, TerminalSize.CODEC, terminalSize);
}
@Override
@@ -65,9 +64,9 @@ public class ComputerBlockEntity extends AbstractComputerBlockEntity {
@Override
@Deprecated
public void removeComponentsFromTag(CompoundTag tag) {
public void removeComponentsFromTag(ValueOutput tag) {
super.removeComponentsFromTag(tag);
tag.remove(NBT_TERMINAL_SIZE);
tag.discard(NBT_TERMINAL_SIZE);
}
@Override

View File

@@ -220,7 +220,7 @@ public final class ServerContext {
@Override
public String getHostString() {
var version = SharedConstants.getCurrentVersion().getName();
var version = SharedConstants.getCurrentVersion().name();
return String.format("ComputerCraft %s (Minecraft %s)", ComputerCraftAPI.getInstalledVersion(), version);
}

View File

@@ -7,7 +7,8 @@ package dan200.computercraft.shared.computer.terminal;
import dan200.computercraft.core.terminal.Palette;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.core.util.Colour;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
public class NetworkedTerminal extends Terminal {
public NetworkedTerminal(int width, int height, boolean colour) {
@@ -76,7 +77,7 @@ public class NetworkedTerminal extends Terminal {
setChanged();
}
public synchronized CompoundTag writeToNBT(CompoundTag nbt) {
public synchronized void writeToNBT(ValueOutput nbt) {
nbt.putInt("term_cursorX", cursorX);
nbt.putInt("term_cursorY", cursorY);
nbt.putBoolean("term_cursorBlink", cursorBlink);
@@ -91,11 +92,9 @@ public class NetworkedTerminal extends Terminal {
var rgb8 = new int[Palette.PALETTE_SIZE];
for (var i = 0; i < Palette.PALETTE_SIZE; i++) rgb8[i] = Palette.encodeRGB8(palette.getColour(i));
nbt.putIntArray("term_palette", rgb8);
return nbt;
}
public synchronized void readFromNBT(CompoundTag nbt) {
public synchronized void readFromNBT(ValueInput nbt) {
cursorX = nbt.getIntOr("term_cursorX", 0);
cursorY = nbt.getIntOr("term_cursorY", 0);
cursorBlink = nbt.getBooleanOr("term_cursorBlink", false);
@@ -104,29 +103,26 @@ public class NetworkedTerminal extends Terminal {
for (var n = 0; n < height; n++) {
text[n].fill(' ');
if (nbt.contains("term_text_" + n)) {
text[n].write(nbt.getStringOr("term_text_" + n, ""));
}
var line = nbt.getStringOr("term_text_" + n, "");
if (!line.isEmpty()) text[n].write(line);
textColour[n].fill(BASE_16.charAt(cursorColour));
if (nbt.contains("term_textColour_" + n)) {
textColour[n].write(nbt.getStringOr("term_textColour_" + n, ""));
}
var fgLine = nbt.getStringOr("term_textColour_" + n, "");
if (!fgLine.isEmpty()) textColour[n].write(fgLine);
backgroundColour[n].fill(BASE_16.charAt(cursorBackgroundColour));
if (nbt.contains("term_textBgColour_" + n)) {
backgroundColour[n].write(nbt.getStringOr("term_textBgColour_" + n, ""));
var bgLine = nbt.getStringOr("term_textBgColour_" + n, "");
if (!bgLine.isEmpty()) backgroundColour[n].write(bgLine);
}
var rgb8 = nbt.getIntArray("term_palette").orElse(null);
if (rgb8 != null && rgb8.length == Palette.PALETTE_SIZE) {
for (var i = 0; i < Palette.PALETTE_SIZE; i++) {
var colours = Palette.decodeRGB8(rgb8[i]);
palette.setColour(i, colours[0], colours[1], colours[2]);
}
}
if (nbt.contains("term_palette")) {
var rgb8 = nbt.getIntArray("term_palette").orElse(null);
if (rgb8 != null && rgb8.length == Palette.PALETTE_SIZE) {
for (var i = 0; i < Palette.PALETTE_SIZE; i++) {
var colours = Palette.decodeRGB8(rgb8[i]);
palette.setColour(i, colours[0], colours[1], colours[2]);
}
}
}
setChanged();
}
}

View File

@@ -13,8 +13,6 @@ import dan200.computercraft.shared.ModRegistry;
import net.minecraft.util.datafix.fixes.DataComponentRemainderFix;
import net.minecraft.util.datafix.fixes.FoodToConsumableFix;
import net.minecraft.util.datafix.fixes.References;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import java.util.function.Function;
@@ -53,6 +51,4 @@ public final class RenamePocketComputerUpgradeFix extends DataFix {
dynamic -> dynamic.renameField("computercraft:pocket_upgrade", "computercraft:back_pocket_upgrade")
);
}
private static final Logger LOG = LoggerFactory.getLogger(RenamePocketComputerUpgradeFix.class);
}

View File

@@ -20,6 +20,7 @@ import net.minecraft.network.protocol.Packet;
import net.minecraft.network.protocol.game.ClientGamePacketListener;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.util.Mth;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.Container;
import net.minecraft.world.SimpleMenuProvider;
import net.minecraft.world.entity.player.Player;
@@ -29,6 +30,11 @@ import net.minecraft.world.level.block.LecternBlock;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.LecternBlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.AbstractList;
import java.util.List;
@@ -41,6 +47,8 @@ import static dan200.computercraft.shared.lectern.CustomLecternBlock.dropItem;
* @see LecternBlockEntity
*/
public final class CustomLecternBlockEntity extends BlockEntity {
private static final Logger LOG = LoggerFactory.getLogger(CustomLecternBlockEntity.class);
private static final String NBT_ITEM = "Item";
private static final String NBT_PAGE = "Page";
@@ -107,19 +115,19 @@ public final class CustomLecternBlockEntity extends BlockEntity {
}
@Override
public void loadAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.loadAdditional(tag, registries);
public void loadAdditional(ValueInput tag) {
super.loadAdditional(tag);
item = tag.getCompound(NBT_ITEM).flatMap(x -> ItemStack.parse(registries, x)).orElse(ItemStack.EMPTY);
item = tag.read(NBT_ITEM, ItemStack.CODEC).orElse(ItemStack.EMPTY);
page = tag.getIntOr(NBT_PAGE, 0);
itemChanged();
}
@Override
protected void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
protected void saveAdditional(ValueOutput tag) {
super.saveAdditional(tag);
if (!item.isEmpty()) tag.put(NBT_ITEM, item.save(registries));
if (!item.isEmpty()) tag.store(NBT_ITEM, ItemStack.CODEC, item);
if (item.getItem() instanceof PrintoutItem) tag.putInt(NBT_PAGE, page);
}
@@ -130,9 +138,11 @@ public final class CustomLecternBlockEntity extends BlockEntity {
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
var tag = super.getUpdateTag(registries);
if (!item.isEmpty()) tag.put(NBT_ITEM, item.save(registries));
return tag;
try (var problems = new ProblemReporter.ScopedCollector(this.problemPath(), LOG)) {
var output = TagValueOutput.createWithContext(problems, registries);
if (!item.isEmpty()) output.store(NBT_ITEM, ItemStack.CODEC, item);
return output.buildResult();
}
}
void openMenu(Player player) {

View File

@@ -87,6 +87,7 @@ public class DiskRecipe extends AbstractCraftingRecipe {
var stack = inv.getItem(i);
if (stack.isEmpty()) continue;
if (ColourUtils.getStackColour(stack) == null) {
inputs++;
stackedContents.accountStack(stack, 1);
}
}

View File

@@ -17,9 +17,7 @@ import dan200.computercraft.shared.network.server.ServerNetworking;
import dan200.computercraft.shared.util.WorldUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -27,6 +25,8 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.block.LevelEvent;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
@@ -114,17 +114,17 @@ public final class DiskDriveBlockEntity extends AbstractContainerBlockEntity imp
}
@Override
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
setDiskStack(nbt.getCompound(NBT_ITEM).flatMap(x -> ItemStack.parse(registries, x)).orElse(ItemStack.EMPTY));
public void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
setDiskStack(nbt.read(NBT_ITEM, ItemStack.CODEC).orElse(ItemStack.EMPTY));
}
@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
super.saveAdditional(tag, registries);
public void saveAdditional(ValueOutput tag) {
super.saveAdditional(tag);
var stack = getDiskStack();
if (!stack.isEmpty()) tag.put(NBT_ITEM, stack.save(registries));
if (!stack.isEmpty()) tag.store(NBT_ITEM, ItemStack.CODEC, stack);
}
void serverTick() {

View File

@@ -15,8 +15,6 @@ import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
@@ -24,6 +22,8 @@ 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.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
@@ -144,15 +144,15 @@ public class CableBlockEntity extends BlockEntity {
}
@Override
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
public void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
peripheral.read(nbt, "");
}
@Override
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput nbt) {
peripheral.write(nbt, "");
super.saveAdditional(nbt, registries);
super.saveAdditional(nbt);
}
private void updateBlockState() {

View File

@@ -15,8 +15,6 @@ import dan200.computercraft.shared.util.DirectionUtil;
import dan200.computercraft.shared.util.TickScheduler;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
@@ -24,6 +22,8 @@ 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.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
@@ -155,15 +155,15 @@ public class WiredModemFullBlockEntity extends BlockEntity {
}
@Override
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
public void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
for (var i = 0; i < peripherals.length; i++) peripherals[i].read(nbt, Integer.toString(i));
}
@Override
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput nbt) {
for (var i = 0; i < peripherals.length; i++) peripherals[i].write(nbt, Integer.toString(i));
super.saveAdditional(nbt, registries);
super.saveAdditional(nbt);
}
void blockTick() {

View File

@@ -11,8 +11,9 @@ import dan200.computercraft.shared.computer.core.ServerContext;
import dan200.computercraft.shared.platform.ComponentAccess;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jspecify.annotations.Nullable;
import java.util.Map;
@@ -97,12 +98,12 @@ public final class WiredModemLocalPeripheral {
return peripheral == null ? Map.of() : Map.of(type + "_" + id, peripheral);
}
public void write(CompoundTag tag, String suffix) {
public void write(ValueOutput tag, String suffix) {
if (id >= 0) tag.putInt(NBT_PERIPHERAL_ID + suffix, id);
if (type != null) tag.putString(NBT_PERIPHERAL_TYPE + suffix, type);
}
public void read(CompoundTag tag, String suffix) {
public void read(ValueInput tag, String suffix) {
id = tag.getIntOr(NBT_PERIPHERAL_ID + suffix, -1);
type = tag.getStringOr(NBT_PERIPHERAL_TYPE + suffix, null);
}

View File

@@ -22,6 +22,8 @@ import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
@@ -107,17 +109,17 @@ public class MonitorBlockEntity extends BlockEntity {
}
@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput tag) {
tag.putInt(NBT_X, xIndex);
tag.putInt(NBT_Y, yIndex);
tag.putInt(NBT_WIDTH, width);
tag.putInt(NBT_HEIGHT, height);
super.saveAdditional(tag, registries);
super.saveAdditional(tag);
}
@Override
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
public void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
var oldXIndex = xIndex;
var oldYIndex = yIndex;

View File

@@ -15,9 +15,7 @@ import dan200.computercraft.shared.util.ColourUtils;
import dan200.computercraft.shared.util.DataComponentUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.inventory.AbstractContainerMenu;
@@ -25,6 +23,8 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import org.jspecify.annotations.Nullable;
import java.util.List;
@@ -55,8 +55,8 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
}
@Override
public void loadAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadAdditional(nbt, registries);
public void loadAdditional(ValueInput nbt) {
super.loadAdditional(nbt);
// Read page
synchronized (page) {
@@ -66,11 +66,11 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
}
// Read inventory
ContainerHelper.loadAllItems(nbt, inventory, registries);
ContainerHelper.loadAllItems(nbt, inventory);
}
@Override
public void saveAdditional(CompoundTag tag, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput tag) {
// Write page
synchronized (page) {
tag.putBoolean(NBT_PRINTING, printing);
@@ -79,9 +79,9 @@ public final class PrinterBlockEntity extends AbstractContainerBlockEntity imple
}
// Write inventory
ContainerHelper.saveAllItems(tag, inventory, registries);
ContainerHelper.saveAllItems(tag, inventory);
super.saveAdditional(tag, registries);
super.saveAdditional(tag);
}
boolean isPrinting() {

View File

@@ -35,6 +35,7 @@ import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.entity.player.Inventory;
@@ -45,13 +46,20 @@ import net.minecraft.world.item.component.DyedItemColor;
import net.minecraft.world.item.component.TooltipDisplay;
import net.minecraft.world.level.block.entity.BlockEntityType;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Collections;
import java.util.function.IntSupplier;
public class TurtleBlockEntity extends AbstractComputerBlockEntity implements BasicContainer {
private static final Logger LOG = LoggerFactory.getLogger(TurtleBlockEntity.class);
public static final int INVENTORY_SIZE = 16;
public static final int INVENTORY_WIDTH = 4;
public static final int INVENTORY_HEIGHT = 4;
@@ -142,26 +150,26 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
}
@Override
public void loadServer(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadServer(nbt, registries);
public void loadServer(ValueInput nbt) {
super.loadServer(nbt);
// Read inventory
ContainerHelper.loadAllItems(nbt, inventory, registries);
ContainerHelper.loadAllItems(nbt, inventory);
for (var i = 0; i < inventory.size(); i++) inventorySnapshot.set(i, inventory.get(i).copy());
// Read state
brain.readFromNBT(nbt, registries);
brain.readFromNBT(nbt);
}
@Override
public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) {
public void saveAdditional(ValueOutput nbt) {
// Write inventory
ContainerHelper.saveAllItems(nbt, inventory, registries);
ContainerHelper.saveAllItems(nbt, inventory);
// Write brain
brain.writeToNBT(nbt, registries);
brain.writeToNBT(nbt);
super.saveAdditional(nbt, registries);
super.saveAdditional(nbt);
}
@Override
@@ -197,13 +205,13 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
@Override
@Deprecated
public void removeComponentsFromTag(CompoundTag tag) {
public void removeComponentsFromTag(ValueOutput tag) {
super.removeComponentsFromTag(tag);
tag.remove(TurtleBrain.NBT_COLOUR);
tag.remove(TurtleBrain.NBT_FUEL);
tag.remove(TurtleBrain.NBT_OVERLAY);
tag.remove(TurtleBrain.NBT_LEFT_UPGRADE);
tag.remove(TurtleBrain.NBT_RIGHT_UPGRADE);
tag.discard(TurtleBrain.NBT_COLOUR);
tag.discard(TurtleBrain.NBT_FUEL);
tag.discard(TurtleBrain.NBT_OVERLAY);
tag.discard(TurtleBrain.NBT_LEFT_UPGRADE);
tag.discard(TurtleBrain.NBT_RIGHT_UPGRADE);
}
@Override
@@ -301,17 +309,19 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba
@Override
public CompoundTag getUpdateTag(HolderLookup.Provider registries) {
var nbt = super.getUpdateTag(registries);
if (label != null) nbt.putString(NBT_LABEL, label);
brain.writeDescription(nbt, registries);
return nbt;
try (var problems = new ProblemReporter.ScopedCollector(problemPath(), LOG)) {
var nbt = TagValueOutput.createWithContext(problems, registries);
if (label != null) nbt.putString(NBT_LABEL, label);
brain.writeDescription(nbt);
return nbt.buildResult();
}
}
@Override
public void loadClient(CompoundTag nbt, HolderLookup.Provider registries) {
super.loadClient(nbt, registries);
public void loadClient(ValueInput nbt) {
super.loadClient(nbt);
label = nbt.getStringOr(NBT_LABEL, null);
brain.readDescription(nbt, registries);
brain.readDescription(nbt);
}
// Privates

View File

@@ -23,17 +23,15 @@ import dan200.computercraft.shared.container.InventoryDelegate;
import dan200.computercraft.shared.turtle.blocks.TurtleBlockEntity;
import dan200.computercraft.shared.util.BlockEntityHelpers;
import dan200.computercraft.shared.util.Holiday;
import dan200.computercraft.shared.util.NBTUtil;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.component.DataComponentPatch;
import net.minecraft.core.particles.ParticleTypes;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.tags.FluidTags;
import net.minecraft.util.ExtraCodecs;
import net.minecraft.world.Container;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.MoverType;
@@ -41,11 +39,16 @@ import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.material.PushReaction;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.jspecify.annotations.Nullable;
import java.util.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Objects;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import static dan200.computercraft.shared.util.WaterloggableHelpers.WATERLOGGED;
@@ -127,67 +130,50 @@ public class TurtleBrain implements TurtleAccessInternal {
/**
* Read common data for saving and client synchronisation.
*
* @param nbt The tag to read from
* @param registries The current registries.
* @param nbt The tag to read from
*/
private void readCommon(CompoundTag nbt, HolderLookup.Provider registries) {
private void readCommon(ValueInput nbt) {
// Read fields
colourHex = nbt.getIntOr(NBT_COLOUR, -1);
fuelLevel = nbt.getIntOr(NBT_FUEL, 0);
overlay = nbt.contains(NBT_OVERLAY) ? NBTUtil.decodeFrom(ResourceLocation.CODEC, registries, nbt, NBT_OVERLAY) : null;
overlay = nbt.read(NBT_OVERLAY, ResourceLocation.CODEC).orElse(null);
// Read upgrades
setUpgradeDirect(TurtleSide.LEFT, NBTUtil.decodeFrom(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE));
setUpgradeDirect(TurtleSide.RIGHT, NBTUtil.decodeFrom(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_RIGHT_UPGRADE));
setUpgradeDirect(TurtleSide.LEFT, nbt.read(NBT_LEFT_UPGRADE, TurtleUpgrades.instance().upgradeDataCodec()).orElse(null));
setUpgradeDirect(TurtleSide.RIGHT, nbt.read(NBT_RIGHT_UPGRADE, TurtleUpgrades.instance().upgradeDataCodec()).orElse(null));
}
private void writeCommon(CompoundTag nbt, HolderLookup.Provider registries) {
private void writeCommon(ValueOutput nbt) {
nbt.putInt(NBT_FUEL, fuelLevel);
if (colourHex != -1) nbt.putInt(NBT_COLOUR, colourHex);
NBTUtil.encodeTo(ResourceLocation.CODEC, registries, nbt, NBT_OVERLAY, overlay);
nbt.storeNullable(NBT_OVERLAY, ResourceLocation.CODEC, overlay);
// Write upgrades
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_LEFT_UPGRADE, getUpgradeWithData(TurtleSide.LEFT));
NBTUtil.encodeTo(TurtleUpgrades.instance().upgradeDataCodec(), registries, nbt, NBT_RIGHT_UPGRADE, getUpgradeWithData(TurtleSide.RIGHT));
nbt.storeNullable(NBT_LEFT_UPGRADE, TurtleUpgrades.instance().upgradeDataCodec(), getUpgradeWithData(TurtleSide.LEFT));
nbt.storeNullable(NBT_RIGHT_UPGRADE, TurtleUpgrades.instance().upgradeDataCodec(), getUpgradeWithData(TurtleSide.RIGHT));
}
public void readFromNBT(CompoundTag nbt, HolderLookup.Provider registries) {
readCommon(nbt, registries);
public void readFromNBT(ValueInput nbt) {
readCommon(nbt);
// Read state
selectedSlot = nbt.getIntOr(NBT_SLOT, 0);
// Read owner
var owner = nbt.getCompound("Owner").orElse(null);
if (owner != null) {
owningPlayer = new GameProfile(
new UUID(owner.getLongOr("UpperId", 0), owner.getLongOr("LowerId", 0)),
owner.getStringOr("Name", "")
);
} else {
owningPlayer = null;
}
owningPlayer = nbt.read("Owner", ExtraCodecs.GAME_PROFILE).orElse(null);
}
public void writeToNBT(CompoundTag nbt, HolderLookup.Provider registries) {
writeCommon(nbt, registries);
public void writeToNBT(ValueOutput nbt) {
writeCommon(nbt);
// Write state
nbt.putInt(NBT_SLOT, selectedSlot);
// Write owner
if (owningPlayer != null) {
var owner = new CompoundTag();
nbt.put("Owner", owner);
owner.putLong("UpperId", owningPlayer.getId().getMostSignificantBits());
owner.putLong("LowerId", owningPlayer.getId().getLeastSignificantBits());
owner.putString("Name", owningPlayer.getName());
}
nbt.storeNullable("Owner", ExtraCodecs.GAME_PROFILE, owningPlayer);
// TODO(1.21.6): Data fixer for this.
}
public void readDescription(CompoundTag nbt, HolderLookup.Provider registries) {
readCommon(nbt, registries);
public void readDescription(ValueInput nbt) {
readCommon(nbt);
// Animation
var anim = TurtleAnimation.values()[nbt.getIntOr("Animation", 0)];
@@ -201,8 +187,8 @@ public class TurtleBrain implements TurtleAccessInternal {
}
}
public void writeDescription(CompoundTag nbt, HolderLookup.Provider registries) {
writeCommon(nbt, registries);
public void writeDescription(ValueOutput nbt) {
writeCommon(nbt);
nbt.putInt("Animation", animation.ordinal());
}

View File

@@ -214,7 +214,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
var baseDamage = (float) player.getAttributeValue(Attributes.ATTACK_DAMAGE) * spec.damageMultiplier();
var tool = player.getWeaponItem();
var source = player.damageSources().playerAttack(player);
var bonusDamage = EnchantmentHelper.modifyDamage(player.serverLevel(), tool, entity, source, baseDamage) - baseDamage;
var bonusDamage = EnchantmentHelper.modifyDamage(player.level(), tool, entity, source, baseDamage) - baseDamage;
// If this is a projectile, attempt to deflect it instead.
if (entity.getType().is(EntityTypeTags.REDIRECTABLE_PROJECTILE) && entity instanceof Projectile projectile &&
@@ -229,13 +229,13 @@ public class TurtleTool extends AbstractTurtleUpgrade {
// Compute the total damage, and deal it out.
var damage = baseDamage + bonusDamage + tool.getItem().getAttackDamageBonus(entity, baseDamage, source);
if (!entity.hurtServer(player.serverLevel(), source, damage)) return false;
if (!entity.hurtServer(player.level(), source, damage)) return false;
// Special case for armor stands: attack twice to guarantee destroy
if (entity.isAlive() && entity instanceof ArmorStand) entity.hurtServer(player.serverLevel(), source, damage);
if (entity.isAlive() && entity instanceof ArmorStand) entity.hurtServer(player.level(), source, damage);
// Apply knockback
var knockBack = EnchantmentHelper.modifyKnockback(player.serverLevel(), tool, entity, source, (float) player.getAttributeValue(Attributes.ATTACK_KNOCKBACK));
var knockBack = EnchantmentHelper.modifyKnockback(player.level(), tool, entity, source, (float) player.getAttributeValue(Attributes.ATTACK_KNOCKBACK));
if (knockBack > 0) {
if (entity instanceof LivingEntity target) {
target.knockback(knockBack * 0.5, -direction.getStepX(), -direction.getStepZ());
@@ -253,7 +253,7 @@ public class TurtleTool extends AbstractTurtleUpgrade {
var didHurt = entity instanceof LivingEntity target && tool.hurtEnemy(target, player);
// Apply remaining enchantments
EnchantmentHelper.doPostAttackEffects(player.serverLevel(), entity, source);
EnchantmentHelper.doPostAttackEffects(player.level(), entity, source);
// Damage the original item stack.
if (!tool.isEmpty() && entity instanceof LivingEntity living && didHurt) {

View File

@@ -6,9 +6,7 @@ package dan200.computercraft.shared.util;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.io.BaseEncoding;
import com.mojang.serialization.Codec;
import dan200.computercraft.core.util.Nullability;
import net.minecraft.core.HolderLookup;
import net.minecraft.nbt.*;
import org.jspecify.annotations.Nullable;
import org.slf4j.Logger;
@@ -30,14 +28,6 @@ public final class NBTUtil {
private NBTUtil() {
}
public static <T> @Nullable T decodeFrom(Codec<T> codec, HolderLookup.Provider registries, CompoundTag tag, String key) {
return tag.read(key, codec, registries.createSerializationContext(NbtOps.INSTANCE)).orElse(null);
}
public static <T> void encodeTo(Codec<T> codec, HolderLookup.Provider registries, CompoundTag destination, String key, @Nullable T value) {
destination.storeNullable(key, codec, registries.createSerializationContext(NbtOps.INSTANCE), value);
}
public static @Nullable Object toLua(@Nullable Tag tag) {
if (tag == null) return null;

View File

@@ -36,3 +36,8 @@ accessible method net/minecraft/client/data/models/ItemModelGenerators generateF
accessible method net/minecraft/client/data/models/ItemModelGenerators generateFlatItem (Lnet/minecraft/world/item/Item;Lnet/minecraft/client/data/models/model/ModelTemplate;)V
accessible method net/minecraft/client/data/models/model/TextureSlot create (Ljava/lang/String;)Lnet/minecraft/client/data/models/model/TextureSlot;
accessible method net/minecraft/data/recipes/RecipeProvider inventoryTrigger ([Lnet/minecraft/advancements/critereon/ItemPredicate;)Lnet/minecraft/advancements/Criterion;
# GUI elements
accessible class net/minecraft/client/gui/GuiGraphics$ScissorStack
accessible field net/minecraft/client/gui/GuiGraphics guiRenderState Lnet/minecraft/client/gui/render/state/GuiRenderState;
accessible field net/minecraft/client/gui/GuiGraphics scissorStack Lnet/minecraft/client/gui/GuiGraphics$ScissorStack;

View File

@@ -27,6 +27,12 @@ accessible field net/minecraft/client/sounds/SoundEngine executor Lnet/minecraft
# Turtle model
accessible class net/minecraft/util/datafix/fixes/ItemStackComponentizationFix$ItemStackData
# GUI elements
accessible field net/minecraft/client/gui/GuiGraphics minecraft Lnet/minecraft/client/Minecraft;
# Fog
accessible field net/minecraft/client/renderer/GameRenderer fogRenderer Lnet/minecraft/client/renderer/fog/FogRenderer;
# TODO(1.21.5): Add these to Fabric.
accessible field net/minecraft/client/data/models/BlockModelGenerators ROTATION_FACING Lnet/minecraft/client/data/models/blockstates/PropertyDispatch;
accessible field net/minecraft/client/data/models/BlockModelGenerators ROTATION_HORIZONTAL_FACING Lnet/minecraft/client/data/models/blockstates/PropertyDispatch;

View File

@@ -7,7 +7,7 @@ package dan200.computercraft.shared.computer.terminal;
import dan200.computercraft.api.lua.LuaValues;
import dan200.computercraft.core.terminal.Terminal;
import dan200.computercraft.test.core.CallCounter;
import net.minecraft.nbt.CompoundTag;
import dan200.computercraft.test.shared.SerialisationUtils;
import org.junit.jupiter.api.Test;
import static dan200.computercraft.test.core.terminal.TerminalMatchers.*;
@@ -24,13 +24,12 @@ class NetworkedTerminalTest {
writeTerminal.setTextColour(3);
writeTerminal.setBackgroundColour(5);
var nbt = new CompoundTag();
writeTerminal.writeToNBT(nbt);
var nbt = SerialisationUtils.writeNBT(writeTerminal::writeToNBT);
var callCounter = new CallCounter();
var readTerminal = new NetworkedTerminal(2, 1, true, callCounter);
readTerminal.readFromNBT(nbt);
SerialisationUtils.readNBT(nbt, readTerminal::readFromNBT);
assertThat(readTerminal, allOf(
textMatches(new String[]{ "hi", }),
@@ -49,12 +48,11 @@ class NetworkedTerminalTest {
void testReadWriteNBTEmpty() {
var terminal = new NetworkedTerminal(0, 0, true);
var nbt = new CompoundTag();
terminal.writeToNBT(nbt);
var nbt = SerialisationUtils.writeNBT(terminal::writeToNBT);
var callCounter = new CallCounter();
terminal = new NetworkedTerminal(0, 1, true, callCounter);
terminal.readFromNBT(nbt);
SerialisationUtils.readNBT(nbt, terminal::readFromNBT);
assertThat(terminal, allOf(
textMatches(new String[]{ "", }),

View File

@@ -0,0 +1,33 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.test.shared;
import net.minecraft.core.RegistryAccess;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.level.storage.ValueOutput;
import java.util.function.Consumer;
/***
* Helpers for serialising and unserialising values.
*/
public final class SerialisationUtils {
private SerialisationUtils() {
}
public static CompoundTag writeNBT(Consumer<ValueOutput> generate) {
var output = TagValueOutput.createWithoutContext(ProblemReporter.DISCARDING);
generate.accept(output);
return output.buildResult();
}
public static void readNBT(CompoundTag tag, Consumer<ValueInput> generate) {
generate.accept(TagValueInput.create(ProblemReporter.DISCARDING, RegistryAccess.EMPTY, tag));
}
}

View File

@@ -16,12 +16,9 @@ import com.mojang.brigadier.builder.RequiredArgumentBuilder;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.gametest.core.TestHooks;
import dan200.computercraft.shared.util.PrettyJsonWriter;
import dan200.computercraft.shared.util.RegistryHelper;
import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiGraphics;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.network.chat.Component;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.crafting.RecipeType;
import net.minecraft.world.item.crafting.display.ShapedCraftingRecipeDisplay;
import net.minecraft.world.item.crafting.display.ShapelessCraftingRecipeDisplay;
@@ -60,8 +57,8 @@ public class Exporter {
}
RenderSystem.assertOnRenderThread();
try (var renderer = new ImageRenderer()) {
export(output, renderer);
try {
export(output);
} catch (IOException e) {
throw new UncheckedIOException(e);
}
@@ -69,7 +66,7 @@ public class Exporter {
Minecraft.getInstance().gui.getChat().addMessage(Component.literal("Export finished!"));
}
private static void export(Path root, ImageRenderer renderer) throws IOException {
private static void export(Path root) throws IOException {
var dump = new JsonDump();
// First find all CC items
@@ -121,21 +118,6 @@ public class Exporter {
var itemDir = root.resolve("items");
if (Files.exists(itemDir)) MoreFiles.deleteRecursively(itemDir, RecursiveDeleteOption.ALLOW_INSECURE);
for (var item : items) {
var stack = new ItemStack(item);
var location = RegistryHelper.getKeyOrThrow(BuiltInRegistries.ITEM, item);
dump.itemNames.put(location.toString(), stack.getHoverName().getString());
renderer.captureRender(itemDir.resolve(location.getNamespace()).resolve(location.getPath() + ".png"),
() -> {
var graphics = new GuiGraphics(Minecraft.getInstance(), Minecraft.getInstance().renderBuffers().bufferSource());
graphics.renderItem(stack, 0, 0);
graphics.flush();
}
);
}
try (Writer writer = Files.newBufferedWriter(root.resolve("index.json")); var jsonWriter = new PrettyJsonWriter(writer)) {
GSON.toJson(dump, JsonDump.class, jsonWriter);
}

View File

@@ -1,71 +0,0 @@
// SPDX-FileCopyrightText: 2022 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.export;
import com.mojang.blaze3d.ProjectionType;
import com.mojang.blaze3d.pipeline.TextureTarget;
import com.mojang.blaze3d.platform.NativeImage;
import com.mojang.blaze3d.systems.RenderSystem;
import org.joml.Matrix4f;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
/**
* Utilities for saving OpenGL output to an image rather than displaying it on the screen.
*/
public class ImageRenderer implements AutoCloseable {
public static final int WIDTH = 64;
public static final int HEIGHT = 64;
private final TextureTarget framebuffer = new TextureTarget("Export", WIDTH, HEIGHT, true);
private final NativeImage image = new NativeImage(WIDTH, HEIGHT, true);
public ImageRenderer() {
// framebuffer.setFilterMode(0, 0, 0, 0);
// framebuffer.clear();
}
public void captureRender(Path output, Runnable render) throws IOException {
Files.createDirectories(output.getParent());
// RenderSystem.clear(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT);
// framebuffer.bindWrite(true);
// Setup rendering state
RenderSystem.backupProjectionMatrix();
RenderSystem.setProjectionMatrix(new Matrix4f().identity().ortho(0, 16, 16, 0, 1000, 3000), ProjectionType.ORTHOGRAPHIC);
var transform = RenderSystem.getModelViewStack();
transform.pushMatrix();
transform.identity();
transform.translate(0.0f, 0.0f, -2000.0f);
// Render
render.run();
// Restore rendering state
RenderSystem.restoreProjectionMatrix();
transform.popMatrix();
// framebuffer.unbindWrite();
// Minecraft.getInstance().getMainRenderTarget().bindWrite(true);
// And save the image
// framebuffer.bindRead();
// image.downloadTexture(0, false);
// image.flipY();
// framebuffer.unbindRead();
image.writeToFile(output);
}
@Override
public void close() {
image.close();
framebuffer.destroyBuffers();
}
}

View File

@@ -6,6 +6,7 @@ package dan200.computercraft.gametest.core;
import com.mojang.brigadier.CommandDispatcher;
import dan200.computercraft.api.ComputerCraftAPI;
import dan200.computercraft.mixin.gametest.ArmorStandAccessor;
import dan200.computercraft.shared.ModRegistry;
import dan200.computercraft.shared.util.NonNegativeId;
import net.minecraft.ChatFormatting;
@@ -42,7 +43,7 @@ class CCTestCommand {
dispatcher.register(choice("cctest")
.then(literal("marker").executes(context -> {
var player = context.getSource().getPlayerOrException();
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.serverLevel()).orElse(null);
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.level()).orElse(null);
if (pos == null) return error(context.getSource(), "No nearby test");
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)
@@ -50,7 +51,7 @@ class CCTestCommand {
if (test == null) return error(context.getSource(), "No nearby structure block");
// Kill the existing armor stand
var level = player.serverLevel();
var level = player.level();
level.getEntities(EntityType.ARMOR_STAND, x -> x.isAlive() && x.getName().getString().equals(test.location().getPath()))
.forEach(e -> e.kill(level));
@@ -59,7 +60,8 @@ class CCTestCommand {
nbt.putBoolean("Marker", true);
nbt.putBoolean("Invisible", true);
var armorStand = new ArmorStand(EntityType.ARMOR_STAND, level);
armorStand.readAdditionalSaveData(nbt);
armorStand.setInvisible(true);
((ArmorStandAccessor) armorStand).computercraft$setMarker(true);
armorStand.copyPosition(player);
armorStand.setCustomName(Component.literal(test.location().getPath()));
level.addFreshEntity(armorStand);
@@ -70,7 +72,7 @@ class CCTestCommand {
var item = context.getArgument("item", ItemInput.class);
var player = context.getSource().getPlayerOrException();
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.serverLevel()).orElse(null);
var pos = StructureUtils.findNearestTest(player.blockPosition(), 15, player.level()).orElse(null);
if (pos == null) return error(context.getSource(), "No nearby test");
var test = player.level().getBlockEntity(pos, BlockEntityType.TEST_INSTANCE_BLOCK)

View File

@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers
//
// SPDX-License-Identifier: MPL-2.0
package dan200.computercraft.mixin.gametest;
import net.minecraft.world.entity.decoration.ArmorStand;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Invoker;
@Mixin(ArmorStand.class)
public interface ArmorStandAccessor {
@Invoker("setMarker")
void computercraft$setMarker(boolean marker);
}

View File

@@ -116,7 +116,7 @@ class ClientTestHelper {
val minecraft: Minecraft = Minecraft.getInstance()
fun screenshot(name: String, callback: () -> Unit = {}) {
Screenshot.grab(minecraft.gameDirectory, name, minecraft.mainRenderTarget) { callback() }
Screenshot.grab(minecraft.gameDirectory, name, minecraft.mainRenderTarget, 1) { callback() }
}
/**

View File

@@ -15,6 +15,7 @@ import net.minecraft.client.gui.screens.TitleScreen
import net.minecraft.client.tutorial.TutorialSteps
import net.minecraft.core.registries.Registries
import net.minecraft.gametest.framework.*
import net.minecraft.network.chat.Component
import net.minecraft.server.MinecraftServer
import net.minecraft.server.level.ParticleStatus
import net.minecraft.sounds.SoundSource
@@ -196,8 +197,8 @@ object ClientTestHooks {
val minecraft = Minecraft.getInstance()
minecraft.execute {
LOG.info("Stopping client.")
minecraft.level!!.disconnect()
minecraft.disconnect()
minecraft.level!!.disconnect(Component.empty())
minecraft.disconnectWithSavingScreen()
minecraft.stop()
exitProcess(

View File

@@ -7,6 +7,7 @@
"defaultRequire": 1
},
"mixins": [
"ArmorStandAccessor",
"GameTestHelperAccessor",
"GameTestInfoAccessor",
"GameTestSequenceAccessor",

View File

@@ -19,20 +19,21 @@ import dan200.computercraft.shared.config.ConfigSpec;
import dan200.computercraft.shared.network.NetworkMessages;
import dan200.computercraft.shared.network.client.ClientNetworkContext;
import dan200.computercraft.shared.platform.FabricConfigFile;
import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap;
import net.fabricmc.fabric.api.client.command.v2.ClientCommandRegistrationCallback;
import net.fabricmc.fabric.api.client.command.v2.FabricClientCommandSource;
import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientTickEvents;
import net.fabricmc.fabric.api.client.model.loading.v1.PreparableModelLoadingPlugin;
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.SpecialGuiElementRegistry;
import net.fabricmc.fabric.api.client.rendering.v1.WorldRenderEvents;
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.screens.MenuScreens;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.chunk.ChunkSectionLayer;
import net.minecraft.client.renderer.item.ItemModels;
import net.minecraft.client.renderer.item.properties.conditional.ConditionalItemModelProperties;
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperties;
@@ -74,11 +75,13 @@ public class ComputerCraftClient {
}, state)
);
BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_NORMAL.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_COMMAND.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.COMPUTER_ADVANCED.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.MONITOR_NORMAL.get(), RenderType.cutout());
BlockRenderLayerMap.INSTANCE.putBlock(ModRegistry.Blocks.MONITOR_ADVANCED.get(), RenderType.cutout());
BlockRenderLayerMap.putBlock(ModRegistry.Blocks.COMPUTER_NORMAL.get(), ChunkSectionLayer.CUTOUT);
BlockRenderLayerMap.putBlock(ModRegistry.Blocks.COMPUTER_COMMAND.get(), ChunkSectionLayer.CUTOUT);
BlockRenderLayerMap.putBlock(ModRegistry.Blocks.COMPUTER_ADVANCED.get(), ChunkSectionLayer.CUTOUT);
BlockRenderLayerMap.putBlock(ModRegistry.Blocks.MONITOR_NORMAL.get(), ChunkSectionLayer.CUTOUT);
BlockRenderLayerMap.putBlock(ModRegistry.Blocks.MONITOR_ADVANCED.get(), ChunkSectionLayer.CUTOUT);
ClientRegistry.registerPictureInPictureRenderers(f -> SpecialGuiElementRegistry.register(c -> f.apply(c.vertexConsumers())));
ClientTickEvents.START_CLIENT_TICK.register(client -> ClientHooks.onTick());
// This isn't 100% consistent with Forge, but not worth a mixin.

View File

@@ -15,6 +15,7 @@ import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
import static dan200.computercraft.core.util.Nullability.assertNonNull;
@@ -26,7 +27,7 @@ class SoundEngineMixin {
@Inject(method = "play", at = @At(value = "HEAD"))
@SuppressWarnings("unused")
private void playSound(SoundInstance sound, CallbackInfo ci) {
private void playSound(SoundInstance sound, CallbackInfoReturnable<SoundEngine.PlayResult> ci) {
self = (SoundEngine) (Object) this;
}

View File

@@ -18,12 +18,10 @@ import net.minecraft.client.data.models.ItemModelGenerators;
import net.minecraft.core.Holder;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.TagsProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
@@ -74,28 +72,17 @@ public class FabricDataProviders implements DataGeneratorEntrypoint {
return addWithRegistries((out, registries) -> new FabricTagProvider.BlockTagProvider(out, registries) {
@Override
protected void addTags(HolderLookup.Provider registries) {
tags.accept(x -> new TagProvider.TagAppender<>(BuiltInRegistries.BLOCK, getOrCreateRawBuilder(x)));
tags.accept(this::valueLookupBuilder);
}
});
}
@Override
public TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks) {
return addWithRegistries((out, registries) -> new FabricTagProvider.ItemTagProvider(out, registries, (FabricTagProvider.BlockTagProvider) blocks) {
public TagsProvider<Item> itemTags(Consumer<TagProvider.TagConsumer<Item>> tags) {
return addWithRegistries((out, registries) -> new FabricTagProvider.ItemTagProvider(out, registries) {
@Override
protected void addTags(HolderLookup.Provider registries) {
var self = this;
tags.accept(new TagProvider.ItemTagConsumer() {
@Override
public TagProvider.TagAppender<Item> tag(TagKey<Item> tag) {
return new TagProvider.TagAppender<>(BuiltInRegistries.ITEM, getOrCreateRawBuilder(tag));
}
@Override
public void copy(TagKey<Block> block, TagKey<Item> item) {
self.copy(block, item);
}
});
tags.accept(this::valueLookupBuilder);
}
});
}

View File

@@ -9,6 +9,7 @@ import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.item.ItemEntity;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -17,12 +18,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(Entity.class)
class EntityMixin {
@Inject(
method = "spawnAtLocation(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/item/ItemStack;F)Lnet/minecraft/world/entity/item/ItemEntity;",
method = "spawnAtLocation(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/phys/Vec3;)Lnet/minecraft/world/entity/item/ItemEntity;",
at = @At(value = "INVOKE", target = "Lnet/minecraft/server/level/ServerLevel;addFreshEntity(Lnet/minecraft/world/entity/Entity;)Z"),
cancellable = true
)
@SuppressWarnings("unused")
private void spawnAtLocation(ServerLevel level, ItemStack stack, float yOffset, CallbackInfoReturnable<ItemEntity> cb) {
private void spawnAtLocation(ServerLevel level, ItemStack stack, Vec3 position, CallbackInfoReturnable<ItemEntity> cb) {
if (CommonHooks.onLivingDrop((Entity) (Object) this, stack)) cb.setReturnValue(null);
}
}

View File

@@ -49,9 +49,9 @@
}
],
"depends": {
"fabricloader": ">=0.16.10",
"fabric-api": ">=0.122.0",
"minecraft": "=1.21.5"
"fabricloader": ">=0.16.14",
"fabric-api": ">=0.127.0",
"minecraft": "=1.21.6"
},
"accessWidener": "computercraft.accesswidener"
}

View File

@@ -96,6 +96,11 @@ public final class ForgeClientRegistry {
});
}
@SubscribeEvent
public static void registerPictureInPictureRenderers(RegisterPictureInPictureRenderersEvent event) {
ClientRegistry.registerPictureInPictureRenderers(event::register);
}
@SubscribeEvent
public static void setupClient(FMLClientSetupEvent event) {
ClientRegistry.register();

View File

@@ -11,20 +11,18 @@ import net.minecraft.client.data.models.ItemModelGenerators;
import net.minecraft.client.data.models.ModelProvider;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.RegistrySetBuilder;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.data.DataGenerator;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.minecraft.data.tags.ItemTagsProvider;
import net.minecraft.data.tags.TagsProvider;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.tags.TagKey;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.block.Block;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.data.BlockTagsProvider;
import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
import net.neoforged.neoforge.common.data.ItemTagsProvider;
import net.neoforged.neoforge.common.data.JsonCodecProvider;
import net.neoforged.neoforge.data.event.GatherDataEvent;
@@ -65,28 +63,17 @@ public class ForgeDataProviders {
return add(out -> new BlockTagsProvider(out, registries, ComputerCraftAPI.MOD_ID) {
@Override
protected void addTags(HolderLookup.Provider registries) {
tags.accept(x -> new TagProvider.TagAppender<>(BuiltInRegistries.BLOCK, getOrCreateRawBuilder(x)));
tags.accept(this::tag);
}
});
}
@Override
public TagsProvider<Item> itemTags(Consumer<TagProvider.ItemTagConsumer> tags, TagsProvider<Block> blocks) {
return add(out -> new ItemTagsProvider(out, registries, blocks.contentsGetter(), ComputerCraftAPI.MOD_ID) {
public TagsProvider<Item> itemTags(Consumer<TagProvider.TagConsumer<Item>> tags) {
return add(out -> new ItemTagsProvider(out, registries, ComputerCraftAPI.MOD_ID) {
@Override
protected void addTags(HolderLookup.Provider registries) {
var self = this;
tags.accept(new TagProvider.ItemTagConsumer() {
@Override
public TagProvider.TagAppender<Item> tag(TagKey<Item> tag) {
return new TagProvider.TagAppender<>(BuiltInRegistries.ITEM, getOrCreateRawBuilder(tag));
}
@Override
public void copy(TagKey<Block> block, TagKey<Item> item) {
self.copy(block, item);
}
});
tags.accept(this::tag);
}
});
}

View File

@@ -15,3 +15,12 @@ public com.mojang.blaze3d.audio.Channel pumpBuffers(I)V
public net.minecraft.client.sounds.SoundEngine executor
public net.minecraft.util.datafix.fixes.ItemStackComponentizationFix$ItemStackData
# GUI elements
public net.minecraft.client.gui.GuiGraphics$ScissorStack
public net.minecraft.client.gui.GuiGraphics guiRenderState
public net.minecraft.client.gui.GuiGraphics scissorStack
public net.minecraft.client.gui.GuiGraphics minecraft
# Fog
public net.minecraft.client.renderer.GameRenderer fogRenderer

View File

@@ -26,7 +26,7 @@ CC: Tweaked is a fork of ComputerCraft, adding programmable computers, turtles a
[[dependencies.computercraft]]
modId="neoforge"
type="required"
versionRange="[${neoVersion},21.6)"
versionRange="[${neoVersion},21.7)"
ordering="NONE"
side="BOTH"