Robots bootable and movable.

This commit is contained in:
Florian Nücke
2021-01-13 19:58:59 +01:00
parent efa43430b3
commit 3b2dc8cefa
29 changed files with 765 additions and 122 deletions

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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);
}
}

View File

@@ -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<RobotContainer> {
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);
}
}

View File

@@ -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);
}
}

View File

@@ -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<RobotEntity> {
@@ -57,10 +53,10 @@ public final class RobotEntityRenderer extends EntityRenderer<RobotEntity> {
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);
// }
}
///////////////////////////////////////////////////////////////////

View File

@@ -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<ITextComponent> 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) {

View File

@@ -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());
}
}

View File

@@ -15,6 +15,7 @@ public final class Containers {
///////////////////////////////////////////////////////////////////
public static final RegistryObject<ContainerType<ComputerContainer>> COMPUTER_CONTAINER = CONTAINERS.register(Constants.COMPUTER_BLOCK_NAME, () -> IForgeContainerType.create(ComputerContainer::create));
public static final RegistryObject<ContainerType<RobotContainer>> ROBOT_CONTAINER = CONTAINERS.register(Constants.ROBOT_ENTITY_NAME, () -> IForgeContainerType.create(RobotContainer::create));
///////////////////////////////////////////////////////////////////

View File

@@ -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);
}
}

View File

@@ -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<BlockPos> TARGET_POSITION = EntityDataManager.createKey(RobotEntity.class, DataSerializers.BLOCK_POS);
public static final DataParameter<Direction> 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<Boolean> 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<ChunkEvent.Unload> chunkUnloadListener = this::handleChunkUnload;
private final Consumer<WorldEvent.Unload> 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<Collection<LazyOptional<DeviceBusElement>>> getNeighbors() {
return Optional.of(Collections.singleton(LazyOptional.of(() -> items.busElement)));
}
@Override
public Collection<Device> getLocalDevices() {
return Collections.singleton(device);
}
@Override
public Optional<UUID> 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() {
}
}
}

View File

@@ -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<BlockPos> 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 {

View File

@@ -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);
}

View File

@@ -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<Direction> 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

View File

@@ -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);
}

View File

@@ -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())
));

View File

@@ -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 <T> void sendToClientsTrackingChunk(final T message, final Chunk chunk) {

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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<NetworkEvent.Context> 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);
}
}

View File

@@ -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);
}
}
}

View File

@@ -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<IItemHandler> 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);
}
}

View File

@@ -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<IItemHandler> getItemHandler(DeviceType deviceType);
boolean isEmpty();
void exportDeviceDataToItemStacks();
}

View File

@@ -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",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.9 KiB