Send terminal output to client and input back to server.
This commit is contained in:
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
123
src/main/java/li/cil/oc2/client/gui/TerminalScreen.java
Normal file
123
src/main/java/li/cil/oc2/client/gui/TerminalScreen.java
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
BIN
src/main/resources/assets/oc2/textures/gui/screen/terminal.png
Normal file
BIN
src/main/resources/assets/oc2/textures/gui/screen/terminal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.4 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
Reference in New Issue
Block a user