diff --git a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java index e941e8a37..dd8f43761 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/ModRegistry.java @@ -34,6 +34,7 @@ import dan200.computercraft.shared.computer.blocks.ComputerBlock; import dan200.computercraft.shared.computer.blocks.ComputerBlockEntity; import dan200.computercraft.shared.computer.core.ComputerFamily; 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.computer.items.ServerComputerReference; import dan200.computercraft.shared.config.Config; @@ -322,6 +323,13 @@ public final class ModRegistry { .persistent(StorageCapacity.CODEC).networkSynchronized(StorageCapacity.STREAM_CODEC) ); + /** + * The terminal size of a computer. + */ + public static final RegistryEntry> TERMINAL_SIZE = register("terminal_size", b -> b + .persistent(TerminalSize.CODEC).networkSynchronized(TerminalSize.STREAM_CODEC) + ); + /** * The left upgrade of a turtle. * diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java index 1cd56979b..4e7585ef0 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/blocks/ComputerBlockEntity.java @@ -10,10 +10,15 @@ import dan200.computercraft.shared.ModRegistry; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; 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.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; @@ -23,17 +28,66 @@ import net.minecraft.world.level.block.state.BlockState; import org.jspecify.annotations.Nullable; public class ComputerBlockEntity extends AbstractComputerBlockEntity { + private static final String NBT_TERMINAL_SIZE = "TerminalSize"; + + private @Nullable TerminalSize terminalSize; + private @Nullable IPeripheral peripheral; public ComputerBlockEntity(BlockEntityType type, BlockPos pos, BlockState state, ComputerFamily family) { super(type, pos, state, family); } + @Override + protected void loadServer(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadServer(nbt, registries); + terminalSize = NBTUtil.decodeFrom(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE); + } + + @Override + public void saveAdditional(CompoundTag nbt, HolderLookup.Provider registries) { + super.saveAdditional(nbt, registries); + NBTUtil.encodeTo(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE, terminalSize); + } + + @Override + protected void loadClient(CompoundTag nbt, HolderLookup.Provider registries) { + super.loadClient(nbt, registries); + terminalSize = NBTUtil.decodeFrom(TerminalSize.CODEC, registries, nbt, NBT_TERMINAL_SIZE); + } + + @Override + public CompoundTag getUpdateTag(HolderLookup.Provider registries) { + var tag = super.getUpdateTag(registries); + NBTUtil.encodeTo(TerminalSize.CODEC, registries, tag, NBT_TERMINAL_SIZE, terminalSize); + return tag; + } + + @Override + protected void applyImplicitComponents(DataComponentInput component) { + super.applyImplicitComponents(component); + terminalSize = component.get(ModRegistry.DataComponents.TERMINAL_SIZE.get()); + } + + + @Override + protected void collectSafeComponents(DataComponentMap.Builder builder) { + super.collectSafeComponents(builder); + builder.set(ModRegistry.DataComponents.TERMINAL_SIZE.get(), terminalSize); + } + + @Override + @Deprecated + public void removeComponentsFromTag(CompoundTag tag) { + super.removeComponentsFromTag(tag); + tag.remove(NBT_TERMINAL_SIZE); + } + @Override protected ServerComputer createComputer(int id) { return new ServerComputer((ServerLevel) getLevel(), getBlockPos(), ServerComputer.properties(id, getFamily()) .label(getLabel()) - .terminalSize(ConfigSpec.computerTermWidth.get(), ConfigSpec.computerTermHeight.get()) + .terminalSize(terminalSize != null ? terminalSize : new TerminalSize(ConfigSpec.computerTermWidth.get(), ConfigSpec.computerTermHeight.get())) .storageCapacity(storageCapacity) ); } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java index 54fea5803..b61d44180 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/ServerComputer.java @@ -295,10 +295,9 @@ public class ServerComputer implements ComputerEnvironment, ComputerEvents.Recei return this; } - public Properties terminalSize(int width, int height) { - if (width <= 0 || height <= 0) throw new IllegalArgumentException("Terminal size must be positive"); - this.terminalWidth = width; - this.terminalHeight = height; + public Properties terminalSize(TerminalSize size) { + this.terminalWidth = size.width(); + this.terminalHeight = size.height(); return this; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java new file mode 100644 index 000000000..81fd90bf9 --- /dev/null +++ b/projects/common/src/main/java/dan200/computercraft/shared/computer/core/TerminalSize.java @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2025 The CC: Tweaked Developers +// +// SPDX-License-Identifier: MPL-2.0 + +package dan200.computercraft.shared.computer.core; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import io.netty.buffer.ByteBuf; +import net.minecraft.network.codec.ByteBufCodecs; +import net.minecraft.network.codec.StreamCodec; +import net.minecraft.util.ExtraCodecs; + +/** + * The size of a computer terminal. + * + * @param width The terminal's width. + * @param height The terminal's height. + */ +public record TerminalSize(int width, int height) { + public static final int MAX_SIZE = 255; + public static final Codec CODEC = RecordCodecBuilder.create(instance -> instance.group( + ExtraCodecs.intRange(1, MAX_SIZE).fieldOf("width").forGetter(TerminalSize::width), + ExtraCodecs.intRange(1, MAX_SIZE).fieldOf("height").forGetter(TerminalSize::height) + ).apply(instance, TerminalSize::new)); + + public static final StreamCodec STREAM_CODEC = StreamCodec.composite( + ByteBufCodecs.VAR_INT, TerminalSize::width, + ByteBufCodecs.VAR_INT, TerminalSize::height, + TerminalSize::new + ); + + public TerminalSize { + checkBounds("width", width); + checkBounds("height", height); + } + + private static void checkBounds(String name, int value) { + if (value < 1 || value > MAX_SIZE) { + throw new IllegalArgumentException(name + " must be between 1 and " + MAX_SIZE); + } + } +} diff --git a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java index 47e30bce2..3d45dac83 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/config/ConfigSpec.java @@ -11,6 +11,7 @@ import dan200.computercraft.core.Logging; import dan200.computercraft.core.apis.http.NetworkUtils; import dan200.computercraft.core.apis.http.options.ProxyType; import dan200.computercraft.core.computer.mainthread.MainThreadConfig; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.peripheral.monitor.MonitorRenderer; import dan200.computercraft.shared.platform.PlatformHelper; import org.apache.logging.log4j.LogManager; @@ -344,13 +345,13 @@ public final class ConfigSpec { .push("term_sizes"); builder.comment("Terminal size of computers.").push("computer"); - computerTermWidth = builder.comment("Width of computer terminal").defineInRange("width", Config.DEFAULT_COMPUTER_TERM_WIDTH, 1, 255); - computerTermHeight = builder.comment("Height of computer terminal").defineInRange("height", Config.DEFAULT_COMPUTER_TERM_HEIGHT, 1, 255); + computerTermWidth = builder.comment("Width of computer terminal").defineInRange("width", Config.DEFAULT_COMPUTER_TERM_WIDTH, 1, TerminalSize.MAX_SIZE); + computerTermHeight = builder.comment("Height of computer terminal").defineInRange("height", Config.DEFAULT_COMPUTER_TERM_HEIGHT, 1, TerminalSize.MAX_SIZE); builder.pop(); builder.comment("Terminal size of pocket computers.").push("pocket_computer"); - pocketTermWidth = builder.comment("Width of pocket computer terminal").defineInRange("width", Config.DEFAULT_POCKET_TERM_WIDTH, 1, 255); - pocketTermHeight = builder.comment("Height of pocket computer terminal").defineInRange("height", Config.DEFAULT_POCKET_TERM_HEIGHT, 1, 255); + pocketTermWidth = builder.comment("Width of pocket computer terminal").defineInRange("width", Config.DEFAULT_POCKET_TERM_WIDTH, 1, TerminalSize.MAX_SIZE); + pocketTermHeight = builder.comment("Height of pocket computer terminal").defineInRange("height", Config.DEFAULT_POCKET_TERM_HEIGHT, 1, TerminalSize.MAX_SIZE); builder.pop(); builder.comment("Maximum size of monitors (in blocks).").push("monitor"); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java index efa4a5c24..3e7a52378 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/core/PocketServerComputer.java @@ -7,7 +7,6 @@ package dan200.computercraft.shared.pocket.core; import dan200.computercraft.api.component.ComputerComponents; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.network.client.PocketComputerDataMessage; import dan200.computercraft.shared.network.client.PocketComputerDeletedClientMessage; import dan200.computercraft.shared.network.server.ServerNetworking; @@ -40,10 +39,7 @@ public final class PocketServerComputer extends ServerComputer { private Set tracking = Set.of(); PocketServerComputer(PocketBrain brain, PocketHolder holder, ServerComputer.Properties properties) { - super(holder.level(), holder.blockPos(), properties - .terminalSize(ConfigSpec.pocketTermWidth.get(), ConfigSpec.pocketTermHeight.get()) - .addComponent(ComputerComponents.POCKET, brain) - ); + super(holder.level(), holder.blockPos(), properties.addComponent(ComputerComponents.POCKET, brain)); this.brain = brain; } diff --git a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java index b9c6ef3aa..de1dc1169 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/pocket/items/PocketComputerItem.java @@ -11,12 +11,10 @@ import dan200.computercraft.api.upgrades.UpgradeData; import dan200.computercraft.core.computer.ComputerSide; import dan200.computercraft.impl.PocketUpgrades; import dan200.computercraft.shared.ModRegistry; -import dan200.computercraft.shared.computer.core.ComputerFamily; -import dan200.computercraft.shared.computer.core.ServerComputer; -import dan200.computercraft.shared.computer.core.ServerComputerRegistry; -import dan200.computercraft.shared.computer.core.ServerContext; +import dan200.computercraft.shared.computer.core.*; import dan200.computercraft.shared.computer.inventory.ComputerMenuWithoutInventory; import dan200.computercraft.shared.computer.items.ServerComputerReference; +import dan200.computercraft.shared.config.ConfigSpec; import dan200.computercraft.shared.network.container.ComputerContainerData; import dan200.computercraft.shared.platform.PlatformHelper; import dan200.computercraft.shared.pocket.core.PocketBrain; @@ -207,6 +205,10 @@ public class PocketComputerItem extends Item { ServerComputer.properties(computerID, getFamily()) .label(getLabel(stack)) .storageCapacity(StorageCapacity.getOrDefault(stack.get(ModRegistry.DataComponents.STORAGE_CAPACITY.get()), -1)) + .terminalSize(stack.getOrDefault( + ModRegistry.DataComponents.TERMINAL_SIZE.get(), + new TerminalSize(ConfigSpec.pocketTermWidth.get(), ConfigSpec.pocketTermHeight.get()) + )) ); var computer = brain.computer(); diff --git a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java index 2f3e3df44..8a5f189d8 100644 --- a/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java +++ b/projects/common/src/main/java/dan200/computercraft/shared/turtle/blocks/TurtleBlockEntity.java @@ -18,6 +18,7 @@ import dan200.computercraft.shared.computer.blocks.ComputerPeripheral; import dan200.computercraft.shared.computer.core.ComputerFamily; import dan200.computercraft.shared.computer.core.ComputerState; import dan200.computercraft.shared.computer.core.ServerComputer; +import dan200.computercraft.shared.computer.core.TerminalSize; import dan200.computercraft.shared.config.Config; import dan200.computercraft.shared.container.BasicContainer; import dan200.computercraft.shared.platform.PlatformHelper; @@ -81,7 +82,7 @@ public class TurtleBlockEntity extends AbstractComputerBlockEntity implements Ba protected ServerComputer createComputer(int id) { var computer = new ServerComputer((ServerLevel) getLevel(), getBlockPos(), ServerComputer.properties(id, getFamily()) .label(getLabel()) - .terminalSize(Config.TURTLE_TERM_WIDTH, Config.TURTLE_TERM_HEIGHT) + .terminalSize(new TerminalSize(Config.TURTLE_TERM_WIDTH, Config.TURTLE_TERM_HEIGHT)) .storageCapacity(storageCapacity) .addComponent(ComputerComponents.TURTLE, brain) );