Compare commits

..

5 Commits
uxn ... main

3
.gitmodules vendored

@ -1 +1,4 @@
[submodule "J65el02"]
path = J65el02
url = git@github.com:walksanatora/J65el02.git

@ -0,0 +1 @@
Subproject commit f5416177b806650d8014201a3e12c24d6e1c8747

@ -19,7 +19,6 @@ repositories {
// See https://docs.gradle.org/current/userguide/declaring_repositories.html // See https://docs.gradle.org/current/userguide/declaring_repositories.html
// for more information about repositories. // for more information about repositories.
maven { url 'https://maven.dblsaiko.net' } //qcommon maven { url 'https://maven.dblsaiko.net' } //qcommon
maven { url 'https://jitpack.io' } //uxnkt
} }
loom { loom {
@ -53,8 +52,8 @@ dependencies {
// Fabric API. This is technically optional, but you probably want it anyway. // Fabric API. This is technically optional, but you probably want it anyway.
modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}"
//shadow(implementation(project(":J65el02"))) shadow(implementation(project(":J65el02")))
shadow(implementation('com.github.walksanatora:uxnkt:v1.2.2'))
shadow(implementation(group: "net.dblsaiko.qcommon.croco", name: "croco", version: "2.1.3")) shadow(implementation(group: "net.dblsaiko.qcommon.croco", name: "croco", version: "2.1.3"))
} }

@ -35,6 +35,7 @@ import net.minecraft.resource.Resource;
import net.minecraft.resource.ResourceManager; import net.minecraft.resource.ResourceManager;
import net.minecraft.resource.ResourceType; import net.minecraft.resource.ResourceType;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.text.Style;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.Identifier; import net.minecraft.util.Identifier;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
@ -46,6 +47,9 @@ import java.io.InputStream;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static net.minecraft.item.ItemStack.DISPLAY_KEY;
import static net.minecraft.item.ItemStack.NAME_KEY;
public class RedControl implements ModInitializer { public class RedControl implements ModInitializer {
// This logger is used to write text to the console and the log file. // This logger is used to write text to the console and the log file.
// It is considered best practice to use your mod id as the logger's name. // It is considered best practice to use your mod id as the logger's name.
@ -70,9 +74,12 @@ public class RedControl implements ModInitializer {
//Item Stacks //Item Stacks
public static final ItemStack BASIC_DISK = new ItemStack(FLOPPY_ITEM); public static final ItemStack BASIC_DISK = new ItemStack(FLOPPY_ITEM);
public static final NbtCompound BASIC_NBT = new NbtCompound(); public static final NbtCompound BASIC_NBT = new NbtCompound();
public static final NbtCompound BASIC_SUB_NBT = new NbtCompound();
public static final ItemStack SLIDESHOW_DISK = new ItemStack(FLOPPY_ITEM); public static final ItemStack SLIDESHOW_DISK = new ItemStack(FLOPPY_ITEM);
public static final NbtCompound SLIDESHOW_NBT = new NbtCompound(); public static final NbtCompound SLIDESHOW_NBT = new NbtCompound();
public static final NbtCompound SLIDESHOW_SUB_NBT = new NbtCompound();
//Item group //Item group
public static final ItemGroup ITEM_GROUP = FabricItemGroup.builder() public static final ItemGroup ITEM_GROUP = FabricItemGroup.builder()
@ -95,7 +102,8 @@ public class RedControl implements ModInitializer {
BASIC_NBT.putString("serial", "BASIC"); BASIC_NBT.putString("serial", "BASIC");
BASIC_NBT.putInt("CustomModelData", 1); BASIC_NBT.putInt("CustomModelData", 1);
BASIC_DISK.setNbt(BASIC_NBT); BASIC_DISK.setNbt(BASIC_NBT);
BASIC_DISK.setCustomName(Text.literal("Basic boot disk")); BASIC_SUB_NBT.putString(NAME_KEY, Text.Serialization.toJsonString(Text.literal("Basic Disk").setStyle(Style.EMPTY.withItalic(false))));
BASIC_DISK.setSubNbt(DISPLAY_KEY, BASIC_SUB_NBT);
entries.add(BASIC_DISK); entries.add(BASIC_DISK);
//Slideshow //Slideshow
@ -103,7 +111,8 @@ public class RedControl implements ModInitializer {
SLIDESHOW_NBT.putString("serial", "SLIDESHOW"); SLIDESHOW_NBT.putString("serial", "SLIDESHOW");
SLIDESHOW_NBT.putInt("CustomModelData", 2); SLIDESHOW_NBT.putInt("CustomModelData", 2);
SLIDESHOW_DISK.setNbt(SLIDESHOW_NBT); SLIDESHOW_DISK.setNbt(SLIDESHOW_NBT);
SLIDESHOW_DISK.setCustomName(Text.literal("Slideshow disk")); SLIDESHOW_SUB_NBT.putString(NAME_KEY, Text.Serialization.toJsonString(Text.literal("Slideshow Disk").setStyle(Style.EMPTY.withItalic(false))));
SLIDESHOW_DISK.setSubNbt(DISPLAY_KEY, SLIDESHOW_SUB_NBT);
entries.add(SLIDESHOW_DISK); entries.add(SLIDESHOW_DISK);
})) }))
.build(); .build();

@ -1,21 +0,0 @@
package net.brokenmoon.redcontrol.api
import net.walksanator.uxnkt.vm.Device
import net.walksanator.uxnkt.vm.IDevice
class DeviceBus {
var isValid = true
val devices = Array<IDevice>(256) { Device() }
fun tryClaimId(id: Byte, device: IDevice): Boolean {
val obj = devices[id.toInt()]
if (obj.javaClass == Device::class.java) {
devices[id.toInt()] = device
return true
}
return false
}
fun forceClaimId(id: Byte, device: IDevice) {
devices[id.toInt()] = device
}
}

@ -1,5 +1,8 @@
package net.brokenmoon.redcontrol.api.drive package net.brokenmoon.redcontrol.api
import com.simon816.j65el02.device.ByteDiskDriver
import com.simon816.j65el02.device.DiskDriver
import com.simon816.j65el02.device.FileDiskDriver
import net.brokenmoon.redcontrol.RedControl import net.brokenmoon.redcontrol.RedControl
import net.fabricmc.loader.api.FabricLoader import net.fabricmc.loader.api.FabricLoader
import net.minecraft.data.client.BlockStateVariantMap.TriFunction import net.minecraft.data.client.BlockStateVariantMap.TriFunction
@ -38,10 +41,10 @@ object DriveFactory {
"rosave" -> { "rosave" -> {
val path = gamedir.resolve(uri.host+uri.path).absolute() val path = gamedir.resolve(uri.host+uri.path).absolute()
if (path.startsWith(gamedir)) { if (path.startsWith(gamedir)) {
return FileDiskDriver(path,name,serial,true) return FileDiskDriver(path,name,serial,false)
} else { return null } } else { return null }
} }
//"http", "https" -> {return null} //TODO: implement http(s) Read-Only drives "http", "https" -> {return null}
else -> { else -> {
if (extendedDrivers.containsKey(uri.scheme)) { if (extendedDrivers.containsKey(uri.scheme)) {
return extendedDrivers[uri.scheme]!!.apply(uri,name,serial) return extendedDrivers[uri.scheme]!!.apply(uri,name,serial)

@ -0,0 +1,209 @@
package net.brokenmoon.redcontrol.api;
import com.simon816.j65el02.Bus;
import com.simon816.j65el02.Cpu;
import com.simon816.j65el02.CpuState;
import com.simon816.j65el02.device.Memory;
import com.simon816.j65el02.device.RedBus;
import com.simon816.j65el02.device.RedBusState;
import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.mixin.BusAccessor;
import net.brokenmoon.redcontrol.mixin.CpuAccessor;
import net.brokenmoon.redcontrol.mixin.MemoryAccessor;
import net.minecraft.nbt.NbtCompound;
import java.io.IOException;
import java.nio.file.Paths;
/**
* A serializable emulator
*/
public class Emulator {
private RedBus bus;
public Cpu cpu;
private Memory ram;
public Emulator(RedBus bus){
this.bus = bus;
cpu = new Cpu();
cpu.setLogCallback((i) -> RedControl.LOGGER.info("CPU emitted a byte {}",i));
cpu.setBus(new Bus(bus));
ram = new Memory(0x0000, 0x4000 - 1, ((CpuAccessor)cpu).getRedBusState());
ram.loadFromBytes(RedControl.images.get("rpcboot.bin"),0x400,0x100);
cpu.getBus().addDevice(ram, ((CpuAccessor)cpu).getRedBusState());
cpu.reset();
ram.write(0, 2, ((CpuAccessor)cpu).getRedBusState());
ram.write(1, 1, ((CpuAccessor)cpu).getRedBusState());
}
/**
* gets the RedBus attached to this Emulator
* @return the red bus attached to this emulator
*/
public RedBus getBus() {
return bus;
}
/**
* sets the bus and sets redbus on the CPU
* @param bus the bus to set the cpu and this emu to
*/
public void setBus(RedBus bus) {
this.bus = bus;
((BusAccessor)this.cpu.getBus()).setRedBus(bus);
}
/**
* returns if the CPU is waiting on interupt
* @return if the cpu is waiting on a interupt
*/
public boolean isWaitingOnInterrupt(){
return cpu.isWaitingForInterrupt();
}
/**
* sets the CPU's interupt state
* @param interrupt the new interupt state
*/
public void setWaitingOnInterrupt(boolean interrupt){
cpu.getCpuState().intWait = interrupt;
}
/**
* steps the CPU by 1 instruction
* and updates all bus/redbus attached devices
*/
public void step() {
if(!isWaitingOnInterrupt()) {
this.cpu.step();
this.cpu.getBus().update(((CpuAccessor)cpu).getRedBusState());
}
}
/**
* resets the CPU to default values, and loads driveID and monitorID back for bootloader to use
* @param driveId the drive bootloader will read from
* @param monitorId the monitor id bootloder and initial program will write to
*/
public void reset(int driveId, int monitorId){
cpu.reset();
ram.write(0, driveId, ((CpuAccessor)cpu).getRedBusState());
ram.write(1, monitorId, ((CpuAccessor)cpu).getRedBusState());
}
/**
* save the emulator into NBT
* @param nbt the NBT to write state into
*/
public void writeNbt(NbtCompound nbt) {
//Cpu write nbt
//Cpu state write nbt
nbt.putInt("aRegister", cpu.getCpuState().a);
nbt.putInt("aTopRegister", cpu.getCpuState().aTop);
nbt.putInt("xRegister", cpu.getCpuState().x);
nbt.putInt("yRegister", cpu.getCpuState().y);
nbt.putInt("spRegister", cpu.getCpuState().sp);
nbt.putInt("pcRegister", cpu.getCpuState().pc);
nbt.putInt("irRegister", cpu.getCpuState().ir);
nbt.putInt("iRegister", cpu.getCpuState().i);
nbt.putInt("rRegister", cpu.getCpuState().r);
nbt.putInt("dRegister", cpu.getCpuState().d);
nbt.putInt("brkRegister", cpu.getCpuState().brk);
nbt.putInt("porRegister", cpu.getCpuState().por);
nbt.putInt("nextirRegister", cpu.getCpuState().nextIr);
nbt.putInt("args1Register", cpu.getCpuState().args[0]);
nbt.putInt("args2Register", cpu.getCpuState().args[1]);
nbt.putInt("nextArgs1Register", cpu.getCpuState().nextArgs[0]);
nbt.putInt("nextArgs2Register", cpu.getCpuState().nextArgs[1]);
nbt.putInt("instSizeRegister", cpu.getCpuState().instSize);
nbt.putBoolean("opTrap", cpu.getCpuState().opTrap);
nbt.putBoolean("irqAsserted", cpu.getCpuState().irqAsserted);
nbt.putBoolean("nmiAsserted", cpu.getCpuState().nmiAsserted);
nbt.putInt("lastPc", cpu.getCpuState().lastPc);
nbt.putBoolean("intWait", cpu.getCpuState().intWait);
nbt.putBoolean("signalStop", cpu.getCpuState().signalStop);
nbt.putBoolean("carryFlag", cpu.getCpuState().carryFlag);
nbt.putBoolean("negativeFlag", cpu.getCpuState().negativeFlag);
nbt.putBoolean("zeroFlag", cpu.getCpuState().zeroFlag);
nbt.putBoolean("irqDisable", cpu.getCpuState().irqDisableFlag);
nbt.putBoolean("decimalMode", cpu.getCpuState().decimalModeFlag);
nbt.putBoolean("breakFlag", cpu.getCpuState().breakFlag);
nbt.putBoolean("overflowFlag", cpu.getCpuState().overflowFlag);
nbt.putBoolean("emuFlag", cpu.getCpuState().emulationFlag);
nbt.putBoolean("mWidth", cpu.getCpuState().mWidthFlag);
nbt.putBoolean("indexWidth", cpu.getCpuState().indexWidthFlag);
nbt.putLong("stepCounter", cpu.getCpuState().stepCounter);
//Redbus state write nbt
RedBusState redBusState = ((CpuAccessor)cpu).getRedBusState();
nbt.putInt("deviceId", redBusState.activeDeviceId);
nbt.putInt("offset", redBusState.offset);
nbt.putInt("memoryWindow", redBusState.memoryWindow);
nbt.putBoolean("enabled", redBusState.enabled);
nbt.putBoolean("enableWindow", redBusState.enableWindow);
//Ram write nbt.
nbt.putByteArray("ramValues", ((MemoryAccessor)this.ram).getMem());
}
/**
* load emulator state from NBT
* @param nbt the NBT to load from.
*/
public void readNbt(NbtCompound nbt) {
//Cpu write nbt
//Cpu state write nbt
cpu.getCpuState().a = nbt.getInt("aRegister");
cpu.getCpuState().aTop = nbt.getInt("aTopRegister");
cpu.getCpuState().x = nbt.getInt("xRegister");
cpu.getCpuState().y = nbt.getInt("yRegister");
cpu.getCpuState().pc = nbt.getInt("pcRegister");
cpu.getCpuState().sp = nbt.getInt("spRegister");
cpu.getCpuState().ir = nbt.getInt("irRegister");
cpu.getCpuState().i = nbt.getInt("iRegister");
cpu.getCpuState().r = nbt.getInt("rRegister");
cpu.getCpuState().d = nbt.getInt("dRegister");
cpu.getCpuState().brk = nbt.getInt("brkRegister");
cpu.getCpuState().por = nbt.getInt("porRegister");
cpu.getCpuState().nextIr = nbt.getInt("nextirRegister");
cpu.getCpuState().args[0] = nbt.getInt("args1Register");
cpu.getCpuState().args[1] = nbt.getInt("args2Register");
cpu.getCpuState().nextArgs[0] = nbt.getInt("nextArgs1Register");
cpu.getCpuState().nextArgs[1] = nbt.getInt("nextArgs2Register");
cpu.getCpuState().instSize = nbt.getInt("instSizeRegister");
cpu.getCpuState().opTrap = nbt.getBoolean("opTrap");
cpu.getCpuState().irqAsserted = nbt.getBoolean("irqAsserted");
cpu.getCpuState().nmiAsserted = nbt.getBoolean("nmiAsserted");
cpu.getCpuState().lastPc = nbt.getInt("lastPc");
cpu.getCpuState().intWait = nbt.getBoolean("intWait");
cpu.getCpuState().signalStop = nbt.getBoolean("signalStop");
cpu.getCpuState().carryFlag = nbt.getBoolean("carryFlag");
cpu.getCpuState().negativeFlag = nbt.getBoolean("negativeFlag");
cpu.getCpuState().zeroFlag = nbt.getBoolean("zeroFlag");
cpu.getCpuState().irqDisableFlag = nbt.getBoolean("irqDisable");
cpu.getCpuState().decimalModeFlag = nbt.getBoolean("decimalMode");
cpu.getCpuState().breakFlag = nbt.getBoolean("breakFlag");
cpu.getCpuState().overflowFlag = nbt.getBoolean("overflowFlag");
cpu.getCpuState().emulationFlag = nbt.getBoolean("emuFlag");
cpu.getCpuState().mWidthFlag = nbt.getBoolean("mWidth");
cpu.getCpuState().indexWidthFlag = nbt.getBoolean("indexWidth");
cpu.getCpuState().stepCounter = nbt.getLong("stepCounter");
//Redbus state write nbt
RedBusState redBusState = ((CpuAccessor)cpu).getRedBusState();
redBusState.activeDeviceId = nbt.getInt("deviceId");
redBusState.offset = nbt.getInt("offset");
redBusState.memoryWindow = nbt.getInt("memoryWindow");
redBusState.enabled = nbt.getBoolean("enabled");
redBusState.enableWindow = nbt.getBoolean("enableWindow");
//Ram write nbt.
((MemoryAccessor)ram).setMem(nbt.getByteArray("ramValues"));
}
}

@ -1,17 +1,21 @@
package net.brokenmoon.redcontrol.api; package net.brokenmoon.redcontrol.api;
import com.simon816.j65el02.device.RedBus;
import net.brokenmoon.redcontrol.util.FloodFill; import net.brokenmoon.redcontrol.util.FloodFill;
import net.minecraft.block.Block;
import net.minecraft.server.world.ServerWorld; import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
public interface NetworkHolder { public interface NetworkHolder {
DeviceBus getBus(World world, BlockPos pos); RCWorldBus getBus(World world, BlockPos pos);
void setBus(World world, BlockPos pos, DeviceBus bus); void setBus(World world, BlockPos pos, RCWorldBus bus);
default void generateBus(ServerWorld world, BlockPos pos){ default void generateBus(ServerWorld world, BlockPos pos){
Block worldBlock = world.getBlockState(pos).getBlock();
if(world.getBlockEntity(pos) instanceof Peripheral entityBlock){ if(world.getBlockEntity(pos) instanceof Peripheral entityBlock){
DeviceBus bus = new DeviceBus(); RCWorldBus bus = new RCWorldBus(new RedBus(), world, pos);
entityBlock.setBus(bus); entityBlock.setBus(bus);
entityBlock.getBus().setValid(true);
this.setBus(world,pos,entityBlock.getBus()); this.setBus(world,pos,entityBlock.getBus());
FloodFill.INSTANCE.blockFloodFiller(world, pos); FloodFill.INSTANCE.blockFloodFiller(world, pos);
} }

@ -1,18 +1,20 @@
package net.brokenmoon.redcontrol.api; package net.brokenmoon.redcontrol.api;
import com.simon816.j65el02.device.RedBus;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.block.entity.BlockEntity; import net.minecraft.block.entity.BlockEntity;
import net.minecraft.block.entity.BlockEntityType; import net.minecraft.block.entity.BlockEntityType;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.walksanator.uxnkt.vm.IDevice;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
/** /**
* a BlockEntity peripheral * a BlockEntity peripheral
*/ */
public abstract class Peripheral extends BlockEntity implements IDevice { public abstract class Peripheral extends BlockEntity implements RedBus.Peripheral {
protected RedBus bus;
protected RCWorldBus worldBus;
protected DeviceBus bus;
protected int id; protected int id;
@ -25,20 +27,21 @@ public abstract class Peripheral extends BlockEntity implements IDevice {
* get the redbus (or creates a new one if it does not exists or is invalid) * get the redbus (or creates a new one if it does not exists or is invalid)
* @return the redbus for this peripheral * @return the redbus for this peripheral
*/ */
public DeviceBus getBus(){ public RCWorldBus getBus(){
if (this.bus == null || !this.bus.isValid()) { if (this.worldBus == null || !this.worldBus.getValid()) {
this.bus = new DeviceBus(); this.worldBus = new RCWorldBus(new RedBus(),world,getPos());
} }
return this.bus; return this.worldBus;
} }
/** /**
* sets the bus for this peripheral and tries to attach it's self at the desired ID * sets the bus for this peripheral and attaches it's self to the bus
* @param bus * @param bus
*/ */
public void setBus(@NotNull DeviceBus bus){ public void setBus(@NotNull RCWorldBus bus){
this.bus = bus; this.bus = bus.getRedBus();
this.bus.tryClaimId((byte)id,this); this.bus.setPeripheral(id, this);
this.worldBus = bus;
} }
/** /**

@ -0,0 +1,49 @@
package net.brokenmoon.redcontrol.api;
import com.simon816.j65el02.device.RedBus;
import net.brokenmoon.redcontrol.blocks.NetworkCarrier;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
/**
* A Bus holder including the blockpos and redbus and a cached world
* also holds if the bus is valid
*/
public class RCWorldBus {
private boolean isValid = false;
private RedBus redBus;
private World backupWorld;
private BlockPos backupPos;
public RCWorldBus(RedBus redBus, World world, BlockPos pos) {
this.redBus = redBus;
backupWorld = world;
backupPos = pos;
}
public void generateBus(ServerWorld world, BlockPos pos){
((NetworkCarrier)(world.getBlockState(pos).getBlock())).generateBus(world, pos);
}
public RedBus getRedBus() {
return redBus;
}
public void setRedBus(RedBus redBus) {
this.redBus = redBus;
}
public void setValid(boolean val){
this.isValid = val;
}
public boolean getValid(){
return this.isValid;
}
}

@ -1,51 +0,0 @@
package net.brokenmoon.redcontrol.api.drive;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
public class ByteDiskDriver implements DiskDriver{
private final ByteBuffer bytes;
private final byte[] drive_name;
private final byte[] drive_serial;
public ByteDiskDriver(byte[] bytes, String name, String serial) {
this.bytes = ByteBuffer.wrap(bytes);
this.drive_name = name.getBytes(StandardCharsets.UTF_8);
this.drive_serial = serial.getBytes(StandardCharsets.UTF_8);
}
@Override
public byte[] getDriveName() {
return drive_name;
}
@Override
public byte[] getDriveSerial() {
return drive_serial;
}
@Override
public void seek(int location) throws IOException {
this.bytes.position(Math.min(bytes.limit(),location));
}
@Override
public void read(ByteBuffer buffer) throws IOException {
int size = Math.min(buffer.capacity(),bytes.remaining());
for (int i = 0; i < size; i++) {
buffer.put(bytes.get());
}
}
@Override
public void write(ByteBuffer buffer) throws IOException {
this.bytes.position(this.bytes.position() + buffer.capacity());
}
@Override
public void writeDiskName(byte[] diskName) throws IOException {
}
}

@ -1,73 +0,0 @@
/*
* Copyright (c) 2018 Simon816
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.brokenmoon.redcontrol.api.drive;
import java.io.IOException;
import java.nio.ByteBuffer;
public interface DiskDriver {
/**
* Gets the name of the drive.
*
* @return Drive name
*/
byte[] getDriveName();
/**
* Gets the serial name of the drive.
*
* @return Drive serial
*/
byte[] getDriveSerial();
/**
* Seeks to the given location in the drive.
*
* @param location Absolute location in the drive
* @throws IOException If the seek operation fails
*/
void seek(int location) throws IOException;
/**
* Reads data from the drive at the current position into the buffer.
*
* @param buffer Buffer where data is to be put into
* @throws IOException If the read operation fails
*/
void read(ByteBuffer buffer) throws IOException;
/**
* Write data from the buffer into the drive at the current position.
*
* @param buffer Buffer to pull data from
* @throws IOException If the write operation fails
*/
void write(ByteBuffer buffer) throws IOException;
/**
* Updates the name of the disk to the given name.
*
* @param diskName New name of the disk
* @throws IOException If the name update operation fails
*/
void writeDiskName(byte[] diskName) throws IOException;
}

@ -1,101 +0,0 @@
/*
* Copyright (c) 2018 Simon816
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
* associated documentation files (the "Software"), to deal in the Software without restriction,
* including without limitation the rights to use, copy, modify, merge, publish, distribute,
* sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT
* NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
package net.brokenmoon.redcontrol.api.drive;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SeekableByteChannel;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.EnumSet;
/**
* A {@link DiskDriver} backed by a real file.
*/
public class FileDiskDriver implements DiskDriver {
private final SeekableByteChannel channel;
private byte[] driveName;
private byte[] driveSerial;
/**
* Constructs a disk driver backed by a real file. The file is opened for reading, and optionally
* writing, until {@link #close} is called.
*
* @param file Path to the file backing this disk
* @param driveName Name of the drive presented to the program
* @param serial Serial number of the drive
* @param readOnly Whether the file should be opened for reading only
* @throws IOException If the file cannot be opened
*/
public FileDiskDriver(Path file, String driveName, String serial, boolean readOnly) throws IOException {
EnumSet<StandardOpenOption> openOptions = EnumSet.of(StandardOpenOption.READ);
if (!readOnly) {
openOptions.add(StandardOpenOption.WRITE);
}
this.channel = Files.newByteChannel(file, openOptions);
this.driveName = driveName.getBytes(StandardCharsets.US_ASCII);
this.driveSerial = serial.getBytes(StandardCharsets.US_ASCII);
}
/**
* Closes the underlying open file for this drive.
* <p>
* This should be called after the machine has been terminated. Using the drive after closing is
* undefined.
*
* @throws IOException If an error occurs when closing
*/
public void close() throws IOException {
this.channel.close();
}
@Override
public byte[] getDriveName() {
return this.driveName;
}
@Override
public byte[] getDriveSerial() {
return this.driveSerial;
}
@Override
public void seek(int location) throws IOException {
this.channel.position(location);
}
@Override
public void read(ByteBuffer buffer) throws IOException {
this.channel.read(buffer);
}
@Override
public void write(ByteBuffer buffer) throws IOException {
this.channel.write(buffer);
}
@Override
public void writeDiskName(byte[] diskName) throws IOException {
// TODO This does nothing
}
}

@ -1,6 +0,0 @@
package net.brokenmoon.redcontrol.api.uxn
import net.walksanator.uxnkt.vm.WrappingByteArray
class MMIOWrappingByteArray : WrappingByteArray(0x10000) {
}

@ -1,17 +0,0 @@
package net.brokenmoon.redcontrol.api.uxn
import net.walksanator.uxnkt.vm.Computer
import net.walksanator.uxnkt.vm.Uxn
import java.util.function.Consumer
class MinecraftComputer(cpu: Uxn) : Computer(cpu) {
override fun queue(prerun: Consumer<Computer>) {
TODO("Not yet implemented")
}
override fun run() {
TODO("Not yet implemented")
}
}

@ -1,5 +1,6 @@
package net.brokenmoon.redcontrol.blockentities; package net.brokenmoon.redcontrol.blockentities;
import com.simon816.j65el02.device.RedBus;
import net.brokenmoon.redcontrol.RedControl; import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.api.*; import net.brokenmoon.redcontrol.api.*;
import net.brokenmoon.redcontrol.blocks.NetworkCarrier; import net.brokenmoon.redcontrol.blocks.NetworkCarrier;
@ -15,6 +16,7 @@ import net.minecraft.world.World;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public class CpuEntity extends Peripheral implements CpuControl { public class CpuEntity extends Peripheral implements CpuControl {
public int i = 0;
public boolean notTicked = true; public boolean notTicked = true;
public Emulator core = new Emulator(new RedBus()); public Emulator core = new Emulator(new RedBus());
@ -26,7 +28,9 @@ public class CpuEntity extends Peripheral implements CpuControl {
@Override @Override
public CpuState getCpuState() {return state;} public CpuState getCpuState() {return state;}
private int resetTimer = 5; private int resetTimer = 40;
public CpuEntity(BlockPos pos, BlockState state) { public CpuEntity(BlockPos pos, BlockState state) {
super(RedControl.CPU_BLOCK_ENTITY, pos, state, 0); super(RedControl.CPU_BLOCK_ENTITY, pos, state, 0);
@ -41,12 +45,12 @@ public class CpuEntity extends Peripheral implements CpuControl {
be.notTicked = false; be.notTicked = false;
} }
if(be.state == CpuState.RUNNING) { if(be.state == CpuState.RUNNING) {
for (int i = 0; i < 1000; i++) for (int i = 0; i < 500; i++)
be.step(); be.step();
} else{ } else{
if (be.state == CpuState.RESET && be.resetTimer > 0){ if (be.state == CpuState.RESET && be.resetTimer > 0){
be.resetTimer--; be.resetTimer--;
} else { } else if(be.state == CpuState.RESET) {
be.core = new Emulator(be.getBus().getRedBus()); be.core = new Emulator(be.getBus().getRedBus());
} }
} }
@ -77,7 +81,7 @@ public class CpuEntity extends Peripheral implements CpuControl {
public void reset() { public void reset() {
this.core.reset(this.defaultDriveId, this.defaultMonitorId); this.core.reset(this.defaultDriveId, this.defaultMonitorId);
state = CpuState.RESET; state = CpuState.RESET;
resetTimer = 5; resetTimer = 40;
markDirty(); markDirty();
world.updateListeners(pos, this.getCachedState(), this.getCachedState(), Block.NOTIFY_LISTENERS); world.updateListeners(pos, this.getCachedState(), this.getCachedState(), Block.NOTIFY_LISTENERS);
} }
@ -95,9 +99,30 @@ public class CpuEntity extends Peripheral implements CpuControl {
} }
public void step() { public void step() {
i++;
core.step();
}
@Override
public void write(int address, int data) {
}
@Override
public int read(int address) {
return 0;
} }
@Override
public void update() {}
@Override
public void setBus(RCWorldBus bus){
this.bus = bus.getRedBus();
this.core.setBus(this.bus);
this.bus.setPeripheral(id, this);
this.worldBus = bus;
}
@Nullable @Nullable
@Override @Override

@ -1,13 +1,15 @@
package net.brokenmoon.redcontrol.blockentities; package net.brokenmoon.redcontrol.blockentities;
import com.simon816.j65el02.device.DiskDriver;
import net.brokenmoon.redcontrol.RedControl; import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.api.DriveFactory;
import net.brokenmoon.redcontrol.api.Peripheral; import net.brokenmoon.redcontrol.api.Peripheral;
import net.brokenmoon.redcontrol.api.drive.DiskDriver;
import net.brokenmoon.redcontrol.item.FloppyDisk; import net.brokenmoon.redcontrol.item.FloppyDisk;
import net.minecraft.block.BlockState; import net.minecraft.block.BlockState;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack; import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NbtCompound; import net.minecraft.nbt.NbtCompound;
import net.minecraft.text.Style;
import net.minecraft.text.Text; import net.minecraft.text.Text;
import net.minecraft.util.ActionResult; import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand; import net.minecraft.util.Hand;
@ -17,6 +19,9 @@ import java.net.URI;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.UUID; import java.util.UUID;
import static net.minecraft.item.ItemStack.DISPLAY_KEY;
import static net.minecraft.item.ItemStack.NAME_KEY;
public class DriveEntity extends Peripheral { public class DriveEntity extends Peripheral {
private static final int SECTOR_SIZE = 0x80; private static final int SECTOR_SIZE = 0x80;
@ -91,7 +96,9 @@ public class DriveEntity extends Peripheral {
this.buffer.position(0); this.buffer.position(0);
byte[] diskName = new byte[SECTOR_SIZE]; byte[] diskName = new byte[SECTOR_SIZE];
this.buffer.get(diskName); this.buffer.get(diskName);
this.disk.setCustomName(Text.literal(new String(diskName).trim())); NbtCompound sub_nbt = new NbtCompound();
sub_nbt.putString(NAME_KEY, Text.Serialization.toJsonString(Text.literal(new String(diskName).trim()).setStyle(Style.EMPTY.withItalic(false))));
this.disk.setSubNbt(DISPLAY_KEY, sub_nbt);
this.driver.writeDiskName(diskName); this.driver.writeDiskName(diskName);
this.command = 0; this.command = 0;
break; break;

@ -1,9 +1,11 @@
package net.brokenmoon.redcontrol.blocks; package net.brokenmoon.redcontrol.blocks;
import com.simon816.j65el02.device.RedBus;
import net.brokenmoon.redcontrol.RedControl; import net.brokenmoon.redcontrol.RedControl;
import net.brokenmoon.redcontrol.api.DeviceBus;
import net.brokenmoon.redcontrol.api.NetworkHolder; import net.brokenmoon.redcontrol.api.NetworkHolder;
import net.brokenmoon.redcontrol.api.RCWorldBus;
import net.brokenmoon.redcontrol.api.Peripheral; import net.brokenmoon.redcontrol.api.Peripheral;
import net.brokenmoon.redcontrol.mixin.RedBusAccessor;
import net.minecraft.block.*; import net.minecraft.block.*;
import net.minecraft.entity.LivingEntity; import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity; import net.minecraft.entity.player.PlayerEntity;
@ -18,7 +20,6 @@ import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World; import net.minecraft.world.World;
import net.walksanator.uxnkt.vm.IDevice;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
public abstract class NetworkCarrier extends BlockWithEntity implements BlockEntityProvider, NetworkHolder { public abstract class NetworkCarrier extends BlockWithEntity implements BlockEntityProvider, NetworkHolder {
@ -26,11 +27,11 @@ public abstract class NetworkCarrier extends BlockWithEntity implements BlockEnt
super(settings); super(settings);
} }
public DeviceBus getBus(World world, BlockPos pos){ public RCWorldBus getBus(World world, BlockPos pos){
return ((Peripheral)world.getBlockEntity(pos)).getBus(); return ((Peripheral)world.getBlockEntity(pos)).getBus();
} }
public void setBus(World world, BlockPos pos, DeviceBus bus){ public void setBus(World world, BlockPos pos, RCWorldBus bus){
((Peripheral)world.getBlockEntity(pos)).setBus(bus); ((Peripheral)world.getBlockEntity(pos)).setBus(bus);
} }
@ -68,8 +69,8 @@ public abstract class NetworkCarrier extends BlockWithEntity implements BlockEnt
player.sendMessage(Text.literal(" " + Integer.toHexString(peripheral.getBus().hashCode())), false); player.sendMessage(Text.literal(" " + Integer.toHexString(peripheral.getBus().hashCode())), false);
player.sendMessage(Text.literal(" " + Integer.toHexString(peripheral.getBus().getRedBus().hashCode())), false); player.sendMessage(Text.literal(" " + Integer.toHexString(peripheral.getBus().getRedBus().hashCode())), false);
player.sendMessage(Text.literal(" Peripherals on RedBus: "), false); player.sendMessage(Text.literal(" Peripherals on RedBus: "), false);
IDevice[] peripherals = peripheral.getBus().getDevices(); RedBus.Peripheral[] peripherals = ((RedBusAccessor) peripheral.getBus().getRedBus()).getPeripherals();
for (IDevice value : peripherals) { for (RedBus.Peripheral value : peripherals) {
if (value != null) { if (value != null) {
player.sendMessage(Text.literal(" " + value.getClass().toString()), false); player.sendMessage(Text.literal(" " + value.getClass().toString()), false);
} }

@ -23,7 +23,6 @@ import net.minecraft.util.Hand
import net.minecraft.util.hit.BlockHitResult import net.minecraft.util.hit.BlockHitResult
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
import net.minecraft.world.World import net.minecraft.world.World
import net.walksanator.uxnkt.vm.Uxn
import java.io.FileNotFoundException import java.io.FileNotFoundException
import kotlin.experimental.xor import kotlin.experimental.xor
@ -58,10 +57,6 @@ class TerminalBlock(settings: Settings) : NetworkCarrier(settings) {
class TerminalEntity(pos: BlockPos, state: BlockState) : Peripheral(RedControl.TERMINAL_BLOCK_ENTITY, pos, state,1) { class TerminalEntity(pos: BlockPos, state: BlockState) : Peripheral(RedControl.TERMINAL_BLOCK_ENTITY, pos, state,1) {
override fun postTick(uxn: Uxn) = update()
override fun readByte(address: Byte): Byte = readData(address)
override fun writeByte(address: Byte, byte: Byte) = storeData(address,byte)
val screen = ByteArray(80 * 50) { 0x20 } val screen = ByteArray(80 * 50) { 0x20 }
val charset = RedControl.images["charset.bin"]?.clone()?: throw FileNotFoundException("expected a charset.bin in images datapack") val charset = RedControl.images["charset.bin"]?.clone()?: throw FileNotFoundException("expected a charset.bin in images datapack")
val kb = ByteArray(16) val kb = ByteArray(16)
@ -114,7 +109,8 @@ class TerminalEntity(pos: BlockPos, state: BlockState) : Peripheral(RedControl.T
} }
} }
fun update() { override fun read(address: Int): Int = readData(address.toByte()).toInt()
override fun update() {
val data = this val data = this
var error = false var error = false
@ -134,6 +130,8 @@ class TerminalEntity(pos: BlockPos, state: BlockState) : Peripheral(RedControl.T
data.command = if (error) -1 else 0 data.command = if (error) -1 else 0
} }
override fun write(address: Int, data: Int) = storeData(address.toByte(),data.toByte())
private fun readData(at: Byte): Byte { private fun readData(at: Byte): Byte {
return when (val at = at.unsigned) { return when (val at = at.unsigned) {
0x00 -> row.toByte() 0x00 -> row.toByte()

@ -0,0 +1,12 @@
package net.brokenmoon.redcontrol.mixin;
import com.simon816.j65el02.Bus;
import com.simon816.j65el02.device.RedBus;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Bus.class)
public interface BusAccessor {
@Accessor(value = "redBus",remap = false)
void setRedBus(RedBus redBus);
}

@ -0,0 +1,15 @@
package net.brokenmoon.redcontrol.mixin;
import com.simon816.j65el02.Cpu;
import com.simon816.j65el02.CpuState;
import com.simon816.j65el02.device.RedBusState;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Cpu.class)
public interface CpuAccessor {
@Accessor(value = "redBusState",remap = false)
RedBusState getRedBusState();
@Accessor(value = "state",remap = false)
CpuState getState();
}

@ -0,0 +1,13 @@
package net.brokenmoon.redcontrol.mixin;
import com.simon816.j65el02.device.Memory;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(Memory.class)
public interface MemoryAccessor {
@Accessor(value = "mem",remap = false)
byte[] getMem();
@Accessor(value = "mem",remap = false)
void setMem(byte[] mem);
}

@ -0,0 +1,12 @@
package net.brokenmoon.redcontrol.mixin;
import com.simon816.j65el02.device.RedBus;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(RedBus.class)
public interface RedBusAccessor {
@Accessor(value = "peripherals",remap = false)
RedBus.Peripheral[] getPeripherals();
}

@ -1,8 +1,9 @@
package net.brokenmoon.redcontrol.util package net.brokenmoon.redcontrol.util
import net.brokenmoon.redcontrol.RedControl import net.brokenmoon.redcontrol.RedControl
import net.brokenmoon.redcontrol.api.DeviceBus
import net.brokenmoon.redcontrol.api.NetworkHolder import net.brokenmoon.redcontrol.api.NetworkHolder
import net.brokenmoon.redcontrol.api.RCWorldBus
import net.brokenmoon.redcontrol.blocks.NetworkCarrier
import net.minecraft.particle.ParticleTypes import net.minecraft.particle.ParticleTypes
import net.minecraft.server.world.ServerWorld import net.minecraft.server.world.ServerWorld
import net.minecraft.util.math.BlockPos import net.minecraft.util.math.BlockPos
@ -12,7 +13,7 @@ object FloodFill {
fun blockFloodFiller(world: ServerWorld, seed: BlockPos) { fun blockFloodFiller(world: ServerWorld, seed: BlockPos) {
val checkable = mutableListOf(seed) val checkable = mutableListOf(seed)
val seen = mutableListOf<BlockPos>() val seen = mutableListOf<BlockPos>()
var bus: DeviceBus? = null var bus: RCWorldBus? = null
while (checkable.isNotEmpty()) { while (checkable.isNotEmpty()) {
val pos = checkable.removeFirst() val pos = checkable.removeFirst()
if (pos in seen) {continue} if (pos in seen) {continue}
@ -57,7 +58,7 @@ object FloodFill {
seen.add(pos) seen.add(pos)
val nc = (state.block as? NetworkHolder) val nc = (state.block as? NetworkHolder)
if (nc != null) { if (nc != null) {
nc.getBus(world,pos).isValid = false nc.getBus(world,pos).valid = false
val cpos = pos.toCenterPos() val cpos = pos.toCenterPos()
world.spawnParticles(ParticleTypes.WAX_OFF,cpos.x,cpos.y,cpos.z,20,0.6,0.6,0.6,0.2) world.spawnParticles(ParticleTypes.WAX_OFF,cpos.x,cpos.y,cpos.z,20,0.6,0.6,0.6,0.2)
} }

@ -3,7 +3,11 @@
"package": "net.brokenmoon.redcontrol.mixin", "package": "net.brokenmoon.redcontrol.mixin",
"compatibilityLevel": "JAVA_17", "compatibilityLevel": "JAVA_17",
"mixins": [ "mixins": [
"BusAccessor",
"CpuAccessor",
"ExampleMixin", "ExampleMixin",
"MemoryAccessor",
"RedBusAccessor",
"WorldMixin" "WorldMixin"
], ],
"injectors": { "injectors": {

Loading…
Cancel
Save