diff --git a/src/main/java/li/cil/oc2/common/block/Blocks.java b/src/main/java/li/cil/oc2/common/block/Blocks.java index d7087741..c4d47d26 100644 --- a/src/main/java/li/cil/oc2/common/block/Blocks.java +++ b/src/main/java/li/cil/oc2/common/block/Blocks.java @@ -20,6 +20,7 @@ public final class Blocks { public static final RegistryObject COMPUTER = BLOCKS.register("computer", ComputerBlock::new); public static final RegistryObject CREATIVE_ENERGY = BLOCKS.register("creative_energy", CreativeEnergyBlock::new); public static final RegistryObject DISK_DRIVE = BLOCKS.register("disk_drive", DiskDriveBlock::new); + public static final RegistryObject FLASH_MEMORY_FLASHER = BLOCKS.register("flash_memory_flasher", FlashMemoryFlasherBlock::new); public static final RegistryObject KEYBOARD = BLOCKS.register("keyboard", KeyboardBlock::new); public static final RegistryObject NETWORK_CONNECTOR = BLOCKS.register("network_connector", NetworkConnectorBlock::new); public static final RegistryObject NETWORK_HUB = BLOCKS.register("network_hub", NetworkHubBlock::new); diff --git a/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java b/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java new file mode 100644 index 00000000..facf611d --- /dev/null +++ b/src/main/java/li/cil/oc2/common/block/FlashMemoryFlasherBlock.java @@ -0,0 +1,88 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.block; + +import li.cil.oc2.common.blockentity.BlockEntities; +import li.cil.oc2.common.blockentity.DiskDriveBlockEntity; +import li.cil.oc2.common.blockentity.FlashMemoryFlasherBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.HorizontalDirectionalBlock; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.phys.BlockHitResult; + +import javax.annotation.Nullable; + +public final class FlashMemoryFlasherBlock extends HorizontalDirectionalBlock implements EntityBlock { + public FlashMemoryFlasherBlock() { + super(Properties + .of(Material.METAL) + .sound(SoundType.METAL) + .strength(1.5f, 6.0f)); + registerDefaultState(getStateDefinition().any().setValue(FACING, Direction.NORTH)); + } + + /////////////////////////////////////////////////////////////////// + + @Override + public BlockState getStateForPlacement(final BlockPlaceContext context) { + return super.defaultBlockState().setValue(FACING, context.getHorizontalDirection().getOpposite()); + } + + @SuppressWarnings("deprecation") + @Override + public InteractionResult use(final BlockState state, final Level level, final BlockPos pos, final Player player, final InteractionHand hand, final BlockHitResult hit) { + final BlockEntity blockEntity = level.getBlockEntity(pos); + if (!(blockEntity instanceof final FlashMemoryFlasherBlockEntity diskDrive)) { + return super.use(state, level, pos, player, hand, hit); + } + + final ItemStack heldStack = player.getItemInHand(hand); + if (player.isShiftKeyDown()) { + if (diskDrive.canEject()) { + if (!level.isClientSide()) { + diskDrive.eject(player); + } + return InteractionResult.sidedSuccess(level.isClientSide()); + } + } else { + if (diskDrive.canInsert(heldStack)) { + if (!level.isClientSide()) { + player.setItemInHand(hand, diskDrive.insert(heldStack, player)); + } + return InteractionResult.sidedSuccess(level.isClientSide()); + } + } + + return super.use(state, level, pos, player, hand, hit); + } + + /////////////////////////////////////////////////////////////////// + // EntityBlock + + @Nullable + @Override + public BlockEntity newBlockEntity(final BlockPos pos, final BlockState state) { + return BlockEntities.FLASH_MEMORY_FLASHER.get().create(pos, state); + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected void createBlockStateDefinition(final StateDefinition.Builder builder) { + super.createBlockStateDefinition(builder); + builder.add(FACING); + } +} diff --git a/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java b/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java index 9822a26b..3e1d1f49 100644 --- a/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java +++ b/src/main/java/li/cil/oc2/common/blockentity/BlockEntities.java @@ -23,6 +23,7 @@ public final class BlockEntities { public static final RegistryObject> COMPUTER = register(Blocks.COMPUTER, ComputerBlockEntity::new); public static final RegistryObject> CREATIVE_ENERGY = register(Blocks.CREATIVE_ENERGY, CreativeEnergyBlockEntity::new); public static final RegistryObject> DISK_DRIVE = register(Blocks.DISK_DRIVE, DiskDriveBlockEntity::new); + public static final RegistryObject> FLASH_MEMORY_FLASHER = register(Blocks.FLASH_MEMORY_FLASHER, FlashMemoryFlasherBlockEntity::new); public static final RegistryObject> KEYBOARD = register(Blocks.KEYBOARD, KeyboardBlockEntity::new); public static final RegistryObject> NETWORK_CONNECTOR = register(Blocks.NETWORK_CONNECTOR, NetworkConnectorBlockEntity::new); public static final RegistryObject> NETWORK_HUB = register(Blocks.NETWORK_HUB, NetworkHubBlockEntity::new); diff --git a/src/main/java/li/cil/oc2/common/blockentity/FlashMemoryFlasherBlockEntity.java b/src/main/java/li/cil/oc2/common/blockentity/FlashMemoryFlasherBlockEntity.java new file mode 100644 index 00000000..d4758e5c --- /dev/null +++ b/src/main/java/li/cil/oc2/common/blockentity/FlashMemoryFlasherBlockEntity.java @@ -0,0 +1,226 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.blockentity; + +import li.cil.oc2.common.Constants; +import li.cil.oc2.common.block.DiskDriveBlock; +import li.cil.oc2.common.block.FlashMemoryFlasherBlock; +import li.cil.oc2.common.bus.device.vm.block.FlashMemoryFlasherContainer; +import li.cil.oc2.common.bus.device.vm.block.FlashMemoryFlasherDevice; +import li.cil.oc2.common.capabilities.Capabilities; +import li.cil.oc2.common.container.TypedItemStackHandler; +import li.cil.oc2.common.network.Network; +import li.cil.oc2.common.network.message.DiskDriveFloppyMessage; +import li.cil.oc2.common.network.message.FirmwareFlasherMessage; +import li.cil.oc2.common.tags.ItemTags; +import li.cil.oc2.common.util.ItemStackUtils; +import li.cil.oc2.common.util.LocationSupplierUtils; +import li.cil.oc2.common.util.SoundEvents; +import li.cil.oc2.common.util.ThrottledSoundEmitter; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.api.distmarker.OnlyIn; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.time.Duration; + +public final class FlashMemoryFlasherBlockEntity extends ModBlockEntity implements FlashMemoryFlasherContainer { + private static final String DATA_TAG_NAME = "data"; + + /////////////////////////////////////////////////////////////////// + + private final FlashMemoryItemStackHandler itemHandler = new FlashMemoryItemStackHandler(); + private final FlashMemoryFlasherDevice device = new FlashMemoryFlasherDevice<>(this); + private final ThrottledSoundEmitter accessSoundEmitter; + private final ThrottledSoundEmitter insertSoundEmitter; + private final ThrottledSoundEmitter ejectSoundEmitter; + + /////////////////////////////////////////////////////////////////// + + public FlashMemoryFlasherBlockEntity(final BlockPos pos, final BlockState state) { + super(BlockEntities.FLASH_MEMORY_FLASHER.get(), pos, state); + + this.accessSoundEmitter = new ThrottledSoundEmitter(LocationSupplierUtils.of(this), + SoundEvents.FLOPPY_ACCESS.get()).withMinInterval(Duration.ofSeconds(1)); + this.insertSoundEmitter = new ThrottledSoundEmitter(LocationSupplierUtils.of(this), + SoundEvents.FLOPPY_INSERT.get()).withMinInterval(Duration.ofMillis(100)); + this.ejectSoundEmitter = new ThrottledSoundEmitter(LocationSupplierUtils.of(this), + SoundEvents.FLOPPY_EJECT.get()).withMinInterval(Duration.ofMillis(100)); + } + + /////////////////////////////////////////////////////////////////// + + public boolean canInsert(final ItemStack stack) { + return !stack.isEmpty() && stack.is(ItemTags.DEVICES_FLASH_MEMORY); + } + + public ItemStack insert(final ItemStack stack, @Nullable final Player player) { + if (!canInsert(stack)) { + return stack; + } + + eject(player); + + insertSoundEmitter.play(); + return itemHandler.insertItem(0, stack, false); + } + + public boolean canEject() { + return !itemHandler.extractItem(0, 1, true).isEmpty(); + } + + public void eject(@Nullable final Player player) { + if (level == null) { + return; + } + + final ItemStack stack = itemHandler.extractItem(0, 1, false); + if (!stack.isEmpty()) { + final Direction facing = getBlockState().getValue(FlashMemoryFlasherBlock.FACING); + ejectSoundEmitter.play(); + ItemStackUtils.spawnAsEntity(level, getBlockPos().relative(facing), stack, facing).ifPresent(entity -> { + if (player != null) { + entity.setNoPickUpDelay(); + entity.setOwner(player.getUUID()); + } + }); + } + } + + public ItemStack getFloppy() { + return itemHandler.getStackInSlot(0); + } + + @OnlyIn(Dist.CLIENT) + public void setFloppyClient(final ItemStack stack) { + itemHandler.setStackInSlot(0, stack); + } + + @Override + protected void collectCapabilities(final CapabilityCollector collector, @Nullable final Direction direction) { + collector.offer(Capabilities.itemHandler(), itemHandler); + + if (direction == getBlockState().getValue(FlashMemoryFlasherBlock.FACING).getOpposite()) { + collector.offer(Capabilities.device(), device); + } + } + + @Override + public CompoundTag getUpdateTag() { + final CompoundTag tag = super.getUpdateTag(); + tag.put(Constants.ITEMS_TAG_NAME, itemHandler.serializeNBT()); + return tag; + } + + @Override + public void handleUpdateTag(final CompoundTag tag) { + super.handleUpdateTag(tag); + itemHandler.deserializeNBT(tag.getCompound(Constants.ITEMS_TAG_NAME)); + } + + @Override + protected void saveAdditional(final CompoundTag tag) { + super.saveAdditional(tag); + + tag.put(Constants.ITEMS_TAG_NAME, itemHandler.serializeNBT()); + } + + @Override + public void load(final CompoundTag tag) { + super.load(tag); + + itemHandler.deserializeNBT(tag.getCompound(Constants.ITEMS_TAG_NAME)); + } + + @Override + public ItemStack getDiskItemStack() { + return itemHandler.getStackInSlotRaw(0); + } + + @Override + public void handleDataAccess() { + accessSoundEmitter.play(); + } + + /////////////////////////////////////////////////////////////////// + + private final class FlashMemoryItemStackHandler extends TypedItemStackHandler { + public FlashMemoryItemStackHandler() { + super(1, ItemTags.DEVICES_FLASH_MEMORY); + } + + public ItemStack getStackInSlotRaw(final int slot) { + return super.getStackInSlot(slot); + } + + @Override + @Nonnull + public ItemStack getStackInSlot(final int slot) { + final ItemStack stack = getStackInSlotRaw(slot); + exportDeviceDataToItemStack(stack); + return stack; + } + + @Override + @Nonnull + public ItemStack extractItem(final int slot, final int amount, final boolean simulate) { + if (slot == 0 && !simulate && amount > 0) { + exportDeviceDataToItemStack(getStackInSlotRaw(0)); + } + + return super.extractItem(slot, amount, simulate); + } + + @Override + public int getSlotLimit(final int slot) { + return 1; + } + + @Override + public CompoundTag serializeNBT() { + exportDeviceDataToItemStack(getStackInSlotRaw(0)); + return super.serializeNBT(); + } + + @Override + protected void onContentsChanged(final int slot) { + super.onContentsChanged(slot); + + if (level == null || level.isClientSide()) { + return; + } + + final ItemStack stack = getStackInSlotRaw(slot); + if (stack.isEmpty()) { + device.removeBlockDevice(); + } else { + final CompoundTag tag = ItemStackUtils.getOrCreateModDataTag(stack).getCompound(DATA_TAG_NAME); + device.updateBlockDevice(tag); + } + + Network.sendToClientsTrackingBlockEntity(new FirmwareFlasherMessage(FlashMemoryFlasherBlockEntity.this), FlashMemoryFlasherBlockEntity.this); + + setChanged(); + } + + private void exportDeviceDataToItemStack(final ItemStack stack) { + if (stack.isEmpty()) { + return; + } + + if (level == null || level.isClientSide()) { + return; + } + + final CompoundTag tag = new CompoundTag(); + device.exportToItemStack(tag); + ItemStackUtils.getOrCreateModDataTag(stack).put(DATA_TAG_NAME, tag); + } + } +} diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java b/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java index a02519be..100d6943 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/BlockDeviceDataRegistry.java @@ -15,6 +15,7 @@ import net.minecraftforge.registries.RegistryObject; import javax.annotation.Nullable; import java.util.function.Supplier; +import java.util.stream.Collectors; import java.util.stream.Stream; public final class BlockDeviceDataRegistry { @@ -36,7 +37,11 @@ public final class BlockDeviceDataRegistry { @Nullable public static ResourceLocation getKey(final BlockDeviceData data) { - return INITIALIZER.getRegistryName(); + ResourceLocation location = REGISTRY.get().getKey(data); + if (location == null) { + location = FileSystems.getKeyByValue(data); + } + return location; } @Nullable diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/BuildrootFirmware.java b/src/main/java/li/cil/oc2/common/bus/device/data/BuildrootFirmware.java index e99273c9..3da118ef 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/BuildrootFirmware.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/BuildrootFirmware.java @@ -3,18 +3,22 @@ package li.cil.oc2.common.bus.device.data; import li.cil.oc2.api.bus.device.data.Firmware; +import li.cil.sedna.api.Sizes; import li.cil.sedna.api.memory.MemoryMap; +import li.cil.sedna.elf.*; import li.cil.sedna.buildroot.Buildroot; import li.cil.sedna.memory.MemoryMaps; import net.minecraft.network.chat.Component; import java.io.IOException; +import java.nio.ByteBuffer; public final class BuildrootFirmware implements Firmware { @Override public boolean run(final MemoryMap memory, final long startAddress) { try { MemoryMaps.store(memory, startAddress, Buildroot.getFirmware()); + //MemoryMaps.store(memory, startAddress + 0x200000, BuildrootFirmware.class.getClassLoader().getResourceAsStream("generated/ociivrkernel.bin")); MemoryMaps.store(memory, startAddress + 0x200000, Buildroot.getLinuxImage()); return true; } catch (final IOException e) { diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java b/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java index 4b01c087..749f5c4b 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java +++ b/src/main/java/li/cil/oc2/common/bus/device/data/FileSystems.java @@ -16,6 +16,7 @@ import net.minecraft.server.packs.resources.PreparableReloadListener; import net.minecraft.server.packs.resources.Resource; import net.minecraft.server.packs.resources.ResourceManager; import net.minecraft.util.profiling.ProfilerFiller; +import net.minecraft.world.level.block.Block; import net.minecraftforge.event.AddReloadListenerEvent; import net.minecraftforge.event.server.ServerStoppedEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -43,6 +44,15 @@ public final class FileSystems { return LAYERED_FILE_SYSTEM; } + public static ResourceLocation getKeyByValue(BlockDeviceData value) { + for (Map.Entry entry : BLOCK_DEVICE_DATA.entrySet()) { + if (Objects.equals(value, entry.getValue())) { + return entry.getKey(); + } + } + return null; + } + public static Map getBlockData() { return BLOCK_DEVICE_DATA; } diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherContainer.java b/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherContainer.java new file mode 100644 index 00000000..57243cc9 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherContainer.java @@ -0,0 +1,11 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.bus.device.vm.block; + +import net.minecraft.world.item.ItemStack; + +public interface FlashMemoryFlasherContainer { + ItemStack getDiskItemStack(); + + void handleDataAccess(); +} diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherDevice.java b/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherDevice.java new file mode 100644 index 00000000..427307e4 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/block/FlashMemoryFlasherDevice.java @@ -0,0 +1,109 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.bus.device.vm.block; + +import li.cil.oc2.common.bus.device.vm.item.AbstractBlockStorageDevice; +import li.cil.oc2.common.item.FlashMemoryItem; +import li.cil.oc2.common.item.FloppyItem; +import li.cil.oc2.common.serialization.BlobStorage; +import li.cil.sedna.api.device.BlockDevice; +import li.cil.sedna.device.block.ByteBufferBlockDevice; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.entity.BlockEntity; + +import java.io.IOException; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.util.concurrent.CompletableFuture; + +public final class FlashMemoryFlasherDevice extends AbstractBlockStorageDevice { + private static final ByteBufferBlockDevice EMPTY_BLOCK_DEVICE = ByteBufferBlockDevice.create(0, false); + + /////////////////////////////////////////////////////////////// + + public FlashMemoryFlasherDevice(final T container) { + super(container, false); + } + + /////////////////////////////////////////////////////////////// + + public void updateBlockDevice(final CompoundTag tag) { + joinOpenJob(); + + if (device == null) { + return; + } + + try { + device.setBlock(EMPTY_BLOCK_DEVICE); + } catch (final IOException e) { + LOGGER.error(e); + } + + if (blobHandle != null) { + BlobStorage.close(blobHandle); + blobHandle = null; + } + + importFromItemStack(tag); + + setOpenJob(createBlockDevice().thenAcceptAsync(blockDevice -> { + try { + device.setBlock(blockDevice); + } catch (final IOException e) { + throw new RuntimeException(e); + } + }, WORKERS)); + } + + public void removeBlockDevice() { + joinOpenJob(); + + if (device == null) { + return; + } + + try { + device.setBlock(EMPTY_BLOCK_DEVICE); + } catch (final IOException e) { + LOGGER.error(e); + } + + if (blobHandle != null) { + BlobStorage.close(blobHandle); + blobHandle = null; + } + } + + /////////////////////////////////////////////////////////////// + + @Override + protected CompletableFuture createBlockDevice() { + final ItemStack stack = identity.getDiskItemStack(); + if (stack.isEmpty() || !(stack.getItem() instanceof final FlashMemoryItem floppy)) { + return CompletableFuture.completedFuture(EMPTY_BLOCK_DEVICE); + } + + final int capacity = floppy.getCapacity(stack); + if (capacity <= 0) { + return CompletableFuture.completedFuture(EMPTY_BLOCK_DEVICE); + } + + blobHandle = BlobStorage.validateHandle(blobHandle); + return CompletableFuture.supplyAsync(() -> { + try { + final FileChannel channel = BlobStorage.getOrOpen(blobHandle); + final MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, capacity); + return ByteBufferBlockDevice.wrap(buffer, false); + } catch (final IOException e) { + throw new RuntimeException(e); + } + }, WORKERS); + } + + @Override + protected void handleDataAccess() { + identity.handleDataAccess(); + } +} diff --git a/src/main/java/li/cil/oc2/common/bus/device/vm/item/ByteBufferFlashStorageDevice.java b/src/main/java/li/cil/oc2/common/bus/device/vm/item/ByteBufferFlashStorageDevice.java index 428d004a..b5bcd6f4 100644 --- a/src/main/java/li/cil/oc2/common/bus/device/vm/item/ByteBufferFlashStorageDevice.java +++ b/src/main/java/li/cil/oc2/common/bus/device/vm/item/ByteBufferFlashStorageDevice.java @@ -13,6 +13,9 @@ import li.cil.oc2.api.bus.device.vm.event.VMInitializingEvent; import li.cil.oc2.common.Constants; import li.cil.oc2.common.bus.device.util.IdentityProxy; import li.cil.oc2.common.bus.device.util.OptionalAddress; +import li.cil.oc2.common.item.AbstractStorageItem; +import li.cil.oc2.common.serialization.BlobStorage; +import li.cil.oc2.common.util.ItemStackUtils; import li.cil.sedna.api.memory.MemoryAccessException; import li.cil.sedna.api.memory.MemoryMap; import li.cil.sedna.device.flash.FlashMemoryDevice; @@ -99,19 +102,32 @@ public final class ByteBufferFlashStorageDevice extends IdentityProxy @Override public void deserializeNBT(final CompoundTag tag) { final byte[] data = tag.getByteArray(DATA_TAG_NAME); - final ByteBuffer bufferData = device.getData(); + final ByteBuffer bufferData = ByteBuffer.allocate(size); bufferData.clear(); bufferData.put(data, 0, Math.min(bufferData.limit(), data.length)); + this.data = bufferData; } /////////////////////////////////////////////////////////////// private boolean allocateDevice(final VMContext context) { - if (!context.getMemoryAllocator().claimMemory(size)) { + if (!context.getMemoryAllocator().claimMemory(12*Constants.MEGABYTE)) { return false; } - data = ByteBuffer.allocate(size); + if (data == null) { + try { + data = ByteBuffer.allocate(12*Constants.MEGABYTE); + data.clear(); + CompoundTag tag = ItemStackUtils.getModDataTag(identity).getCompound(DATA_TAG_NAME); + if (tag.hasUUID("blob")) { + BlobStorage.getOrOpen(tag.getUUID("blob")).read(data, 0); + } + } catch(Exception e) { + System.out.println("Error message: " + e.getMessage()); + } + } + device = new FlashMemoryDevice(data); return true; diff --git a/src/main/java/li/cil/oc2/common/entity/Robot.java b/src/main/java/li/cil/oc2/common/entity/Robot.java index d94df8c6..ce724e13 100644 --- a/src/main/java/li/cil/oc2/common/entity/Robot.java +++ b/src/main/java/li/cil/oc2/common/entity/Robot.java @@ -18,6 +18,7 @@ import li.cil.oc2.common.capabilities.Capabilities; import li.cil.oc2.common.container.FixedSizeItemStackHandler; import li.cil.oc2.common.container.RobotInventoryContainer; import li.cil.oc2.common.container.RobotTerminalContainer; +import li.cil.oc2.common.energy.EnergyStorageItemStack; import li.cil.oc2.common.energy.FixedEnergyStorage; import li.cil.oc2.common.entity.robot.*; import li.cil.oc2.common.integration.Wrenches; @@ -393,7 +394,9 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R public void importFromItemStack(final ItemStack stack) { final CompoundTag itemsTag = NBTUtils.getChildTag(stack.getTag(), MOD_TAG_NAME, ITEMS_TAG_NAME); + deviceItems.loadItems(itemsTag); + inventory.deserializeNBT(itemsTag.getCompound(INVENTORY_TAG_NAME)); energy.deserializeNBT(NBTUtils.getChildTag(stack.getTag(), MOD_TAG_NAME, ENERGY_TAG_NAME)); @@ -416,6 +419,14 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R tag.put(TERMINAL_TAG_NAME, NBTSerialization.serialize(terminal)); } + System.out.println("Action processor: " + actionProcessor.serialize().toString()); + System.out.println("Bus element: " + busElement.serialize().toString()); + System.out.println("Items: " + deviceItems.saveItems().toString()); + System.out.println("Devices: " + deviceItems.saveDevices().toString()); + System.out.println("Energy: " + energy.serializeNBT().toString()); + System.out.println("Inventory: " + inventory.serializeNBT().toString()); + System.out.println("Selected Slot: " + getEntityData().get(SELECTED_SLOT).toString()); + tag.put(COMMAND_PROCESSOR_TAG_NAME, actionProcessor.serialize()); tag.put(BUS_ELEMENT_TAG_NAME, busElement.serialize()); tag.put(ITEMS_TAG_NAME, deviceItems.saveItems()); @@ -427,6 +438,18 @@ public final class Robot extends Entity implements li.cil.oc2.api.capabilities.R @Override protected void readAdditionalSaveData(final CompoundTag tag) { + System.out.println("VM State: " + tag.getCompound(STATE_TAG_NAME).toString()); + System.out.println("Terminal: " + tag.getCompound(TERMINAL_TAG_NAME).toString()); + System.out.println("Action processor: " + tag.getCompound(COMMAND_PROCESSOR_TAG_NAME).toString()); + System.out.println("Bus element: " + tag.getCompound(BUS_ELEMENT_TAG_NAME).toString()); + System.out.println("Items: " + tag.getCompound(ITEMS_TAG_NAME).toString()); + System.out.println("Devices: " + tag.getCompound(DEVICES_TAG_NAME).toString()); + System.out.println("Energy: " + tag.getCompound(ENERGY_TAG_NAME).toString()); + System.out.println("Inventory: " + tag.getCompound(INVENTORY_TAG_NAME).toString()); + System.out.println("Selected Slot: " + tag.getCompound(SELECTED_SLOT_TAG_NAME).toString()); + + + virtualMachine.deserialize(tag.getCompound(STATE_TAG_NAME)); NBTSerialization.deserialize(tag.getCompound(TERMINAL_TAG_NAME), terminal); actionProcessor.deserialize(tag.getCompound(COMMAND_PROCESSOR_TAG_NAME)); diff --git a/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java b/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java index 8b7b7354..c3f5e734 100644 --- a/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java +++ b/src/main/java/li/cil/oc2/common/item/AbstractBlockDeviceItem.java @@ -4,6 +4,7 @@ package li.cil.oc2.common.item; import li.cil.oc2.api.bus.device.data.BlockDeviceData; import li.cil.oc2.common.bus.device.data.BlockDeviceDataRegistry; +import li.cil.oc2.common.bus.device.data.FileSystems; import li.cil.oc2.common.util.ItemStackUtils; import net.minecraft.ResourceLocationException; import net.minecraft.network.chat.Component; diff --git a/src/main/java/li/cil/oc2/common/item/FlashMemoryItem.java b/src/main/java/li/cil/oc2/common/item/FlashMemoryItem.java index 54992ae2..9af80ff9 100644 --- a/src/main/java/li/cil/oc2/common/item/FlashMemoryItem.java +++ b/src/main/java/li/cil/oc2/common/item/FlashMemoryItem.java @@ -4,6 +4,7 @@ package li.cil.oc2.common.item; import li.cil.oc2.api.API; import li.cil.oc2.common.bus.device.vm.item.ByteBufferFlashStorageDevice; +import li.cil.oc2.common.util.ItemStackUtils; import li.cil.oc2.common.util.NBTTagIds; import net.minecraft.Util; import net.minecraft.nbt.CompoundTag; diff --git a/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java b/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java index d1c3a10b..3441bf0c 100644 --- a/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java +++ b/src/main/java/li/cil/oc2/common/item/FlashMemoryWithExternalDataItem.java @@ -7,9 +7,13 @@ import li.cil.oc2.common.bus.device.data.FirmwareRegistry; import li.cil.oc2.common.util.ItemStackUtils; import net.minecraft.ResourceLocationException; import net.minecraft.Util; +import net.minecraft.core.NonNullList; +import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.util.StringUtil; +import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; import javax.annotation.Nullable; diff --git a/src/main/java/li/cil/oc2/common/item/Items.java b/src/main/java/li/cil/oc2/common/item/Items.java index 17529421..ed913f48 100644 --- a/src/main/java/li/cil/oc2/common/item/Items.java +++ b/src/main/java/li/cil/oc2/common/item/Items.java @@ -30,6 +30,7 @@ public final class Items { public static final RegistryObject COMPUTER = register(Blocks.COMPUTER); public static final RegistryObject CREATIVE_ENERGY = register(Blocks.CREATIVE_ENERGY); public static final RegistryObject DISK_DRIVE = register(Blocks.DISK_DRIVE); + public static final RegistryObject FLASH_MEMORY_FLASHER = register(Blocks.FLASH_MEMORY_FLASHER); public static final RegistryObject KEYBOARD = register(Blocks.KEYBOARD); public static final RegistryObject NETWORK_CONNECTOR = register(Blocks.NETWORK_CONNECTOR); public static final RegistryObject NETWORK_HUB = register(Blocks.NETWORK_HUB); @@ -61,7 +62,7 @@ public final class Items { new HardDriveWithExternalDataItem(BlockDeviceDataRegistry.BUILDROOT.getId(), DyeColor.BROWN)); public static final RegistryObject FLASH_MEMORY = register("flash_memory", () -> - new FlashMemoryItem(4 * Constants.KILOBYTE)); + new FlashMemoryItem(12 * Constants.MEGABYTE)); public static final RegistryObject FLASH_MEMORY_CUSTOM = register("flash_memory_custom", () -> new FlashMemoryWithExternalDataItem(FirmwareRegistry.BUILDROOT.getId())); diff --git a/src/main/java/li/cil/oc2/common/item/RobotItem.java b/src/main/java/li/cil/oc2/common/item/RobotItem.java index 4e566248..7410f595 100644 --- a/src/main/java/li/cil/oc2/common/item/RobotItem.java +++ b/src/main/java/li/cil/oc2/common/item/RobotItem.java @@ -44,6 +44,11 @@ import static li.cil.oc2.common.util.NBTUtils.makeInventoryTag; import static li.cil.oc2.common.util.RegistryUtils.key; public final class RobotItem extends ModItem { + @Override + public void fillItemCategory(final CreativeModeTab tab, final NonNullList items) { + items.add(getRobotWithFlash()); + } + @Override public void appendHoverText(final ItemStack stack, @Nullable final Level level, final List tooltip, final TooltipFlag flag) { super.appendHoverText(stack, level, tooltip, flag); @@ -79,6 +84,8 @@ public final class RobotItem extends ModItem { return InteractionResult.FAIL; } + System.out.println("Created successfully"); + robot.moveTo(position.x, position.y - robot.getBbHeight() * 0.5f, position.z, Direction.fromYRot(context.getRotation()).getOpposite().toYRot(), 0); if (!level.noCollision(robot)) { diff --git a/src/main/java/li/cil/oc2/common/network/Network.java b/src/main/java/li/cil/oc2/common/network/Network.java index 8e895efe..2750af62 100644 --- a/src/main/java/li/cil/oc2/common/network/Network.java +++ b/src/main/java/li/cil/oc2/common/network/Network.java @@ -61,6 +61,8 @@ public final class Network { registerMessage(OpenRobotTerminalMessage.class, OpenRobotTerminalMessage::new, NetworkDirection.PLAY_TO_SERVER); registerMessage(DiskDriveFloppyMessage.class, DiskDriveFloppyMessage::new, NetworkDirection.PLAY_TO_CLIENT); + registerMessage(FirmwareFlasherMessage.class, FirmwareFlasherMessage::new, NetworkDirection.PLAY_TO_CLIENT); + registerMessage(BusInterfaceNameMessage.ToClient.class, BusInterfaceNameMessage.ToClient::new, NetworkDirection.PLAY_TO_CLIENT); registerMessage(BusInterfaceNameMessage.ToServer.class, BusInterfaceNameMessage.ToServer::new, NetworkDirection.PLAY_TO_SERVER); @@ -138,7 +140,7 @@ public final class Network { INSTANCE.messageBuilder(type, getNextPacketId(), direction) .encoder(AbstractMessage::toBytes) .decoder(decoder) - .consumer(AbstractMessage::handleMessage) + .consumerNetworkThread(AbstractMessage::handleMessage) .add(); } diff --git a/src/main/java/li/cil/oc2/common/network/message/FirmwareFlasherMessage.java b/src/main/java/li/cil/oc2/common/network/message/FirmwareFlasherMessage.java new file mode 100644 index 00000000..82532f38 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/network/message/FirmwareFlasherMessage.java @@ -0,0 +1,50 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.network.message; + +import li.cil.oc2.common.blockentity.DiskDriveBlockEntity; +import li.cil.oc2.common.blockentity.FlashMemoryFlasherBlockEntity; +import li.cil.oc2.common.network.MessageUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent; + +public final class FirmwareFlasherMessage extends AbstractMessage { + private BlockPos pos; + private CompoundTag data; + + /////////////////////////////////////////////////////////////////// + + public FirmwareFlasherMessage(final FlashMemoryFlasherBlockEntity diskDrive) { + this.pos = diskDrive.getBlockPos(); + this.data = diskDrive.getFloppy().serializeNBT(); + } + + public FirmwareFlasherMessage(final FriendlyByteBuf buffer) { + super(buffer); + } + + /////////////////////////////////////////////////////////////////// + + @Override + public void fromBytes(final FriendlyByteBuf buffer) { + pos = buffer.readBlockPos(); + data = buffer.readNbt(); + } + + @Override + public void toBytes(final FriendlyByteBuf buffer) { + buffer.writeBlockPos(pos); + buffer.writeNbt(data); + } + + /////////////////////////////////////////////////////////////////// + + @Override + protected void handleMessage(final NetworkEvent.Context context) { + MessageUtils.withClientBlockEntityAt(pos, DiskDriveBlockEntity.class, + diskDrive -> diskDrive.setFloppyClient(ItemStack.of(data))); + } +} diff --git a/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java index ccd65794..b67741f0 100644 --- a/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java +++ b/src/main/java/li/cil/oc2/common/vm/AbstractVirtualMachine.java @@ -78,6 +78,7 @@ public abstract class AbstractVirtualMachine implements VirtualMachine { state.board.getCpu().setFrequency(Constants.CPU_FREQUENCY); state.board.setBootArguments("root=/dev/vda rw"); state.board.setStandardOutputDevice(state.builtinDevices.uart); + } /////////////////////////////////////////////////////////////////// diff --git a/src/main/java/li/cil/oc2/common/vm/BuiltinDevices.java b/src/main/java/li/cil/oc2/common/vm/BuiltinDevices.java index 153bf963..434884ed 100644 --- a/src/main/java/li/cil/oc2/common/vm/BuiltinDevices.java +++ b/src/main/java/li/cil/oc2/common/vm/BuiltinDevices.java @@ -13,6 +13,7 @@ import li.cil.sedna.device.serial.UART16550A; import li.cil.sedna.device.virtio.VirtIOConsoleDevice; import li.cil.sedna.device.virtio.VirtIOFileSystemDevice; +import java.util.OptionalLong; import java.util.function.Function; public final class BuiltinDevices { diff --git a/src/main/java/li/cil/oc2/common/vm/Terminal.java b/src/main/java/li/cil/oc2/common/vm/Terminal.java index 36c05efd..a10734d2 100644 --- a/src/main/java/li/cil/oc2/common/vm/Terminal.java +++ b/src/main/java/li/cil/oc2/common/vm/Terminal.java @@ -811,8 +811,8 @@ public final class Terminal { builder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_COLOR_TEX); - renderForeground(matrix, builder, row); renderBackground(matrix, builder, row); + renderForeground(matrix, builder, row); BufferBuilder.RenderedBuffer rb = builder.end(); diff --git a/src/main/resources/assets/oc2/blockstates/flash_memory_flasher.json b/src/main/resources/assets/oc2/blockstates/flash_memory_flasher.json new file mode 100644 index 00000000..be0a273c --- /dev/null +++ b/src/main/resources/assets/oc2/blockstates/flash_memory_flasher.json @@ -0,0 +1,19 @@ +{ + "variants": { + "facing=north": { + "model": "oc2:block/flash_memory_flasher" + }, + "facing=south": { + "model": "oc2:block/flash_memory_flasher", + "y": 180 + }, + "facing=west": { + "model": "oc2:block/flash_memory_flasher", + "y": 270 + }, + "facing=east": { + "model": "oc2:block/flash_memory_flasher", + "y": 90 + } + } +} diff --git a/src/main/resources/assets/oc2/models/block/flash_memory_flasher.json b/src/main/resources/assets/oc2/models/block/flash_memory_flasher.json new file mode 100644 index 00000000..6456d38a --- /dev/null +++ b/src/main/resources/assets/oc2/models/block/flash_memory_flasher.json @@ -0,0 +1 @@ +{"parent":"block/block","textures":{"atlas0":"oc2:block/disk_drive/disk_drive_atlas0","atlas1":"oc2:block/disk_drive/disk_drive_atlas1","atlas2":"oc2:block/disk_drive/disk_drive_atlas2","atlas3":"oc2:block/disk_drive/disk_drive_atlas3","particle":"#atlas0"},"elements":[{"from":[0,0,0],"to":[16,6,16],"faces":{"east":{"texture":"atlas0","cullface":"east","uv":[0.0,0.0,8.0,3.0]},"west":{"texture":"atlas0","cullface":"west","uv":[0.0,3.0,8.0,6.0]},"up":{"texture":"atlas0","uv":[0.0,6.0,8.0,14.0]},"down":{"texture":"atlas0","cullface":"down","uv":[8.0,6.0,16.0,14.0]},"north":{"texture":"atlas0","cullface":"north","uv":[8.0,3.0,16.0,6.0]},"south":{"texture":"atlas0","cullface":"south","uv":[8.0,0.0,16.0,3.0]}}},{"from":[0,6,15],"to":[6,10,16],"faces":{"east":{"texture":"atlas2","uv":[14.0,0.0,14.5,2.0]},"west":{"texture":"atlas2","cullface":"west","uv":[14.5,0.0,15.0,2.0]},"up":{"texture":"atlas2","uv":[8.0,15.5,11.0,16.0]},"down":{"texture":"atlas2","uv":[11.0,15.5,14.0,16.0]},"south":{"texture":"atlas2","cullface":"south","uv":[8.0,0.0,11.0,2.0]}}},{"from":[10,6,15],"to":[16,10,16],"faces":{"east":{"texture":"atlas2","cullface":"east","uv":[15.0,0.0,15.5,2.0]},"west":{"texture":"atlas2","uv":[15.5,0.0,16.0,2.0]},"up":{"texture":"atlas2","uv":[8.0,13.5,11.0,14.0]},"down":{"texture":"atlas2","uv":[11.0,13.5,14.0,14.0]},"south":{"texture":"atlas2","cullface":"south","uv":[11.0,0.0,14.0,2.0]}}},{"from":[0,6,0],"to":[16,9,15],"faces":{"east":{"texture":"atlas2","cullface":"east","uv":[8.0,14.0,15.5,15.5]},"west":{"texture":"atlas2","cullface":"west","uv":[8.0,12.0,15.5,13.5]},"up":{"texture":"atlas1","uv":[0.0,0.0,8.0,7.5]},"north":{"texture":"atlas0","cullface":"north","uv":[0.0,14.0,8.0,15.5]},"south":{"texture":"atlas0","uv":[8.0,14.0,16.0,15.5]}}},{"from":[0,9,1],"to":[16,10,15],"faces":{"east":{"texture":"atlas1","cullface":"east","uv":[0.0,15.5,7.0,16.0]},"west":{"texture":"atlas1","cullface":"west","uv":[7.0,15.5,14.0,16.0]},"up":{"texture":"atlas1","uv":[0.0,7.5,8.0,14.5]},"down":{"texture":"atlas1","uv":[8.0,7.5,16.0,14.5]},"north":{"texture":"atlas0","uv":[0.0,15.5,8.0,16.0]},"south":{"texture":"atlas0","uv":[8.0,15.5,16.0,16.0]}}},{"from":[0,9,0],"to":[3,12,1],"faces":{"east":{"texture":"atlas2","uv":[15.5,12.0,16.0,13.5]},"west":{"texture":"atlas2","cullface":"west","uv":[15.5,14.0,16.0,15.5]},"up":{"texture":"atlas1","uv":[14.0,15.5,15.5,16.0]},"down":{"texture":"atlas2","uv":[14.0,15.5,15.5,16.0]},"north":{"texture":"atlas3","cullface":"north","uv":[0.0,0.0,1.5,1.5]}}},{"from":[13,9,0],"to":[16,12,1],"faces":{"east":{"texture":"atlas3","cullface":"east","uv":[1.5,0.0,2.0,1.5]},"west":{"texture":"atlas3","uv":[2.0,0.0,2.5,1.5]},"up":{"texture":"atlas2","uv":[14.0,13.5,15.5,14.0]},"down":{"texture":"atlas3","uv":[0.0,1.5,1.5,2.0]},"north":{"texture":"atlas3","cullface":"north","uv":[0.0,2.0,1.5,3.5]}}},{"from":[0,10,1],"to":[16,12,16],"faces":{"east":{"texture":"atlas2","cullface":"east","uv":[8.0,2.0,15.5,3.0]},"west":{"texture":"atlas2","cullface":"west","uv":[8.0,3.0,15.5,4.0]},"down":{"texture":"atlas1","uv":[8.0,0.0,16.0,7.5]},"north":{"texture":"atlas1","uv":[0.0,14.5,8.0,15.5]},"south":{"texture":"atlas1","cullface":"south","uv":[8.0,14.5,16.0,15.5]}}},{"from":[0,12,0],"to":[16,16,16],"faces":{"east":{"texture":"atlas2","cullface":"east","uv":[0.0,0.0,8.0,2.0]},"west":{"texture":"atlas2","cullface":"west","uv":[0.0,2.0,8.0,4.0]},"up":{"texture":"atlas2","cullface":"up","uv":[0.0,4.0,8.0,12.0]},"down":{"texture":"atlas2","uv":[8.0,4.0,16.0,12.0]},"north":{"texture":"atlas2","cullface":"north","uv":[0.0,12.0,8.0,14.0]},"south":{"texture":"atlas2","cullface":"south","uv":[0.0,14.0,8.0,16.0]}}}]} \ No newline at end of file diff --git a/src/main/resources/assets/oc2/models/item/flash_memory_flasher.json b/src/main/resources/assets/oc2/models/item/flash_memory_flasher.json new file mode 100644 index 00000000..4d0591e6 --- /dev/null +++ b/src/main/resources/assets/oc2/models/item/flash_memory_flasher.json @@ -0,0 +1,3 @@ +{ + "parent": "oc2:block/flash_memory_flasher" +} diff --git a/src/main/resources/data/oc2/recipes/disk_drive.json b/src/main/resources/data/oc2/recipes/disk_drive.json index 8946227d..d9549442 100644 --- a/src/main/resources/data/oc2/recipes/disk_drive.json +++ b/src/main/resources/data/oc2/recipes/disk_drive.json @@ -28,4 +28,4 @@ "result": { "item": "oc2:disk_drive" } -} \ No newline at end of file +} diff --git a/src/main/resources/data/oc2/recipes/flash_memory_flasher.json b/src/main/resources/data/oc2/recipes/flash_memory_flasher.json new file mode 100644 index 00000000..896d065e --- /dev/null +++ b/src/main/resources/data/oc2/recipes/flash_memory_flasher.json @@ -0,0 +1,31 @@ +{ + "type": "minecraft:crafting_shaped", + "pattern": [ + "IUI", + "XTD", + "IBI" + ], + "key": { + "I": { + "tag": "forge:ingots/iron" + }, + "U": { + "tag": "minecraft:buttons" + }, + "T": { + "item": "oc2:transistor" + }, + "X": { + "item": "oc2:bus_interface" + }, + "D": { + "item": "minecraft:dropper" + }, + "B": { + "item": "oc2:circuit_board" + } + }, + "result": { + "item": "oc2:flash_memory_flasher" + } +} diff --git a/src/main/scripts/bin/flash.sh b/src/main/scripts/bin/flash.sh new file mode 100644 index 00000000..f00e8a64 --- /dev/null +++ b/src/main/scripts/bin/flash.sh @@ -0,0 +1,7 @@ +dd ibs=$(echo "12*1024*1024" | bc) count=1 if=/dev/zero of=$1 +if [ "$3" = "yes" ]; then + dd if=fw_jump.bin of=$1 + dd if=$2 of=$1 seek=2097152 oflag=seek_bytes +else + dd if=$2 of=$1 +fi