Send terminal output to client and input back to server.

This commit is contained in:
Florian Nücke
2020-09-30 13:27:32 +02:00
parent cd1d06842d
commit 9275d9562a
17 changed files with 448 additions and 47 deletions

View File

@@ -46,7 +46,10 @@ public final class OpenComputers {
public static final RegistryObject<ContainerType<ComputerContainer>> COMPUTER_CONTAINER = CONTAINERS.register(Constants.COMPUTER_BLOCK_NAME, () -> IForgeContainerType.create((id, inventory, data) -> {
final BlockPos pos = data.readBlockPos();
final TileEntity tileEntity = inventory.player.getEntityWorld().getTileEntity(pos);
return new ComputerContainer(id, tileEntity);
if (!(tileEntity instanceof ComputerTileEntity)) {
return null;
}
return new ComputerContainer(id, (ComputerTileEntity) tileEntity);
}));
public OpenComputers() {

View File

@@ -1,12 +1,12 @@
package li.cil.oc2.client;
import li.cil.oc2.OpenComputers;
import li.cil.oc2.client.gui.ComputerScreen;
import li.cil.oc2.client.gui.ComputerContainerScreen;
import net.minecraft.client.gui.ScreenManager;
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
public final class ClientSetup {
public static void run(final FMLClientSetupEvent event) {
ScreenManager.registerFactory(OpenComputers.COMPUTER_CONTAINER.get(), ComputerScreen::new);
ScreenManager.registerFactory(OpenComputers.COMPUTER_CONTAINER.get(), ComputerContainerScreen::new);
}
}

View File

@@ -10,10 +10,10 @@ import net.minecraft.util.text.ITextComponent;
import java.util.Objects;
public final class ComputerScreen extends ContainerScreen<ComputerContainer> {
public final class ComputerContainerScreen extends ContainerScreen<ComputerContainer> {
private static final ResourceLocation BACKGROUND = new ResourceLocation(API.MOD_ID, "textures/gui/container/computer.png");
public ComputerScreen(final ComputerContainer container, final PlayerInventory inventory, final ITextComponent title) {
public ComputerContainerScreen(final ComputerContainer container, final PlayerInventory inventory, final ITextComponent title) {
super(container, inventory, title);
xSize = 196;
ySize = 197;
@@ -23,19 +23,12 @@ public final class ComputerScreen extends ContainerScreen<ComputerContainer> {
public void render(final int mouseX, final int mouseY, final float partialTicks) {
renderBackground();
super.render(mouseX, mouseY, partialTicks);
RenderSystem.disableBlend();
// TODO Render terminal text.
renderHoveredToolTip(mouseX, mouseY);
}
@Override
protected void drawGuiContainerBackgroundLayer(final float partialTicks, final int mouseX, final int mouseY) {
RenderSystem.color4f(1f, 1f, 1f, 1f);
Objects.requireNonNull(minecraft).getTextureManager().bindTexture(BACKGROUND);
final int x = (width - xSize) / 2;
final int y = (height - ySize) / 2;
blit(x, y, 0, 0, xSize, ySize);
blit(guiLeft, guiTop, 0, 0, xSize, ySize);
}
}

View File

@@ -130,7 +130,7 @@ public final class RISCVTestScreen extends Screen {
return true;
}
} else {
if (keyCode == GLFW.GLFW_KEY_V && (modifiers & GLFW.GLFW_MOD_CONTROL) != 0) {
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0 && keyCode == GLFW.GLFW_KEY_V) {
final String value = Objects.requireNonNull(minecraft).keyboardListener.getClipboardString();
for (final char ch : value.toCharArray()) {
terminal.putInput((byte) ch);

View File

@@ -0,0 +1,123 @@
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.client.gui.terminal.Terminal;
import li.cil.oc2.client.gui.terminal.TerminalInput;
import li.cil.oc2.common.network.ComputerTerminalInputMessage;
import li.cil.oc2.common.network.Network;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.client.gui.screen.Screen;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.ITextComponent;
import org.lwjgl.glfw.GLFW;
import java.nio.ByteBuffer;
import java.util.Objects;
public final class TerminalScreen 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;
private static final int SCREEN_WIDTH = 8 + 80 * 9 / 2 + 8;
private static final int SCREEN_HEIGHT = 8 + 24 * 16 / 2 + 8;
private static final int TERMINAL_AREA_X = 8;
private static final int TERMINAL_AREA_Y = 8;
private static final int TERMINAL_AREA_WIDTH = 80 * 9 / 2;
private static final int TERMINAL_AREA_HEIGHT = 24 * 16 / 2;
private final ComputerTileEntity tileEntity;
private final Terminal terminal;
private final int windowWidth, windowHeight;
private int windowLeft, windowTop;
private boolean isMouseOverTerminal;
public TerminalScreen(final ComputerTileEntity tileEntity, final ITextComponent title) {
super(title);
this.tileEntity = tileEntity;
terminal = tileEntity.getTerminal();
windowWidth = SCREEN_WIDTH;
windowHeight = SCREEN_HEIGHT;
}
@Override
public void render(final int mouseX, final int mouseY, final float partialTicks) {
renderBackground();
isMouseOverTerminal = isPointInRegion(TERMINAL_AREA_X, TERMINAL_AREA_Y, TERMINAL_AREA_WIDTH, TERMINAL_AREA_HEIGHT, mouseX, mouseY);
RenderSystem.color4f(1f, 1f, 1f, 1f);
Objects.requireNonNull(minecraft).getTextureManager().bindTexture(BACKGROUND);
blit(windowLeft, windowTop, 0, 0, windowWidth, windowHeight, TEXTURE_SIZE, TEXTURE_SIZE);
if (isMouseOverTerminal) {
Objects.requireNonNull(minecraft).getTextureManager().bindTexture(BACKGROUND_TERMINAL_FOCUSED);
blit(windowLeft, windowTop, 0, 0, windowWidth, windowHeight, TEXTURE_SIZE, TEXTURE_SIZE);
}
super.render(mouseX, mouseY, partialTicks);
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);
}
@Override
public void tick() {
super.tick();
final ByteBuffer input = terminal.getInput();
if (input != null) {
Network.INSTANCE.sendToServer(new ComputerTerminalInputMessage(tileEntity, input));
}
}
@Override
public boolean isPauseScreen() {
return false;
}
@Override
public boolean charTyped(final char ch, final int modifier) {
terminal.putInput((byte) ch);
return true;
}
@Override
public boolean keyPressed(final int keyCode, final int scanCode, final int modifiers) {
if (!isMouseOverTerminal && keyCode == GLFW.GLFW_KEY_ESCAPE) {
return super.keyPressed(keyCode, scanCode, modifiers);
}
if ((modifiers & GLFW.GLFW_MOD_CONTROL) != 0 && keyCode == GLFW.GLFW_KEY_V) {
final String value = Objects.requireNonNull(minecraft).keyboardListener.getClipboardString();
for (final char ch : value.toCharArray()) {
terminal.putInput((byte) ch);
}
return true;
}
if (TerminalInput.KEYCODE_SEQUENCES.containsKey(keyCode)) {
final byte[] sequence = TerminalInput.KEYCODE_SEQUENCES.get(keyCode);
for (int i = 0; i < sequence.length; i++) {
terminal.putInput(sequence[i]);
}
return true;
}
return false;
}
protected void init() {
super.init();
this.windowLeft = (this.width - this.windowWidth) / 2;
this.windowTop = (this.height - this.windowHeight) / 2;
}
private boolean isPointInRegion(int x, int y, int width, int height, double mouseX, double mouseY) {
mouseX = mouseX - this.windowLeft;
mouseY = mouseY - this.windowTop;
return mouseX >= x && mouseX < x + width && mouseY >= y && mouseY < y + height;
}
}

View File

@@ -13,16 +13,21 @@ import net.minecraft.client.renderer.Matrix4f;
import net.minecraft.client.renderer.Tessellator;
import net.minecraft.client.renderer.WorldVertexBufferUploader;
import net.minecraft.client.renderer.vertex.DefaultVertexFormats;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.state.properties.NoteBlockInstrument;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import org.lwjgl.opengl.GL11;
import javax.annotation.Nullable;
import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.concurrent.atomic.AtomicInteger;
// Implements a couple of control sequences from here: https://en.wikipedia.org/wiki/ANSI_escape_code#CSI_sequences
public final class Terminal {
private static final int TAB_WIDTH = 4;
private static final int WIDTH = 80, HEIGHT = 25;
private static final int WIDTH = 80, HEIGHT = 24;
private enum State {
NORMAL, // Currently reading characters normally.
@@ -31,7 +36,7 @@ public final class Terminal {
}
private final ByteArrayFIFOQueue input = new ByteArrayFIFOQueue(32);
private final char[] buffer = new char[WIDTH * HEIGHT];
private final byte[] buffer = new byte[WIDTH * HEIGHT];
private State state = State.NORMAL;
private final int[] args = new int[4];
private int argCount = 0;
@@ -42,7 +47,7 @@ public final class Terminal {
private final AtomicInteger dirty = new AtomicInteger(-1);
public Terminal() {
Arrays.fill(buffer, ' ');
clear();
}
public int getWidth() {
@@ -53,6 +58,7 @@ public final class Terminal {
return HEIGHT * MonospaceFontRenderer.INSTANCE.getCharHeight();
}
@OnlyIn(Dist.CLIENT)
public void render(final MatrixStack stack) {
final FontRenderer fontRenderer = MonospaceFontRenderer.INSTANCE;
@@ -70,6 +76,53 @@ public final class Terminal {
}
}
public CompoundNBT serialize(final boolean forClient) {
final CompoundNBT nbt = new CompoundNBT();
if (!forClient) {
// todo serialize input
}
nbt.putByteArray("buffer", buffer);
nbt.putByte("state", (byte) state.ordinal());
nbt.putIntArray("args", args);
nbt.putInt("argCount", argCount);
nbt.putInt("x", x);
nbt.putInt("y", y);
nbt.putInt("savedX", savedX);
nbt.putInt("savedY", savedY);
return nbt;
}
public void deserialize(final CompoundNBT nbt) {
if (nbt.contains("input")) {
// todo deserialize input
}
final byte[] buffer = nbt.getByteArray("buffer");
if (buffer.length == this.buffer.length) {
System.arraycopy(buffer, 0, this.buffer, 0, buffer.length);
}
final byte state = nbt.getByte("state");
final State[] states = State.values();
if (state >= 0 && state < states.length) {
this.state = states[state];
}
final int[] args = nbt.getIntArray("args");
if (args.length == this.args.length) {
System.arraycopy(args, 0, this.args, 0, args.length);
}
argCount = nbt.getInt("argCount");
x = nbt.getInt("x");
y = nbt.getInt("y");
savedX = nbt.getInt("savedX");
savedY = nbt.getInt("savedY");
}
public synchronized int readInput() {
if (input.isEmpty()) {
return -1;
@@ -78,6 +131,32 @@ public final class Terminal {
}
}
@Nullable
public synchronized ByteBuffer getInput() {
if (input.isEmpty()) {
return null;
} else {
final ByteBuffer buffer = ByteBuffer.allocate(input.size());
while (!input.isEmpty()) {
buffer.put(input.dequeueByte());
}
buffer.flip();
return buffer;
}
}
public synchronized void putInput(final ByteBuffer values) {
while (values.hasRemaining()) {
input.enqueue(values.get());
}
}
public synchronized void putOutput(final ByteBuffer values) {
while (values.hasRemaining()) {
putOutput(values.get());
}
}
public synchronized void putInput(final byte value) {
input.enqueue(value);
}
@@ -243,7 +322,12 @@ public final class Terminal {
}
}
@OnlyIn(Dist.CLIENT)
private void renderCursor(final MatrixStack stack) {
if (x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
return;
}
final FontRenderer fontRenderer = MonospaceFontRenderer.INSTANCE;
GlStateManager.depthMask(false);
@@ -282,7 +366,7 @@ public final class Terminal {
}
setChar(x, y, ch);
setCursorPos(x + 1, y);
x++;
}
private void setChar(final int x, final int y, final char ch) {
@@ -290,12 +374,12 @@ public final class Terminal {
return;
}
buffer[x + y * WIDTH] = ch;
buffer[x + y * WIDTH] = (byte) ch;
dirty.accumulateAndGet(1 << y, (prev, next) -> prev | next);
}
private void clear() {
Arrays.fill(buffer, ' ');
Arrays.fill(buffer, (byte) ' ');
dirty.set((1 << HEIGHT) - 1);
}
@@ -304,7 +388,7 @@ public final class Terminal {
}
private void clearLine(final int y, final int fromIndex, final int toIndex) {
Arrays.fill(buffer, y * WIDTH + fromIndex, y * WIDTH + toIndex, ' ');
Arrays.fill(buffer, y * WIDTH + fromIndex, y * WIDTH + toIndex, (byte) ' ');
dirty.accumulateAndGet(1 << y, (prev, next) -> prev | next);
}
@@ -319,7 +403,7 @@ public final class Terminal {
private void shiftUpOne() {
System.arraycopy(buffer, WIDTH, buffer, 0, buffer.length - WIDTH);
System.arraycopy(lines, 1, lines, 0, lines.length - 1);
Arrays.fill(buffer, WIDTH * HEIGHT - WIDTH, WIDTH * HEIGHT, ' ');
Arrays.fill(buffer, WIDTH * HEIGHT - WIDTH, WIDTH * HEIGHT, (byte) ' ');
// Shift all dirty down one because we moved rows up one (up = lower indices).
// Mark bottom-most line (highest index) as dirty.

View File

@@ -1,9 +1,10 @@
package li.cil.oc2.common;
import li.cil.oc2.common.network.Network;
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
public final class CommonSetup {
public static void run(final FMLCommonSetupEvent event) {
Network.setup();
}
}

View File

@@ -1,12 +1,14 @@
package li.cil.oc2.common.block;
import li.cil.oc2.OpenComputers;
import li.cil.oc2.client.gui.TerminalScreen;
import li.cil.oc2.common.container.ComputerContainer;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.SoundType;
import net.minecraft.block.material.Material;
import net.minecraft.client.Minecraft;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.entity.player.PlayerInventory;
import net.minecraft.entity.player.ServerPlayerEntity;
@@ -18,7 +20,6 @@ import net.minecraft.util.Hand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.BlockRayTraceResult;
import net.minecraft.util.text.ITextComponent;
import net.minecraft.util.text.TranslationTextComponent;
import net.minecraft.world.IBlockReader;
import net.minecraft.world.World;
import net.minecraftforge.fml.network.NetworkHooks;
@@ -44,28 +45,53 @@ public final class ComputerBlock extends Block {
@SuppressWarnings("deprecation")
@Override
public ActionResultType onBlockActivated(final BlockState state, final World world, final BlockPos pos, final PlayerEntity player, final Hand hand, final BlockRayTraceResult hit) {
if (!world.isRemote()) {
if (!(player instanceof ServerPlayerEntity)) {
throw new IllegalArgumentException();
}
final TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof ComputerTileEntity)) {
throw new IllegalStateException();
}
final TileEntity tileEntity = world.getTileEntity(pos);
if (!(tileEntity instanceof ComputerTileEntity)) {
throw new IllegalStateException();
}
NetworkHooks.openGui((ServerPlayerEntity) player, new INamedContainerProvider() {
@Override
public ITextComponent getDisplayName() {
return new TranslationTextComponent("blah");
final ComputerTileEntity computer = (ComputerTileEntity) tileEntity;
if (player.isSneaking()) {
if (!world.isRemote()) {
if (computer.isRunning()) {
return ActionResultType.CONSUME;
} else {
computer.start();
}
@Override
public Container createMenu(final int id, final PlayerInventory inventory, final PlayerEntity player) {
return new ComputerContainer(id, tileEntity);
}
} else {
final boolean openContainer = false; // TODO
if (openContainer) {
if (!world.isRemote()) {
if (!(player instanceof ServerPlayerEntity)) {
throw new IllegalArgumentException();
}
openContainerScreen(tileEntity, (ServerPlayerEntity) player);
}
}, tileEntity.getPos());
} else {
if (world.isRemote()) {
openTerminalScreen(computer);
}
}
}
return ActionResultType.SUCCESS;
}
private void openContainerScreen(final TileEntity tileEntity, final ServerPlayerEntity player) {
NetworkHooks.openGui(player, new INamedContainerProvider() {
@Override
public ITextComponent getDisplayName() {
return getNameTextComponent();
}
@Override
public Container createMenu(final int id, final PlayerInventory inventory, final PlayerEntity player) {
return new ComputerContainer(id, (ComputerTileEntity) tileEntity);
}
}, tileEntity.getPos());
}
private void openTerminalScreen(final ComputerTileEntity computer) {
Minecraft.getInstance().displayGuiScreen(new TerminalScreen(computer, getNameTextComponent()));
}
}

View File

@@ -1,18 +1,18 @@
package li.cil.oc2.common.container;
import li.cil.oc2.OpenComputers;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.container.Container;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.IWorldPosCallable;
import net.minecraft.world.World;
import javax.annotation.Nullable;
public final class ComputerContainer extends Container {
private final TileEntity tileEntity;
private final ComputerTileEntity tileEntity;
public ComputerContainer(final int id, @Nullable final TileEntity tileEntity) {
public ComputerContainer(final int id, @Nullable final ComputerTileEntity tileEntity) {
super(OpenComputers.COMPUTER_CONTAINER.get(), id);
this.tileEntity = tileEntity;
}

View File

@@ -0,0 +1,31 @@
package li.cil.oc2.common.network;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.util.math.BlockPos;
import java.nio.ByteBuffer;
public abstract class AbstractComputerTerminalMessage {
protected BlockPos pos;
protected byte[] data;
public AbstractComputerTerminalMessage(final ComputerTileEntity tileEntity, final ByteBuffer data) {
this.pos = tileEntity.getPos();
this.data = data.array();
}
public AbstractComputerTerminalMessage(final PacketBuffer buffer) {
fromBytes(buffer);
}
public void fromBytes(final PacketBuffer buffer) {
pos = buffer.readBlockPos();
data = buffer.readByteArray();
}
public static void toBytes(final AbstractComputerTerminalMessage message, final PacketBuffer buffer) {
buffer.writeBlockPos(message.pos);
buffer.writeByteArray(message.data);
}
}

View File

@@ -0,0 +1,34 @@
package li.cil.oc2.common.network;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.entity.player.ServerPlayerEntity;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.server.ServerWorld;
import net.minecraftforge.fml.network.NetworkEvent;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
public final class ComputerTerminalInputMessage extends AbstractComputerTerminalMessage {
public ComputerTerminalInputMessage(final ComputerTileEntity tileEntity, final ByteBuffer data) {
super(tileEntity, data);
}
public ComputerTerminalInputMessage(final PacketBuffer buffer) {
super(buffer);
}
public static boolean handleInput(final AbstractComputerTerminalMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> {
final ServerPlayerEntity player = context.get().getSender();
if (player == null) return;
final ServerWorld world = player.getServerWorld();
// TODO Check if chunk is loaded first.
final TileEntity tileEntity = world.getTileEntity(message.pos);
if (!(tileEntity instanceof ComputerTileEntity)) return;
((ComputerTileEntity) tileEntity).getTerminal().putInput(ByteBuffer.wrap(message.data));
});
return true;
}
}

View File

@@ -0,0 +1,32 @@
package li.cil.oc2.common.network;
import li.cil.oc2.common.tile.ComputerTileEntity;
import net.minecraft.client.Minecraft;
import net.minecraft.client.world.ClientWorld;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraftforge.fml.network.NetworkEvent;
import java.nio.ByteBuffer;
import java.util.function.Supplier;
public final class ComputerTerminalOutputMessage extends AbstractComputerTerminalMessage {
public ComputerTerminalOutputMessage(final ComputerTileEntity tileEntity, final ByteBuffer data) {
super(tileEntity, data);
}
public ComputerTerminalOutputMessage(final PacketBuffer buffer) {
super(buffer);
}
public static boolean handleOutput(final AbstractComputerTerminalMessage message, final Supplier<NetworkEvent.Context> context) {
context.get().enqueueWork(() -> {
final ClientWorld world = Minecraft.getInstance().world;
if (world == null) return;
final TileEntity tileEntity = world.getTileEntity(message.pos);
if (!(tileEntity instanceof ComputerTileEntity)) return;
((ComputerTileEntity) tileEntity).getTerminal().putOutput(ByteBuffer.wrap(message.data));
});
return true;
}
}

View File

@@ -1,4 +1,37 @@
package li.cil.oc2.common.network;
import li.cil.oc2.api.API;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.network.NetworkDirection;
import net.minecraftforge.fml.network.NetworkRegistry;
import net.minecraftforge.fml.network.simple.SimpleChannel;
public final class Network {
private static final String PROTOCOL_VERSION = "1";
private static int nextPacketId = 1;
public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(
new ResourceLocation(API.MOD_ID, "main"),
() -> PROTOCOL_VERSION,
PROTOCOL_VERSION::equals,
PROTOCOL_VERSION::equals
);
public static void setup() {
INSTANCE.messageBuilder(ComputerTerminalOutputMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_CLIENT)
.encoder(ComputerTerminalOutputMessage::toBytes)
.decoder(ComputerTerminalOutputMessage::new)
.consumer(ComputerTerminalOutputMessage::handleOutput)
.add();
INSTANCE.messageBuilder(ComputerTerminalInputMessage.class, getNextPacketId(), NetworkDirection.PLAY_TO_SERVER)
.encoder(ComputerTerminalInputMessage::toBytes)
.decoder(ComputerTerminalInputMessage::new)
.consumer(ComputerTerminalInputMessage::handleInput)
.add();
}
private static int getNextPacketId() {
return nextPacketId++;
}
}

View File

@@ -3,6 +3,8 @@ package li.cil.oc2.common.tile;
import it.unimi.dsi.fastutil.bytes.ByteArrayFIFOQueue;
import li.cil.oc2.OpenComputers;
import li.cil.oc2.client.gui.terminal.Terminal;
import li.cil.oc2.common.network.ComputerTerminalOutputMessage;
import li.cil.oc2.common.network.Network;
import li.cil.oc2.common.vm.VirtualMachineRunner;
import li.cil.sedna.api.Sizes;
import li.cil.sedna.api.device.PhysicalMemory;
@@ -15,16 +17,21 @@ import li.cil.sedna.riscv.R5Board;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.tileentity.ITickableTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.chunk.Chunk;
import net.minecraftforge.fml.network.PacketDistributor;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.BufferedInputStream;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.Objects;
public final class ComputerTileEntity extends TileEntity implements ITickableTileEntity {
private static final Logger LOGGER = LogManager.getLogger();
private final Terminal terminal = new Terminal();
private Chunk chunk;
private VirtualMachineRunner runner;
private R5Board board;
@@ -37,6 +44,10 @@ public final class ComputerTileEntity extends TileEntity implements ITickableTil
super(OpenComputers.COMPUTER_TILE_ENTITY.get());
}
public Terminal getTerminal() {
return terminal;
}
public void start() {
startVirtualMachine();
}
@@ -45,12 +56,20 @@ public final class ComputerTileEntity extends TileEntity implements ITickableTil
stopVirtualMachine();
}
public boolean isRunning() {
return runner != null;
}
@Override
public void tick() {
if (world == null || world.isRemote()) {
return;
}
if (chunk == null) {
chunk = Objects.requireNonNull(getWorld()).getChunkAt(getPos());
}
if (runner != null) {
runner.tick();
}
@@ -64,9 +83,23 @@ public final class ComputerTileEntity extends TileEntity implements ITickableTil
@Override
public void onChunkUnloaded() {
super.onChunkUnloaded();
stopVirtualMachine();
}
@Override
public CompoundNBT getUpdateTag() {
final CompoundNBT result = super.getUpdateTag();
result.put("terminal", terminal.serialize(true));
return result;
}
@Override
public void handleUpdateTag(final CompoundNBT tag) {
super.handleUpdateTag(tag);
terminal.deserialize(tag.getCompound("terminal"));
}
@Override
public void read(final CompoundNBT compound) {
super.read(compound);
@@ -78,7 +111,7 @@ public final class ComputerTileEntity extends TileEntity implements ITickableTil
public CompoundNBT write(final CompoundNBT compound) {
final CompoundNBT result = super.write(compound);
joinVirtualMachine();
// todo serialize VM
// TODO serialize VM
return result;
}
@@ -172,9 +205,17 @@ public final class ComputerTileEntity extends TileEntity implements ITickableTil
@Override
protected void handleAfterRun() {
final ByteBuffer output = ByteBuffer.allocate(outputBuffer.size());
while (!outputBuffer.isEmpty()) {
terminal.putOutput(outputBuffer.dequeueByte());
output.put(outputBuffer.dequeueByte());
}
output.flip();
terminal.putOutput(output);
output.flip();
final ComputerTerminalOutputMessage message = new ComputerTerminalOutputMessage(ComputerTileEntity.this, output);
Network.INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), message);
}
}
}

View File

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB