From 3b2dc8cefac48b20d00ba8b3ff65158363949aa1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Wed, 13 Jan 2021 19:58:59 +0100 Subject: [PATCH] Robots bootable and movable. --- .../java/li/cil/oc2/client/ClientSetup.java | 2 + ...creen.java => AbstractTerminalScreen.java} | 37 +-- .../client/gui/ComputerTerminalScreen.java | 38 +++ .../oc2/client/gui/RobotContainerScreen.java | 41 +++ .../oc2/client/gui/RobotTerminalScreen.java | 38 +++ .../renderer/entity/RobotEntityRenderer.java | 12 +- .../cil/oc2/common/block/ComputerBlock.java | 12 +- .../common/container/ComputerContainer.java | 26 +- .../cil/oc2/common/container/Containers.java | 1 + .../oc2/common/container/RobotContainer.java | 69 ++++++ .../li/cil/oc2/common/entity/RobotEntity.java | 233 +++++++++++++++--- .../entity/robot/RobotMovementAction.java | 10 +- .../entity/robot/RobotMovementActionType.java | 6 +- .../entity/robot/RobotRotationAction.java | 8 +- .../entity/robot/RobotRotationActionType.java | 6 +- .../li/cil/oc2/common/item/ItemGroup.java | 10 +- .../li/cil/oc2/common/network/Network.java | 30 +++ .../message/ComputerBusStateMessage.java | 10 +- .../message/ComputerRunStateMessage.java | 10 +- .../network/message/RobotBusStateMessage.java | 43 ++++ .../message/RobotInitializationMessage.java | 64 +++++ .../RobotInitializationRequestMessage.java | 39 +++ .../network/message/RobotPowerMessage.java | 52 ++++ .../network/message/RobotRunStateMessage.java | 43 ++++ .../common/tileentity/ComputerTileEntity.java | 16 +- ...tractVirtualMachineItemStackHandlers.java} | 15 +- .../vm/VirtualMachineItemStackHandlers.java | 14 ++ src/main/resources/assets/oc2/lang/en_us.json | 2 + .../oc2/textures/entity/robot/robot.png | Bin 4797 -> 4984 bytes 29 files changed, 765 insertions(+), 122 deletions(-) rename src/main/java/li/cil/oc2/client/gui/{TerminalScreen.java => AbstractTerminalScreen.java} (87%) create mode 100644 src/main/java/li/cil/oc2/client/gui/ComputerTerminalScreen.java create mode 100644 src/main/java/li/cil/oc2/client/gui/RobotContainerScreen.java create mode 100644 src/main/java/li/cil/oc2/client/gui/RobotTerminalScreen.java create mode 100644 src/main/java/li/cil/oc2/common/container/RobotContainer.java create mode 100644 src/main/java/li/cil/oc2/common/network/message/RobotBusStateMessage.java create mode 100644 src/main/java/li/cil/oc2/common/network/message/RobotInitializationMessage.java create mode 100644 src/main/java/li/cil/oc2/common/network/message/RobotInitializationRequestMessage.java create mode 100644 src/main/java/li/cil/oc2/common/network/message/RobotPowerMessage.java create mode 100644 src/main/java/li/cil/oc2/common/network/message/RobotRunStateMessage.java rename src/main/java/li/cil/oc2/common/vm/{CommonVirtualMachineItemStackHandlers.java => AbstractVirtualMachineItemStackHandlers.java} (93%) create mode 100644 src/main/java/li/cil/oc2/common/vm/VirtualMachineItemStackHandlers.java diff --git a/src/main/java/li/cil/oc2/client/ClientSetup.java b/src/main/java/li/cil/oc2/client/ClientSetup.java index 661f171f..5f10c33c 100644 --- a/src/main/java/li/cil/oc2/client/ClientSetup.java +++ b/src/main/java/li/cil/oc2/client/ClientSetup.java @@ -3,6 +3,7 @@ package li.cil.oc2.client; import li.cil.oc2.api.API; import li.cil.oc2.api.bus.device.DeviceType; import li.cil.oc2.client.gui.ComputerContainerScreen; +import li.cil.oc2.client.gui.RobotContainerScreen; import li.cil.oc2.client.item.CustomItemModelProperties; import li.cil.oc2.client.model.BusCableModelLoader; import li.cil.oc2.client.renderer.NetworkCableRenderer; @@ -32,6 +33,7 @@ public final class ClientSetup { CustomItemModelProperties.initialize(); ScreenManager.registerFactory(Containers.COMPUTER_CONTAINER.get(), ComputerContainerScreen::new); + ScreenManager.registerFactory(Containers.ROBOT_CONTAINER.get(), RobotContainerScreen::new); ClientRegistry.bindTileEntityRenderer(TileEntities.COMPUTER_TILE_ENTITY.get(), ComputerTileEntityRenderer::new); ClientRegistry.bindTileEntityRenderer(TileEntities.NETWORK_CONNECTOR_TILE_ENTITY.get(), NetworkConnectorTileEntityRenderer::new); diff --git a/src/main/java/li/cil/oc2/client/gui/TerminalScreen.java b/src/main/java/li/cil/oc2/client/gui/AbstractTerminalScreen.java similarity index 87% rename from src/main/java/li/cil/oc2/client/gui/TerminalScreen.java rename to src/main/java/li/cil/oc2/client/gui/AbstractTerminalScreen.java index 64613277..46f8efd4 100644 --- a/src/main/java/li/cil/oc2/client/gui/TerminalScreen.java +++ b/src/main/java/li/cil/oc2/client/gui/AbstractTerminalScreen.java @@ -7,13 +7,11 @@ import li.cil.oc2.client.gui.terminal.TerminalInput; import li.cil.oc2.client.gui.widget.Sprite; import li.cil.oc2.client.gui.widget.ToggleImageButton; import li.cil.oc2.common.Constants; -import li.cil.oc2.common.network.Network; -import li.cil.oc2.common.network.message.ComputerPowerMessage; -import li.cil.oc2.common.network.message.ComputerTerminalInputMessage; -import li.cil.oc2.common.tileentity.ComputerTileEntity; import li.cil.oc2.common.vm.Terminal; +import li.cil.oc2.common.vm.VirtualMachineState; import net.minecraft.client.entity.player.ClientPlayerEntity; import net.minecraft.client.gui.screen.Screen; +import net.minecraft.entity.player.PlayerEntity; import net.minecraft.util.ResourceLocation; import net.minecraft.util.text.ITextComponent; import net.minecraft.util.text.TranslationTextComponent; @@ -23,7 +21,7 @@ import java.nio.ByteBuffer; import static java.util.Objects.requireNonNull; -public final class TerminalScreen extends Screen { +public abstract class AbstractTerminalScreen extends Screen { private static final ResourceLocation BACKGROUND = new ResourceLocation(API.MOD_ID, "textures/gui/screen/terminal.png"); private static final ResourceLocation BACKGROUND_TERMINAL_FOCUSED = new ResourceLocation(API.MOD_ID, "textures/gui/screen/terminal_focused.png"); private static final int TEXTURE_SIZE = 512; @@ -50,7 +48,7 @@ public final class TerminalScreen extends Screen { /////////////////////////////////////////////////////////////////// - private final ComputerTileEntity tileEntity; + private final VirtualMachineState state; private final Terminal terminal; private final int windowWidth, windowHeight; private int windowLeft, windowTop; @@ -58,10 +56,10 @@ public final class TerminalScreen extends Screen { /////////////////////////////////////////////////////////////////// - public TerminalScreen(final ComputerTileEntity tileEntity, final ITextComponent title) { + public AbstractTerminalScreen(final VirtualMachineState state, final Terminal terminal, final ITextComponent title) { super(title); - this.tileEntity = tileEntity; - terminal = tileEntity.getTerminal(); + this.state = state; + this.terminal = terminal; windowWidth = SCREEN_WIDTH; windowHeight = SCREEN_HEIGHT; } @@ -84,13 +82,13 @@ public final class TerminalScreen extends Screen { super.render(matrixStack, mouseX, mouseY, partialTicks); - if (tileEntity.getState().isRunning()) { + if (state.isRunning()) { final MatrixStack stack = new MatrixStack(); stack.translate(windowLeft + TERMINAL_AREA_X, windowTop + TERMINAL_AREA_Y, this.itemRenderer.zLevel); stack.scale(TERMINAL_AREA_WIDTH / (float) terminal.getWidth(), TERMINAL_AREA_HEIGHT / (float) terminal.getHeight(), 1f); terminal.render(stack); } else { - final ITextComponent bootError = tileEntity.getState().getBootError(); + final ITextComponent bootError = state.getBootError(); if (bootError != null) { final int textWidth = font.getStringPropertyWidth(bootError); final int textOffsetX = (TERMINAL_AREA_WIDTH - textWidth) / 2; @@ -110,13 +108,13 @@ public final class TerminalScreen extends Screen { final ByteBuffer input = terminal.getInput(); if (input != null) { - Network.INSTANCE.sendToServer(new ComputerTerminalInputMessage(tileEntity, input)); + sendTerminalInputToServer(input); } assert minecraft != null; final ClientPlayerEntity player = minecraft.player; assert player != null; - if (!player.isAlive() || !tileEntity.getPos().withinDistance(player.getPositionVec(), 8)) { + if (!player.isAlive() || !canInteractWith(player)) { closeScreen(); } } @@ -166,6 +164,12 @@ public final class TerminalScreen extends Screen { /////////////////////////////////////////////////////////////////// + protected abstract void sendPowerStateToServer(boolean value); + + protected abstract void sendTerminalInputToServer(final ByteBuffer input); + + protected abstract boolean canInteractWith(PlayerEntity player); + protected void init() { super.init(); this.windowLeft = (this.width - this.windowWidth) / 2; @@ -185,13 +189,12 @@ public final class TerminalScreen extends Screen { @Override public void onPress() { super.onPress(); - final ComputerPowerMessage message = new ComputerPowerMessage(tileEntity, !tileEntity.getState().isRunning()); - Network.INSTANCE.sendToServer(message); + sendPowerStateToServer(!state.isRunning()); } @Override public boolean isToggled() { - return tileEntity.getState().isRunning(); + return state.isRunning(); } }); @@ -220,7 +223,7 @@ public final class TerminalScreen extends Screen { /////////////////////////////////////////////////////////////////// private boolean shouldCaptureInput() { - return isMouseOverTerminal && enableInputCapture && tileEntity.getState().isRunning(); + return isMouseOverTerminal && enableInputCapture && state.isRunning(); } private boolean isPointInRegion(final int x, final int y, final int width, final int height, double mouseX, double mouseY) { diff --git a/src/main/java/li/cil/oc2/client/gui/ComputerTerminalScreen.java b/src/main/java/li/cil/oc2/client/gui/ComputerTerminalScreen.java new file mode 100644 index 00000000..e6806cfd --- /dev/null +++ b/src/main/java/li/cil/oc2/client/gui/ComputerTerminalScreen.java @@ -0,0 +1,38 @@ +package li.cil.oc2.client.gui; + +import li.cil.oc2.common.network.Network; +import li.cil.oc2.common.network.message.ComputerPowerMessage; +import li.cil.oc2.common.network.message.ComputerTerminalInputMessage; +import li.cil.oc2.common.tileentity.ComputerTileEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.text.ITextComponent; + +import java.nio.ByteBuffer; + +public final class ComputerTerminalScreen extends AbstractTerminalScreen { + private final ComputerTileEntity computer; + + /////////////////////////////////////////////////////////////////// + + public ComputerTerminalScreen(final ComputerTileEntity computer, final ITextComponent title) { + super(computer.getState(), computer.getTerminal(), title); + this.computer = computer; + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected void sendPowerStateToServer(final boolean value) { + Network.INSTANCE.sendToServer(new ComputerPowerMessage(computer, value)); + } + + @Override + protected void sendTerminalInputToServer(final ByteBuffer input) { + Network.INSTANCE.sendToServer(new ComputerTerminalInputMessage(computer, input)); + } + + @Override + protected boolean canInteractWith(final PlayerEntity player) { + return computer.getPos().withinDistance(player.getPositionVec(), 8); + } +} diff --git a/src/main/java/li/cil/oc2/client/gui/RobotContainerScreen.java b/src/main/java/li/cil/oc2/client/gui/RobotContainerScreen.java new file mode 100644 index 00000000..b9c49ed6 --- /dev/null +++ b/src/main/java/li/cil/oc2/client/gui/RobotContainerScreen.java @@ -0,0 +1,41 @@ +package li.cil.oc2.client.gui; + +import com.mojang.blaze3d.matrix.MatrixStack; +import com.mojang.blaze3d.systems.RenderSystem; +import li.cil.oc2.api.API; +import li.cil.oc2.common.container.RobotContainer; +import net.minecraft.client.gui.screen.inventory.ContainerScreen; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.util.ResourceLocation; +import net.minecraft.util.text.ITextComponent; + +import static java.util.Objects.requireNonNull; + +public final class RobotContainerScreen extends ContainerScreen { + private static final ResourceLocation BACKGROUND = new ResourceLocation(API.MOD_ID, "textures/gui/container/computer.png"); + + /////////////////////////////////////////////////////////////////// + + public RobotContainerScreen(final RobotContainer container, final PlayerInventory inventory, final ITextComponent title) { + super(container, inventory, title); + xSize = 176; + ySize = 197; + playerInventoryTitleY = ySize - 94; + } + + @Override + public void render(final MatrixStack matrixStack, final int mouseX, final int mouseY, final float partialTicks) { + renderBackground(matrixStack); + super.render(matrixStack, mouseX, mouseY, partialTicks); + renderHoveredTooltip(matrixStack, mouseX, mouseY); + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected void drawGuiContainerBackgroundLayer(final MatrixStack matrixStack, final float partialTicks, final int mouseX, final int mouseY) { + RenderSystem.color4f(1f, 1f, 1f, 1f); + requireNonNull(minecraft).getTextureManager().bindTexture(BACKGROUND); + blit(matrixStack, guiLeft, guiTop, 0, 0, xSize, ySize); + } +} diff --git a/src/main/java/li/cil/oc2/client/gui/RobotTerminalScreen.java b/src/main/java/li/cil/oc2/client/gui/RobotTerminalScreen.java new file mode 100644 index 00000000..869da5ce --- /dev/null +++ b/src/main/java/li/cil/oc2/client/gui/RobotTerminalScreen.java @@ -0,0 +1,38 @@ +package li.cil.oc2.client.gui; + +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.Network; +import li.cil.oc2.common.network.message.RobotPowerMessage; +import li.cil.oc2.common.network.message.RobotTerminalInputMessage; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.text.ITextComponent; + +import java.nio.ByteBuffer; + +public final class RobotTerminalScreen extends AbstractTerminalScreen { + private final RobotEntity robot; + + /////////////////////////////////////////////////////////////////// + + public RobotTerminalScreen(final RobotEntity robot, final ITextComponent title) { + super(robot.getState(), robot.getTerminal(), title); + this.robot = robot; + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected void sendPowerStateToServer(final boolean value) { + Network.INSTANCE.sendToServer(new RobotPowerMessage(robot, value)); + } + + @Override + protected void sendTerminalInputToServer(final ByteBuffer input) { + Network.INSTANCE.sendToServer(new RobotTerminalInputMessage(robot, input)); + } + + @Override + protected boolean canInteractWith(final PlayerEntity player) { + return robot.isEntityInRange(player, 8); + } +} diff --git a/src/main/java/li/cil/oc2/client/renderer/entity/RobotEntityRenderer.java b/src/main/java/li/cil/oc2/client/renderer/entity/RobotEntityRenderer.java index d7b76c86..50758beb 100644 --- a/src/main/java/li/cil/oc2/client/renderer/entity/RobotEntityRenderer.java +++ b/src/main/java/li/cil/oc2/client/renderer/entity/RobotEntityRenderer.java @@ -4,7 +4,6 @@ import com.mojang.blaze3d.matrix.MatrixStack; import com.mojang.blaze3d.vertex.IVertexBuilder; import li.cil.oc2.api.API; import li.cil.oc2.common.entity.RobotEntity; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.IRenderTypeBuffer; import net.minecraft.client.renderer.LightTexture; import net.minecraft.client.renderer.entity.EntityRenderer; @@ -13,11 +12,8 @@ import net.minecraft.client.renderer.entity.model.EntityModel; import net.minecraft.client.renderer.model.ModelRenderer; import net.minecraft.client.renderer.texture.OverlayTexture; import net.minecraft.util.ResourceLocation; -import net.minecraft.util.math.EntityRayTraceResult; import net.minecraft.util.math.MathHelper; -import net.minecraft.util.math.RayTraceResult; import net.minecraft.util.math.vector.Vector3f; -import net.minecraft.util.text.StringTextComponent; import net.minecraftforge.common.model.TransformationHelper; public final class RobotEntityRenderer extends EntityRenderer { @@ -57,10 +53,10 @@ public final class RobotEntityRenderer extends EntityRenderer { matrixStack.pop(); - final RayTraceResult hit = Minecraft.getInstance().objectMouseOver; - if (hit instanceof EntityRayTraceResult && entity == ((EntityRayTraceResult) hit).getEntity()) { - super.renderName(entity, new StringTextComponent("hi"), matrixStack, buffer, packedLight); - } +// final RayTraceResult hit = Minecraft.getInstance().objectMouseOver; +// if (hit instanceof EntityRayTraceResult && entity == ((EntityRayTraceResult) hit).getEntity()) { +// super.renderName(entity, new StringTextComponent("hi"), matrixStack, buffer, packedLight); +// } } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/block/ComputerBlock.java b/src/main/java/li/cil/oc2/common/block/ComputerBlock.java index 52d03a80..2eb700c0 100644 --- a/src/main/java/li/cil/oc2/common/block/ComputerBlock.java +++ b/src/main/java/li/cil/oc2/common/block/ComputerBlock.java @@ -1,7 +1,7 @@ package li.cil.oc2.common.block; import li.cil.oc2.api.capabilities.RedstoneEmitter; -import li.cil.oc2.client.gui.TerminalScreen; +import li.cil.oc2.client.gui.ComputerTerminalScreen; import li.cil.oc2.common.capabilities.Capabilities; import li.cil.oc2.common.container.ComputerContainer; import li.cil.oc2.common.integration.Wrenches; @@ -9,7 +9,7 @@ import li.cil.oc2.common.item.Items; import li.cil.oc2.common.tileentity.ComputerTileEntity; import li.cil.oc2.common.tileentity.TileEntities; import li.cil.oc2.common.util.VoxelShapeUtils; -import li.cil.oc2.common.vm.CommonVirtualMachineItemStackHandlers; +import li.cil.oc2.common.vm.AbstractVirtualMachineItemStackHandlers; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.HorizontalBlock; @@ -76,7 +76,7 @@ public final class ComputerBlock extends HorizontalBlock { @Override public void addInformation(final ItemStack stack, @Nullable final IBlockReader world, final List tooltip, final ITooltipFlag advanced) { super.addInformation(stack, world, tooltip, advanced); - CommonVirtualMachineItemStackHandlers.addInformation(stack, tooltip); + AbstractVirtualMachineItemStackHandlers.addInformation(stack, tooltip); } @Override @@ -178,8 +178,8 @@ public final class ComputerBlock extends HorizontalBlock { final TileEntity tileEntity = world.getTileEntity(pos); if (!world.isRemote() && tileEntity instanceof ComputerTileEntity) { final ComputerTileEntity computer = (ComputerTileEntity) tileEntity; - if (!computer.getItemHandlers().isEmpty()) { - computer.getItemHandlers().exportDeviceDataToItemStacks(); + if (!computer.getItemStackHandlers().isEmpty()) { + computer.getItemStackHandlers().exportDeviceDataToItemStacks(); if (player.isCreative()) { final ItemStack stack = new ItemStack(Items.COMPUTER_ITEM.get()); @@ -209,7 +209,7 @@ public final class ComputerBlock extends HorizontalBlock { @OnlyIn(Dist.CLIENT) private void openTerminalScreen(final ComputerTileEntity computer) { - Minecraft.getInstance().displayGuiScreen(new TerminalScreen(computer, getTranslatedName())); + Minecraft.getInstance().displayGuiScreen(new ComputerTerminalScreen(computer, getTranslatedName())); } private void openContainerScreen(final ComputerTileEntity tileEntity, final PlayerEntity player) { diff --git a/src/main/java/li/cil/oc2/common/container/ComputerContainer.java b/src/main/java/li/cil/oc2/common/container/ComputerContainer.java index 8452bf65..1d108e33 100644 --- a/src/main/java/li/cil/oc2/common/container/ComputerContainer.java +++ b/src/main/java/li/cil/oc2/common/container/ComputerContainer.java @@ -3,14 +3,13 @@ package li.cil.oc2.common.container; import li.cil.oc2.api.bus.device.DeviceTypes; import li.cil.oc2.common.block.Blocks; import li.cil.oc2.common.tileentity.ComputerTileEntity; -import li.cil.oc2.common.vm.CommonVirtualMachineItemStackHandlers; +import li.cil.oc2.common.vm.VirtualMachineItemStackHandlers; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.network.PacketBuffer; import net.minecraft.tileentity.TileEntity; import net.minecraft.util.IWorldPosCallable; import net.minecraft.util.math.BlockPos; -import net.minecraft.world.World; import javax.annotation.Nullable; @@ -27,36 +26,35 @@ public final class ComputerContainer extends AbstractContainer { /////////////////////////////////////////////////////////////////// - private final World world; - private final BlockPos pos; + private final ComputerTileEntity computer; /////////////////////////////////////////////////////////////////// - public ComputerContainer(final int id, final ComputerTileEntity tileEntity, final PlayerInventory inventory) { + public ComputerContainer(final int id, final ComputerTileEntity computer, final PlayerInventory inventory) { super(Containers.COMPUTER_CONTAINER.get(), id); - this.world = inventory.player.getEntityWorld(); - this.pos = tileEntity.getPos(); + this.computer = computer; - final CommonVirtualMachineItemStackHandlers itemHandlers = tileEntity.getItemHandlers(); - itemHandlers.getItemHandler(DeviceTypes.FLASH_MEMORY).ifPresent(itemHandler -> { + final VirtualMachineItemStackHandlers handlers = computer.getItemStackHandlers(); + + handlers.getItemHandler(DeviceTypes.FLASH_MEMORY).ifPresent(itemHandler -> { if (itemHandler.getSlots() > 0) { this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.FLASH_MEMORY, 0, 64, 78)); } }); - itemHandlers.getItemHandler(DeviceTypes.MEMORY).ifPresent(itemHandler -> { + handlers.getItemHandler(DeviceTypes.MEMORY).ifPresent(itemHandler -> { for (int slot = 0; slot < itemHandler.getSlots(); slot++) { this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.MEMORY, slot, 64 + slot * SLOT_SIZE, 24)); } }); - itemHandlers.getItemHandler(DeviceTypes.HARD_DRIVE).ifPresent(itemHandler -> { + handlers.getItemHandler(DeviceTypes.HARD_DRIVE).ifPresent(itemHandler -> { for (int slot = 0; slot < itemHandler.getSlots(); slot++) { this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.HARD_DRIVE, slot, 100 + (slot % 2) * SLOT_SIZE, 60 + (slot / 2) * SLOT_SIZE)); } }); - itemHandlers.getItemHandler(DeviceTypes.CARD).ifPresent(itemHandler -> { + handlers.getItemHandler(DeviceTypes.CARD).ifPresent(itemHandler -> { for (int slot = 0; slot < itemHandler.getSlots(); slot++) { this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.CARD, slot, 38, 24 + slot * SLOT_SIZE)); } @@ -65,8 +63,10 @@ public final class ComputerContainer extends AbstractContainer { createPlayerInventoryAndHotbarSlots(inventory, 8, 115); } + /////////////////////////////////////////////////////////////////// + @Override public boolean canInteractWith(final PlayerEntity player) { - return isWithinUsableDistance(IWorldPosCallable.of(world, pos), player, Blocks.COMPUTER_BLOCK.get()); + return isWithinUsableDistance(IWorldPosCallable.of(computer.getWorld(), computer.getPos()), player, Blocks.COMPUTER_BLOCK.get()); } } diff --git a/src/main/java/li/cil/oc2/common/container/Containers.java b/src/main/java/li/cil/oc2/common/container/Containers.java index 264ef6e3..a052b719 100644 --- a/src/main/java/li/cil/oc2/common/container/Containers.java +++ b/src/main/java/li/cil/oc2/common/container/Containers.java @@ -15,6 +15,7 @@ public final class Containers { /////////////////////////////////////////////////////////////////// public static final RegistryObject> COMPUTER_CONTAINER = CONTAINERS.register(Constants.COMPUTER_BLOCK_NAME, () -> IForgeContainerType.create(ComputerContainer::create)); + public static final RegistryObject> ROBOT_CONTAINER = CONTAINERS.register(Constants.ROBOT_ENTITY_NAME, () -> IForgeContainerType.create(RobotContainer::create)); /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/container/RobotContainer.java b/src/main/java/li/cil/oc2/common/container/RobotContainer.java new file mode 100644 index 00000000..0895e23c --- /dev/null +++ b/src/main/java/li/cil/oc2/common/container/RobotContainer.java @@ -0,0 +1,69 @@ +package li.cil.oc2.common.container; + +import li.cil.oc2.api.bus.device.DeviceTypes; +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.vm.VirtualMachineItemStackHandlers; +import net.minecraft.entity.Entity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.network.PacketBuffer; + +import javax.annotation.Nullable; + +public final class RobotContainer extends AbstractContainer { + @Nullable + public static RobotContainer create(final int id, final PlayerInventory inventory, final PacketBuffer data) { + final int entityId = data.readVarInt(); + final Entity entity = inventory.player.getEntityWorld().getEntityByID(entityId); + if (!(entity instanceof RobotEntity)) { + return null; + } + return new RobotContainer(id, (RobotEntity) entity, inventory); + } + + /////////////////////////////////////////////////////////////////// + + private final RobotEntity robot; + + /////////////////////////////////////////////////////////////////// + + public RobotContainer(final int id, final RobotEntity robot, final PlayerInventory inventory) { + super(Containers.ROBOT_CONTAINER.get(), id); + this.robot = robot; + + final VirtualMachineItemStackHandlers handlers = robot.getItemStackHandlers(); + + handlers.getItemHandler(DeviceTypes.FLASH_MEMORY).ifPresent(itemHandler -> { + if (itemHandler.getSlots() > 0) { + this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.FLASH_MEMORY, 0, 64, 78)); + } + }); + + handlers.getItemHandler(DeviceTypes.MEMORY).ifPresent(itemHandler -> { + for (int slot = 0; slot < itemHandler.getSlots(); slot++) { + this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.MEMORY, slot, 64 + slot * SLOT_SIZE, 24)); + } + }); + + handlers.getItemHandler(DeviceTypes.HARD_DRIVE).ifPresent(itemHandler -> { + for (int slot = 0; slot < itemHandler.getSlots(); slot++) { + this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.HARD_DRIVE, slot, 100 + (slot % 2) * SLOT_SIZE, 60 + (slot / 2) * SLOT_SIZE)); + } + }); + + handlers.getItemHandler(DeviceTypes.CARD).ifPresent(itemHandler -> { + for (int slot = 0; slot < itemHandler.getSlots(); slot++) { + this.addSlot(new TypedSlotItemHandler(itemHandler, DeviceTypes.CARD, slot, 38, 24 + slot * SLOT_SIZE)); + } + }); + + createPlayerInventoryAndHotbarSlots(inventory, 8, 115); + } + + /////////////////////////////////////////////////////////////////// + + @Override + public boolean canInteractWith(final PlayerEntity player) { + return robot.isEntityInRange(player, 8); + } +} diff --git a/src/main/java/li/cil/oc2/common/entity/RobotEntity.java b/src/main/java/li/cil/oc2/common/entity/RobotEntity.java index 09d6fadf..78fde973 100644 --- a/src/main/java/li/cil/oc2/common/entity/RobotEntity.java +++ b/src/main/java/li/cil/oc2/common/entity/RobotEntity.java @@ -2,23 +2,33 @@ package li.cil.oc2.common.entity; import li.cil.oc2.api.bus.DeviceBusElement; import li.cil.oc2.api.bus.device.Device; +import li.cil.oc2.api.bus.device.object.Callback; +import li.cil.oc2.api.bus.device.object.ObjectDevice; +import li.cil.oc2.api.bus.device.object.Parameter; +import li.cil.oc2.client.gui.RobotTerminalScreen; import li.cil.oc2.common.Constants; import li.cil.oc2.common.bus.AbstractDeviceBusController; +import li.cil.oc2.common.bus.AbstractDeviceBusElement; import li.cil.oc2.common.bus.device.util.Devices; import li.cil.oc2.common.bus.device.util.ItemDeviceInfo; +import li.cil.oc2.common.container.RobotContainer; import li.cil.oc2.common.entity.robot.*; import li.cil.oc2.common.integration.Wrenches; import li.cil.oc2.common.network.Network; -import li.cil.oc2.common.network.message.RobotBootErrorMessage; -import li.cil.oc2.common.network.message.RobotTerminalOutputMessage; +import li.cil.oc2.common.network.message.*; import li.cil.oc2.common.serialization.NBTSerialization; import li.cil.oc2.common.util.NBTTagIds; import li.cil.oc2.common.util.WorldUtils; import li.cil.oc2.common.vm.*; import net.minecraft.block.SoundType; +import net.minecraft.client.Minecraft; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.inventory.container.Container; +import net.minecraft.inventory.container.INamedContainerProvider; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.nbt.ListNBT; @@ -27,25 +37,36 @@ import net.minecraft.network.datasync.DataParameter; import net.minecraft.network.datasync.DataSerializers; import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.ActionResultType; +import net.minecraft.util.Direction; import net.minecraft.util.Hand; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; import net.minecraft.util.math.MathHelper; import net.minecraft.util.text.ITextComponent; import net.minecraft.world.World; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.api.distmarker.OnlyIn; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.common.util.LazyOptional; +import net.minecraftforge.event.world.ChunkEvent; +import net.minecraftforge.event.world.WorldEvent; import net.minecraftforge.fml.network.NetworkHooks; import javax.annotation.Nullable; import java.nio.ByteBuffer; import java.util.*; +import java.util.function.Consumer; public final class RobotEntity extends Entity { + public static final DataParameter TARGET_POSITION = EntityDataManager.createKey(RobotEntity.class, DataSerializers.BLOCK_POS); + public static final DataParameter TARGET_DIRECTION = EntityDataManager.createKey(RobotEntity.class, DataSerializers.DIRECTION); + private static final String TERMINAL_TAG_NAME = "terminal"; private static final String STATE_TAG_NAME = "state"; + private static final String BUS_ELEMENT_TAG_NAME = "bus_element"; private static final String COMMAND_PROCESSOR_TAG_NAME = "commands"; - private static final DataParameter IS_RUNNING = EntityDataManager.createKey(RobotEntity.class, DataSerializers.BOOLEAN); - private static final int MAX_QUEUED_ACTIONS = 16; + private static final int MAX_QUEUED_ACTIONS = 15; private static final int MEMORY_SLOTS = 4; private static final int HARD_DRIVE_SLOTS = 2; @@ -54,12 +75,15 @@ public final class RobotEntity extends Entity { /////////////////////////////////////////////////////////////////// + private final Consumer chunkUnloadListener = this::handleChunkUnload; + private final Consumer worldUnloadListener = this::handleWorldUnload; + private final AnimationState animationState = new AnimationState(); private final CommandProcessor commandProcessor = new CommandProcessor(); private final Terminal terminal = new Terminal(); - private final RobotVirtualMachineState state; private final RobotItemStackHandlers items = new RobotItemStackHandlers(); + private final RobotBusElement busElement = new RobotBusElement(); /////////////////////////////////////////////////////////////////// @@ -68,8 +92,11 @@ public final class RobotEntity extends Entity { this.preventEntitySpawning = true; setNoGravity(true); - final RobotBusController busController = new RobotBusController(items.busElement); + final RobotBusController busController = new RobotBusController(busElement); state = new RobotVirtualMachineState(busController, new CommonVirtualMachine(busController)); + state.virtualMachine.rtcMinecraft.setWorld(world); + + items.busElement.addDevice(new ObjectDevice(new RobotDevice(), "robot")); } /////////////////////////////////////////////////////////////////// @@ -87,14 +114,10 @@ public final class RobotEntity extends Entity { return state; } - public CommonVirtualMachineItemStackHandlers getItemHandlers() { + public VirtualMachineItemStackHandlers getItemStackHandlers() { return items; } - public boolean isRunning() { - return dataManager.get(IS_RUNNING); - } - public void start() { final World world = getEntityWorld(); if (world == null || world.isRemote()) { @@ -115,8 +138,24 @@ public final class RobotEntity extends Entity { @Override public void tick() { + if (firstUpdate) { + if (getEntityWorld().isRemote()) { + requestInitialState(); + } else { + registerListeners(); + RobotActions.initializeData(this); + if (commandProcessor.action != null) { + commandProcessor.action.initialize(this); + } + } + } + super.tick(); + if (!getEntityWorld().isRemote()) { + state.tick(); + } + commandProcessor.tick(); } @@ -124,25 +163,19 @@ public final class RobotEntity extends Entity { public ActionResultType processInitialInteract(final PlayerEntity player, final Hand hand) { final ItemStack stack = player.getHeldItem(hand); if (Wrenches.isWrench(stack)) { - if (!world.isRemote()) { + if (!world.isRemote() && player instanceof ServerPlayerEntity) { if (player.isSneaking()) { remove(); WorldUtils.playSound(world, getPosition(), SoundType.METAL, SoundType::getBreakSound); } else { - // todo open container + openContainerScreen(player); } } } else { if (player.isSneaking()) { start(); - } else { -// if (rand.nextBoolean()) { -// commandProcessor.move(MovementDirection.values()[rand.nextInt(MovementDirection.values().length)]); -// } else { -// commandProcessor.rotate(rand.nextBoolean() ? RotationDirection.LEFT : RotationDirection.RIGHT); - commandProcessor.rotate(RotationDirection.RIGHT); -// } - // TODO open terminal + inventory screen + } else if (world.isRemote()) { + openTerminalScreen(); } } @@ -154,6 +187,18 @@ public final class RobotEntity extends Entity { return NetworkHooks.getEntitySpawningPacket(this); } + @Override + public void remove(final boolean keepData) { + super.remove(keepData); + + handleUnload(); + + // Full unload to release out-of-nbt persisted runtime-only data such as ram. + state.virtualMachine.vmAdapter.unload(); + + // TODO drop self as item + } + @Override public boolean canBeCollidedWith() { return true; @@ -182,7 +227,6 @@ public final class RobotEntity extends Entity { @Override protected void registerData() { - getDataManager().register(IS_RUNNING, false); RobotActions.registerData(getDataManager()); } @@ -191,6 +235,7 @@ public final class RobotEntity extends Entity { tag.put(STATE_TAG_NAME, state.serialize()); tag.put(TERMINAL_TAG_NAME, NBTSerialization.serialize(terminal)); tag.put(COMMAND_PROCESSOR_TAG_NAME, commandProcessor.serialize()); + tag.put(BUS_ELEMENT_TAG_NAME, busElement.serialize()); tag.put(Constants.INVENTORY_TAG_NAME, items.serialize()); } @@ -199,6 +244,7 @@ public final class RobotEntity extends Entity { state.deserialize(tag.getCompound(STATE_TAG_NAME)); NBTSerialization.deserialize(tag.getCompound(TERMINAL_TAG_NAME), terminal); commandProcessor.deserialize(tag.getCompound(COMMAND_PROCESSOR_TAG_NAME)); + busElement.deserialize(tag.getCompound(BUS_ELEMENT_TAG_NAME)); if (tag.contains(Constants.INVENTORY_TAG_NAME, NBTTagIds.TAG_COMPOUND)) { items.deserialize(tag.getCompound(Constants.INVENTORY_TAG_NAME)); @@ -216,6 +262,69 @@ public final class RobotEntity extends Entity { /////////////////////////////////////////////////////////////////// + @OnlyIn(Dist.CLIENT) + private void requestInitialState() { + Network.INSTANCE.sendToServer(new RobotInitializationRequestMessage(this)); + } + + @OnlyIn(Dist.CLIENT) + private void openTerminalScreen() { + Minecraft.getInstance().displayGuiScreen(new RobotTerminalScreen(this, getName())); + } + + private void registerListeners() { + MinecraftForge.EVENT_BUS.addListener(chunkUnloadListener); + MinecraftForge.EVENT_BUS.addListener(worldUnloadListener); + } + + private void unregisterListeners() { + MinecraftForge.EVENT_BUS.unregister(chunkUnloadListener); + MinecraftForge.EVENT_BUS.unregister(worldUnloadListener); + } + + private void handleChunkUnload(final ChunkEvent.Unload event) { + if (event.getWorld() != getEntityWorld()) { + return; + } + + final ChunkPos chunkPos = new ChunkPos(getPosition()); + if (!Objects.equals(chunkPos, event.getChunk().getPos())) { + return; + } + + unregisterListeners(); + handleUnload(); + } + + private void handleWorldUnload(final WorldEvent.Unload event) { + if (event.getWorld() != getEntityWorld()) { + return; + } + + unregisterListeners(); + handleUnload(); + } + + private void handleUnload() { + state.joinVirtualMachine(); + state.virtualMachine.vmAdapter.suspend(); + state.busController.dispose(); + } + + private void openContainerScreen(final PlayerEntity player) { + NetworkHooks.openGui((ServerPlayerEntity) player, new INamedContainerProvider() { + @Override + public ITextComponent getDisplayName() { + return getName(); + } + + @Override + public Container createMenu(final int id, final PlayerInventory inventory, final PlayerEntity player) { + return new RobotContainer(id, RobotEntity.this, inventory); + } + }, b -> b.writeVarInt(getEntityId())); + } + private static float lerpClamped(final float from, final float to, final float delta) { if (from < to) { return Math.min(from + delta, to); @@ -255,7 +364,7 @@ public final class RobotEntity extends Entity { public float topRenderHover = -(hashCode() & 0xFFFF); // init to "random" to avoid synchronous hovering public void update(final float deltaTime, final Random random) { - if (isRunning() || commandProcessor.hasQueuedActions()) { + if (getState().isRunning() || commandProcessor.hasQueuedActions()) { topRenderHover = topRenderHover + deltaTime * HOVER_ANIMATION_SPEED; final float topOffsetY = MathHelper.sin(topRenderHover) / 32f; @@ -287,6 +396,10 @@ public final class RobotEntity extends Entity { return action != null || !queue.isEmpty(); } + public int getQueuedActionCount() { + return (action != null ? 1 : 0) + queue.size(); + } + public boolean move(final MovementDirection direction) { return addAction(new RobotMovementAction(direction)); } @@ -347,7 +460,6 @@ public final class RobotEntity extends Entity { if (tag.contains(ACTION_TAG_NAME, NBTTagIds.TAG_COMPOUND)) { action = RobotActions.deserialize(tag.getCompound(ACTION_TAG_NAME)); - action.initialize(RobotEntity.this); } } @@ -356,7 +468,7 @@ public final class RobotEntity extends Entity { return false; } - if (!isRunning()) { + if (!getState().isRunning()) { return false; } @@ -369,7 +481,7 @@ public final class RobotEntity extends Entity { } } - private final class RobotItemStackHandlers extends CommonVirtualMachineItemStackHandlers { + private final class RobotItemStackHandlers extends AbstractVirtualMachineItemStackHandlers { public RobotItemStackHandlers() { super(MEMORY_SLOTS, HARD_DRIVE_SLOTS, FLASH_MEMORY_SLOTS, CARD_SLOTS); } @@ -380,6 +492,43 @@ public final class RobotEntity extends Entity { } } + private final class RobotBusElement extends AbstractDeviceBusElement { + private static final String DEVICE_ID_TAG_NAME = "device_id"; + + private final Device device = new ObjectDevice(new RobotDevice(), "robot"); + private UUID deviceId = UUID.randomUUID(); + + @Override + public Optional>> getNeighbors() { + return Optional.of(Collections.singleton(LazyOptional.of(() -> items.busElement))); + } + + @Override + public Collection getLocalDevices() { + return Collections.singleton(device); + } + + @Override + public Optional getDeviceIdentifier(final Device device) { + if (device == this.device) { + return Optional.of(deviceId); + } + return super.getDeviceIdentifier(device); + } + + public CompoundNBT serialize() { + final CompoundNBT tag = new CompoundNBT(); + tag.putUniqueId(DEVICE_ID_TAG_NAME, deviceId); + return tag; + } + + public void deserialize(final CompoundNBT tag) { + if (tag.hasUniqueId(DEVICE_ID_TAG_NAME)) { + deviceId = tag.getUniqueId(DEVICE_ID_TAG_NAME); + } + } + } + private final class RobotBusController extends AbstractDeviceBusController { public RobotBusController(final DeviceBusElement root) { super(root); @@ -437,15 +586,41 @@ public final class RobotEntity extends Entity { commandProcessor.clear(); } + @Override + protected void handleBusStateChanged(final AbstractDeviceBusController.BusState value) { + Network.sendToClientsTrackingEntity(new RobotBusStateMessage(RobotEntity.this), RobotEntity.this); + } + @Override protected void handleRunStateChanged(final RunState value) { - dataManager.set(IS_RUNNING, isRunning()); + Network.sendToClientsTrackingEntity(new RobotRunStateMessage(RobotEntity.this), RobotEntity.this); } @Override protected void handleBootErrorChanged(@Nullable final ITextComponent value) { - final RobotBootErrorMessage message = new RobotBootErrorMessage(RobotEntity.this); - Network.sendToClientsTrackingEntity(message, RobotEntity.this); + Network.sendToClientsTrackingEntity(new RobotBootErrorMessage(RobotEntity.this), RobotEntity.this); + } + } + + public final class RobotDevice { + @Callback + public boolean move(@Parameter("direction") @Nullable final MovementDirection direction) { + if (direction == null) throw new IllegalArgumentException(); + return commandProcessor.move(direction); + } + + @Callback + public boolean turn(@Parameter("direction") @Nullable final RotationDirection direction) { + if (direction == null) throw new IllegalArgumentException(); + return commandProcessor.rotate(direction); + } + + @Callback + public int getQueuedActionCount() { + return commandProcessor.getQueuedActionCount(); + } + + private RobotDevice() { } } } diff --git a/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementAction.java b/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementAction.java index 5cb678fd..01b4d4bb 100644 --- a/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementAction.java +++ b/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementAction.java @@ -7,9 +7,6 @@ import li.cil.oc2.common.util.NBTTagIds; import li.cil.oc2.common.util.NBTUtils; import net.minecraft.entity.MoverType; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.datasync.DataParameter; -import net.minecraft.network.datasync.DataSerializers; -import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.Direction; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.vector.Vector3d; @@ -17,12 +14,11 @@ import net.minecraft.util.math.vector.Vector3d; import javax.annotation.Nullable; public final class RobotMovementAction extends AbstractRobotAction { - public static final DataParameter TARGET_POSITION = EntityDataManager.createKey(RobotEntity.class, DataSerializers.BLOCK_POS); public static final double TARGET_EPSILON = 0.0001; /////////////////////////////////////////////////////////////////// - private static final float MOVEMENT_SPEED = 0.5f / Constants.TICK_SECONDS; // In blocks per second. + private static final float MOVEMENT_SPEED = 1f / Constants.TICK_SECONDS; // In blocks per second. private static final String DIRECTION_TAG_NAME = "direction"; private static final String START_TAG_NAME = "start"; @@ -84,7 +80,7 @@ public final class RobotMovementAction extends AbstractRobotAction { target = getTargetPositionInBlock(targetPosition); } - robot.getDataManager().set(TARGET_POSITION, new BlockPos(target)); + robot.getDataManager().set(RobotEntity.TARGET_POSITION, new BlockPos(target)); } @Override @@ -99,7 +95,7 @@ public final class RobotMovementAction extends AbstractRobotAction { if (didCollide && !robot.getEntityWorld().isRemote()) { if (start != null) { target = getTargetPositionInBlock(start); - robot.getDataManager().set(TARGET_POSITION, start); + robot.getDataManager().set(RobotEntity.TARGET_POSITION, start); start = null; } else { diff --git a/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementActionType.java b/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementActionType.java index 268e95cf..986d8c8e 100644 --- a/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementActionType.java +++ b/src/main/java/li/cil/oc2/common/entity/robot/RobotMovementActionType.java @@ -15,17 +15,17 @@ public final class RobotMovementActionType extends AbstractRobotActionType { @Override public void registerData(final EntityDataManager dataManager) { - dataManager.register(RobotMovementAction.TARGET_POSITION, BlockPos.ZERO); + dataManager.register(RobotEntity.TARGET_POSITION, BlockPos.ZERO); } @Override public void initializeData(final RobotEntity robot) { - robot.getDataManager().set(RobotMovementAction.TARGET_POSITION, robot.getPosition()); + robot.getDataManager().set(RobotEntity.TARGET_POSITION, robot.getPosition()); } @Override public void performClient(final RobotEntity robot) { - final Vector3d target = RobotMovementAction.getTargetPositionInBlock(robot.getDataManager().get(RobotMovementAction.TARGET_POSITION)); + final Vector3d target = RobotMovementAction.getTargetPositionInBlock(robot.getDataManager().get(RobotEntity.TARGET_POSITION)); if (robot.getPositionVec().squareDistanceTo(target) > RobotMovementAction.TARGET_EPSILON) { RobotMovementAction.moveTowards(robot, target); } diff --git a/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationAction.java b/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationAction.java index b106f36a..c02040ef 100644 --- a/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationAction.java +++ b/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationAction.java @@ -5,21 +5,17 @@ import li.cil.oc2.common.entity.RobotEntity; import li.cil.oc2.common.util.NBTTagIds; import li.cil.oc2.common.util.NBTUtils; import net.minecraft.nbt.CompoundNBT; -import net.minecraft.network.datasync.DataParameter; -import net.minecraft.network.datasync.DataSerializers; -import net.minecraft.network.datasync.EntityDataManager; import net.minecraft.util.Direction; import net.minecraft.util.math.MathHelper; import javax.annotation.Nullable; public final class RobotRotationAction extends AbstractRobotAction { - public static final DataParameter TARGET_DIRECTION = EntityDataManager.createKey(RobotEntity.class, DataSerializers.DIRECTION); public static final float TARGET_EPSILON = 0.0001f; /////////////////////////////////////////////////////////////////// - private static final float ROTATION_SPEED = 45f / Constants.TICK_SECONDS; // In degrees per second. + private static final float ROTATION_SPEED = 90f / Constants.TICK_SECONDS; // In degrees per second. private static final String DIRECTION_TAG_NAME = "direction"; private static final String TARGET_TAG_NAME = "start"; @@ -61,7 +57,7 @@ public final class RobotRotationAction extends AbstractRobotAction { } } - robot.getDataManager().set(TARGET_DIRECTION, target); + robot.getDataManager().set(RobotEntity.TARGET_DIRECTION, target); } @Override diff --git a/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationActionType.java b/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationActionType.java index 81a8f513..0488beea 100644 --- a/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationActionType.java +++ b/src/main/java/li/cil/oc2/common/entity/robot/RobotRotationActionType.java @@ -15,17 +15,17 @@ public final class RobotRotationActionType extends AbstractRobotActionType { @Override public void registerData(final EntityDataManager dataManager) { - dataManager.register(RobotRotationAction.TARGET_DIRECTION, Direction.NORTH); + dataManager.register(RobotEntity.TARGET_DIRECTION, Direction.NORTH); } @Override public void initializeData(final RobotEntity robot) { - robot.getDataManager().set(RobotRotationAction.TARGET_DIRECTION, robot.getHorizontalFacing()); + robot.getDataManager().set(RobotEntity.TARGET_DIRECTION, robot.getHorizontalFacing()); } @Override public void performClient(final RobotEntity robot) { - final Direction target = robot.getDataManager().get(RobotRotationAction.TARGET_DIRECTION); + final Direction target = robot.getDataManager().get(RobotEntity.TARGET_DIRECTION); if (MathHelper.degreesDifferenceAbs(robot.rotationYaw, target.getHorizontalAngle()) > RobotRotationAction.TARGET_EPSILON) { RobotRotationAction.rotateTowards(robot, target); } diff --git a/src/main/java/li/cil/oc2/common/item/ItemGroup.java b/src/main/java/li/cil/oc2/common/item/ItemGroup.java index 775489bc..ef4a796b 100644 --- a/src/main/java/li/cil/oc2/common/item/ItemGroup.java +++ b/src/main/java/li/cil/oc2/common/item/ItemGroup.java @@ -5,7 +5,7 @@ import li.cil.oc2.common.Constants; import li.cil.oc2.common.bus.device.data.BaseBlockDevices; import li.cil.oc2.common.bus.device.data.Firmwares; import li.cil.oc2.common.util.ItemStackUtils; -import li.cil.oc2.common.vm.CommonVirtualMachineItemStackHandlers; +import li.cil.oc2.common.vm.AbstractVirtualMachineItemStackHandlers; import net.minecraft.item.ItemStack; import net.minecraft.nbt.CompoundNBT; import net.minecraft.util.NonNullList; @@ -46,18 +46,18 @@ public final class ItemGroup { final ItemStack computer = new ItemStack(Items.COMPUTER_ITEM.get()); final CompoundNBT computerItems = ItemStackUtils.getOrCreateTileEntityInventoryTag(computer); - computerItems.put(CommonVirtualMachineItemStackHandlers.MEMORY_TAG_NAME, makeInventoryTag( + computerItems.put(AbstractVirtualMachineItemStackHandlers.MEMORY_TAG_NAME, makeInventoryTag( MemoryItem.withCapacity(8 * Constants.MEGABYTE), MemoryItem.withCapacity(8 * Constants.MEGABYTE), MemoryItem.withCapacity(8 * Constants.MEGABYTE) )); - computerItems.put(CommonVirtualMachineItemStackHandlers.HARD_DRIVE_TAG_NAME, makeInventoryTag( + computerItems.put(AbstractVirtualMachineItemStackHandlers.HARD_DRIVE_TAG_NAME, makeInventoryTag( HardDriveItem.withBase(BaseBlockDevices.BUILDROOT.get()) )); - computerItems.put(CommonVirtualMachineItemStackHandlers.FLASH_MEMORY_TAG_NAME, makeInventoryTag( + computerItems.put(AbstractVirtualMachineItemStackHandlers.FLASH_MEMORY_TAG_NAME, makeInventoryTag( FlashMemoryItem.withFirmware(Firmwares.BUILDROOT.get()) )); - computerItems.put(CommonVirtualMachineItemStackHandlers.CARD_TAG_NAME, makeInventoryTag( + computerItems.put(AbstractVirtualMachineItemStackHandlers.CARD_TAG_NAME, makeInventoryTag( new ItemStack(Items.NETWORK_INTERFACE_CARD_ITEM.get()) )); diff --git a/src/main/java/li/cil/oc2/common/network/Network.java b/src/main/java/li/cil/oc2/common/network/Network.java index 56aef763..4b15aa8a 100644 --- a/src/main/java/li/cil/oc2/common/network/Network.java +++ b/src/main/java/li/cil/oc2/common/network/Network.java @@ -81,11 +81,41 @@ public final class Network { .consumer(RobotTerminalInputMessage::handleMessage) .add(); + INSTANCE.messageBuilder(RobotRunStateMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(RobotRunStateMessage::toBytes) + .decoder(RobotRunStateMessage::new) + .consumer(RobotRunStateMessage::handleMessage) + .add(); + + INSTANCE.messageBuilder(RobotBusStateMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(RobotBusStateMessage::toBytes) + .decoder(RobotBusStateMessage::new) + .consumer(RobotBusStateMessage::handleMessage) + .add(); + INSTANCE.messageBuilder(RobotBootErrorMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT) .encoder(RobotBootErrorMessage::toBytes) .decoder(RobotBootErrorMessage::new) .consumer(RobotBootErrorMessage::handleMessage) .add(); + + INSTANCE.messageBuilder(RobotPowerMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_SERVER) + .encoder(RobotPowerMessage::toBytes) + .decoder(RobotPowerMessage::new) + .consumer(RobotPowerMessage::handleMessage) + .add(); + + INSTANCE.messageBuilder(RobotInitializationRequestMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_SERVER) + .encoder(RobotInitializationRequestMessage::toBytes) + .decoder(RobotInitializationRequestMessage::new) + .consumer(RobotInitializationRequestMessage::handleMessage) + .add(); + + INSTANCE.messageBuilder(RobotInitializationMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT) + .encoder(RobotInitializationMessage::toBytes) + .decoder(RobotInitializationMessage::new) + .consumer(RobotInitializationMessage::handleMessage) + .add(); } public static void sendToClientsTrackingChunk(final T message, final Chunk chunk) { diff --git a/src/main/java/li/cil/oc2/common/network/message/ComputerBusStateMessage.java b/src/main/java/li/cil/oc2/common/network/message/ComputerBusStateMessage.java index 6a6b9c8c..0bdea435 100644 --- a/src/main/java/li/cil/oc2/common/network/message/ComputerBusStateMessage.java +++ b/src/main/java/li/cil/oc2/common/network/message/ComputerBusStateMessage.java @@ -11,13 +11,13 @@ import java.util.function.Supplier; public final class ComputerBusStateMessage { private BlockPos pos; - private AbstractDeviceBusController.BusState busState; + private AbstractDeviceBusController.BusState value; /////////////////////////////////////////////////////////////////// public ComputerBusStateMessage(final ComputerTileEntity tileEntity) { this.pos = tileEntity.getPos(); - this.busState = tileEntity.getState().getBusState(); + this.value = tileEntity.getState().getBusState(); } public ComputerBusStateMessage(final PacketBuffer buffer) { @@ -28,17 +28,17 @@ public final class ComputerBusStateMessage { public static boolean handleMessage(final ComputerBusStateMessage message, final Supplier context) { context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, ComputerTileEntity.class, - (tileEntity) -> tileEntity.getState().setBusStateClient(message.busState))); + (tileEntity) -> tileEntity.getState().setBusStateClient(message.value))); return true; } public void fromBytes(final PacketBuffer buffer) { pos = buffer.readBlockPos(); - busState = buffer.readEnumValue(AbstractDeviceBusController.BusState.class); + value = buffer.readEnumValue(AbstractDeviceBusController.BusState.class); } public static void toBytes(final ComputerBusStateMessage message, final PacketBuffer buffer) { buffer.writeBlockPos(message.pos); - buffer.writeEnumValue(message.busState); + buffer.writeEnumValue(message.value); } } diff --git a/src/main/java/li/cil/oc2/common/network/message/ComputerRunStateMessage.java b/src/main/java/li/cil/oc2/common/network/message/ComputerRunStateMessage.java index 5ca26e32..755217e2 100644 --- a/src/main/java/li/cil/oc2/common/network/message/ComputerRunStateMessage.java +++ b/src/main/java/li/cil/oc2/common/network/message/ComputerRunStateMessage.java @@ -11,13 +11,13 @@ import java.util.function.Supplier; public final class ComputerRunStateMessage { private BlockPos pos; - private VirtualMachineState.RunState runState; + private VirtualMachineState.RunState value; /////////////////////////////////////////////////////////////////// public ComputerRunStateMessage(final ComputerTileEntity tileEntity) { this.pos = tileEntity.getPos(); - this.runState = tileEntity.getState().getRunState(); + this.value = tileEntity.getState().getRunState(); } public ComputerRunStateMessage(final PacketBuffer buffer) { @@ -28,17 +28,17 @@ public final class ComputerRunStateMessage { public static boolean handleMessage(final ComputerRunStateMessage message, final Supplier context) { context.get().enqueueWork(() -> MessageUtils.withClientTileEntityAt(message.pos, ComputerTileEntity.class, - (tileEntity) -> tileEntity.getState().setRunStateClient(message.runState))); + (tileEntity) -> tileEntity.getState().setRunStateClient(message.value))); return true; } public void fromBytes(final PacketBuffer buffer) { pos = buffer.readBlockPos(); - runState = buffer.readEnumValue(VirtualMachineState.RunState.class); + value = buffer.readEnumValue(VirtualMachineState.RunState.class); } public static void toBytes(final ComputerRunStateMessage message, final PacketBuffer buffer) { buffer.writeBlockPos(message.pos); - buffer.writeEnumValue(message.runState); + buffer.writeEnumValue(message.value); } } diff --git a/src/main/java/li/cil/oc2/common/network/message/RobotBusStateMessage.java b/src/main/java/li/cil/oc2/common/network/message/RobotBusStateMessage.java new file mode 100644 index 00000000..d6cdf62f --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/RobotBusStateMessage.java @@ -0,0 +1,43 @@ +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.bus.AbstractDeviceBusController; +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.MessageUtils; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public final class RobotBusStateMessage { + private int entityId; + private AbstractDeviceBusController.BusState value; + + /////////////////////////////////////////////////////////////////// + + public RobotBusStateMessage(final RobotEntity robot) { + this.entityId = robot.getEntityId(); + this.value = robot.getState().getBusState(); + } + + public RobotBusStateMessage(final PacketBuffer buffer) { + fromBytes(buffer); + } + + /////////////////////////////////////////////////////////////////// + + public static boolean handleMessage(final RobotBusStateMessage message, final Supplier context) { + context.get().enqueueWork(() -> MessageUtils.withClientEntity(message.entityId, RobotEntity.class, + (robot) -> robot.getState().setBusStateClient(message.value))); + return true; + } + + public void fromBytes(final PacketBuffer buffer) { + entityId = buffer.readVarInt(); + value = buffer.readEnumValue(AbstractDeviceBusController.BusState.class); + } + + public static void toBytes(final RobotBusStateMessage message, final PacketBuffer buffer) { + buffer.writeVarInt(message.entityId); + buffer.writeEnumValue(message.value); + } +} diff --git a/src/main/java/li/cil/oc2/common/network/message/RobotInitializationMessage.java b/src/main/java/li/cil/oc2/common/network/message/RobotInitializationMessage.java new file mode 100644 index 00000000..96c16700 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/RobotInitializationMessage.java @@ -0,0 +1,64 @@ +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.bus.AbstractDeviceBusController; +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.MessageUtils; +import li.cil.oc2.common.serialization.NBTSerialization; +import li.cil.oc2.common.vm.VirtualMachineState; +import net.minecraft.nbt.CompoundNBT; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.text.ITextComponent; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public final class RobotInitializationMessage { + private int entityId; + private AbstractDeviceBusController.BusState busState; + private VirtualMachineState.RunState runState; + private ITextComponent bootError; + private CompoundNBT terminal; + + /////////////////////////////////////////////////////////////////// + + public RobotInitializationMessage(final RobotEntity robot) { + this.entityId = robot.getEntityId(); + this.busState = robot.getState().getBusState(); + this.runState = robot.getState().getRunState(); + this.bootError = robot.getState().getBootError(); + this.terminal = NBTSerialization.serialize(robot.getTerminal()); + } + + public RobotInitializationMessage(final PacketBuffer buffer) { + fromBytes(buffer); + } + + /////////////////////////////////////////////////////////////////// + + public static boolean handleMessage(final RobotInitializationMessage message, final Supplier context) { + context.get().enqueueWork(() -> MessageUtils.withClientEntity(message.entityId, RobotEntity.class, + (robot) -> { + robot.getState().setBusStateClient(message.busState); + robot.getState().setRunStateClient(message.runState); + robot.getState().setBootErrorClient(message.bootError); + NBTSerialization.deserialize(message.terminal, robot.getTerminal()); + })); + return true; + } + + public void fromBytes(final PacketBuffer buffer) { + entityId = buffer.readVarInt(); + busState = buffer.readEnumValue(AbstractDeviceBusController.BusState.class); + runState = buffer.readEnumValue(VirtualMachineState.RunState.class); + bootError = buffer.readTextComponent(); + terminal = buffer.readCompoundTag(); + } + + public static void toBytes(final RobotInitializationMessage message, final PacketBuffer buffer) { + buffer.writeVarInt(message.entityId); + buffer.writeEnumValue(message.busState); + buffer.writeEnumValue(message.runState); + buffer.writeTextComponent(message.bootError); + buffer.writeCompoundTag(message.terminal); + } +} diff --git a/src/main/java/li/cil/oc2/common/network/message/RobotInitializationRequestMessage.java b/src/main/java/li/cil/oc2/common/network/message/RobotInitializationRequestMessage.java new file mode 100644 index 00000000..0ecf1af5 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/RobotInitializationRequestMessage.java @@ -0,0 +1,39 @@ +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.MessageUtils; +import li.cil.oc2.common.network.Network; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public final class RobotInitializationRequestMessage { + private int entityId; + + /////////////////////////////////////////////////////////////////// + + public RobotInitializationRequestMessage(final RobotEntity robot) { + this.entityId = robot.getEntityId(); + } + + public RobotInitializationRequestMessage(final PacketBuffer buffer) { + fromBytes(buffer); + } + + /////////////////////////////////////////////////////////////////// + + public static boolean handleMessage(final RobotInitializationRequestMessage message, final Supplier context) { + context.get().enqueueWork(() -> MessageUtils.withServerEntity(context, message.entityId, RobotEntity.class, + (robot) -> Network.INSTANCE.reply(new RobotInitializationMessage(robot), context.get()))); + return true; + } + + public void fromBytes(final PacketBuffer buffer) { + entityId = buffer.readVarInt(); + } + + public static void toBytes(final RobotInitializationRequestMessage message, final PacketBuffer buffer) { + buffer.writeVarInt(message.entityId); + } +} diff --git a/src/main/java/li/cil/oc2/common/network/message/RobotPowerMessage.java b/src/main/java/li/cil/oc2/common/network/message/RobotPowerMessage.java new file mode 100644 index 00000000..497ec0dd --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/RobotPowerMessage.java @@ -0,0 +1,52 @@ +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.MessageUtils; +import net.minecraft.entity.player.ServerPlayerEntity; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public final class RobotPowerMessage { + private int entityId; + private boolean power; + + /////////////////////////////////////////////////////////////////// + + public RobotPowerMessage(final RobotEntity robot, final boolean power) { + this.entityId = robot.getEntityId(); + this.power = power; + } + + public RobotPowerMessage(final PacketBuffer buffer) { + fromBytes(buffer); + } + + /////////////////////////////////////////////////////////////////// + + public static boolean handleMessage(final RobotPowerMessage message, final Supplier context) { + context.get().enqueueWork(() -> MessageUtils.withServerEntity(context, message.entityId, RobotEntity.class, + (robot) -> { + final ServerPlayerEntity player = context.get().getSender(); + if (player != null && robot.isEntityInRange(player, 8)) { + if (message.power) { + robot.start(); + } else { + robot.stop(); + } + } + })); + return true; + } + + public void fromBytes(final PacketBuffer buffer) { + entityId = buffer.readVarInt(); + power = buffer.readBoolean(); + } + + public static void toBytes(final RobotPowerMessage message, final PacketBuffer buffer) { + buffer.writeVarInt(message.entityId); + buffer.writeBoolean(message.power); + } +} diff --git a/src/main/java/li/cil/oc2/common/network/message/RobotRunStateMessage.java b/src/main/java/li/cil/oc2/common/network/message/RobotRunStateMessage.java new file mode 100644 index 00000000..d2ec7c02 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/RobotRunStateMessage.java @@ -0,0 +1,43 @@ +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.entity.RobotEntity; +import li.cil.oc2.common.network.MessageUtils; +import li.cil.oc2.common.vm.VirtualMachineState; +import net.minecraft.network.PacketBuffer; +import net.minecraftforge.fml.network.NetworkEvent; + +import java.util.function.Supplier; + +public final class RobotRunStateMessage { + private int entityId; + private VirtualMachineState.RunState value; + + /////////////////////////////////////////////////////////////////// + + public RobotRunStateMessage(final RobotEntity robot) { + this.entityId = robot.getEntityId(); + this.value = robot.getState().getRunState(); + } + + public RobotRunStateMessage(final PacketBuffer buffer) { + fromBytes(buffer); + } + + /////////////////////////////////////////////////////////////////// + + public static boolean handleMessage(final RobotRunStateMessage message, final Supplier context) { + context.get().enqueueWork(() -> MessageUtils.withClientEntity(message.entityId, RobotEntity.class, + (robot) -> robot.getState().setRunStateClient(message.value))); + return true; + } + + public void fromBytes(final PacketBuffer buffer) { + entityId = buffer.readVarInt(); + value = buffer.readEnumValue(VirtualMachineState.RunState.class); + } + + public static void toBytes(final RobotRunStateMessage message, final PacketBuffer buffer) { + buffer.writeVarInt(message.entityId); + buffer.writeEnumValue(message.value); + } +} diff --git a/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java b/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java index f510a9d7..65f9916a 100644 --- a/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java +++ b/src/main/java/li/cil/oc2/common/tileentity/ComputerTileEntity.java @@ -83,7 +83,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic return state; } - public CommonVirtualMachineItemStackHandlers getItemHandlers() { + public VirtualMachineItemStackHandlers getItemStackHandlers() { return items; } @@ -162,7 +162,8 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic super.remove(); // Unload only suspends, but we want to do a full clean-up when we get - // destroyed, so stuff inside us can delete out-of-nbt persisted data. + // destroyed, so stuff inside us can delete out-of-nbt persisted runtime- + // only data such as ram. state.virtualMachine.vmAdapter.unload(); } @@ -259,7 +260,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic /////////////////////////////////////////////////////////////////// - private final class ComputerItemStackHandlers extends CommonVirtualMachineItemStackHandlers { + private final class ComputerItemStackHandlers extends AbstractVirtualMachineItemStackHandlers { public ComputerItemStackHandlers() { super(MEMORY_SLOTS, HARD_DRIVE_SLOTS, FLASH_MEMORY_SLOTS, CARD_SLOTS); } @@ -364,8 +365,7 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic @Override protected void handleBusStateChanged(final AbstractDeviceBusController.BusState value) { - final ComputerBusStateMessage message = new ComputerBusStateMessage(ComputerTileEntity.this); - Network.sendToClientsTrackingChunk(message, chunk); + Network.sendToClientsTrackingChunk(new ComputerBusStateMessage(ComputerTileEntity.this), chunk); if (value == AbstractDeviceBusController.BusState.READY) { // Bus just became ready, meaning new devices may be available, meaning new @@ -379,15 +379,13 @@ public final class ComputerTileEntity extends AbstractTileEntity implements ITic // This method can be called from disposal logic, so if we are disposed quickly enough // chunk may not be initialized yet. Avoid resulting NRE in network logic. if (chunk != null) { - final ComputerRunStateMessage message = new ComputerRunStateMessage(ComputerTileEntity.this); - Network.sendToClientsTrackingChunk(message, chunk); + Network.sendToClientsTrackingChunk(new ComputerRunStateMessage(ComputerTileEntity.this), chunk); } } @Override protected void handleBootErrorChanged(@Nullable final ITextComponent value) { - final ComputerBootErrorMessage message = new ComputerBootErrorMessage(ComputerTileEntity.this); - Network.sendToClientsTrackingChunk(message, chunk); + Network.sendToClientsTrackingChunk(new ComputerBootErrorMessage(ComputerTileEntity.this), chunk); } } } diff --git a/src/main/java/li/cil/oc2/common/vm/CommonVirtualMachineItemStackHandlers.java b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachineItemStackHandlers.java similarity index 93% rename from src/main/java/li/cil/oc2/common/vm/CommonVirtualMachineItemStackHandlers.java rename to src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachineItemStackHandlers.java index a2c3eb39..c5fde87d 100644 --- a/src/main/java/li/cil/oc2/common/vm/CommonVirtualMachineItemStackHandlers.java +++ b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachineItemStackHandlers.java @@ -20,7 +20,7 @@ import net.minecraftforge.items.wrapper.CombinedInvWrapper; import java.util.*; import java.util.function.Function; -public abstract class CommonVirtualMachineItemStackHandlers { +public abstract class AbstractVirtualMachineItemStackHandlers implements VirtualMachineItemStackHandlers { private static final long ITEM_DEVICE_BASE_ADDRESS = 0x40000000L; private static final int ITEM_DEVICE_STRIDE = 0x1000; @@ -52,10 +52,10 @@ public abstract class CommonVirtualMachineItemStackHandlers { /////////////////////////////////////////////////////////////////// - public CommonVirtualMachineItemStackHandlers(final int memorySlots, - final int hardDriveSlots, - final int flashMemorySlots, - final int cardSlots) { + public AbstractVirtualMachineItemStackHandlers(final int memorySlots, + final int hardDriveSlots, + final int flashMemorySlots, + final int cardSlots) { memoryItemHandler = new ItemHandler(memorySlots, this::getDevices, DeviceTypes.MEMORY); hardDriveItemHandler = new ItemHandler(hardDriveSlots, this::getDevices, DeviceTypes.HARD_DRIVE); flashMemoryItemHandler = new ItemHandler(flashMemorySlots, this::getDevices, DeviceTypes.FLASH_MEMORY); @@ -66,6 +66,7 @@ public abstract class CommonVirtualMachineItemStackHandlers { /////////////////////////////////////////////////////////////////// + @Override public Optional getItemHandler(final DeviceType deviceType) { if (deviceType == DeviceTypes.MEMORY) { return Optional.of(memoryItemHandler); @@ -79,6 +80,7 @@ public abstract class CommonVirtualMachineItemStackHandlers { return Optional.empty(); } + @Override public boolean isEmpty() { for (int slot = 0; slot < itemHandlers.getSlots(); slot++) { if (!itemHandlers.getStackInSlot(slot).isEmpty()) { @@ -116,6 +118,7 @@ public abstract class CommonVirtualMachineItemStackHandlers { return OptionalLong.empty(); } + @Override public void exportDeviceDataToItemStacks() { memoryItemHandler.exportDeviceDataToItemStacks(); hardDriveItemHandler.exportDeviceDataToItemStacks(); @@ -166,7 +169,7 @@ public abstract class CommonVirtualMachineItemStackHandlers { @Override protected void onContentsChanged(final int slot) { super.onContentsChanged(slot); - CommonVirtualMachineItemStackHandlers.this.onContentsChanged(this, slot); + AbstractVirtualMachineItemStackHandlers.this.onContentsChanged(this, slot); } } diff --git a/src/main/java/li/cil/oc2/common/vm/VirtualMachineItemStackHandlers.java b/src/main/java/li/cil/oc2/common/vm/VirtualMachineItemStackHandlers.java new file mode 100644 index 00000000..28832870 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/vm/VirtualMachineItemStackHandlers.java @@ -0,0 +1,14 @@ +package li.cil.oc2.common.vm; + +import li.cil.oc2.api.bus.device.DeviceType; +import net.minecraftforge.items.IItemHandler; + +import java.util.Optional; + +public interface VirtualMachineItemStackHandlers { + Optional getItemHandler(DeviceType deviceType); + + boolean isEmpty(); + + void exportDeviceDataToItemStacks(); +} diff --git a/src/main/resources/assets/oc2/lang/en_us.json b/src/main/resources/assets/oc2/lang/en_us.json index 3f98655e..316a6585 100644 --- a/src/main/resources/assets/oc2/lang/en_us.json +++ b/src/main/resources/assets/oc2/lang/en_us.json @@ -16,6 +16,8 @@ "item.oc2.redstone_interface_card": "Redstone Interface Card", "item.oc2.network_interface_card": "Network Interface Card", + "entity.oc2.robot": "Robot", + "config.oc2.maxAllocatedMemory": "Maximum allocated memory", "config.oc2.maxMemorySize:": "Maximum memory device size", "config.oc2.maxHardDriveSize": "Maximum hard drive device size", diff --git a/src/main/resources/assets/oc2/textures/entity/robot/robot.png b/src/main/resources/assets/oc2/textures/entity/robot/robot.png index 1071b5f274ca23cb2057e5321bcb04edd05acae9..8aeb30b577c9c53ddc30b8d3b2e9ecc7e727897a 100644 GIT binary patch delta 3448 zcmYk8Rb11J0){tQ5ou6HeIsP(z&Q{{r-UL($^hvY-3@<9K}r}QEh$V&1*BU-2b=+u z*uWv5)R0y{>U^iq<#X}8zxU$3css=o#b1cf(Cej(9g8~HD?wfS{k`R-rM&}u-KD&I zouwV@r5)WJJsds#{iG362}-`NMi&_UiOas%{$mMT5;fic>N|q{^m`n@AeSkc$PNnXv}|6lYkbjJt>d$`NH+j=@HL4)BAj!w1#?*33^UoSf^ ze?{qk819&V>;I(x_=}R zA(5y3LR*vG(5YJ!kc6vHHE-H}W%sgqyK4Io=h4yuC)bpJOX_>wS6FHJ@bC+flRnZ1 zWloXK8GS56Qxs|o?DAfVe4BAAz%~R0R_ZK0ArD0)nvLE!7?~3<<4%$giQPdCvazf0 z>sYIQQwv?o5D?pK-#fzIxK{^#uf~HF%P4PH;|kEiy?N&fl)m|fdFOe4{);&AJCvE& zX65orB1el3oa1iUMRdEhed02Drt^nQEtaoije zrR3L;egxrX^R~vQoUza#?T_q2oG!Hw3yV6$_HN?vGa3$eyPvO@TrOM3;gg3Gc%`9b z@zYdUq*1qVR>DalF8%{f61o^t8*s$-ngj}81q{OR3$p#7=}}qs0-Jgd%b7&$mh4k8 zs0HJPA2C0aUD6DqCz?!)OZS+yjxWw8M{SX_KP$aL5p1M-iW*m_0dOrtLy~UoZB;k1 zZj?$;j?{sDTM0ZH?I^>Lsu2(|RN2NaKs2;;og~F4{%zKL&j6;q)n#$7x}u!;Jl72d zxb_=Qx&{P>TdJA9xaY?OKd>2ppW@bRo^0=A(WglLEX$fOh542_cLSPNuZqv$NRpW; z*M!m6Y?;jK$3I$8ehY*4;lBlS!3T0hI2d2D@l;pnj1AN@NfDu?=ua}KH@?Mx1=pE| zxpZfj?x@eatewvcxk{;$Ql6z(1tefV2}AP`XeU&Bj~JXwq9ij%oC1&^CvkOw=VpLgQ%0!gVwm&-@gNRP@O?(FU6cSY#z!z z#J;BoPeeDTcl19Ih>kTD>4V8C&KLyQzgD!Mc9K3M=F0EAoWP-9S7)oU=y6*C0$i#q z?e>pyI~)+sCe}1CLzCPDfdGbl40QRf5uOKC^LyMt#behlhU zvm@Cw=-FdKQa+Txx<;XZSO9>%cQj+T_-p`re*lWUXwiVn3y%EV_~V>H*(uXTQ%7>F zCDY3rEedj97N6~7&rbFXCBW5mt0LW`+oI)d6+*ONxgDH?Al}@~LnVx>O&vJh*0>sv zX%{2P>uVYh5F#SAag+v4@t9#w+a^8PrL=Hg#Oy^RqBAuFmn%bntF`THU0l7aEGgg$J+V zE1P`B;IpLQ{IEd4$p-1t+C%PB4e(ovM}%J0cFHbrgKd8KYYcM4#nJr9K)0)UVWUe7 zVf#e0(Tg}LL~dP1cPxN^^5&Fb4G6(h__f=BVaITxEfCH^i{OQz^s`MSZb}f2b`YcX za}m%fk$(JFUzXrsTS9=lj9}bS|`&qEnvJvZL?-(<3K7sEQ`Q!m?j+AYW4b; zV>D7XY(6fj#hBI6lFZ8CB3=AlOG8KGTlDFcFJ`^Lhwn1Rtr{^}7{5H=$~!tW+;INW zZ1IJSNR##K*01O*EaWrK+haN#b{mzZlha`=5{FPa2J=)XesvQ8yi+h-FHL14nMflQ zfUiOe9kUba_1^A;wU0^RYZGPl-8}Woa*%r#;^`5INkwfaDaO$nhN@KS4TO5_la_Efnh7Ibg*fclG&-cLqgp==H(o ztN}EXx=zHoiVfDSH`8m~s3wirK9gTPX|XhudZ93`kWlyJ3+fTwoz0SUbZ%>MnSjXj zbY1oO(au}Gf#b_T1TXHogc(9>Jw;iQwro92iPNSzhE44X#UX~LuaVmuH^mLurJMF7 zX8IU!{HXe3IHmU;E#}O?6NtSoIw~gHnna^d!tw`$#?6PV6_~5Df84G$olN3&cWjRO zv;k(bQ*c<$#ac*LB@H3rYNb7uP#o3i=W((>)lPlkt~93~y7tm1h#O)`5@zng_bw+M zI$6V&c2zSP!n{T|SwYojegez|EZ=OL=ZNg~E5>D|q*mOOZNmL5?yU=iE-lcxjMZel ztmgd@7ItkcMW=F=@!H_s!h73`mGgo`^fA=2-O&mDkMPUD#}g58 zwPRH10RF*N>f2mK%kACwG~n-rk$Wt*esywj9s36{HAO|fa`?@9flT0!wijgt?n53< znvAtgT1Gxv+ofZSPe`O^edFgD)O@!O=p@>giQ~^iRc&4bY!eqCR-_abKQl*9?Hbc= z$^M(Ao)s>Yw4iY3{*IY+_sP4opgz1uAH=Jnc<3!}pS!F$Cm~IRgT3>ttya5J)9oJG zC698=AiO;8Vzv(wc?{_AdW`?zXI|f9Rf&b?E}Q=zDwRu3-H0pHOz}t-N<12w&E*r- zypMxiFk)mM$@fAB)Z)FmPMd!rKg@nKH6mtCoC_+uKh|Fx*Ve8DBlQ;)b`2B^#>QTR zUpSQeaLAUvVARl+;S(jRICYs4$iVxk^tD0pL>HAp>0wAxrs&pFhC)AKj|EP)AF1&!?KYS+cs>q$PMxAiDS4f!9`RPn+jPD`pVD8s-akr-`Vp^ zOX*V#Yeezp;H&GqMJj5HZNj2*CWR4B6)2IC)2f`w-svdL=qLh<3|#~*IbPK)*lX$s z1uMWVf)uEJrWAV`Tg*i65nKhw?IB8CrrW4Ry*5@4v}N)jR(h9_>8>;_RI1X zDO_mXi1lN?4j#f5vkQX@u|4cp!9v(Mc3GO1AS^qFG0prC)|umupw-i38|A59hf^U^ XR!5LtPj$mzrx>KG^+2;u-6s0)Xsd~t delta 3232 zcmV;R3}5s3CcPz)BLW1kktO@HPyuBE3NchMIXW;iIy5PWt18{7>`Bg=W@503J_a2g1&8`@&2RYqgrI8@hnY^uxAQ7y%#Hoa|_2%VfX|CDlc<3=r|mXcO0X0D~E z4S!Sp`)8m1$O>|4j-urr?0L3v%{Gg1%xp`TXMMTm0g*aQoKl-bMDrDhSyEz= z2Ah;9C42SnFTOa=adHt&@(jU$V= z;fd(ok3Le>cRu{k9-4|v(Rd+j%+_woynhUER2QG@1E4>Ylu!d(er6#NDy2-*_TD{a zCRG;s=FS~03jJdCBxkKZHmk5n?7)VkX$Rs(&&L zGqudawUSxHU|q_;Zr>*0$JrvFz!DchnY?5%XH}n!GEB?8q6V93BIZU@%oaJUYMW$c zPHB7Zo|e)!EFu;{5Wxo}x-vW;>Gv6lg-+r4g97{=l_DvT^GpYlQCQjS(rUGN>#b6X zq~z1(s(j^&Gn>}RIk#kQ<8AKAiGj^L z-~w|CU)9aEYZjVi9GO{iwtt8;^|tr!xv8#Pzdr4DDd)Xgz#)&m{kB;_b$#txohHe- zj$;~zT8b4Q2BGc!`(zL=z1kL`I3lCSfdfMhiVx|4{mqS`!{bgQCh90apYdfF|(vZUgzd4!+-GZ#~;7<$tM;n zl2RImzuvt0-lw1PTr@HbGdC-eYMCbUPAR2ru@oZu=jWfNoDBxGR_f)7nMzVBQ?G=7?2KXN+<)H~$#_IEpWMCcap$2zUg70z!kFmC2M^T96x>^kn?DKmz!gX}=*s0tyu!J}XB`wl^Wrk_A?%fR1alb zJQNE)-D@1w(%Mcn$zx3da_mUcAU> z&OG|=JMp@3vwyL)Ws)s#sKuo!ZMPVs2myQUr3c!Vp+aG1adaBOFtASbOwZPqn6y`# zd9^Czh{apG0)|%{Qy6l^FYT zmMv)K9y=MU?okJwAD8RO1#;(k2hr8bIwy(%#{*PdD>IjIl$0c;_0_AYy1jc>4dQ)= z`{=g{S48aS+*fcPqJdHMgPsX6+e3&T3~;hR3t`#{I92Kju{9}(Sfq@jVsA&amZDZF z*D5(Puz#?dTp?*LsmWawXxg6Szyto%(~3s|_3FsZ>C=lBY-P5A%IpCUVmoB!nUh;D zsEhaXgf>R_qf19rdfN}&5f-bODIb6Two%A2>}re3RAXd1GYhN6Ck^q4^;xUrB< zFkQOdwBV(TJ6@(tzu&u0)yhW4Qlpw$)%wq1SAXe!A@T-MZ?97?+L6>Q zu~Fv|e7I@1N43_zNZIX}Sxc#<*a4t*c>{T4OUBJyD|amEp~6<@brE7_uXo4T%mXfX z`B{O0@{WJ_fv`DeX_d%Je?Q1t|Dutp|FwfML>F>2x&q%~LO?Rzf8ao4gzl1KiJ57; zwSQOIW$c~q-#7q%K{*5o@$9%`#Q~`RA}D(>zQ6Sak8|$X?h<)PLB<_>q{OoSdjZLd2xHkuY@-kzBfD)wMET zdi{0nXKu5Lt){9erT;yA*sz+?UyhDi17@1McjTXTo}8Q@`4aGNZt)=^y{BM(CF25X zc&Ht~?F=rWL{FbSr9;=NufA#nM1+PxhM_|5nk>^1nXai5m$^E>^pdLP-V?CG34i-H z2svlo4xyZ-caQ5d8O@hzawKwZ4K*js(diB`Te!81TZt$QL)q=pFw|PLlzirlebh02 zp`0b9l(RZtPZOts&IGvvwgJ~3iM4&`mX!Yc z@S$7UdDz>U