From 25863311bd90207752da379b3dcf73e39c09a978 Mon Sep 17 00:00:00 2001 From: BallOfEnergy <66693744+BallOfEnergy1@users.noreply.github.com> Date: Thu, 15 Aug 2024 14:13:33 -0500 Subject: [PATCH] New compatibility! This uses OpenComputer's Floppy Disk API, allowing mods to create new loot disks and add them to the tables (this took me a while; I love this system so much, it's my baby :heart:). --- .../java/com/hbm/handler/CompatHandler.java | 167 ++++++++++- src/main/java/com/hbm/main/MainRegistry.java | 5 +- src/main/resources/assets/hbm/disks/README.md | 13 + .../hbm/disks/pwrangler/usr/bin/PWRangler.lua | 274 ++++++++++++++++++ 4 files changed, 454 insertions(+), 5 deletions(-) create mode 100644 src/main/resources/assets/hbm/disks/README.md create mode 100644 src/main/resources/assets/hbm/disks/pwrangler/usr/bin/PWRangler.lua diff --git a/src/main/java/com/hbm/handler/CompatHandler.java b/src/main/java/com/hbm/handler/CompatHandler.java index f61c35c0f..fe0b08ca0 100644 --- a/src/main/java/com/hbm/handler/CompatHandler.java +++ b/src/main/java/com/hbm/handler/CompatHandler.java @@ -1,13 +1,30 @@ package com.hbm.handler; +import com.hbm.blocks.ModBlocks; +import com.hbm.inventory.RecipesCommon; import com.hbm.inventory.fluid.FluidType; import com.hbm.inventory.fluid.Fluids; +import com.hbm.lib.RefStrings; +import com.hbm.main.MainRegistry; +import cpw.mods.fml.common.Loader; import cpw.mods.fml.common.Optional; +import li.cil.oc.api.Items; +import li.cil.oc.api.fs.FileSystem; import li.cil.oc.api.machine.Arguments; import li.cil.oc.api.machine.Context; import li.cil.oc.api.network.*; +import net.minecraft.item.ItemStack; import net.minecraftforge.common.util.ForgeDirection; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Callable; + +import static com.hbm.main.CraftingManager.addShapelessAuto; +import static li.cil.oc.api.FileSystem.asReadOnly; +import static li.cil.oc.api.FileSystem.fromClass; /** * General handler for OpenComputers compatibility. @@ -15,13 +32,29 @@ import net.minecraftforge.common.util.ForgeDirection; */ public class CompatHandler { + /** + * Used for converting a steam type to an integer (compression levels). + * @param type Steam type. + * @return Object[] array containing an int with the "compression level" + */ public static Object[] steamTypeToInt(FluidType type) { - if(type == Fluids.STEAM) {return new Object[] {0};} - else if(type == Fluids.HOTSTEAM) {return new Object[] {1};} - else if(type == Fluids.SUPERHOTSTEAM) {return new Object[] {2};} - return new Object[] {3}; + switch(type.getID()) { + default: + return new Object[] {0}; + case(4): // Fluids.HOTSTEAM + return new Object[] {1}; + case(5): // Fluids.SUPERHOTSTEAM + return new Object[] {2}; + case(6): // Fluids.ULTRAHOTSTEAM + return new Object[] {3}; + } } + /** + * Used for converting a compression level to a steam type. + * @param arg Steam compression level. + * @return FluidType of the steam type based on the compression level. + */ public static FluidType intToSteamType(int arg) { switch(arg) { default: @@ -35,6 +68,132 @@ public class CompatHandler { } } + /** + * Allows for easy creation of read-only filesystems. Primarily for floppy disks. + * (Though maybe reading directly from VOTV drives as filesystems could be implemented. :3) + **/ + private static class ReadOnlyFileSystem implements Callable { + + private final String name; + + ReadOnlyFileSystem(String name) { + this.name = name; + } + + @Override + @Optional.Method(modid = "OpenComputers") + public li.cil.oc.api.fs.FileSystem call() throws Exception { + return asReadOnly(fromClass(MainRegistry.class, RefStrings.MODID, "disks/" + FloppyDisk.sanitizeName(name))); + } + } + + // Floppy disk class. + public static class FloppyDisk { + // Specifies the callable ReadOnlyFileSystem to allow OC to access the floppy. + public final ReadOnlyFileSystem fs; + // Specifies the color of the floppy disk (0-16 colors defined by OC). + public final Byte color; + // Set after loading the disk; allows for adding a recipe to the item. + public ItemStack item; + + FloppyDisk(String name, int color) { + this.fs = new ReadOnlyFileSystem(FloppyDisk.sanitizeName(name)); + this.color = (byte) color; + } + + // Disk names will be sanitized before the FileSystem is created. + // This only affects the location/directory, not the display name. + // (Prevents filesystems from breaking/crashing due to having file separators, wildcards, etc. + public static String sanitizeName(String input) { + return input.toLowerCase().replaceAll("\\W", ""); + } + } + + /** + * Simple enum for mapping OC color ordinals to a nicer format for adding new disks. + */ + public enum OCColors { + BLACK, //0x444444 + RED, //0xB3312C + GREEN, //0x339911 + BROWN, //0x51301A + BLUE, //0x6666FF + PURPLE, //0x7B2FBE + CYAN, //0x66FFFF + LIGHTGRAY, //0xABABAB + GRAY, //0x666666 + PINK, //0xD88198 + LIME, //0x66FF66 + YELLOW, //0xFFFF66 + LIGHTBLUE, //0xAAAAFF + MAGENTA, //0xC354CD + ORANGE, //0xEB8844 + WHITE //0xF0F0F0 + } + + // Where all disks are stored with their name and `FloppyDisk` class. + public static HashMap disks = new HashMap<>(); + + /** + * Called in the FML PostLoad stage, after the OC API loads. + *
+ * Loads various parts of OC compatibility. + */ + public static void init() { + if(Loader.isModLoaded("OpenComputers")) { + /* + For anyone wanting to add their own floppy disks, + read the README found in assets.hbm.disks. + */ + + // Idea/Code by instantnootles + disks.put("PWRangler", new FloppyDisk("PWRangler", OCColors.CYAN.ordinal())); + + // begin registering disks + Logger logger = LogManager.getLogger("HBM"); + logger.info("Loading OpenComputers disks..."); + if(disks.size() == 0) { + logger.info("No disks registered; see com.hbm.handler.CompatHandler.disks"); + return; + } + disks.forEach((s, disk) -> { + + // Test if the disk path even exists. + FileSystem fs = fromClass(MainRegistry.class, RefStrings.MODID, "disks/" + disk.fs.name); + + if (fs == null) { // Disk path does NOT exist, and it should not be loaded. + + logger.error("Error loading disk: " + s + " at /assets/" + RefStrings.MODID + "/disks/" + disk.fs.name); + logger.error("This is likely due to the path to the disk being non-existent."); + + } else { // Disk path DOES exist, and it should be loaded. + + disk.item = Items.registerFloppy(s, disk.color, disk.fs); // The big part, actually registering the floppies! + logger.info("Registered disk: " + s + " at /assets/" + RefStrings.MODID + "/disks/" + disk.fs.name); + + } + }); + logger.info("OpenComputers disks registered."); + + // OC disk recipes! + List floppyDisks = new RecipesCommon.OreDictStack("oc:floppy").toStacks(); + + if(floppyDisks.size() > 0) { //check that floppy disks even exist in oredict. + + // Recipes must be initialized here, since if they were initialized in `CraftingManager` then the disk item would not be created yet. + addShapelessAuto(disks.get("PWRangler").item, new Object[] {"oc:floppy", new ItemStack(ModBlocks.pwr_casing)}); + + logger.info("OpenComputers disk recipe added for PWRangler."); + } else { + logger.info("OpenComputers floppy disk oredict not found, recipes cannot be loaded!"); + } + + // boom, OC disks loaded + logger.info("OpenComputers disks loaded."); + } + } + + // Null component name, default to this if broken to avoid NullPointerExceptions. public static final String nullComponent = "ntm_null"; /** diff --git a/src/main/java/com/hbm/main/MainRegistry.java b/src/main/java/com/hbm/main/MainRegistry.java index caccee6f3..d4f3860b7 100644 --- a/src/main/java/com/hbm/main/MainRegistry.java +++ b/src/main/java/com/hbm/main/MainRegistry.java @@ -877,7 +877,10 @@ public class MainRegistry { proxy.registerMissileItems(); BlockMotherOfAllOres.init(); - + + // Load compatibility for OC. + CompatHandler.init(); + //expand for the largest entity we have (currently Quackos who is 17.5m in diameter, that's one fat duck) World.MAX_ENTITY_RADIUS = Math.max(World.MAX_ENTITY_RADIUS, 8.75); diff --git a/src/main/resources/assets/hbm/disks/README.md b/src/main/resources/assets/hbm/disks/README.md new file mode 100644 index 000000000..973c2bfa1 --- /dev/null +++ b/src/main/resources/assets/hbm/disks/README.md @@ -0,0 +1,13 @@ +# OpenComputers Floppy Disks + +This directory is where the contents of floppy disks registered by `com.hbm.handler.CompatHandler` reside. + +New floppy disks can be added by: +1. Adding a line inside the `init()` function in the `CompatHandler` class to add the floppy disk to the list of disks to register + (actually registering the disks is done automatically by the handler.) +2. Adding the Lua (Preferably 5.3) files to the directory path based on the name you chose for your floppy disk. +
Note: the names of drives are "sanitized", meaning the directory path will be the name you selected but all lowercase and stripped of any non-word character. + (A-Z, a-z, 0-9, _) +3. Add a recipe to the disk at the end of the `init()` function in the `CompatHandler` class, though this step is not required. + +After those steps are complete, a new floppy disk should be registered into OC with a recipe (if added). \ No newline at end of file diff --git a/src/main/resources/assets/hbm/disks/pwrangler/usr/bin/PWRangler.lua b/src/main/resources/assets/hbm/disks/pwrangler/usr/bin/PWRangler.lua new file mode 100644 index 000000000..0b86935da --- /dev/null +++ b/src/main/resources/assets/hbm/disks/pwrangler/usr/bin/PWRangler.lua @@ -0,0 +1,274 @@ +local component = require "component" +local event = require "event" +local gpu = component.gpu +local call = component.invoke + +colorGradient = {0x00FF00, 0x6BEE00, 0x95DB00, 0xB0C800, 0xC5B400, 0xD79F00, 0xE68700, 0xF46900, 0xFC4700, 0xFF0000} +coreHeatESTOP = true +coolantLossESTOP = true + +runSig = true + +coldCoolantLevel = 0 +coldCoolantOutflow = 0 +prevCoolantFlow = 0 + +hotCoolantLevel = 0 +hotCoolantOutflow = 0 +prevHotCoolantFlow = 0 + +gpu.fill(1,1,160,160," ") + +-- Button Bullshit +function newButton(x, y, width, height, colorUp, colorDown, func) + local button = {xpos = 0, ypos = 0, width = 0, height = 0, colorUp = 0, colorDown = 0, func = nil} + button.xpos = x + button.ypos = y + button.width = width + button.height = height + button.colorUp = colorUp + button.colorDown = colorDown + button.func = func + return button +end + +function drawButton(button, color) + component.gpu.setBackground(color) + component.gpu.fill(button.xpos, button.ypos, button.width, button.height, " ") + component.gpu.setBackground(0x000000) +end + +pressedButton = nil +function buttonPress(_, _, x, y, _, _) + for _, b in pairs(buttons) do + if((x>=b.xpos) and (x<(b.xpos+b.width)) and (y>=b.ypos) and (y<(b.ypos+b.height)) ) then + drawButton(b, b.colorDown) + pressedButton = b + end + end +end + +function buttonRelease(_, _, x, y, _, _) + drawButton(pressedButton, pressedButton.colorUp) + pressedButton.func() + pressedButton = nil +end +--Button bullshit ends + +buttons = {} + +buttons[1] = newButton(61, 6, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")+1) end) +buttons[2] = newButton(68, 6, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")+5) end) +buttons[3] = newButton(75, 6, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")+10) end) + +buttons[4] = newButton(61, 9, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")-1) end) +buttons[5] = newButton(68, 9, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")-5) end) +buttons[6] = newButton(75, 9, 6, 2, 0xFFFFFF, 0xAAAAAA, function() component.proxy(pwrController).setLevel(call(pwrController, "getLevel")-10) end) + +buttons[7] = newButton(82, 6, 11, 5, 0xFF0000, 0xAA0000, function() component.proxy(pwrController).setLevel(100) end) +buttons[8] = newButton(94, 6, 12, 2, 0x00FF00, 0x00AA00, function() coreHeatESTOP = not coreHeatESTOP if coreHeatESTOP == true then buttons[8].colorUp = 0x00FF00 buttons[8].colorDown = 0x00AA00 else buttons[8].colorUp = 0xFF0000 buttons[8].colorDown = 0xAA0000 end end) +buttons[9] = newButton(94, 9, 12, 2, 0x00FF00, 0x00AA00, function() coolantLossESTOP = not coolantLossESTOP if coolantLossESTOP == true then buttons[9].colorUp = 0x00FF00 buttons[9].colorDown = 0x00AA00 else buttons[9].colorUp = 0xFF0000 buttons[9].colorDown = 0xAA0000 end end) + +buttons[10] = newButton(107, 8, 5, 3, 0xFF0000, 0xAA0000, function() runSig = false end) + +for address, _ in component.list("ntm_pwr_control") do + pwrController = address +end + +gpu.setForeground(0xAAAAAA) + +--Control rods +gpu.fill(60,4,54,8,"█") + +--Outlet +gpu.fill(91,13,16,8,"█") + +--Inlet +gpu.fill(91,30,16,8,"█") + +gpu.set(61,13," █████████████████████") +gpu.set(61,14," █ █ █ █ █ █ █ █ █ █") +gpu.set(61,15," █ █ █▄█▄█▄█▄█▄█ █ █") +gpu.set(61,16," ▄█████▀█▀█▀█▀█▀█████▄") +gpu.set(61,17," ▄███▀█ █ █ █ █ █ █ █▀███▄") +gpu.set(61,18," ▄██ █ █ █ █ █ █ █ █ █ █ ██▄") +gpu.set(61,19," ██ ██") +gpu.set(61,20,"██▀ █████████████████████ ▀██") +gpu.set(61,21,"██ █████████████████████ ██▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄") +gpu.set(61,22,"██ █ █ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀") +gpu.set(61,23,"██ █████████████████████ → → → → → → → → → →") +gpu.set(61,24,"██ █ █ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄") +gpu.set(61,25,"██ █████████████████████ ██▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀") +gpu.set(61,26,"██ █ █ ██") +gpu.set(61,27,"██ █████████████████████ ██") +gpu.set(61,28,"██ █ █ ██") +gpu.set(61,29,"██ █████████████████████ ██") +gpu.set(61,30,"██ █ █ ██") +gpu.set(61,31,"██ █████████████████████ ██") +gpu.set(61,32,"██ ██") +gpu.set(61,33,"██ ██") +gpu.set(61,34,"██ ██") +gpu.set(61,35,"██ ██") +gpu.set(61,36,"██ ██") +gpu.set(61,37,"██ ██") +gpu.set(61,38,"██ ██▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄") +gpu.set(61,39,"██ ▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀") +gpu.set(61,40,"██ ← ← ← ← ← ← ← ← ← ←") +gpu.set(61,41,"██ ▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄") +gpu.set(61,42,"██ ██▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀") +gpu.set(61,43,"██▄ ▄██") +gpu.set(61,44," ██ ██") +gpu.set(61,45," ▀██ ██▀") +gpu.set(61,46," ▀██▄▄ ▄▄██▀") +gpu.set(61,47," ▀▀███▄▄▄▄▄▄▄▄▄▄▄███▀▀") +gpu.set(61,48," ▀▀▀▀▀▀▀▀▀▀▀▀") + +gpu.setBackground(0xAAAAAA) +gpu.setForeground(0x000000) + +gpu.set(70,4,"CONTROL RODS") +gpu.set(61,5,"INS+1 INS+5 INS+10") +gpu.set(61,8,"RET+1 RET+5 RET+10") + +gpu.set(85,5,"ESTOP") +gpu.set(107,5,"LEVEL") +gpu.set(107,7,"QUIT") + +gpu.set(94,5,"OVHEAT ESTOP") +gpu.set(94,8,"NOCOOL ESTOP") + +gpu.set(95,13,"OUTFLOW") +gpu.set(92,14,"BUFFER") +gpu.set(99,14,"HOTΔ") + +gpu.set(95,30,"INFLOW") +gpu.set(92,31,"BUFFER") +gpu.set(99,31,"COOLΔ") + +gpu.set(69,20,"REACTOR CORE") +gpu.set(71,21,"CORE HEAT:") +gpu.set(71,23,"HULL HEAT:") +gpu.set(71,25,"CORE FLUX:") +gpu.set(68,27,"COLD HEATEX LVL:") +gpu.set(69,29,"HOT HEATEX LVL:") +gpu.setBackground(0x000000) + +gpu.setForeground(0xFFFFFF) +gpu.fill(107,6,5,1,"█") + +--Outflow Buffer +gpu.fill(92,15,6,5,"█") + +--CoolDelta +gpu.fill(99,15,7,1,"█") + +--HotDelta + +gpu.set(66,19,"┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃") +gpu.fill(66,22,19,1,"█") +gpu.fill(66,24,19,1,"█") +gpu.fill(66,26,19,1,"█") +gpu.fill(66,28,19,1,"█") +gpu.fill(66,30,19,1,"█") +gpu.set(66,32,"┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃ ┃") +gpu.setForeground(0xAAAAAA) + +gpu.setForeground(0x000000) +gpu.setBackground(0xFFFFFF) +gpu.set(83,22,"TU") +gpu.set(83,24,"TU") +gpu.setForeground(0xFFFFFF) +gpu.setBackground(0x000000) + + +event.listen("touch", buttonPress) +event.listen("drop", buttonRelease) + +while (runSig == true) do + rodLevel = call(pwrController, "getLevel") + + coreHeat, _ = call(pwrController, "getHeat") + coreHeat = coreHeat//1000000 + + for _, b in pairs(buttons) do + drawButton(b, b.colorUp) + end + + for j=rodLevel//10,10 do + gpu.fill(64+(j*2), 33, 1, 10, " ") + end + + for j=1,rodLevel//10 do + gpu.fill(64+(j*2), 33, 1, 10, "┃") + end + + gpu.fill(64+(math.ceil(rodLevel/10)*2), 33, 1, math.fmod(rodLevel,10), "┃") + + for j=0,20,2 do + gpu.setForeground(colorGradient[coreHeat+1]) + gpu.fill(65+j, 33, 1, 9, "█") + gpu.setForeground(0xAAAAAA) + end + + gpu.setBackground(0xFFFFFF) + + gpu.setForeground(0xFFFFFF) + gpu.fill(66,22,19,1,"█") + gpu.fill(66,24,19,1,"█") + gpu.fill(66,26,19,1,"█") + gpu.fill(66,28,19,1,"█") + gpu.fill(66,30,19,1,"█") + + gpu.fill(92,15,6,5,"█") + gpu.fill(92,32,6,5,"█") + + gpu.fill(99,15,7,1,"█") + gpu.fill(99,32,7,1,"█") + + prevCoolantFlow = coldCoolantLevel + prevHotCoolantFlow = hotCoolantLevel + + fullCoreHeat, fullHullHeat = call(pwrController, "getHeat") + coldCoolantLevel, _, hotCoolantLevel, _ = call(pwrController, "getCoolantInfo") + + coldCoolantOutflow = coldCoolantLevel - prevCoolantFlow + hotCoolantOutflow = hotCoolantLevel - prevHotCoolantFlow + + gpu.setForeground(0xFF0099) + gpu.fill(92,15+(5-hotCoolantLevel//25600),6,hotCoolantLevel//25600, "█") + gpu.setForeground(0x000000) + + gpu.setForeground(0x00FFFF) + gpu.fill(92,32+(5-coldCoolantLevel//25600),6,coldCoolantLevel//25600, "█") + gpu.setForeground(0x000000) + + gpu.set(66,22,tostring(fullCoreHeat)) + gpu.set(66,24,tostring(fullHullHeat)) + gpu.set(66,26,tostring(call(pwrController, "getFlux"))) + gpu.set(66,28,tostring(coldCoolantLevel)) + gpu.set(66,30,tostring(hotCoolantLevel)) + + gpu.set(99,15,tostring(hotCoolantOutflow)) + gpu.set(99,32,tostring(coldCoolantOutflow)) + + gpu.set(107,6," ") + gpu.set(107,6,tostring(call(pwrController, "getLevel"))) + + gpu.setBackground(0x000000) + gpu.setForeground(0xFFFFFF) + + if (coreHeatESTOP == true) and (fullCoreHeat) > 9000000 then + component.proxy(pwrController).setLevel(100) + end + + if (coolantLossESTOP == true) and (coldCoolantLevel) < 10000 then + component.proxy(pwrController).setLevel(100) + end + + os.sleep(0.25) +end + +event.ignore("touch", buttonPress) +event.ignore("drop", buttonRelease) + +gpu.fill(1,1,160,160," ") \ No newline at end of file