diff --git a/src/main/java/net/brokenmoon/redcontrol/api/RCBus.java b/src/main/java/net/brokenmoon/redcontrol/api/RCBus.java index d1ba666..aa29fa9 100644 --- a/src/main/java/net/brokenmoon/redcontrol/api/RCBus.java +++ b/src/main/java/net/brokenmoon/redcontrol/api/RCBus.java @@ -8,35 +8,38 @@ import net.minecraft.world.World; public class RCBus { - boolean isValid = false; + private boolean isValid = false; private RedBus redBus; - Peripheral[] peripherals = new Peripheral[256]; public RCBus(RedBus redBus) { this.redBus = redBus; } public void write(int address, int data, World world, BlockPos pos) { if(isValid) { - Peripheral peripheral = peripherals[address]; - peripheral.getBus().getRedBus().write(address, data); + getRedBus().write(address, data); } else { - generateBus(world, pos); - write(address, data, world, pos); + generateBusWithWrite(address, data, world, pos); } } + private void generateBusWithWrite(int address, int data, World world, BlockPos pos) { + ((NetworkCarrier)(world.getBlockState(pos).getBlock())).generateBusWithWrite(world, pos, address, data); + } + public int read(int address, boolean cpuAccess, World world, BlockPos pos) { if(isValid) { - Peripheral peripheral = peripherals[address]; - return peripheral.getBus().getRedBus().read(address, cpuAccess) & 0xff; + return getRedBus().read(address, cpuAccess) & 0xff; } else { - generateBus(world, pos); - return read(address, cpuAccess, world, pos); + return generateBusWithRead(address, cpuAccess, world, pos); } } + private int generateBusWithRead(int address, boolean cpuAccess, World world, BlockPos pos) { + return ((NetworkCarrier)(world.getBlockState(pos).getBlock())).generateBusWithRead(world, pos, address, cpuAccess); + } + public void generateBus(World world, BlockPos pos){ ((NetworkCarrier)(world.getBlockState(pos).getBlock())).generateBus(world, pos); } @@ -53,11 +56,11 @@ public class RCBus { this.redBus.updatePeripheral(); } - public Peripheral[] getPeripherals(){ - return peripherals; + public boolean getValid(){ + return this.isValid; } - public void setPeripherals(Peripheral[] peripherals){ - this.peripherals = peripherals; + public void setValid(boolean validity){ + this.isValid = validity; } } diff --git a/src/main/java/net/brokenmoon/redcontrol/blockentities/CpuEntity.java b/src/main/java/net/brokenmoon/redcontrol/blockentities/CpuEntity.java index 714ceee..7af514c 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blockentities/CpuEntity.java +++ b/src/main/java/net/brokenmoon/redcontrol/blockentities/CpuEntity.java @@ -9,11 +9,14 @@ import net.brokenmoon.redcontrol.api.RCCpu; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BrewingStandBlockEntity; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Date; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.Semaphore; @@ -31,7 +34,7 @@ public class CpuEntity extends Peripheral implements Runnable{ }; static Timer timer = new Timer(); - + boolean notTicked = true; private boolean running = false; private Semaphore waiInterrupt = new Semaphore(2); private final RCCpu cpu; @@ -58,9 +61,22 @@ public class CpuEntity extends Peripheral implements Runnable{ throw new RuntimeException(e); } cpu.getBus().addDevice(ram); - reset(); + + } + + public static void tick(World world, BlockPos pos, BlockState state, CpuEntity be) { + if(be.notTicked) { + be.reset(); + be.notTicked = false; + be.start(); + } } + public void start(){ + timer.schedule(cpuTask, new Date(), 2L); + } + + public RCBus getRCBus(){ return this.rcbus; } @@ -90,12 +106,6 @@ public class CpuEntity extends Peripheral implements Runnable{ this.defaultMonitorId = id; } - public void signal() { - if (this.waiInterrupt.availablePermits() < 2) { - this.waiInterrupt.release(); - } - } - public boolean isRunning() { return this.running; } @@ -119,8 +129,8 @@ public class CpuEntity extends Peripheral implements Runnable{ public void reset() { stop(); this.cpu.reset(); - this.getRCBus().write(0, this.defaultDriveId, this.getWorld(), this.getPos()); - this.getRCBus().write(1, this.defaultMonitorId, this.getWorld(), this.getPos()); + this.getRCBus().write(0, this.defaultDriveId, getWorld(), this.getPos()); + this.getRCBus().write(1, this.defaultMonitorId, getWorld(), this.getPos()); } public void step() { @@ -140,4 +150,18 @@ public class CpuEntity extends Peripheral implements Runnable{ } } + @Override + public void write(int address, int data) { + + } + + @Override + public int read(int address) { + return 0; + } + + @Override + public void update() { + + } } diff --git a/src/main/java/net/brokenmoon/redcontrol/blockentities/MonitorEntity.java b/src/main/java/net/brokenmoon/redcontrol/blockentities/MonitorEntity.java index 27e9198..5e3b4e1 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blockentities/MonitorEntity.java +++ b/src/main/java/net/brokenmoon/redcontrol/blockentities/MonitorEntity.java @@ -2,11 +2,194 @@ package net.brokenmoon.redcontrol.blockentities; import net.brokenmoon.redcontrol.RedControl; import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; import net.minecraft.util.math.BlockPos; public class MonitorEntity extends Peripheral { + + public static final int WIDTH = 80; + public static final int HEIGHT = 50; + + private int accessRow; + private int cursorX; + private int cursorY; + private int cursorMode = 2; // (0: hidden, 1: solid, 2: blink) + private int keyBufferStart; + private int keyBufferPos; + private int blitMode; // (1: fill, 2: invert; 3: shift) + private int blitXStartOrFill; + private int blitYStart; + private int blitXOffset; + private int blitYOffset; + private int blitWidth; + private int blitHeight; + + private byte[] keyBuffer = new byte[0x10]; + private byte[][] windowData = new byte[HEIGHT][WIDTH]; + + private boolean isDisplayDirty; + private boolean isCursorDirty; + public MonitorEntity(BlockPos pos, BlockState state) { super(RedControl.MONITOR_BLOCK_ENTITY, pos, state, 1); } + + @Override + public void write(int address, int data) { + switch (address) { + case 0x00: + this.accessRow = data; + break; + case 0x01: + this.isCursorDirty = this.cursorX != data; + this.cursorX = data; + break; + case 0x02: + this.isCursorDirty = this.cursorY != data; + this.cursorY = data; + break; + case 0x03: + this.isCursorDirty = this.cursorMode != data; + this.cursorMode = data; + break; + case 0x04: + this.keyBufferStart = data & 0x0f; + break; + case 0x05: + this.keyBufferPos = data & 0x0f; + break; + case 0x06: + break; + case 0x07: + this.blitMode = data; + break; + case 0x08: + this.blitXStartOrFill = data; + break; + case 0x09: + this.blitYStart = data; + break; + case 0x0A: + this.blitXOffset = data; + break; + case 0x0B: + this.blitYOffset = data; + break; + case 0x0C: + this.blitWidth = data; + break; + case 0x0D: + this.blitHeight = data; + break; + default: + if (address >= 0x10 && address < 0x60) { + this.isDisplayDirty = true; + this.windowData[this.accessRow][address - 0x10] = (byte) data; + } + } + } + + @Override + public int read(int address) { + switch (address) { + case 0x00: + return this.accessRow; + case 0x01: + return this.cursorX; + case 0x02: + return this.cursorY; + case 0x03: + return this.cursorMode; + case 0x04: + return this.keyBufferStart; + case 0x05: + return this.keyBufferPos; + case 0x06: + return this.keyBuffer[this.keyBufferStart] & 0xff; + case 0x07: + return this.blitMode; + case 0x08: + return this.blitXStartOrFill; + case 0x09: + return this.blitYStart; + case 0x0A: + return this.blitXOffset; + case 0x0B: + return this.blitYOffset; + case 0x0C: + return this.blitWidth; + case 0x0D: + return this.blitHeight; + default: + if (address >= 0x10 && address < 0x60) { + return this.windowData[this.accessRow][address - 0x10] & 0xff; + } + return 0; + } + } + + @Override + public void update() { + int maxWidth = Math.min(WIDTH, this.blitWidth + this.blitXOffset); + int maxHeight = Math.min(HEIGHT, this.blitHeight + this.blitYOffset); + + int row = this.blitYOffset; + int col; + + this.isDisplayDirty |= this.blitMode != 0; + + switch (this.blitMode) { + case 1: // fill + for (; row < maxHeight; row++) { + for (col = this.blitXOffset; col < maxWidth; col++) { + this.windowData[row][col] = (byte) this.blitXStartOrFill; + } + } + break; + case 2: // invert + for (; row < maxHeight; row++) { + for (col = this.blitXOffset; col < maxWidth; col++) { + this.windowData[row][col] ^= 0x80; + } + } + break; + case 3: // shift + int shiftX = this.blitXStartOrFill - this.blitXOffset; + int shiftY = this.blitYStart - this.blitYOffset; + for (; row < maxHeight; row++) { + int srcRow = row + shiftY; + if (srcRow >= 0 & srcRow < HEIGHT) { + for (col = this.blitXOffset; col < maxWidth; col++) { + int srcCol = col + shiftX; + if (srcCol >= 0 && srcCol < WIDTH) { + this.windowData[row][col] = this.windowData[srcRow][srcCol]; + } + } + } + } + break; + } + + this.blitMode = 0; + + if (this.isCursorDirty) { + this.isCursorDirty = false; + this.updateCursor(this.cursorX, this.cursorY, this.cursorMode); + } + } + + private void updateCursor(int cursorX, int cursorY, int cursorMode) { + } + + /** + * Appends a key code to the key buffer. + * + * @param key The key code + */ + public void onKey(byte key) { + int nextPos = (this.keyBufferPos + 1) & 0x0f; + if (nextPos != this.keyBufferStart) { + this.keyBuffer[this.keyBufferPos] = key; + this.keyBufferPos = nextPos; + } + } } diff --git a/src/main/java/net/brokenmoon/redcontrol/blockentities/Peripheral.java b/src/main/java/net/brokenmoon/redcontrol/blockentities/Peripheral.java index 13b429f..0ca4909 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blockentities/Peripheral.java +++ b/src/main/java/net/brokenmoon/redcontrol/blockentities/Peripheral.java @@ -8,7 +8,7 @@ import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntityType; import net.minecraft.util.math.BlockPos; -public abstract class Peripheral extends BlockEntity { +public abstract class Peripheral extends BlockEntity implements RedBus.Peripheral { private RCBus bus; @@ -34,4 +34,8 @@ public abstract class Peripheral extends BlockEntity { public void setId(int id) { this.id = id; } + + public void onJoinBus() { + bus.getRedBus().setPeripheral(this.id, this); + } } diff --git a/src/main/java/net/brokenmoon/redcontrol/blocks/CpuBlock.java b/src/main/java/net/brokenmoon/redcontrol/blocks/CpuBlock.java index 6936cff..c1a1b58 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blocks/CpuBlock.java +++ b/src/main/java/net/brokenmoon/redcontrol/blocks/CpuBlock.java @@ -1,11 +1,15 @@ package net.brokenmoon.redcontrol.blocks; +import com.mojang.serialization.MapCodec; +import com.simon816.j65el02.Cpu; +import net.brokenmoon.redcontrol.RedControl; import net.brokenmoon.redcontrol.blockentities.CpuEntity; -import net.minecraft.block.Block; -import net.minecraft.block.BlockEntityProvider; -import net.minecraft.block.BlockState; +import net.minecraft.block.*; import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityTicker; +import net.minecraft.block.entity.BlockEntityType; import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; public class CpuBlock extends NetworkCarrier { @@ -13,9 +17,26 @@ public class CpuBlock extends NetworkCarrier { super(settings); } + @Override + protected MapCodec getCodec() { + return null; + } + @Nullable @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { return new CpuEntity(pos, state); } + + @Override + public BlockRenderType getRenderType(BlockState state) { + // With inheriting from BlockWithEntity this defaults to INVISIBLE, so we need to change that! + return BlockRenderType.MODEL; + } + + @Override + public BlockEntityTicker getTicker(World world, BlockState state, BlockEntityType type) { + return validateTicker(type, RedControl.CPU_BLOCK_ENTITY, (world1, pos, state1, be) -> CpuEntity.tick(world1, pos, state1, be)); + } + } diff --git a/src/main/java/net/brokenmoon/redcontrol/blocks/MonitorBlock.java b/src/main/java/net/brokenmoon/redcontrol/blocks/MonitorBlock.java index cde3ec0..ef16d4f 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blocks/MonitorBlock.java +++ b/src/main/java/net/brokenmoon/redcontrol/blocks/MonitorBlock.java @@ -1,9 +1,11 @@ package net.brokenmoon.redcontrol.blocks; +import com.mojang.serialization.MapCodec; import net.brokenmoon.redcontrol.blockentities.MonitorEntity; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; +import net.minecraft.block.BlockWithEntity; import net.minecraft.block.entity.BlockEntity; import net.minecraft.util.math.BlockPos; import org.jetbrains.annotations.Nullable; @@ -13,6 +15,11 @@ public class MonitorBlock extends NetworkCarrier { super(settings); } + @Override + protected MapCodec getCodec() { + return null; + } + @Nullable @Override public BlockEntity createBlockEntity(BlockPos pos, BlockState state) { diff --git a/src/main/java/net/brokenmoon/redcontrol/blocks/NetworkCarrier.java b/src/main/java/net/brokenmoon/redcontrol/blocks/NetworkCarrier.java index 8a5e2f0..1597c77 100644 --- a/src/main/java/net/brokenmoon/redcontrol/blocks/NetworkCarrier.java +++ b/src/main/java/net/brokenmoon/redcontrol/blocks/NetworkCarrier.java @@ -6,14 +6,14 @@ import net.brokenmoon.redcontrol.blockentities.Peripheral; import net.minecraft.block.Block; import net.minecraft.block.BlockEntityProvider; import net.minecraft.block.BlockState; -import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.BlockWithEntity; import net.minecraft.entity.LivingEntity; import net.minecraft.item.ItemStack; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; -public abstract class NetworkCarrier extends Block implements BlockEntityProvider { +public abstract class NetworkCarrier extends BlockWithEntity implements BlockEntityProvider { public NetworkCarrier(Settings settings) { super(settings); } @@ -46,9 +46,48 @@ public abstract class NetworkCarrier extends Block implements BlockEntityProvide Block worldBlock = world.getBlockState(pos).getBlock(); if(world.getBlockEntity(pos) instanceof Peripheral){ Peripheral entityBlock = (Peripheral) world.getBlockEntity(pos); - entityBlock.getBus().setPeripherals(new Peripheral[255]); - entityBlock.getBus().getPeripherals()[entityBlock.getId()] = entityBlock; + if(entityBlock.getBus() == null) + entityBlock.setBus(new RCBus(new RedBus())); + entityBlock.getBus().getRedBus().setPeripheral(entityBlock.getId(), entityBlock); + entityBlock.getBus().setValid(true); + floodBus(entityBlock.getBus(), world, pos); } } + + private void floodBus(RCBus bus, World world, BlockPos pos) { + replaceBus(bus, world, pos.north()); + replaceBus(bus, world, pos.south()); + replaceBus(bus, world, pos.east()); + replaceBus(bus, world, pos.west()); + replaceBus(bus, world, pos.up()); + replaceBus(bus, world, pos.down()); + } + + private void replaceBus(RCBus bus, World world, BlockPos pos) { + if(world.getBlockEntity(pos) instanceof Peripheral && ((Peripheral) world.getBlockEntity(pos)).getBus() != bus){ + ((Peripheral) world.getBlockEntity(pos)).setBus(bus); + ((Peripheral) world.getBlockEntity(pos)).onJoinBus(); + floodBus(bus, world, pos); + } + } + + public void generateBusWithWrite(World world, BlockPos pos, int address, int data) { + if(world.getBlockEntity(pos) instanceof Peripheral){ + Peripheral entityBlock = (Peripheral) world.getBlockEntity(pos); + generateBus(world,pos); + floodBus(entityBlock.getBus(), world, pos); + entityBlock.getBus().write(address, data, world, pos); + } + } + + public int generateBusWithRead(World world, BlockPos pos, int address, boolean cpuAccess) { + if(world.getBlockEntity(pos) instanceof Peripheral){ + Peripheral entityBlock = (Peripheral) world.getBlockEntity(pos); + generateBus(world,pos); + floodBus(entityBlock.getBus(), world, pos); + return entityBlock.getBus().read(address, cpuAccess, world, pos); + } + return 0; + } } diff --git a/src/main/java/net/brokenmoon/redcontrol/driver/MonitorBlockDriver.java b/src/main/java/net/brokenmoon/redcontrol/driver/MonitorBlockDriver.java deleted file mode 100644 index 5f61b1c..0000000 --- a/src/main/java/net/brokenmoon/redcontrol/driver/MonitorBlockDriver.java +++ /dev/null @@ -1,25 +0,0 @@ -package net.brokenmoon.redcontrol.driver; - -import com.simon816.j65el02.device.RPMonitor; - -public class MonitorBlockDriver implements RCMonitorDriver{ - @Override - public void setMonitor(RPMonitor monitor) { - - } - - @Override - public void setMonitor(RCMonitor monitor) { - - } - - @Override - public void updateCursor(int cursorX, int cursorY, int cursorMode) { - - } - - @Override - public void update(byte[][] windowData) { - - } -} diff --git a/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitor.java b/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitor.java deleted file mode 100644 index e2292f4..0000000 --- a/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitor.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.brokenmoon.redcontrol.driver; - -import com.simon816.j65el02.device.RedBus; - -public class RCMonitor implements RedBus.Peripheral { - @Override - public void write(int address, int data) { - - } - - @Override - public int read(int address) { - return 0; - } - - @Override - public void update() { - - } -} diff --git a/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitorDriver.java b/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitorDriver.java deleted file mode 100644 index 5e15bb6..0000000 --- a/src/main/java/net/brokenmoon/redcontrol/driver/RCMonitorDriver.java +++ /dev/null @@ -1,36 +0,0 @@ -package net.brokenmoon.redcontrol.driver; - -import com.simon816.j65el02.device.MonitorDriver; -import com.simon816.j65el02.device.RPMonitor; - -public interface RCMonitorDriver extends MonitorDriver { - /** - * Called when the {@link RPMonitor} is constructed in order to associate the monitor with the - * driver. - * - * @param monitor The monitor - */ - public void setMonitor(RCMonitor monitor); - - /** - * Called when the cursor data is changed. - * - * @param cursorX - * @param cursorY - * @param cursorMode - */ - public void updateCursor(int cursorX, int cursorY, int cursorMode); - - /** - * Called when the display data has changed. The array is a 2D array of size - * [{@link RPMonitor#HEIGHT}][{@link RPMonitor#WIDTH}]. - * - * The display data is character data (not pixels). The lower 7 bits is the character while the - * MSB is a flag whether the color should be inverted (i.e. foreground and background color - * should be switched). Mapping for the 7 bit value to character is defined by a charset, which - * must be agreed upon by the display driver and programs written for the device. - * - * @param windowData The character data - */ - public void update(byte[][] windowData); -}