From 14210c538f5e6ba90677c5b79eb0bbe1b18ff790 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Mon, 14 Feb 2022 00:04:43 +0100 Subject: [PATCH] Add support for custom block devices via data packs. --- .../device/data/BlockDeviceDataRegistry.java | 10 +++- .../common/bus/device/data/FileSystems.java | 42 +++++++++++-- .../device/data/ResourceBlockDeviceData.java | 60 +++++++++++++++++++ 3 files changed, 106 insertions(+), 6 deletions(-) create mode 100644 src/main/java/li/cil/oc2/common/bus/device/data/ResourceBlockDeviceData.java 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 c20fa7fc..5dc07da3 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 @@ -37,10 +37,16 @@ public final class BlockDeviceDataRegistry { @Nullable public static BlockDeviceData getValue(final ResourceLocation location) { - return REGISTRY.get().getValue(location); + final BlockDeviceData value = REGISTRY.get().getValue(location); + if (value != null) { + return value; + } + return FileSystems.getBlockData().get(location); } public static Stream values() { - return REGISTRY.get().getValues().stream(); + return Stream.concat( + REGISTRY.get().getValues().stream(), + FileSystems.getBlockData().values().stream()); } } 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 c86085bb..40aa9801 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 @@ -7,6 +7,7 @@ import com.google.gson.JsonParser; import com.google.gson.JsonPrimitive; import it.unimi.dsi.fastutil.objects.Object2IntArrayMap; import li.cil.oc2.api.API; +import li.cil.oc2.api.bus.device.data.BlockDeviceData; import li.cil.oc2.common.vm.fs.LayeredFileSystem; import li.cil.sedna.fs.FileSystem; import li.cil.sedna.fs.ZipStreamFileSystem; @@ -24,16 +25,17 @@ import org.apache.logging.log4j.Logger; import java.io.InputStream; import java.io.InputStreamReader; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Comparator; +import java.util.*; import java.util.concurrent.CompletableFuture; import java.util.concurrent.Executor; +import static li.cil.oc2.common.util.TextFormatUtils.formatSize; + @Mod.EventBusSubscriber(modid = API.MOD_ID, bus = Mod.EventBusSubscriber.Bus.FORGE) public final class FileSystems { private static final Logger LOGGER = LogManager.getLogger(); private static final LayeredFileSystem LAYERED_FILE_SYSTEM = new LayeredFileSystem(); + private static final Map BLOCK_DEVICE_DATA = new HashMap<>(); /////////////////////////////////////////////////////////////////// @@ -41,8 +43,21 @@ public final class FileSystems { return LAYERED_FILE_SYSTEM; } + public static Map getBlockData() { + return BLOCK_DEVICE_DATA; + } + public static void reset() { LAYERED_FILE_SYSTEM.clear(); + + for (final BlockDeviceData data : BLOCK_DEVICE_DATA.values()) { + try { + ((ResourceBlockDeviceData) data).close(); + } catch (final Exception e) { + LOGGER.error(e); + } + } + BLOCK_DEVICE_DATA.clear(); } /////////////////////////////////////////////////////////////////// @@ -99,7 +114,25 @@ public final class FileSystems { fileSystemOrder.put(fileSystem, 0); } } - case "block" -> LOGGER.error("Not yet implemented."); + case "block" -> { + final ResourceLocation location = new ResourceLocation(json.getAsJsonPrimitive("location").getAsString()); + if (BlockDeviceDataRegistry.getValue(location) != null) { + LOGGER.error("Block device from datapack collides with already registered location [{}].", location); + continue; + } + + final String name; + if (json.has("name")) { + name = json.getAsJsonPrimitive("name").getAsString(); + } else { + name = "???"; + } + + final ResourceBlockDeviceData data = new ResourceBlockDeviceData(resourceManager, location, name); + + LOGGER.info(" Adding block device [{}] with id [{}] and a size of [{}].", name, location, formatSize(data.getBlockDevice().getCapacity())); + BLOCK_DEVICE_DATA.put(location, data); + } default -> LOGGER.error("Unsupported file system type [{}].", type); } } catch (final Throwable e) { @@ -123,4 +156,5 @@ public final class FileSystems { .thenCompose(stage::wait); } } + } diff --git a/src/main/java/li/cil/oc2/common/bus/device/data/ResourceBlockDeviceData.java b/src/main/java/li/cil/oc2/common/bus/device/data/ResourceBlockDeviceData.java new file mode 100644 index 00000000..757b6759 --- /dev/null +++ b/src/main/java/li/cil/oc2/common/bus/device/data/ResourceBlockDeviceData.java @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: MIT */ + +package li.cil.oc2.common.bus.device.data; + +import li.cil.oc2.api.bus.device.data.BlockDeviceData; +import li.cil.sedna.api.device.BlockDevice; +import li.cil.sedna.device.block.ByteBufferBlockDevice; +import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.TextComponent; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.packs.resources.ResourceManager; +import net.minecraftforge.registries.IForgeRegistryEntry; +import org.jetbrains.annotations.Nullable; + +import java.io.IOException; +import java.io.InputStream; + +public final class ResourceBlockDeviceData implements IForgeRegistryEntry, BlockDeviceData, AutoCloseable { + private final ResourceLocation location; + private final String name; + private final BlockDevice blockDevice; + + public ResourceBlockDeviceData(final ResourceManager resourceManager, final ResourceLocation location, final String name) throws IOException { + this.location = location; + this.name = name; + final InputStream stream = resourceManager.getResource(location).getInputStream(); + this.blockDevice = ByteBufferBlockDevice.createFromStream(stream, true); + } + + @Override + public BlockDeviceData setRegistryName(final ResourceLocation name) { + throw new UnsupportedOperationException(); + } + + @Nullable + @Override + public ResourceLocation getRegistryName() { + return location; + } + + @Override + public Class getRegistryType() { + return BlockDeviceData.class; + } + + @Override + public void close() throws Exception { + blockDevice.close(); + } + + @Override + public BlockDevice getBlockDevice() { + return blockDevice; + } + + @Override + public Component getDisplayName() { + return new TextComponent(name); + } +}