From ede6425465cf139f70cc3c76a1e2b58d87a87e8f Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 11 Mar 2026 13:17:16 -0400 Subject: [PATCH 01/33] Add Electricity Pylon --- .../io/github/pylonmc/pylon/PylonBlocks.java | 10 +- .../io/github/pylonmc/pylon/PylonItems.java | 12 +- .../io/github/pylonmc/pylon/PylonKeys.java | 2 + .../io/github/pylonmc/pylon/PylonPages.java | 2 + .../content/electricity/ElectricityPylon.java | 186 ++++++++++++++++++ src/main/resources/lang/en.yml | 6 + 6 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 6800f4da3..abc750323 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -1,17 +1,12 @@ package io.github.pylonmc.pylon; import io.github.pylonmc.pylon.content.assembling.AssemblyTable; -import io.github.pylonmc.pylon.content.building.Elevator; -import io.github.pylonmc.pylon.content.building.ExplosiveTarget; -import io.github.pylonmc.pylon.content.building.Immobilizer; -import io.github.pylonmc.pylon.content.building.Pedestal; -import io.github.pylonmc.pylon.content.building.WitherProofBlock; +import io.github.pylonmc.pylon.content.building.*; import io.github.pylonmc.pylon.content.components.*; +import io.github.pylonmc.pylon.content.electricity.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.cargo.*; -import io.github.pylonmc.pylon.content.machines.diesel.machines.DieselCoreDrill; import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; -import io.github.pylonmc.pylon.content.components.SmokestackCap; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; @@ -173,5 +168,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.CREATIVE_ITEM_VOIDER, Material.STRUCTURE_VOID, CreativeItemVoider.class); RebarBlock.register(PylonKeys.COLLIMATOR, Material.OBSIDIAN, Collimator.class); RebarBlock.register(PylonKeys.COLLIMATOR_PILLAR, Material.DEEPSLATE_TILE_WALL, CollimatorPillar.class); + RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 3f6c573a9..eb4232148 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -46,7 +46,10 @@ import org.bukkit.attribute.Attribute; import org.bukkit.attribute.AttributeModifier; import org.bukkit.enchantments.Enchantment; -import org.bukkit.inventory.*; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.EquipmentSlotGroup; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.ShapelessRecipe; import org.bukkit.inventory.recipe.CraftingBookCategory; import org.bukkit.potion.PotionType; @@ -2892,6 +2895,13 @@ private PylonItems() { RecipeType.VANILLA_SHAPELESS.addRecipe(recipe); } + public static final ItemStack ELECTRICITY_PYLON = ItemStackBuilder.rebar(Material.SEA_LANTERN, PylonKeys.ELECTRICITY_PYLON) + .build(); + static { + RebarItem.register(RebarItem.class, ELECTRICITY_PYLON, PylonKeys.ELECTRICITY_PYLON); + PylonPages.ELECTRICITY.addItem(ELECTRICITY_PYLON); + } + static { PylonPages.initialise(); PylonGuides.initialise(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 6afe48009..b0bc2deb4 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -437,4 +437,6 @@ public class PylonKeys { public static final NamespacedKey PORTABLE_FLUID_TANK_PALLADIUM = pylonKey("portable_fluid_tank_palladium"); public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); + + public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/PylonPages.java b/src/main/java/io/github/pylonmc/pylon/PylonPages.java index 5ea10d98e..44faf35e4 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonPages.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonPages.java @@ -34,6 +34,7 @@ public class PylonPages { public static final SimpleStaticGuidePage CARGO = new SimpleStaticGuidePage(pylonKey("machines_cargo")); public static final SimpleStaticGuidePage DIESEL_MACHINES = new SimpleStaticGuidePage(pylonKey("machines_diesel_machines")); public static final SimpleStaticGuidePage DIESEL_PRODUCTION = new SimpleStaticGuidePage(pylonKey("machines_diesel_production")); + public static final SimpleStaticGuidePage ELECTRICITY = new SimpleStaticGuidePage(pylonKey("machines_electricity")); public static final SimpleStaticGuidePage MACHINES = new SimpleStaticGuidePage(pylonKey("machines")); public static final SimpleStaticGuidePage ASSEMBLING = new SimpleStaticGuidePage(pylonKey("assembling")); @@ -70,6 +71,7 @@ public static void initialise() { MACHINES.addPage(PylonItems.CARGO_BUFFER, CARGO); MACHINES.addPage(PylonItems.DIESEL_PIPE_BENDER, DIESEL_MACHINES); MACHINES.addPage(PylonItems.BIOREFINERY, DIESEL_PRODUCTION); + MACHINES.addPage(PylonItems.ELECTRICITY_PYLON, ELECTRICITY); RebarGuide.getRootPage().addPage(PylonItems.MIXING_POT, MACHINES); RebarGuide.getRootPage().addPage(PylonItems.ASSEMBLY_TABLE, ASSEMBLING); diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java new file mode 100644 index 000000000..83d1bc69f --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -0,0 +1,186 @@ +package io.github.pylonmc.pylon.content.electricity; + +import io.github.pylonmc.pylon.Pylon; +import io.github.pylonmc.rebar.block.BlockStorage; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarBreakHandler; +import io.github.pylonmc.rebar.block.base.RebarInteractBlock; +import io.github.pylonmc.rebar.block.context.BlockBreakContext; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; +import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; +import io.github.pylonmc.rebar.event.api.annotation.MultiHandler; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Player; +import org.bukkit.event.Event; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.event.player.PlayerMoveEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.persistence.PersistentDataType; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; + +import java.util.*; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public final class ElectricityPylon extends RebarBlock implements + RebarInteractBlock, + RebarBreakHandler, + Listener { + + private static final NamespacedKey CONNECTING_KEY = pylonKey("connecting"); + private static final NamespacedKey CONNECTING_ID_KEY = pylonKey("connecting_id"); + + private static final NamespacedKey CONNECTED_KEY = pylonKey("connected"); + private static final PersistentDataType> CONNECTED_TYPE = RebarSerializers.MAP.mapTypeFrom( + RebarSerializers.BLOCK_POSITION, + RebarSerializers.UUID + ); + + private final Map connectedPylons; + + @SuppressWarnings("unused") + public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + connectedPylons = new HashMap<>(); + } + + @SuppressWarnings("unused") + public ElectricityPylon(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + connectedPylons = pdc.get(CONNECTED_KEY, CONNECTED_TYPE); + } + + { + Bukkit.getPluginManager().registerEvents(this, Pylon.getInstance()); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + super.write(pdc); + pdc.set(CONNECTED_KEY, CONNECTED_TYPE, connectedPylons); + } + + @Override + public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { + for (var entry : connectedPylons.entrySet()) { + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(entry.getValue()); + assert display != null; + display.remove(); + + BlockPosition otherPos = entry.getKey(); + ElectricityPylon otherPylon = BlockStorage.getAs(ElectricityPylon.class, otherPos); + assert otherPylon != null; + otherPylon.connectedPylons.remove(new BlockPosition(getBlock())); + } + PlayerMoveEvent.getHandlerList().unregister(this); + PlayerQuitEvent.getHandlerList().unregister(this); + } + + @Override + @MultiHandler(priorities = EventPriority.MONITOR) + public void onInteract(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) { + Player player = event.getPlayer(); + if (player.isSneaking() + || event.getHand() != EquipmentSlot.HAND + || event.getAction() != Action.RIGHT_CLICK_BLOCK + || event.useInteractedBlock() == Event.Result.DENY + ) return; + + BlockPosition thisPos = new BlockPosition(getBlock()); + PersistentDataContainer playerPdc = player.getPersistentDataContainer(); + BlockPosition connecting = playerPdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + if (connecting == null) { + Location blockLocation = getBlock().getLocation().toCenterLocation(); + Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); + ItemDisplay display = new ItemDisplayBuilder() + .transformation(getDisplayTransform(blockLocation, playerLocation)) + .material(Material.COPPER_BLOCK) + .build(blockLocation.add(playerLocation.subtract(blockLocation).multiply(0.5))); + playerPdc.set(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION, thisPos); + playerPdc.set(CONNECTING_ID_KEY, RebarSerializers.UUID, display.getUniqueId()); + } else if (connecting.equals(thisPos)) { + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + display.remove(); + playerPdc.remove(CONNECTING_KEY); + playerPdc.remove(CONNECTING_ID_KEY); + } else { + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + Location thisCenter = getBlock().getLocation().toCenterLocation(); + Location connectingLocation = connecting.getLocation().toCenterLocation(); + display.setTransformationMatrix(getDisplayTransform(thisCenter, connectingLocation)); + display.teleportAsync(thisCenter.add(connectingLocation.clone().subtract(thisCenter).multiply(0.5))); + + ElectricityPylon otherPylon = BlockStorage.getAs(ElectricityPylon.class, connecting); + assert otherPylon != null; + if (otherPylon.connectedPylons.containsKey(thisPos)) { + // disconnect if already connected + display.remove(); + otherPylon.connectedPylons.remove(thisPos); + Objects.requireNonNull(Bukkit.getEntity(connectedPylons.remove(connecting))).remove(); + } else { + otherPylon.connectedPylons.put(thisPos, display.getUniqueId()); + connectedPylons.put(connecting, display.getUniqueId()); + } + playerPdc.remove(CONNECTING_KEY); + playerPdc.remove(CONNECTING_ID_KEY); + } + } + + @EventHandler + private void onPlayerMove(PlayerMoveEvent event) { + if (!event.hasChangedPosition()) return; + Player player = event.getPlayer(); + PersistentDataContainer pdc = player.getPersistentDataContainer(); + if (!pdc.has(CONNECTING_KEY)) return; + BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + assert connecting != null; + Location connectingLocation = connecting.getLocation().toCenterLocation(); + Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + display.setTeleportDuration(1); + display.setInterpolationDelay(0); + display.setInterpolationDuration(1); + display.setTransformationMatrix(getDisplayTransform(connectingLocation, playerLocation)); + display.teleportAsync(connectingLocation.add(playerLocation.clone().subtract(connectingLocation).multiply(0.5))); + } + + @EventHandler + private void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + PersistentDataContainer pdc = player.getPersistentDataContainer(); + if (!pdc.has(CONNECTING_KEY)) return; + BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + assert connecting != null; + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + display.remove(); + pdc.remove(CONNECTING_KEY); + pdc.remove(CONNECTING_ID_KEY); + } + + private static Matrix4f getDisplayTransform(Location from, Location to) { + return new TransformBuilder() + .lookAlong(from, to) + .scale(0.05, 0.05, from.distance(to)) + .buildForItemDisplay(); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 1b5a7d499..aa176ca16 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2227,6 +2227,11 @@ item: waila: "Palladium Condenser | %duration-if-any%" waila_format: "| %duration%" + electricity_pylon: + name: "Electricity Pylon" + lore: |- + TODO + fluid: castable: display-text: " Casts into %result%" @@ -2381,6 +2386,7 @@ guide: machines_diesel_machines: "Diesel Machines" machines_diesel_production: "Diesel Production" machines_smelting: "Smelting" + machines_electricity: "Electricity" machines: "Machines" assembling: "Assembling" building: "Building" From bd61dec73e45c34a25b7ca556b94d1096966c202 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 11 Mar 2026 15:52:35 -0400 Subject: [PATCH 02/33] Add base code --- .../pylon/content/electricity/ElectricityPylon.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java index 83d1bc69f..cf38f1a24 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -4,10 +4,12 @@ import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarBreakHandler; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; import io.github.pylonmc.rebar.block.base.RebarInteractBlock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNode; import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; import io.github.pylonmc.rebar.event.api.annotation.MultiHandler; @@ -41,7 +43,8 @@ public final class ElectricityPylon extends RebarBlock implements RebarInteractBlock, RebarBreakHandler, - Listener { + Listener, + RebarElectricBlock { private static final NamespacedKey CONNECTING_KEY = pylonKey("connecting"); private static final NamespacedKey CONNECTING_ID_KEY = pylonKey("connecting_id"); @@ -58,6 +61,8 @@ public final class ElectricityPylon extends RebarBlock implements public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); connectedPylons = new HashMap<>(); + + createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONNECTOR); } @SuppressWarnings("unused") From 9fb3fb8fa79a2a0cff9bfdd4a3547cf9e41c0db9 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 11 Mar 2026 20:39:01 -0400 Subject: [PATCH 03/33] Simple networks --- build.gradle.kts | 3 + .../content/electricity/ElectricityPylon.java | 76 +++++++++++-------- 2 files changed, 48 insertions(+), 31 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 191465456..a356573ed 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -30,6 +30,9 @@ repositories { maven("https://maven.pvphub.me/tofaa") { name = "EntityLib" } + maven("https://repo.codemc.io/repository/maven-releases/") { + name = "CodeMC" + } } val rebarVersion = project.properties["rebar.version"] as String diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java index cf38f1a24..bbfd6a3dc 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -6,6 +6,7 @@ import io.github.pylonmc.rebar.block.base.RebarBreakHandler; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; import io.github.pylonmc.rebar.block.base.RebarInteractBlock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.datatypes.RebarSerializers; @@ -14,10 +15,7 @@ import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; import io.github.pylonmc.rebar.event.api.annotation.MultiHandler; import io.github.pylonmc.rebar.util.position.BlockPosition; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; @@ -44,59 +42,69 @@ public final class ElectricityPylon extends RebarBlock implements RebarInteractBlock, RebarBreakHandler, Listener, - RebarElectricBlock { + RebarElectricBlock, + RebarTickingBlock { private static final NamespacedKey CONNECTING_KEY = pylonKey("connecting"); private static final NamespacedKey CONNECTING_ID_KEY = pylonKey("connecting_id"); private static final NamespacedKey CONNECTED_KEY = pylonKey("connected"); - private static final PersistentDataType> CONNECTED_TYPE = RebarSerializers.MAP.mapTypeFrom( - RebarSerializers.BLOCK_POSITION, + private static final PersistentDataType> CONNECTED_TYPE = RebarSerializers.MAP.mapTypeFrom( + RebarSerializers.UUID, RebarSerializers.UUID ); - private final Map connectedPylons; + private final Map connected; @SuppressWarnings("unused") public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - connectedPylons = new HashMap<>(); + connected = new HashMap<>(); + + setTickInterval(10); createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONNECTOR); } @SuppressWarnings("unused") public ElectricityPylon(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); - connectedPylons = pdc.get(CONNECTED_KEY, CONNECTED_TYPE); + connected = pdc.get(CONNECTED_KEY, CONNECTED_TYPE); } - { + @Override + public void postInitialise() { Bukkit.getPluginManager().registerEvents(this, Pylon.getInstance()); + + getElectricNode().onDisconnect((thisNode, otherNode) -> { + UUID displayId = connected.remove(otherNode.getId()); + if (displayId == null) return; + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(displayId); + if (display != null) display.remove(); + }); } @Override public void write(@NotNull PersistentDataContainer pdc) { super.write(pdc); - pdc.set(CONNECTED_KEY, CONNECTED_TYPE, connectedPylons); + pdc.set(CONNECTED_KEY, CONNECTED_TYPE, connected); } @Override public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { - for (var entry : connectedPylons.entrySet()) { - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(entry.getValue()); - assert display != null; - display.remove(); - - BlockPosition otherPos = entry.getKey(); - ElectricityPylon otherPylon = BlockStorage.getAs(ElectricityPylon.class, otherPos); - assert otherPylon != null; - otherPylon.connectedPylons.remove(new BlockPosition(getBlock())); - } PlayerMoveEvent.getHandlerList().unregister(this); PlayerQuitEvent.getHandlerList().unregister(this); } + @Override + public void tick() { + Particle.DUST.builder() + .color(Color.fromARGB(getElectricNode().getNetwork().hashCode())) + .location(getBlock().getLocation().toCenterLocation().add(0, 0.6, 0)) + .receivers(32, true) + .spawn(); + } + @Override @MultiHandler(priorities = EventPriority.MONITOR) public void onInteract(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) { @@ -128,21 +136,23 @@ public void onInteract(@NotNull PlayerInteractEvent event, @NotNull EventPriorit } else { ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); assert display != null; - Location thisCenter = getBlock().getLocation().toCenterLocation(); - Location connectingLocation = connecting.getLocation().toCenterLocation(); - display.setTransformationMatrix(getDisplayTransform(thisCenter, connectingLocation)); - display.teleportAsync(thisCenter.add(connectingLocation.clone().subtract(thisCenter).multiply(0.5))); ElectricityPylon otherPylon = BlockStorage.getAs(ElectricityPylon.class, connecting); assert otherPylon != null; - if (otherPylon.connectedPylons.containsKey(thisPos)) { + ElectricNode thisNode = getElectricNode(); + ElectricNode otherNode = otherPylon.getElectricNode(); + if (thisNode.isConnectedTo(otherNode)) { // disconnect if already connected display.remove(); - otherPylon.connectedPylons.remove(thisPos); - Objects.requireNonNull(Bukkit.getEntity(connectedPylons.remove(connecting))).remove(); + thisNode.disconnect(otherNode); } else { - otherPylon.connectedPylons.put(thisPos, display.getUniqueId()); - connectedPylons.put(connecting, display.getUniqueId()); + Location thisCenter = getBlock().getLocation().toCenterLocation(); + Location connectingLocation = connecting.getLocation().toCenterLocation(); + display.setTransformationMatrix(getDisplayTransform(thisCenter, connectingLocation)); + display.teleportAsync(thisCenter.add(connectingLocation.clone().subtract(thisCenter).multiply(0.5))); + thisNode.connect(otherNode); + connected.put(otherNode.getId(), display.getUniqueId()); + otherPylon.connected.put(thisNode.getId(), display.getUniqueId()); } playerPdc.remove(CONNECTING_KEY); playerPdc.remove(CONNECTING_ID_KEY); @@ -182,6 +192,10 @@ private void onPlayerQuit(PlayerQuitEvent event) { pdc.remove(CONNECTING_ID_KEY); } + private ElectricNode getElectricNode() { + return getElectricNodes().getFirst(); + } + private static Matrix4f getDisplayTransform(Location from, Location to) { return new TransformBuilder() .lookAlong(from, to) From ab607f6d47a660d07c330e0d558e7504b4d97fb2 Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 17 Mar 2026 10:21:03 -0400 Subject: [PATCH 04/33] Add creative power source and generify number input --- .../io/github/pylonmc/pylon/PylonBlocks.java | 2 + .../io/github/pylonmc/pylon/PylonItems.java | 7 + .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../electricity/CreativePowerSource.java | 100 ++++++++++++++ .../machines/cargo/CargoAccumulator.java | 42 ++---- .../machines/cargo/CargoFluidAccumulator.java | 83 ++++-------- .../content/machines/cargo/CargoGate.java | 42 ++---- .../content/machines/cargo/CargoMeter.java | 45 ++----- .../machines/fluid/FluidAccumulator.java | 47 ++----- .../content/machines/fluid/FluidLimiter.java | 43 ++---- .../content/machines/fluid/FluidMeter.java | 45 ++----- .../pylonmc/pylon/util/NumberInputButton.java | 123 ++++++++++++++++++ src/main/resources/lang/en.yml | 67 +++++----- 13 files changed, 364 insertions(+), 283 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java create mode 100644 src/main/java/io/github/pylonmc/pylon/util/NumberInputButton.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index abc750323..920899a0b 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -3,6 +3,7 @@ import io.github.pylonmc.pylon.content.assembling.AssemblyTable; import io.github.pylonmc.pylon.content.building.*; import io.github.pylonmc.pylon.content.components.*; +import io.github.pylonmc.pylon.content.electricity.CreativePowerSource; import io.github.pylonmc.pylon.content.electricity.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.cargo.*; import io.github.pylonmc.pylon.content.machines.diesel.machines.*; @@ -169,5 +170,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.COLLIMATOR, Material.OBSIDIAN, Collimator.class); RebarBlock.register(PylonKeys.COLLIMATOR_PILLAR, Material.DEEPSLATE_TILE_WALL, CollimatorPillar.class); RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); + RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index eb4232148..9f92802db 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -2902,6 +2902,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(ELECTRICITY_PYLON); } + public static final ItemStack CREATIVE_POWER_SOURCE = ItemStackBuilder.rebar(Material.PINK_STAINED_GLASS, PylonKeys.CREATIVE_POWER_SOURCE) + .build(); + static { + RebarItem.register(RebarItem.class, CREATIVE_POWER_SOURCE, PylonKeys.CREATIVE_POWER_SOURCE); + PylonPages.CREATIVE_ITEMS.addItem(CREATIVE_POWER_SOURCE); + } + static { PylonPages.initialise(); PylonGuides.initialise(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index b0bc2deb4..a7c366e38 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -439,4 +439,5 @@ public class PylonKeys { public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); + public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java new file mode 100644 index 000000000..c7085cab4 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java @@ -0,0 +1,100 @@ +package io.github.pylonmc.pylon.content.electricity; + +import io.github.pylonmc.pylon.util.NumberInputButton; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarGuiBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.unit.MetricPrefix; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.gui.Gui; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public final class CreativePowerSource extends RebarBlock implements + RebarElectricBlock.Producer, + RebarGuiBlock { + + private static final NamespacedKey VOLTAGE_KEY = pylonKey("voltage"); + private static final NamespacedKey POWER_KEY = pylonKey("power"); + + private int voltage; + private int power; + + @SuppressWarnings("unused") + public CreativePowerSource(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + voltage = 0; + power = 0; + + createElectricNode(block.getLocation().toCenterLocation(), ElectricNode.Type.PRODUCER); + } + + @SuppressWarnings({"unused", "DataFlowIssue"}) + public CreativePowerSource(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + + voltage = pdc.get(VOLTAGE_KEY, RebarSerializers.INTEGER); + power = pdc.get(POWER_KEY, RebarSerializers.INTEGER); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(VOLTAGE_KEY, RebarSerializers.INTEGER, voltage); + pdc.set(POWER_KEY, RebarSerializers.INTEGER, power); + } + + @Override + public double getVoltage() { + return voltage; + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure("# # # v # p # # #") + .addIngredient('#', GuiItems.background()) + .addIngredient('v', NumberInputButton.builder() + .material(Material.REDSTONE) + .name(Component.translatable("pylon.gui.voltage")) + .increment(1) + .shiftIncrement(10) + .min(0) + .valueGetter(() -> voltage) + .valueSetter(value -> voltage = value) + .valueFormatter(v -> formatQuantity(UnitFormat.VOLTS, v)) + .reopenWindow(this::openWindow) + .build()) + .addIngredient('p', NumberInputButton.builder() + .material(Material.NETHER_STAR) + .name(Component.translatable("pylon.gui.power")) + .increment(1) + .shiftIncrement(10) + .min(0) + .valueGetter(() -> power) + .valueSetter(value -> power = value) + .valueFormatter(p -> formatQuantity(UnitFormat.WATTS, p)) + .reopenWindow(this::openWindow) + .build()) + .build(); + } + + private static ComponentLike formatQuantity(UnitFormat format, int quantity) { + return format.format(quantity) + .ignorePrefixes(MetricPrefix.DECI, MetricPrefix.DECA, MetricPrefix.HECTO) + .abbreviate(true) + .autoSelectPrefix() + .decimalPlaces(0); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoAccumulator.java b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoAccumulator.java index 3e649c705..7303e8406 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoAccumulator.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoAccumulator.java @@ -1,6 +1,7 @@ package io.github.pylonmc.pylon.content.machines.cargo; import com.google.common.base.Preconditions; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarCargoBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; @@ -26,17 +27,12 @@ import org.bukkit.block.Block; import org.bukkit.entity.BlockDisplay; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.util.Arrays; import java.util.List; @@ -66,8 +62,6 @@ public class CargoAccumulator extends RebarBlock implements .addCustomModelDataString(getKey() + ":input"); public final ItemStackBuilder outputStack = ItemStackBuilder.of(Material.RED_TERRACOTTA) .addCustomModelDataString(getKey() + ":output"); - public final ItemStackBuilder thresholdButtonStack = ItemStackBuilder.gui(Material.WHITE_CONCRETE, getKey() + "threshold_button") - .lore(Component.translatable("pylon.gui.threshold_button.lore")); public static class Item extends RebarItem { @@ -176,7 +170,17 @@ public void write(@NotNull PersistentDataContainer pdc) { .addIngredient('I', GuiItems.input()) .addIngredient('o', outputInventory) .addIngredient('O', GuiItems.output()) - .addIngredient('t', new ThresholdButton()) + .addIngredient('t', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.threshold")) + .increment(1) + .shiftIncrement(10) + .min(1) + .valueGetter(() -> threshold) + .valueSetter(value -> threshold = value) + .valueFormatter(UnitFormat.ITEMS::format) + .reopenWindow(this::openWindow) + .build()) .build(); } @@ -248,26 +252,4 @@ private void doTransfer() { .setBlock(Material.REDSTONE_LAMP.createBlockData("[lit=true]")); } } - - public class ThresholdButton extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NonNull Player viewer) { - return thresholdButtonStack - .name((Component.translatable("pylon.gui.threshold_button.name").arguments( - RebarArgument.of("threshold", threshold) - ))); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - if (clickType.isLeftClick()) { - threshold += 1; - } else { - threshold = Math.max(1, threshold - 1); - } - notifyWindows(); - doTransfer(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoFluidAccumulator.java b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoFluidAccumulator.java index f2ddc6325..e2c419caf 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoFluidAccumulator.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoFluidAccumulator.java @@ -1,6 +1,7 @@ package io.github.pylonmc.pylon.content.machines.cargo; import com.google.common.base.Preconditions; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.*; @@ -28,17 +29,12 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.util.Arrays; import java.util.List; @@ -76,10 +72,6 @@ public class CargoFluidAccumulator extends RebarBlock implements .addCustomModelDataString(getKey() + ":input"); public final ItemStackBuilder outputStack = ItemStackBuilder.of(Material.RED_TERRACOTTA) .addCustomModelDataString(getKey() + ":output"); - public final ItemStackBuilder itemThresholdButtonStack = ItemStackBuilder.gui(Material.WHITE_CONCRETE, getKey() + "item_threshold_button") - .lore(Component.translatable("pylon.gui.item_threshold_button.lore")); - public final ItemStackBuilder fluidThresholdButtonStack = ItemStackBuilder.gui(Material.WHITE_CONCRETE, getKey() + "fluid_threshold_button") - .lore(Component.translatable("pylon.gui.fluid_threshold_button.lore")); public static class Item extends RebarItem { @@ -162,7 +154,7 @@ public CargoFluidAccumulator(@NotNull Block block, @NotNull BlockCreateContext c allowFluidInputs = true; } - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "DataFlowIssue"}) public CargoFluidAccumulator(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); itemThreshold = pdc.get(ITEM_THRESHOLD_KEY, RebarSerializers.INTEGER); @@ -231,8 +223,30 @@ public boolean isAllowedFluid(@NotNull RebarFluid fluid) { .addIngredient('I', GuiItems.input()) .addIngredient('o', outputInventory) .addIngredient('O', GuiItems.output()) - .addIngredient('t', new ItemThresholdButton()) - .addIngredient('T', new FluidThresholdButton()) + .addIngredient('t', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.item-threshold")) + .increment(1) + .shiftIncrement(10) + .min(1) + .max(64) + .valueGetter(() -> itemThreshold) + .valueSetter(value -> itemThreshold = value) + .valueFormatter(UnitFormat.ITEMS::format) + .reopenWindow(this::openWindow) + .build()) + .addIngredient('T', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.fluid-threshold")) + .increment(10) + .shiftIncrement(100) + .min(10) + .max(fluidBuffer) + .valueGetter(() -> fluidThreshold) + .valueSetter(value -> fluidThreshold = value) + .valueFormatter(UnitFormat.MILLIBUCKETS::format) + .reopenWindow(this::openWindow) + .build()) .build(); } @@ -308,49 +322,4 @@ private void doTransfer() { allowFluidInputs = false; } } - - public class ItemThresholdButton extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player viewer) { - return itemThresholdButtonStack - .name((Component.translatable("pylon.gui.item_threshold_button.name").arguments( - RebarArgument.of("threshold", itemThreshold) - ))); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - if (clickType.isLeftClick()) { - itemThreshold += 1; - } else { - itemThreshold = Math.max(1, itemThreshold - 1); - } - notifyWindows(); - doTransfer(); - } - } - - public class FluidThresholdButton extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player viewer) { - return fluidThresholdButtonStack - .name((Component.translatable("pylon.gui.fluid_threshold_button.name").arguments( - RebarArgument.of("threshold", fluidThreshold) - ))); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - int amount = clickType.isShiftClick() ? 100 : 10; - if (clickType.isLeftClick()) { - fluidThreshold = Math.min(fluidBuffer, fluidThreshold + amount); - } else { - fluidThreshold = Math.min(fluidBuffer, Math.max(10, fluidThreshold - amount)); - } - notifyWindows(); - doTransfer(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoGate.java b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoGate.java index f308e8644..7ebcbc161 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoGate.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoGate.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.machines.cargo; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarCargoBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; @@ -28,17 +29,12 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.BlockDisplay; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.util.List; import java.util.Map; @@ -77,30 +73,6 @@ public class CargoGate extends RebarBlock implements .name(Component.translatable("pylon.gui.left")); public final ItemStackBuilder rightStack = ItemStackBuilder.gui(Material.LIGHT_BLUE_STAINED_GLASS_PANE, getKey() + "right") .name(Component.translatable("pylon.gui.right")); - public final ItemStackBuilder thresholdButtonStack = ItemStackBuilder.gui(Material.WHITE_CONCRETE, getKey() + "threshold_button") - .lore(Component.translatable("pylon.gui.threshold_button.lore")); - - public class ThresholdButton extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player viewer) { - return thresholdButtonStack - .name((Component.translatable("pylon.gui.threshold_button.name").arguments( - RebarArgument.of("threshold", threshold) - ))); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - if (clickType.isLeftClick()) { - threshold += 1; - } else { - threshold = Math.max(1, threshold - 1); - } - itemsRemaining = threshold; - notifyWindows(); - } - } public static class Item extends RebarItem { @@ -213,7 +185,17 @@ public void write(@NotNull PersistentDataContainer pdc) { .addIngredient('o', outputInventory) .addIngredient('R', rightStack) .addIngredient('r', rightInventory) - .addIngredient('t', new ThresholdButton()) + .addIngredient('t', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.threshold")) + .increment(1) + .shiftIncrement(10) + .min(1) + .valueGetter(() -> threshold) + .valueSetter(value -> threshold = value) + .valueFormatter(UnitFormat.ITEMS::format) + .reopenWindow(this::openWindow) + .build()) .build(); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoMeter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoMeter.java index 0032d9e75..902db512b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoMeter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/cargo/CargoMeter.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.machines.cargo; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.*; @@ -27,18 +28,13 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.entity.TextDisplay; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.time.Duration; import java.util.ArrayList; @@ -242,7 +238,18 @@ public void postInitialise() { ) .addIngredient('#', GuiItems.background()) .addIngredient('x', inventory) - .addIngredient('m', new MeasurementDurationItem()) + .addIngredient('m', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.measurement-duration")) + .increment(1) + .shiftIncrement(10) + .min(minNumberOfMeasurements) + .max(maxNumberOfMeasurements) + .valueGetter(() -> numberOfMeasurements) + .valueSetter(value -> numberOfMeasurements = value) + .valueFormatter(value -> UnitFormat.formatDuration(getDuration(value), true, true)) + .reopenWindow(this::openWindow) + .build()) .build(); } @@ -278,30 +285,4 @@ public void tick() { public static Duration getDuration(int numberOfMeasurements) { return Duration.ofMillis((long) numberOfMeasurements * RebarConfig.CARGO_TICK_INTERVAL * 50); } - - public class MeasurementDurationItem extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player viewer) { - return ItemStackBuilder.of(Material.WHITE_CONCRETE) - .name(Component.translatable("pylon.gui.fluid_meter.name").arguments( - RebarArgument.of("measurement-duration", UnitFormat.formatDuration(getDuration(numberOfMeasurements), true, true)) - )) - .lore(Component.translatable("pylon.gui.fluid_meter.lore")); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - int newValue; - if (clickType.isLeftClick()) { - newValue = numberOfMeasurements + (clickType.isShiftClick() ? 10 : 1); - } else if (clickType.isRightClick()) { - newValue = numberOfMeasurements + (clickType.isShiftClick() ? -10 : -1); - } else { - newValue = numberOfMeasurements; - } - numberOfMeasurements = Math.clamp(newValue, minNumberOfMeasurements, maxNumberOfMeasurements); - notifyWindows(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidAccumulator.java b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidAccumulator.java index 0632003d7..34e4f92a4 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidAccumulator.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidAccumulator.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.machines.fluid; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; @@ -28,16 +29,11 @@ import org.bukkit.block.BlockFace; import org.bukkit.entity.BlockDisplay; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.util.List; @@ -155,7 +151,18 @@ public boolean isAllowedFluid(@NotNull RebarFluid fluid) { return Gui.builder() .setStructure("# # # # m # # # #") .addIngredient('#', GuiItems.background()) - .addIngredient('m', new AmountItem()) + .addIngredient('m', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.amount")) + .increment(10) + .shiftIncrement(100) + .min(minAmount) + .max(maxAmount) + .valueGetter(() -> (int) getFluidCapacity()) + .valueSetter(this::setCapacity) + .valueFormatter(UnitFormat.MILLIBUCKETS::format) + .reopenWindow(this::openWindow) + .build()) .build(); } @@ -196,32 +203,4 @@ public double fluidAmountRequested(@NotNull RebarFluid fluid) { return List.of(); } - - public class AmountItem extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NonNull Player player) { - return ItemStackBuilder.of(Material.WHITE_CONCRETE) - .name(Component.translatable("pylon.gui.fluid_accumulator.name").arguments( - RebarArgument.of("amount", UnitFormat.MILLIBUCKETS.format(getFluidCapacity())) - )) - .lore(Component.translatable("pylon.gui.fluid_accumulator.lore")); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - double delta = clickType.isShiftClick() ? 100 : 10; - double newAmount; - if (clickType.isLeftClick()) { - newAmount = getFluidCapacity() + delta; - } else if (clickType.isRightClick()) { - newAmount = getFluidCapacity() - delta; - } else { - newAmount = getFluidCapacity(); - } - newAmount = Math.clamp(newAmount, minAmount, maxAmount); - setCapacity(newAmount); - notifyWindows(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidLimiter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidLimiter.java index dacf80d34..e2a90021f 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidLimiter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidLimiter.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.machines.fluid; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; @@ -25,16 +26,11 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.util.List; @@ -156,31 +152,18 @@ public double fluidAmountRequested(@NotNull RebarFluid fluid) { return Gui.builder() .setStructure("# # # # m # # # #") .addIngredient('#', GuiItems.background()) - .addIngredient('m', new MaxFlowRateItem()) + .addIngredient('m', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.max-flow-rate")) + .increment(10) + .shiftIncrement(100) + .min(minAmount) + .max(maxAmount) + .valueGetter(() -> maxFlowRate) + .valueSetter(value -> maxFlowRate = value) + .valueFormatter(UnitFormat.MILLIBUCKETS_PER_SECOND::format) + .reopenWindow(this::openWindow) + .build()) .build(); } - - public class MaxFlowRateItem extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player player) { - return ItemStackBuilder.of(Material.WHITE_CONCRETE) - .name(Component.translatable("pylon.gui.fluid_accumulator.name").arguments( - RebarArgument.of("amount", UnitFormat.MILLIBUCKETS_PER_SECOND.format(maxFlowRate)) - )) - .lore(Component.translatable("pylon.gui.fluid_accumulator.lore")); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - int delta = clickType.isShiftClick() ? 100 : 10; - if (clickType.isLeftClick()) { - maxFlowRate += delta; - } else if (clickType.isRightClick()) { - maxFlowRate -= delta; - } - maxFlowRate = Math.clamp(maxFlowRate, minAmount, maxAmount); - notifyWindows(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidMeter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidMeter.java index 6d070c4b0..0bc89f30b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidMeter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/FluidMeter.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.machines.fluid; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; @@ -32,17 +33,12 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.entity.TextDisplay; -import org.bukkit.event.inventory.ClickType; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; -import org.jspecify.annotations.NonNull; -import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.item.AbstractItem; -import xyz.xenondevs.invui.item.ItemProvider; import java.time.Duration; import java.util.ArrayList; @@ -186,7 +182,18 @@ public void write(@NotNull PersistentDataContainer pdc) { return Gui.builder() .setStructure("# # # # m # # # #") .addIngredient('#', GuiItems.background()) - .addIngredient('m', new MeasurementDurationItem()) + .addIngredient('m', NumberInputButton.builder() + .material(Material.WHITE_CONCRETE) + .name(Component.translatable("pylon.gui.measurement-duration")) + .increment(1) + .shiftIncrement(10) + .min(minNumberOfMeasurements) + .max(maxNumberOfMeasurements) + .valueGetter(() -> numberOfMeasurements) + .valueSetter(value -> numberOfMeasurements = value) + .valueFormatter(value -> UnitFormat.formatDuration(getDuration(value), true, true)) + .reopenWindow(this::openWindow) + .build()) .build(); } @@ -239,30 +246,4 @@ public boolean isAllowedFluid(@NotNull RebarFluid fluid) { public static Duration getDuration(int numberOfMeasurements) { return Duration.ofMillis((long) numberOfMeasurements * RebarConfig.FLUID_TICK_INTERVAL * 50); } - - public class MeasurementDurationItem extends AbstractItem { - - @Override - public @NonNull ItemProvider getItemProvider(@NotNull Player viewer) { - return ItemStackBuilder.of(Material.WHITE_CONCRETE) - .name(Component.translatable("pylon.gui.fluid_meter.name").arguments( - RebarArgument.of("measurement-duration", UnitFormat.formatDuration(getDuration(numberOfMeasurements), true, true)) - )) - .lore(Component.translatable("pylon.gui.fluid_meter.lore")); - } - - @Override - public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { - int newValue; - if (clickType.isLeftClick()) { - newValue = numberOfMeasurements + (clickType.isShiftClick() ? 10 : 1); - } else if (clickType.isRightClick()) { - newValue = numberOfMeasurements + (clickType.isShiftClick() ? -10 : -1); - } else { - newValue = numberOfMeasurements; - } - numberOfMeasurements = Math.clamp(newValue, minNumberOfMeasurements, maxNumberOfMeasurements); - notifyWindows(); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/util/NumberInputButton.java b/src/main/java/io/github/pylonmc/pylon/util/NumberInputButton.java new file mode 100644 index 000000000..3816bb629 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/util/NumberInputButton.java @@ -0,0 +1,123 @@ +package io.github.pylonmc.pylon.util; + +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.PlayerInput; +import lombok.Builder; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import xyz.xenondevs.invui.Click; +import xyz.xenondevs.invui.item.AbstractBoundItem; +import xyz.xenondevs.invui.item.ItemProvider; +import xyz.xenondevs.invui.window.Window; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.function.Supplier; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +@Builder +public class NumberInputButton extends AbstractBoundItem { + + private final Material material; + private final Component name; + + private final int increment; + private final int shiftIncrement; + + private final @Nullable Integer min; + private final @Nullable Integer max; + + private final Supplier valueGetter; + private final Consumer valueSetter; + + @lombok.Builder.Default + private final Function valueFormatter = Component::text; + + @lombok.Builder.Default + private final Consumer reopenWindow = _unused -> {}; + + @Override + public @NotNull ItemProvider getItemProvider(@NotNull Player viewer) { + int value = valueGetter.get(); + List lore = new ArrayList<>(); + lore.add(Component.translatable( + "pylon.gui.number-button.lore", + RebarArgument.of("increment", valueFormatter.apply(increment)), + RebarArgument.of("increment-shift", valueFormatter.apply(shiftIncrement)) + )); + if (min != null) { + lore.add(Component.translatable("pylon.gui.number-button.min", RebarArgument.of("min", valueFormatter.apply(min)))); + } + if (max != null) { + lore.add(Component.translatable("pylon.gui.number-button.max", RebarArgument.of("max", valueFormatter.apply(max)))); + } + return ItemStackBuilder.gui(material, pylonKey("number_input_button")) + .name(Component.translatable( + "pylon.gui.number-button.name", + RebarArgument.of("name", name), + RebarArgument.of("value", valueFormatter.apply(value)) + )) + .lore(lore); + } + + private void setValue(int value) { + if (min != null) { + value = Math.max(value, min); + } + if (max != null) { + value = Math.min(value, max); + } + valueSetter.accept(value); + notifyWindows(); + } + + @Override + public void handleClick(@NotNull ClickType clickType, @NotNull Player player, @NotNull Click click) { + int value = valueGetter.get(); + int increment = clickType.isShiftClick() ? shiftIncrement : this.increment; + if (clickType == ClickType.DROP) { + String key; + if (min != null && max != null) { + key = "pylon.gui.number-button.enter-value.both"; + } else if (min != null) { + key = "pylon.gui.number-button.enter-value.min"; + } else if (max != null) { + key = "pylon.gui.number-button.enter-value.max"; + } else { + key = "pylon.gui.number-button.enter-value.none"; + } + Window window = getGui().getWindows().stream().filter(w -> w.getViewer().equals(player)).findAny().orElseThrow(); + window.close(); + player.sendMessage(Component.translatable( + key, + RebarArgument.of("min", min != null ? Component.text(min) : Component.empty()), + RebarArgument.of("max", max != null ? Component.text(max) : Component.empty()) + )); + PlayerInput.requestInput(player).thenAccept(input -> { + if (input == null) return; + try { + int newValue = Integer.parseInt(input); + setValue(newValue); + reopenWindow.accept(player); + } catch (NumberFormatException e) { + player.sendMessage(Component.translatable("pylon.gui.number-button.enter-value.invalid")); + } + }); + return; + } else if (clickType.isLeftClick()) { + value += increment; + } else if (clickType.isRightClick()) { + value -= increment; + } + setValue(value); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index aa176ca16..b302630c7 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2232,6 +2232,11 @@ item: lore: |- TODO + creative_power_source: + name: "<#ff00ff>Creative Power Source" + lore: |- + Provides an infinite supply of power + fluid: castable: display-text: " Casts into %result%" @@ -2547,23 +2552,6 @@ gui: lore: |- The will always send items to this side unless it's full Left click to cycle priority - threshold_button: - name: "Threshold: %threshold%" - lore: |- - Left click to increase - Right click to decrease - item_threshold_button: - name: "Item Threshold: %threshold%" - lore: |- - Left click to increase - Right click to decrease - fluid_threshold_button: - name: "Fluid Threshold: %threshold%" - lore: |- - Left click to increase by 10 - Right click to decrease by 10 - Shift left click to increase by 100 - Shift right click to decrease by 100 whitelist-blacklist-toggle: whitelist: name: "Whitelist mode" @@ -2626,27 +2614,6 @@ gui: name: "Current inventory: %inventory%" lore: |- Click to cycle - fluid_meter: - name: "Measurement duration: %measurement-duration%" - lore: |- - Left click to increase - Right click to decrease - Shift left click to increase (10x) - Shift right click to decrease (10x) - fluid_accumulator: - name: "Amount: %amount%" - lore: |- - Left click to increase - Right click to decrease - Shift left click to increase (10x) - Shift right click to decrease (10x) - fluid_limiter: - name: "Max flow rate: %max-flow-rate%" - lore: |- - Left click to increase - Right click to decrease - Shift left click to increase (10x) - Shift right click to decrease (10x) assembly_table: step: "<#adc5ce>Step %step_index%: %tool% (x%clicks%)" no_recipe: "No recipe" @@ -2655,6 +2622,30 @@ gui: hammer: "Hammer" screwdriver: "Screwdriver" redstone_soldering_iron: "Redstone Soldering Iron" + number-button: + name: "%name%: %value%" + lore: |- + Left click to increase by %increment% + Right click to decrease by %increment% + Shift left click to increase by %increment-shift% + Shift right click to decrease by %increment-shift% + Press to enter the value manually + min: " Minimum value: %min%" + max: " Maximum value: %max%" + enter-value: + none: "Enter a new value:" + min: "Enter a new value (min: %min%):" + max: "Enter a new value (max: %max%):" + both: "Enter a new value (min: %min%, max: %max%):" + invalid: "Invalid input, please enter an integer" + voltage: "Voltage" + power: "Power" + max-flow-rate: "Max flow rate" + amount: "Amount" + measurement-duration: "Measurement duration" + threshold: "Threshold" + item-threshold: "Item threshold" + fluid-threshold: "Fluid threshold" inventory: fuel: "Fuel" From 45e9dc701390975812dcc14dbb18540f3023eb95 Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 17 Mar 2026 13:47:46 -0400 Subject: [PATCH 05/33] Allow electricity pylon to connect to any electricity block --- .../java/io/github/pylonmc/pylon/Pylon.java | 2 + .../content/electricity/ElectricityPylon.java | 160 ++++++++---------- src/main/resources/lang/en.yml | 2 + 3 files changed, 79 insertions(+), 85 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/Pylon.java b/src/main/java/io/github/pylonmc/pylon/Pylon.java index 6ae8a6ef0..ef00c690f 100644 --- a/src/main/java/io/github/pylonmc/pylon/Pylon.java +++ b/src/main/java/io/github/pylonmc/pylon/Pylon.java @@ -2,6 +2,7 @@ import io.github.pylonmc.pylon.command.PylonCommand; import io.github.pylonmc.pylon.content.building.Immobilizer; +import io.github.pylonmc.pylon.content.electricity.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.fluid.Sprinkler; import io.github.pylonmc.pylon.content.machines.simple.Grindstone; import io.github.pylonmc.pylon.content.machines.smelting.Bloomery; @@ -71,6 +72,7 @@ public void onEnable() { pm.registerEvents(new EnchantingTalisman.EnchantingListener(), this); pm.registerEvents(new HuntingTalisman.HuntingTalismanListener(), this); pm.registerEvents(new ExperienceTalisman.XPTalismanListener(), this); + pm.registerEvents(new ElectricityPylon.InteractionListener(), this); RebarRegistry.RESEARCHES.mapKey(pylonKey("simple_components"), pylonKey("components_1")); RebarRegistry.RESEARCHES.mapKey(pylonKey("scientific_revolution_4"), pylonKey("scientific_revolution_3")); diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java index bbfd6a3dc..1812eccc8 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -5,7 +5,7 @@ import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarBreakHandler; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; -import io.github.pylonmc.rebar.block.base.RebarInteractBlock; +import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; import io.github.pylonmc.rebar.block.base.RebarTickingBlock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; @@ -13,55 +13,43 @@ import io.github.pylonmc.rebar.electricity.ElectricNode; import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; -import io.github.pylonmc.rebar.event.api.annotation.MultiHandler; import io.github.pylonmc.rebar.util.position.BlockPosition; +import net.kyori.adventure.text.Component; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.event.Event; import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.persistence.PersistentDataType; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.*; +import java.util.List; +import java.util.Objects; import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class ElectricityPylon extends RebarBlock implements - RebarInteractBlock, RebarBreakHandler, Listener, RebarElectricBlock, - RebarTickingBlock { + RebarTickingBlock, + RebarEntityHolderBlock { private static final NamespacedKey CONNECTING_KEY = pylonKey("connecting"); private static final NamespacedKey CONNECTING_ID_KEY = pylonKey("connecting_id"); - private static final NamespacedKey CONNECTED_KEY = pylonKey("connected"); - private static final PersistentDataType> CONNECTED_TYPE = RebarSerializers.MAP.mapTypeFrom( - RebarSerializers.UUID, - RebarSerializers.UUID - ); - - private final Map connected; - @SuppressWarnings("unused") public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - connected = new HashMap<>(); - setTickInterval(10); createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONNECTOR); } @@ -69,31 +57,20 @@ public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext contex @SuppressWarnings("unused") public ElectricityPylon(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); - connected = pdc.get(CONNECTED_KEY, CONNECTED_TYPE); } @Override public void postInitialise() { Bukkit.getPluginManager().registerEvents(this, Pylon.getInstance()); - getElectricNode().onDisconnect((thisNode, otherNode) -> { - UUID displayId = connected.remove(otherNode.getId()); - if (displayId == null) return; - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(displayId); - if (display != null) display.remove(); - }); - } - - @Override - public void write(@NotNull PersistentDataContainer pdc) { - super.write(pdc); - pdc.set(CONNECTED_KEY, CONNECTED_TYPE, connected); + getElectricNode().onDisconnect((thisNode, otherNode) -> tryRemoveEntity(otherNode.getId().toString())); } @Override public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { PlayerMoveEvent.getHandlerList().unregister(this); PlayerQuitEvent.getHandlerList().unregister(this); + PlayerInteractEvent.getHandlerList().unregister(this); } @Override @@ -105,60 +82,6 @@ public void tick() { .spawn(); } - @Override - @MultiHandler(priorities = EventPriority.MONITOR) - public void onInteract(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) { - Player player = event.getPlayer(); - if (player.isSneaking() - || event.getHand() != EquipmentSlot.HAND - || event.getAction() != Action.RIGHT_CLICK_BLOCK - || event.useInteractedBlock() == Event.Result.DENY - ) return; - - BlockPosition thisPos = new BlockPosition(getBlock()); - PersistentDataContainer playerPdc = player.getPersistentDataContainer(); - BlockPosition connecting = playerPdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - if (connecting == null) { - Location blockLocation = getBlock().getLocation().toCenterLocation(); - Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); - ItemDisplay display = new ItemDisplayBuilder() - .transformation(getDisplayTransform(blockLocation, playerLocation)) - .material(Material.COPPER_BLOCK) - .build(blockLocation.add(playerLocation.subtract(blockLocation).multiply(0.5))); - playerPdc.set(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION, thisPos); - playerPdc.set(CONNECTING_ID_KEY, RebarSerializers.UUID, display.getUniqueId()); - } else if (connecting.equals(thisPos)) { - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - display.remove(); - playerPdc.remove(CONNECTING_KEY); - playerPdc.remove(CONNECTING_ID_KEY); - } else { - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - - ElectricityPylon otherPylon = BlockStorage.getAs(ElectricityPylon.class, connecting); - assert otherPylon != null; - ElectricNode thisNode = getElectricNode(); - ElectricNode otherNode = otherPylon.getElectricNode(); - if (thisNode.isConnectedTo(otherNode)) { - // disconnect if already connected - display.remove(); - thisNode.disconnect(otherNode); - } else { - Location thisCenter = getBlock().getLocation().toCenterLocation(); - Location connectingLocation = connecting.getLocation().toCenterLocation(); - display.setTransformationMatrix(getDisplayTransform(thisCenter, connectingLocation)); - display.teleportAsync(thisCenter.add(connectingLocation.clone().subtract(thisCenter).multiply(0.5))); - thisNode.connect(otherNode); - connected.put(otherNode.getId(), display.getUniqueId()); - otherPylon.connected.put(thisNode.getId(), display.getUniqueId()); - } - playerPdc.remove(CONNECTING_KEY); - playerPdc.remove(CONNECTING_ID_KEY); - } - } - @EventHandler private void onPlayerMove(PlayerMoveEvent event) { if (!event.hasChangedPosition()) return; @@ -202,4 +125,71 @@ private static Matrix4f getDisplayTransform(Location from, Location to) { .scale(0.05, 0.05, from.distance(to)) .buildForItemDisplay(); } + + private static Location getMidpoint(Location a, Location b) { + return a.clone().add(b).multiply(0.5); + } + + public static class InteractionListener implements Listener { + @EventHandler(ignoreCancelled = true) + private void onRightClickElectricBlock(PlayerInteractEvent event) { + if (event.getHand() != EquipmentSlot.HAND || event.useInteractedBlock() == Event.Result.DENY) return; + + Block clickedBlock = event.getClickedBlock(); + if (clickedBlock == null) return; + RebarElectricBlock electricBlock = BlockStorage.getAs(RebarElectricBlock.class, clickedBlock); + if (electricBlock == null) return; + + BlockPosition clickedPos = new BlockPosition(clickedBlock); + Player player = event.getPlayer(); + PersistentDataContainer playerPdc = player.getPersistentDataContainer(); + BlockPosition connecting = playerPdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + if (connecting == null) { + if (electricBlock instanceof ElectricityPylon && !player.isSneaking() && event.getAction().isRightClick()) { + Location connectionLocation = electricBlock.getElectricNodes().getFirst().getConnectionPoint(); + Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); + ItemDisplay display = new ItemDisplayBuilder() + .transformation(getDisplayTransform(connectionLocation, playerLocation)) + .material(Material.COPPER_BLOCK) + .build(getMidpoint(connectionLocation, playerLocation)); + playerPdc.set(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION, clickedPos); + playerPdc.set(CONNECTING_ID_KEY, RebarSerializers.UUID, display.getUniqueId()); + } + return; + } + + event.setUseInteractedBlock(Event.Result.DENY); + + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + if (connecting.equals(clickedPos)) { + display.remove(); + playerPdc.remove(CONNECTING_KEY); + playerPdc.remove(CONNECTING_ID_KEY); + return; + } + + ElectricityPylon connectingBlock = BlockStorage.getAsOrThrow(ElectricityPylon.class, connecting); + ElectricNode connectingNode = connectingBlock.getElectricNodes().getFirst(); + ElectricNode clickedNode = electricBlock.getElectricNodes().getFirst(); + if (!clickedNode.getConnections().isEmpty() && clickedNode.getType() != ElectricNode.Type.CONNECTOR) { + player.sendActionBar(Component.translatable("pylon.message.electricity_pylon.already_connected")); + return; + } + + if (connectingNode.isConnectedTo(clickedNode)) { + display.remove(); + connectingNode.disconnect(clickedNode); + } else { + Location connectingLocation = connectingNode.getConnectionPoint(); + Location clickedLocation = clickedNode.getConnectionPoint(); + display.setTransformationMatrix(getDisplayTransform(connectingLocation, clickedLocation)); + display.teleportAsync(getMidpoint(connectingLocation, clickedLocation)); + connectingNode.connect(clickedNode); + connectingBlock.addEntity(clickedNode.getId().toString(), display); + } + playerPdc.remove(CONNECTING_KEY); + playerPdc.remove(CONNECTING_ID_KEY); + } + } } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index b302630c7..0db0c0f0f 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2476,6 +2476,8 @@ guide: lore: "" message: + electricity_pylon: + already_connected: "This block is already connected to an electricity pylon" assembly_table: full: "Output full!" fluid_selector: From c256663cd1cc5ed4ff47b1cb4cea459203fd998e Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 17 Mar 2026 13:50:37 -0400 Subject: [PATCH 06/33] Don't need this no more --- .../pylonmc/pylon/content/electricity/ElectricityPylon.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java index 1812eccc8..40b086676 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -70,7 +70,6 @@ public void postInitialise() { public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { PlayerMoveEvent.getHandlerList().unregister(this); PlayerQuitEvent.getHandlerList().unregister(this); - PlayerInteractEvent.getHandlerList().unregister(this); } @Override From 883769d374f0d79fbe4b62900c199359848662e0 Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 17 Mar 2026 13:53:08 -0400 Subject: [PATCH 07/33] Move the listeners to listener class --- .../content/electricity/ElectricityPylon.java | 81 ++++++++----------- 1 file changed, 33 insertions(+), 48 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java index 40b086676..cb3feae16 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java @@ -1,13 +1,10 @@ package io.github.pylonmc.pylon.content.electricity; -import io.github.pylonmc.pylon.Pylon; import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarBreakHandler; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; import io.github.pylonmc.rebar.block.base.RebarTickingBlock; -import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.datatypes.RebarSerializers; import io.github.pylonmc.rebar.electricity.ElectricNode; @@ -26,19 +23,15 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; import org.bukkit.inventory.EquipmentSlot; -import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.List; import java.util.Objects; import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class ElectricityPylon extends RebarBlock implements - RebarBreakHandler, - Listener, RebarElectricBlock, RebarTickingBlock, RebarEntityHolderBlock { @@ -61,17 +54,9 @@ public ElectricityPylon(@NotNull Block block, @NotNull PersistentDataContainer p @Override public void postInitialise() { - Bukkit.getPluginManager().registerEvents(this, Pylon.getInstance()); - getElectricNode().onDisconnect((thisNode, otherNode) -> tryRemoveEntity(otherNode.getId().toString())); } - @Override - public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { - PlayerMoveEvent.getHandlerList().unregister(this); - PlayerQuitEvent.getHandlerList().unregister(this); - } - @Override public void tick() { Particle.DUST.builder() @@ -81,39 +66,6 @@ public void tick() { .spawn(); } - @EventHandler - private void onPlayerMove(PlayerMoveEvent event) { - if (!event.hasChangedPosition()) return; - Player player = event.getPlayer(); - PersistentDataContainer pdc = player.getPersistentDataContainer(); - if (!pdc.has(CONNECTING_KEY)) return; - BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - assert connecting != null; - Location connectingLocation = connecting.getLocation().toCenterLocation(); - Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - display.setTeleportDuration(1); - display.setInterpolationDelay(0); - display.setInterpolationDuration(1); - display.setTransformationMatrix(getDisplayTransform(connectingLocation, playerLocation)); - display.teleportAsync(connectingLocation.add(playerLocation.clone().subtract(connectingLocation).multiply(0.5))); - } - - @EventHandler - private void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - PersistentDataContainer pdc = player.getPersistentDataContainer(); - if (!pdc.has(CONNECTING_KEY)) return; - BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - assert connecting != null; - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - display.remove(); - pdc.remove(CONNECTING_KEY); - pdc.remove(CONNECTING_ID_KEY); - } - private ElectricNode getElectricNode() { return getElectricNodes().getFirst(); } @@ -190,5 +142,38 @@ private void onRightClickElectricBlock(PlayerInteractEvent event) { playerPdc.remove(CONNECTING_KEY); playerPdc.remove(CONNECTING_ID_KEY); } + + @EventHandler + private void onPlayerQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + PersistentDataContainer pdc = player.getPersistentDataContainer(); + if (!pdc.has(CONNECTING_KEY)) return; + BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + assert connecting != null; + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + display.remove(); + pdc.remove(CONNECTING_KEY); + pdc.remove(CONNECTING_ID_KEY); + } + + @EventHandler + private void onPlayerMove(PlayerMoveEvent event) { + if (!event.hasChangedPosition()) return; + Player player = event.getPlayer(); + PersistentDataContainer pdc = player.getPersistentDataContainer(); + if (!pdc.has(CONNECTING_KEY)) return; + BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); + assert connecting != null; + Location connectingLocation = connecting.getLocation().toCenterLocation(); + Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); + ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); + assert display != null; + display.setTeleportDuration(1); + display.setInterpolationDelay(0); + display.setInterpolationDuration(1); + display.setTransformationMatrix(getDisplayTransform(connectingLocation, playerLocation)); + display.teleportAsync(connectingLocation.add(playerLocation.clone().subtract(connectingLocation).multiply(0.5))); + } } } From 4defe3606371dba9e0c634ba870b090ef529103f Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 17 Mar 2026 15:21:10 -0400 Subject: [PATCH 08/33] Skeleton electric grindstone --- .../java/io/github/pylonmc/pylon/Pylon.java | 2 +- .../io/github/pylonmc/pylon/PylonBlocks.java | 6 +- .../io/github/pylonmc/pylon/PylonItems.java | 8 ++ .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../diesel/machines/DieselGrindstone.java | 108 ++-------------- .../electric}/CreativePowerSource.java | 2 +- .../machines/electric/ElectricGrindstone.java | 67 ++++++++++ .../electric}/ElectricityPylon.java | 2 +- .../machines/generic/AbstractGrindstone.java | 122 ++++++++++++++++++ src/main/resources/lang/en.yml | 7 + .../settings/electric_grindstone.yml | 5 + 11 files changed, 225 insertions(+), 105 deletions(-) rename src/main/java/io/github/pylonmc/pylon/content/{electricity => machines/electric}/CreativePowerSource.java (98%) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java rename src/main/java/io/github/pylonmc/pylon/content/{electricity => machines/electric}/ElectricityPylon.java (99%) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java create mode 100644 src/main/resources/settings/electric_grindstone.yml diff --git a/src/main/java/io/github/pylonmc/pylon/Pylon.java b/src/main/java/io/github/pylonmc/pylon/Pylon.java index ef00c690f..bf805b295 100644 --- a/src/main/java/io/github/pylonmc/pylon/Pylon.java +++ b/src/main/java/io/github/pylonmc/pylon/Pylon.java @@ -2,7 +2,7 @@ import io.github.pylonmc.pylon.command.PylonCommand; import io.github.pylonmc.pylon.content.building.Immobilizer; -import io.github.pylonmc.pylon.content.electricity.ElectricityPylon; +import io.github.pylonmc.pylon.content.machines.electric.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.fluid.Sprinkler; import io.github.pylonmc.pylon.content.machines.simple.Grindstone; import io.github.pylonmc.pylon.content.machines.smelting.Bloomery; diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 920899a0b..bf8e1c5a9 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -3,12 +3,13 @@ import io.github.pylonmc.pylon.content.assembling.AssemblyTable; import io.github.pylonmc.pylon.content.building.*; import io.github.pylonmc.pylon.content.components.*; -import io.github.pylonmc.pylon.content.electricity.CreativePowerSource; -import io.github.pylonmc.pylon.content.electricity.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.cargo.*; import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; +import io.github.pylonmc.pylon.content.machines.electric.CreativePowerSource; +import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; +import io.github.pylonmc.pylon.content.machines.electric.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -171,5 +172,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.COLLIMATOR_PILLAR, Material.DEEPSLATE_TILE_WALL, CollimatorPillar.class); RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); + RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 9f92802db..15ba6048e 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -15,6 +15,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; +import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -2909,6 +2910,13 @@ private PylonItems() { PylonPages.CREATIVE_ITEMS.addItem(CREATIVE_POWER_SOURCE); } + public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) + .build(); + static { + RebarItem.register(ElectricGrindstone.Item.class, ELECTRIC_GRINDSTONE, PylonKeys.ELECTRIC_GRINDSTONE); + PylonPages.ELECTRICITY.addItem(ELECTRIC_GRINDSTONE); + } + static { PylonPages.initialise(); PylonGuides.initialise(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index a7c366e38..db1fc4f96 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -440,4 +440,5 @@ public class PylonKeys { public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); + public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java index efa661539..93e8a5140 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java @@ -2,11 +2,10 @@ import com.destroystokyo.paper.ParticleBuilder; import io.github.pylonmc.pylon.PylonFluids; -import io.github.pylonmc.pylon.content.machines.simple.Grindstone; -import io.github.pylonmc.pylon.recipes.GrindstoneRecipe; +import io.github.pylonmc.pylon.content.machines.generic.AbstractGrindstone; import io.github.pylonmc.pylon.util.PylonUtils; -import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; +import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; @@ -17,11 +16,7 @@ import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; -import io.github.pylonmc.rebar.logistics.LogisticGroupType; -import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.RebarUtils; -import io.github.pylonmc.rebar.util.gui.GuiItems; -import io.github.pylonmc.rebar.util.gui.ProgressItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; import net.kyori.adventure.text.format.TextColor; @@ -38,32 +33,20 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; -import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.inventory.VirtualInventory; import java.util.List; -import java.util.Map; import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; -public class DieselGrindstone extends RebarBlock implements - RebarGuiBlock, - RebarVirtualInventoryBlock, +public class DieselGrindstone extends AbstractGrindstone implements RebarFluidBufferBlock, - RebarDirectionalBlock, - RebarTickingBlock, - RebarLogisticBlock, - RebarRecipeProcessor { + RebarDirectionalBlock { public static final NamespacedKey STONE_ROTATION_KEY = pylonKey("stone_rotation"); public final double dieselPerSecond = getSettings().getOrThrow("diesel-per-second", ConfigAdapter.DOUBLE); public final double dieselBuffer = getSettings().getOrThrow("diesel-buffer", ConfigAdapter.DOUBLE); - public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); - - private final VirtualInventory inputInventory = new VirtualInventory(1); - private final VirtualInventory outputInventory = new VirtualInventory(3); private double stoneRotation; public static class Item extends RebarItem { @@ -96,7 +79,7 @@ public Item(@NotNull ItemStack stack) { @SuppressWarnings("unused") public DieselGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - setTickInterval(tickInterval); + createFluidPoint(FluidPointType.INPUT, BlockFace.NORTH, context, false, 0.55F); setFacing(context.getFacing()); addEntity("chimney", new ItemDisplayBuilder() @@ -128,12 +111,10 @@ public DieselGrindstone(@NotNull Block block, @NotNull BlockCreateContext contex .build(block.getLocation().toCenterLocation().add(0, 0.5, 0)) ); createFluidBuffer(PylonFluids.BIODIESEL, dieselBuffer, true, false); - setRecipeType(GrindstoneRecipe.RECIPE_TYPE); - setRecipeProgressItem(new ProgressItem(GuiItems.background())); stoneRotation = 0; } - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "DataFlowIssue"}) public DieselGrindstone(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); stoneRotation = pdc.get(STONE_ROTATION_KEY, RebarSerializers.DOUBLE); @@ -144,19 +125,6 @@ public void write(@NotNull PersistentDataContainer pdc) { pdc.set(STONE_ROTATION_KEY, RebarSerializers.DOUBLE, stoneRotation); } - @Override - public void postInitialise() { - createLogisticGroup("input", LogisticGroupType.INPUT, inputInventory); - createLogisticGroup("output", LogisticGroupType.OUTPUT, outputInventory); - outputInventory.addPreUpdateHandler(RebarUtils.DISALLOW_PLAYERS_FROM_ADDING_ITEMS_HANDLER); - outputInventory.addPostUpdateHandler(event -> tryStartRecipe()); - inputInventory.addPostUpdateHandler(event -> { - if (!(event.getUpdateReason() instanceof MachineUpdateReason)) { - tryStartRecipe(); - } - }); - } - @Override public void tick() { if (!isProcessingRecipe() || fluidAmount(PylonFluids.BIODIESEL) < dieselPerSecond * tickInterval / 20) { @@ -186,58 +154,6 @@ public void tick() { ); } - public void tryStartRecipe() { - if (isProcessingRecipe()) { - return; - } - - ItemStack stack = inputInventory.getItem(0); - if (stack == null) { - return; - } - - recipeLoop: - for (GrindstoneRecipe recipe : GrindstoneRecipe.RECIPE_TYPE) { - if (!recipe.input().matches(stack)) { - continue; - } - - for (ItemStack output : recipe.results().getElements()) { - if (!outputInventory.canHold(output)) { - break recipeLoop; - } - } - - startRecipe(recipe, recipe.cycles() * Grindstone.CYCLE_DURATION_TICKS); - getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); - inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); - break; - } - } - - @Override - public void onRecipeFinished(@NotNull GrindstoneRecipe recipe) { - getRecipeProgressItem().setItem(GuiItems.background()); - outputInventory.addItem(null, recipe.results().getRandom()); - } - - @Override - public @NotNull Gui createGui() { - return Gui.builder() - .setStructure( - "# I # # # O O O #", - "# i # p # o o o #", - "# I # # # O O O #" - ) - .addIngredient('#', GuiItems.background()) - .addIngredient('I', GuiItems.input()) - .addIngredient('i', inputInventory) - .addIngredient('O', GuiItems.output()) - .addIngredient('o', outputInventory) - .addIngredient('p', getRecipeProgressItem()) - .build(); - } - @Override public @Nullable WailaDisplay getWaila(@NotNull Player player) { return new WailaDisplay(getDefaultWailaTranslationKey().arguments( @@ -252,15 +168,7 @@ public void onRecipeFinished(@NotNull GrindstoneRecipe recipe) { @Override public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { - RebarVirtualInventoryBlock.super.onBreak(drops, context); + super.onBreak(drops, context); RebarFluidBufferBlock.super.onBreak(drops, context); } - - @Override - public @NotNull Map getVirtualInventories() { - return Map.of( - "input", inputInventory, - "output", outputInventory - ); - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java similarity index 98% rename from src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index c7085cab4..afb6ea9f9 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.electricity; +package io.github.pylonmc.pylon.content.machines.electric; import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java new file mode 100644 index 000000000..bd34f9ec5 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -0,0 +1,67 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.content.machines.generic.AbstractGrindstone; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import it.unimi.dsi.fastutil.doubles.DoubleDoublePair; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + +public class ElectricGrindstone extends AbstractGrindstone implements + RebarElectricBlock.Consumer { + + public static class Item extends RebarItem { + + public final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + public final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); + public final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); + + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of( + RebarArgument.of("power-usage", UnitFormat.WATTS.format(powerUsage)), + RebarArgument.of("min-voltage", UnitFormat.VOLTS.format(voltageMin)), + RebarArgument.of("max-voltage", UnitFormat.VOLTS.format(voltageMax)) + ); + } + } + + public final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + public final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); + public final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); + + @SuppressWarnings("unused") + public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONSUMER); + } + + @SuppressWarnings("unused") + public ElectricGrindstone(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public @NotNull DoubleDoublePair getVoltageRange() { + return DoubleDoublePair.of(voltageMin, voltageMax); + } + + @Override + public void tick() { + + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java similarity index 99% rename from src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java index cb3feae16..b2de5e6d8 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/electricity/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.electricity; +package io.github.pylonmc.pylon.content.machines.electric; import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java new file mode 100644 index 000000000..0410a90c6 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java @@ -0,0 +1,122 @@ +package io.github.pylonmc.pylon.content.machines.generic; + +import io.github.pylonmc.pylon.content.machines.simple.Grindstone; +import io.github.pylonmc.pylon.recipes.GrindstoneRecipe; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.logistics.LogisticGroupType; +import io.github.pylonmc.rebar.util.MachineUpdateReason; +import io.github.pylonmc.rebar.util.RebarUtils; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.ProgressItem; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.gui.Gui; +import xyz.xenondevs.invui.inventory.VirtualInventory; + +import java.util.Map; + +public abstract class AbstractGrindstone extends RebarBlock implements + RebarGuiBlock, + RebarVirtualInventoryBlock, + RebarTickingBlock, + RebarLogisticBlock, + RebarRecipeProcessor { + + public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + + private final VirtualInventory inputInventory = new VirtualInventory(1); + private final VirtualInventory outputInventory = new VirtualInventory(3); + + @SuppressWarnings("unused") + public AbstractGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + setTickInterval(tickInterval); + setRecipeType(GrindstoneRecipe.RECIPE_TYPE); + setRecipeProgressItem(new ProgressItem(GuiItems.background())); + } + + @SuppressWarnings("unused") + public AbstractGrindstone(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void postInitialise() { + createLogisticGroup("input", LogisticGroupType.INPUT, inputInventory); + createLogisticGroup("output", LogisticGroupType.OUTPUT, outputInventory); + outputInventory.addPreUpdateHandler(RebarUtils.DISALLOW_PLAYERS_FROM_ADDING_ITEMS_HANDLER); + outputInventory.addPostUpdateHandler(event -> tryStartRecipe()); + inputInventory.addPostUpdateHandler(event -> { + if (!(event.getUpdateReason() instanceof MachineUpdateReason)) { + tryStartRecipe(); + } + }); + } + + private void tryStartRecipe() { + if (isProcessingRecipe()) { + return; + } + + ItemStack stack = inputInventory.getItem(0); + if (stack == null) { + return; + } + + recipeLoop: + for (GrindstoneRecipe recipe : GrindstoneRecipe.RECIPE_TYPE) { + if (!recipe.input().matches(stack)) { + continue; + } + + for (ItemStack output : recipe.results().getElements()) { + if (!outputInventory.canHold(output)) { + break recipeLoop; + } + } + + startRecipe(recipe, recipe.cycles() * Grindstone.CYCLE_DURATION_TICKS); + getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); + inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); + break; + } + } + + @Override + public void onRecipeFinished(@NotNull GrindstoneRecipe recipe) { + getRecipeProgressItem().setItem(GuiItems.background()); + outputInventory.addItem(null, recipe.results().getRandom()); + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure( + "# I # # # O O O #", + "# i # p # o o o #", + "# I # # # O O O #" + ) + .addIngredient('#', GuiItems.background()) + .addIngredient('I', GuiItems.input()) + .addIngredient('i', inputInventory) + .addIngredient('O', GuiItems.output()) + .addIngredient('o', outputInventory) + .addIngredient('p', getRecipeProgressItem()) + .build(); + } + + @Override + public @NotNull Map getVirtualInventories() { + return Map.of( + "input", inputInventory, + "output", outputInventory + ); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 0db0c0f0f..756d924f3 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2237,6 +2237,13 @@ item: lore: |- Provides an infinite supply of power + electric_grindstone: + name: "Electric Grindstone" + lore: |- + Grinds items using electricity + Power usage: %power-usage% + Voltage range: %min-voltage% to %max-voltage% + fluid: castable: display-text: " Casts into %result%" diff --git a/src/main/resources/settings/electric_grindstone.yml b/src/main/resources/settings/electric_grindstone.yml new file mode 100644 index 000000000..19fb0ba6f --- /dev/null +++ b/src/main/resources/settings/electric_grindstone.yml @@ -0,0 +1,5 @@ +power-usage: 20 +voltage-range: + min: 50 + max: 200 +tick-interval: 10 \ No newline at end of file From 83a6597ce00a1bd9b95499ee18486a0eb063fc85 Mon Sep 17 00:00:00 2001 From: Seggan Date: Mon, 13 Apr 2026 11:55:35 -0400 Subject: [PATCH 09/33] Slightly broken but ok --- .../electric/CreativePowerSource.java | 25 ++++++---- .../machines/electric/ElectricGrindstone.java | 29 +++++++---- .../machines/electric/ElectricityPylon.java | 49 ++++++++++++------- 3 files changed, 65 insertions(+), 38 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index afb6ea9f9..79fde47a6 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -1,5 +1,16 @@ package io.github.pylonmc.pylon.content.machines.electric; +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; + +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; @@ -10,17 +21,8 @@ import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.unit.MetricPrefix; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.ComponentLike; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.block.Block; -import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.NotNull; import xyz.xenondevs.invui.gui.Gui; -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - public final class CreativePowerSource extends RebarBlock implements RebarElectricBlock.Producer, RebarGuiBlock { @@ -60,6 +62,11 @@ public double getVoltage() { return voltage; } + @Override + public double getPower() { + return power; + } + @Override public @NotNull Gui createGui() { return Gui.builder() diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index bd34f9ec5..b65081004 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -1,5 +1,15 @@ package io.github.pylonmc.pylon.content.machines.electric; +import net.kyori.adventure.text.Component; + +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +import java.util.List; + import io.github.pylonmc.pylon.content.machines.generic.AbstractGrindstone; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; @@ -9,12 +19,6 @@ import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import it.unimi.dsi.fastutil.doubles.DoubleDoublePair; -import org.bukkit.block.Block; -import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.NotNull; - -import java.util.List; public class ElectricGrindstone extends AbstractGrindstone implements RebarElectricBlock.Consumer { @@ -39,9 +43,9 @@ public Item(@NotNull ItemStack stack) { } } - public final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); - public final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); - public final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); + private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + private final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); + private final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); @SuppressWarnings("unused") public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { @@ -61,7 +65,12 @@ public ElectricGrindstone(@NotNull Block block, @NotNull PersistentDataContainer } @Override - public void tick() { + public double getRequiredPower() { + return powerUsage; + } + @Override + public void tick() { + Bukkit.broadcast(Component.text(isPowered() ? "This better be 100% free-range electricity" : "WHERES MAH POWER")); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java index b2de5e6d8..80d883c5b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java @@ -1,17 +1,9 @@ package io.github.pylonmc.pylon.content.machines.electric; -import io.github.pylonmc.rebar.block.BlockStorage; -import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarElectricBlock; -import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; -import io.github.pylonmc.rebar.block.base.RebarTickingBlock; -import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; -import io.github.pylonmc.rebar.electricity.ElectricNode; -import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; -import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; -import io.github.pylonmc.rebar.util.position.BlockPosition; +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + import net.kyori.adventure.text.Component; + import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ItemDisplay; @@ -29,10 +21,21 @@ import java.util.Objects; -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; +import io.github.pylonmc.rebar.block.BlockStorage; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNetwork; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; +import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; +import io.github.pylonmc.rebar.util.position.BlockPosition; public final class ElectricityPylon extends RebarBlock implements - RebarElectricBlock, + RebarElectricBlock.Connector, RebarTickingBlock, RebarEntityHolderBlock { @@ -57,13 +60,21 @@ public void postInitialise() { getElectricNode().onDisconnect((thisNode, otherNode) -> tryRemoveEntity(otherNode.getId().toString())); } + @Override + public double getCurrentLimit(@NotNull ElectricNode otherNode) { + return 100; + } + @Override public void tick() { - Particle.DUST.builder() - .color(Color.fromARGB(getElectricNode().getNetwork().hashCode())) - .location(getBlock().getLocation().toCenterLocation().add(0, 0.6, 0)) - .receivers(32, true) - .spawn(); + ElectricNetwork network = getElectricNode().getNetwork(); + for (ElectricNode node : network.getNodes()) { + Particle.DUST.builder() + .color(Color.fromARGB(network.hashCode())) + .location(node.getBlock().getLocation().toCenterLocation().add(0, 0.6, 0)) + .receivers(32, true) + .spawn(); + } } private ElectricNode getElectricNode() { @@ -123,7 +134,7 @@ private void onRightClickElectricBlock(PlayerInteractEvent event) { ElectricityPylon connectingBlock = BlockStorage.getAsOrThrow(ElectricityPylon.class, connecting); ElectricNode connectingNode = connectingBlock.getElectricNodes().getFirst(); ElectricNode clickedNode = electricBlock.getElectricNodes().getFirst(); - if (!clickedNode.getConnections().isEmpty() && clickedNode.getType() != ElectricNode.Type.CONNECTOR) { + if (!clickedNode.getConnections().isEmpty() && !clickedNode.isConnectedTo(connectingNode) && clickedNode.getType() != ElectricNode.Type.CONNECTOR) { player.sendActionBar(Component.translatable("pylon.message.electricity_pylon.already_connected")); return; } From 933fa7a9e28a98e20e546729d656b016ba381feb Mon Sep 17 00:00:00 2001 From: Seggan Date: Mon, 13 Apr 2026 16:53:55 -0400 Subject: [PATCH 10/33] Add projectile key (closes #562) --- .../pylon/content/tools/HydraulicCannon.java | 4 ++-- .../pylonmc/pylon/util/DisplayProjectile.java | 13 +++++++++---- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/HydraulicCannon.java b/src/main/java/io/github/pylonmc/pylon/content/tools/HydraulicCannon.java index bc9ca33f5..3a6e0d135 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/HydraulicCannon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/HydraulicCannon.java @@ -16,6 +16,7 @@ import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.base.RebarInteractor; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.List; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Location; import org.bukkit.Material; @@ -27,8 +28,6 @@ import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class HydraulicCannon extends RebarItem implements RebarInteractor, HydraulicRefuelable { @@ -114,6 +113,7 @@ public void onUsedToClick(@NotNull PlayerInteractEvent event, @NotNull EventPrio .add(direction.clone().multiply(1.5)); EntityStorage.add(new DisplayProjectile( player, + PylonKeys.TIN_PROJECTILE, projectileMaterial, source, direction, diff --git a/src/main/java/io/github/pylonmc/pylon/util/DisplayProjectile.java b/src/main/java/io/github/pylonmc/pylon/util/DisplayProjectile.java index a85a8e337..7cbb14d98 100644 --- a/src/main/java/io/github/pylonmc/pylon/util/DisplayProjectile.java +++ b/src/main/java/io/github/pylonmc/pylon/util/DisplayProjectile.java @@ -5,8 +5,12 @@ import io.github.pylonmc.rebar.entity.base.RebarTickingEntity; import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; import io.github.pylonmc.rebar.entity.display.transform.LineBuilder; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import java.util.List; +import java.util.Optional; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.NamespacedKey; import org.bukkit.Particle; import org.bukkit.damage.DamageSource; import org.bukkit.damage.DamageType; @@ -19,9 +23,6 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3d; -import java.util.List; -import java.util.Optional; - public final class DisplayProjectile extends RebarEntity implements RebarTickingEntity { private final Player player; @@ -32,6 +33,7 @@ public final class DisplayProjectile extends RebarEntity implements public DisplayProjectile( Player player, + @NotNull NamespacedKey key, Material material, Location source, @NotNull Vector direction, @@ -49,7 +51,10 @@ public DisplayProjectile( .thickness(thickness) .build() ) - .material(material) + .itemStack( + ItemStackBuilder.of(material) + .addCustomModelDataString("pylon:display_projectile/" + key) + ) .build(source) ); this.player = player; From bfed3d6fa4ca02a89926cabf53ca1744836d0cb2 Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 14 Apr 2026 09:32:33 -0400 Subject: [PATCH 11/33] Start multimeter --- .../io/github/pylonmc/pylon/PylonItems.java | 23 ++++++++------- .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../content/machines/electric/Multimeter.java | 28 +++++++++++++++++++ src/main/resources/lang/en.yml | 5 ++++ 4 files changed, 45 insertions(+), 12 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 233e4b567..6915665ac 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -17,6 +17,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; +import io.github.pylonmc.pylon.content.machines.electric.Multimeter; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -29,18 +30,10 @@ import io.github.pylonmc.pylon.content.science.ResearchPack; import io.github.pylonmc.pylon.content.talismans.*; import io.github.pylonmc.pylon.content.tools.*; -import io.github.pylonmc.pylon.guide.PressableItemsPage; import io.github.pylonmc.pylon.guide.HydraulicRefuelableItemsPage; +import io.github.pylonmc.pylon.guide.PressableItemsPage; import io.github.pylonmc.pylon.guide.SmelteryBurnerFuelsPage; -import io.github.pylonmc.pylon.recipes.CrucibleRecipe; -import io.github.pylonmc.pylon.recipes.GrindstoneRecipe; -import io.github.pylonmc.pylon.recipes.HammerRecipe; -import io.github.pylonmc.pylon.recipes.MoldingRecipe; -import io.github.pylonmc.pylon.recipes.PipeBendingRecipe; -import io.github.pylonmc.pylon.recipes.PitKilnRecipe; -import io.github.pylonmc.pylon.recipes.ShimmerAltarRecipe; -import io.github.pylonmc.pylon.recipes.StrainingRecipe; -import io.github.pylonmc.pylon.recipes.TableSawRecipe; +import io.github.pylonmc.pylon.recipes.*; import io.github.pylonmc.rebar.config.Settings; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; import io.github.pylonmc.rebar.content.fluid.FluidPipe; @@ -57,6 +50,7 @@ import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.registry.keys.SoundEventKeys; import io.papermc.paper.registry.keys.tags.DamageTypeTagKeys; +import java.util.Objects; import net.kyori.adventure.key.Key; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -69,8 +63,6 @@ import org.bukkit.inventory.recipe.CraftingBookCategory; import org.bukkit.potion.PotionType; -import java.util.Objects; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; @SuppressWarnings({"UnstableApiUsage", "OverlyComplexClass"}) @@ -3209,6 +3201,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(ELECTRICITY_PYLON); } + public static final ItemStack MULTIMETER = ItemStackBuilder.rebar(Material.CLOCK, PylonKeys.MULTIMETER) + .build(); + static { + RebarItem.register(Multimeter.class, MULTIMETER, PylonKeys.MULTIMETER); + PylonPages.TOOLS.addItem(MULTIMETER); + } + public static final ItemStack CREATIVE_POWER_SOURCE = ItemStackBuilder.rebar(Material.PINK_STAINED_GLASS, PylonKeys.CREATIVE_POWER_SOURCE) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 9a49ae750..5b56ab6a2 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -464,6 +464,7 @@ public class PylonKeys { public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); + public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java new file mode 100644 index 000000000..0342f93b3 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java @@ -0,0 +1,28 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.rebar.block.BlockStorage; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.item.base.RebarInteractor; +import java.util.Comparator; +import org.bukkit.Location; +import org.bukkit.event.EventPriority; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class Multimeter extends RebarItem implements RebarInteractor { + public Multimeter(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public void onUsedToClick(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) { + Location playerLocation = event.getPlayer().getLocation(); + ElectricityPylon pylon = BlockStorage.getByType(ElectricityPylon.class).stream() + .min(Comparator.comparing(p -> p.getBlock().getLocation().toCenterLocation().distanceSquared(playerLocation))) + .filter(p -> p.getBlock().getLocation().toCenterLocation().distanceSquared(playerLocation) < 64 * 64) + .orElse(null); + if (pylon == null) return; + throw new UnsupportedOperationException("Multimeter interaction not implemented yet"); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 8dd443b08..35d51b9a4 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2414,6 +2414,11 @@ item: lore: |- TODO + multimeter: + name: "Multimeter" + lore: |- + Measures the current of a wire + creative_power_source: name: "<#ff00ff>Creative Power Source" lore: |- From e2d993ba804b95c5a02bfd8046c1b05dd12111fe Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 15 Apr 2026 19:33:46 -0400 Subject: [PATCH 12/33] Rewrite node API --- .../electric/CreativePowerSource.java | 61 ++++--------------- .../machines/electric/ElectricGrindstone.java | 33 +++++----- .../machines/electric/ElectricityPylon.java | 55 ++++++++--------- .../machines/smelting/SmelteryController.java | 9 ++- 4 files changed, 55 insertions(+), 103 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index 79fde47a6..0a817bf4e 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -1,70 +1,33 @@ package io.github.pylonmc.pylon.content.machines.electric; -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.ComponentLike; - -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.block.Block; -import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.NotNull; - import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricProducerBlock; import io.github.pylonmc.rebar.block.base.RebarGuiBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; -import io.github.pylonmc.rebar.electricity.ElectricNode; import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.unit.MetricPrefix; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.ComponentLike; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; import xyz.xenondevs.invui.gui.Gui; public final class CreativePowerSource extends RebarBlock implements - RebarElectricBlock.Producer, + RebarElectricProducerBlock, RebarGuiBlock { - private static final NamespacedKey VOLTAGE_KEY = pylonKey("voltage"); - private static final NamespacedKey POWER_KEY = pylonKey("power"); - - private int voltage; - private int power; - @SuppressWarnings("unused") public CreativePowerSource(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - - voltage = 0; - power = 0; - - createElectricNode(block.getLocation().toCenterLocation(), ElectricNode.Type.PRODUCER); } @SuppressWarnings({"unused", "DataFlowIssue"}) public CreativePowerSource(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); - - voltage = pdc.get(VOLTAGE_KEY, RebarSerializers.INTEGER); - power = pdc.get(POWER_KEY, RebarSerializers.INTEGER); - } - - @Override - public void write(@NotNull PersistentDataContainer pdc) { - pdc.set(VOLTAGE_KEY, RebarSerializers.INTEGER, voltage); - pdc.set(POWER_KEY, RebarSerializers.INTEGER, power); - } - - @Override - public double getVoltage() { - return voltage; - } - - @Override - public double getPower() { - return power; } @Override @@ -78,8 +41,8 @@ public double getPower() { .increment(1) .shiftIncrement(10) .min(0) - .valueGetter(() -> voltage) - .valueSetter(value -> voltage = value) + .valueGetter(() -> (int) getVoltageProducing()) + .valueSetter(this::setVoltageProducing) .valueFormatter(v -> formatQuantity(UnitFormat.VOLTS, v)) .reopenWindow(this::openWindow) .build()) @@ -89,8 +52,8 @@ public double getPower() { .increment(1) .shiftIncrement(10) .min(0) - .valueGetter(() -> power) - .valueSetter(value -> power = value) + .valueGetter(() -> (int) getPowerProducing()) + .valueSetter(this::setPowerProducing) .valueFormatter(p -> formatQuantity(UnitFormat.WATTS, p)) .reopenWindow(this::openWindow) .build()) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index b65081004..10a46218b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -1,27 +1,24 @@ package io.github.pylonmc.pylon.content.machines.electric; -import net.kyori.adventure.text.Component; - -import org.bukkit.Bukkit; -import org.bukkit.block.Block; -import org.bukkit.inventory.ItemStack; -import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.NotNull; - -import java.util.List; - import io.github.pylonmc.pylon.content.machines.generic.AbstractGrindstone; -import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; -import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.electricity.VoltageRange; import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import it.unimi.dsi.fastutil.doubles.DoubleDoublePair; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.Bukkit; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; public class ElectricGrindstone extends AbstractGrindstone implements - RebarElectricBlock.Consumer { + RebarElectricConsumerBlock { public static class Item extends RebarItem { @@ -50,8 +47,6 @@ public Item(@NotNull ItemStack stack) { @SuppressWarnings("unused") public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - - createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONSUMER); } @SuppressWarnings("unused") @@ -60,8 +55,8 @@ public ElectricGrindstone(@NotNull Block block, @NotNull PersistentDataContainer } @Override - public @NotNull DoubleDoublePair getVoltageRange() { - return DoubleDoublePair.of(voltageMin, voltageMax); + public @NotNull VoltageRange getVoltageRange() { + return new VoltageRange(voltageMin, voltageMax); } @Override @@ -71,6 +66,6 @@ public double getRequiredPower() { @Override public void tick() { - Bukkit.broadcast(Component.text(isPowered() ? "This better be 100% free-range electricity" : "WHERES MAH POWER")); + Bukkit.broadcast(Component.text(new BlockPosition(getBlock()) + (isPowered() ? "This better be 100% free-range electricity" : "WHERES MAH POWER"))); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java index 80d883c5b..945b7978d 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java @@ -1,9 +1,19 @@ package io.github.pylonmc.pylon.content.machines.electric; -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - +import io.github.pylonmc.rebar.block.BlockStorage; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNetwork; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; +import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.Objects; import net.kyori.adventure.text.Component; - import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ItemDisplay; @@ -19,23 +29,10 @@ import org.jetbrains.annotations.NotNull; import org.joml.Matrix4f; -import java.util.Objects; - -import io.github.pylonmc.rebar.block.BlockStorage; -import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarElectricBlock; -import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; -import io.github.pylonmc.rebar.block.base.RebarTickingBlock; -import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; -import io.github.pylonmc.rebar.electricity.ElectricNetwork; -import io.github.pylonmc.rebar.electricity.ElectricNode; -import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; -import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; -import io.github.pylonmc.rebar.util.position.BlockPosition; +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class ElectricityPylon extends RebarBlock implements - RebarElectricBlock.Connector, + RebarElectricBlock, RebarTickingBlock, RebarEntityHolderBlock { @@ -47,7 +44,10 @@ public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext contex super(block, context); setTickInterval(10); - createElectricNode(getBlock().getLocation().toCenterLocation(), ElectricNode.Type.CONNECTOR); + addElectricNode(new ElectricNode.Connector( + new BlockPosition(block), + getBlock().getLocation().toCenterLocation() + )); } @SuppressWarnings("unused") @@ -60,25 +60,20 @@ public void postInitialise() { getElectricNode().onDisconnect((thisNode, otherNode) -> tryRemoveEntity(otherNode.getId().toString())); } - @Override - public double getCurrentLimit(@NotNull ElectricNode otherNode) { - return 100; - } - @Override public void tick() { ElectricNetwork network = getElectricNode().getNetwork(); for (ElectricNode node : network.getNodes()) { Particle.DUST.builder() .color(Color.fromARGB(network.hashCode())) - .location(node.getBlock().getLocation().toCenterLocation().add(0, 0.6, 0)) + .location(node.getBlock().toLocation().toCenterLocation().add(0, 0.6, 0)) .receivers(32, true) .spawn(); } } - private ElectricNode getElectricNode() { - return getElectricNodes().getFirst(); + private ElectricNode.Connector getElectricNode() { + return (ElectricNode.Connector) getElectricNodes().getFirst(); } private static Matrix4f getDisplayTransform(Location from, Location to) { @@ -132,9 +127,9 @@ private void onRightClickElectricBlock(PlayerInteractEvent event) { } ElectricityPylon connectingBlock = BlockStorage.getAsOrThrow(ElectricityPylon.class, connecting); - ElectricNode connectingNode = connectingBlock.getElectricNodes().getFirst(); + ElectricNode.Connector connectingNode = connectingBlock.getElectricNode(); ElectricNode clickedNode = electricBlock.getElectricNodes().getFirst(); - if (!clickedNode.getConnections().isEmpty() && !clickedNode.isConnectedTo(connectingNode) && clickedNode.getType() != ElectricNode.Type.CONNECTOR) { + if (clickedNode instanceof ElectricNode.Leaf leafNode && leafNode.getConnection() != null && !clickedNode.isConnectedTo(leafNode)) { player.sendActionBar(Component.translatable("pylon.message.electricity_pylon.already_connected")); return; } @@ -176,7 +171,7 @@ private void onPlayerMove(PlayerMoveEvent event) { if (!pdc.has(CONNECTING_KEY)) return; BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); assert connecting != null; - Location connectingLocation = connecting.getLocation().toCenterLocation(); + Location connectingLocation = connecting.toLocation().toCenterLocation(); Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); assert display != null; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java index c25a2ee9c..e584d470b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java @@ -26,6 +26,9 @@ import io.github.pylonmc.rebar.util.position.ChunkPosition; import it.unimi.dsi.fastutil.objects.Object2DoubleMap; import it.unimi.dsi.fastutil.objects.Object2DoubleRBTreeMap; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.Collectors; import kotlin.Pair; import lombok.Getter; import net.kyori.adventure.text.Component; @@ -52,10 +55,6 @@ import xyz.xenondevs.invui.item.Item; import xyz.xenondevs.invui.item.ItemProvider; -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class SmelteryController extends SmelteryComponent @@ -437,7 +436,7 @@ private void applyHeat() { private void spawnPixels() { pixels.clear(); - Location location = center.getLocation().add(-1, 0, -1); + Location location = center.toLocation().add(-1, 0, -1); for (int x = 0; x < PIXELS_PER_SIDE; x++) { for (int z = 0; z < PIXELS_PER_SIDE; z++) { Location relative = location.clone().add((double) x / RESOLUTION, 0, (double) z / RESOLUTION); From fa20743fff9fe3d3b4c93ae320dfdc6a2e8e90cb Mon Sep 17 00:00:00 2001 From: Seggan Date: Sun, 19 Apr 2026 20:22:20 -0400 Subject: [PATCH 13/33] Start transformer --- .../io/github/pylonmc/pylon/PylonBlocks.java | 2 + .../io/github/pylonmc/pylon/PylonItems.java | 8 + .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../machines/electric/Transformer.java | 145 ++++++++++++++++++ src/main/resources/lang/en.yml | 5 + 5 files changed, 161 insertions(+) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index fd2da1d78..5d459b5d1 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -10,6 +10,7 @@ import io.github.pylonmc.pylon.content.machines.electric.CreativePowerSource; import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.electric.ElectricityPylon; +import io.github.pylonmc.pylon.content.machines.electric.Transformer; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -185,6 +186,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.PALLADIUM_SILO, Material.BLUE_TERRACOTTA, Silo.class); RebarBlock.register(PylonKeys.SILO_CONVERTER, Material.STRIPPED_OAK_LOG, SiloConverter.class); RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); + RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 6915665ac..611ad3d51 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3201,6 +3201,14 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(ELECTRICITY_PYLON); } + public static final ItemStack TRANSFORMER = ItemStackBuilder.rebar(Material.STRUCTURE_VOID, PylonKeys.TRANSFORMER) + .set(DataComponentTypes.ITEM_MODEL, Material.COPPER_BULB.key()) + .build(); + static { + RebarItem.register(RebarItem.class, TRANSFORMER, PylonKeys.TRANSFORMER); + PylonPages.ELECTRICITY.addItem(TRANSFORMER); + } + public static final ItemStack MULTIMETER = ItemStackBuilder.rebar(Material.CLOCK, PylonKeys.MULTIMETER) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 5b56ab6a2..60de0b87c 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -464,6 +464,7 @@ public class PylonKeys { public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); + public static final NamespacedKey TRANSFORMER = pylonKey("transformer"); public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java new file mode 100644 index 000000000..fca52c917 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java @@ -0,0 +1,145 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; +import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import org.bukkit.NamespacedKey; +import org.bukkit.Registry; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; + +public class Transformer extends RebarBlock implements + RebarDirectionalBlock, + RebarEntityHolderBlock { + + @SuppressWarnings("unused") + public Transformer(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + setFacing(context.getFacing()); + + addEntity("core", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) + .addCustomModelDataString(getKey() + ":core")) + .transformation(new Matrix4f() + .scaleLocal(0.20009678623931632F, 0.20032039188618334F, 0.6004731961191524F) + .translateLocal(-0.4F, 0F, 0F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("core_1", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) + .addCustomModelDataString(getKey() + ":core")) + .transformation(new Matrix4f() + .scaleLocal(0.1997668812131523F, 0.19966703461153537F, 0.6003585166957504F) + .translateLocal(0.4F, 0F, 0F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("rung", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) + .addCustomModelDataString(getKey() + ":rung")) + .transformation(new Matrix4f() + .scaleLocal(0.1996251290519708F, 0.19976789546029616F, 1.0003100350848213F) + .translateLocal(0.4F, 0F, 0F) + .rotateLocalY(1.5707963267948966F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("rung_1", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) + .addCustomModelDataString(getKey() + ":rung")) + .transformation(new Matrix4f() + .scaleLocal(0.19970989558988675F, 0.20049819786540016F, 1.0000264976327606F) + .translateLocal(0.4F, 0F, 0F) + .rotateLocalY(-1.5707963267948966F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.3995463833191263F, 0.4001898742525297F, 0.0997048554794333F) + .translateLocal(-0.4F, 0F, -0.1875F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil_1", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.3999329168670776F, 0.40013877682813603F, 0.10002070272683829F) + .translateLocal(-0.4F, 0F, -0.0625F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil_2", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.3995519473196249F, 0.40019206234199983F, 0.0996939243442167F) + .translateLocal(-0.4F, 0F, 0.1875F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil_3", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.4001911460388317F, 0.3997099305044037F, 0.10003237057314601F) + .translateLocal(-0.4F, 0F, 0.0625F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil_4", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.4002971305276804F, 0.3996788757583065F, 0.10002218158359033F) + .translateLocal(0.4F, 0F, -0.0625F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + + addEntity("coil_5", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) + .addCustomModelDataString(getKey() + ":coil")) + .transformation(new Matrix4f() + .scaleLocal(0.40047277836438155F, 0.400447837292574F, 0.10040968619996378F) + .translateLocal(0.4F, 0F, 0.0625F) + .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(block.getLocation().toCenterLocation()) + ); + } + + @SuppressWarnings("unused") + public Transformer(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 35d51b9a4..93428dcf4 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2414,6 +2414,11 @@ item: lore: |- TODO + transformer: + name: "Transformer" + lore: |- + TODO + multimeter: name: "Multimeter" lore: |- From 6e0ec782123a657b82a74daae2471ed5a1ed1b5b Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 21 Apr 2026 17:25:39 -0400 Subject: [PATCH 14/33] Rewrite connections --- .../java/io/github/pylonmc/pylon/Pylon.java | 7 +- .../io/github/pylonmc/pylon/PylonItems.java | 7 + .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../electric/CreativePowerSource.java | 1 + .../machines/electric/ElectricGrindstone.java | 1 + .../machines/electric/ElectricityPylon.java | 157 ++---------------- .../pylon/content/tools/PylonWire.java | 35 ++++ src/main/resources/lang/en.yml | 8 +- src/main/resources/settings/wire_1_gauge.yml | 1 + 9 files changed, 65 insertions(+), 153 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java create mode 100644 src/main/resources/settings/wire_1_gauge.yml diff --git a/src/main/java/io/github/pylonmc/pylon/Pylon.java b/src/main/java/io/github/pylonmc/pylon/Pylon.java index 67f0b3d94..da57432a6 100644 --- a/src/main/java/io/github/pylonmc/pylon/Pylon.java +++ b/src/main/java/io/github/pylonmc/pylon/Pylon.java @@ -2,7 +2,6 @@ import io.github.pylonmc.pylon.command.PylonCommand; import io.github.pylonmc.pylon.content.building.Immobilizer; -import io.github.pylonmc.pylon.content.machines.electric.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.fluid.Sprinkler; import io.github.pylonmc.pylon.content.machines.simple.Grindstone; import io.github.pylonmc.pylon.content.machines.smelting.Bloomery; @@ -13,6 +12,8 @@ import io.github.pylonmc.rebar.addon.RebarAddon; import io.github.pylonmc.rebar.registry.RebarRegistry; import io.papermc.paper.plugin.lifecycle.event.types.LifecycleEvents; +import java.util.Locale; +import java.util.Set; import lombok.Getter; import org.bstats.bukkit.Metrics; import org.bukkit.Bukkit; @@ -21,9 +22,6 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; -import java.util.Locale; -import java.util.Set; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public class Pylon extends JavaPlugin implements RebarAddon { @@ -73,7 +71,6 @@ public void onEnable() { pm.registerEvents(new EnchantingTalisman.EnchantingListener(), this); pm.registerEvents(new HuntingTalisman.HuntingTalismanListener(), this); pm.registerEvents(new ExperienceTalisman.XPTalismanListener(), this); - pm.registerEvents(new ElectricityPylon.InteractionListener(), this); RebarRegistry.RESEARCHES.mapKey(pylonKey("simple_components"), pylonKey("components_1")); RebarRegistry.RESEARCHES.mapKey(pylonKey("scientific_revolution_4"), pylonKey("scientific_revolution_3")); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 611ad3d51..08944cb3c 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3209,6 +3209,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(TRANSFORMER); } + public static final ItemStack WIRE_1_GAUGE = ItemStackBuilder.rebar(Material.STRING, PylonKeys.WIRE_1_GAUGE) + .build(); + static { + RebarItem.register(PylonWire.class, WIRE_1_GAUGE, PylonKeys.WIRE_1_GAUGE); + PylonPages.TOOLS.addItem(WIRE_1_GAUGE); + } + public static final ItemStack MULTIMETER = ItemStackBuilder.rebar(Material.CLOCK, PylonKeys.MULTIMETER) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 60de0b87c..09d2bae5f 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -466,6 +466,7 @@ public class PylonKeys { public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); public static final NamespacedKey TRANSFORMER = pylonKey("transformer"); public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); + public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index 0a817bf4e..c35686371 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -23,6 +23,7 @@ public final class CreativePowerSource extends RebarBlock implements @SuppressWarnings("unused") public CreativePowerSource(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); + setFacing(context.getFacing()); } @SuppressWarnings({"unused", "DataFlowIssue"}) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index 10a46218b..ceeee4978 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -47,6 +47,7 @@ public Item(@NotNull ItemStack stack) { @SuppressWarnings("unused") public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); + setFacing(context.getFacing()); } @SuppressWarnings("unused") diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java index 945b7978d..e0e9e0f21 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java @@ -1,53 +1,34 @@ package io.github.pylonmc.pylon.content.machines.electric; -import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; -import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; import io.github.pylonmc.rebar.block.base.RebarTickingBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; import io.github.pylonmc.rebar.electricity.ElectricNetwork; import io.github.pylonmc.rebar.electricity.ElectricNode; -import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; -import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; +import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.util.position.BlockPosition; -import java.util.Objects; -import net.kyori.adventure.text.Component; -import org.bukkit.*; +import org.bukkit.Color; +import org.bukkit.Particle; import org.bukkit.block.Block; -import org.bukkit.entity.ItemDisplay; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerMoveEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.inventory.EquipmentSlot; +import org.bukkit.block.BlockFace; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; -import org.joml.Matrix4f; - -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class ElectricityPylon extends RebarBlock implements RebarElectricBlock, - RebarTickingBlock, - RebarEntityHolderBlock { - - private static final NamespacedKey CONNECTING_KEY = pylonKey("connecting"); - private static final NamespacedKey CONNECTING_ID_KEY = pylonKey("connecting_id"); + RebarTickingBlock { @SuppressWarnings("unused") public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setTickInterval(10); - addElectricNode(new ElectricNode.Connector( - new BlockPosition(block), - getBlock().getLocation().toCenterLocation() - )); + ElectricNode.Connector centralNode = addElectricNode(new ElectricNode.Connector(new BlockPosition(block))); + for (BlockFace face : RebarUtils.IMMEDIATE_FACES) { + ElectricNode.Connector port = addElectricPort(face, new ElectricNode.Connector(new BlockPosition(block))); + centralNode.connect(port); + } } @SuppressWarnings("unused") @@ -55,14 +36,9 @@ public ElectricityPylon(@NotNull Block block, @NotNull PersistentDataContainer p super(block, pdc); } - @Override - public void postInitialise() { - getElectricNode().onDisconnect((thisNode, otherNode) -> tryRemoveEntity(otherNode.getId().toString())); - } - @Override public void tick() { - ElectricNetwork network = getElectricNode().getNetwork(); + ElectricNetwork network = getElectricNodes().getFirst().getNetwork(); for (ElectricNode node : network.getNodes()) { Particle.DUST.builder() .color(Color.fromARGB(network.hashCode())) @@ -71,115 +47,4 @@ public void tick() { .spawn(); } } - - private ElectricNode.Connector getElectricNode() { - return (ElectricNode.Connector) getElectricNodes().getFirst(); - } - - private static Matrix4f getDisplayTransform(Location from, Location to) { - return new TransformBuilder() - .lookAlong(from, to) - .scale(0.05, 0.05, from.distance(to)) - .buildForItemDisplay(); - } - - private static Location getMidpoint(Location a, Location b) { - return a.clone().add(b).multiply(0.5); - } - - public static class InteractionListener implements Listener { - @EventHandler(ignoreCancelled = true) - private void onRightClickElectricBlock(PlayerInteractEvent event) { - if (event.getHand() != EquipmentSlot.HAND || event.useInteractedBlock() == Event.Result.DENY) return; - - Block clickedBlock = event.getClickedBlock(); - if (clickedBlock == null) return; - RebarElectricBlock electricBlock = BlockStorage.getAs(RebarElectricBlock.class, clickedBlock); - if (electricBlock == null) return; - - BlockPosition clickedPos = new BlockPosition(clickedBlock); - Player player = event.getPlayer(); - PersistentDataContainer playerPdc = player.getPersistentDataContainer(); - BlockPosition connecting = playerPdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - if (connecting == null) { - if (electricBlock instanceof ElectricityPylon && !player.isSneaking() && event.getAction().isRightClick()) { - Location connectionLocation = electricBlock.getElectricNodes().getFirst().getConnectionPoint(); - Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); - ItemDisplay display = new ItemDisplayBuilder() - .transformation(getDisplayTransform(connectionLocation, playerLocation)) - .material(Material.COPPER_BLOCK) - .build(getMidpoint(connectionLocation, playerLocation)); - playerPdc.set(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION, clickedPos); - playerPdc.set(CONNECTING_ID_KEY, RebarSerializers.UUID, display.getUniqueId()); - } - return; - } - - event.setUseInteractedBlock(Event.Result.DENY); - - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(playerPdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - if (connecting.equals(clickedPos)) { - display.remove(); - playerPdc.remove(CONNECTING_KEY); - playerPdc.remove(CONNECTING_ID_KEY); - return; - } - - ElectricityPylon connectingBlock = BlockStorage.getAsOrThrow(ElectricityPylon.class, connecting); - ElectricNode.Connector connectingNode = connectingBlock.getElectricNode(); - ElectricNode clickedNode = electricBlock.getElectricNodes().getFirst(); - if (clickedNode instanceof ElectricNode.Leaf leafNode && leafNode.getConnection() != null && !clickedNode.isConnectedTo(leafNode)) { - player.sendActionBar(Component.translatable("pylon.message.electricity_pylon.already_connected")); - return; - } - - if (connectingNode.isConnectedTo(clickedNode)) { - display.remove(); - connectingNode.disconnect(clickedNode); - } else { - Location connectingLocation = connectingNode.getConnectionPoint(); - Location clickedLocation = clickedNode.getConnectionPoint(); - display.setTransformationMatrix(getDisplayTransform(connectingLocation, clickedLocation)); - display.teleportAsync(getMidpoint(connectingLocation, clickedLocation)); - connectingNode.connect(clickedNode); - connectingBlock.addEntity(clickedNode.getId().toString(), display); - } - playerPdc.remove(CONNECTING_KEY); - playerPdc.remove(CONNECTING_ID_KEY); - } - - @EventHandler - private void onPlayerQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - PersistentDataContainer pdc = player.getPersistentDataContainer(); - if (!pdc.has(CONNECTING_KEY)) return; - BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - assert connecting != null; - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - display.remove(); - pdc.remove(CONNECTING_KEY); - pdc.remove(CONNECTING_ID_KEY); - } - - @EventHandler - private void onPlayerMove(PlayerMoveEvent event) { - if (!event.hasChangedPosition()) return; - Player player = event.getPlayer(); - PersistentDataContainer pdc = player.getPersistentDataContainer(); - if (!pdc.has(CONNECTING_KEY)) return; - BlockPosition connecting = pdc.get(CONNECTING_KEY, RebarSerializers.BLOCK_POSITION); - assert connecting != null; - Location connectingLocation = connecting.toLocation().toCenterLocation(); - Location playerLocation = player.getEyeLocation().subtract(0, 0.5, 0); - ItemDisplay display = (ItemDisplay) Bukkit.getEntity(Objects.requireNonNull(pdc.get(CONNECTING_ID_KEY, RebarSerializers.UUID))); - assert display != null; - display.setTeleportDuration(1); - display.setInterpolationDelay(0); - display.setInterpolationDuration(1); - display.setTransformationMatrix(getDisplayTransform(connectingLocation, playerLocation)); - display.teleportAsync(connectingLocation.add(playerLocation.clone().subtract(connectingLocation).multiply(0.5))); - } - } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java new file mode 100644 index 000000000..b08b6d280 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java @@ -0,0 +1,35 @@ +package io.github.pylonmc.pylon.content.tools; + +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.item.base.RebarWire; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.List; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.jetbrains.annotations.NotNull; + +public class PylonWire extends RebarItem implements RebarWire { + + private final double currentLimit = getSettings().getOrThrow("current-limit", ConfigAdapter.DOUBLE); + + public PylonWire(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of(RebarArgument.of("current-limit", UnitFormat.AMPRERES.format(currentLimit))); + } + + @Override + public double getCurrentLimit() { + return currentLimit; + } + + @Override + public @NotNull Material getDisplayMaterial() { + return Material.COPPER_BLOCK; + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 93428dcf4..8935b592c 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2436,6 +2436,12 @@ item: Power usage: %power-usage% Voltage range: %min-voltage% to %max-voltage% + wire_1_gauge: + name: "1 Gauge Wire" + lore: |- + Transmits electricity + Current limit: %current-limit% + fluid: castable: display-text: " Casts into %result%" @@ -2691,8 +2697,6 @@ guide: lore: "" message: - electricity_pylon: - already_connected: "This block is already connected to an electricity pylon" assembly_table: full: "Output full!" fluid_selector: diff --git a/src/main/resources/settings/wire_1_gauge.yml b/src/main/resources/settings/wire_1_gauge.yml new file mode 100644 index 000000000..c5e97e6b0 --- /dev/null +++ b/src/main/resources/settings/wire_1_gauge.yml @@ -0,0 +1 @@ +current-limit: 50 \ No newline at end of file From 6535b3dcd69bc8e908ff6fb15df981320b6861cd Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 21 Apr 2026 17:31:47 -0400 Subject: [PATCH 15/33] Add transformers --- .../machines/electric/Transformer.java | 87 ++++++++++++++++++- .../content/machines/simple/Grindstone.java | 7 +- .../pylon/content/machines/simple/Press.java | 5 +- .../pylon/content/tools/PylonWire.java | 6 +- src/main/resources/lang/en.yml | 8 +- src/main/resources/settings/wire_1_gauge.yml | 2 +- 6 files changed, 97 insertions(+), 18 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java index fca52c917..9246d8a91 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java @@ -1,11 +1,23 @@ package io.github.pylonmc.pylon.content.machines.electric; +import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; -import io.github.pylonmc.rebar.block.base.RebarEntityHolderBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.base.RebarGuiBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.electricity.ElectricityManager; import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.UUID; +import lombok.Getter; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.Registry; import org.bukkit.block.Block; @@ -14,10 +26,24 @@ import org.joml.Matrix4f; import org.joml.Quaternionf; import org.joml.Vector3f; +import xyz.xenondevs.invui.gui.Gui; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public class Transformer extends RebarBlock implements RebarDirectionalBlock, - RebarEntityHolderBlock { + RebarElectricBlock, + RebarGuiBlock { + + private static final NamespacedKey VOLTAGE_KEY = pylonKey("voltage"); + private static final NamespacedKey INPUT_NODE_KEY = pylonKey("input_node"); + private static final NamespacedKey OUTPUT_NODE_KEY = pylonKey("output_node"); + + private ElectricNode.Connector inputNode; + private ElectricNode.Connector outputNode; + + @Getter + private double voltage; @SuppressWarnings("unused") public Transformer(@NotNull Block block, @NotNull BlockCreateContext context) { @@ -136,10 +162,65 @@ public Transformer(@NotNull Block block, @NotNull BlockCreateContext context) { ) .build(block.getLocation().toCenterLocation()) ); + + voltage = 0; + + inputNode = addElectricPort(getFacing(), new ElectricNode.Connector(new BlockPosition(block))); + outputNode = addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Connector(new BlockPosition(block))); + inputNode.connect(outputNode); + ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); } - @SuppressWarnings("unused") + @SuppressWarnings({"unused", "DataFlowIssue"}) public Transformer(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); + + voltage = pdc.get(VOLTAGE_KEY, RebarSerializers.DOUBLE); + } + + @Override + protected void postLoad(@NotNull PersistentDataContainer pdc) { + UUID inputNodeId = pdc.get(INPUT_NODE_KEY, RebarSerializers.UUID); + UUID outputNodeId = pdc.get(OUTPUT_NODE_KEY, RebarSerializers.UUID); + inputNode = (ElectricNode.Connector) getElectricNodes().stream() + .filter(node -> node.getId().equals(inputNodeId)) + .findFirst() + .orElseThrow(); + outputNode = (ElectricNode.Connector) getElectricNodes().stream() + .filter(node -> node.getId().equals(outputNodeId)) + .findFirst() + .orElseThrow(); + ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(VOLTAGE_KEY, RebarSerializers.DOUBLE, voltage); + pdc.set(INPUT_NODE_KEY, RebarSerializers.UUID, inputNode.getId()); + pdc.set(OUTPUT_NODE_KEY, RebarSerializers.UUID, outputNode.getId()); + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure("# # # # v # # # #") + .addIngredient('#', GuiItems.background()) + .addIngredient('v', NumberInputButton.builder() + .material(Material.REDSTONE) + .name(Component.translatable("pylon.gui.voltage")) + .increment(1) + .shiftIncrement(10) + .min(0) + .valueGetter(() -> (int) getVoltage()) + .valueSetter(this::setVoltage) + .valueFormatter(UnitFormat.VOLTS::format) + .reopenWindow(this::openWindow) + .build()) + .build(); + } + + public void setVoltage(double voltage) { + this.voltage = voltage; + ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Grindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Grindstone.java index bb69b667d..73cf08166 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Grindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Grindstone.java @@ -21,6 +21,8 @@ import io.github.pylonmc.rebar.logistics.slot.ItemDisplayLogisticSlot; import io.github.pylonmc.rebar.util.position.BlockPosition; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.List; +import java.util.Map; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Bukkit; @@ -44,9 +46,6 @@ import org.joml.Matrix4f; import org.joml.Vector3i; -import java.util.List; -import java.util.Map; - public class Grindstone extends RebarBlock implements RebarSimpleMultiblock, @@ -90,7 +89,7 @@ public void postInitialise() { } @Override - protected void postLoad() { + protected void postLoad(@NotNull PersistentDataContainer pdc) { if (isProcessingRecipe()) { finishRecipe(); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Press.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Press.java index 00d76533f..f834e7329 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Press.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Press.java @@ -22,6 +22,7 @@ import io.github.pylonmc.rebar.util.position.BlockPosition; import io.github.pylonmc.rebar.waila.WailaDisplay; import io.papermc.paper.event.entity.EntityCompostItemEvent; +import java.util.List; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -40,8 +41,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; -import java.util.List; - public class Press extends RebarBlock implements RebarInteractBlock, @@ -92,7 +91,7 @@ public Press(@NotNull Block block, @NotNull PersistentDataContainer pdc) { } @Override - public void postLoad() { + public void postLoad(@NotNull PersistentDataContainer pdc) { if (isProcessingRecipe()) { finishRecipe(); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java index b08b6d280..740cd42b3 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java @@ -12,7 +12,7 @@ public class PylonWire extends RebarItem implements RebarWire { - private final double currentLimit = getSettings().getOrThrow("current-limit", ConfigAdapter.DOUBLE); + private final double currentLimit = getSettings().getOrThrow("max-current", ConfigAdapter.DOUBLE); public PylonWire(@NotNull ItemStack stack) { super(stack); @@ -20,11 +20,11 @@ public PylonWire(@NotNull ItemStack stack) { @Override public @NotNull List<@NotNull RebarArgument> getPlaceholders() { - return List.of(RebarArgument.of("current-limit", UnitFormat.AMPRERES.format(currentLimit))); + return List.of(RebarArgument.of("max-current", UnitFormat.AMPRERES.format(currentLimit))); } @Override - public double getCurrentLimit() { + public double getMaxCurrent() { return currentLimit; } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 8935b592c..60cb75104 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2417,7 +2417,7 @@ item: transformer: name: "Transformer" lore: |- - TODO + Sets the voltage of any current crossing through it to a specific value multimeter: name: "Multimeter" @@ -2437,10 +2437,10 @@ item: Voltage range: %min-voltage% to %max-voltage% wire_1_gauge: - name: "1 Gauge Wire" + name: "1-Gauge Wire" lore: |- Transmits electricity - Current limit: %current-limit% + Max current: %max-current% fluid: castable: @@ -2462,7 +2462,7 @@ fluid: slurry_raw_iron: "Raw Iron Slurry" slurry_raw_tin: "Raw Tin Slurry" steel: "Liquid Steel" - sulfur: "Sulfur" + sulfur: "Liquid Sulfur" tin: "Liquid Tin" water: "Water" palladium: "<#b642f5>Liquid Palladium" diff --git a/src/main/resources/settings/wire_1_gauge.yml b/src/main/resources/settings/wire_1_gauge.yml index c5e97e6b0..077d5c94e 100644 --- a/src/main/resources/settings/wire_1_gauge.yml +++ b/src/main/resources/settings/wire_1_gauge.yml @@ -1 +1 @@ -current-limit: 50 \ No newline at end of file +max-current: 50 \ No newline at end of file From 1cd3a5b7bf3054a096d1760fc2de31e0d8edadf1 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 22 Apr 2026 09:35:27 -0400 Subject: [PATCH 16/33] Take wires --- .../pylonmc/pylon/content/components/FluidHatch.java | 9 ++------- .../content/machines/fluid/PortableFluidTank.java | 11 +++++------ .../machines/hydraulics/HydraulicPurifier.java | 7 +++---- .../github/pylonmc/pylon/content/tools/Moldable.java | 2 +- .../pylon/guide/HydraulicRefuelableItemsPage.java | 7 +++---- .../io/github/pylonmc/pylon/recipes/HammerRecipe.java | 7 +++---- .../pylonmc/pylon/recipes/SiloConverterRecipe.java | 11 +++-------- 7 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java index d7cbede11..323a3b8da 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java @@ -22,6 +22,7 @@ import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.waila.Waila; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.*; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Bukkit; @@ -35,12 +36,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public abstract class FluidHatch extends RebarBlock implements @@ -59,7 +54,7 @@ public abstract class FluidHatch extends RebarBlock implements Bukkit.getScheduler().runTaskLater(Pylon.getInstance(), () -> { List components = new ArrayList<>(); for (RebarItemSchema schema : RebarRegistry.ITEMS) { - if (RebarItem.fromStack(schema.getItemStack()) instanceof FluidTankCasing.Item) { + if (RebarItem.fromStack(schema.createNewItem()) instanceof FluidTankCasing.Item) { components.add(new RebarMultiblockComponent(schema.getKey())); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java index 8244ca82a..d8b689f57 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java @@ -19,6 +19,10 @@ import io.github.pylonmc.rebar.waila.WailaDisplay; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.item.CustomModelData; +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.JoinConfiguration; @@ -34,11 +38,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; -import java.util.stream.Collectors; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; @@ -167,7 +166,7 @@ public boolean isAllowedFluid(@NotNull RebarFluid fluid) { @Override public @Nullable ItemStack getPickItem() { // TODO implement clone for RebarItem and just clone it - ItemStack stack = RebarRegistry.ITEMS.getOrThrow(getKey()).getItemStack(); + ItemStack stack = RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItem(); Item item = new Item(stack); item.setFluid(getFluidType()); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java index 99b7b1b5f..ce248a92c 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java @@ -12,14 +12,13 @@ import io.github.pylonmc.rebar.recipe.RecipeType; import io.github.pylonmc.rebar.registry.RebarRegistry; import io.github.pylonmc.rebar.util.gui.GuiItems; +import java.util.ArrayList; +import java.util.List; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import xyz.xenondevs.invui.gui.Gui; -import java.util.ArrayList; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public interface HydraulicPurifier extends RebarTickingBlock { @@ -75,7 +74,7 @@ static List getPurifiers() { RebarItemSchema itemSchema = RebarRegistry.ITEMS.get(blockSchema.getKey()); if (itemSchema == null) continue; // should never happen - purifiers.add(itemSchema.getItemStack()); + purifiers.add(itemSchema.createNewItem()); } return purifiers; diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java b/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java index 6f847edc4..fd14f9938 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java @@ -11,7 +11,7 @@ public interface Moldable extends Keyed { boolean isMoldingFinished(); default ItemStack moldingInputStack() { - return RebarRegistry.ITEMS.getOrThrow(getKey()).getItemStack(); + return RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItem(); } default ItemStack moldingResult() { diff --git a/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java b/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java index e92535fa3..25ffe6bdb 100644 --- a/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java +++ b/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java @@ -8,13 +8,12 @@ import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; import io.github.pylonmc.rebar.registry.RebarRegistry; +import java.util.List; import lombok.Getter; import net.kyori.adventure.text.Component; import org.jspecify.annotations.NonNull; import xyz.xenondevs.invui.item.Item; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; @@ -34,8 +33,8 @@ public HydraulicRefuelableItemsPage() { private static @NonNull List getButtons() { return RebarRegistry.ITEMS.stream() - .filter(item -> RebarItem.fromStack(item.getItemStack()) instanceof HydraulicRefuelable) - .map(item -> (Item) new ItemButton(item.getItemStack())) + .filter(item -> RebarItem.fromStack(item.createNewItem()) instanceof HydraulicRefuelable) + .map(item -> (Item) new ItemButton(item.createNewItem())) .toList(); } } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java index f1ed76841..714654dce 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java @@ -13,15 +13,14 @@ import io.github.pylonmc.rebar.util.MiningLevel; import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.ArrayList; +import java.util.List; import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import xyz.xenondevs.invui.gui.Gui; -import java.util.ArrayList; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; /** @@ -97,7 +96,7 @@ public float getChanceFor(@NotNull MiningLevel hammerLevel) { private List getHammers() { List hammers = new ArrayList<>(); for (RebarItemSchema itemSchema : RebarRegistry.ITEMS.getValues()) { - ItemStack stack = itemSchema.getItemStack(); + ItemStack stack = itemSchema.createNewItem(); RebarItem item = RebarItem.fromStack(stack); if (item instanceof Hammer hammer) { float chance = Math.min(1, getChanceFor(hammer.miningLevel)); diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java index d05bfbfa5..a550d27a0 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java @@ -7,20 +7,15 @@ import io.github.pylonmc.rebar.guide.button.ItemButton; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.RebarItemSchema; -import io.github.pylonmc.rebar.recipe.ConfigurableRecipeType; -import io.github.pylonmc.rebar.recipe.FluidOrItem; -import io.github.pylonmc.rebar.recipe.RebarRecipe; -import io.github.pylonmc.rebar.recipe.RecipeInput; -import io.github.pylonmc.rebar.recipe.RecipeType; +import io.github.pylonmc.rebar.recipe.*; import io.github.pylonmc.rebar.registry.RebarRegistry; import io.github.pylonmc.rebar.util.gui.GuiItems; +import java.util.List; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import xyz.xenondevs.invui.gui.Gui; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; @@ -60,7 +55,7 @@ public record SiloConverterRecipe( public @NotNull Gui display() { List silos = RebarRegistry.ITEMS.getValues() .stream() - .map(RebarItemSchema::getItemStack) + .map(RebarItemSchema::createNewItem) .filter(item -> RebarItem.fromStack(item) instanceof Silo.Item) .filter(item -> !item.isSimilar(result)) .toList(); From 0277dc0c2c9ae61c9e4babe97d4bd8b3dcc6b2d4 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 22 Apr 2026 13:50:41 -0400 Subject: [PATCH 17/33] Working capacitors/acceptors --- .../io/github/pylonmc/pylon/PylonBlocks.java | 6 +- .../io/github/pylonmc/pylon/PylonItems.java | 8 ++ .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../content/machines/electric/Capacitor.java | 117 ++++++++++++++++++ .../electric/CreativePowerSource.java | 2 +- .../machines/electric/ElectricityPylon.java | 4 +- .../machines/electric/Transformer.java | 33 ++--- src/main/resources/lang/en.yml | 8 ++ .../resources/settings/capacitor_1_kj.yml | 1 + 9 files changed, 148 insertions(+), 32 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java create mode 100644 src/main/resources/settings/capacitor_1_kj.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 5d459b5d1..3028de361 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -7,10 +7,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; -import io.github.pylonmc.pylon.content.machines.electric.CreativePowerSource; -import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; -import io.github.pylonmc.pylon.content.machines.electric.ElectricityPylon; -import io.github.pylonmc.pylon.content.machines.electric.Transformer; +import io.github.pylonmc.pylon.content.machines.electric.*; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -187,6 +184,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.SILO_CONVERTER, Material.STRIPPED_OAK_LOG, SiloConverter.class); RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); + RebarBlock.register(PylonKeys.CAPACITOR_1_KJ, Material.BLUE_GLAZED_TERRACOTTA, Capacitor.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 08944cb3c..3db71cbc7 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -16,6 +16,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; +import io.github.pylonmc.pylon.content.machines.electric.Capacitor; import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.electric.Multimeter; import io.github.pylonmc.pylon.content.machines.fluid.*; @@ -3209,6 +3210,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(TRANSFORMER); } + public static final ItemStack CAPACITOR_1_KJ = ItemStackBuilder.rebar(Material.BLUE_GLAZED_TERRACOTTA, PylonKeys.CAPACITOR_1_KJ) + .build(); + static { + RebarItem.register(Capacitor.Item.class, CAPACITOR_1_KJ, PylonKeys.CAPACITOR_1_KJ); + PylonPages.ELECTRICITY.addItem(CAPACITOR_1_KJ); + } + public static final ItemStack WIRE_1_GAUGE = ItemStackBuilder.rebar(Material.STRING, PylonKeys.WIRE_1_GAUGE) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 09d2bae5f..9e5f29f28 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -465,6 +465,7 @@ public class PylonKeys { public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); public static final NamespacedKey TRANSFORMER = pylonKey("transformer"); + public static final NamespacedKey CAPACITOR_1_KJ = pylonKey("capacitor_1_kj"); public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java new file mode 100644 index 000000000..a6a9156b1 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java @@ -0,0 +1,117 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.Settings; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.entity.display.TextDisplayBuilder; +import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.List; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.entity.TextDisplay; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public class Capacitor extends RebarBlock implements + RebarElectricBlock, + RebarDirectionalBlock { + + public static final class Item extends RebarItem { + + private final double capacity = getSettings().getOrThrow("capacity", ConfigAdapter.DOUBLE); + + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of(RebarArgument.of("capacity", UnitFormat.JOULES.format(capacity))); + } + } + + private final double capacity = getSettings().getOrThrow("capacity", ConfigAdapter.DOUBLE); + + private static final NamespacedKey STORED_ENERGY_KEY = pylonKey("stored_energy"); + private double storedEnergy; + + private ElectricNode.Producer output; + + @SuppressWarnings("unused") + public Capacitor(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + setFacing(context.getFacing()); + + addElectricPort(getFacing(), new ElectricNode.Acceptor("input", new BlockPosition(block))); + addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0, 0)); + + addEntity("text_0", new TextDisplayBuilder() + .transformation(new TransformBuilder() + .lookAlong(getFacing()) + .rotate(0, Math.PI / 2, 0)) + .build(getBlock().getLocation().toCenterLocation().add(getFacing().getDirection().multiply(0.5001).rotateAroundY(Math.PI / 2))) + ); + + addEntity("text_1", new TextDisplayBuilder() + .transformation(new TransformBuilder() + .lookAlong(getFacing()) + .rotate(0, -Math.PI / 2, 0)) + .build(getBlock().getLocation().toCenterLocation().add(getFacing().getDirection().multiply(0.5001).rotateAroundY(-Math.PI / 2))) + ); + + storedEnergy = 0; + } + + @SuppressWarnings({"unused", "DataFlowIssue"}) + public Capacitor(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + + storedEnergy = pdc.get(STORED_ENERGY_KEY, RebarSerializers.DOUBLE); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(STORED_ENERGY_KEY, RebarSerializers.DOUBLE, storedEnergy); + } + + @Override + public void postInitialise() { + ElectricNode.Acceptor input = (ElectricNode.Acceptor) getElectricNodeOrThrow("input"); + input.onAccept(energy -> { + double accepted = Math.min(energy, capacity - storedEnergy); + setStoredEnergy(storedEnergy + accepted); + return accepted; + }); + + output = (ElectricNode.Producer) getElectricNodeOrThrow("output"); + output.onPowerTake(energy -> { + double taken = Math.min(energy, storedEnergy); + setStoredEnergy(storedEnergy - taken); + }); + + setStoredEnergy(storedEnergy); + } + + public void setStoredEnergy(double energy) { + storedEnergy = energy; + getHeldEntityOrThrow(TextDisplay.class, "text_0").text(UnitFormat.JOULES.format(storedEnergy).decimalPlaces(1).asComponent()); + getHeldEntityOrThrow(TextDisplay.class, "text_1").text(UnitFormat.JOULES.format(storedEnergy).decimalPlaces(1).asComponent()); + double maxCurrent = Settings.get(PylonKeys.WIRE_1_GAUGE).getOrThrow("max-current", ConfigAdapter.DOUBLE); + output.setPower(storedEnergy); + output.setVoltage(storedEnergy / maxCurrent); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index c35686371..d1427c268 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -26,7 +26,7 @@ public CreativePowerSource(@NotNull Block block, @NotNull BlockCreateContext con setFacing(context.getFacing()); } - @SuppressWarnings({"unused", "DataFlowIssue"}) + @SuppressWarnings({"unused"}) public CreativePowerSource(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java index e0e9e0f21..6615aec89 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java @@ -24,9 +24,9 @@ public ElectricityPylon(@NotNull Block block, @NotNull BlockCreateContext contex super(block, context); setTickInterval(10); - ElectricNode.Connector centralNode = addElectricNode(new ElectricNode.Connector(new BlockPosition(block))); + ElectricNode.Connector centralNode = addElectricNode(new ElectricNode.Connector("center", new BlockPosition(block))); for (BlockFace face : RebarUtils.IMMEDIATE_FACES) { - ElectricNode.Connector port = addElectricPort(face, new ElectricNode.Connector(new BlockPosition(block))); + ElectricNode.Connector port = addElectricPort(face, new ElectricNode.Connector(face.name(), new BlockPosition(block))); centralNode.connect(port); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java index 9246d8a91..d17e4babf 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java @@ -14,7 +14,6 @@ import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.util.position.BlockPosition; -import java.util.UUID; import lombok.Getter; import net.kyori.adventure.text.Component; import org.bukkit.Material; @@ -36,11 +35,6 @@ public class Transformer extends RebarBlock implements RebarGuiBlock { private static final NamespacedKey VOLTAGE_KEY = pylonKey("voltage"); - private static final NamespacedKey INPUT_NODE_KEY = pylonKey("input_node"); - private static final NamespacedKey OUTPUT_NODE_KEY = pylonKey("output_node"); - - private ElectricNode.Connector inputNode; - private ElectricNode.Connector outputNode; @Getter private double voltage; @@ -165,10 +159,9 @@ public Transformer(@NotNull Block block, @NotNull BlockCreateContext context) { voltage = 0; - inputNode = addElectricPort(getFacing(), new ElectricNode.Connector(new BlockPosition(block))); - outputNode = addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Connector(new BlockPosition(block))); - inputNode.connect(outputNode); - ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); + ElectricNode first = addElectricPort(getFacing(), new ElectricNode.Connector("first", new BlockPosition(block))); + ElectricNode second = addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Connector("second", new BlockPosition(block))); + first.connect(second); } @SuppressWarnings({"unused", "DataFlowIssue"}) @@ -179,25 +172,13 @@ public Transformer(@NotNull Block block, @NotNull PersistentDataContainer pdc) { } @Override - protected void postLoad(@NotNull PersistentDataContainer pdc) { - UUID inputNodeId = pdc.get(INPUT_NODE_KEY, RebarSerializers.UUID); - UUID outputNodeId = pdc.get(OUTPUT_NODE_KEY, RebarSerializers.UUID); - inputNode = (ElectricNode.Connector) getElectricNodes().stream() - .filter(node -> node.getId().equals(inputNodeId)) - .findFirst() - .orElseThrow(); - outputNode = (ElectricNode.Connector) getElectricNodes().stream() - .filter(node -> node.getId().equals(outputNodeId)) - .findFirst() - .orElseThrow(); - ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); + public void postInitialise() { + setVoltage(voltage); } @Override public void write(@NotNull PersistentDataContainer pdc) { pdc.set(VOLTAGE_KEY, RebarSerializers.DOUBLE, voltage); - pdc.set(INPUT_NODE_KEY, RebarSerializers.UUID, inputNode.getId()); - pdc.set(OUTPUT_NODE_KEY, RebarSerializers.UUID, outputNode.getId()); } @Override @@ -221,6 +202,8 @@ public void write(@NotNull PersistentDataContainer pdc) { public void setVoltage(double voltage) { this.voltage = voltage; - ElectricityManager.setTransformerEdge(inputNode, outputNode, voltage); + ElectricNode.Connector first = (ElectricNode.Connector) getElectricNodeOrThrow("first"); + ElectricNode.Connector second = (ElectricNode.Connector) getElectricNodeOrThrow("second"); + ElectricityManager.setTransformerEdge(first, second, voltage); } } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 60cb75104..68877ebb6 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2442,6 +2442,14 @@ item: Transmits electricity Max current: %max-current% + capacitor_1_kj: + name: "1 kJ Capacitor" + lore: |- + Stores electricity + Capacitors have a lower priority than most electric blocks, so they will only take excess power that other blocks can't use + The output voltage is such that the entire charge can be passed through a in one tick + Capacity: %capacity% + fluid: castable: display-text: " Casts into %result%" diff --git a/src/main/resources/settings/capacitor_1_kj.yml b/src/main/resources/settings/capacitor_1_kj.yml new file mode 100644 index 000000000..a394186b5 --- /dev/null +++ b/src/main/resources/settings/capacitor_1_kj.yml @@ -0,0 +1 @@ +capacity: 1000 \ No newline at end of file From 69402e216be4cef4229947d36520f1fe3d68ee6a Mon Sep 17 00:00:00 2001 From: Seggan Date: Fri, 24 Apr 2026 11:16:41 -0400 Subject: [PATCH 18/33] Boiler --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonFluids.java | 13 +- .../io/github/pylonmc/pylon/PylonItems.java | 8 + .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../content/machines/electric/Boiler.java | 239 ++++++++++++++++++ .../machines/smelting/SmelteryBurner.java | 75 +++--- .../pylon/util/BurnerProgressItem.java | 33 +++ src/main/resources/lang/en.yml | 10 +- src/main/resources/settings/boiler.yml | 9 + 9 files changed, 343 insertions(+), 46 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java create mode 100644 src/main/java/io/github/pylonmc/pylon/util/BurnerProgressItem.java create mode 100644 src/main/resources/settings/boiler.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 3028de361..937110675 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -186,6 +186,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); RebarBlock.register(PylonKeys.CAPACITOR_1_KJ, Material.BLUE_GLAZED_TERRACOTTA, Capacitor.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); + RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonFluids.java b/src/main/java/io/github/pylonmc/pylon/PylonFluids.java index ce19ff30b..23fa39237 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonFluids.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonFluids.java @@ -8,8 +8,6 @@ import org.bukkit.Material; import org.bukkit.inventory.ItemStack; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class PylonFluids { @@ -18,6 +16,8 @@ private PylonFluids() { throw new AssertionError("Utility class"); } + public static final double WATER_TO_STEAM_RATIO = 1.0 / 10.0; + public static final RebarFluid WATER = new RebarFluid( pylonKey("water"), Material.BLUE_CONCRETE @@ -36,6 +36,14 @@ private PylonFluids() { IngredientCalculator.addBaseIngredient(LAVA); } + public static final RebarFluid STEAM = new RebarFluid( + pylonKey("steam"), + Material.WHITE_STAINED_GLASS + ).addTag(FluidTemperature.HOT); + static { + STEAM.register(); + } + public static final RebarFluid PLANT_OIL = new RebarFluid( pylonKey("plant_oil"), Material.YELLOW_CONCRETE_POWDER @@ -53,7 +61,6 @@ private PylonFluids() { HYDRAULIC_FLUID.register(); } - public static final RebarFluid DIRTY_HYDRAULIC_FLUID = new RebarFluid( pylonKey("dirty_hydraulic_fluid"), Material.BROWN_CONCRETE_POWDER diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 3db71cbc7..29069f0d3 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -16,6 +16,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; +import io.github.pylonmc.pylon.content.machines.electric.Boiler; import io.github.pylonmc.pylon.content.machines.electric.Capacitor; import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.electric.Multimeter; @@ -3237,6 +3238,13 @@ private PylonItems() { RebarItem.register(RebarItem.class, CREATIVE_POWER_SOURCE, PylonKeys.CREATIVE_POWER_SOURCE); PylonPages.CREATIVE_ITEMS.addItem(CREATIVE_POWER_SOURCE); } + + public static final ItemStack BOILER = ItemStackBuilder.rebar(Material.BLAST_FURNACE, PylonKeys.BOILER) + .build(); + static { + RebarItem.register(Boiler.Item.class, BOILER, PylonKeys.BOILER); + PylonPages.ELECTRICITY.addItem(BOILER); + } public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) .build(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 9e5f29f28..1fb41f086 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -469,5 +469,6 @@ public class PylonKeys { public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); + public static final NamespacedKey BOILER = pylonKey("boiler"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java new file mode 100644 index 000000000..1957202aa --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -0,0 +1,239 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonFluids; +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.content.components.FluidInputHatch; +import io.github.pylonmc.pylon.content.components.FluidOutputHatch; +import io.github.pylonmc.pylon.util.BurnerProgressItem; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.Settings; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.ItemTypeWrapper; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.logistics.LogisticGroupType; +import io.github.pylonmc.rebar.registry.RebarRegistry; +import io.github.pylonmc.rebar.util.MachineUpdateReason; +import io.github.pylonmc.rebar.util.RebarUtils; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import kotlin.Pair; +import org.bukkit.Keyed; +import org.bukkit.NamespacedKey; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3i; +import xyz.xenondevs.invui.gui.Gui; +import xyz.xenondevs.invui.inventory.VirtualInventory; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public class Boiler extends RebarBlock implements + RebarSimpleMultiblock, +RebarDirectionalBlock, + RebarProcessor, + RebarTickingBlock, + RebarVirtualInventoryBlock, + RebarGuiBlock, + RebarLogisticBlock { + + public static class Item extends RebarItem { + + private final double steamPerSecond = getSettings().getOrThrow("steam-per-second", ConfigAdapter.DOUBLE); + + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of( + RebarArgument.of("water-usage", UnitFormat.MILLIBUCKETS_PER_SECOND.format(steamPerSecond * PylonFluids.WATER_TO_STEAM_RATIO)), + RebarArgument.of("steam-production", UnitFormat.MILLIBUCKETS_PER_SECOND.format(steamPerSecond)) + ); + } + } + + private static final ConfigAdapter> FUELS_TYPE = ConfigAdapter.MAP.from( + ConfigAdapter.ITEM_STACK, + ConfigAdapter.INTEGER + ); + + public record Fuel(@NotNull NamespacedKey key, @NotNull ItemStack item, int burnTimeSeconds) implements Keyed { + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + } + + public static final RebarRegistry FUEL_REGISTRY = new RebarRegistry<>(pylonKey("boiler_fuels")); + + static { + for (var fuel : Settings.get(PylonKeys.BOILER).getOrThrow("fuels", FUELS_TYPE).entrySet()) { + FUEL_REGISTRY.register(new Fuel(ItemTypeWrapper.of(fuel.getKey()).getKey(), fuel.getKey(), fuel.getValue())); + } + } + + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + private final double steamPerSecond = getSettings().getOrThrow("steam-per-second", ConfigAdapter.DOUBLE); + + private final VirtualInventory fuelInventory = new VirtualInventory(1); + private final BurnerProgressItem progressItem = new BurnerProgressItem(); + + @SuppressWarnings("unused") + public Boiler(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setTickInterval(tickInterval); + setFacing(context.getFacing()); + setMultiblockDirection(context.getFacing()); + } + + @SuppressWarnings("unused") + public Boiler(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void postInitialise() { + setProcessProgressItem(progressItem); + createLogisticGroup("fuel", LogisticGroupType.INPUT, fuelInventory); + fuelInventory.addPreUpdateHandler(event -> { + ItemStack item = event.getNewItem(); + for (Fuel fuel : FUEL_REGISTRY) { + if (fuel.item().isSimilar(item)) { + return; + } + } + event.setCancelled(true); + }); + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # i p i # # #", + "# # # i x i # # #", + "# # # i i i # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.background()) + .addIngredient('i', GuiItems.input()) + .addIngredient('p', progressItem) + .addIngredient('x', fuelInventory) + .build(); + } + + @Override + public @NotNull Map<@NotNull String, @NotNull VirtualInventory> getVirtualInventories() { + return Map.of("fuel", fuelInventory); + } + + private static final Vector3i WATER_INPUT_HATCH = new Vector3i(1, 0, 0); + private static final Vector3i STEAM_OUTPUT_HATCH = new Vector3i(-1, 0, 0); + private static final Vector3i SMOKESTACK_CAP = new Vector3i(0, 2, 1); + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + Map components = new HashMap<>(); + + components.put(WATER_INPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_INPUT_HATCH)); + components.put(STEAM_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_OUTPUT_HATCH)); + + // bottom layer + for (int x = -1; x <= 1; x++) { + for (int z = 0; z <= 2; z++) { + components.put(new Vector3i(x, -1, z), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + } + } + + // middle layer + components.put(new Vector3i(-1, 0, 1), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(1, 0, 1), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(-1, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(0, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(1, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + + // top layer + components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + for (int x = -1; x <= 1; x++) { + for (int z = 1; z <= 2; z++) { + components.put(new Vector3i(x, 1, z), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + } + } + + components.put(SMOKESTACK_CAP, new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + + return components; + } + + @Override + public void onMultiblockFormed() { + RebarSimpleMultiblock.super.onMultiblockFormed(); + getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH).setFluidType(PylonFluids.WATER); + getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH).setFluidType(PylonFluids.STEAM); + } + + private void tryStartProcessing() { + for (Fuel fuel : FUEL_REGISTRY) { + if (fuelInventory.removeFirstSimilar(new MachineUpdateReason(), 1, fuel.item()) > 0) { + startProcess(fuel.burnTimeSeconds() * 20); + refreshBlockTextureItem(); + return; + } + } + } + + @Override + public void tick() { + if (!isFormedAndFullyLoaded()) return; + + if (!isProcessing()) { + tryStartProcessing(); + } + + if (!isProcessing()) return; + + progressProcess(tickInterval); + + double steamProduction = steamPerSecond * (tickInterval / 20.0); + double waterConsumption = steamProduction * PylonFluids.WATER_TO_STEAM_RATIO; + FluidInputHatch waterInput = getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH); + FluidOutputHatch steamOutput = getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH); + double toRemove = Math.min(Math.min(waterInput.fluidAmount(PylonFluids.WATER), waterConsumption), steamOutput.fluidSpaceRemaining(PylonFluids.STEAM) * PylonFluids.WATER_TO_STEAM_RATIO); + if (toRemove > 0) { + waterInput.removeFluid(PylonFluids.WATER, toRemove); + steamOutput.addFluid(PylonFluids.STEAM, toRemove / PylonFluids.WATER_TO_STEAM_RATIO); + } + + Particle.CAMPFIRE_SIGNAL_SMOKE.builder() + .location(getBlock().getLocation().add(Vector.fromJOML(RebarUtils.rotateVectorToFace(SMOKESTACK_CAP, getFacing()))).toCenterLocation()) + .offset(0, 1, 0) + .count(0) + .extra(0.03) + .spawn(); + } + + @Override + public void finishProcess() { + refreshBlockTextureItem(); + tryStartProcessing(); + } + + @Override + public @NotNull Map<@NotNull String, @NotNull Pair<@NotNull String, @NotNull Integer>> getBlockTextureProperties() { + var properties = super.getBlockTextureProperties(); + properties.put("lit", new Pair<>(String.valueOf(isProcessing()), 2)); + return properties; + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryBurner.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryBurner.java index cd269c00a..b805d7a66 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryBurner.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryBurner.java @@ -1,17 +1,17 @@ package io.github.pylonmc.pylon.content.machines.smelting; import io.github.pylonmc.pylon.PylonItems; +import io.github.pylonmc.pylon.util.BurnerProgressItem; import io.github.pylonmc.rebar.block.base.*; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.datatypes.RebarSerializers; -import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; import io.github.pylonmc.rebar.logistics.LogisticGroupType; import io.github.pylonmc.rebar.registry.RebarRegistry; +import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.util.gui.GuiItems; -import io.github.pylonmc.rebar.util.gui.ProgressItem; +import java.util.Map; import kotlin.Pair; -import net.kyori.adventure.text.Component; import org.bukkit.Keyed; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -24,8 +24,6 @@ import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import java.util.Map; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public final class SmelteryBurner extends SmelteryComponent implements @@ -47,13 +45,8 @@ public final class SmelteryBurner extends SmelteryComponent implements private @Nullable Fuel fuel; - private final ItemStackBuilder notBurningProgressItem = ItemStackBuilder.of(Material.BLAZE_POWDER) - .name(Component.translatable("pylon.gui.smeltery_burner.not_burning")); - private final ItemStackBuilder burningProgressItem = ItemStackBuilder.of(Material.BLAZE_POWDER) - .name(Component.translatable("pylon.gui.smeltery_burner.burning")); - - private final VirtualInventory inventory = new VirtualInventory(3); - private final ProgressItem progressItem = new ProgressItem(notBurningProgressItem); + private final VirtualInventory fuelInventory = new VirtualInventory(3); + private final BurnerProgressItem progressItem = new BurnerProgressItem(); @SuppressWarnings("unused") public SmelteryBurner(@NotNull Block block, @NotNull BlockCreateContext context) { @@ -79,13 +72,13 @@ public void write(@NotNull PersistentDataContainer pdc) { @Override public void postInitialise() { setProcessProgressItem(progressItem); - createLogisticGroup("fuel", LogisticGroupType.INPUT, inventory); + createLogisticGroup("fuel", LogisticGroupType.INPUT, fuelInventory); } @Override public @NotNull Map> getBlockTextureProperties() { var properties = super.getBlockTextureProperties(); - properties.put("lit", new Pair<>(fuel != null ? "true" : "false", 2)); + properties.put("lit", new Pair<>(String.valueOf(fuel != null), 2)); return properties; } @@ -94,16 +87,29 @@ public void postInitialise() { return Gui.builder() .setStructure( "# # # # # # # # #", - "# # # # f # # # #", - "# # # x x x # # #", + "# # # i p i # # #", + "# # # i x i # # #", + "# # # i i i # # #", "# # # # # # # # #" ) - .addIngredient('f', progressItem) - .addIngredient('x', inventory) .addIngredient('#', GuiItems.background()) + .addIngredient('i', GuiItems.input()) + .addIngredient('p', progressItem) + .addIngredient('x', fuelInventory) .build(); } + private void tryStartProcessing() { + for (Fuel fuel : FUELS) { + if (fuelInventory.removeFirstSimilar(new MachineUpdateReason(), 1, fuel.material()) > 0) { + this.fuel = fuel; + startProcess(fuel.burnTimeSeconds() * 20); + refreshBlockTextureItem(); + return; + } + } + } + @Override public void tick() { SmelteryController controller = getController(); @@ -111,45 +117,30 @@ public void tick() { return; } + if (!isProcessing()) { + tryStartProcessing(); + } + + if (!isProcessing()) return; + progressProcess(getTickInterval()); if (fuel != null) { controller.heatAsymptotically(fuel.temperature); return; } - - itemLoop: - for (int i = 0; i < inventory.getSize(); i++) { - ItemStack item = inventory.getItem(i); - if (item == null) { - continue; - } - - for (Fuel fuel : FUELS) { - if (!item.isSimilar(fuel.material)) { - continue; - } - - this.fuel = fuel; - progressItem.setItem(burningProgressItem); - inventory.setItem(null, i, item.subtract()); - startProcess(Math.round(fuel.burnTimeSeconds * 20)); - refreshBlockTextureItem(); - break itemLoop; - } - } } @Override public void onProcessFinished() { - progressItem.setItem(notBurningProgressItem); refreshBlockTextureItem(); fuel = null; + tryStartProcessing(); } @Override public @NotNull Map getVirtualInventories() { - return Map.of("fuels", inventory); + return Map.of("fuels", fuelInventory); } // TODO display fuels @@ -157,7 +148,7 @@ public record Fuel( @NotNull NamespacedKey key, @NotNull ItemStack material, double temperature, - long burnTimeSeconds + int burnTimeSeconds ) implements Keyed { @Override public @NotNull NamespacedKey getKey() { diff --git a/src/main/java/io/github/pylonmc/pylon/util/BurnerProgressItem.java b/src/main/java/io/github/pylonmc/pylon/util/BurnerProgressItem.java new file mode 100644 index 000000000..b8cc06d8c --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/util/BurnerProgressItem.java @@ -0,0 +1,33 @@ +package io.github.pylonmc.pylon.util; + +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.gui.ProgressItem; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.item.ItemProvider; + +public class BurnerProgressItem extends ProgressItem { + + private static final ItemStackBuilder NOT_BURNING = ItemStackBuilder.of(Material.CHARCOAL) + .name(Component.translatable("pylon.gui.burning.not_burning")) + .addCustomModelDataString("pylon:burner_progress/not_burning"); + private static final ItemStackBuilder BURNING = ItemStackBuilder.of(Material.BLAZE_POWDER) + .name(Component.translatable("pylon.gui.burning.burning")) + .addCustomModelDataString("pylon:burner_progress/burning"); + + public BurnerProgressItem() { + super(NOT_BURNING); + } + + @Override + public @NotNull ItemProvider getItemProvider(@NotNull Player viewer) { + if (getTotalTime() != null) { + setItem(BURNING); + } else { + setItem(NOT_BURNING); + } + return super.getItemProvider(viewer); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 68877ebb6..b9eff9c08 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2436,6 +2436,13 @@ item: Power usage: %power-usage% Voltage range: %min-voltage% to %max-voltage% + boiler: + name: "Boiler" + lore: |- + Burns fuel to produce steam + Water usage: %water-usage% + Steam production: %steam-production% + wire_1_gauge: name: "1-Gauge Wire" lore: |- @@ -2473,6 +2480,7 @@ fluid: sulfur: "Liquid Sulfur" tin: "Liquid Tin" water: "Water" + steam: "<#d8d8d8>Steam" palladium: "<#b642f5>Liquid Palladium" plant_oil: "<#c4b352>Plant Oil" hydraulic_fluid: "<#212d99>Hydraulic Fluid" @@ -2826,7 +2834,7 @@ gui: name: "Contents" fluid: "%amount% of %fluid%" empty: "Empty" - smeltery_burner: + burning: burning: "Burning" not_burning: "Not burning" smeltery_caster: diff --git a/src/main/resources/settings/boiler.yml b/src/main/resources/settings/boiler.yml new file mode 100644 index 000000000..c874438ac --- /dev/null +++ b/src/main/resources/settings/boiler.yml @@ -0,0 +1,9 @@ +tick-interval: 10 +steam-per-second: 100 + +# map of fluid to burn amount in seconds +fuels: + minecraft:coal: 30 + minecraft:charcoal: 30 + minecraft:coal_block: 270 + pylon:charcoal_block: 270 \ No newline at end of file From 852ac2efa49f6fa5895a5ee23822dcd975a4cc40 Mon Sep 17 00:00:00 2001 From: Seggan Date: Fri, 24 Apr 2026 11:27:11 -0400 Subject: [PATCH 19/33] Boiler recipe --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonItems.java | 9 ++++++++ .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../content/machines/electric/Boiler.java | 16 +++++++------- src/main/resources/lang/en.yml | 10 +++++++++ .../recipes/minecraft/crafting_shaped.yml | 22 +++++++++++++++++++ src/main/resources/settings/boiler.yml | 2 +- 7 files changed, 52 insertions(+), 9 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 937110675..0dc5015a2 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -186,6 +186,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); RebarBlock.register(PylonKeys.CAPACITOR_1_KJ, Material.BLUE_GLAZED_TERRACOTTA, Capacitor.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); + RebarBlock.register(PylonKeys.BOILER_CASING, Material.NETHERITE_BLOCK, RebarBlock.class); RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 29069f0d3..5ec3c6b7e 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3196,6 +3196,7 @@ private PylonItems() { RecipeType.VANILLA_SHAPELESS.addRecipe(recipe); } + // public static final ItemStack ELECTRICITY_PYLON = ItemStackBuilder.rebar(Material.SEA_LANTERN, PylonKeys.ELECTRICITY_PYLON) .build(); static { @@ -3238,6 +3239,13 @@ private PylonItems() { RebarItem.register(RebarItem.class, CREATIVE_POWER_SOURCE, PylonKeys.CREATIVE_POWER_SOURCE); PylonPages.CREATIVE_ITEMS.addItem(CREATIVE_POWER_SOURCE); } + + public static final ItemStack BOILER_CASING = ItemStackBuilder.rebar(Material.NETHERITE_BLOCK, PylonKeys.BOILER_CASING) + .build(); + static { + RebarItem.register(RebarItem.class, BOILER_CASING, PylonKeys.BOILER_CASING); + PylonPages.COMPONENTS.addItem(BOILER_CASING); + } public static final ItemStack BOILER = ItemStackBuilder.rebar(Material.BLAST_FURNACE, PylonKeys.BOILER) .build(); @@ -3252,6 +3260,7 @@ private PylonItems() { RebarItem.register(ElectricGrindstone.Item.class, ELECTRIC_GRINDSTONE, PylonKeys.ELECTRIC_GRINDSTONE); PylonPages.ELECTRICITY.addItem(ELECTRIC_GRINDSTONE); } + // static { PylonPages.initialise(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 1fb41f086..8d7d58a04 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -469,6 +469,7 @@ public class PylonKeys { public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); + public static final NamespacedKey BOILER_CASING = pylonKey("boiler_casing"); public static final NamespacedKey BOILER = pylonKey("boiler"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index 1957202aa..911829901 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -153,22 +153,22 @@ public void postInitialise() { // bottom layer for (int x = -1; x <= 1; x++) { for (int z = 0; z <= 2; z++) { - components.put(new Vector3i(x, -1, z), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(x, -1, z), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); } } // middle layer - components.put(new Vector3i(-1, 0, 1), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); - components.put(new Vector3i(1, 0, 1), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); - components.put(new Vector3i(-1, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); - components.put(new Vector3i(0, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); - components.put(new Vector3i(1, 0, 2), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(-1, 0, 1), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(1, 0, 1), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(-1, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(0, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(1, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); // top layer - components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); for (int x = -1; x <= 1; x++) { for (int z = 1; z <= 2; z++) { - components.put(new Vector3i(x, 1, z), new RebarMultiblockComponent(PylonKeys.STEEL_BLOCK)); + components.put(new Vector3i(x, 1, z), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); } } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index b9eff9c08..83e85506f 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2436,12 +2436,22 @@ item: Power usage: %power-usage% Voltage range: %min-voltage% to %max-voltage% + boiler_casing: + name: "Boiler Casing" + boiler: name: "Boiler" lore: |- Burns fuel to produce steam Water usage: %water-usage% Steam production: %steam-production% + + Components + 1x + 20x + 1x + 1x + 1x wire_1_gauge: name: "1-Gauge Wire" diff --git a/src/main/resources/recipes/minecraft/crafting_shaped.yml b/src/main/resources/recipes/minecraft/crafting_shaped.yml index 6a8013b8b..da752c661 100644 --- a/src/main/resources/recipes/minecraft/crafting_shaped.yml +++ b/src/main/resources/recipes/minecraft/crafting_shaped.yml @@ -2772,3 +2772,25 @@ pylon:palladium_silo: result: pylon:palladium_silo: 4 category: building + +pylon:boiler_casing: + pattern: + - "SSS" + - "S S" + - "SSS" + key: + S: pylon:steel_sheet + result: + pylon:boiler_casing: 4 + category: building + +pylon:boiler: + pattern: + - " C " + - "CFC" + - " C " + key: + C: pylon:boiler_casing + F: minecraft:furnace + result: pylon:boiler + category: building \ No newline at end of file diff --git a/src/main/resources/settings/boiler.yml b/src/main/resources/settings/boiler.yml index c874438ac..72129e9a8 100644 --- a/src/main/resources/settings/boiler.yml +++ b/src/main/resources/settings/boiler.yml @@ -1,5 +1,5 @@ tick-interval: 10 -steam-per-second: 100 +steam-per-second: 500 # map of fluid to burn amount in seconds fuels: From 22a20b7a45f74ed39396b4724bf08f5002764d67 Mon Sep 17 00:00:00 2001 From: Seggan Date: Mon, 27 Apr 2026 14:43:44 -0400 Subject: [PATCH 20/33] Steam power go brr --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonItems.java | 12 +- .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../content/machines/electric/Boiler.java | 2 +- .../machines/electric/ElectricGrindstone.java | 14 +- .../machines/electric/SteamEngine.java | 129 ++++++++++++++++++ src/main/resources/lang/en.yml | 19 ++- src/main/resources/settings/steam_engine.yml | 5 + 8 files changed, 167 insertions(+), 16 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java create mode 100644 src/main/resources/settings/steam_engine.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 0dc5015a2..1c0cc56d7 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -188,6 +188,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); RebarBlock.register(PylonKeys.BOILER_CASING, Material.NETHERITE_BLOCK, RebarBlock.class); RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); + RebarBlock.register(PylonKeys.STEAM_ENGINE, Material.IRON_BLOCK, SteamEngine.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 5ec3c6b7e..f656e4651 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -16,10 +16,7 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; -import io.github.pylonmc.pylon.content.machines.electric.Boiler; -import io.github.pylonmc.pylon.content.machines.electric.Capacitor; -import io.github.pylonmc.pylon.content.machines.electric.ElectricGrindstone; -import io.github.pylonmc.pylon.content.machines.electric.Multimeter; +import io.github.pylonmc.pylon.content.machines.electric.*; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; @@ -3254,6 +3251,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(BOILER); } + public static final ItemStack STEAM_ENGINE = ItemStackBuilder.rebar(Material.IRON_BLOCK, PylonKeys.STEAM_ENGINE) + .build(); + static { + RebarItem.register(SteamEngine.Item.class, STEAM_ENGINE, PylonKeys.STEAM_ENGINE); + PylonPages.ELECTRICITY.addItem(STEAM_ENGINE); + } + public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 8d7d58a04..43ddf11c8 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -471,5 +471,6 @@ public class PylonKeys { public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); public static final NamespacedKey BOILER_CASING = pylonKey("boiler_casing"); public static final NamespacedKey BOILER = pylonKey("boiler"); + public static final NamespacedKey STEAM_ENGINE = pylonKey("steam_engine"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index 911829901..7df84769a 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -39,7 +39,7 @@ public class Boiler extends RebarBlock implements RebarSimpleMultiblock, -RebarDirectionalBlock, + RebarDirectionalBlock, RebarProcessor, RebarTickingBlock, RebarVirtualInventoryBlock, diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index ceeee4978..14b5b7832 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -8,10 +8,7 @@ import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import io.github.pylonmc.rebar.util.position.BlockPosition; import java.util.List; -import net.kyori.adventure.text.Component; -import org.bukkit.Bukkit; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; @@ -20,6 +17,10 @@ public class ElectricGrindstone extends AbstractGrindstone implements RebarElectricConsumerBlock { + private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + private final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); + private final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); + public static class Item extends RebarItem { public final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); @@ -40,10 +41,6 @@ public Item(@NotNull ItemStack stack) { } } - private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); - private final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); - private final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); - @SuppressWarnings("unused") public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); @@ -67,6 +64,7 @@ public double getRequiredPower() { @Override public void tick() { - Bukkit.broadcast(Component.text(new BlockPosition(getBlock()) + (isPowered() ? "This better be 100% free-range electricity" : "WHERES MAH POWER"))); + if (!isProcessingRecipe() || !isPowered()) return; + progressRecipe(tickInterval); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java new file mode 100644 index 000000000..ca1efff14 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java @@ -0,0 +1,129 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonFluids; +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.util.PylonUtils; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.electricity.ElectricNode; +import io.github.pylonmc.rebar.fluid.FluidPointType; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import io.github.pylonmc.rebar.util.position.BlockPosition; +import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.List; +import java.util.Map; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3i; + +public class SteamEngine extends RebarBlock implements + RebarDirectionalBlock, + RebarFluidBufferBlock, + RebarElectricBlock, + RebarTickingBlock, + RebarSimpleMultiblock { + + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + private final double steamUsage = getSettings().getOrThrow("steam-usage", ConfigAdapter.DOUBLE); + private final double steamCapacity = getSettings().getOrThrow("steam-capacity", ConfigAdapter.DOUBLE); + private final double powerProduction = getSettings().getOrThrow("power-production", ConfigAdapter.DOUBLE); + private final double outputVoltage = getSettings().getOrThrow("output-voltage", ConfigAdapter.DOUBLE); + + public static final class Item extends RebarItem { + + private final double steamUsage = getSettings().getOrThrow("steam-usage", ConfigAdapter.DOUBLE); + private final double steamCapacity = getSettings().getOrThrow("steam-capacity", ConfigAdapter.DOUBLE); + private final double powerProduction = getSettings().getOrThrow("power-production", ConfigAdapter.DOUBLE); + private final double outputVoltage = getSettings().getOrThrow("output-voltage", ConfigAdapter.DOUBLE); + + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of( + RebarArgument.of("steam-usage", UnitFormat.MILLIBUCKETS_PER_SECOND.format(steamUsage)), + RebarArgument.of("steam-capacity", UnitFormat.MILLIBUCKETS.format(steamCapacity)), + RebarArgument.of("power-production", UnitFormat.WATTS.format(powerProduction)), + RebarArgument.of("output-voltage", UnitFormat.VOLTS.format(outputVoltage)) + ); + } + } + + private ElectricNode.Producer node; + + @SuppressWarnings("unused") + public SteamEngine(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + setTickInterval(tickInterval); + createFluidPoint(FluidPointType.INPUT, context.getFacing()); + createFluidBuffer(PylonFluids.STEAM, steamCapacity, true, false); + addElectricPort(context.getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0, 0)); + } + + @SuppressWarnings("unused") + public SteamEngine(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void postInitialise() { + node = (ElectricNode.Producer) getElectricNodeOrThrow("output"); + } + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + return Map.of(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + } + + @Override + public void tick() { + double adjustedSteamUsage = tickInterval / 20.0 * steamUsage; + if (fluidAmount(PylonFluids.STEAM) < adjustedSteamUsage) { + node.setVoltage(0); + node.setPower(0); + return; + } + removeFluid(PylonFluids.STEAM, adjustedSteamUsage); + node.setVoltage(outputVoltage); + node.setPower(powerProduction); + + Particle.CAMPFIRE_SIGNAL_SMOKE.builder() + .location(getBlock().getLocation().add(0, 1, 0).toCenterLocation()) + .offset(0, 1, 0) + .count(0) + .extra(0.03) + .spawn(); + } + + @Override + public @Nullable WailaDisplay getWaila(@NotNull Player player) { + return new WailaDisplay(getDefaultWailaTranslationKey().arguments( + RebarArgument.of("bar", PylonUtils.createFluidAmountBar( + fluidAmount(PylonFluids.STEAM), + fluidCapacity(PylonFluids.STEAM), + 20, + TextColor.fromHexString("#d8d8d8") + )), + RebarArgument.of("power", Component.translatable( + "pylon.waila.electric.producer", + RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())), + RebarArgument.of("voltage", UnitFormat.VOLTS.format(node.getVoltage()) + )) + ) + )); + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 83e85506f..9a3a94f62 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2453,6 +2453,20 @@ item: 1x 1x + steam_engine: + name: "Steam Engine" + lore: |- + Uses steam to produce power + Steam usage: %steam-usage% + Steam capacity: %steam-capacity% + Power production: %power-production% + Output voltage: %output-voltage% + + Components + 1x + 5000000x TODO + waila: "Steam Engine | %bar% | %power%" + wire_1_gauge: name: "1-Gauge Wire" lore: |- @@ -2502,9 +2516,8 @@ fluid: biodiesel: "<#eaa627>Biodiesel" waila: - fluid_tank: - empty: "(empty)" - filled: "| %bar%/%capacity% of %fluid%" + electric: + producer: "Producing %power% at %voltage%" crucible: item: empty: "| No items |" diff --git a/src/main/resources/settings/steam_engine.yml b/src/main/resources/settings/steam_engine.yml new file mode 100644 index 000000000..13a8f74db --- /dev/null +++ b/src/main/resources/settings/steam_engine.yml @@ -0,0 +1,5 @@ +tick-interval: 10 +steam-usage: 100 +steam-capacity: 200 +power-production: 50 +output-voltage: 64 \ No newline at end of file From e43dc98450b1d1403ae6ef5bc322d171f62c97f5 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 29 Apr 2026 13:57:12 -0400 Subject: [PATCH 21/33] Basic gas turbine multiblock --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonItems.java | 7 ++ .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../io/github/pylonmc/pylon/PylonRecipes.java | 30 +++++++- .../content/machines/electric/GasTurbine.java | 77 +++++++++++++++++++ .../pylon/recipes/GasTurbineRecipe.java | 77 +++++++++++++++++++ src/main/resources/lang/en.yml | 22 +++++- .../resources/recipes/pylon/gas_turbine.yml | 6 ++ src/main/resources/settings/gas_turbine.yml | 1 + 9 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java create mode 100644 src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java create mode 100644 src/main/resources/recipes/pylon/gas_turbine.yml create mode 100644 src/main/resources/settings/gas_turbine.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 1c0cc56d7..9898e9ea7 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -189,6 +189,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.BOILER_CASING, Material.NETHERITE_BLOCK, RebarBlock.class); RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); RebarBlock.register(PylonKeys.STEAM_ENGINE, Material.IRON_BLOCK, SteamEngine.class); + RebarBlock.register(PylonKeys.GAS_TURBINE, Material.IRON_BLOCK, GasTurbine.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index f656e4651..9cd742dad 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3257,6 +3257,13 @@ private PylonItems() { RebarItem.register(SteamEngine.Item.class, STEAM_ENGINE, PylonKeys.STEAM_ENGINE); PylonPages.ELECTRICITY.addItem(STEAM_ENGINE); } + + public static final ItemStack GAS_TURBINE = ItemStackBuilder.rebar(Material.IRON_BLOCK, PylonKeys.GAS_TURBINE) + .build(); + static { + RebarItem.register(RebarItem.class, GAS_TURBINE, PylonKeys.GAS_TURBINE); + PylonPages.ELECTRICITY.addItem(GAS_TURBINE); + } public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) .build(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 43ddf11c8..adb01a1e2 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -472,5 +472,6 @@ public class PylonKeys { public static final NamespacedKey BOILER_CASING = pylonKey("boiler_casing"); public static final NamespacedKey BOILER = pylonKey("boiler"); public static final NamespacedKey STEAM_ENGINE = pylonKey("steam_engine"); + public static final NamespacedKey GAS_TURBINE = pylonKey("gas_turbine"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java index 770d09d24..2a6a0cb44 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java @@ -5,18 +5,18 @@ import io.github.pylonmc.rebar.config.Config; import io.github.pylonmc.rebar.config.Settings; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.fluid.FluidWithAmount; import io.github.pylonmc.rebar.guide.button.FluidButton; import io.github.pylonmc.rebar.guide.button.ItemButton; import io.github.pylonmc.rebar.recipe.FluidOrItem; import io.github.pylonmc.rebar.recipe.RecipeInput; import io.github.pylonmc.rebar.util.gui.GuiItems; +import java.util.List; import org.bukkit.Material; import org.bukkit.NamespacedKey; import org.bukkit.inventory.ItemStack; import xyz.xenondevs.invui.gui.Gui; -import java.util.List; - public class PylonRecipes { @@ -45,6 +45,7 @@ public static void initialize() { TableSawRecipe.RECIPE_TYPE.register(); SiloConverterRecipe.RECIPE_TYPE.register(); HydraulicPurifier.RECIPE_TYPE.register(); + GasTurbineRecipe.RECIPE_TYPE.register(); //hardcoded initCollimator(); @@ -77,6 +78,31 @@ private static void initCollimator() { ).register(); } + private static void initBoiler() { + NamespacedKey key = PylonKeys.BOILER; + double steamPerSecond = Settings.get(key).getOrThrow("steam-per-second", ConfigAdapter.DOUBLE); + RecipeInput.Fluid input = RecipeInput.of(PylonFluids.WATER, steamPerSecond * PylonFluids.WATER_TO_STEAM_RATIO); + FluidWithAmount output = new FluidWithAmount(PylonFluids.STEAM, steamPerSecond); + new SingleRecipe( + key, + input, + output.asFluidOrItem(), + () -> Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # # # # # # #", + "# i # # x # # o #", + "# # # # # # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('i', new FluidButton(input)) + .addIngredient('x', ItemButton.from(PylonItems.BOILER)) + .addIngredient('o', new FluidButton(output)) + .build() + ).register(); + } + private static void initPalladiumCondenser() { NamespacedKey key = PylonKeys.PALLADIUM_CONDENSER; Config setting = Settings.get(key); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java new file mode 100644 index 000000000..f03936a67 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -0,0 +1,77 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; +import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import java.util.HashMap; +import java.util.Map; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3i; + +public class GasTurbine extends RebarBlock implements + RebarSimpleMultiblock, + RebarTickingBlock, + RebarDirectionalBlock { + + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + + @SuppressWarnings("unused") + public GasTurbine(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + + setMultiblockDirection(context.getFacing()); + setFacing(context.getFacing()); + setTickInterval(tickInterval); + } + + @SuppressWarnings("unused") + public GasTurbine(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void tick() { + + } + + private static final Vector3i FLUID_INPUT_HATCH = new Vector3i(0, 0, -2); + private static final Vector3i FLUID_OUTPUT_HATCH = new Vector3i(0, 0, 2); + private static final Vector3i ELECTRICITY_OUTPUT_HATCH = new Vector3i(0, -1, 2); + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + Map components = new HashMap<>(); + + lineOfThree(0, 1, PylonKeys.REINFORCED_GLASS, components); + lineOfThree(-1, 0, PylonKeys.REINFORCED_GLASS, components); + lineOfThree(1, 0, PylonKeys.REINFORCED_GLASS, components); + + lineOfThree(0, -1, PylonKeys.STEEL_SUPPORT_BEAM, components); + + lineOfThree(0, -2, PylonKeys.BRONZE_FOUNDATION, components); + lineOfThree(-1, -1, PylonKeys.BRONZE_FOUNDATION, components); + lineOfThree(1, -1, PylonKeys.BRONZE_FOUNDATION, components); + + components.put(new Vector3i(0, -1, -2), new RebarMultiblockComponent(PylonKeys.BRONZE_FOUNDATION)); + + components.put(FLUID_INPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_INPUT_HATCH)); + components.put(FLUID_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_OUTPUT_HATCH)); + // TODO: electricity output hatch + components.put(ELECTRICITY_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.BRONZE_FOUNDATION)); + + return components; + } + + private static void lineOfThree(int x, int y, NamespacedKey key, Map components) { + components.put(new Vector3i(x, y, 0), new RebarMultiblockComponent(key)); + components.put(new Vector3i(x, y, 1), new RebarMultiblockComponent(key)); + components.put(new Vector3i(x, y, -1), new RebarMultiblockComponent(key)); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java new file mode 100644 index 000000000..9d6e43077 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java @@ -0,0 +1,77 @@ +package io.github.pylonmc.pylon.recipes; + +import io.github.pylonmc.pylon.PylonItems; +import io.github.pylonmc.rebar.config.ConfigSection; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.fluid.FluidWithAmount; +import io.github.pylonmc.rebar.guide.button.FluidButton; +import io.github.pylonmc.rebar.guide.button.ItemButton; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.recipe.*; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.List; +import net.kyori.adventure.text.Component; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NonNull; +import xyz.xenondevs.invui.gui.Gui; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public record GasTurbineRecipe( + @NotNull NamespacedKey key, + @NotNull RecipeInput.Fluid input, + @NotNull FluidWithAmount output, + double powerProduction +) implements RebarRecipe { + + public static final RecipeType RECIPE_TYPE = new ConfigurableRecipeType<>(pylonKey("gas_turbine")) { + @Override + protected @NonNull GasTurbineRecipe loadRecipe(@NotNull NamespacedKey key, @NotNull ConfigSection section) { + return new GasTurbineRecipe( + key, + section.getOrThrow("input", ConfigAdapter.RECIPE_INPUT_FLUID), + section.getOrThrow("output", ConfigAdapter.FLUID_WITH_AMOUNT), + section.getOrThrow("power-production", ConfigAdapter.DOUBLE) + ); + } + }; + + @Override + public @NotNull List<@NotNull RecipeInput> getInputs() { + return List.of(input); + } + + @Override + public @NotNull List<@NotNull FluidOrItem> getResults() { + return List.of(output.asFluidOrItem()); + } + + @Override + public @NonNull Gui display() { + return Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # # # # # # #", + "# i # # x # # o #", + "# # # # # # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('i', new FluidButton(input)) + .addIngredient('x', ItemButton.from(ItemStackBuilder.of(PylonItems.GAS_TURBINE.clone()) + .lore( + Component.empty(), + Component.translatable("pylon.gui.watts-per-mb", UnitFormat.WATTS_PER_MILLIBUCKET.format(powerProduction / input.amountMillibuckets()).decimalPlaces(1)) + ) + .build())) + .addIngredient('o', new FluidButton(output)) + .build(); + } + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } +} diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 9a3a94f62..e00275adc 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2412,7 +2412,8 @@ item: electricity_pylon: name: "Electricity Pylon" lore: |- - TODO + Acts as a multidirectional bus for wires to connect to + Power may be transmitted from any port to any other port transformer: name: "Transformer" @@ -2464,9 +2465,25 @@ item: Components 1x - 5000000x TODO + 1x waila: "Steam Engine | %bar% | %power%" + gas_turbine: + name: "Gas Turbine" + lore: |- + Uses hot gases to produce power + The more hot gases piped into it, the more power it produces + + Components + 1x + 9x + 3x + 1x + 1x + 1x + 1x + waila: "Gas Turbine | %power%" + wire_1_gauge: name: "1-Gauge Wire" lore: |- @@ -2912,6 +2929,7 @@ gui: threshold: "Threshold" item-threshold: "Item threshold" fluid-threshold: "Fluid threshold" + watts-per-mb: "Power production: %power%" inventory: fuel: "Fuel" diff --git a/src/main/resources/recipes/pylon/gas_turbine.yml b/src/main/resources/recipes/pylon/gas_turbine.yml new file mode 100644 index 000000000..e98fdf34a --- /dev/null +++ b/src/main/resources/recipes/pylon/gas_turbine.yml @@ -0,0 +1,6 @@ +pylon:steam: + input: + pylon:steam: 10 + output: + pylon:water: 1 + power-production: 10 \ No newline at end of file diff --git a/src/main/resources/settings/gas_turbine.yml b/src/main/resources/settings/gas_turbine.yml new file mode 100644 index 000000000..eadac4ca6 --- /dev/null +++ b/src/main/resources/settings/gas_turbine.yml @@ -0,0 +1 @@ +tick-interval: 10 \ No newline at end of file From da19c364501c8a1b4e48ffec1ef45608526d62e7 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 29 Apr 2026 14:16:25 -0400 Subject: [PATCH 22/33] Electricity input/output hatches --- .../io/github/pylonmc/pylon/PylonBlocks.java | 2 ++ .../io/github/pylonmc/pylon/PylonItems.java | 14 ++++++++++++ .../io/github/pylonmc/pylon/PylonKeys.java | 2 ++ .../machines/electric/ElectricGrindstone.java | 12 ++-------- .../electric/ElectricityInputHatch.java | 22 +++++++++++++++++++ .../electric/ElectricityOutputHatch.java | 22 +++++++++++++++++++ .../content/machines/electric/GasTurbine.java | 3 +-- src/main/resources/lang/en.yml | 10 +++++++++ 8 files changed, 75 insertions(+), 12 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 9898e9ea7..1ae1bcdaa 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -186,6 +186,8 @@ public static void initialize() { RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); RebarBlock.register(PylonKeys.CAPACITOR_1_KJ, Material.BLUE_GLAZED_TERRACOTTA, Capacitor.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); + RebarBlock.register(PylonKeys.ELECTRICITY_INPUT_HATCH, Material.GREEN_CONCRETE, ElectricityInputHatch.class); + RebarBlock.register(PylonKeys.ELECTRICITY_OUTPUT_HATCH, Material.ORANGE_CONCRETE, ElectricityOutputHatch.class); RebarBlock.register(PylonKeys.BOILER_CASING, Material.NETHERITE_BLOCK, RebarBlock.class); RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); RebarBlock.register(PylonKeys.STEAM_ENGINE, Material.IRON_BLOCK, SteamEngine.class); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 9cd742dad..0a42f0879 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3236,6 +3236,20 @@ private PylonItems() { RebarItem.register(RebarItem.class, CREATIVE_POWER_SOURCE, PylonKeys.CREATIVE_POWER_SOURCE); PylonPages.CREATIVE_ITEMS.addItem(CREATIVE_POWER_SOURCE); } + + public static final ItemStack ELECTRICITY_INPUT_HATCH = ItemStackBuilder.rebar(Material.GREEN_CONCRETE, PylonKeys.ELECTRICITY_INPUT_HATCH) + .build(); + static { + RebarItem.register(RebarItem.class, ELECTRICITY_INPUT_HATCH, PylonKeys.ELECTRICITY_INPUT_HATCH); + PylonPages.COMPONENTS.addItem(ELECTRICITY_INPUT_HATCH); + } + + public static final ItemStack ELECTRICITY_OUTPUT_HATCH = ItemStackBuilder.rebar(Material.ORANGE_CONCRETE, PylonKeys.ELECTRICITY_OUTPUT_HATCH) + .build(); + static { + RebarItem.register(RebarItem.class, ELECTRICITY_OUTPUT_HATCH, PylonKeys.ELECTRICITY_OUTPUT_HATCH); + PylonPages.COMPONENTS.addItem(ELECTRICITY_OUTPUT_HATCH); + } public static final ItemStack BOILER_CASING = ItemStackBuilder.rebar(Material.NETHERITE_BLOCK, PylonKeys.BOILER_CASING) .build(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index adb01a1e2..cea4b474d 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -469,6 +469,8 @@ public class PylonKeys { public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); public static final NamespacedKey CREATIVE_POWER_SOURCE = pylonKey("creative_power_source"); + public static final NamespacedKey ELECTRICITY_INPUT_HATCH = pylonKey("electricity_input_hatch"); + public static final NamespacedKey ELECTRICITY_OUTPUT_HATCH = pylonKey("electricity_output_hatch"); public static final NamespacedKey BOILER_CASING = pylonKey("boiler_casing"); public static final NamespacedKey BOILER = pylonKey("boiler"); public static final NamespacedKey STEAM_ENGINE = pylonKey("steam_engine"); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index 14b5b7832..1fe0ebdda 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -45,6 +45,8 @@ public Item(@NotNull ItemStack stack) { public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); + setVoltageRange(new VoltageRange(voltageMin, voltageMax)); + setRequiredPower(powerUsage); } @SuppressWarnings("unused") @@ -52,16 +54,6 @@ public ElectricGrindstone(@NotNull Block block, @NotNull PersistentDataContainer super(block, pdc); } - @Override - public @NotNull VoltageRange getVoltageRange() { - return new VoltageRange(voltageMin, voltageMax); - } - - @Override - public double getRequiredPower() { - return powerUsage; - } - @Override public void tick() { if (!isProcessingRecipe() || !isPowered()) return; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java new file mode 100644 index 000000000..d8d0dc8a4 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java @@ -0,0 +1,22 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +public class ElectricityInputHatch extends RebarBlock implements RebarElectricConsumerBlock { + + @SuppressWarnings("unused") + public ElectricityInputHatch(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + } + + @SuppressWarnings("unused") + public ElectricityInputHatch(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java new file mode 100644 index 000000000..ab3ed6025 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java @@ -0,0 +1,22 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarElectricProducerBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +public class ElectricityOutputHatch extends RebarBlock implements RebarElectricProducerBlock { + + @SuppressWarnings("unused") + public ElectricityOutputHatch(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + } + + @SuppressWarnings("unused") + public ElectricityOutputHatch(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index f03936a67..69d28c43b 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -63,8 +63,7 @@ public void tick() { components.put(FLUID_INPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_INPUT_HATCH)); components.put(FLUID_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_OUTPUT_HATCH)); - // TODO: electricity output hatch - components.put(ELECTRICITY_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.BRONZE_FOUNDATION)); + components.put(ELECTRICITY_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.ELECTRICITY_OUTPUT_HATCH)); return components; } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index e00275adc..f5ff71783 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2430,6 +2430,16 @@ item: lore: |- Provides an infinite supply of power + electricity_input_hatch: + name: "Electricity Input Hatch" + lore: |- + Accepts power from wires + + electricity_output_hatch: + name: "Electricity Output Hatch" + lore: |- + Outputs power to wires + electric_grindstone: name: "Electric Grindstone" lore: |- From 4b7823be5aae6649e3a6efb2a8266e8fdd7b0c8a Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 29 Apr 2026 15:30:04 -0400 Subject: [PATCH 23/33] Rewrite fluid hatches --- .../pylon/content/components/FluidHatch.java | 129 +++++++++++++----- .../diesel/machines/DieselCoreDrill.java | 13 +- .../diesel/machines/PalladiumCondenser.java | 23 ++-- .../diesel/production/Biorefinery.java | 24 ++-- .../machines/diesel/production/Fermenter.java | 10 +- .../content/machines/electric/Boiler.java | 5 +- .../content/machines/electric/GasTurbine.java | 12 +- .../hydraulics/HydraulicCoreDrill.java | 17 +-- src/main/resources/lang/en.yml | 2 +- 9 files changed, 150 insertions(+), 85 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java index 323a3b8da..5861a52e4 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java @@ -7,7 +7,7 @@ import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; -import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; +import io.github.pylonmc.rebar.block.base.RebarFluidBlock; import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; @@ -23,6 +23,8 @@ import io.github.pylonmc.rebar.waila.Waila; import io.github.pylonmc.rebar.waila.WailaDisplay; import java.util.*; +import kotlin.Pair; +import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Bukkit; @@ -39,15 +41,28 @@ import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public abstract class FluidHatch extends RebarBlock implements - RebarFluidBufferBlock, + RebarFluidBlock, RebarSimpleMultiblock, RebarDirectionalBlock { + private static final NamespacedKey ALLOWED_FLUIDS_KEY = pylonKey("allowed_fluids"); private static final NamespacedKey FLUID_KEY = pylonKey("fluid"); + private static final NamespacedKey FLUID_AMOUNT_KEY = pylonKey("fluid_amount"); + private static final NamespacedKey CAPACITY_KEY = pylonKey("capacity"); private static MixedMultiblockComponent component = null; - public @Nullable RebarFluid fluid; + @Getter + private Set allowedFluids = new HashSet<>(); + + @Getter + private @Nullable RebarFluid fluid; + + @Getter + private double fluidAmount = 0; + + @Getter + private double capacity = 0; static { // run on first tick after all addons registered @@ -72,14 +87,21 @@ public FluidHatch(@NotNull Block block, @NotNull BlockCreateContext context) { ); } + @SuppressWarnings("DataFlowIssue") public FluidHatch(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); + allowedFluids = pdc.get(ALLOWED_FLUIDS_KEY, RebarSerializers.SET.setTypeFrom(RebarSerializers.REBAR_FLUID)); fluid = pdc.get(FLUID_KEY, RebarSerializers.REBAR_FLUID); + fluidAmount = pdc.get(FLUID_AMOUNT_KEY, RebarSerializers.DOUBLE); + capacity = pdc.get(CAPACITY_KEY, RebarSerializers.DOUBLE); } @Override public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(ALLOWED_FLUIDS_KEY, RebarSerializers.SET.setTypeFrom(RebarSerializers.REBAR_FLUID), allowedFluids); RebarUtils.setNullable(pdc, FLUID_KEY, RebarSerializers.REBAR_FLUID, fluid); + pdc.set(FLUID_AMOUNT_KEY, RebarSerializers.DOUBLE, fluidAmount); + pdc.set(CAPACITY_KEY, RebarSerializers.DOUBLE, capacity); } @Override @@ -95,10 +117,7 @@ public boolean checkFormed() { if (formed) { FluidTankCasing casing = BlockStorage.getAs(FluidTankCasing.class, getBlock().getRelative(BlockFace.UP)); Preconditions.checkState(casing != null); - Waila.addWailaOverride(casing.getBlock(), this::getWaila); - if (fluid != null) { - setFluidCapacity(fluid, casing.capacity); - } + setCapacity(casing.capacity); } return formed; } @@ -108,7 +127,7 @@ public void onMultiblockUnformed(boolean partUnloaded) { RebarSimpleMultiblock.super.onMultiblockUnformed(partUnloaded); Waila.removeWailaOverride(getBlock().getRelative(BlockFace.UP)); if (fluid != null) { - setFluidCapacity(fluid, 0); + setCapacity(0); getFluidDisplay().setTransformationMatrix(new TransformBuilder() .scale(0, 0, 0) .buildForItemDisplay() @@ -117,10 +136,49 @@ public void onMultiblockUnformed(boolean partUnloaded) { } @Override - public boolean setFluid(@NotNull RebarFluid fluid, double amount) { - boolean result = RebarFluidBufferBlock.super.setFluid(fluid, amount); - float scale = (float) (0.9 * fluidAmount(fluid) / fluidCapacity(fluid)); + public @NotNull List<@NotNull Pair> getSuppliedFluids() { + if (fluid == null || fluidAmount <= 1e-6) { + return List.of(); + } + return List.of(new Pair<>(fluid, fluidAmount)); + } + + @Override + public double fluidAmountRequested(@NotNull RebarFluid fluid) { + if (Objects.equals(this.fluid, fluid)) { + return capacity - fluidAmount; + } else if (allowedFluids.contains(fluid)) { + return capacity; + } else { + return 0; + } + } + + @Override + public void onFluidAdded(@NotNull RebarFluid fluid, double amount) { + setFluid(fluid, fluidAmount + amount); + } + + @Override + public void onFluidRemoved(@NotNull RebarFluid fluid, double amount) { + setFluid(fluid, fluidAmount - amount); + } + + public void addFluid(@NotNull RebarFluid fluid, double amount) { + onFluidAdded(fluid, amount); + } + + public void removeFluid(@NotNull RebarFluid fluid, double amount) { + onFluidRemoved(fluid, amount); + } + + public void setFluid(@NotNull RebarFluid fluid, double amount) { + this.fluid = fluid; + this.fluidAmount = Math.min(amount, capacity); + float scale = (float) (0.9 * fluidAmount / capacity); if (scale < 1.0e-9) { + this.fluid = null; + this.fluidAmount = 0; getFluidDisplay().setItemStack(null); } else { getFluidDisplay().setItemStack(fluid.getItem()); @@ -130,7 +188,14 @@ public boolean setFluid(@NotNull RebarFluid fluid, double amount) { .scale(0.9, scale, 0.9) .buildForItemDisplay() ); - return result; + } + + public double getFluidSpaceRemaining() { + if (fluid == null) { + return capacity; + } else { + return capacity - fluidAmount; + } } @Override @@ -139,13 +204,13 @@ public boolean setFluid(@NotNull RebarFluid fluid, double amount) { if (!isFormedAndFullyLoaded()) { info = Component.translatable("pylon.message.fluid_hatch.no_casing"); } else if (fluid == null) { - info = Component.translatable("pylon.message.fluid_hatch.no_multiblock"); + info = Component.translatable("pylon.message.fluid_hatch.empty"); } else { info = Component.translatable("pylon.message.fluid_hatch.working") .arguments( RebarArgument.of("bars", PylonUtils.createFluidAmountBar( - fluidAmount(fluid), - fluidCapacity(fluid), + fluidAmount, + capacity, 20, TextColor.color(200, 255, 255) )), @@ -157,27 +222,28 @@ public boolean setFluid(@NotNull RebarFluid fluid, double amount) { )); } - public void setFluidType(@Nullable RebarFluid fluid) { - if (Objects.equals(this.fluid, fluid)) { - return; - } - - if (this.fluid != null) { - deleteFluidBuffer(this.fluid); + public void setAllowedFluids(@NotNull RebarFluid @NotNull ... fluids) { + setAllowedFluids(Set.of(fluids)); + } + + public void setAllowedFluids(@NotNull Set fluids) { + this.allowedFluids = fluids; + + if (this.fluid != null && !fluids.contains(this.fluid)) { + fluid = null; + setCapacity(0); getFluidDisplay().setTransformationMatrix(new TransformBuilder() .scale(0, 0, 0) .buildForItemDisplay() ); + this.fluid = null; } - this.fluid = fluid; - if (fluid != null) { - createFluidBuffer(fluid, 0, true, true); - } - if (isFormedAndFullyLoaded() && fluid != null) { - FluidTankCasing casing = BlockStorage.getAs(FluidTankCasing.class, getBlock().getRelative(BlockFace.UP)); - Preconditions.checkState(casing != null); - setFluidCapacity(fluid, casing.capacity); - } + checkFormed(); + } + + private void setCapacity(double capacity) { + this.capacity = capacity; + this.fluidAmount = Math.min(this.fluidAmount, capacity); } public @NotNull ItemDisplay getFluidDisplay() { @@ -186,7 +252,6 @@ public void setFluidType(@Nullable RebarFluid fluid) { @Override public void postBreak(@NotNull BlockBreakContext context) { - RebarFluidBufferBlock.super.postBreak(context); Waila.removeWailaOverride(getBlock().getRelative(BlockFace.UP)); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java index 05967f702..a914e6672 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java @@ -11,6 +11,10 @@ import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; @@ -18,11 +22,6 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3i; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class DieselCoreDrill extends CoreDrill { @@ -114,7 +113,7 @@ public void tick() { FluidInputHatch fluidInputHatch = getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH); ItemOutputHatch itemOutputHatch = getMultiblockComponentOrThrow(ItemOutputHatch.class, ITEM_OUTPUT_HATCH); - if (fluidInputHatch.fluidAmount(PylonFluids.BIODIESEL) < dieselPerRotation || !itemOutputHatch.inventory.canHold(output)) { + if (fluidInputHatch.getFluidAmount() < dieselPerRotation || !itemOutputHatch.inventory.canHold(output)) { return; } @@ -145,6 +144,6 @@ public void onProcessFinished() { public void onMultiblockFormed() { super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH) - .setFluidType(PylonFluids.BIODIESEL); + .setAllowedFluids(PylonFluids.BIODIESEL); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java index c1e12e135..5083ec453 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java @@ -21,6 +21,11 @@ import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.time.Duration; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.bukkit.Particle; @@ -32,12 +37,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.time.Duration; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - public class PalladiumCondenser extends RebarBlock implements RebarSimpleMultiblock, @@ -180,9 +179,9 @@ public void tick() { FluidOutputHatch dirtyHydraulicFluidOutputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, DIRTY_HYDRAULIC_FLUID_OUTPUT_HATCH); ItemOutputHatch palladiumDustOutputHatch = getMultiblockComponentOrThrow(ItemOutputHatch.class, PALLADIUM_DUST_OUTPUT_HATCH); - if (biodieselInputHatch.fluidAmount(PylonFluids.BIODIESEL) < dieselPerSecond * getTickInterval() / 20 - || hydraulicFluidInputHatch.fluidAmount(PylonFluids.HYDRAULIC_FLUID) < hydraulicFluidPerSecond * getTickInterval() / 20 - || dirtyHydraulicFluidOutputHatch.fluidSpaceRemaining(PylonFluids.DIRTY_HYDRAULIC_FLUID) < hydraulicFluidPerSecond * getTickInterval() / 20 + if (biodieselInputHatch.getFluidAmount() < dieselPerSecond * getTickInterval() / 20 + || hydraulicFluidInputHatch.getFluidAmount() < hydraulicFluidPerSecond * getTickInterval() / 20 + || dirtyHydraulicFluidOutputHatch.getFluidSpaceRemaining() < hydraulicFluidPerSecond * getTickInterval() / 20 || !palladiumDustOutputHatch.inventory.canHold(PylonItems.PALLADIUM_DUST) ) { return; @@ -243,11 +242,9 @@ public void onProcessFinished() { public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, BIODIESEL_INPUT_HATCH) - .setFluidType(PylonFluids.BIODIESEL); + .setAllowedFluids(PylonFluids.BIODIESEL); getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT_HATCH) - .setFluidType(PylonFluids.HYDRAULIC_FLUID); - getMultiblockComponentOrThrow(FluidOutputHatch.class, DIRTY_HYDRAULIC_FLUID_OUTPUT_HATCH) - .setFluidType(PylonFluids.DIRTY_HYDRAULIC_FLUID); + .setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); } @Override diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java index d9553e9cb..2de5e347a 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java @@ -21,11 +21,16 @@ import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import io.github.pylonmc.rebar.waila.Waila; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; -import org.bukkit.*; +import org.bukkit.Keyed; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Particle; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; @@ -36,10 +41,6 @@ import org.joml.Vector3d; import org.joml.Vector3i; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; public class Biorefinery extends RebarBlock implements @@ -158,9 +159,8 @@ public Biorefinery(@NotNull Block block, @NotNull PersistentDataContainer pdc) { @Override public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); - getMultiblockComponentOrThrow(FluidInputHatch.class, ETHANOL_INPUT_HATCH).setFluidType(PylonFluids.ETHANOL); - getMultiblockComponentOrThrow(FluidInputHatch.class, PLANT_OIL_INPUT_HATCH).setFluidType(PylonFluids.PLANT_OIL); - getMultiblockComponentOrThrow(FluidOutputHatch.class, BIODIESEL_OUTPUT_HATCH).setFluidType(PylonFluids.BIODIESEL); + getMultiblockComponentOrThrow(FluidInputHatch.class, ETHANOL_INPUT_HATCH).setAllowedFluids(PylonFluids.ETHANOL); + getMultiblockComponentOrThrow(FluidInputHatch.class, PLANT_OIL_INPUT_HATCH).setAllowedFluids(PylonFluids.PLANT_OIL); } @Override @@ -177,12 +177,12 @@ public void tick() { FluidOutputHatch biodieselOutputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, BIODIESEL_OUTPUT_HATCH); double biodieselToProduce = Math.min( - biodieselOutputHatch.fluidSpaceRemaining(PylonFluids.BIODIESEL), + biodieselOutputHatch.getFluidSpaceRemaining(), Math.min( biodieselPerSecond * getTickInterval() / 20.0, Math.min( - ethanolInputHatch.fluidAmount(PylonFluids.ETHANOL) / ethanolPerMbOfBiodiesel, - plantOilInputHatch.fluidAmount(PylonFluids.PLANT_OIL) / plantOilPerMbOfBiodiesel + ethanolInputHatch.getFluidAmount() / ethanolPerMbOfBiodiesel, + plantOilInputHatch.getFluidAmount() / plantOilPerMbOfBiodiesel ) ) ); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java index 28a71c8ba..06b5c5057 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java @@ -21,6 +21,9 @@ import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -32,10 +35,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class Fermenter extends RebarBlock implements RebarSimpleMultiblock, RebarDirectionalBlock, @@ -125,7 +124,6 @@ public Fermenter(@NotNull Block block, @NotNull PersistentDataContainer pdc) { public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); onMultiblockRefreshed(); - getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH).setFluidType(PylonFluids.ETHANOL); getHeldEntityOrThrow(ItemDisplay.class, "sugarcane").setItemStack(PylonFluids.SUGARCANE.getItem()); } @@ -185,7 +183,7 @@ && fluidSpaceRemaining(PylonFluids.SUGARCANE) > ethanolPerSugarcane } double sugarcaneProportion = fluidAmount(PylonFluids.SUGARCANE) / fluidCapacity(PylonFluids.SUGARCANE); - double outputSpaceRemaining = outputHatch.fluidSpaceRemaining(PylonFluids.ETHANOL); + double outputSpaceRemaining = outputHatch.getFluidSpaceRemaining(); double ethanolToOutput = Math.min(outputSpaceRemaining, sugarcaneProportion * maxEthanolOutputRate * getTickInterval() / 20); if (ethanolToOutput > 1.0e-6) { removeFluid(PylonFluids.SUGARCANE, ethanolToOutput); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index 7df84769a..c16907e7f 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -180,8 +180,7 @@ public void postInitialise() { @Override public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); - getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH).setFluidType(PylonFluids.WATER); - getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH).setFluidType(PylonFluids.STEAM); + getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH).setAllowedFluids(PylonFluids.WATER); } private void tryStartProcessing() { @@ -210,7 +209,7 @@ public void tick() { double waterConsumption = steamProduction * PylonFluids.WATER_TO_STEAM_RATIO; FluidInputHatch waterInput = getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH); FluidOutputHatch steamOutput = getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH); - double toRemove = Math.min(Math.min(waterInput.fluidAmount(PylonFluids.WATER), waterConsumption), steamOutput.fluidSpaceRemaining(PylonFluids.STEAM) * PylonFluids.WATER_TO_STEAM_RATIO); + double toRemove = Math.min(Math.min(waterInput.getFluidAmount(), waterConsumption), steamOutput.getFluidSpaceRemaining() * PylonFluids.WATER_TO_STEAM_RATIO); if (toRemove > 0) { waterInput.removeFluid(PylonFluids.WATER, toRemove); steamOutput.addFluid(PylonFluids.STEAM, toRemove / PylonFluids.WATER_TO_STEAM_RATIO); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index 69d28c43b..b28bcdcca 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -1,6 +1,8 @@ package io.github.pylonmc.pylon.content.machines.electric; import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.content.components.FluidInputHatch; +import io.github.pylonmc.pylon.recipes.GasTurbineRecipe; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; @@ -9,6 +11,7 @@ import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; import java.util.HashMap; import java.util.Map; +import java.util.stream.Collectors; import org.bukkit.NamespacedKey; import org.bukkit.block.Block; import org.bukkit.persistence.PersistentDataContainer; @@ -73,4 +76,11 @@ private static void lineOfThree(int x, int y, NamespacedKey key, Map r.input().fluids().stream()).collect(Collectors.toSet())); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java index b9dfb9b51..6f9ece7d7 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java @@ -11,6 +11,10 @@ import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; @@ -18,11 +22,6 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3i; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public class HydraulicCoreDrill extends CoreDrill { public final int hydraulicFluidUsage = getSettings().getOrThrow("hydraulic-fluid-usage", ConfigAdapter.INTEGER); @@ -105,8 +104,8 @@ public void tick() { FluidOutputHatch outputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); ItemOutputHatch itemOutputHatch = getMultiblockComponentOrThrow(ItemOutputHatch.class, ITEM_OUTPUT_HATCH); - if (inputHatch.fluidAmount(PylonFluids.HYDRAULIC_FLUID) < hydraulicFluidPerRotation - || outputHatch.fluidSpaceRemaining(PylonFluids.DIRTY_HYDRAULIC_FLUID) < hydraulicFluidPerRotation + if (inputHatch.getFluidAmount() < hydraulicFluidPerRotation + || outputHatch.getFluidSpaceRemaining() < hydraulicFluidPerRotation || !itemOutputHatch.inventory.canHold(output) ) { return; @@ -133,8 +132,6 @@ public void onProcessFinished() { public void onMultiblockFormed() { super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH) - .setFluidType(PylonFluids.HYDRAULIC_FLUID); - getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH) - .setFluidType(PylonFluids.DIRTY_HYDRAULIC_FLUID); + .setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); } } diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index f5ff71783..d1c449563 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2770,7 +2770,7 @@ message: clear: "Clear" fluid_hatch: no_casing: "No casing" - no_multiblock: "No multiblock" + empty: "Empty" working: "%bars% (%fluid%)" biorefinery: no_fuel: "No fuel" From d7720bfbf369b486af33fb4a2a33b95752ec04e0 Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 30 Apr 2026 09:42:58 -0400 Subject: [PATCH 24/33] Nuke voltage --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 - .../io/github/pylonmc/pylon/PylonItems.java | 8 - .../io/github/pylonmc/pylon/PylonKeys.java | 1 - .../content/machines/electric/Capacitor.java | 6 +- .../electric/CreativePowerSource.java | 17 +- .../machines/electric/ElectricGrindstone.java | 12 +- .../machines/electric/SteamEngine.java | 10 +- .../machines/electric/Transformer.java | 209 ------------------ .../pylon/content/tools/PylonWire.java | 6 +- src/main/resources/lang/en.yml | 14 +- .../settings/electric_grindstone.yml | 7 +- src/main/resources/settings/wire_1_gauge.yml | 2 +- 12 files changed, 17 insertions(+), 276 deletions(-) delete mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 1ae1bcdaa..9337db685 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -183,7 +183,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.PALLADIUM_SILO, Material.BLUE_TERRACOTTA, Silo.class); RebarBlock.register(PylonKeys.SILO_CONVERTER, Material.STRIPPED_OAK_LOG, SiloConverter.class); RebarBlock.register(PylonKeys.ELECTRICITY_PYLON, Material.SEA_LANTERN, ElectricityPylon.class); - RebarBlock.register(PylonKeys.TRANSFORMER, Material.STRUCTURE_VOID, Transformer.class); RebarBlock.register(PylonKeys.CAPACITOR_1_KJ, Material.BLUE_GLAZED_TERRACOTTA, Capacitor.class); RebarBlock.register(PylonKeys.CREATIVE_POWER_SOURCE, Material.PINK_STAINED_GLASS, CreativePowerSource.class); RebarBlock.register(PylonKeys.ELECTRICITY_INPUT_HATCH, Material.GREEN_CONCRETE, ElectricityInputHatch.class); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 0a42f0879..4312ac1b8 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3201,14 +3201,6 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(ELECTRICITY_PYLON); } - public static final ItemStack TRANSFORMER = ItemStackBuilder.rebar(Material.STRUCTURE_VOID, PylonKeys.TRANSFORMER) - .set(DataComponentTypes.ITEM_MODEL, Material.COPPER_BULB.key()) - .build(); - static { - RebarItem.register(RebarItem.class, TRANSFORMER, PylonKeys.TRANSFORMER); - PylonPages.ELECTRICITY.addItem(TRANSFORMER); - } - public static final ItemStack CAPACITOR_1_KJ = ItemStackBuilder.rebar(Material.BLUE_GLAZED_TERRACOTTA, PylonKeys.CAPACITOR_1_KJ) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index cea4b474d..66ecad711 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -464,7 +464,6 @@ public class PylonKeys { public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); public static final NamespacedKey ELECTRICITY_PYLON = pylonKey("electricity_pylon"); - public static final NamespacedKey TRANSFORMER = pylonKey("transformer"); public static final NamespacedKey CAPACITOR_1_KJ = pylonKey("capacitor_1_kj"); public static final NamespacedKey MULTIMETER = pylonKey("multimeter"); public static final NamespacedKey WIRE_1_GAUGE = pylonKey("wire_1_gauge"); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java index a6a9156b1..78768f8ac 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java @@ -1,11 +1,9 @@ package io.github.pylonmc.pylon.content.machines.electric; -import io.github.pylonmc.pylon.PylonKeys; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.config.Settings; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; import io.github.pylonmc.rebar.datatypes.RebarSerializers; import io.github.pylonmc.rebar.electricity.ElectricNode; @@ -57,7 +55,7 @@ public Capacitor(@NotNull Block block, @NotNull BlockCreateContext context) { setFacing(context.getFacing()); addElectricPort(getFacing(), new ElectricNode.Acceptor("input", new BlockPosition(block))); - addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0, 0)); + addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0)); addEntity("text_0", new TextDisplayBuilder() .transformation(new TransformBuilder() @@ -110,8 +108,6 @@ public void setStoredEnergy(double energy) { storedEnergy = energy; getHeldEntityOrThrow(TextDisplay.class, "text_0").text(UnitFormat.JOULES.format(storedEnergy).decimalPlaces(1).asComponent()); getHeldEntityOrThrow(TextDisplay.class, "text_1").text(UnitFormat.JOULES.format(storedEnergy).decimalPlaces(1).asComponent()); - double maxCurrent = Settings.get(PylonKeys.WIRE_1_GAUGE).getOrThrow("max-current", ConfigAdapter.DOUBLE); output.setPower(storedEnergy); - output.setVoltage(storedEnergy / maxCurrent); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java index d1427c268..b0c7a1b05 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java @@ -34,27 +34,16 @@ public CreativePowerSource(@NotNull Block block, @NotNull PersistentDataContaine @Override public @NotNull Gui createGui() { return Gui.builder() - .setStructure("# # # v # p # # #") + .setStructure("# # # # p # # # #") .addIngredient('#', GuiItems.background()) - .addIngredient('v', NumberInputButton.builder() - .material(Material.REDSTONE) - .name(Component.translatable("pylon.gui.voltage")) - .increment(1) - .shiftIncrement(10) - .min(0) - .valueGetter(() -> (int) getVoltageProducing()) - .valueSetter(this::setVoltageProducing) - .valueFormatter(v -> formatQuantity(UnitFormat.VOLTS, v)) - .reopenWindow(this::openWindow) - .build()) .addIngredient('p', NumberInputButton.builder() .material(Material.NETHER_STAR) .name(Component.translatable("pylon.gui.power")) .increment(1) .shiftIncrement(10) .min(0) - .valueGetter(() -> (int) getPowerProducing()) - .valueSetter(this::setPowerProducing) + .valueGetter(() -> (int) getPower()) + .valueSetter(this::setPower) .valueFormatter(p -> formatQuantity(UnitFormat.WATTS, p)) .reopenWindow(this::openWindow) .build()) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java index 1fe0ebdda..1504f3f11 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java @@ -4,7 +4,6 @@ import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; -import io.github.pylonmc.rebar.electricity.VoltageRange; import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; @@ -18,14 +17,10 @@ public class ElectricGrindstone extends AbstractGrindstone implements RebarElectricConsumerBlock { private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); - private final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); - private final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); public static class Item extends RebarItem { public final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); - public final double voltageMin = getSettings().getOrThrow("voltage-range.min", ConfigAdapter.DOUBLE); - public final double voltageMax = getSettings().getOrThrow("voltage-range.max", ConfigAdapter.DOUBLE); public Item(@NotNull ItemStack stack) { super(stack); @@ -33,11 +28,7 @@ public Item(@NotNull ItemStack stack) { @Override public @NotNull List<@NotNull RebarArgument> getPlaceholders() { - return List.of( - RebarArgument.of("power-usage", UnitFormat.WATTS.format(powerUsage)), - RebarArgument.of("min-voltage", UnitFormat.VOLTS.format(voltageMin)), - RebarArgument.of("max-voltage", UnitFormat.VOLTS.format(voltageMax)) - ); + return List.of(RebarArgument.of("power-usage", UnitFormat.WATTS.format(powerUsage))); } } @@ -45,7 +36,6 @@ public Item(@NotNull ItemStack stack) { public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setVoltageRange(new VoltageRange(voltageMin, voltageMax)); setRequiredPower(powerUsage); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java index ca1efff14..5293b1469 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java @@ -71,7 +71,7 @@ public SteamEngine(@NotNull Block block, @NotNull BlockCreateContext context) { setTickInterval(tickInterval); createFluidPoint(FluidPointType.INPUT, context.getFacing()); createFluidBuffer(PylonFluids.STEAM, steamCapacity, true, false); - addElectricPort(context.getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0, 0)); + addElectricPort(context.getFacing().getOppositeFace(), new ElectricNode.Producer("output", new BlockPosition(block), 0)); } @SuppressWarnings("unused") @@ -93,12 +93,10 @@ public void postInitialise() { public void tick() { double adjustedSteamUsage = tickInterval / 20.0 * steamUsage; if (fluidAmount(PylonFluids.STEAM) < adjustedSteamUsage) { - node.setVoltage(0); node.setPower(0); return; } removeFluid(PylonFluids.STEAM, adjustedSteamUsage); - node.setVoltage(outputVoltage); node.setPower(powerProduction); Particle.CAMPFIRE_SIGNAL_SMOKE.builder() @@ -120,10 +118,8 @@ public void tick() { )), RebarArgument.of("power", Component.translatable( "pylon.waila.electric.producer", - RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())), - RebarArgument.of("voltage", UnitFormat.VOLTS.format(node.getVoltage()) - )) - ) + RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())) + )) )); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java deleted file mode 100644 index d17e4babf..000000000 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Transformer.java +++ /dev/null @@ -1,209 +0,0 @@ -package io.github.pylonmc.pylon.content.machines.electric; - -import io.github.pylonmc.pylon.util.NumberInputButton; -import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; -import io.github.pylonmc.rebar.block.base.RebarElectricBlock; -import io.github.pylonmc.rebar.block.base.RebarGuiBlock; -import io.github.pylonmc.rebar.block.context.BlockCreateContext; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; -import io.github.pylonmc.rebar.electricity.ElectricNode; -import io.github.pylonmc.rebar.electricity.ElectricityManager; -import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; -import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; -import io.github.pylonmc.rebar.util.gui.GuiItems; -import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import io.github.pylonmc.rebar.util.position.BlockPosition; -import lombok.Getter; -import net.kyori.adventure.text.Component; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; -import org.bukkit.block.Block; -import org.bukkit.persistence.PersistentDataContainer; -import org.jetbrains.annotations.NotNull; -import org.joml.Matrix4f; -import org.joml.Quaternionf; -import org.joml.Vector3f; -import xyz.xenondevs.invui.gui.Gui; - -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - -public class Transformer extends RebarBlock implements - RebarDirectionalBlock, - RebarElectricBlock, - RebarGuiBlock { - - private static final NamespacedKey VOLTAGE_KEY = pylonKey("voltage"); - - @Getter - private double voltage; - - @SuppressWarnings("unused") - public Transformer(@NotNull Block block, @NotNull BlockCreateContext context) { - super(block, context); - - setFacing(context.getFacing()); - - addEntity("core", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) - .addCustomModelDataString(getKey() + ":core")) - .transformation(new Matrix4f() - .scaleLocal(0.20009678623931632F, 0.20032039188618334F, 0.6004731961191524F) - .translateLocal(-0.4F, 0F, 0F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("core_1", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) - .addCustomModelDataString(getKey() + ":core")) - .transformation(new Matrix4f() - .scaleLocal(0.1997668812131523F, 0.19966703461153537F, 0.6003585166957504F) - .translateLocal(0.4F, 0F, 0F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("rung", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) - .addCustomModelDataString(getKey() + ":rung")) - .transformation(new Matrix4f() - .scaleLocal(0.1996251290519708F, 0.19976789546029616F, 1.0003100350848213F) - .translateLocal(0.4F, 0F, 0F) - .rotateLocalY(1.5707963267948966F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("rung_1", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("netherite_block"))) - .addCustomModelDataString(getKey() + ":rung")) - .transformation(new Matrix4f() - .scaleLocal(0.19970989558988675F, 0.20049819786540016F, 1.0000264976327606F) - .translateLocal(0.4F, 0F, 0F) - .rotateLocalY(-1.5707963267948966F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.3995463833191263F, 0.4001898742525297F, 0.0997048554794333F) - .translateLocal(-0.4F, 0F, -0.1875F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil_1", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.3999329168670776F, 0.40013877682813603F, 0.10002070272683829F) - .translateLocal(-0.4F, 0F, -0.0625F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil_2", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.3995519473196249F, 0.40019206234199983F, 0.0996939243442167F) - .translateLocal(-0.4F, 0F, 0.1875F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil_3", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.4001911460388317F, 0.3997099305044037F, 0.10003237057314601F) - .translateLocal(-0.4F, 0F, 0.0625F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil_4", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.4002971305276804F, 0.3996788757583065F, 0.10002218158359033F) - .translateLocal(0.4F, 0F, -0.0625F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - addEntity("coil_5", new ItemDisplayBuilder() - .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("copper_block"))) - .addCustomModelDataString(getKey() + ":coil")) - .transformation(new Matrix4f() - .scaleLocal(0.40047277836438155F, 0.400447837292574F, 0.10040968619996378F) - .translateLocal(0.4F, 0F, 0.0625F) - .rotateLocal(new Quaternionf().lookAlong(context.getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) - ) - .build(block.getLocation().toCenterLocation()) - ); - - voltage = 0; - - ElectricNode first = addElectricPort(getFacing(), new ElectricNode.Connector("first", new BlockPosition(block))); - ElectricNode second = addElectricPort(getFacing().getOppositeFace(), new ElectricNode.Connector("second", new BlockPosition(block))); - first.connect(second); - } - - @SuppressWarnings({"unused", "DataFlowIssue"}) - public Transformer(@NotNull Block block, @NotNull PersistentDataContainer pdc) { - super(block, pdc); - - voltage = pdc.get(VOLTAGE_KEY, RebarSerializers.DOUBLE); - } - - @Override - public void postInitialise() { - setVoltage(voltage); - } - - @Override - public void write(@NotNull PersistentDataContainer pdc) { - pdc.set(VOLTAGE_KEY, RebarSerializers.DOUBLE, voltage); - } - - @Override - public @NotNull Gui createGui() { - return Gui.builder() - .setStructure("# # # # v # # # #") - .addIngredient('#', GuiItems.background()) - .addIngredient('v', NumberInputButton.builder() - .material(Material.REDSTONE) - .name(Component.translatable("pylon.gui.voltage")) - .increment(1) - .shiftIncrement(10) - .min(0) - .valueGetter(() -> (int) getVoltage()) - .valueSetter(this::setVoltage) - .valueFormatter(UnitFormat.VOLTS::format) - .reopenWindow(this::openWindow) - .build()) - .build(); - } - - public void setVoltage(double voltage) { - this.voltage = voltage; - ElectricNode.Connector first = (ElectricNode.Connector) getElectricNodeOrThrow("first"); - ElectricNode.Connector second = (ElectricNode.Connector) getElectricNodeOrThrow("second"); - ElectricityManager.setTransformerEdge(first, second, voltage); - } -} diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java index 740cd42b3..85a474372 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java @@ -12,7 +12,7 @@ public class PylonWire extends RebarItem implements RebarWire { - private final double currentLimit = getSettings().getOrThrow("max-current", ConfigAdapter.DOUBLE); + private final double maxPower = getSettings().getOrThrow("max-power", ConfigAdapter.DOUBLE); public PylonWire(@NotNull ItemStack stack) { super(stack); @@ -20,12 +20,12 @@ public PylonWire(@NotNull ItemStack stack) { @Override public @NotNull List<@NotNull RebarArgument> getPlaceholders() { - return List.of(RebarArgument.of("max-current", UnitFormat.AMPRERES.format(currentLimit))); + return List.of(RebarArgument.of("max-power", UnitFormat.AMPRERES.format(maxPower))); } @Override public double getMaxCurrent() { - return currentLimit; + return maxPower; } @Override diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index d1c449563..474189782 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2415,15 +2415,10 @@ item: Acts as a multidirectional bus for wires to connect to Power may be transmitted from any port to any other port - transformer: - name: "Transformer" - lore: |- - Sets the voltage of any current crossing through it to a specific value - multimeter: name: "Multimeter" lore: |- - Measures the current of a wire + Measures the power passing through a wire creative_power_source: name: "<#ff00ff>Creative Power Source" @@ -2445,7 +2440,6 @@ item: lore: |- Grinds items using electricity Power usage: %power-usage% - Voltage range: %min-voltage% to %max-voltage% boiler_casing: name: "Boiler Casing" @@ -2471,7 +2465,6 @@ item: Steam usage: %steam-usage% Steam capacity: %steam-capacity% Power production: %power-production% - Output voltage: %output-voltage% Components 1x @@ -2498,14 +2491,13 @@ item: name: "1-Gauge Wire" lore: |- Transmits electricity - Max current: %max-current% + Max power: %max-power% capacitor_1_kj: name: "1 kJ Capacitor" lore: |- Stores electricity Capacitors have a lower priority than most electric blocks, so they will only take excess power that other blocks can't use - The output voltage is such that the entire charge can be passed through a in one tick Capacity: %capacity% fluid: @@ -2544,7 +2536,7 @@ fluid: waila: electric: - producer: "Producing %power% at %voltage%" + producer: "Producing %power%" crucible: item: empty: "| No items |" diff --git a/src/main/resources/settings/electric_grindstone.yml b/src/main/resources/settings/electric_grindstone.yml index 19fb0ba6f..c551a6f4f 100644 --- a/src/main/resources/settings/electric_grindstone.yml +++ b/src/main/resources/settings/electric_grindstone.yml @@ -1,5 +1,2 @@ -power-usage: 20 -voltage-range: - min: 50 - max: 200 -tick-interval: 10 \ No newline at end of file +tick-interval: 10 +power-usage: 20 \ No newline at end of file diff --git a/src/main/resources/settings/wire_1_gauge.yml b/src/main/resources/settings/wire_1_gauge.yml index 077d5c94e..dcacea5bf 100644 --- a/src/main/resources/settings/wire_1_gauge.yml +++ b/src/main/resources/settings/wire_1_gauge.yml @@ -1 +1 @@ -max-current: 50 \ No newline at end of file +max-power: 50 \ No newline at end of file From a1fc8038c8b48eaf270de63cf0af575a634b3fc6 Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 30 Apr 2026 11:13:56 -0400 Subject: [PATCH 25/33] Fix multiblock facing --- .../diesel/machines/PalladiumCondenser.java | 1 - .../diesel/production/Biorefinery.java | 1 - .../machines/diesel/production/Fermenter.java | 1 - .../content/machines/electric/Boiler.java | 1 - .../content/machines/simple/Collimator.java | 18 ++++-------------- .../content/machines/simple/CoreDrill.java | 5 +---- .../content/machines/smelting/Bloomery.java | 9 ++++----- 7 files changed, 9 insertions(+), 27 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java index 5083ec453..81ff99414 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java @@ -99,7 +99,6 @@ public Item(@NotNull ItemStack stack) { public PalladiumCondenser(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setMultiblockDirection(getFacing()); setTickInterval(tickInterval); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java index 2de5e347a..e9d38755f 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java @@ -82,7 +82,6 @@ public Item(@NotNull ItemStack stack) { public Biorefinery(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setMultiblockDirection(context.getFacing()); setTickInterval(tickInterval); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java index 06b5c5057..b1003ed81 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Fermenter.java @@ -73,7 +73,6 @@ public Item(@NotNull ItemStack stack) { public Fermenter(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setMultiblockDirection(context.getFacing()); setTickInterval(tickInterval); createFluidBuffer(PylonFluids.SUGARCANE, ethanolPerSugarcane * sugarcaneCapacity, false, false); addEntity("sugarcane", new ItemDisplayBuilder() diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index c16907e7f..0b1b0d115 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -94,7 +94,6 @@ public Boiler(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setTickInterval(tickInterval); setFacing(context.getFacing()); - setMultiblockDirection(context.getFacing()); } @SuppressWarnings("unused") diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Collimator.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Collimator.java index 863d13b7d..9d218c76d 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Collimator.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/Collimator.java @@ -3,17 +3,9 @@ import io.github.pylonmc.pylon.PylonFluids; import io.github.pylonmc.pylon.PylonItems; import io.github.pylonmc.pylon.PylonKeys; -import io.github.pylonmc.pylon.content.machines.fluid.FluidTank; -import io.github.pylonmc.pylon.content.machines.fluid.FluidTankWithDisplayEntity; import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; -import io.github.pylonmc.rebar.block.base.RebarFluidTank; -import io.github.pylonmc.rebar.block.base.RebarGuiBlock; -import io.github.pylonmc.rebar.block.base.RebarProcessor; -import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; -import io.github.pylonmc.rebar.block.base.RebarTickingBlock; -import io.github.pylonmc.rebar.block.base.RebarVirtualInventoryBlock; +import io.github.pylonmc.rebar.block.base.*; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; @@ -25,6 +17,9 @@ import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.time.Duration; +import java.util.List; +import java.util.Map; import net.kyori.adventure.text.format.TextColor; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -37,10 +32,6 @@ import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import java.time.Duration; -import java.util.List; -import java.util.Map; - public class Collimator extends RebarBlock implements RebarFluidTank, @@ -79,7 +70,6 @@ public Collimator(@NotNull Block block, @NotNull BlockCreateContext context) { setFacing(context.getFacing()); createFluidPoint(FluidPointType.INPUT, BlockFace.NORTH, context, false); setCapacity(obscyraPerCohesiveUnit); - setMultiblockDirection(context.getFacing()); startProcess(secondsPerCohesiveUnit * 20); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CoreDrill.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CoreDrill.java index f5b70d7f7..2e80d523f 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CoreDrill.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CoreDrill.java @@ -18,6 +18,7 @@ import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.util.position.BlockPosition; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.List; import lombok.Getter; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; @@ -34,9 +35,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; -import java.time.Duration; -import java.util.List; - public abstract class CoreDrill extends RebarBlock implements RebarSimpleMultiblock, RebarDirectionalBlock, @@ -74,7 +72,6 @@ public Item(@NotNull ItemStack stack) { protected CoreDrill(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setMultiblockDirection(getFacing()); addEntity("drill", new ItemDisplayBuilder() .itemStack(drillStack) .transformation(new TransformBuilder() diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Bloomery.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Bloomery.java index 2f6c5198f..a870ae94c 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Bloomery.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Bloomery.java @@ -20,6 +20,9 @@ import io.github.pylonmc.rebar.logistics.LogisticGroupType; import io.github.pylonmc.rebar.logistics.slot.ItemDisplayLogisticSlot; import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -42,10 +45,6 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3i; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; - public final class Bloomery extends RebarBlock implements RebarSimpleMultiblock, RebarInteractBlock, @@ -68,7 +67,7 @@ public Bloomery(@NotNull Block block, @NotNull BlockCreateContext context) { .build(getBlock().getLocation().toCenterLocation()) ); setTickInterval(TICK_INTERVAL); - setMultiblockDirection(context.getFacing()); + setFacing(context.getFacing()); } @SuppressWarnings("unused") From 9e6d9293daae73cd06418d5b402725a0277bdeff Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 30 Apr 2026 13:23:37 -0400 Subject: [PATCH 26/33] Multiblock gas turbine (spinny!!!!) --- .../content/machines/electric/GasTurbine.java | 223 +++++++++++++++++- .../machines/electric/SteamEngine.java | 9 +- .../pylon/content/tools/PylonWire.java | 2 +- src/main/resources/lang/en.yml | 6 +- 4 files changed, 224 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index b28bcdcca..8d6f62420 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -1,27 +1,45 @@ package io.github.pylonmc.pylon.content.machines.electric; +import io.github.pylonmc.pylon.Pylon; import io.github.pylonmc.pylon.PylonKeys; import io.github.pylonmc.pylon.content.components.FluidInputHatch; +import io.github.pylonmc.pylon.content.components.FluidOutputHatch; import io.github.pylonmc.pylon.recipes.GasTurbineRecipe; import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; import io.github.pylonmc.rebar.block.base.RebarTickingBlock; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.entity.display.ItemDisplayBuilder; +import io.github.pylonmc.rebar.entity.display.transform.TransformUtil; +import io.github.pylonmc.rebar.fluid.RebarFluid; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; +import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.NamespacedKey; +import org.bukkit.Registry; import org.bukkit.block.Block; +import org.bukkit.entity.ItemDisplay; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Matrix4f; +import org.joml.Quaternionf; +import org.joml.Vector3f; import org.joml.Vector3i; public class GasTurbine extends RebarBlock implements RebarSimpleMultiblock, - RebarTickingBlock, - RebarDirectionalBlock { + RebarTickingBlock { private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); @@ -29,7 +47,6 @@ public class GasTurbine extends RebarBlock implements public GasTurbine(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - setMultiblockDirection(context.getFacing()); setFacing(context.getFacing()); setTickInterval(tickInterval); } @@ -41,7 +58,65 @@ public GasTurbine(@NotNull Block block, @NotNull PersistentDataContainer pdc) { @Override public void tick() { + if (!isFormedAndFullyLoaded()) return; + ElectricityOutputHatch electricityOutputHatch = getMultiblockComponentOrThrow(ElectricityOutputHatch.class, ELECTRICITY_OUTPUT_HATCH); + electricityOutputHatch.setPower(0); + + FluidInputHatch inputHatch = getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH); + RebarFluid inputFluid = inputHatch.getFluid(); + if (inputFluid == null) return; + double inputAmount = inputHatch.getFluidAmount(); + + GasTurbineRecipe matchingRecipe = GasTurbineRecipe.RECIPE_TYPE.stream() + .filter(r -> r.input().contains(inputFluid)) + .findFirst() + .orElse(null); + if (matchingRecipe == null) return; + + FluidOutputHatch outputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); + RebarFluid outputFluid = matchingRecipe.output().fluid(); + if (outputHatch.getFluid() != null && !outputHatch.getFluid().equals(outputFluid)) return; + + double inputOutputRatio = matchingRecipe.input().amountMillibuckets() / matchingRecipe.output().amount(); + + double outputAmount = inputAmount / inputOutputRatio; + double actualOutputAmount = Math.min(outputAmount, outputHatch.getFluidSpaceRemaining()); + double actualInputAmount = Math.min(inputAmount, outputAmount * inputOutputRatio); + + inputHatch.removeFluid(inputFluid, actualInputAmount); + outputHatch.addFluid(outputFluid, actualOutputAmount); + + double powerOutput = matchingRecipe.powerProduction() * (actualInputAmount / matchingRecipe.input().amountMillibuckets()) * (20D / tickInterval); + electricityOutputHatch.setPower(powerOutput); + + Vector3f direction = getFacing().getOppositeFace().getDirection().toVector3f(); + + for (String entityId : getHeldEntities().keySet()) { + if (!entityId.startsWith("turbine_")) continue; + + ItemDisplay display = getHeldEntityOrThrow(ItemDisplay.class, entityId); + Matrix4f transform = TransformUtil.transformationToMatrix(display.getTransformation()); + + int stepsPerTick = 5; + for (int i = 0; i < stepsPerTick; i++) { + Bukkit.getScheduler().runTaskLater(Pylon.getInstance(), () -> { + transform.rotateLocal(new Quaternionf().rotateAxis((float) (2 * Math.PI / stepsPerTick), direction)); + if (display.isValid()) { + display.setInterpolationDelay(0); + display.setInterpolationDuration(tickInterval / stepsPerTick); + display.setTransformationMatrix(transform); + } + }, i * (tickInterval / stepsPerTick)); + } + } + } + + @Override + public @Nullable WailaDisplay getWaila(@NotNull Player player) { + return new WailaDisplay(getDefaultWailaTranslationKey().arguments( + RebarArgument.of("power", UnitFormat.WATTS.format(getMultiblockComponentOrThrow(ElectricityOutputHatch.class, ELECTRICITY_OUTPUT_HATCH).getPower())) + )); } private static final Vector3i FLUID_INPUT_HATCH = new Vector3i(0, 0, -2); @@ -77,10 +152,150 @@ private static void lineOfThree(int x, int y, NamespacedKey key, Map r.input().fluids().stream()).collect(Collectors.toSet())); + + if (getHeldEntity("turbine_shaft") == null) { + getBlock().setType(Material.STRUCTURE_VOID); + refreshBlockTextureItem(); + setupDisplay(); + } + } + + @Override + public void onMultiblockUnformed(boolean partUnloaded) { + RebarSimpleMultiblock.super.onMultiblockUnformed(partUnloaded); + + if (!partUnloaded) { + for (String entityId : new ArrayList<>(getHeldEntities().keySet())) { + if (entityId.startsWith("turbine_")) { + tryRemoveEntity(entityId); + } + } + + getBlock().setType(Material.IRON_BLOCK); + refreshBlockTextureItem(); + } + + ElectricityOutputHatch electricityOutputHatch = getMultiblockComponent(ElectricityOutputHatch.class, ELECTRICITY_OUTPUT_HATCH); + if (electricityOutputHatch != null) { + electricityOutputHatch.setPower(0); + } + } + + private void setupDisplay() { + addEntity("turbine_shaft", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_shaft")) + .transformation(new Matrix4f() + .scaleLocal(0.20031818431717888F, 0.1998618756962673F, 2.999928431318844F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.7001095104874101F, 0.7003343199606629F, 0.05027297059664036F) + .translateLocal(0F, 0F, 0.02499999999999991F) + .translateLocal(0F, 0F, -1.2F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_1", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.5995684032343717F, 0.5998784121385513F, 0.049829445006917716F) + .translateLocal(0F, 0F, -0.025000000000000022F) + .translateLocal(0F, 0F, -1.1F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_2", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.400408077237662F, 0.39961631863827995F, 0.049862215651233666F) + .translateLocal(0F, 0F, -0.02499999999999991F) + .translateLocal(0F, 0F, -1.05F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_3", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.4998993373616677F, 0.4999216378035786F, 0.050083582762834034F) + .translateLocal(0F, 0F, -0.025000000000000022F) + .translateLocal(0F, 0F, -0.15000000000000002F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_4", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.6000367675274685F, 0.6501684628404046F, 0.04992085141408112F) + .translateLocal(0F, -0.025000000000000022F, 0.02499999999999991F) + .translateLocal(0F, 0F, 0.6000000000000001F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_5", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.5002561171050549F, 0.5496725403840674F, 0.050218433779457734F) + .translateLocal(0F, -0.02499999999999991F, -0.025000000000000133F) + .translateLocal(0F, 0F, 0.7F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_6", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.2999681211206062F, 0.35012340582916684F, 0.049593864090870424F) + .translateLocal(0F, -0.025000000000000022F, -0.02499999999999991F) + .translateLocal(0F, 0F, 0.75F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); + + addEntity("turbine_blisk_7", new ItemDisplayBuilder() + .itemStack(ItemStackBuilder.of(Registry.MATERIAL.getOrThrow(NamespacedKey.minecraft("iron_block"))) + .addCustomModelDataString(getKey() + ":turbine_blisk")) + .transformation(new Matrix4f() + .scaleLocal(0.5002451479182026F, 0.5003304693503907F, 0.049636693814377984F) + .translateLocal(0F, 0F, -0.025000000000000133F) + .translateLocal(0F, 0F, 1.05F) + .rotateLocal(new Quaternionf().lookAlong(getFacing().getDirection().toVector3f().mul(-1F, -1F, 1F), new Vector3f(0, 1, 0))) + ) + .build(getBlock().getLocation().toCenterLocation()) + ); } } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java index 5293b1469..fc6fb3979 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java @@ -16,7 +16,6 @@ import io.github.pylonmc.rebar.waila.WailaDisplay; import java.util.List; import java.util.Map; -import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Particle; import org.bukkit.block.Block; @@ -56,8 +55,7 @@ public Item(@NotNull ItemStack stack) { return List.of( RebarArgument.of("steam-usage", UnitFormat.MILLIBUCKETS_PER_SECOND.format(steamUsage)), RebarArgument.of("steam-capacity", UnitFormat.MILLIBUCKETS.format(steamCapacity)), - RebarArgument.of("power-production", UnitFormat.WATTS.format(powerProduction)), - RebarArgument.of("output-voltage", UnitFormat.VOLTS.format(outputVoltage)) + RebarArgument.of("power-production", UnitFormat.WATTS.format(powerProduction)) ); } } @@ -116,10 +114,7 @@ public void tick() { 20, TextColor.fromHexString("#d8d8d8") )), - RebarArgument.of("power", Component.translatable( - "pylon.waila.electric.producer", - RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())) - )) + RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())) )); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java index 85a474372..83eb35abd 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/PylonWire.java @@ -20,7 +20,7 @@ public PylonWire(@NotNull ItemStack stack) { @Override public @NotNull List<@NotNull RebarArgument> getPlaceholders() { - return List.of(RebarArgument.of("max-power", UnitFormat.AMPRERES.format(maxPower))); + return List.of(RebarArgument.of("max-power", UnitFormat.WATTS.format(maxPower))); } @Override diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 474189782..786a67dd8 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2469,7 +2469,7 @@ item: Components 1x 1x - waila: "Steam Engine | %bar% | %power%" + waila: "Steam Engine | %bar% | producing %power%" gas_turbine: name: "Gas Turbine" @@ -2485,7 +2485,7 @@ item: 1x 1x 1x - waila: "Gas Turbine | %power%" + waila: "Gas Turbine | producing %power%" wire_1_gauge: name: "1-Gauge Wire" @@ -2535,8 +2535,6 @@ fluid: biodiesel: "<#eaa627>Biodiesel" waila: - electric: - producer: "Producing %power%" crucible: item: empty: "| No items |" From b86292508448f55e367e61ef5ebd2fb610bf7660 Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 30 Apr 2026 15:29:58 -0400 Subject: [PATCH 27/33] Recipe pages --- src/main/java/io/github/pylonmc/pylon/PylonItems.java | 4 ++++ src/main/java/io/github/pylonmc/pylon/PylonRecipes.java | 1 + 2 files changed, 5 insertions(+) diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 4312ac1b8..c1ac1b660 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3269,6 +3269,8 @@ private PylonItems() { static { RebarItem.register(RebarItem.class, GAS_TURBINE, PylonKeys.GAS_TURBINE); PylonPages.ELECTRICITY.addItem(GAS_TURBINE); + RebarGuide.getOrCreateInfoPage(PylonKeys.GAS_TURBINE) + .addButton(new MachineRecipesButton(GAS_TURBINE, GasTurbineRecipe.RECIPE_TYPE)); } public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) @@ -3276,6 +3278,8 @@ private PylonItems() { static { RebarItem.register(ElectricGrindstone.Item.class, ELECTRIC_GRINDSTONE, PylonKeys.ELECTRIC_GRINDSTONE); PylonPages.ELECTRICITY.addItem(ELECTRIC_GRINDSTONE); + RebarGuide.getOrCreateInfoPage(PylonKeys.ELECTRIC_GRINDSTONE) + .addButton(new MachineRecipesButton(ELECTRIC_GRINDSTONE, GrindstoneRecipe.RECIPE_TYPE)); } // diff --git a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java index 2a6a0cb44..e9097d434 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java @@ -52,6 +52,7 @@ public static void initialize() { initPalladiumCondenser(); initBiorefinery(); initFermenter(); + initBoiler(); } private static void initCollimator() { From 76b5515b2cb0dcde4f86c2381caae17efbd31c67 Mon Sep 17 00:00:00 2001 From: Seggan Date: Thu, 30 Apr 2026 16:54:03 -0400 Subject: [PATCH 28/33] Particles --- .../content/machines/electric/GasTurbine.java | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index 8d6f62420..742d7eff1 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -15,21 +15,21 @@ import io.github.pylonmc.rebar.fluid.RebarFluid; import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.Vector3fs; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; +import java.util.concurrent.ThreadLocalRandom; import java.util.stream.Collectors; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Registry; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; @@ -110,6 +110,22 @@ public void tick() { }, i * (tickInterval / stepsPerTick)); } } + + Vector3f acrossDirection = new Vector3f(direction).cross(Vector3fs.positiveY()).normalize(); + Vector3f veryBack = new Vector3f(direction).mul(-1.5f).sub(0, 0.5f, 0).sub(new Vector3f(acrossDirection).mul(0.5f)); + int particles = (int) Math.ceil(Math.log(inputAmount)); + for (int i = 0; i < particles; i++) { + Vector3f randomOffset = new Vector3f(acrossDirection).mul(ThreadLocalRandom.current().nextFloat()).add(0, ThreadLocalRandom.current().nextFloat(), 0); + Location spawnLocation = getBlock().getLocation().toCenterLocation().add(Vector.fromJOML(new Vector3f(veryBack).add(randomOffset))); + Bukkit.getScheduler().runTaskLater(Pylon.getInstance(), () -> { + Particle.POOF.builder() + .count(0) + .offset(direction.x, direction.y, direction.z) + .extra(0.5) + .location(spawnLocation) + .spawn(); + }, ThreadLocalRandom.current().nextInt(tickInterval)); + } } @Override From a741e4596f2c73463ac218a36fa20b16cd67f105 Mon Sep 17 00:00:00 2001 From: Seggan Date: Mon, 4 May 2026 13:31:59 -0400 Subject: [PATCH 29/33] Combustion tower --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonFluids.java | 16 +++ .../io/github/pylonmc/pylon/PylonItems.java | 7 + .../io/github/pylonmc/pylon/PylonKeys.java | 2 + .../machines/electric/CombustionTower.java | 130 ++++++++++++++++++ src/main/resources/lang/en.yml | 25 +++- .../resources/recipes/pylon/gas_turbine.yml | 7 + .../resources/settings/combustion_tower.yml | 5 + 8 files changed, 192 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java create mode 100644 src/main/resources/settings/combustion_tower.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 9337db685..9a5278479 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -191,6 +191,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.BOILER, Material.BLAST_FURNACE, Boiler.class); RebarBlock.register(PylonKeys.STEAM_ENGINE, Material.IRON_BLOCK, SteamEngine.class); RebarBlock.register(PylonKeys.GAS_TURBINE, Material.IRON_BLOCK, GasTurbine.class); + RebarBlock.register(PylonKeys.COMBUSTION_TOWER, Material.BRICKS, CombustionTower.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonFluids.java b/src/main/java/io/github/pylonmc/pylon/PylonFluids.java index 23fa39237..ee0785cf8 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonFluids.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonFluids.java @@ -255,6 +255,22 @@ private PylonFluids() { SPONGE_IRON_SLURRY.register(); } + public static final RebarFluid VERY_HOT_EXHAUST = new RebarFluid( + pylonKey("very_hot_exhaust"), + Material.RED_STAINED_GLASS + ).addTag(FluidTemperature.HOT); + static { + VERY_HOT_EXHAUST.register(); + } + + public static final RebarFluid HOT_EXHAUST = new RebarFluid( + pylonKey("hot_exhaust"), + Material.ORANGE_STAINED_GLASS + ).addTag(FluidTemperature.HOT); + static { + HOT_EXHAUST.register(); + } + /** * Calling this function will run the static blocks */ diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index c1ac1b660..d4383c44f 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -3272,6 +3272,13 @@ private PylonItems() { RebarGuide.getOrCreateInfoPage(PylonKeys.GAS_TURBINE) .addButton(new MachineRecipesButton(GAS_TURBINE, GasTurbineRecipe.RECIPE_TYPE)); } + + public static final ItemStack COMBUSTION_TOWER = ItemStackBuilder.rebar(Material.BRICKS, PylonKeys.COMBUSTION_TOWER) + .build(); + static { + RebarItem.register(CombustionTower.Item.class, COMBUSTION_TOWER, PylonKeys.COMBUSTION_TOWER); + PylonPages.ELECTRICITY.addItem(COMBUSTION_TOWER); + } public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) .build(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 66ecad711..e9e107a69 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -474,5 +474,7 @@ public class PylonKeys { public static final NamespacedKey BOILER = pylonKey("boiler"); public static final NamespacedKey STEAM_ENGINE = pylonKey("steam_engine"); public static final NamespacedKey GAS_TURBINE = pylonKey("gas_turbine"); + public static final NamespacedKey COMBUSTION_TOWER = pylonKey("combustion_tower"); + public static final NamespacedKey HEAT_EXCHANGER = pylonKey("heat_exchanger"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java new file mode 100644 index 000000000..4787f23d0 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java @@ -0,0 +1,130 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonFluids; +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.util.PylonUtils; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; +import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.fluid.FluidPointType; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3i; + +public class CombustionTower extends RebarBlock implements + RebarTickingBlock, + RebarFluidBufferBlock, + RebarSimpleMultiblock { + + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + private final double dieselUsage = getSettings().getOrThrow("diesel-usage", ConfigAdapter.DOUBLE); + private final double dieselBuffer = getSettings().getOrThrow("diesel-buffer", ConfigAdapter.DOUBLE); + private final double exhaustProduction = getSettings().getOrThrow("exhaust-production", ConfigAdapter.DOUBLE); + private final double exhaustBuffer = getSettings().getOrThrow("exhaust-buffer", ConfigAdapter.DOUBLE); + + public static class Item extends RebarItem { + + private final double dieselUsage = getSettings().getOrThrow("diesel-usage", ConfigAdapter.DOUBLE); + private final double exhaustProduction = getSettings().getOrThrow("exhaust-production", ConfigAdapter.DOUBLE); + + @SuppressWarnings("unused") + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of( + RebarArgument.of("diesel-usage", UnitFormat.MILLIBUCKETS_PER_SECOND.format(dieselUsage)), + RebarArgument.of("exhaust-production", UnitFormat.MILLIBUCKETS_PER_SECOND.format(exhaustProduction)) + ); + } + } + + @SuppressWarnings("unused") + public CombustionTower(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + setTickInterval(tickInterval); + + createFluidBuffer(PylonFluids.BIODIESEL, dieselBuffer, true, false); + createFluidBuffer(PylonFluids.VERY_HOT_EXHAUST, exhaustBuffer, false, true); + + createFluidPoint(FluidPointType.INPUT, BlockFace.NORTH); + createFluidPoint(FluidPointType.OUTPUT, BlockFace.SOUTH); + } + + @SuppressWarnings("unused") + public CombustionTower(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void tick() { + if (!isFormedAndFullyLoaded()) return; + + double dieselToConsume = Math.min(dieselUsage / getTicksPerSecond(), fluidAmount(PylonFluids.BIODIESEL)); + double exhaustToProduce = dieselToConsume * (exhaustProduction / dieselUsage); + double actualExhaustProduced = Math.min(exhaustToProduce, fluidSpaceRemaining(PylonFluids.VERY_HOT_EXHAUST)); + double actualDieselConsumed = actualExhaustProduced * (dieselUsage / exhaustProduction); + + removeFluid(PylonFluids.BIODIESEL, actualDieselConsumed); + addFluid(PylonFluids.VERY_HOT_EXHAUST, actualExhaustProduced); + + Particle.CAMPFIRE_SIGNAL_SMOKE.builder() + .location(getBlock().getLocation().add(Vector.fromJOML(SMOKESTACK_POS)).toCenterLocation()) + .offset(0, 1, 0) + .count(0) + .extra(0.03) + .spawn(); + } + + @Override + public @Nullable WailaDisplay getWaila(@NotNull Player player) { + return new WailaDisplay(getDefaultWailaTranslationKey().arguments( + RebarArgument.of("diesel", PylonUtils.createFluidAmountBar( + fluidAmount(PylonFluids.BIODIESEL), + fluidCapacity(PylonFluids.BIODIESEL), + 20, + TextColor.fromHexString("#eaa627") + )), + RebarArgument.of("exhaust", PylonUtils.createFluidAmountBar( + fluidAmount(PylonFluids.VERY_HOT_EXHAUST), + fluidCapacity(PylonFluids.VERY_HOT_EXHAUST), + 20, + TextColor.fromHexString("#ff2b0f") + )) + )); + } + + private static final Vector3i SMOKESTACK_POS = new Vector3i(0, 3, 0); + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + Map components = new HashMap<>(); + + components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_RING)); + components.put(new Vector3i(0, 2, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_RING)); + components.put(SMOKESTACK_POS, new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + + return components; + } +} \ No newline at end of file diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 786a67dd8..4ffe9e1bb 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -2481,12 +2481,33 @@ item: 1x 9x 3x - 1x + 10x 1x 1x 1x waila: "Gas Turbine | producing %power%" + combustion_tower: + name: "Combustion Tower" + lore: |- + Burns diesel to produce very hot exhaust + Diesel usage: %diesel-usage% + Very hot exhaust production: %exhaust-production% + + Components + 1x + waila: "Combustion Tower | %diesel% | %exhaust%" + + heat_exchanger: + name: "Heat Exchanger" + lore: |- + Exchanges heat between two fluids + + Components + 1x + 2x + 2x + wire_1_gauge: name: "1-Gauge Wire" lore: |- @@ -2533,6 +2554,8 @@ fluid: sugarcane: "<#a3ed2d>Sugarcane" ethanol: "<#d8d8d8>Ethanol" biodiesel: "<#eaa627>Biodiesel" + very_hot_exhaust: "<#ff2b0f>Very Hot Exhaust" + hot_exhaust: "<#ff6b0f>Hot Exhaust" waila: crucible: diff --git a/src/main/resources/recipes/pylon/gas_turbine.yml b/src/main/resources/recipes/pylon/gas_turbine.yml index e98fdf34a..f1d717799 100644 --- a/src/main/resources/recipes/pylon/gas_turbine.yml +++ b/src/main/resources/recipes/pylon/gas_turbine.yml @@ -3,4 +3,11 @@ pylon:steam: pylon:steam: 10 output: pylon:water: 1 + power-production: 10 + +pylon:exhaust: + input: + pylon:very_hot_exhaust: 10 + output: + pylon:hot_exhaust: 5 power-production: 10 \ No newline at end of file diff --git a/src/main/resources/settings/combustion_tower.yml b/src/main/resources/settings/combustion_tower.yml new file mode 100644 index 000000000..d0c6754b2 --- /dev/null +++ b/src/main/resources/settings/combustion_tower.yml @@ -0,0 +1,5 @@ +tick-interval: 10 +diesel-usage: 50 +diesel-buffer: 1000 +exhaust-production: 100 +exhaust-buffer: 1000 \ No newline at end of file From e3e6b53c3871f72f0a427dd267eda7d15e7f00d1 Mon Sep 17 00:00:00 2001 From: Seggan Date: Mon, 11 May 2026 16:16:23 -0400 Subject: [PATCH 30/33] Fix compile --- .../components/LiseletteCollector.java | 2 +- .../diesel/machines/DieselGrindstone.java | 62 +------------------ .../content/machines/electric/Boiler.java | 22 +++---- .../machines/electric/CombustionTower.java | 6 +- .../content/machines/electric/GasTurbine.java | 14 ++--- .../machines/electric/SteamEngine.java | 2 +- .../machines/fluid/PortableFluidTank.java | 2 +- .../machines/generic/AbstractGrindstone.java | 38 +++++++----- .../hydraulics/BurnerHydraulicPurifier.java | 19 +++--- .../ConvectionHydraulicPurifier.java | 19 +++--- .../hydraulics/HydraulicPurifier.java | 2 +- .../LiseletteHydraulicPurifier.java | 16 +++-- .../content/machines/simple/PotionAltar.java | 36 ++++------- .../machines/smelting/SmelteryController.java | 49 ++++++--------- .../pylon/content/tools/BrickMold.java | 11 +++- .../pylonmc/pylon/content/tools/Moldable.java | 2 +- .../guide/HydraulicRefuelableItemsPage.java | 4 +- .../pylonmc/pylon/recipes/HammerRecipe.java | 3 +- .../pylon/recipes/SiloConverterRecipe.java | 2 +- 19 files changed, 114 insertions(+), 197 deletions(-) diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/LiseletteCollector.java b/src/main/java/io/github/pylonmc/pylon/content/components/LiseletteCollector.java index d1e613c3d..d46a2ec57 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/LiseletteCollector.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/LiseletteCollector.java @@ -41,7 +41,7 @@ public LiseletteCollector(@NotNull Block block, @NotNull PersistentDataContainer } @Override - protected void postLoad() { + protected void postLoad(@NotNull PersistentDataContainer pdc) { getHeldEntityOrThrow(ItemDisplay.class, "shell") .setBrightness(new Display.Brightness(15, 15)); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java index 912963357..24f289532 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselGrindstone.java @@ -19,6 +19,7 @@ import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.List; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Material; import org.bukkit.NamespacedKey; @@ -34,8 +35,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; -import java.util.List; - import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; @@ -154,65 +153,6 @@ public void tick() { ); } - public void tryStartRecipe() { - if (isProcessingRecipe()) { - return; - } - - ItemStack stack = inputInventory.getItem(0); - if (stack == null) { - return; - } - - if (getLastRecipe() != null && tryStartRecipe(getLastRecipe(), stack)) { - return; - } - - for (GrindstoneRecipe recipe : GrindstoneRecipe.RECIPE_TYPE) { - if (tryStartRecipe(recipe, stack)) { - return; - } - } - } - - private boolean tryStartRecipe(GrindstoneRecipe recipe, ItemStack stack) { - if (!recipe.input().matches(stack)) { - return false; - } - - if (!outputInventory.canHold(List.copyOf(recipe.results().getElements()))) { - return true; - } - - startRecipe(recipe, recipe.cycles() * Grindstone.CYCLE_DURATION_TICKS); - getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); - inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); - return true; - } - - @Override - public void onRecipeFinished(@NotNull GrindstoneRecipe recipe) { - getRecipeProgressItem().setItem(GuiItems.background()); - outputInventory.addItem(null, recipe.results().getRandom()); - } - - @Override - public @NotNull Gui createGui() { - return Gui.builder() - .setStructure( - "# I # # # O O O #", - "# i # p # o o o #", - "# I # # # O O O #" - ) - .addIngredient('#', GuiItems.background()) - .addIngredient('I', GuiItems.input()) - .addIngredient('i', inputInventory) - .addIngredient('O', GuiItems.output()) - .addIngredient('o', outputInventory) - .addIngredient('p', getRecipeProgressItem()) - .build(); - } - @Override public @Nullable WailaDisplay getWaila(@NotNull Player player) { return new WailaDisplay(getDefaultWailaTranslationKey().arguments( diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index 0b1b0d115..e30ec9acc 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -146,32 +146,32 @@ public void postInitialise() { public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { Map components = new HashMap<>(); - components.put(WATER_INPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_INPUT_HATCH)); - components.put(STEAM_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_OUTPUT_HATCH)); + components.put(WATER_INPUT_HATCH, MultiblockComponent.of(PylonKeys.FLUID_INPUT_HATCH)); + components.put(STEAM_OUTPUT_HATCH, MultiblockComponent.of(PylonKeys.FLUID_OUTPUT_HATCH)); // bottom layer for (int x = -1; x <= 1; x++) { for (int z = 0; z <= 2; z++) { - components.put(new Vector3i(x, -1, z), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(x, -1, z), MultiblockComponent.of(PylonKeys.BOILER_CASING)); } } // middle layer - components.put(new Vector3i(-1, 0, 1), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); - components.put(new Vector3i(1, 0, 1), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); - components.put(new Vector3i(-1, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); - components.put(new Vector3i(0, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); - components.put(new Vector3i(1, 0, 2), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(-1, 0, 1), MultiblockComponent.of(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(1, 0, 1), MultiblockComponent.of(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(-1, 0, 2), MultiblockComponent.of(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(0, 0, 2), MultiblockComponent.of(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(1, 0, 2), MultiblockComponent.of(PylonKeys.BOILER_CASING)); // top layer - components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(0, 1, 0), MultiblockComponent.of(PylonKeys.BOILER_CASING)); for (int x = -1; x <= 1; x++) { for (int z = 1; z <= 2; z++) { - components.put(new Vector3i(x, 1, z), new RebarMultiblockComponent(PylonKeys.BOILER_CASING)); + components.put(new Vector3i(x, 1, z), MultiblockComponent.of(PylonKeys.BOILER_CASING)); } } - components.put(SMOKESTACK_CAP, new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + components.put(SMOKESTACK_CAP, MultiblockComponent.of(PylonKeys.SMOKESTACK_CAP)); return components; } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java index 4787f23d0..7cac95ebe 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java @@ -121,9 +121,9 @@ public void tick() { public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { Map components = new HashMap<>(); - components.put(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_RING)); - components.put(new Vector3i(0, 2, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_RING)); - components.put(SMOKESTACK_POS, new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + components.put(new Vector3i(0, 1, 0), MultiblockComponent.of(PylonKeys.SMOKESTACK_RING)); + components.put(new Vector3i(0, 2, 0), MultiblockComponent.of(PylonKeys.SMOKESTACK_RING)); + components.put(SMOKESTACK_POS, MultiblockComponent.of(PylonKeys.SMOKESTACK_CAP)); return components; } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index 742d7eff1..b0204d51e 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -153,19 +153,19 @@ public void tick() { lineOfThree(-1, -1, PylonKeys.BRONZE_FOUNDATION, components); lineOfThree(1, -1, PylonKeys.BRONZE_FOUNDATION, components); - components.put(new Vector3i(0, -1, -2), new RebarMultiblockComponent(PylonKeys.BRONZE_FOUNDATION)); + components.put(new Vector3i(0, -1, -2), MultiblockComponent.of(PylonKeys.BRONZE_FOUNDATION)); - components.put(FLUID_INPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_INPUT_HATCH)); - components.put(FLUID_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.FLUID_OUTPUT_HATCH)); - components.put(ELECTRICITY_OUTPUT_HATCH, new RebarMultiblockComponent(PylonKeys.ELECTRICITY_OUTPUT_HATCH)); + components.put(FLUID_INPUT_HATCH, MultiblockComponent.of(PylonKeys.FLUID_INPUT_HATCH)); + components.put(FLUID_OUTPUT_HATCH, MultiblockComponent.of(PylonKeys.FLUID_OUTPUT_HATCH)); + components.put(ELECTRICITY_OUTPUT_HATCH, MultiblockComponent.of(PylonKeys.ELECTRICITY_OUTPUT_HATCH)); return components; } private static void lineOfThree(int x, int y, NamespacedKey key, Map components) { - components.put(new Vector3i(x, y, 0), new RebarMultiblockComponent(key)); - components.put(new Vector3i(x, y, 1), new RebarMultiblockComponent(key)); - components.put(new Vector3i(x, y, -1), new RebarMultiblockComponent(key)); + components.put(new Vector3i(x, y, 0), MultiblockComponent.of(key)); + components.put(new Vector3i(x, y, 1), MultiblockComponent.of(key)); + components.put(new Vector3i(x, y, -1), MultiblockComponent.of(key)); } @Override diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java index fc6fb3979..bd4d165d0 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java @@ -84,7 +84,7 @@ public void postInitialise() { @Override public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { - return Map.of(new Vector3i(0, 1, 0), new RebarMultiblockComponent(PylonKeys.SMOKESTACK_CAP)); + return Map.of(new Vector3i(0, 1, 0), MultiblockComponent.of(PylonKeys.SMOKESTACK_CAP)); } @Override diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java index d8b689f57..2b0d62224 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/fluid/PortableFluidTank.java @@ -166,7 +166,7 @@ public boolean isAllowedFluid(@NotNull RebarFluid fluid) { @Override public @Nullable ItemStack getPickItem() { // TODO implement clone for RebarItem and just clone it - ItemStack stack = RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItem(); + ItemStack stack = RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItemStack(); Item item = new Item(stack); item.setFluid(getFluidType()); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java index 0410a90c6..8fb578600 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractGrindstone.java @@ -12,6 +12,8 @@ import io.github.pylonmc.rebar.util.RebarUtils; import io.github.pylonmc.rebar.util.gui.GuiItems; import io.github.pylonmc.rebar.util.gui.ProgressItem; +import java.util.List; +import java.util.Map; import org.bukkit.block.Block; import org.bukkit.inventory.ItemStack; import org.bukkit.persistence.PersistentDataContainer; @@ -19,8 +21,6 @@ import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.inventory.VirtualInventory; -import java.util.Map; - public abstract class AbstractGrindstone extends RebarBlock implements RebarGuiBlock, RebarVirtualInventoryBlock, @@ -60,7 +60,7 @@ public void postInitialise() { }); } - private void tryStartRecipe() { + public void tryStartRecipe() { if (isProcessingRecipe()) { return; } @@ -70,23 +70,30 @@ private void tryStartRecipe() { return; } - recipeLoop: + if (getLastRecipe() != null && tryStartRecipe(getLastRecipe(), stack)) { + return; + } + for (GrindstoneRecipe recipe : GrindstoneRecipe.RECIPE_TYPE) { - if (!recipe.input().matches(stack)) { - continue; + if (tryStartRecipe(recipe, stack)) { + return; } + } + } - for (ItemStack output : recipe.results().getElements()) { - if (!outputInventory.canHold(output)) { - break recipeLoop; - } - } + private boolean tryStartRecipe(GrindstoneRecipe recipe, ItemStack stack) { + if (!recipe.input().matches(stack)) { + return false; + } - startRecipe(recipe, recipe.cycles() * Grindstone.CYCLE_DURATION_TICKS); - getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); - inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); - break; + if (!outputInventory.canHold(List.copyOf(recipe.results().getElements()))) { + return true; } + + startRecipe(recipe, recipe.cycles() * Grindstone.CYCLE_DURATION_TICKS); + getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); + inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); + return true; } @Override @@ -111,7 +118,6 @@ public void onRecipeFinished(@NotNull GrindstoneRecipe recipe) { .addIngredient('p', getRecipeProgressItem()) .build(); } - @Override public @NotNull Map getVirtualInventories() { return Map.of( diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java index 8a0a89ac0..c9fb36799 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java @@ -16,7 +16,10 @@ import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; -import net.kyori.adventure.text.Component; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Particle; import org.bukkit.block.Block; @@ -32,11 +35,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - public class BurnerHydraulicPurifier extends RebarBlock implements RebarSimpleMultiblock, @@ -83,7 +81,6 @@ public BurnerHydraulicPurifier(@NotNull Block block, @NotNull BlockCreateContext super(block, context); setTickInterval(tickInterval); setFacing(context.getFacing()); - setMultiblockDirection(context.getFacing()); } @SuppressWarnings("unused") @@ -149,8 +146,8 @@ public void tick() { double fluidToPurify = Math.min( hydraulicFluidPerMachineTick, Math.min( - fluidInput.fluidAmount(PylonFluids.DIRTY_HYDRAULIC_FLUID), - fluidOutput.fluidSpaceRemaining(PylonFluids.HYDRAULIC_FLUID) + fluidInput.getFluidAmount(), + fluidOutput.getFluidSpaceRemaining() ) ); if (fluidToPurify < hydraulicFluidPerMachineTick) { @@ -201,9 +198,7 @@ public void tryConsumeFuel() { @Override public void onMultiblockFormed() { getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT) - .setFluidType(PylonFluids.DIRTY_HYDRAULIC_FLUID); - getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT) - .setFluidType(PylonFluids.HYDRAULIC_FLUID); + .setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); RebarSimpleMultiblock.super.onMultiblockFormed(); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java index 24bf19fd7..2fc7b3392 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java @@ -19,6 +19,10 @@ import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Material; @@ -35,11 +39,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - public class ConvectionHydraulicPurifier extends RebarBlock implements RebarSimpleMultiblock, @@ -91,7 +90,6 @@ public ConvectionHydraulicPurifier(@NotNull Block block, @NotNull BlockCreateCon super(block, context); setTickInterval(tickInterval); setFacing(context.getFacing()); - setMultiblockDirection(context.getFacing()); addEntity("lava1", new ItemDisplayBuilder() .material(Material.ORANGE_CONCRETE) .brightness(0) @@ -180,8 +178,8 @@ public void tick() { FluidInputHatch hydraulicInput = getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT); FluidOutputHatch hydraulicOutput = getMultiblockComponentOrThrow(FluidOutputHatch.class, HYDRAULIC_FLUID_OUTPUT); - double inputFluidAvailable = hydraulicInput.fluidAmount(PylonFluids.DIRTY_HYDRAULIC_FLUID); - double outputSpaceRemaining = hydraulicOutput.fluidSpaceRemaining(PylonFluids.HYDRAULIC_FLUID); + double inputFluidAvailable = hydraulicInput.getFluidAmount(); + double outputSpaceRemaining = hydraulicOutput.getFluidSpaceRemaining(); double fluidToPurify = Math.min(purificationSpeed, Math.min(inputFluidAvailable, outputSpaceRemaining)) * getTickInterval() / 20; double efficiency = getEfficiency(); @@ -206,10 +204,7 @@ public void tick() { @Override public void onMultiblockFormed() { - FluidInputHatch hydraulicInput = getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT); - FluidOutputHatch hydraulicOutput = getMultiblockComponentOrThrow(FluidOutputHatch.class, HYDRAULIC_FLUID_OUTPUT); - hydraulicInput.setFluidType(PylonFluids.DIRTY_HYDRAULIC_FLUID); - hydraulicOutput.setFluidType(PylonFluids.HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT).setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); Block light = getBlock().getRelative(BlockFace.UP); if (light.getType().isAir()) { light.setType(Material.LIGHT); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java index a593c89f6..3a1d99bfa 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicPurifier.java @@ -70,7 +70,7 @@ static List getPurifiers() { RebarItemSchema itemSchema = RebarRegistry.ITEMS.get(blockSchema.getKey()); if (itemSchema == null) continue; // should never happen - purifiers.add(itemSchema.createNewItem()); + purifiers.add(itemSchema.createNewItemStack()); } return purifiers; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java index cd35081b7..5183b98bd 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java @@ -18,6 +18,10 @@ import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.util.position.BlockPosition; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; import org.bukkit.Bukkit; import org.bukkit.Particle; import org.bukkit.block.Block; @@ -29,11 +33,6 @@ import org.jetbrains.annotations.NotNull; import org.joml.Vector3i; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Random; - public class LiseletteHydraulicPurifier extends RebarBlock implements RebarSimpleMultiblock, @@ -123,8 +122,7 @@ public LiseletteHydraulicPurifier(@NotNull Block block, @NotNull PersistentDataC @Override public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); - getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH).setFluidType(PylonFluids.DIRTY_HYDRAULIC_FLUID); - getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH).setFluidType(PylonFluids.HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH).setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); } @Override @@ -166,8 +164,8 @@ public void tick() { double toPurify = Math.min( speed * maxFluidPurifiedPerStrike, Math.min( - inputHatch.fluidAmount(PylonFluids.DIRTY_HYDRAULIC_FLUID), - outputHatch.fluidSpaceRemaining(PylonFluids.HYDRAULIC_FLUID) / purificationEfficiency + inputHatch.getFluidAmount(), + outputHatch.getFluidSpaceRemaining() / purificationEfficiency ) ); inputHatch.removeFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, toPurify); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/PotionAltar.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/PotionAltar.java index f3d0f5225..a92d4f1a0 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/PotionAltar.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/PotionAltar.java @@ -9,12 +9,7 @@ import io.github.pylonmc.pylon.util.PylonUtils; import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.RebarBreakHandler; -import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; -import io.github.pylonmc.rebar.block.base.RebarInteractBlock; -import io.github.pylonmc.rebar.block.base.RebarRecipeProcessor; -import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; -import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.base.*; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; @@ -27,17 +22,13 @@ import io.github.pylonmc.rebar.waila.WailaDisplay; import io.papermc.paper.datacomponent.DataComponentTypes; import io.papermc.paper.datacomponent.item.PotionContents; +import java.util.*; +import java.util.concurrent.ThreadLocalRandom; import lombok.Getter; import net.kyori.adventure.sound.Sound; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.TextColor; -import org.bukkit.Bukkit; -import org.bukkit.Color; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Particle; -import org.bukkit.Vibration; +import org.bukkit.*; import org.bukkit.Vibration.Destination.BlockDestination; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -55,13 +46,6 @@ import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.ThreadLocalRandom; - /** * @author balugaq */ @@ -69,9 +53,9 @@ public class PotionAltar extends RebarBlock implements RebarSimpleMultiblock, RebarInteractBlock, RebarTickingBlock, RebarDirectionalBlock, RebarBreakHandler { private static final NamespacedKey RECIPE_TICKS_REMAINING_KEY = PylonUtils.pylonKey("potion_altar_recipe_ticks_remaining"); - private static final MultiblockComponent SHIMMER_PEDESTAL_COMPONENT = new RebarMultiblockComponent(PylonKeys.SHIMMER_PEDESTAL); - private static final MultiblockComponent POTION_PEDESTAL_COMPONENT = new RebarMultiblockComponent(PylonKeys.POTION_PEDESTAL); - private static final MultiblockComponent LIT_ORANGE_CANDLE_COMPONENT = new VanillaBlockdataMultiblockComponent(Material.ORANGE_CANDLE.createBlockData("[lit=true]")); + private static final MultiblockComponent SHIMMER_PEDESTAL_COMPONENT = MultiblockComponent.of(PylonKeys.SHIMMER_PEDESTAL); + private static final MultiblockComponent POTION_PEDESTAL_COMPONENT = MultiblockComponent.of(PylonKeys.POTION_PEDESTAL); + private static final MultiblockComponent LIT_ORANGE_CANDLE_COMPONENT = MultiblockComponent.of(Material.ORANGE_CANDLE.createBlockData("[lit=true]")); private final Sound START_SOUND = getSettings().getOrThrow("sound.start", ConfigAdapter.SOUND); private final Sound FINISH_SOUND = getSettings().getOrThrow("sound.finish", ConfigAdapter.SOUND); private final Sound CANCEL_SOUND = getSettings().getOrThrow("sound.cancel", ConfigAdapter.SOUND); @@ -110,7 +94,6 @@ public PotionAltar(Block block, BlockCreateContext context) { setTickInterval(tickInterval); setFacing(context.getFacing()); - setMultiblockDirection(getFacing()); addEntity("brewing_stand", new BlockDisplayBuilder() .transformation(new TransformBuilder() @@ -417,7 +400,10 @@ private Pedestal getCatalystPedestal() { @NotNull private List getBlockOffsets(@NotNull MultiblockComponent component) { - return validStructures().getFirst().entrySet().stream().filter(entry -> entry.getValue() == component).map(Map.Entry::getKey).toList(); + return RebarSimpleMultiblock.rotateComponentsToFace(getComponents(), getFacing()).entrySet().stream() + .filter(entry -> entry.getValue() == component) + .map(Map.Entry::getKey) + .toList(); } @NotNull diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java index 2f86b2888..46c8dbc33 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryController.java @@ -1,34 +1,6 @@ package io.github.pylonmc.pylon.content.machines.smelting; -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - import com.google.common.base.Preconditions; - -import net.kyori.adventure.text.Component; -import net.kyori.adventure.text.format.Style; - -import org.apache.commons.lang3.ArrayUtils; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.data.Directional; -import org.bukkit.damage.DamageSource; -import org.bukkit.damage.DamageType; -import org.bukkit.entity.*; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.persistence.PersistentDataContainer; -import org.bukkit.util.BoundingBox; -import org.bukkit.util.noise.SimplexOctaveGenerator; -import org.jetbrains.annotations.NotNull; -import org.joml.Vector3i; -import org.jspecify.annotations.NonNull; - -import java.util.*; -import java.util.concurrent.ThreadLocalRandom; -import java.util.stream.Collectors; - import io.github.pylonmc.pylon.PylonKeys; import io.github.pylonmc.pylon.recipes.SmelteryRecipe; import io.github.pylonmc.pylon.util.HslColor; @@ -60,6 +32,25 @@ import java.util.stream.Collectors; import kotlin.Pair; import lombok.Getter; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.Style; +import org.apache.commons.lang3.ArrayUtils; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.data.Directional; +import org.bukkit.damage.DamageSource; +import org.bukkit.damage.DamageType; +import org.bukkit.entity.*; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.BoundingBox; +import org.bukkit.util.noise.SimplexOctaveGenerator; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3i; +import org.jspecify.annotations.NonNull; import xyz.xenondevs.invui.Click; import xyz.xenondevs.invui.gui.Gui; import xyz.xenondevs.invui.item.AbstractItem; @@ -579,7 +570,7 @@ public void tick() { heaters = 0; updateFluidDisplay(); - BoundingBox box = BoundingBox.of(center.getLocation(), 2, 0, 2); + BoundingBox box = BoundingBox.of(center.toLocation(), 2, 0, 2); box.expand(BlockFace.UP, height); double damage = Math.max(0, temperature / 100 + 1); diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/BrickMold.java b/src/main/java/io/github/pylonmc/pylon/content/tools/BrickMold.java index cab223c10..89a1f4957 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/BrickMold.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/BrickMold.java @@ -8,8 +8,10 @@ import io.github.pylonmc.rebar.event.api.annotation.MultiHandler; import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.item.RebarItemSchema; import io.github.pylonmc.rebar.item.base.RebarBlockInteractor; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.List; import org.bukkit.Particle; import org.bukkit.event.Event; import org.bukkit.event.EventPriority; @@ -17,8 +19,6 @@ import org.bukkit.inventory.ItemStack; import org.jetbrains.annotations.NotNull; -import java.util.List; - public class BrickMold extends RebarItem implements RebarBlockInteractor { @@ -49,7 +49,12 @@ public void onUsedToClickBlock(@NotNull PlayerInteractEvent event, @NotNull Even ItemStack particleType; RebarBlock rebarBlock = BlockStorage.get(event.getClickedBlock()); if (rebarBlock != null) { - particleType = rebarBlock.getDefaultItem().getItemStack(); + RebarItemSchema defaultItem = rebarBlock.getDefaultItem(); + if (defaultItem != null) { + particleType = defaultItem.getOriginalTemplate(); + } else { + particleType = new ItemStack(event.getClickedBlock().getType()); + } } else { particleType = new ItemStack(event.getClickedBlock().getType()); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java b/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java index fd14f9938..0abccaa3c 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java +++ b/src/main/java/io/github/pylonmc/pylon/content/tools/Moldable.java @@ -11,7 +11,7 @@ public interface Moldable extends Keyed { boolean isMoldingFinished(); default ItemStack moldingInputStack() { - return RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItem(); + return RebarRegistry.ITEMS.getOrThrow(getKey()).createNewItemStack(); } default ItemStack moldingResult() { diff --git a/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java b/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java index 25ffe6bdb..d24e31deb 100644 --- a/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java +++ b/src/main/java/io/github/pylonmc/pylon/guide/HydraulicRefuelableItemsPage.java @@ -33,8 +33,8 @@ public HydraulicRefuelableItemsPage() { private static @NonNull List getButtons() { return RebarRegistry.ITEMS.stream() - .filter(item -> RebarItem.fromStack(item.createNewItem()) instanceof HydraulicRefuelable) - .map(item -> (Item) new ItemButton(item.createNewItem())) + .filter(item -> RebarItem.fromStack(item.createNewItemStack()) instanceof HydraulicRefuelable) + .map(item -> (Item) new ItemButton(item.createNewItemStack())) .toList(); } } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java index 80646926a..0b973c05e 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java @@ -12,6 +12,7 @@ import io.github.pylonmc.rebar.registry.RebarRegistry; import io.github.pylonmc.rebar.util.MiningLevel; import io.github.pylonmc.rebar.util.gui.GuiItems; +import java.util.ArrayList; import java.util.List; import net.kyori.adventure.text.Component; import org.bukkit.NamespacedKey; @@ -90,7 +91,7 @@ public record HammerRecipe( Hammer hammer = RebarItem.fromStack(itemSchema.getOriginalTemplate(), Hammer.class); if (hammer == null) continue; - ItemStack stack = itemSchema.createNewItem(); + ItemStack stack = itemSchema.createNewItemStack(); if (!hammer.miningLevel.isAtLeast(level)) { continue; } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java index a550d27a0..0882c7f53 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/SiloConverterRecipe.java @@ -55,7 +55,7 @@ public record SiloConverterRecipe( public @NotNull Gui display() { List silos = RebarRegistry.ITEMS.getValues() .stream() - .map(RebarItemSchema::createNewItem) + .map(RebarItemSchema::createNewItemStack) .filter(item -> RebarItem.fromStack(item) instanceof Silo.Item) .filter(item -> !item.isSimilar(result)) .toList(); From d764bbb8e82f9f80d4b472545a4f2301fe094209 Mon Sep 17 00:00:00 2001 From: Seggan Date: Tue, 12 May 2026 13:37:51 -0400 Subject: [PATCH 31/33] \*read in electroboom's voice* COMBINED CYCLE CLOSED COOLING DIESEL POWER PLANT --- .../io/github/pylonmc/pylon/PylonBlocks.java | 1 + .../io/github/pylonmc/pylon/PylonItems.java | 8 +- .../io/github/pylonmc/pylon/PylonRecipes.java | 32 ++++ .../pylon/content/components/FluidHatch.java | 20 ++- .../diesel/machines/DieselCoreDrill.java | 2 +- .../diesel/machines/PalladiumCondenser.java | 6 +- .../diesel/production/Biorefinery.java | 5 +- .../content/machines/electric/Boiler.java | 12 +- .../machines/electric/CombustionTower.java | 11 +- .../content/machines/electric/GasTurbine.java | 19 ++- .../machines/electric/HeatExchanger.java | 151 ++++++++++++++++++ .../hydraulics/BurnerHydraulicPurifier.java | 6 +- .../CoalFiredPurificationTower.java | 0 .../ConvectionHydraulicPurifier.java | 3 +- .../hydraulics/HydraulicCoreDrill.java | 4 +- .../LiseletteHydraulicPurifier.java | 3 +- .../pylon/recipes/HeatExchangerRecipe.java | 80 ++++++++++ .../recipes/pylon/heat_exchanger.yml | 21 +++ .../resources/settings/heat_exchanger.yml | 1 + 19 files changed, 352 insertions(+), 33 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java delete mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/CoalFiredPurificationTower.java create mode 100644 src/main/java/io/github/pylonmc/pylon/recipes/HeatExchangerRecipe.java create mode 100644 src/main/resources/recipes/pylon/heat_exchanger.yml create mode 100644 src/main/resources/settings/heat_exchanger.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 1cf9e8740..ee249a9d7 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -198,6 +198,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.STEAM_ENGINE, Material.IRON_BLOCK, SteamEngine.class); RebarBlock.register(PylonKeys.GAS_TURBINE, Material.IRON_BLOCK, GasTurbine.class); RebarBlock.register(PylonKeys.COMBUSTION_TOWER, Material.BRICKS, CombustionTower.class); + RebarBlock.register(PylonKeys.HEAT_EXCHANGER, Material.RED_NETHER_BRICK_WALL, HeatExchanger.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 3beb2111c..87eacfed8 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -49,7 +49,6 @@ import io.papermc.paper.datacomponent.item.consumable.ItemUseAnimation; import io.papermc.paper.registry.keys.SoundEventKeys; import io.papermc.paper.registry.keys.tags.DamageTypeTagKeys; -import java.util.Objects; import net.kyori.adventure.key.Key; import org.bukkit.*; import org.bukkit.attribute.Attribute; @@ -3333,6 +3332,13 @@ private PylonItems() { PylonPages.ELECTRICITY.addItem(COMBUSTION_TOWER); } + public static final ItemStack HEAT_EXCHANGER = ItemStackBuilder.rebar(Material.RED_NETHER_BRICK_WALL, PylonKeys.HEAT_EXCHANGER) + .build(); + static { + RebarItem.register(RebarItem.class, HEAT_EXCHANGER, PylonKeys.HEAT_EXCHANGER); + PylonPages.ELECTRICITY.addItem(HEAT_EXCHANGER); + } + public static final ItemStack ELECTRIC_GRINDSTONE = ItemStackBuilder.rebar(Material.SMOOTH_STONE, PylonKeys.ELECTRIC_GRINDSTONE) .build(); static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java index 625ca617a..537237bb2 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java @@ -47,6 +47,7 @@ public static void initialize() { HydraulicPurifier.RECIPE_TYPE.register(); FormingRecipe.RECIPE_TYPE.register(); GasTurbineRecipe.RECIPE_TYPE.register(); + HeatExchangerRecipe.RECIPE_TYPE.register(); //hardcoded initCollimator(); @@ -54,6 +55,7 @@ public static void initialize() { initBiorefinery(); initFermenter(); initBoiler(); + initCombustionTower(); } private static void initCollimator() { @@ -210,4 +212,34 @@ private static void initFermenter() { .build() ).register(); } + + private static void initCombustionTower() { + NamespacedKey key = PylonKeys.COMBUSTION_TOWER; + Config setting = Settings.get(key); + + double dieselUsage = setting.getOrThrow("diesel-usage", ConfigAdapter.DOUBLE); + double exhaustProduction = setting.getOrThrow("exhaust-production", ConfigAdapter.DOUBLE); + + RecipeInput.Fluid input = RecipeInput.of(PylonFluids.BIODIESEL, dieselUsage); + FluidWithAmount output = new FluidWithAmount(PylonFluids.VERY_HOT_EXHAUST, exhaustProduction); + + new SingleRecipe( + key, + input, + output.asFluidOrItem(), + () -> Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # # # # # # #", + "# d # # x # # e #", + "# # # # # # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('d', new FluidButton(input)) + .addIngredient('x', ItemButton.from(PylonItems.COMBUSTION_TOWER)) + .addIngredient('e', new FluidButton(output)) + .build() + ).register(); + } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java index 35acd4c59..d96f5d517 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/FluidHatch.java @@ -16,7 +16,6 @@ import io.github.pylonmc.rebar.entity.display.transform.TransformBuilder; import io.github.pylonmc.rebar.fluid.RebarFluid; import io.github.pylonmc.rebar.i18n.RebarArgument; -import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.RebarItemSchema; import io.github.pylonmc.rebar.registry.RebarRegistry; import io.github.pylonmc.rebar.util.RebarUtils; @@ -34,6 +33,7 @@ import org.bukkit.entity.ItemDisplay; import org.bukkit.entity.Player; import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3i; @@ -154,11 +154,19 @@ public double fluidAmountRequested(@NotNull RebarFluid fluid) { } } + /** + * Implementation of {@link RebarFluidBlock}. Use {@link #addFluid} instead. + */ + @ApiStatus.Internal @Override public void onFluidAdded(@NotNull RebarFluid fluid, double amount) { setFluid(fluid, fluidAmount + amount); } + /** + * Implementation of {@link RebarFluidBlock}. Use {@link #removeFluid} instead. + */ + @ApiStatus.Internal @Override public void onFluidRemoved(@NotNull RebarFluid fluid, double amount) { setFluid(fluid, fluidAmount - amount); @@ -168,8 +176,10 @@ public void addFluid(@NotNull RebarFluid fluid, double amount) { onFluidAdded(fluid, amount); } - public void removeFluid(@NotNull RebarFluid fluid, double amount) { - onFluidRemoved(fluid, amount); + public void removeFluid(double amount) { + if (fluid != null) { + onFluidRemoved(fluid, amount); + } } public void setFluid(@NotNull RebarFluid fluid, double amount) { @@ -241,6 +251,10 @@ public void setAllowedFluids(@NotNull Set fluids) { checkFormed(); } + public boolean canAcceptFluid(@NotNull RebarFluid fluid) { + return fluidAmount < capacity && ((this.fluid == null && allowedFluids.contains(fluid)) || Objects.equals(this.fluid, fluid)); + } + private void setCapacity(double capacity) { this.capacity = capacity; this.fluidAmount = Math.min(this.fluidAmount, capacity); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java index ea3cf286e..74d5744bb 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselCoreDrill.java @@ -117,7 +117,7 @@ public void tick() { return; } - fluidInputHatch.removeFluid(PylonFluids.BIODIESEL, dieselPerRotation); + fluidInputHatch.removeFluid(dieselPerRotation); new ParticleBuilder(Particle.CAMPFIRE_COSY_SMOKE) .location(getMultiblockBlock(SMOKESTACK_CAP).getLocation().toCenterLocation()) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java index 55a219dd8..794e47797 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/PalladiumCondenser.java @@ -186,8 +186,8 @@ public void tick() { return; } - biodieselInputHatch.removeFluid(PylonFluids.BIODIESEL, dieselPerSecond * getTickInterval() / 20); - hydraulicFluidInputHatch.removeFluid(PylonFluids.HYDRAULIC_FLUID, hydraulicFluidPerSecond * getTickInterval() / 20); + biodieselInputHatch.removeFluid(dieselPerSecond * getTickInterval() / 20); + hydraulicFluidInputHatch.removeFluid(hydraulicFluidPerSecond * getTickInterval() / 20); dirtyHydraulicFluidOutputHatch.addFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, hydraulicFluidPerSecond * getTickInterval() / 20); progressProcess(getTickInterval()); @@ -244,6 +244,8 @@ public void onMultiblockFormed() { .setAllowedFluids(PylonFluids.BIODIESEL); getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT_HATCH) .setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidOutputHatch.class, DIRTY_HYDRAULIC_FLUID_OUTPUT_HATCH) + .setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); } @Override diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java index 9dc61767c..9263f5c93 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/production/Biorefinery.java @@ -160,6 +160,7 @@ public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, ETHANOL_INPUT_HATCH).setAllowedFluids(PylonFluids.ETHANOL); getMultiblockComponentOrThrow(FluidInputHatch.class, PLANT_OIL_INPUT_HATCH).setAllowedFluids(PylonFluids.PLANT_OIL); + getMultiblockComponentOrThrow(FluidOutputHatch.class, BIODIESEL_OUTPUT_HATCH).setAllowedFluids(PylonFluids.BIODIESEL); } @Override @@ -187,8 +188,8 @@ public void tick() { ); if (biodieselToProduce > RebarUtils.FLUID_EPSILON) { - ethanolInputHatch.removeFluid(PylonFluids.ETHANOL, biodieselToProduce * ethanolPerMbOfBiodiesel); - plantOilInputHatch.removeFluid(PylonFluids.PLANT_OIL, biodieselToProduce * plantOilPerMbOfBiodiesel); + ethanolInputHatch.removeFluid(biodieselToProduce * ethanolPerMbOfBiodiesel); + plantOilInputHatch.removeFluid(biodieselToProduce * plantOilPerMbOfBiodiesel); biodieselOutputHatch.addFluid(PylonFluids.BIODIESEL, biodieselToProduce); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java index e30ec9acc..d61ecfc99 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java @@ -180,6 +180,7 @@ public void postInitialise() { public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH).setAllowedFluids(PylonFluids.WATER); + getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH).setAllowedFluids(PylonFluids.STEAM); } private void tryStartProcessing() { @@ -208,11 +209,12 @@ public void tick() { double waterConsumption = steamProduction * PylonFluids.WATER_TO_STEAM_RATIO; FluidInputHatch waterInput = getMultiblockComponentOrThrow(FluidInputHatch.class, WATER_INPUT_HATCH); FluidOutputHatch steamOutput = getMultiblockComponentOrThrow(FluidOutputHatch.class, STEAM_OUTPUT_HATCH); - double toRemove = Math.min(Math.min(waterInput.getFluidAmount(), waterConsumption), steamOutput.getFluidSpaceRemaining() * PylonFluids.WATER_TO_STEAM_RATIO); - if (toRemove > 0) { - waterInput.removeFluid(PylonFluids.WATER, toRemove); - steamOutput.addFluid(PylonFluids.STEAM, toRemove / PylonFluids.WATER_TO_STEAM_RATIO); - } + double ratio = Math.min(1, waterInput.getFluidAmount() / waterConsumption); + ratio = Math.min(ratio, steamOutput.getFluidSpaceRemaining() / steamProduction); + if (ratio <= 0) return; + + waterInput.removeFluid(waterConsumption * ratio); + steamOutput.addFluid(PylonFluids.STEAM, steamProduction * ratio); Particle.CAMPFIRE_SIGNAL_SMOKE.builder() .location(getBlock().getLocation().add(Vector.fromJOML(RebarUtils.rotateVectorToFace(SMOKESTACK_CAP, getFacing()))).toCenterLocation()) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java index 7cac95ebe..a76497d44 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java @@ -81,13 +81,12 @@ public CombustionTower(@NotNull Block block, @NotNull PersistentDataContainer pd public void tick() { if (!isFormedAndFullyLoaded()) return; - double dieselToConsume = Math.min(dieselUsage / getTicksPerSecond(), fluidAmount(PylonFluids.BIODIESEL)); - double exhaustToProduce = dieselToConsume * (exhaustProduction / dieselUsage); - double actualExhaustProduced = Math.min(exhaustToProduce, fluidSpaceRemaining(PylonFluids.VERY_HOT_EXHAUST)); - double actualDieselConsumed = actualExhaustProduced * (dieselUsage / exhaustProduction); + double ratio = Math.min(1, fluidAmount(PylonFluids.BIODIESEL) / dieselUsage); + ratio = Math.min(ratio, fluidSpaceRemaining(PylonFluids.VERY_HOT_EXHAUST) / exhaustProduction); + if (ratio <= 0) return; - removeFluid(PylonFluids.BIODIESEL, actualDieselConsumed); - addFluid(PylonFluids.VERY_HOT_EXHAUST, actualExhaustProduced); + removeFluid(PylonFluids.BIODIESEL, dieselUsage * ratio); + addFluid(PylonFluids.VERY_HOT_EXHAUST, exhaustProduction * ratio); Particle.CAMPFIRE_SIGNAL_SMOKE.builder() .location(getBlock().getLocation().add(Vector.fromJOML(SMOKESTACK_POS)).toCenterLocation()) diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java index b0204d51e..8a2db6883 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java @@ -76,18 +76,19 @@ public void tick() { FluidOutputHatch outputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); RebarFluid outputFluid = matchingRecipe.output().fluid(); - if (outputHatch.getFluid() != null && !outputHatch.getFluid().equals(outputFluid)) return; + if (!outputHatch.canAcceptFluid(outputFluid)) return; - double inputOutputRatio = matchingRecipe.input().amountMillibuckets() / matchingRecipe.output().amount(); + double recipeInputAmount = matchingRecipe.input().amountMillibuckets(); + double recipeOutputAmount = matchingRecipe.output().amount(); + double ratio = inputAmount / recipeInputAmount; + ratio = Math.min(ratio, outputHatch.getFluidSpaceRemaining() / recipeOutputAmount); + double actualInputAmount = ratio * recipeInputAmount; + double actualOutputAmount = ratio * recipeOutputAmount; - double outputAmount = inputAmount / inputOutputRatio; - double actualOutputAmount = Math.min(outputAmount, outputHatch.getFluidSpaceRemaining()); - double actualInputAmount = Math.min(inputAmount, outputAmount * inputOutputRatio); - - inputHatch.removeFluid(inputFluid, actualInputAmount); + inputHatch.removeFluid(actualInputAmount); outputHatch.addFluid(outputFluid, actualOutputAmount); - double powerOutput = matchingRecipe.powerProduction() * (actualInputAmount / matchingRecipe.input().amountMillibuckets()) * (20D / tickInterval); + double powerOutput = matchingRecipe.powerProduction() * ratio; electricityOutputHatch.setPower(powerOutput); Vector3f direction = getFacing().getOppositeFace().getDirection().toVector3f(); @@ -178,6 +179,8 @@ public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH) .setAllowedFluids(GasTurbineRecipe.RECIPE_TYPE.stream().flatMap(r -> r.input().fluids().stream()).collect(Collectors.toSet())); + getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH) + .setAllowedFluids(GasTurbineRecipe.RECIPE_TYPE.stream().map(r -> r.output().fluid()).collect(Collectors.toSet())); if (getHeldEntity("turbine_shaft") == null) { getBlock().setType(Material.STRUCTURE_VOID); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java new file mode 100644 index 000000000..fcb62bfed --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java @@ -0,0 +1,151 @@ +package io.github.pylonmc.pylon.content.machines.electric; + +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.content.components.FluidInputHatch; +import io.github.pylonmc.pylon.content.components.FluidOutputHatch; +import io.github.pylonmc.pylon.recipes.HeatExchangerRecipe; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.fluid.FluidWithAmount; +import io.github.pylonmc.rebar.fluid.RebarFluid; +import io.github.pylonmc.rebar.recipe.RecipeInput; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.bukkit.block.Block; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import org.joml.Vector3i; + +public class HeatExchanger extends RebarBlock implements + RebarSimpleMultiblock, + RebarTickingBlock { + + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + + @SuppressWarnings("unused") + public HeatExchanger(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + setTickInterval(tickInterval); + } + + @SuppressWarnings("unused") + public HeatExchanger(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void tick() { + if (!isFormedAndFullyLoaded()) return; + + FluidInputHatch inputHatch1 = getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH_1); + FluidInputHatch inputHatch2 = getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH_2); + FluidOutputHatch outputHatch1 = getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH_1); + FluidOutputHatch outputHatch2 = getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH_2); + FluidInputHatch fromInputHatch = null; + FluidOutputHatch fromOutputHatch = null; + FluidInputHatch toInputHatch = null; + FluidOutputHatch toOutputHatch = null; + HeatExchangerRecipe matchingRecipe = null; + for (HeatExchangerRecipe recipe : HeatExchangerRecipe.RECIPE_TYPE) { + if (recipe.transferFrom().getFirst().contains(inputHatch1.getFluid())) { + fromInputHatch = inputHatch1; + fromOutputHatch = outputHatch1; + toInputHatch = inputHatch2; + toOutputHatch = outputHatch2; + matchingRecipe = recipe; + break; + } else if (recipe.transferFrom().getFirst().contains(inputHatch2.getFluid())) { + fromInputHatch = inputHatch2; + fromOutputHatch = outputHatch2; + toInputHatch = inputHatch1; + toOutputHatch = outputHatch1; + matchingRecipe = recipe; + break; + } + } + + if (matchingRecipe == null) return; + + double recipeRatio = 1; + + FluidWithAmount fromOutput = matchingRecipe.transferFrom().getSecond(); + if (fromOutput != null) { + if (!fromOutputHatch.canAcceptFluid(fromOutput.fluid())) return; + double outputAmount = fromOutput.amount(); + double actualOutputAmount = Math.min(outputAmount, fromOutputHatch.getFluidSpaceRemaining()); + recipeRatio = Math.min(recipeRatio, actualOutputAmount / outputAmount); + } + FluidWithAmount toOutput = matchingRecipe.transferTo().getSecond(); + if (toOutput != null) { + if (!toOutputHatch.canAcceptFluid(toOutput.fluid())) return; + double outputAmount = toOutput.amount(); + double actualOutputAmount = Math.min(outputAmount, toOutputHatch.getFluidSpaceRemaining()); + recipeRatio = Math.min(recipeRatio, actualOutputAmount / outputAmount); + } + + RecipeInput.Fluid fromInput = matchingRecipe.transferFrom().getFirst(); + if (!fromInput.contains(fromInputHatch.getFluid())) return; + double fromInputAmount = fromInput.amountMillibuckets(); + double actualFromInputAmount = Math.min(fromInputAmount, fromInputHatch.getFluidAmount()); + recipeRatio = Math.min(recipeRatio, actualFromInputAmount / fromInputAmount); + + RecipeInput.Fluid toInput = matchingRecipe.transferTo().getFirst(); + if (!toInput.contains(toInputHatch.getFluid())) return; + double toInputAmount = toInput.amountMillibuckets(); + double actualToInputAmount = Math.min(toInputAmount, toInputHatch.getFluidAmount()); + recipeRatio = Math.min(recipeRatio, actualToInputAmount / toInputAmount); + + recipeRatio /= getTicksPerSecond(); // Convert from per-second to per-tick + + fromInputHatch.removeFluid(fromInputAmount * recipeRatio); + toInputHatch.removeFluid(toInputAmount * recipeRatio); + if (fromOutput != null) { + fromOutputHatch.addFluid(fromOutput.fluid(), fromOutput.amount() * recipeRatio); + } + if (toOutput != null) { + toOutputHatch.addFluid(toOutput.fluid(), toOutput.amount() * recipeRatio); + } + } + + private static final Vector3i INPUT_HATCH_1 = new Vector3i(1, 0, 0); + private static final Vector3i OUTPUT_HATCH_1 = new Vector3i(-1, 0, 0); + private static final Vector3i INPUT_HATCH_2 = new Vector3i(0, 0, -1); + private static final Vector3i OUTPUT_HATCH_2 = new Vector3i(0, 0, 1); + + @Override + public void onMultiblockFormed() { + RebarSimpleMultiblock.super.onMultiblockFormed(); + + Set allowedInputs = HeatExchangerRecipe.RECIPE_TYPE.stream() + .flatMap(recipe -> Stream.of(recipe.transferFrom().getFirst(), recipe.transferTo().getFirst())) + .flatMap(input -> input.fluids().stream()) + .collect(Collectors.toSet()); + getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH_1).setAllowedFluids(allowedInputs); + getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH_2).setAllowedFluids(allowedInputs); + + Set allowedOutputs = HeatExchangerRecipe.RECIPE_TYPE.stream() + .flatMap(recipe -> Stream.of(recipe.transferFrom().getSecond(), recipe.transferTo().getSecond())) + .filter(Objects::nonNull) + .map(FluidWithAmount::fluid) + .collect(Collectors.toSet()); + getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH_1).setAllowedFluids(allowedOutputs); + getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH_2).setAllowedFluids(allowedOutputs); + } + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + return Map.of( + INPUT_HATCH_1, MultiblockComponent.of(PylonKeys.FLUID_INPUT_HATCH), + OUTPUT_HATCH_1, MultiblockComponent.of(PylonKeys.FLUID_OUTPUT_HATCH), + INPUT_HATCH_2, MultiblockComponent.of(PylonKeys.FLUID_INPUT_HATCH), + OUTPUT_HATCH_2, MultiblockComponent.of(PylonKeys.FLUID_OUTPUT_HATCH) + ); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java index c9fb36799..b8b3c5fc6 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/BurnerHydraulicPurifier.java @@ -158,7 +158,7 @@ public void tick() { lightable.setLit(true); getBlock().setBlockData(lightable); - fluidInput.removeFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, fluidToPurify); + fluidInput.removeFluid(fluidToPurify); fluidOutput.addFluid(PylonFluids.HYDRAULIC_FLUID, fluidToPurify * purificationEfficiency); progressProcess(getTickInterval()); @@ -197,9 +197,11 @@ public void tryConsumeFuel() { @Override public void onMultiblockFormed() { + RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT) .setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); - RebarSimpleMultiblock.super.onMultiblockFormed(); + getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT) + .setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); } @Override diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/CoalFiredPurificationTower.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/CoalFiredPurificationTower.java deleted file mode 100644 index e69de29bb..000000000 diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java index 2fc7b3392..02214fdc1 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/ConvectionHydraulicPurifier.java @@ -198,13 +198,14 @@ public void tick() { .spawn(); } - hydraulicInput.removeFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, fluidToPurify); + hydraulicInput.removeFluid(fluidToPurify); hydraulicOutput.addFluid(PylonFluids.HYDRAULIC_FLUID, efficiency * fluidToPurify); } @Override public void onMultiblockFormed() { getMultiblockComponentOrThrow(FluidInputHatch.class, HYDRAULIC_FLUID_INPUT).setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidOutputHatch.class, HYDRAULIC_FLUID_OUTPUT).setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); Block light = getBlock().getRelative(BlockFace.UP); if (light.getType().isAir()) { light.setType(Material.LIGHT); diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java index eb6152942..1e98d3b4a 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/HydraulicCoreDrill.java @@ -111,7 +111,7 @@ public void tick() { return; } - inputHatch.removeFluid(PylonFluids.HYDRAULIC_FLUID, hydraulicFluidPerRotation); + inputHatch.removeFluid(hydraulicFluidPerRotation); outputHatch.addFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, hydraulicFluidPerRotation); if (!isProcessing()) { @@ -133,5 +133,7 @@ public void onMultiblockFormed() { super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, FLUID_INPUT_HATCH) .setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH) + .setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java index 5183b98bd..035a1327c 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/hydraulics/LiseletteHydraulicPurifier.java @@ -123,6 +123,7 @@ public LiseletteHydraulicPurifier(@NotNull Block block, @NotNull PersistentDataC public void onMultiblockFormed() { RebarSimpleMultiblock.super.onMultiblockFormed(); getMultiblockComponentOrThrow(FluidInputHatch.class, INPUT_HATCH).setAllowedFluids(PylonFluids.DIRTY_HYDRAULIC_FLUID); + getMultiblockComponentOrThrow(FluidOutputHatch.class, OUTPUT_HATCH).setAllowedFluids(PylonFluids.HYDRAULIC_FLUID); } @Override @@ -168,7 +169,7 @@ public void tick() { outputHatch.getFluidSpaceRemaining() / purificationEfficiency ) ); - inputHatch.removeFluid(PylonFluids.DIRTY_HYDRAULIC_FLUID, toPurify); + inputHatch.removeFluid(toPurify); outputHatch.addFluid(PylonFluids.HYDRAULIC_FLUID, toPurify * purificationEfficiency); }, 45); diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/HeatExchangerRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/HeatExchangerRecipe.java new file mode 100644 index 000000000..d7669168b --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/recipes/HeatExchangerRecipe.java @@ -0,0 +1,80 @@ +package io.github.pylonmc.pylon.recipes; + +import io.github.pylonmc.pylon.PylonItems; +import io.github.pylonmc.rebar.config.ConfigSection; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.fluid.FluidWithAmount; +import io.github.pylonmc.rebar.guide.button.FluidButton; +import io.github.pylonmc.rebar.guide.button.ItemButton; +import io.github.pylonmc.rebar.recipe.*; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import java.util.List; +import java.util.Objects; +import java.util.stream.Stream; +import kotlin.Pair; +import org.bukkit.NamespacedKey; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.jspecify.annotations.NonNull; +import xyz.xenondevs.invui.gui.Gui; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + +public record HeatExchangerRecipe( + @NotNull NamespacedKey key, + @NotNull Pair transferFrom, + @NotNull Pair transferTo +) implements RebarRecipe { + + public static final RecipeType RECIPE_TYPE = new ConfigurableRecipeType<>(pylonKey("heat_exchanger")) { + @Override + protected @NotNull HeatExchangerRecipe loadRecipe(@NotNull NamespacedKey key, @NotNull ConfigSection section) { + RecipeInput.Fluid transferFromInput = section.getOrThrow("from.input", ConfigAdapter.RECIPE_INPUT_FLUID); + FluidWithAmount transferFromOutput = section.get("from.output", ConfigAdapter.FLUID_WITH_AMOUNT); + RecipeInput.Fluid transferToInput = section.getOrThrow("to.input", ConfigAdapter.RECIPE_INPUT_FLUID); + FluidWithAmount transferToOutput = section.get("to.output", ConfigAdapter.FLUID_WITH_AMOUNT); + return new HeatExchangerRecipe( + key, + new Pair<>(transferFromInput, transferFromOutput), + new Pair<>(transferToInput, transferToOutput) + ); + } + }; + + @Override + public @NotNull List<@NotNull RecipeInput> getInputs() { + return List.of(transferFrom.getFirst(), transferTo.getFirst()); + } + + @Override + public @NotNull List<@NotNull FluidOrItem> getResults() { + return Stream.of(transferFrom.getSecond(), transferTo.getSecond()) + .filter(Objects::nonNull) + .map(FluidWithAmount::asFluidOrItem) + .toList(); + } + + @Override + public @NonNull Gui display() { + return Gui.builder() + .setStructure( + "# # # # # # # # #", + "# i # # # # # o #", + "# # # # x # # # #", + "# I # # # # # O #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('i', new FluidButton(transferFrom.getFirst())) + .addIngredient('o', transferFrom.getSecond() != null ? new FluidButton(transferFrom.getSecond()) : GuiItems.backgroundBlack()) + .addIngredient('I', new FluidButton(transferTo.getFirst())) + .addIngredient('O', transferTo.getSecond() != null ? new FluidButton(transferTo.getSecond()) : GuiItems.backgroundBlack()) + .addIngredient('x', ItemButton.from(PylonItems.HEAT_EXCHANGER)) + .build(); + } + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } +} diff --git a/src/main/resources/recipes/pylon/heat_exchanger.yml b/src/main/resources/recipes/pylon/heat_exchanger.yml new file mode 100644 index 000000000..9c18ab47a --- /dev/null +++ b/src/main/resources/recipes/pylon/heat_exchanger.yml @@ -0,0 +1,21 @@ +pylon:very_hot_exhaust: + from: + input: + pylon:very_hot_exhaust: 500 + output: + pylon:hot_exhaust: 50 + to: + input: + pylon:water: 50 + output: + pylon:steam: 500 + +pylon:hot_exhaust: + from: + input: + pylon:hot_exhaust: 500 + to: + input: + pylon:water: 50 + output: + pylon:steam: 500 \ No newline at end of file diff --git a/src/main/resources/settings/heat_exchanger.yml b/src/main/resources/settings/heat_exchanger.yml new file mode 100644 index 000000000..eadac4ca6 --- /dev/null +++ b/src/main/resources/settings/heat_exchanger.yml @@ -0,0 +1 @@ +tick-interval: 10 \ No newline at end of file From 35c140ed8d537619d9041535d719cb0ca1bfc0e0 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 13 May 2026 12:02:37 -0400 Subject: [PATCH 32/33] Move stuff around --- src/main/java/io/github/pylonmc/pylon/PylonBlocks.java | 7 ++++++- src/main/java/io/github/pylonmc/pylon/PylonItems.java | 7 ++++++- .../machines/{electric => electricity}/Capacitor.java | 2 +- .../{electric => electricity}/ElectricityInputHatch.java | 2 +- .../{electric => electricity}/ElectricityOutputHatch.java | 2 +- .../{electric => electricity}/ElectricityPylon.java | 2 +- .../machines/{electric => electricity}/Multimeter.java | 2 +- .../{electric => electricity/generation}/Boiler.java | 2 +- .../generation}/CombustionTower.java | 2 +- .../generation}/CreativePowerSource.java | 2 +- .../{electric => electricity/generation}/GasTurbine.java | 3 ++- .../generation}/HeatExchanger.java | 2 +- .../{electric => electricity/generation}/SteamEngine.java | 2 +- .../machines}/ElectricGrindstone.java | 2 +- 14 files changed, 25 insertions(+), 14 deletions(-) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity}/Capacitor.java (98%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity}/ElectricityInputHatch.java (92%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity}/ElectricityOutputHatch.java (92%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity}/ElectricityPylon.java (96%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity}/Multimeter.java (95%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/Boiler.java (99%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/CombustionTower.java (98%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/CreativePowerSource.java (97%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/GasTurbine.java (99%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/HeatExchanger.java (99%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/generation}/SteamEngine.java (98%) rename src/main/java/io/github/pylonmc/pylon/content/machines/{electric => electricity/machines}/ElectricGrindstone.java (96%) diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index ee249a9d7..72b6e4b2b 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -7,7 +7,12 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; -import io.github.pylonmc.pylon.content.machines.electric.*; +import io.github.pylonmc.pylon.content.machines.electricity.Capacitor; +import io.github.pylonmc.pylon.content.machines.electricity.ElectricityInputHatch; +import io.github.pylonmc.pylon.content.machines.electricity.ElectricityOutputHatch; +import io.github.pylonmc.pylon.content.machines.electricity.ElectricityPylon; +import io.github.pylonmc.pylon.content.machines.electricity.generation.*; +import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 87eacfed8..8e865c23b 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -16,7 +16,12 @@ import io.github.pylonmc.pylon.content.machines.diesel.machines.*; import io.github.pylonmc.pylon.content.machines.diesel.production.Biorefinery; import io.github.pylonmc.pylon.content.machines.diesel.production.Fermenter; -import io.github.pylonmc.pylon.content.machines.electric.*; +import io.github.pylonmc.pylon.content.machines.electricity.Capacitor; +import io.github.pylonmc.pylon.content.machines.electricity.Multimeter; +import io.github.pylonmc.pylon.content.machines.electricity.generation.Boiler; +import io.github.pylonmc.pylon.content.machines.electricity.generation.CombustionTower; +import io.github.pylonmc.pylon.content.machines.electricity.generation.SteamEngine; +import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Capacitor.java similarity index 98% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Capacitor.java index 78768f8ac..f129520f9 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Capacitor.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Capacitor.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarDirectionalBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityInputHatch.java similarity index 92% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityInputHatch.java index d8d0dc8a4..e07e9eedc 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityInputHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityInputHatch.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityOutputHatch.java similarity index 92% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityOutputHatch.java index ab3ed6025..dfdcf3e32 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityOutputHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityOutputHatch.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarElectricProducerBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityPylon.java similarity index 96% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityPylon.java index 6615aec89..515c3e1e6 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricityPylon.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/ElectricityPylon.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarElectricBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Multimeter.java similarity index 95% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Multimeter.java index 0342f93b3..14d769bff 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Multimeter.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/Multimeter.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity; import io.github.pylonmc.rebar.block.BlockStorage; import io.github.pylonmc.rebar.item.RebarItem; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/Boiler.java similarity index 99% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/Boiler.java index d61ecfc99..15739aad9 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/Boiler.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/Boiler.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.PylonFluids; import io.github.pylonmc.pylon.PylonKeys; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CombustionTower.java similarity index 98% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CombustionTower.java index a76497d44..95fe22016 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CombustionTower.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CombustionTower.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.PylonFluids; import io.github.pylonmc.pylon.PylonKeys; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CreativePowerSource.java similarity index 97% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CreativePowerSource.java index b0c7a1b05..a70afa57f 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/CreativePowerSource.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/CreativePowerSource.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.util.NumberInputButton; import io.github.pylonmc.rebar.block.RebarBlock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java similarity index 99% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java index 8a2db6883..9085d0faf 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java @@ -1,9 +1,10 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.Pylon; import io.github.pylonmc.pylon.PylonKeys; import io.github.pylonmc.pylon.content.components.FluidInputHatch; import io.github.pylonmc.pylon.content.components.FluidOutputHatch; +import io.github.pylonmc.pylon.content.machines.electricity.ElectricityOutputHatch; import io.github.pylonmc.pylon.recipes.GasTurbineRecipe; import io.github.pylonmc.rebar.block.RebarBlock; import io.github.pylonmc.rebar.block.base.RebarSimpleMultiblock; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/HeatExchanger.java similarity index 99% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/HeatExchanger.java index fcb62bfed..bfee90702 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/HeatExchanger.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/HeatExchanger.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.PylonKeys; import io.github.pylonmc.pylon.content.components.FluidInputHatch; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java similarity index 98% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java index bd4d165d0..149ed18a8 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/SteamEngine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.generation; import io.github.pylonmc.pylon.PylonFluids; import io.github.pylonmc.pylon.PylonKeys; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java similarity index 96% rename from src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java rename to src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java index 1504f3f11..f63246760 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electric/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java @@ -1,4 +1,4 @@ -package io.github.pylonmc.pylon.content.machines.electric; +package io.github.pylonmc.pylon.content.machines.electricity.machines; import io.github.pylonmc.pylon.content.machines.generic.AbstractGrindstone; import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; From 5b70012730caf1cd264b479e20cec7524248ba89 Mon Sep 17 00:00:00 2001 From: Seggan Date: Wed, 13 May 2026 13:32:15 -0400 Subject: [PATCH 33/33] Electric brick molder & fix a few issues --- .../io/github/pylonmc/pylon/PylonBlocks.java | 2 + .../io/github/pylonmc/pylon/PylonItems.java | 8 ++ .../io/github/pylonmc/pylon/PylonKeys.java | 1 + .../diesel/machines/DieselBrickMolder.java | 115 ++-------------- .../electricity/generation/GasTurbine.java | 2 +- .../electricity/generation/SteamEngine.java | 4 +- .../machines/ElectricBrickMolder.java | 60 +++++++++ .../machines/ElectricGrindstone.java | 7 +- .../machines/generic/AbstractBrickMolder.java | 123 ++++++++++++++++++ .../pylon/recipes/GasTurbineRecipe.java | 6 +- src/main/resources/lang/en.yml | 11 +- .../settings/electric_brick_molder.yml | 3 + 12 files changed, 233 insertions(+), 109 deletions(-) create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricBrickMolder.java create mode 100644 src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractBrickMolder.java create mode 100644 src/main/resources/settings/electric_brick_molder.yml diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 72b6e4b2b..a95119bd4 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -12,6 +12,7 @@ import io.github.pylonmc.pylon.content.machines.electricity.ElectricityOutputHatch; import io.github.pylonmc.pylon.content.machines.electricity.ElectricityPylon; import io.github.pylonmc.pylon.content.machines.electricity.generation.*; +import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricBrickMolder; import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; @@ -205,5 +206,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.COMBUSTION_TOWER, Material.BRICKS, CombustionTower.class); RebarBlock.register(PylonKeys.HEAT_EXCHANGER, Material.RED_NETHER_BRICK_WALL, HeatExchanger.class); RebarBlock.register(PylonKeys.ELECTRIC_GRINDSTONE, Material.SMOOTH_STONE, ElectricGrindstone.class); + RebarBlock.register(PylonKeys.ELECTRIC_BRICK_MOLDER, Material.IRON_BLOCK, ElectricBrickMolder.class); } } diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 8e865c23b..caf55ec24 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -21,6 +21,7 @@ import io.github.pylonmc.pylon.content.machines.electricity.generation.Boiler; import io.github.pylonmc.pylon.content.machines.electricity.generation.CombustionTower; import io.github.pylonmc.pylon.content.machines.electricity.generation.SteamEngine; +import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricBrickMolder; import io.github.pylonmc.pylon.content.machines.electricity.machines.ElectricGrindstone; import io.github.pylonmc.pylon.content.machines.fluid.*; import io.github.pylonmc.pylon.content.machines.hydraulics.*; @@ -3352,6 +3353,13 @@ private PylonItems() { RebarGuide.getOrCreateInfoPage(PylonKeys.ELECTRIC_GRINDSTONE) .addButton(new MachineRecipesButton(ELECTRIC_GRINDSTONE, GrindstoneRecipe.RECIPE_TYPE)); } + + public static final ItemStack ELECTRIC_BRICK_MOLDER = ItemStackBuilder.rebar(Material.IRON_BLOCK, PylonKeys.ELECTRIC_BRICK_MOLDER) + .build(); + static { + RebarItem.register(ElectricBrickMolder.Item.class, ELECTRIC_BRICK_MOLDER, PylonKeys.ELECTRIC_BRICK_MOLDER); + PylonPages.ELECTRICITY.addItem(ELECTRIC_BRICK_MOLDER); + } // static { diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 9b55e4c01..692229c0d 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -487,4 +487,5 @@ public class PylonKeys { public static final NamespacedKey COMBUSTION_TOWER = pylonKey("combustion_tower"); public static final NamespacedKey HEAT_EXCHANGER = pylonKey("heat_exchanger"); public static final NamespacedKey ELECTRIC_GRINDSTONE = pylonKey("electric_grindstone"); + public static final NamespacedKey ELECTRIC_BRICK_MOLDER = pylonKey("electric_brick_molder"); } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselBrickMolder.java b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselBrickMolder.java index 1ec69244c..ac9785145 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselBrickMolder.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/diesel/machines/DieselBrickMolder.java @@ -2,10 +2,10 @@ import com.destroystokyo.paper.ParticleBuilder; import io.github.pylonmc.pylon.PylonFluids; +import io.github.pylonmc.pylon.content.machines.generic.AbstractBrickMolder; import io.github.pylonmc.pylon.recipes.MoldingRecipe; import io.github.pylonmc.pylon.util.PylonUtils; -import io.github.pylonmc.rebar.block.RebarBlock; -import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.base.RebarFluidBufferBlock; import io.github.pylonmc.rebar.block.context.BlockBreakContext; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; @@ -15,13 +15,10 @@ import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.RebarItem; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; -import io.github.pylonmc.rebar.logistics.LogisticGroupType; -import io.github.pylonmc.rebar.util.MachineUpdateReason; import io.github.pylonmc.rebar.util.RebarUtils; -import io.github.pylonmc.rebar.util.gui.GuiItems; -import io.github.pylonmc.rebar.util.gui.ProgressItem; import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; import io.github.pylonmc.rebar.waila.WailaDisplay; +import java.util.List; import net.kyori.adventure.text.format.TextColor; import org.bukkit.Material; import org.bukkit.Particle; @@ -35,29 +32,12 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.joml.Vector3d; -import xyz.xenondevs.invui.gui.Gui; -import xyz.xenondevs.invui.inventory.VirtualInventory; - -import java.util.List; -import java.util.Map; -public class DieselBrickMolder extends RebarBlock implements - RebarGuiBlock, - RebarVirtualInventoryBlock, - RebarFluidBufferBlock, - RebarDirectionalBlock, - RebarTickingBlock, - RebarLogisticBlock, - RebarRecipeProcessor { +public class DieselBrickMolder extends AbstractBrickMolder implements RebarFluidBufferBlock { public final double dieselBuffer = getSettings().getOrThrow("diesel-buffer", ConfigAdapter.DOUBLE); public final double dieselPerSecond = getSettings().getOrThrow("diesel-per-second", ConfigAdapter.DOUBLE); - public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); - public final int ticksPerMoldingCycle = getSettings().getOrThrow("ticks-per-molding-cycle", ConfigAdapter.INTEGER); - - private final VirtualInventory inputInventory = new VirtualInventory(1); - private final VirtualInventory outputInventory = new VirtualInventory(1); public static class Item extends RebarItem { @@ -92,9 +72,7 @@ public Item(@NotNull ItemStack stack) { @SuppressWarnings("unused") public DieselBrickMolder(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); - setTickInterval(tickInterval); createFluidPoint(FluidPointType.INPUT, BlockFace.NORTH, context, false, 0.55F); - setFacing(context.getFacing()); addEntity("chimney", new ItemDisplayBuilder() .itemStack(chimneyStack) .transformation(new TransformBuilder() @@ -131,8 +109,6 @@ public DieselBrickMolder(@NotNull Block block, @NotNull BlockCreateContext conte .build(block.getLocation().toCenterLocation().add(0, 0.5, 0)) ); createFluidBuffer(PylonFluids.BIODIESEL, dieselBuffer, true, false); - setRecipeType(MoldingRecipe.RECIPE_TYPE); - setRecipeProgressItem(new ProgressItem(GuiItems.background())); } @SuppressWarnings("unused") @@ -140,19 +116,6 @@ public DieselBrickMolder(@NotNull Block block, @NotNull PersistentDataContainer super(block, pdc); } - @Override - public void postInitialise() { - createLogisticGroup("input", LogisticGroupType.INPUT, inputInventory); - createLogisticGroup("output", LogisticGroupType.OUTPUT, outputInventory); - outputInventory.addPreUpdateHandler(RebarUtils.DISALLOW_PLAYERS_FROM_ADDING_ITEMS_HANDLER); - outputInventory.addPostUpdateHandler(event -> tryStartRecipe()); - inputInventory.addPostUpdateHandler(event -> { - if (!(event.getUpdateReason() instanceof MachineUpdateReason)) { - tryStartRecipe(); - } - }); - } - @Override public void tick() { if (!isProcessingRecipe() || fluidAmount(PylonFluids.BIODIESEL) < dieselPerSecond * tickInterval / 20) { @@ -178,61 +141,13 @@ public void tick() { .spawn(); } - public void tryStartRecipe() { - if (isProcessingRecipe()) { - return; - } - - ItemStack stack = inputInventory.getItem(0); - if (stack == null || stack.isEmpty()) { - return; - } - - if (getLastRecipe() != null && tryStartRecipe(getLastRecipe(), stack)) { - return; - } - - for (MoldingRecipe recipe : MoldingRecipe.RECIPE_TYPE) { - if (tryStartRecipe(recipe, stack)) { - break; - } - } - } - - private boolean tryStartRecipe(MoldingRecipe recipe, ItemStack stack) { - if (!recipe.input().isSimilar(stack) || !outputInventory.canHold(recipe.result())) { - return false; - } - - startRecipe(recipe, recipe.moldingCycles() * tickInterval * ticksPerMoldingCycle); - getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); - getHeldEntityOrThrow(ItemDisplay.class, "item").setItemStack(stack); - inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); - return true; - } - - @Override - public void onRecipeFinished(@NotNull MoldingRecipe recipe) { - getRecipeProgressItem().setItem(GuiItems.background()); - getHeldEntityOrThrow(ItemDisplay.class, "item").setItemStack(null); - outputInventory.addItem(new MachineUpdateReason(), recipe.result().clone()); - } - @Override - public @NotNull Gui createGui() { - return Gui.builder() - .setStructure( - "# # I # # # O # #", - "# # i # p # o # #", - "# # I # # # O # #" - ) - .addIngredient('#', GuiItems.background()) - .addIngredient('I', GuiItems.input()) - .addIngredient('i', inputInventory) - .addIngredient('p', getRecipeProgressItem()) - .addIngredient('O', GuiItems.output()) - .addIngredient('o', outputInventory) - .build(); + protected boolean tryStartRecipe(MoldingRecipe recipe, ItemStack stack) { + boolean result = super.tryStartRecipe(recipe, stack); + if (result) { + getHeldEntityOrThrow(ItemDisplay.class, "item").setItemStack(stack); + } + return result; } @Override @@ -249,15 +164,13 @@ public void onRecipeFinished(@NotNull MoldingRecipe recipe) { @Override public void onBreak(@NotNull List<@NotNull ItemStack> drops, @NotNull BlockBreakContext context) { - RebarVirtualInventoryBlock.super.onBreak(drops, context); + super.onBreak(drops, context); RebarFluidBufferBlock.super.onBreak(drops, context); } @Override - public @NotNull Map getVirtualInventories() { - return Map.of( - "input", inputInventory, - "output", outputInventory - ); + public void onRecipeFinished(@NotNull MoldingRecipe recipe) { + super.onRecipeFinished(recipe); + getHeldEntityOrThrow(ItemDisplay.class, "item").setItemStack(null); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java index 9085d0faf..9eb94f268 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/GasTurbine.java @@ -133,7 +133,7 @@ public void tick() { @Override public @Nullable WailaDisplay getWaila(@NotNull Player player) { return new WailaDisplay(getDefaultWailaTranslationKey().arguments( - RebarArgument.of("power", UnitFormat.WATTS.format(getMultiblockComponentOrThrow(ElectricityOutputHatch.class, ELECTRICITY_OUTPUT_HATCH).getPower())) + RebarArgument.of("power", UnitFormat.WATTS.format(getMultiblockComponentOrThrow(ElectricityOutputHatch.class, ELECTRICITY_OUTPUT_HATCH).getPower()).decimalPlaces(1)) )); } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java index 149ed18a8..6e9423d62 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/generation/SteamEngine.java @@ -37,14 +37,12 @@ public class SteamEngine extends RebarBlock implements private final double steamUsage = getSettings().getOrThrow("steam-usage", ConfigAdapter.DOUBLE); private final double steamCapacity = getSettings().getOrThrow("steam-capacity", ConfigAdapter.DOUBLE); private final double powerProduction = getSettings().getOrThrow("power-production", ConfigAdapter.DOUBLE); - private final double outputVoltage = getSettings().getOrThrow("output-voltage", ConfigAdapter.DOUBLE); public static final class Item extends RebarItem { private final double steamUsage = getSettings().getOrThrow("steam-usage", ConfigAdapter.DOUBLE); private final double steamCapacity = getSettings().getOrThrow("steam-capacity", ConfigAdapter.DOUBLE); private final double powerProduction = getSettings().getOrThrow("power-production", ConfigAdapter.DOUBLE); - private final double outputVoltage = getSettings().getOrThrow("output-voltage", ConfigAdapter.DOUBLE); public Item(@NotNull ItemStack stack) { super(stack); @@ -114,7 +112,7 @@ public void tick() { 20, TextColor.fromHexString("#d8d8d8") )), - RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower())) + RebarArgument.of("power", UnitFormat.WATTS.format(node.getPower()).decimalPlaces(1)) )); } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricBrickMolder.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricBrickMolder.java new file mode 100644 index 000000000..154421573 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricBrickMolder.java @@ -0,0 +1,60 @@ +package io.github.pylonmc.pylon.content.machines.electricity.machines; + +import io.github.pylonmc.pylon.content.machines.generic.AbstractBrickMolder; +import io.github.pylonmc.rebar.block.base.RebarElectricConsumerBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.RebarItem; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import java.util.List; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; + +public class ElectricBrickMolder extends AbstractBrickMolder implements RebarElectricConsumerBlock { + + private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + + public static class Item extends RebarItem { + + private final double powerUsage = getSettings().getOrThrow("power-usage", ConfigAdapter.DOUBLE); + private final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + private final int ticksPerMoldingCycle = getSettings().getOrThrow("ticks-per-molding-cycle", ConfigAdapter.INTEGER); + + public Item(@NotNull ItemStack stack) { + super(stack); + } + + @Override + public @NotNull List<@NotNull RebarArgument> getPlaceholders() { + return List.of( + RebarArgument.of("molding-cycles", UnitFormat.CYCLES_PER_SECOND.format(20 / (ticksPerMoldingCycle * tickInterval))), + RebarArgument.of("power-usage", UnitFormat.WATTS.format(powerUsage)) + ); + } + } + + @SuppressWarnings("unused") + public ElectricBrickMolder(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + } + + @SuppressWarnings("unused") + public ElectricBrickMolder(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + @Override + public void postInitialise() { + super.postInitialise(); + setRequiredPower(powerUsage); + } + + @Override + public void tick() { + if (!isProcessingRecipe() || !isPowered()) return; + progressRecipe(tickInterval); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java index f63246760..d7672b80a 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/electricity/machines/ElectricGrindstone.java @@ -36,7 +36,6 @@ public Item(@NotNull ItemStack stack) { public ElectricGrindstone(@NotNull Block block, @NotNull BlockCreateContext context) { super(block, context); setFacing(context.getFacing()); - setRequiredPower(powerUsage); } @SuppressWarnings("unused") @@ -44,6 +43,12 @@ public ElectricGrindstone(@NotNull Block block, @NotNull PersistentDataContainer super(block, pdc); } + @Override + public void postInitialise() { + super.postInitialise(); + setRequiredPower(powerUsage); + } + @Override public void tick() { if (!isProcessingRecipe() || !isPowered()) return; diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractBrickMolder.java b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractBrickMolder.java new file mode 100644 index 000000000..3f6059fc7 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/generic/AbstractBrickMolder.java @@ -0,0 +1,123 @@ +package io.github.pylonmc.pylon.content.machines.generic; + +import io.github.pylonmc.pylon.recipes.MoldingRecipe; +import io.github.pylonmc.rebar.block.RebarBlock; +import io.github.pylonmc.rebar.block.base.*; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.logistics.LogisticGroupType; +import io.github.pylonmc.rebar.util.MachineUpdateReason; +import io.github.pylonmc.rebar.util.RebarUtils; +import io.github.pylonmc.rebar.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.ProgressItem; +import java.util.Map; +import org.bukkit.block.Block; +import org.bukkit.inventory.ItemStack; +import org.bukkit.persistence.PersistentDataContainer; +import org.jetbrains.annotations.NotNull; +import xyz.xenondevs.invui.gui.Gui; +import xyz.xenondevs.invui.inventory.VirtualInventory; + +public abstract class AbstractBrickMolder extends RebarBlock implements + RebarGuiBlock, + RebarVirtualInventoryBlock, + RebarDirectionalBlock, + RebarTickingBlock, + RebarLogisticBlock, + RebarRecipeProcessor { + + public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + public final int ticksPerMoldingCycle = getSettings().getOrThrow("ticks-per-molding-cycle", ConfigAdapter.INTEGER); + + public AbstractBrickMolder(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + setTickInterval(tickInterval); + setRecipeType(MoldingRecipe.RECIPE_TYPE); + setRecipeProgressItem(new ProgressItem(GuiItems.background())); + } + + public AbstractBrickMolder(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + } + + private final VirtualInventory inputInventory = new VirtualInventory(1); + private final VirtualInventory outputInventory = new VirtualInventory(1); + + @Override + public @NotNull Map getVirtualInventories() { + return Map.of( + "input", inputInventory, + "output", outputInventory + ); + } + + @Override + public void postInitialise() { + createLogisticGroup("input", LogisticGroupType.INPUT, inputInventory); + createLogisticGroup("output", LogisticGroupType.OUTPUT, outputInventory); + outputInventory.addPreUpdateHandler(RebarUtils.DISALLOW_PLAYERS_FROM_ADDING_ITEMS_HANDLER); + outputInventory.addPostUpdateHandler(event -> tryStartRecipe()); + inputInventory.addPostUpdateHandler(event -> { + if (!(event.getUpdateReason() instanceof MachineUpdateReason)) { + tryStartRecipe(); + } + }); + } + + public void tryStartRecipe() { + if (isProcessingRecipe()) { + return; + } + + ItemStack stack = inputInventory.getItem(0); + if (stack == null || stack.isEmpty()) { + return; + } + + if (getLastRecipe() != null && tryStartRecipe(getLastRecipe(), stack)) { + return; + } + + for (MoldingRecipe recipe : MoldingRecipe.RECIPE_TYPE) { + if (tryStartRecipe(recipe, stack)) { + break; + } + } + } + + protected boolean tryStartRecipe(MoldingRecipe recipe, ItemStack stack) { + if (!recipe.input().isSimilar(stack) || !outputInventory.canHold(recipe.result())) { + return false; + } + + startRecipe(recipe, recipe.moldingCycles() * tickInterval * ticksPerMoldingCycle); + getRecipeProgressItem().setItem(ItemStackBuilder.of(stack.asOne()).clearLore()); + inputInventory.setItem(new MachineUpdateReason(), 0, stack.subtract(recipe.input().getAmount())); + return true; + } + + @Override + public void onRecipeFinished(@NotNull MoldingRecipe recipe) { + getRecipeProgressItem().setItem(GuiItems.background()); + outputInventory.addItem(new MachineUpdateReason(), recipe.result().clone()); + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure( + "# # I # # # O # #", + "# # i # p # o # #", + "# # I # # # O # #" + ) + .addIngredient('#', GuiItems.background()) + .addIngredient('I', GuiItems.input()) + .addIngredient('i', inputInventory) + .addIngredient('p', getRecipeProgressItem()) + .addIngredient('O', GuiItems.output()) + .addIngredient('o', outputInventory) + .build(); + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java index 9d6e43077..fafd309bd 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/GasTurbineRecipe.java @@ -6,6 +6,7 @@ import io.github.pylonmc.rebar.fluid.FluidWithAmount; import io.github.pylonmc.rebar.guide.button.FluidButton; import io.github.pylonmc.rebar.guide.button.ItemButton; +import io.github.pylonmc.rebar.i18n.RebarArgument; import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; import io.github.pylonmc.rebar.recipe.*; import io.github.pylonmc.rebar.util.gui.GuiItems; @@ -63,7 +64,10 @@ public record GasTurbineRecipe( .addIngredient('x', ItemButton.from(ItemStackBuilder.of(PylonItems.GAS_TURBINE.clone()) .lore( Component.empty(), - Component.translatable("pylon.gui.watts-per-mb", UnitFormat.WATTS_PER_MILLIBUCKET.format(powerProduction / input.amountMillibuckets()).decimalPlaces(1)) + Component.translatable( + "pylon.gui.watts-per-mb", + RebarArgument.of("power", UnitFormat.WATTS_PER_MILLIBUCKET.format(powerProduction / input.amountMillibuckets()).decimalPlaces(1)) + ) ) .build())) .addIngredient('o', new FluidButton(output)) diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 8bb8fb661..7eee89f44 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -1662,7 +1662,7 @@ item: diesel_grindstone: name: "Diesel Grindstone" lore: |- - Grinds items + Grinds items using diesel Diesel usage: %diesel-usage% Diesel buffer: %diesel-buffer% waila: "Diesel Grindstone | %diesel-bar%" @@ -1670,7 +1670,7 @@ item: diesel_brick_molder: name: "Diesel Brick Molder" lore: |- - Molds materials into bricks + Molds materials into bricks using diesel Diesel usage: %diesel-usage% Diesel buffer: %diesel-buffer% Molding cycles: %molding-cycles% @@ -2528,6 +2528,13 @@ item: Grinds items using electricity Power usage: %power-usage% + electric_brick_molder: + name: "Electric Brick Molder" + lore: |- + Molds materials into bricks using electricity + Power usage: %power-usage% + Molding cycles: %molding-cycles% + boiler_casing: name: "Boiler Casing" diff --git a/src/main/resources/settings/electric_brick_molder.yml b/src/main/resources/settings/electric_brick_molder.yml new file mode 100644 index 000000000..4f61777c7 --- /dev/null +++ b/src/main/resources/settings/electric_brick_molder.yml @@ -0,0 +1,3 @@ +power-usage: 10 +tick-interval: 10 +ticks-per-molding-cycle: 2 # Machine ticks, not server ticks \ No newline at end of file