diff --git a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java index 06175390d..34164d942 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonBlocks.java @@ -49,6 +49,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_TIN, Material.GREEN_STAINED_GLASS, PortableFluidTank.class); RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_IRON, Material.LIGHT_GRAY_STAINED_GLASS, PortableFluidTank.class); RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_BRONZE, Material.ORANGE_STAINED_GLASS, PortableFluidTank.class); + RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_OBSIDIAN, Material.BLACK_STAINED_GLASS, PortableFluidTank.class); RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_IGNEOUS_COMPOSITE, Material.BLACK_STAINED_GLASS, PortableFluidTank.class); RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_STEEL, Material.GRAY_STAINED_GLASS, PortableFluidTank.class); RebarBlock.register(PylonKeys.PORTABLE_FLUID_TANK_PALLADIUM, Material.BLUE_STAINED_GLASS, PortableFluidTank.class); @@ -58,6 +59,7 @@ public static void initialize() { RebarBlock.register(PylonKeys.FLUID_TANK_CASING_TIN, Material.GREEN_STAINED_GLASS, FluidTankCasing.class); RebarBlock.register(PylonKeys.FLUID_TANK_CASING_IRON, Material.LIGHT_GRAY_STAINED_GLASS, FluidTankCasing.class); RebarBlock.register(PylonKeys.FLUID_TANK_CASING_BRONZE, Material.ORANGE_STAINED_GLASS, FluidTankCasing.class); + RebarBlock.register(PylonKeys.FLUID_TANK_CASING_OBSIDIAN, Material.BLACK_STAINED_GLASS, FluidTankCasing.class); RebarBlock.register(PylonKeys.FLUID_TANK_CASING_IGNEOUS_COMPOSITE, Material.BLACK_STAINED_GLASS, FluidTankCasing.class); RebarBlock.register(PylonKeys.FLUID_TANK_CASING_STEEL, Material.GRAY_STAINED_GLASS, FluidTankCasing.class); RebarBlock.register(PylonKeys.FLUID_TANK_CASING_PALLADIUM, Material.BLUE_STAINED_GLASS, FluidTankCasing.class); @@ -91,7 +93,6 @@ public static void initialize() { RebarBlock.register(PylonKeys.DIESEL_SMELTERY_HEATER, Material.FURNACE, DieselSmelteryHeater.class); RebarBlock.register(PylonKeys.CASTING_UNIT, Material.BRICKS, CastingUnit.class); RebarBlock.register(PylonKeys.FORMING_TABLE, Material.CRAFTING_TABLE, FormingTable.class); - RebarBlock.register(PylonKeys.PIT_KILN, Material.DECORATED_POT, PitKiln.class); RebarBlock.register(PylonKeys.FLUID_STRAINER, Material.COPPER_GRATE, FluidStrainer.class); RebarBlock.register(PylonKeys.EXPLOSIVE_TARGET, Material.TARGET, ExplosiveTarget.class); RebarBlock.register(PylonKeys.EXPLOSIVE_TARGET_FIERY, Material.TARGET, ExplosiveTarget.class); @@ -178,6 +179,8 @@ public static void initialize() { RebarBlock.register(PylonKeys.POTION_ALTAR, Material.STONE_BRICK_SLAB, PotionAltar.class); RebarBlock.register(PylonKeys.COLLIMATOR, Material.OBSIDIAN, Collimator.class); RebarBlock.register(PylonKeys.COLLIMATOR_PILLAR, Material.DEEPSLATE_TILE_WALL, CollimatorPillar.class); + RebarBlock.register(PylonKeys.CRUDE_ALLOY_FURNACE, Material.BLAST_FURNACE, CrudeAlloyFurnace.class); + RebarBlock.register(PylonKeys.KILN, Material.BLAST_FURNACE, Kiln.class); RebarBlock.register(PylonKeys.WOODEN_SILO, Material.BROWN_TERRACOTTA, Silo.class); RebarBlock.register(PylonKeys.COPPER_SILO, Material.TERRACOTTA, Silo.class); RebarBlock.register(PylonKeys.TIN_SILO, Material.GREEN_TERRACOTTA, Silo.class); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonHelpPages.java b/src/main/java/io/github/pylonmc/pylon/PylonHelpPages.java index e059ab62f..54ae75645 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonHelpPages.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonHelpPages.java @@ -15,7 +15,6 @@ public class PylonHelpPages { public static final SimpleStaticGuidePage HELP = new SimpleStaticGuidePage(pylonKey("help")); public static final SimpleStaticGuidePage PROGRESSION = new SimpleStaticGuidePage(pylonKey("help_progression")); - public static final SimpleStaticGuidePage PIT_KILN = new SimpleStaticGuidePage(pylonKey("help_pit_kiln")); public static final SimpleStaticGuidePage FLUID_HANDLING = new SimpleStaticGuidePage(pylonKey("help_fluid_handling")); public static final SimpleStaticGuidePage HYDRAULICS = new SimpleStaticGuidePage(pylonKey("help_hydraulics")); public static final SimpleStaticGuidePage BLOOMERY = new SimpleStaticGuidePage(pylonKey("help_bloomery")); @@ -29,7 +28,6 @@ public static void initialise() { PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.IRON_PICKAXE, Pylon.getInstance(), "help.progression.manual_core"))); PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.CLOCK, Pylon.getInstance(), "help.loupe"))); // recycle loupe desc - PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.BRICKS, Pylon.getInstance(), "help.progression.pit_kiln"))); PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.BRICK, Pylon.getInstance(), "help.progression.bronze_age"))); PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.WATER_BUCKET, Pylon.getInstance(), "help.progression.hydraulic_machines"))); PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.MINECART, Pylon.getInstance(), "help.progression.cargo_machines"))); @@ -40,11 +38,6 @@ public static void initialise() { PROGRESSION.addButton(Item.simple(ItemStackBuilder.guide(Material.ELYTRA, Pylon.getInstance(), "help.progression.flight_ring"))); HELP.addPage(Material.BOOKSHELF, PROGRESSION); - PIT_KILN.addButton(Item.simple(ItemStackBuilder.guide(Material.DECORATED_POT, Pylon.getInstance(), "help.pit_kiln.kiln"))); - PIT_KILN.addButton(Item.simple(ItemStackBuilder.guide(Material.DECORATED_POT, Pylon.getInstance(), "help.pit_kiln.construction"))); - PIT_KILN.addButton(Item.simple(ItemStackBuilder.guide(Material.DECORATED_POT, Pylon.getInstance(), "help.pit_kiln.crafting"))); - HELP.addButton(new PageButton(ItemStackBuilder.of(Material.DECORATED_POT).addCustomModelDataString(PylonKeys.PIT_KILN.asString()), PIT_KILN)); - HELP.addButton(new PageButton(ItemStackBuilder.of(Material.BROWN_TERRACOTTA).addCustomModelDataString(PylonKeys.FLUID_PIPE_WOOD.asString()), FLUID_HANDLING)); HELP.addButton(new PageButton(ItemStackBuilder.of(Material.WAXED_COPPER_BULB).addCustomModelDataString(PylonKeys.HYDRAULIC_CORE_DRILL.asString()), HYDRAULICS)); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonItems.java b/src/main/java/io/github/pylonmc/pylon/PylonItems.java index 49de445bc..3a1a1a225 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonItems.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonItems.java @@ -20,7 +20,6 @@ import io.github.pylonmc.pylon.content.machines.hydraulics.*; import io.github.pylonmc.pylon.content.machines.simple.*; import io.github.pylonmc.pylon.content.machines.smelting.DieselSmelteryHeater; -import io.github.pylonmc.pylon.content.machines.smelting.PitKiln; import io.github.pylonmc.pylon.content.machines.storage.Silo; import io.github.pylonmc.pylon.content.resources.CharcoalBlock; import io.github.pylonmc.pylon.content.resources.IronBloom; @@ -483,6 +482,13 @@ private PylonItems() { PylonPages.MISCELLANEOUS.addItem(FINE_SEDIMENT); } + public static final ItemStack SLAG = ItemStackBuilder.rebar(Material.FLINT, PylonKeys.SLAG) + .build(); + static { + RebarItem.register(RebarItem.class, SLAG); + PylonPages.MISCELLANEOUS.addItem(SLAG); + } + public static final ItemStack QUARTZ_DUST = ItemStackBuilder.rebar(Material.CLAY_BALL, PylonKeys.QUARTZ_DUST) .set(DataComponentTypes.ITEM_MODEL, Material.SUGAR.getKey()) .build(); @@ -1979,6 +1985,15 @@ private PylonItems() { PylonPages.SIMPLE_MACHINES.addItem(GRINDSTONE_HANDLE); } + public static final ItemStack CRUDE_ALLOY_FURNACE = ItemStackBuilder.rebar(Material.BLAST_FURNACE, PylonKeys.CRUDE_ALLOY_FURNACE) + .build(); + static { + RebarItem.register(RebarItem.class, CRUDE_ALLOY_FURNACE, PylonKeys.CRUDE_ALLOY_FURNACE); + PylonPages.SIMPLE_MACHINES.addItem(CRUDE_ALLOY_FURNACE); + RebarGuide.getOrCreateInfoPage(PylonKeys.CRUDE_ALLOY_FURNACE) + .addButton(new MachineRecipesButton(CRUDE_ALLOY_FURNACE, CrudeAlloyFurnaceRecipe.RECIPE_TYPE)); + } + public static final ItemStack MIXING_POT = ItemStackBuilder.rebar(Material.CAULDRON, PylonKeys.MIXING_POT) .build(); static { @@ -2164,13 +2179,14 @@ private PylonItems() { // // - public static final ItemStack PIT_KILN = ItemStackBuilder.rebar(Material.DECORATED_POT, PylonKeys.PIT_KILN) + + public static final ItemStack KILN = ItemStackBuilder.rebar(Material.BLAST_FURNACE, PylonKeys.KILN) .build(); static { - RebarItem.register(PitKiln.Item.class, PIT_KILN, PylonKeys.PIT_KILN); - PylonPages.SMELTING.addItem(PIT_KILN); - RebarGuide.getOrCreateInfoPage(PylonKeys.PIT_KILN) - .addButton(new MachineRecipesButton(PIT_KILN, PitKilnRecipe.RECIPE_TYPE)); + RebarItem.register(RebarItem.class, KILN, PylonKeys.KILN); + PylonPages.SMELTING.addItem(KILN); + RebarGuide.getOrCreateInfoPage(PylonKeys.KILN) + .addButton(new MachineRecipesButton(KILN, KilnRecipe.RECIPE_TYPE)); } public static final ItemStack BLOOMERY = ItemStackBuilder.rebar(Material.MAGMA_BLOCK, PylonKeys.BLOOMERY) @@ -2340,6 +2356,17 @@ private PylonItems() { PylonPages.FLUID_PIPES_AND_TANKS.addItem(FLUID_PIPE_BRONZE); } + public static final ItemStack FLUID_PIPE_OBSIDIAN = ItemStackBuilder.rebar(Material.CLAY_BALL, PylonKeys.FLUID_PIPE_OBSIDIAN) + .set( + DataComponentTypes.ITEM_MODEL, + Settings.get(PylonKeys.FLUID_PIPE_OBSIDIAN).getOrThrow("material", ConfigAdapter.MATERIAL).key() + ) + .build(); + static { + RebarItem.register(FluidPipe.class, FLUID_PIPE_OBSIDIAN); + PylonPages.FLUID_PIPES_AND_TANKS.addItem(FLUID_PIPE_OBSIDIAN); + } + public static final ItemStack FLUID_PIPE_IGNEOUS_COMPOSITE = ItemStackBuilder.rebar(Material.CLAY_BALL, PylonKeys.FLUID_PIPE_IGNEOUS_COMPOSITE) .set( DataComponentTypes.ITEM_MODEL, @@ -2440,6 +2467,20 @@ private PylonItems() { PylonPages.FLUID_PIPES_AND_TANKS.addItem(PORTABLE_FLUID_TANK_BRONZE); } + public static final ItemStack PORTABLE_FLUID_TANK_OBSIDIAN + = ItemStackBuilder.rebar(Material.BLACK_STAINED_GLASS, PylonKeys.PORTABLE_FLUID_TANK_OBSIDIAN) + .editPdc(pdc -> pdc.set(PortableFluidTank.Item.FLUID_AMOUNT_KEY, RebarSerializers.DOUBLE, 0.0)) + .addCustomModelDataString("pylon:fluid:empty") + .build(); + static { + RebarItem.register( + PortableFluidTank.Item.class, + PORTABLE_FLUID_TANK_OBSIDIAN, + PylonKeys.PORTABLE_FLUID_TANK_OBSIDIAN + ); + PylonPages.FLUID_PIPES_AND_TANKS.addItem(PORTABLE_FLUID_TANK_OBSIDIAN); + } + public static final ItemStack PORTABLE_FLUID_TANK_IGNEOUS_COMPOSITE = ItemStackBuilder.rebar(Material.BLACK_STAINED_GLASS, PylonKeys.PORTABLE_FLUID_TANK_IGNEOUS_COMPOSITE) .editPdc(pdc -> pdc.set(PortableFluidTank.Item.FLUID_AMOUNT_KEY, RebarSerializers.DOUBLE, 0.0)) @@ -2525,6 +2566,14 @@ private PylonItems() { PylonPages.FLUID_PIPES_AND_TANKS.addItem(FLUID_TANK_CASING_BRONZE); } + public static final ItemStack FLUID_TANK_CASING_OBSIDIAN + = ItemStackBuilder.rebar(Material.BLACK_STAINED_GLASS, PylonKeys.FLUID_TANK_CASING_OBSIDIAN) + .build(); + static { + RebarItem.register(FluidTankCasing.Item.class, FLUID_TANK_CASING_OBSIDIAN, PylonKeys.FLUID_TANK_CASING_OBSIDIAN); + PylonPages.FLUID_PIPES_AND_TANKS.addItem(FLUID_TANK_CASING_OBSIDIAN); + } + public static final ItemStack FLUID_TANK_CASING_IGNEOUS_COMPOSITE = ItemStackBuilder.rebar(Material.BLACK_STAINED_GLASS, PylonKeys.FLUID_TANK_CASING_IGNEOUS_COMPOSITE) .build(); diff --git a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java index 6f16fc675..83860961f 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonKeys.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonKeys.java @@ -125,7 +125,6 @@ public class PylonKeys { public static final NamespacedKey STONE_HAMMER = pylonKey("stone_hammer"); public static final NamespacedKey IRON_HAMMER = pylonKey("iron_hammer"); public static final NamespacedKey DIAMOND_HAMMER = pylonKey("diamond_hammer"); - public static final NamespacedKey NETHERITE_HAMMER = pylonKey("netherite_hammer"); public static final NamespacedKey WATERING_CAN = pylonKey("watering_can"); public static final NamespacedKey SPRINKLER = pylonKey("sprinkler"); @@ -155,6 +154,8 @@ public class PylonKeys { public static final NamespacedKey GRINDSTONE = pylonKey("grindstone"); public static final NamespacedKey GRINDSTONE_HANDLE = pylonKey("grindstone_handle"); + public static final NamespacedKey CRUDE_ALLOY_FURNACE = pylonKey("crude_alloy_furnace"); + public static final NamespacedKey KILN = pylonKey("kiln"); public static final NamespacedKey MIXING_POT = pylonKey("mixing_pot"); public static final NamespacedKey CRUCIBLE = pylonKey("crucible"); @@ -166,6 +167,7 @@ public class PylonKeys { public static final NamespacedKey FLUID_PIPE_TIN = pylonKey("fluid_pipe_tin"); public static final NamespacedKey FLUID_PIPE_BRONZE = pylonKey("fluid_pipe_bronze"); public static final NamespacedKey FLUID_PIPE_IRON = pylonKey("fluid_pipe_iron"); + public static final NamespacedKey FLUID_PIPE_OBSIDIAN = pylonKey("fluid_pipe_obsidian"); public static final NamespacedKey FLUID_PIPE_IGNEOUS_COMPOSITE = pylonKey("fluid_pipe_igneous_composite"); public static final NamespacedKey FLUID_PIPE_STEEL = pylonKey("fluid_pipe_steel"); public static final NamespacedKey FLUID_PIPE_CREATIVE = pylonKey("fluid_pipe_creative"); @@ -175,6 +177,7 @@ public class PylonKeys { public static final NamespacedKey PORTABLE_FLUID_TANK_TIN = pylonKey("portable_fluid_tank_tin"); public static final NamespacedKey PORTABLE_FLUID_TANK_IRON = pylonKey("portable_fluid_tank_iron"); public static final NamespacedKey PORTABLE_FLUID_TANK_BRONZE = pylonKey("portable_fluid_tank_bronze"); + public static final NamespacedKey PORTABLE_FLUID_TANK_OBSIDIAN = pylonKey("portable_fluid_tank_obsidian"); public static final NamespacedKey PORTABLE_FLUID_TANK_IGNEOUS_COMPOSITE = pylonKey("portable_fluid_tank_igneous_composite"); public static final NamespacedKey PORTABLE_FLUID_TANK_STEEL = pylonKey("portable_fluid_tank_steel"); @@ -184,6 +187,7 @@ public class PylonKeys { public static final NamespacedKey FLUID_TANK_CASING_TIN = pylonKey("fluid_tank_casing_tin"); public static final NamespacedKey FLUID_TANK_CASING_IRON = pylonKey("fluid_tank_casing_iron"); public static final NamespacedKey FLUID_TANK_CASING_BRONZE = pylonKey("fluid_tank_casing_bronze"); + public static final NamespacedKey FLUID_TANK_CASING_OBSIDIAN = pylonKey("fluid_tank_casing_obsidian"); public static final NamespacedKey FLUID_TANK_CASING_IGNEOUS_COMPOSITE = pylonKey("fluid_tank_casing_igneous_composite"); public static final NamespacedKey FLUID_TANK_CASING_STEEL = pylonKey("fluid_tank_casing_steel"); @@ -249,8 +253,6 @@ public class PylonKeys { public static final NamespacedKey SHEET_MOLD = pylonKey("mold_sheet"); public static final NamespacedKey PIPE_MOLD = pylonKey("mold_pipe"); - public static final NamespacedKey PIT_KILN = pylonKey("pit_kiln"); - public static final NamespacedKey EXPLOSIVE_TARGET = pylonKey("explosive_target"); public static final NamespacedKey EXPLOSIVE_TARGET_FIERY = pylonKey("explosive_target_fiery"); public static final NamespacedKey EXPLOSIVE_TARGET_SUPER = pylonKey("explosive_target_super"); @@ -472,4 +474,5 @@ public class PylonKeys { public static final NamespacedKey PALLADIUM_SILO = pylonKey("palladium_silo"); public static final NamespacedKey FINE_SEDIMENT = pylonKey("fine_sediment"); + public static final NamespacedKey SLAG = pylonKey("slag"); } \ 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 d46adfd3f..989e5fd35 100644 --- a/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java +++ b/src/main/java/io/github/pylonmc/pylon/PylonRecipes.java @@ -39,11 +39,12 @@ public static void initialize() { PipeBendingRecipe.RECIPE_TYPE.register(); PressRecipe.RECIPE_TYPE.register(); SmelteryRecipe.RECIPE_TYPE.register(); - PitKilnRecipe.RECIPE_TYPE.register(); + KilnRecipe.RECIPE_TYPE.register(); StrainingRecipe.RECIPE_TYPE.register(); TableSawRecipe.RECIPE_TYPE.register(); SiloConverterRecipe.RECIPE_TYPE.register(); HydraulicPurifier.RECIPE_TYPE.register(); + CrudeAlloyFurnaceRecipe.RECIPE_TYPE.register(); FormingRecipe.RECIPE_TYPE.register(); //hardcoded @@ -71,8 +72,8 @@ private static void initCollimator() { ) .addIngredient('#', GuiItems.backgroundBlack()) .addIngredient('i', new FluidButton(input.amountMillibuckets(), PylonFluids.OBSCYRA)) - .addIngredient('x', ItemButton.from(PylonItems.COLLIMATOR)) - .addIngredient('o', ItemButton.from(PylonItems.COHESIVE_UNIT)) + .addIngredient('x', ItemButton.of(PylonItems.COLLIMATOR)) + .addIngredient('o', ItemButton.of(PylonItems.COHESIVE_UNIT)) .build() ).register(); } @@ -110,11 +111,11 @@ private static void initPalladiumCondenser() { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('x', ItemButton.from(PylonItems.PALLADIUM_CONDENSER)) + .addIngredient('x', ItemButton.of(PylonItems.PALLADIUM_CONDENSER)) .addIngredient('H', new FluidButton((double) dieselUse, PylonFluids.BIODIESEL)) .addIngredient('d', new FluidButton((double) hydraulicUse, PylonFluids.HYDRAULIC_FLUID)) - .addIngredient('s', ItemButton.from(dusts)) - .addIngredient('p', ItemButton.from(PylonItems.PALLADIUM_DUST)) + .addIngredient('s', ItemButton.of(dusts)) + .addIngredient('p', ItemButton.of(PylonItems.PALLADIUM_DUST)) .addIngredient('D', new FluidButton((double) hydraulicUse, PylonFluids.DIRTY_HYDRAULIC_FLUID)) .build() ).register(); @@ -146,7 +147,7 @@ private static void initBiorefinery() { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('x', ItemButton.from(PylonItems.BIOREFINERY)) + .addIngredient('x', ItemButton.of(PylonItems.BIOREFINERY)) .addIngredient('o', new FluidButton(1.0, PylonFluids.BIODIESEL)) .addIngredient('p', new FluidButton(plantOilPerMbOfBiodiesel, PylonFluids.PLANT_OIL)) .addIngredient('e', new FluidButton(ethanolPerMbOfBiodiesel, PylonFluids.ETHANOL)) @@ -176,8 +177,8 @@ private static void initFermenter() { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(ItemStack.of(Material.SUGAR_CANE))) - .addIngredient('x', ItemButton.from(PylonItems.FERMENTER)) + .addIngredient('i', ItemButton.of(ItemStack.of(Material.SUGAR_CANE))) + .addIngredient('x', ItemButton.of(PylonItems.FERMENTER)) .addIngredient('o', new FluidButton(ethanolPerSugarcane, PylonFluids.ETHANOL)) .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 63440849e..3af773c39 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 @@ -138,13 +138,19 @@ public boolean setFluid(@NotNull RebarFluid fluid, double amount) { return result; } + public double fluidAmount() { + return fluid == null + ? 0.0 + : fluidAmount(fluid); + } + @Override public @Nullable WailaDisplay getWaila(@NotNull Player player) { Component info; 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.no_fluid"); } else { info = Component.translatable("pylon.message.fluid_hatch.working") .arguments( diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/FluidInputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/components/FluidInputHatch.java index 28012644c..ccd12d5e7 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/FluidInputHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/FluidInputHatch.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.components; +import com.google.common.base.Preconditions; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.fluid.FluidPointType; import org.bukkit.block.Block; @@ -16,4 +17,9 @@ public FluidInputHatch(@NotNull Block block, @NotNull BlockCreateContext context public FluidInputHatch(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); } + + public void removeFluid(double amount) { + Preconditions.checkState(fluid != null); + removeFluid(fluid, amount); + } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/components/FluidOutputHatch.java b/src/main/java/io/github/pylonmc/pylon/content/components/FluidOutputHatch.java index 8a8ba7310..45c3b10d1 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/components/FluidOutputHatch.java +++ b/src/main/java/io/github/pylonmc/pylon/content/components/FluidOutputHatch.java @@ -1,5 +1,6 @@ package io.github.pylonmc.pylon.content.components; +import com.google.common.base.Preconditions; import io.github.pylonmc.rebar.block.context.BlockCreateContext; import io.github.pylonmc.rebar.fluid.FluidPointType; import org.bukkit.block.Block; @@ -16,4 +17,14 @@ public FluidOutputHatch(@NotNull Block block, @NotNull BlockCreateContext contex public FluidOutputHatch(@NotNull Block block, @NotNull PersistentDataContainer pdc) { super(block, pdc); } + + public void addFluid(double amount) { + Preconditions.checkState(fluid != null); + addFluid(fluid, amount); + } + + public void canAddFluid(double amount) { + Preconditions.checkState(fluid != null); + addFluid(fluid, amount); + } } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CrudeAlloyFurnace.java b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CrudeAlloyFurnace.java new file mode 100644 index 000000000..8d02c6213 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/simple/CrudeAlloyFurnace.java @@ -0,0 +1,307 @@ +package io.github.pylonmc.pylon.content.machines.simple; + +import com.destroystokyo.paper.ParticleBuilder; +import io.github.pylonmc.pylon.recipes.CrudeAlloyFurnaceRecipe; +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.RebarEntityHolderBlock; +import io.github.pylonmc.rebar.block.base.RebarGuiBlock; +import io.github.pylonmc.rebar.block.base.RebarLogisticBlock; +import io.github.pylonmc.rebar.block.base.RebarRecipeProcessor; +import io.github.pylonmc.rebar.block.base.RebarTickingBlock; +import io.github.pylonmc.rebar.block.base.RebarVirtualInventoryBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +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.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.logistics.LogisticGroupType; +import io.github.pylonmc.rebar.logistics.slot.VirtualInventoryLogisticSlot; +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.waila.WailaDisplay; +import net.kyori.adventure.text.Component; +import net.kyori.adventure.text.format.NamedTextColor; +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; +import org.bukkit.persistence.PersistentDataContainer; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.joml.Vector3d; +import org.jspecify.annotations.NonNull; +import xyz.xenondevs.invui.gui.Gui; +import xyz.xenondevs.invui.inventory.VirtualInventory; +import xyz.xenondevs.invui.inventory.event.ItemPostUpdateEvent; + +import java.util.Map; +import java.util.function.Consumer; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + + +public class CrudeAlloyFurnace extends RebarBlock implements + RebarGuiBlock, + RebarVirtualInventoryBlock, + RebarEntityHolderBlock, + RebarDirectionalBlock, + RebarTickingBlock, + RebarLogisticBlock, + RebarRecipeProcessor { + + public static final NamespacedKey FUEL_TICKS_TOTAL_KEY = pylonKey("fuel_ticks_total"); + public static final NamespacedKey FUEL_TICKS_REMAINING_KEY = pylonKey("fuel_ticks_remaining"); + + public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + + private final VirtualInventory fuelInventory = new VirtualInventory(1); + private final VirtualInventory inputInventory = new VirtualInventory(3); + private final VirtualInventory outputInventory = new VirtualInventory(1); + + public final ItemStackBuilder chamberStack = ItemStackBuilder.of(Material.IRON_BLOCK) + .addCustomModelDataString(getKey() + ":chamber"); + public final ItemStackBuilder chimneyStack = ItemStackBuilder.of(Material.GRAY_CONCRETE) + .addCustomModelDataString(getKey() + ":chimney"); + + public final ItemStackBuilder fuelLeftStack = ItemStackBuilder.gui(Material.FLINT_AND_STEEL, getKey() + "fuel-left") + .name(Component.translatable("pylon.gui.fuel-left")); + public final ItemStackBuilder noFuelLeftStack = ItemStackBuilder.gui(Material.BARRIER, getKey() + "no-fuel-left") + .name(Component.translatable("pylon.gui.no-fuel-left")); + public final ItemStackBuilder noRecipeStack = ItemStackBuilder.gui(Material.BARRIER, getKey() + "no-recipe") + .name(Component.translatable("pylon.gui.no-recipe")); + public final ItemStackBuilder fuelStack = ItemStackBuilder.gui(Material.BLACK_STAINED_GLASS_PANE, getKey() + "fuel") + .name(Component.translatable("pylon.gui.fuel")); + + private final ProgressItem fuelProgressItem = new ProgressItem(GuiItems.background()); + + private int fuelTicksTotal; + private int fuelTicksRemaining; + + @SuppressWarnings("unused") + public CrudeAlloyFurnace(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setTickInterval(tickInterval); + setFacing(context.getFacing()); + addEntity("chimney", new ItemDisplayBuilder() + .itemStack(chimneyStack) + .transformation(new TransformBuilder() + .lookAlong(getFacing()) + .translate(0.0, -0.5, -0.35) + .scale(0.2, 1.6, 0.2)) + .build(block.getLocation().toCenterLocation().add(0, 0.5, 0)) + ); + addEntity("chamber", new ItemDisplayBuilder() + .itemStack(chamberStack) + .transformation(new TransformBuilder() + .translate(0, -0.1, 0) + .scale(0.6)) + .build(block.getLocation().toCenterLocation().add(0, 0.5, 0)) + ); + setRecipeType(CrudeAlloyFurnaceRecipe.RECIPE_TYPE); + setRecipeProgressItem(new ProgressItem(noRecipeStack, false)); + } + + @SuppressWarnings("unused") + public CrudeAlloyFurnace(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + fuelTicksTotal = pdc.get(FUEL_TICKS_TOTAL_KEY, RebarSerializers.INTEGER); + fuelTicksRemaining = pdc.get(FUEL_TICKS_REMAINING_KEY, RebarSerializers.INTEGER); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(FUEL_TICKS_TOTAL_KEY, RebarSerializers.INTEGER, fuelTicksTotal); + pdc.set(FUEL_TICKS_REMAINING_KEY, RebarSerializers.INTEGER, fuelTicksRemaining); + } + + @Override + public void postInitialise() { + createLogisticGroup("fuel", LogisticGroupType.INPUT, fuelInventory); + createLogisticGroup("input1", LogisticGroupType.INPUT, new VirtualInventoryLogisticSlot(inputInventory, 0)); + createLogisticGroup("input2", LogisticGroupType.INPUT, new VirtualInventoryLogisticSlot(inputInventory, 1)); + createLogisticGroup("input3", LogisticGroupType.INPUT, new VirtualInventoryLogisticSlot(inputInventory, 2)); + createLogisticGroup("output", LogisticGroupType.OUTPUT, outputInventory); + + outputInventory.addPreUpdateHandler(RebarUtils.DISALLOW_PLAYERS_FROM_ADDING_ITEMS_HANDLER); + + Consumer startRecipeHandler = (ItemPostUpdateEvent event) -> { + if (!(event.getUpdateReason() instanceof MachineUpdateReason)) { + tryStartRecipe(); + } + }; + fuelInventory.addPostUpdateHandler(startRecipeHandler); + inputInventory.addPostUpdateHandler(startRecipeHandler); + outputInventory.addPostUpdateHandler(startRecipeHandler); + } + + @Override + public void tick() { + if (fuelTicksRemaining <= 0) { + if (isProcessingRecipe()) { + tryConsumeFuel(); + } + if (fuelTicksRemaining <= 0) { + return; + } + } + + fuelTicksRemaining -= getTickInterval(); + fuelProgressItem.setTotalTimeTicks(fuelTicksTotal); + fuelProgressItem.setRemainingTimeTicks(fuelTicksRemaining); + if (fuelTicksRemaining <= 0) { + fuelProgressItem.setTotalTimeTicks(null); + fuelProgressItem.setItem(noFuelLeftStack); + } + + Vector smokePosition = Vector.fromJOML(RebarUtils.rotateVectorToFace( + new Vector3d(0.0, 0.8, -0.35), + getFacing().getOppositeFace() + )); + new ParticleBuilder(Particle.CAMPFIRE_COSY_SMOKE) + .location(getBlock().getLocation().toCenterLocation().add(smokePosition)) + .offset(0, 1, 0) + .count(0) + .extra(0.05) + .spawn(); + + if (isProcessingRecipe()) { + progressRecipe(getTickInterval()); + } + } + + public void tryConsumeFuel() { + if (fuelTicksRemaining > 0) { + return; + } + + ItemStack fuel = fuelInventory.getItem(0); + if (fuel == null) { + return; + } + + // dividing by 10 due to suspected bug with getBurnDuration + fuelTicksTotal = fuel.getType().asItemType().getBurnDuration() / 10; + fuelTicksRemaining = fuelTicksTotal; + fuelProgressItem.setItem(fuelLeftStack); + fuelProgressItem.setTotalTimeTicks(fuelTicksTotal); + fuelProgressItem.setRemainingTimeTicks(fuelTicksRemaining); + fuelInventory.setItem(new MachineUpdateReason(), 0, fuel.subtract()); + } + + public boolean tryStartRecipe(@NonNull CrudeAlloyFurnaceRecipe recipe) { + int input1count = 0; + for (ItemStack stack : inputInventory.getUnsafeItems()) { + if (stack != null && recipe.input1().matchesIgnoringAmount(stack)) { + input1count += stack.getAmount(); + } + } + + int input2count = 0; + for (ItemStack stack : inputInventory.getUnsafeItems()) { + if (stack != null && recipe.input2().matchesIgnoringAmount(stack)) { + input2count += stack.getAmount(); + } + } + + if (input1count < recipe.input1().getAmount() + || input2count < recipe.input2().getAmount() + || !outputInventory.canHold(recipe.result()) + ) { + return false; + } + + tryConsumeFuel(); + if (fuelTicksRemaining == 0) { + return false; + } + + inputInventory.removeFirst(new MachineUpdateReason(), recipe.input1().getAmount(), recipe.input1()::matchesIgnoringAmount); + inputInventory.removeFirst(new MachineUpdateReason(), recipe.input2().getAmount(), recipe.input2()::matchesIgnoringAmount); + + startRecipe(recipe, recipe.timeTicks()); + getRecipeProgressItem().setItem(ItemStackBuilder.of(recipe.result().asOne()).clearLore()); + + return true; + } + + public void tryStartRecipe() { + if (isProcessingRecipe()) { + return; + } + + if (getLastRecipe() != null && tryStartRecipe(getLastRecipe())) { + return; + } + + for (CrudeAlloyFurnaceRecipe recipe : CrudeAlloyFurnaceRecipe.RECIPE_TYPE) { + if (tryStartRecipe(recipe)) { + break; + } + } + } + + @Override + public void onRecipeFinished(@NotNull CrudeAlloyFurnaceRecipe recipe) { + getRecipeProgressItem().setItem(noRecipeStack); + outputInventory.addItem(new MachineUpdateReason(), recipe.result().clone()); + tryStartRecipe(); + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure( + "# # # # # # # O #", + "# I i i i I p o #", + "# # # b # # # O #", + "# # F f F # # # #", + "# # # # # # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.background()) + .addIngredient('I', GuiItems.input()) + .addIngredient('i', inputInventory) + .addIngredient('p', getRecipeProgressItem()) + .addIngredient('O', GuiItems.output()) + .addIngredient('o', outputInventory) + .addIngredient('f', fuelInventory) + .addIngredient('F', fuelStack) + .addIngredient('b', fuelProgressItem) + .build(); + } + + @Override + public @Nullable WailaDisplay getWaila(@NotNull Player player) { + Double progress = getRecipeProgress(); + return new WailaDisplay(getDefaultWailaTranslationKey().arguments( + RebarArgument.of("info", progress == null + ? Component.text("") + : Component.translatable("pylon.item.crude_alloy_furnace.info").arguments( + RebarArgument.of("progress", PylonUtils.createProgressBar( + 1 - progress, + 20, + NamedTextColor.WHITE + )) + ) + ) + )); + } + + @Override + public @NotNull Map getVirtualInventories() { + return Map.of( + "fuel", fuelInventory, + "input", inputInventory, + "output", outputInventory + ); + } +} 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 951438e9b..99ccdc245 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 @@ -189,7 +189,7 @@ && tryStartRecipe(lastRecipe, new Pair<>(item, item.getItemStack()), fluidSpaceR } private boolean tryStartRecipe(PressRecipe recipe, Pair stack, double fluidSpaceRemaining) { - if (recipe.oilAmount() > fluidSpaceRemaining || !recipe.input().contains(stack.getSecond())) { + if (recipe.oilAmount() > fluidSpaceRemaining || !recipe.input().matchesIgnoringAmount(stack.getSecond())) { return false; } diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Kiln.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Kiln.java new file mode 100644 index 000000000..c815c1b19 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/Kiln.java @@ -0,0 +1,425 @@ +package io.github.pylonmc.pylon.content.machines.smelting; + +import com.destroystokyo.paper.ParticleBuilder; +import io.github.pylonmc.pylon.PylonKeys; +import io.github.pylonmc.pylon.content.components.FluidOutputHatch; +import io.github.pylonmc.pylon.content.components.ItemInputHatch; +import io.github.pylonmc.pylon.content.components.ItemOutputHatch; +import io.github.pylonmc.pylon.recipes.KilnRecipe; +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.RebarGuiBlock; +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.RebarVirtualInventoryBlock; +import io.github.pylonmc.rebar.block.context.BlockCreateContext; +import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; +import io.github.pylonmc.rebar.datatypes.RebarSerializers; +import io.github.pylonmc.rebar.i18n.RebarArgument; +import io.github.pylonmc.rebar.item.builder.ItemStackBuilder; +import io.github.pylonmc.rebar.util.MachineUpdateReason; +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.Component; +import net.kyori.adventure.text.format.TextColor; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.Particle; +import org.bukkit.block.Block; +import org.bukkit.block.data.type.Furnace; +import org.bukkit.block.data.type.Light; +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.joml.Vector3i; +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.HashMap; +import java.util.Map; +import java.util.Random; + +import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; + + +public class Kiln extends RebarBlock implements + RebarSimpleMultiblock, + RebarGuiBlock, + RebarRecipeProcessor, + RebarDirectionalBlock, + RebarVirtualInventoryBlock, + RebarTickingBlock { + + public static final NamespacedKey TEMPERATURE_KEY = pylonKey("temperature"); + public static final NamespacedKey FUEL_TICKS_TOTAL_KEY = pylonKey("fuel_ticks_total"); + public static final NamespacedKey FUEL_TICKS_REMAINING_KEY = pylonKey("fuel_ticks_remaining"); + + private static final Vector3i ITEM_INPUT_HATCH_1 = new Vector3i(1, 0, 1); + private static final Vector3i ITEM_INPUT_HATCH_2 = new Vector3i(1, 1, 1); + private static final Vector3i ITEM_OUTPUT_HATCH = new Vector3i(-1, 0, 1); + private static final Vector3i FLUID_OUTPUT_HATCH = new Vector3i(-1, 1, 1); + private static final Vector3i LIGHT = new Vector3i(0, 1, 1); + + private static final Random RANDOM = new Random(); + + public final int tickInterval = getSettings().getOrThrow("tick-interval", ConfigAdapter.INTEGER); + public final double minTemperature = getSettings().getOrThrow("min-temperature", ConfigAdapter.DOUBLE); + public final double maxTemperature = getSettings().getOrThrow("max-temperature", ConfigAdapter.DOUBLE); + public final double heatingRate = getSettings().getOrThrow("heating-rate", ConfigAdapter.DOUBLE); + + private final VirtualInventory fuelInventory = new VirtualInventory(1); + + private final ProgressItem fuelProgressItem = new ProgressItem(GuiItems.background()); + + public final ItemStackBuilder burningStack = ItemStackBuilder.gui(Material.FLINT_AND_STEEL, getKey() + "fuel-left") + .name(Component.translatable("pylon.gui.fuel-left")); + public final ItemStackBuilder fuelStack = ItemStackBuilder.gui(Material.BLACK_STAINED_GLASS_PANE, getKey() + "fuel") + .name(Component.translatable("pylon.gui.fuel")); + public final ItemStackBuilder temperatureStack = ItemStackBuilder.gui(Material.REDSTONE, getKey() + "temperature") + .name(Component.translatable("pylon.gui.temperature")); + + public final AbstractItem temperatureItem = new TemperatureItem(); + + private int fuelTicksTotal; + private int fuelTicksRemaining; + public double temperature; + + @SuppressWarnings("unused") + public Kiln(@NotNull Block block, @NotNull BlockCreateContext context) { + super(block, context); + setFacing(context.getFacing()); + setMultiblockDirection(context.getFacing()); + setTickInterval(tickInterval); + setRecipeType(KilnRecipe.RECIPE_TYPE); + setRecipeProgressItem(new ProgressItem(GuiItems.background(), false)); + temperature = minTemperature; + } + + @SuppressWarnings("unused") + public Kiln(@NotNull Block block, @NotNull PersistentDataContainer pdc) { + super(block, pdc); + temperature = pdc.get(TEMPERATURE_KEY, RebarSerializers.DOUBLE); + fuelTicksTotal = pdc.get(FUEL_TICKS_TOTAL_KEY, RebarSerializers.INTEGER); + fuelTicksRemaining = pdc.get(FUEL_TICKS_REMAINING_KEY, RebarSerializers.INTEGER); + } + + @Override + public void write(@NotNull PersistentDataContainer pdc) { + pdc.set(TEMPERATURE_KEY, RebarSerializers.DOUBLE, temperature); + pdc.set(FUEL_TICKS_TOTAL_KEY, RebarSerializers.INTEGER, fuelTicksTotal); + pdc.set(FUEL_TICKS_REMAINING_KEY, RebarSerializers.INTEGER, fuelTicksRemaining); + } + + @Override + public @NotNull Map<@NotNull Vector3i, @NotNull MultiblockComponent> getComponents() { + Map components = new HashMap<>(); + + components.put(new Vector3i(0, 0, 1), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(new Vector3i(0, 0, 2), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(ITEM_INPUT_HATCH_1, MultiblockComponent.of(PylonKeys.ITEM_INPUT_HATCH)); + components.put(ITEM_OUTPUT_HATCH, MultiblockComponent.of(PylonKeys.ITEM_OUTPUT_HATCH)); + components.put(new Vector3i(1, 0, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 0, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(1, 0, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 0, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + + components.put(new Vector3i(0, 1, 0), MultiblockComponent.of(PylonKeys.BRONZE_GRATING)); + components.put(ITEM_INPUT_HATCH_2, MultiblockComponent.of(PylonKeys.ITEM_INPUT_HATCH)); + components.put(FLUID_OUTPUT_HATCH, MultiblockComponent.of(PylonKeys.FLUID_OUTPUT_HATCH)); + components.put(new Vector3i(0, 1, 2), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(new Vector3i(1, 1, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 1, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(1, 1, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 1, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + + components.put(new Vector3i(0, 2, 0), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(new Vector3i(1, 2, 1), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(new Vector3i(0, 2, 2), MultiblockComponent.of(Material.MUD_BRICKS)); + components.put(new Vector3i(1, 2, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 2, 0), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(1, 2, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + components.put(new Vector3i(-1, 2, 2), MultiblockComponent.of(Material.MUD_BRICK_WALL)); + + return components; + } + + @Override + public void tick() { + if (!isFormedAndFullyLoaded()) { + return; + } + + // Fuel stuff + tryConsumeFuel(); + if (fuelTicksRemaining >= 0) { + fuelTicksRemaining -= getTickInterval(); + } + tryConsumeFuel(); + + if (fuelTicksRemaining >= 0) { + fuelProgressItem.setTotalTimeTicks(fuelTicksTotal); + fuelProgressItem.setRemainingTimeTicks(fuelTicksRemaining); + fuelProgressItem.setItem(burningStack); + } else { + fuelProgressItem.setTotalTimeTicks(null); + fuelProgressItem.setItem(GuiItems.background()); + } + + // Temperature stuff + if (fuelTicksRemaining > 0) { + temperature += heatingRate / getTickInterval(); + } + temperature -= (heatingRate / (maxTemperature - minTemperature)) * (temperature - minTemperature) / getTickInterval(); + temperatureItem.notifyWindows(); + + // Visual stuff + Furnace furnace = (Furnace) getBlock().getBlockData(); + furnace.setLit(fuelTicksRemaining > 0); + getBlock().setBlockData(furnace); + refreshBlockTextureItem(); + + int level = Math.clamp((int) Math.round(15 * temperature / maxTemperature), 0, 15); + Block light = getLight(); + if (light.getType() == Material.LIGHT) { + Light blockData = (Light) light.getBlockData(); + blockData.setLevel(level); + light.setBlockData(blockData); + } + + for (int i = 0; i < level; i++) { + double x = RANDOM.nextDouble(-0.4, 0.4); + double y = 1.0 + RANDOM.nextDouble(-0.4, 0.4); + double z = RANDOM.nextDouble(-0.4, 0.4); + new ParticleBuilder(Particle.CAMPFIRE_SIGNAL_SMOKE) + .location(getBlock().getLocation().toCenterLocation().add(getFacing().getOppositeFace().getDirection()).add(x, y, z)) + .offset(0.0, 1.0, 0.0) + .extra(0.03) + .count(0) + .spawn(); + } + + // Recipe stuff + tryStartRecipe(); + KilnRecipe recipe = getCurrentRecipe(); + if (recipe != null) { + boolean canHoldOutputItem = getMultiblockComponentOrThrow(ItemOutputHatch.class, ITEM_OUTPUT_HATCH) + .inventory.canHold(recipe.outputItem()); + FluidOutputHatch fluidOutputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); + boolean canHoldOutputFluid = recipe.outputFluid() == null + || fluidOutputHatch.fluid == null + || fluidOutputHatch.canSetFluid(recipe.outputFluid(), fluidOutputHatch.fluidAmount() + recipe.outputFluidAmount()); + if (canHoldOutputItem && canHoldOutputFluid && temperature > recipe.temperature()) { + progressRecipe(getTickInterval()); + } + } + } + + public void tryConsumeFuel() { + if (fuelTicksRemaining > 0) { + return; + } + + ItemStack fuel = fuelInventory.getItem(0); + if (fuel == null) { + return; + } + + // dividing by 10 due to suspected bug with getBurnDuration + fuelTicksTotal = fuel.getType().asItemType().getBurnDuration() / 10; + fuelTicksRemaining = fuelTicksTotal; + fuelInventory.setItem(new MachineUpdateReason(), 0, fuel.subtract()); + } + + public boolean tryStartRecipe(@NonNull KilnRecipe recipe) { + if (temperature < recipe.temperature()) { + return false; + } + + if (recipe.outputItem() != null) { + boolean canHoldOutputItem = getMultiblockComponentOrThrow(ItemOutputHatch.class, ITEM_OUTPUT_HATCH) + .inventory.canHold(recipe.outputItem()); + if (!canHoldOutputItem) { + return false; + } + } + + if (recipe.outputFluid() != null && recipe.outputFluidAmount() != null) { + FluidOutputHatch fluidOutputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); + boolean canHoldFluidOutput = fluidOutputHatch.fluid == null + || fluidOutputHatch.fluidAmount(fluidOutputHatch.fluid) < 1.0e-6 + || fluidOutputHatch.fluid.equals(recipe.outputFluid()) && fluidOutputHatch.fluidSpaceRemaining(fluidOutputHatch.fluid) > recipe.outputFluidAmount(); + if (!canHoldFluidOutput) { + return false; + } + } + + ItemInputHatch itemInputHatch1 = getMultiblockComponentOrThrow(ItemInputHatch.class, ITEM_INPUT_HATCH_1); + ItemInputHatch itemInputHatch2 = getMultiblockComponentOrThrow(ItemInputHatch.class, ITEM_INPUT_HATCH_2); + ItemStack input1 = itemInputHatch1.inventory.getItem(0); + ItemStack input2 = itemInputHatch2.inventory.getItem(0); + + boolean matches = false; + if (recipe.input2() == null) { + if (recipe.input1().matches(input1)) { + itemInputHatch1.inventory.setItem(new MachineUpdateReason(), 0, input1.subtract(recipe.input1().getAmount())); + matches = true; + } else if (recipe.input1().matches(input2)) { + itemInputHatch2.inventory.setItem(new MachineUpdateReason(), 0, input2.subtract(recipe.input1().getAmount())); + matches = true; + } + } else { + if (recipe.input1().matches(input1) && recipe.input2().matches(input2)) { + itemInputHatch1.inventory.setItem(new MachineUpdateReason(), 0, input1.subtract(recipe.input1().getAmount())); + itemInputHatch2.inventory.setItem(new MachineUpdateReason(), 0, input2.subtract(recipe.input2().getAmount())); + matches = true; + } + if (recipe.input1().matches(input2) && recipe.input2().matches(input1)) { + itemInputHatch1.inventory.setItem(new MachineUpdateReason(), 0, input1.subtract(recipe.input2().getAmount())); + itemInputHatch2.inventory.setItem(new MachineUpdateReason(), 0, input2.subtract(recipe.input1().getAmount())); + matches = true; + } + } + + if (!matches) { + return false; + } + + if (recipe.outputFluid() != null) { + getRecipeProgressItem().setItem(ItemStackBuilder.of(recipe.outputFluid().getItem()) + .clearLore() + ); + } else if (recipe.outputItem() != null) { + getRecipeProgressItem().setItem(ItemStackBuilder.of(recipe.outputItem()) + .clearLore() + ); + } + startRecipe(recipe, recipe.timeTicks()); + return true; + } + + public void tryStartRecipe() { + if (isProcessingRecipe()) { + return; + } + + if (getLastRecipe() != null && tryStartRecipe(getLastRecipe())) { + return; + } + + for (KilnRecipe recipe : KilnRecipe.RECIPE_TYPE) { + if (tryStartRecipe(recipe)) { + break; + } + } + } + + @Override + public @NotNull Gui createGui() { + return Gui.builder() + .setStructure("# F f F # b t p #") + .addIngredient('#', GuiItems.background()) + .addIngredient('F', fuelStack) + .addIngredient('f', fuelInventory) + .addIngredient('p', getRecipeProgressItem()) + .addIngredient('b', fuelProgressItem) + .addIngredient('t', temperatureItem) + .build(); + } + + @Override + public void onRecipeFinished(@NonNull KilnRecipe recipe) { + if (recipe.outputFluid() != null && recipe.outputFluidAmount() != null) { + FluidOutputHatch fluidOutputHatch = getMultiblockComponentOrThrow(FluidOutputHatch.class, FLUID_OUTPUT_HATCH); + fluidOutputHatch.setFluidType(recipe.outputFluid()); + fluidOutputHatch.addFluid(recipe.outputFluidAmount()); + } + if (recipe.outputItem() != null) { + getMultiblockComponentOrThrow(ItemOutputHatch.class, ITEM_OUTPUT_HATCH) + .inventory.addItem(new MachineUpdateReason(), recipe.outputItem()); + } + getRecipeProgressItem().setItem(GuiItems.background()); + tryStartRecipe(); + } + + @Override + public void onMultiblockFormed() { + RebarSimpleMultiblock.super.onMultiblockFormed(); + Block light = getLight(); + if (light.getType().isAir()) { + light.setType(Material.LIGHT); + Light blockData = (Light) light.getBlockData(); + blockData.setLevel(0); + light.setBlockData(blockData); + } + } + + @Override + public void onMultiblockUnformed(boolean partUnloaded) { + RebarSimpleMultiblock.super.onMultiblockUnformed(partUnloaded); + Block light = getLight(); + if (light.getType() == Material.LIGHT) { + light.setType(Material.AIR); + } + } + + public @NotNull Block getLight() { + return getMultiblockBlock(LIGHT); + } + + @Override + public @NotNull Map getVirtualInventories() { + return Map.of( + "fuel", fuelInventory + ); + } + + @Override + public @Nullable WailaDisplay getWaila(@NotNull Player player) { + if (!isFormedAndFullyLoaded()) { + return new WailaDisplay(getNameTranslationKey()); + } + + return new WailaDisplay(getDefaultWailaTranslationKey().arguments( + RebarArgument.of("temperature-bar", PylonUtils.createBar( + temperature / maxTemperature, + 20, + PylonUtils.colorToTextColor(PylonUtils.colorFromTemperature(temperature) + ))), + RebarArgument.of("temperature", UnitFormat.CELSIUS.format(temperature).decimalPlaces(1)), + RebarArgument.of("progress", getRecipeProgress() == null + ? Component.empty() + : Component.translatable("pylon.waila.kiln").arguments( + RebarArgument.of("progress", PylonUtils.createProgressBar( + 1.0 - getRecipeProgress(), + 20, + TextColor.color(255, 255, 255) + )) + )) + )); + } + + public class TemperatureItem extends AbstractItem { + + @Override + public @NonNull ItemProvider getItemProvider(@NonNull Player viewer) { + return temperatureStack.clone() + .lore(Component.translatable("pylon.gui.kiln.temperature") + .arguments(RebarArgument.of("temperature", UnitFormat.CELSIUS.format(temperature).decimalPlaces(1))) + ); + } + + @Override + public void handleClick(@NonNull ClickType clickType, @NonNull Player player, @NonNull Click click) {} + } +} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/PitKiln.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/PitKiln.java deleted file mode 100644 index 9e982037f..000000000 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/PitKiln.java +++ /dev/null @@ -1,418 +0,0 @@ -package io.github.pylonmc.pylon.content.machines.smelting; - -import io.github.pylonmc.pylon.PylonKeys; -import io.github.pylonmc.pylon.recipes.PitKilnRecipe; -import io.github.pylonmc.rebar.block.RebarBlock; -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.Settings; -import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; -import io.github.pylonmc.rebar.datatypes.RebarSerializers; -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.recipe.RecipeInput; -import io.github.pylonmc.rebar.util.RebarUtils; -import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; -import io.github.pylonmc.rebar.util.position.BlockPosition; -import io.github.pylonmc.rebar.waila.Waila; -import io.github.pylonmc.rebar.waila.WailaDisplay; -import io.papermc.paper.event.block.BlockBreakBlockEvent; -import net.kyori.adventure.text.Component; -import org.bukkit.Effect; -import org.bukkit.Material; -import org.bukkit.NamespacedKey; -import org.bukkit.Sound; -import org.bukkit.SoundCategory; -import org.bukkit.block.Block; -import org.bukkit.block.data.type.Campfire; -import org.bukkit.entity.Player; -import org.bukkit.event.Event; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.Action; -import org.bukkit.event.inventory.InventoryMoveItemEvent; -import org.bukkit.event.player.PlayerInteractEvent; -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.jetbrains.annotations.Nullable; -import org.joml.Vector3i; - -import java.time.Duration; -import java.util.*; - -import static io.github.pylonmc.pylon.util.PylonUtils.pylonKey; - -public final class PitKiln extends RebarBlock implements - RebarSimpleMultiblock, RebarInteractBlock, RebarTickingBlock, RebarBreakHandler, RebarNoVanillaContainerBlock { - - public static final int CAPACITY = Settings.get(PylonKeys.PIT_KILN).getOrThrow("capacity", ConfigAdapter.INTEGER); - public static final int PROCESSING_TIME_SECONDS = - Settings.get(PylonKeys.PIT_KILN).getOrThrow("processing-time-seconds", ConfigAdapter.INTEGER); - - private static final double MULTIPLIER_CAMPFIRE = Settings.get(PylonKeys.PIT_KILN).getOrThrow("speed-multipliers.campfire", ConfigAdapter.DOUBLE); - private static final double MULTIPLIER_SOUL_CAMPFIRE = Settings.get(PylonKeys.PIT_KILN).getOrThrow("speed-multipliers.soul-campfire", ConfigAdapter.DOUBLE); - private static final double MULTIPLIER_FIRE = Settings.get(PylonKeys.PIT_KILN).getOrThrow("speed-multipliers.fire", ConfigAdapter.DOUBLE); - private static final double MULTIPLIER_SOUL_FIRE = Settings.get(PylonKeys.PIT_KILN).getOrThrow("speed-multipliers.soul-fire", ConfigAdapter.DOUBLE); - - private static final double MULTIPLIER_DIRT = Settings.get(PylonKeys.PIT_KILN).getOrThrow("item-multipliers.coarse-dirt", ConfigAdapter.DOUBLE); - private static final double MULTIPLIER_PODZOL = Settings.get(PylonKeys.PIT_KILN).getOrThrow("item-multipliers.podzol", ConfigAdapter.DOUBLE); - - public static final class Item extends RebarItem { - - public Item(@NotNull ItemStack stack) { - super(stack); - } - - @Override - public @NotNull List getPlaceholders() { - return List.of( - RebarArgument.of("capacity", CAPACITY), - RebarArgument.of("smelting_time", UnitFormat.formatDuration(Duration.ofSeconds(PROCESSING_TIME_SECONDS), false)), - RebarArgument.of("campfire", MULTIPLIER_CAMPFIRE), - RebarArgument.of("soul_campfire", MULTIPLIER_SOUL_CAMPFIRE), - RebarArgument.of("fire", MULTIPLIER_FIRE), - RebarArgument.of("soul_fire", MULTIPLIER_SOUL_FIRE), - RebarArgument.of("coarse_dirt", MULTIPLIER_DIRT), - RebarArgument.of("podzol", MULTIPLIER_PODZOL) - ); - } - } - - private static final NamespacedKey CONTENTS_KEY = pylonKey("contents"); - private static final PersistentDataType> CONTENTS_TYPE = - RebarSerializers.LIST.listTypeFrom(RebarSerializers.ITEM_STACK); - private static final NamespacedKey PROCESSING_KEY = pylonKey("processing"); - private static final NamespacedKey PROCESSING_TIME_KEY = pylonKey("processing_time"); - - private final ArrayList contents; - private final Set processing; - private @Nullable Double processingTime; - - @SuppressWarnings("unused") - public PitKiln(@NotNull Block block, @NotNull BlockCreateContext context) { - super(block, context); - contents = new ArrayList<>(); - processing = new HashSet<>(); - processingTime = null; - } - - @SuppressWarnings("unused") - public PitKiln(@NotNull Block block, @NotNull PersistentDataContainer pdc) { - super(block, pdc); - contents = new ArrayList<>(pdc.get(CONTENTS_KEY, CONTENTS_TYPE)); - processing = pdc.get(PROCESSING_KEY, RebarSerializers.SET.setTypeFrom(RebarSerializers.ITEM_STACK)); - processingTime = pdc.get(PROCESSING_TIME_KEY, RebarSerializers.DOUBLE); - } - - @Override - public void write(@NotNull PersistentDataContainer pdc) { - pdc.set(CONTENTS_KEY, CONTENTS_TYPE, contents); - pdc.set(PROCESSING_KEY, RebarSerializers.SET.setTypeFrom(RebarSerializers.ITEM_STACK), processing); - RebarUtils.setNullable(pdc, PROCESSING_TIME_KEY, RebarSerializers.DOUBLE, processingTime); - } - - @Override - public void onBreak(@NotNull List drops, @NotNull BlockBreakContext context) { - drops.addAll(contents); - } - - @Override - public void postBreak(@NotNull BlockBreakContext context) { - removeWailas(); - } - - @Override - @MultiHandler(priorities = {EventPriority.NORMAL, EventPriority.MONITOR}) - public void onInteract(@NotNull PlayerInteractEvent event, @NotNull EventPriority priority) { - if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.useInteractedBlock() == Event.Result.DENY || event.getHand() != EquipmentSlot.HAND) - return; - - if (priority == EventPriority.NORMAL) { - event.setUseItemInHand(Event.Result.DENY); - return; - } else { - event.setUseInteractedBlock(Event.Result.DENY); - } - - event.getPlayer().swingHand(event.getHand()); - if(!event.getPlayer().isSneaking()) { - ItemStack item = event.getItem(); - if (item == null || item.isEmpty()) { - return; - } - addItem(item, true); - } else { - if(contents.isEmpty()){ - return; - } - event.getPlayer().give(contents.removeLast()); - } - } - - public int countItems() { - int amount = 0; - for (ItemStack item : contents) { - amount += item.getAmount(); - } - return amount; - } - - /** - * Will add 1 of the type specified in the itemstack - * - * @param item specified itemstack type - * @param directRemoval if item stack passed will be decreased - */ - public void addItem(ItemStack item, boolean directRemoval) { - if (countItems() >= CAPACITY) return; - - for (ItemStack contentItem : contents) { - if (contentItem.isSimilar(item)) { - contentItem.add(); - if (directRemoval) item.subtract(); - return; - } - } - - contents.add(item.asOne()); - - if (directRemoval) item.subtract(); - } - - @Override - public void tick() { - if (!isFormedAndFullyLoaded()) { - if (processingTime != null) { - processingTime = null; - processing.clear(); - } - return; - } - if (processingTime == null) { - tryStartProcessing(); - } - - if (processingTime == null) return; - processingTime -= getTickInterval() / 20.0; - if (processingTime > 0) return; - - processingTime = null; - double calcMultiplier = 0; - for (Vector3i top : TOP_POSITIONS) { - Block topBlock = getBlock().getRelative(top.x(), top.y(), top.z()); - calcMultiplier += switch (topBlock.getType()) { - case PODZOL -> MULTIPLIER_PODZOL; - case COARSE_DIRT -> MULTIPLIER_DIRT; - default -> throw new AssertionError(); - }; - topBlock.setType(Material.COARSE_DIRT); - } - - double multiplier = calcMultiplier / TOP_POSITIONS.size(); - - outputLoop: - for (ItemStack outputItem : processing) { - int addAmount = (int) Math.floor(outputItem.getAmount() * multiplier); - for (ItemStack contentItem : contents) { - if (contentItem.isSimilar(outputItem)) { - contentItem.add(addAmount); - continue outputLoop; - } - } - contents.add(outputItem.asQuantity(addAmount)); - } - processing.clear(); - for (Vector3i coal : COAL_POSITIONS) { - Block coalBlock = getBlock().getRelative(coal.x(), coal.y(), coal.z()); - if (!(new BlockBreakBlockEvent(coalBlock, getBlock(), List.of())).callEvent()) { - continue; - } - coalBlock.setType(Material.AIR); - } - Block fireBlock = getBlock().getRelative(FIRE_POSITION.x(), FIRE_POSITION.y(), FIRE_POSITION.z()); - switch (fireBlock.getType()) { - case CAMPFIRE: - case SOUL_CAMPFIRE: - if (!(fireBlock.getBlockData() instanceof Campfire campfireData)) { - break; - } - campfireData.setLit(false); - fireBlock.getWorld().playSound(fireBlock.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 1.0F, 1.0F); - fireBlock.setBlockData(campfireData); - break; - default: - if (new BlockBreakBlockEvent(fireBlock, getBlock(), List.of()).callEvent()) { - fireBlock.getWorld().playSound(fireBlock.getLocation(), Sound.BLOCK_FIRE_EXTINGUISH, SoundCategory.BLOCKS, 1.0F, 1.0F); - fireBlock.setType(Material.AIR); - } - } - } - - @Override - public @NotNull WailaDisplay getWaila(@NotNull Player player) { - return getComponentWaila(player); - } - - private WailaDisplay getComponentWaila(@NotNull Player player) { - Component status = processingTime != null - ? Component.translatable( - "pylon.waila.pit_kiln.smelting", - RebarArgument.of( - "time", - UnitFormat.formatDuration(Duration.ofSeconds(processingTime.longValue()), false) - ) - ) - : Component.translatable("pylon.waila.pit_kiln.invalid_recipe"); - return new WailaDisplay(Component.translatable( - "pylon.item.pit_kiln.waila", - RebarArgument.of("info", status), - RebarArgument.of("nitems", countItems()) - )); - } - - @Override - public void onMultiblockFormed() { - RebarSimpleMultiblock.super.onMultiblockFormed(); - for (Vector3i relative : getComponents().keySet()) { - BlockPosition block = new BlockPosition(getBlock()).addScalar(relative.x(), relative.y(), relative.z()); - Waila.addWailaOverride(block, this::getComponentWaila); - } - } - - @Override - public void onMultiblockUnformed(boolean partUnloaded) { - RebarSimpleMultiblock.super.onMultiblockUnformed(partUnloaded); - removeWailas(); - } - - private void removeWailas() { - for (Vector3i relative : getComponents().keySet()) { - BlockPosition block = new BlockPosition(getBlock()).addScalar(relative.x(), relative.y(), relative.z()); - Waila.removeWailaOverride(block); - } - } - - private void tryStartProcessing() { - if (processingTime != null || contents.isEmpty()) return; - recipeLoop: - for (PitKilnRecipe recipe : PitKilnRecipe.RECIPE_TYPE) { - int ratio = Integer.MAX_VALUE; - for (RecipeInput.Item input : recipe.input()) { - int existing = 0; - for (ItemStack contentItem : contents) { - if (input.contains(contentItem)) { - existing = contentItem.getAmount(); - break; - } - } - int required = input.getAmount(); - if (existing < required) { - continue recipeLoop; - } - ratio = Math.min(ratio, existing / required); - } - if (ratio <= 0) continue; - - for (RecipeInput.Item input : recipe.input()) { - int removeAmount = input.getAmount() * ratio; - for (ItemStack contentItem : contents) { - if (input.contains(contentItem)) { - contentItem.subtract(removeAmount); - break; - } - } - } - Set outputItems = new HashSet<>(recipe.output().size()); - for (ItemStack outputItem : recipe.output()) { - ItemStack outputCopy = outputItem.asOne(); - outputCopy.setAmount(outputItem.getAmount() * ratio); - outputItems.add(outputCopy); - } - processing.addAll(outputItems); - double multiplier = switch (getBlock().getRelative(FIRE_POSITION.x(), FIRE_POSITION.y(), FIRE_POSITION.z()).getType()) { - case CAMPFIRE -> MULTIPLIER_CAMPFIRE; - case SOUL_CAMPFIRE -> MULTIPLIER_SOUL_CAMPFIRE; - case FIRE -> MULTIPLIER_FIRE; - case SOUL_FIRE -> MULTIPLIER_SOUL_FIRE; - default -> throw new AssertionError(); - }; - processingTime = PROCESSING_TIME_SECONDS / multiplier; - break; - } - } - - // - private static final List COAL_POSITIONS = List.of( - new Vector3i(-1, 0, -1), - new Vector3i(0, 0, -1), - new Vector3i(1, 0, -1), - new Vector3i(-1, 0, 0), - new Vector3i(1, 0, 0), - new Vector3i(-1, 0, 1), - new Vector3i(0, 0, 1), - new Vector3i(1, 0, 1) - ); - - private static final List TOP_POSITIONS = List.of( - new Vector3i(-1, 1, -1), - new Vector3i(0, 1, -1), - new Vector3i(1, 1, -1), - new Vector3i(-1, 1, 0), - new Vector3i(0, 1, 0), - new Vector3i(1, 1, 0), - new Vector3i(-1, 1, 1), - new Vector3i(0, 1, 1), - new Vector3i(1, 1, 1) - ); - - private static final Vector3i FIRE_POSITION = new Vector3i(0, -1, 0); - - @Override - public @NotNull Map getComponents() { - Map components = new HashMap<>(); - for (Vector3i coalPosition : COAL_POSITIONS) { - components.put(coalPosition, MultiblockComponent.of( - List.of(Material.COAL_BLOCK.createBlockData()), - List.of(PylonKeys.CHARCOAL_BLOCK) - ) - ); - } - for (Vector3i podzolPosition : TOP_POSITIONS) { - components.put(podzolPosition, MultiblockComponent.of(Material.COARSE_DIRT, Material.PODZOL)); - } - components.put(new Vector3i(-1, 0, -2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(0, 0, -2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(1, 0, -2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-1, 0, 2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(0, 0, 2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(1, 0, 2), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-2, 0, -1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-2, 0, 0), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-2, 0, 1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(2, 0, -1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(2, 0, 0), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(2, 0, 1), MultiblockComponent.of(Material.COARSE_DIRT)); - - components.put(new Vector3i(-1, -1, -1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(0, -1, -1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(1, -1, -1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-1, -1, 0), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(1, -1, 0), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(-1, -1, 1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(0, -1, 1), MultiblockComponent.of(Material.COARSE_DIRT)); - components.put(new Vector3i(1, -1, 1), MultiblockComponent.of(Material.COARSE_DIRT)); - - components.put(FIRE_POSITION, MultiblockComponent.of( - Material.CAMPFIRE.createBlockData("[lit=true]"), - Material.SOUL_CAMPFIRE.createBlockData("[lit=true]"), - Material.FIRE.createBlockData(), - Material.SOUL_FIRE.createBlockData() - )); - return components; - } - // -} diff --git a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryHopper.java b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryHopper.java index b6dedf2a4..8f5f68aba 100644 --- a/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryHopper.java +++ b/src/main/java/io/github/pylonmc/pylon/content/machines/smelting/SmelteryHopper.java @@ -78,7 +78,7 @@ public void tick() { if (item == null) continue; MeltingRecipe recipe = null; for (MeltingRecipe meltingRecipe : MeltingRecipe.RECIPE_TYPE) { - if (meltingRecipe.input().contains(item)) { + if (meltingRecipe.input().matchesIgnoringAmount(item)) { recipe = meltingRecipe; break; } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/CrucibleRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/CrucibleRecipe.java index f140f9726..a27f9d631 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/CrucibleRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/CrucibleRecipe.java @@ -110,8 +110,8 @@ public static boolean isValid(ItemStack item) { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(input)) - .addIngredient('m', ItemButton.from(PylonItems.CRUCIBLE)) + .addIngredient('i', ItemButton.of(input)) + .addIngredient('m', ItemButton.of(PylonItems.CRUCIBLE)) .addIngredient('h', new ItemButton(getHeatSources())) .addIngredient('o', new FluidButton(output.amountMillibuckets(), output.fluid()) ).build(); diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/CrudeAlloyFurnaceRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/CrudeAlloyFurnaceRecipe.java new file mode 100644 index 000000000..38af39db7 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/recipes/CrudeAlloyFurnaceRecipe.java @@ -0,0 +1,82 @@ +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.guide.button.ItemButton; +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.util.gui.GuiItems; +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; + + +/** + * @param input1 the first input item (respects amount) + * @param input2 the second input item (respects amount) + * @param result the output item (respects amount) + * @param timeTicks the recipe time in ticks + */ +public record CrudeAlloyFurnaceRecipe( + @NotNull NamespacedKey key, + @NotNull RecipeInput.Item input1, + @NotNull RecipeInput.Item input2, + @NotNull ItemStack result, + int timeTicks +) implements RebarRecipe { + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + + public static final RecipeType RECIPE_TYPE = new ConfigurableRecipeType<>(pylonKey("crude_alloy_furnace")) { + @Override + protected @NotNull CrudeAlloyFurnaceRecipe loadRecipe(@NotNull NamespacedKey key, @NotNull ConfigSection section) { + return new CrudeAlloyFurnaceRecipe( + key, + section.getOrThrow("input1", ConfigAdapter.RECIPE_INPUT_ITEM), + section.getOrThrow("input2", ConfigAdapter.RECIPE_INPUT_ITEM), + section.getOrThrow("result", ConfigAdapter.ITEM_STACK), + section.getOrThrow("time-ticks", ConfigAdapter.INTEGER) + ); + } + }; + + @Override + public @NotNull List getInputs() { + return List.of(input1, input2); + } + + @Override + public @NotNull List getResults() { + return List.of(FluidOrItem.of(result)); + } + + @Override + public @NotNull Gui display() { + return Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # # # # # # #", + "# # i j b o # # #", + "# # # # # # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('i', ItemButton.of(input1)) + .addIngredient('j', ItemButton.of(input2)) + .addIngredient('b', PylonItems.CRUDE_ALLOY_FURNACE) + .addIngredient('o', ItemButton.of(result)) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/FormingRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/FormingRecipe.java index 6647e33d5..b777e8ce8 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/FormingRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/FormingRecipe.java @@ -53,9 +53,9 @@ public record FormingRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(input)) - .addIngredient('m', ItemButton.from(PylonItems.FORMING_TABLE)) - .addIngredient('o', ItemButton.from(result)) + .addIngredient('i', ItemButton.of(input)) + .addIngredient('m', ItemButton.of(PylonItems.FORMING_TABLE)) + .addIngredient('o', ItemButton.of(result)) .build(); } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/GrindstoneRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/GrindstoneRecipe.java index ea6a5d80c..1e86b8d71 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/GrindstoneRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/GrindstoneRecipe.java @@ -90,8 +90,8 @@ public int timeTicks() { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('g', ItemButton.from(PylonItems.GRINDSTONE)) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('g', ItemButton.of(PylonItems.GRINDSTONE)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('c', GuiItems.progressCyclingItem(cycles * Grindstone.CYCLE_DURATION_TICKS, ItemStackBuilder.of(Material.CLOCK) .name(net.kyori.adventure.text.Component.translatable( @@ -117,7 +117,7 @@ public int timeTicks() { UnitFormat.PERCENT.format(Math.round(normalizedWeight * 100)).decimalPlaces(2)) )); stack.lore(lore); - gui.addIngredient((char) ('0' + i), ItemButton.from(stack)); + gui.addIngredient((char) ('0' + i), ItemButton.of(stack)); i++; } 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 334be707e..abe20c1fc 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/HammerRecipe.java @@ -80,9 +80,9 @@ public record HammerRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('h', new ItemButton(getHammers())) - .addIngredient('o', ItemButton.from(result)) + .addIngredient('o', ItemButton.of(result)) .build(); } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/KilnRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/KilnRecipe.java new file mode 100644 index 000000000..f9ea43460 --- /dev/null +++ b/src/main/java/io/github/pylonmc/pylon/recipes/KilnRecipe.java @@ -0,0 +1,127 @@ +package io.github.pylonmc.pylon.recipes; + +import com.google.common.base.Preconditions; +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.RebarFluid; +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.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.util.gui.GuiItems; +import io.github.pylonmc.rebar.util.gui.unit.UnitFormat; +import net.kyori.adventure.text.Component; +import org.bukkit.Material; +import org.bukkit.NamespacedKey; +import org.bukkit.inventory.ItemStack; +import org.eclipse.sisu.Nullable; +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; + + +/** + * @param input1 the first input item (respects amount) + * @param input2 the second input item (respects amount) + * @param result the output item (respects amount) + * @param timeTicks the recipe time in ticks + */ +public record KilnRecipe( + @NotNull NamespacedKey key, + @NotNull RecipeInput.Item input1, + @Nullable RecipeInput.Item input2, + @Nullable ItemStack outputItem, + @Nullable RebarFluid outputFluid, + @Nullable Double outputFluidAmount, + int timeTicks, + double temperature +) implements RebarRecipe { + + @Override + public @NotNull NamespacedKey getKey() { + return key; + } + + public static final RecipeType RECIPE_TYPE = new ConfigurableRecipeType<>(pylonKey("kiln")) { + @Override + protected @NotNull KilnRecipe loadRecipe(@NotNull NamespacedKey key, @NotNull ConfigSection section) { + + RebarFluid outputFluid = section.get("output-fluid", ConfigAdapter.REBAR_FLUID); + Double outputFluidAmount = section.get("output-fluid-amount", ConfigAdapter.DOUBLE); + Preconditions.checkState((outputFluid == null) == (outputFluidAmount == null), "Either none or both of output-fluid and output-fluid-amount should be set"); + return new KilnRecipe( + key, + section.getOrThrow("input1", ConfigAdapter.RECIPE_INPUT_ITEM), + section.get("input2", ConfigAdapter.RECIPE_INPUT_ITEM), + section.get("output-item", ConfigAdapter.ITEM_STACK), + outputFluid, + outputFluidAmount, + section.getOrThrow("time-ticks", ConfigAdapter.INTEGER), + section.getOrThrow("temperature", ConfigAdapter.DOUBLE) + ); + } + }; + + @Override + public @NotNull List getInputs() { + List inputs = new ArrayList<>(); + inputs.add(input1); + if (input2 != null) { + inputs.add(input2); + } + return inputs; + } + + @Override + public @NotNull List getResults() { + List inputs = new ArrayList<>(); + if (outputItem != null) { + inputs.add(FluidOrItem.of(outputItem)); + } + if (outputFluid != null) { + inputs.add(FluidOrItem.of(outputFluid, outputFluidAmount)); + } + return inputs; + } + + @Override + public @NotNull Gui display() { + return Gui.builder() + .setStructure( + "# # # # # # # # #", + "# # # # d # # # #", + "# i j # b # o p #", + "# # # # t # # # #", + "# # # # # # # # #" + ) + .addIngredient('#', GuiItems.backgroundBlack()) + .addIngredient('i', ItemButton.of(input1)) + .addIngredient('j', ItemButton.of(input2)) + .addIngredient('b', PylonItems.KILN) + .addIngredient('o', ItemButton.of(outputItem)) + .addIngredient('p', new FluidButton(outputFluidAmount, outputFluid)) + .addIngredient('d', GuiItems.progressCyclingItem(timeTicks, ItemStackBuilder.of(Material.CLOCK) + .name(Component.translatable( + "pylon.guide.recipe.kiln", + RebarArgument.of("time", UnitFormat.SECONDS.format(timeTicks / 20)) + )) + )) + .addIngredient('t', GuiItems.progressCyclingItem(timeTicks, ItemStackBuilder.of(Material.REDSTONE) + .name(Component.translatable( + "pylon.guide.recipe.temperature", + RebarArgument.of("temperature", UnitFormat.CELSIUS.format(temperature)) + )) + )) + .build(); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/MeltingRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/MeltingRecipe.java index 9f93e25e8..14539c6a4 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/MeltingRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/MeltingRecipe.java @@ -69,8 +69,8 @@ public record MeltingRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('h', ItemButton.from(PylonItems.SMELTERY_HOPPER)) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('h', ItemButton.of(PylonItems.SMELTERY_HOPPER)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('t', ItemStackBuilder.of(Material.BLAZE_POWDER) .name(Component.translatable( "pylon.guide.recipe.melting", diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/MixingPotRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/MixingPotRecipe.java index fdc2918e6..dbf3a3183 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/MixingPotRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/MixingPotRecipe.java @@ -102,16 +102,16 @@ public boolean matches( ) .addIngredient('#', GuiItems.backgroundBlack()) .addIngredient('f', new FluidButton(inputFluid)) - .addIngredient('m', ItemButton.from(PylonItems.MIXING_POT)) + .addIngredient('m', ItemButton.of(PylonItems.MIXING_POT)) .addIngredient('i', requiresEnrichedFire - ? ItemButton.from(PylonItems.ENRICHED_SOUL_SOIL) + ? ItemButton.of(PylonItems.ENRICHED_SOUL_SOIL) : GuiItems.background() ); builder.addIngredient( 'o', switch (output) { - case FluidOrItem.Item item -> ItemButton.from(item.item()); + case FluidOrItem.Item item -> ItemButton.of(item.item()); case FluidOrItem.Fluid fluid -> new FluidButton(fluid.amountMillibuckets(), fluid.fluid()); default -> throw new AssertionError(); } @@ -121,7 +121,7 @@ public boolean matches( int i = 0; for (RecipeInput.Item input : inputItems) { - gui.setItem(10 + ((i / 3) * 9) + i % 3, ItemButton.from(input)); + gui.setItem(10 + ((i / 3) * 9) + i % 3, ItemButton.of(input)); i++; } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/PipeBendingRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/PipeBendingRecipe.java index 36f40b7a4..2d7ca3bc1 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/PipeBendingRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/PipeBendingRecipe.java @@ -70,9 +70,9 @@ public record PipeBendingRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('b', GuiItems.progressCyclingItem(timeTicks, ItemStackBuilder.of(PylonItems.HYDRAULIC_PIPE_BENDER))) - .addIngredient('o', ItemButton.from(result)) + .addIngredient('o', ItemButton.of(result)) .build(); } } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/PitKilnRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/PitKilnRecipe.java deleted file mode 100644 index 0d80dab19..000000000 --- a/src/main/java/io/github/pylonmc/pylon/recipes/PitKilnRecipe.java +++ /dev/null @@ -1,82 +0,0 @@ -package io.github.pylonmc.pylon.recipes; - -import com.google.common.base.Preconditions; -import io.github.pylonmc.pylon.PylonItems; -import io.github.pylonmc.pylon.content.machines.smelting.PitKiln; -import io.github.pylonmc.rebar.config.ConfigSection; -import io.github.pylonmc.rebar.config.adapter.ConfigAdapter; -import io.github.pylonmc.rebar.guide.button.ItemButton; -import io.github.pylonmc.rebar.recipe.*; -import io.github.pylonmc.rebar.util.gui.GuiItems; -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 record PitKilnRecipe( - @NotNull NamespacedKey key, - @NotNull List input, - @NotNull List output -) implements RebarRecipe { - - public static final RecipeType RECIPE_TYPE = new ConfigurableRecipeType<>(pylonKey("pit_kiln")) { - @Override - protected @NotNull PitKilnRecipe loadRecipe(@NotNull NamespacedKey key, @NotNull ConfigSection section) { - return new PitKilnRecipe( - key, - section.getOrThrow("inputs", ConfigAdapter.LIST.from(ConfigAdapter.RECIPE_INPUT_ITEM)), - section.getOrThrow("outputs", ConfigAdapter.LIST.from(ConfigAdapter.ITEM_STACK)) - ); - } - }; - - public PitKilnRecipe { - Preconditions.checkArgument(!input.isEmpty(), "Input cannot be empty"); - Preconditions.checkArgument(input.size() <= PitKiln.CAPACITY, "Input cannot exceed the pit kiln's capacity of %s".formatted(PitKiln.CAPACITY)); - Preconditions.checkArgument(!output.isEmpty(), "Output cannot be empty"); - Preconditions.checkArgument(output.size() <= input.size(), "Output cannot exceed input size"); - } - - @Override - public @NotNull List getInputs() { - return new ArrayList<>(input); - } - - @Override - public @NotNull List getResults() { - return output.stream().map(FluidOrItem::of).toList(); - } - - @Override - public @NotNull Gui display() { - var gui = Gui.builder() - .setStructure( - "# # # # # # # # #", - "# 0 1 # # # a b #", - "# 2 3 # p # c d #", - "# 4 5 # # # e f #", - "# # # # # # # # #" - ) - .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('p', ItemButton.from(PylonItems.PIT_KILN)); - for (int i = 0; i < 6; i++) { - if (i >= input().size()) break; - gui.addIngredient((char) ('0' + i), ItemButton.from(input.get(i))); - } - for (int i = 0; i < 6; i++) { - if (i >= output().size()) break; - gui.addIngredient((char) ('a' + i), ItemButton.from(output.get(i))); - } - return gui.build(); - } - - @Override - public @NotNull NamespacedKey getKey() { - return key; - } -} diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/PressRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/PressRecipe.java index 823cd35b1..6795d82b9 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/PressRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/PressRecipe.java @@ -67,8 +67,8 @@ public record PressRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('p', ItemButton.from(PylonItems.PRESS)) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('p', ItemButton.of(PylonItems.PRESS)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('c', GuiItems.progressCyclingItem(Press.TIME_PER_ITEM_TICKS, ItemStackBuilder.of(Material.CLOCK) .name(net.kyori.adventure.text.Component.translatable( diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/ShimmerAltarRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/ShimmerAltarRecipe.java index 9d281a13b..0dcc4c685 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/ShimmerAltarRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/ShimmerAltarRecipe.java @@ -159,16 +159,16 @@ public boolean isValidRecipe(List ingredients, ItemStack catalyst) { "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('m', ItemButton.from(PylonItems.SHIMMER_ALTAR)) - .addIngredient('c', ItemButton.from(catalyst)) - .addIngredient('0', ItemButton.from(inputs.get(0))) - .addIngredient('1', ItemButton.from(inputs.get(1))) - .addIngredient('2', ItemButton.from(inputs.get(2))) - .addIngredient('3', ItemButton.from(inputs.get(3))) - .addIngredient('4', ItemButton.from(inputs.get(4))) - .addIngredient('5', ItemButton.from(inputs.get(5))) - .addIngredient('6', ItemButton.from(inputs.get(6))) - .addIngredient('7', ItemButton.from(inputs.get(7))) + .addIngredient('m', ItemButton.of(PylonItems.SHIMMER_ALTAR)) + .addIngredient('c', ItemButton.of(catalyst)) + .addIngredient('0', ItemButton.of(inputs.get(0))) + .addIngredient('1', ItemButton.of(inputs.get(1))) + .addIngredient('2', ItemButton.of(inputs.get(2))) + .addIngredient('3', ItemButton.of(inputs.get(3))) + .addIngredient('4', ItemButton.of(inputs.get(4))) + .addIngredient('5', ItemButton.of(inputs.get(5))) + .addIngredient('6', ItemButton.of(inputs.get(6))) + .addIngredient('7', ItemButton.of(inputs.get(7))) .addIngredient('t', GuiItems.progressCyclingItem((int) (timeSeconds * 20), ItemStackBuilder.of(Material.CLOCK) .name(net.kyori.adventure.text.Component.translatable( @@ -176,7 +176,7 @@ public boolean isValidRecipe(List ingredients, ItemStack catalyst) { RebarArgument.of("time", UnitFormat.SECONDS.format(timeSeconds)) )) )) - .addIngredient('r', ItemButton.from(result)) + .addIngredient('r', ItemButton.of(result)) .build(); } } diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/SmelteryRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/SmelteryRecipe.java index 16d11f4fc..c314032de 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/SmelteryRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/SmelteryRecipe.java @@ -129,7 +129,7 @@ public SmelteryRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('s', ItemButton.from(PylonItems.SMELTERY_CONTROLLER)) + .addIngredient('s', ItemButton.of(PylonItems.SMELTERY_CONTROLLER)) .addIngredient('t', ItemStackBuilder.of(Material.COAL) .name(Component.translatable( "pylon.gui.smeltery.temperature", diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/StrainingRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/StrainingRecipe.java index b7d41f775..4d7a0b4ee 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/StrainingRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/StrainingRecipe.java @@ -75,7 +75,7 @@ public record StrainingRecipe( .addIngredient('i', new FluidButton(input)) .addIngredient('s', PylonItems.FLUID_STRAINER) .addIngredient('o', new FluidButton(input.amountMillibuckets(), outputFluid)) - .addIngredient('t', ItemButton.from(outputItem)) + .addIngredient('t', ItemButton.of(outputItem)) .build(); } } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/recipes/TableSawRecipe.java b/src/main/java/io/github/pylonmc/pylon/recipes/TableSawRecipe.java index 4e9da7959..fc9749a22 100644 --- a/src/main/java/io/github/pylonmc/pylon/recipes/TableSawRecipe.java +++ b/src/main/java/io/github/pylonmc/pylon/recipes/TableSawRecipe.java @@ -70,9 +70,9 @@ public record TableSawRecipe( "# # # # # # # # #" ) .addIngredient('#', GuiItems.backgroundBlack()) - .addIngredient('i', ItemButton.from(input)) + .addIngredient('i', ItemButton.of(input)) .addIngredient('s', GuiItems.progressCyclingItem(timeTicks, ItemStackBuilder.of(PylonItems.HYDRAULIC_TABLE_SAW))) - .addIngredient('o', ItemButton.from(result)) + .addIngredient('o', ItemButton.of(result)) .build(); } } \ No newline at end of file diff --git a/src/main/java/io/github/pylonmc/pylon/util/PylonUtils.java b/src/main/java/io/github/pylonmc/pylon/util/PylonUtils.java index 11d72958f..eeb38d299 100644 --- a/src/main/java/io/github/pylonmc/pylon/util/PylonUtils.java +++ b/src/main/java/io/github/pylonmc/pylon/util/PylonUtils.java @@ -30,6 +30,7 @@ import org.jetbrains.annotations.Nullable; import org.joml.Matrix4f; import org.joml.Vector3d; +import org.jspecify.annotations.NonNull; import java.util.Map; import java.util.function.Consumer; @@ -99,6 +100,10 @@ public void drawParticleLine( return Color.fromRGB(r, g, b); } + public @NotNull TextColor colorToTextColor(@NonNull Color color) { + return TextColor.color(color.getRed(), color.getGreen(), color.getBlue()); + } + private int clampAndRound(double value) { int rounded = (int) Math.round(value); return Math.max(0, Math.min(255, rounded)); diff --git a/src/main/resources/lang/en.yml b/src/main/resources/lang/en.yml index 4465734df..9a2c5c073 100644 --- a/src/main/resources/lang/en.yml +++ b/src/main/resources/lang/en.yml @@ -244,6 +244,15 @@ item: Fluid: %fluid_per_second% Temperatures: %temperatures% + fluid_pipe_obsidian: + name: "Obsidian Fluid Pipe" + lore: |- + Right click a connection point, another pipe, or a block to start placing + Right click a placed pipe with a block to make it look like that block + You can only connect pipes of the same type + Fluid: %fluid_per_second% + Temperatures: %temperatures% + fluid_pipe_igneous_composite: name: "Igneous Composite Fluid Pipe" lore: |- @@ -337,15 +346,25 @@ item: Allowed temperatures: %temperatures% waila: "Bronze Portable Fluid Tank | %bars% (%fluid%)" + portable_fluid_tank_obsidian: + name: "Obsidian Portable Fluid Tank" + lore: |- + Can be placed down and connected with pipes + Retains contents when broken + Right click with a bucket to add/remove fluids (only works with water or lava) + Fluid: %amount%/%capacity% (%fluid%) + Allowed temperatures: %temperatures% + waila: "Igneous Composite Portable Fluid Tank | %bars% (%fluid%)" + portable_fluid_tank_igneous_composite: - name: "Igneous Composite Portable Fluid Tank" - lore: |- - Can be placed down and connected with pipes - Retains contents when broken - Right click with a bucket to add/remove fluids (only works with water or lava) - Fluid: %amount%/%capacity% (%fluid%) - Allowed temperatures: %temperatures% - waila: "Igneous Composite Portable Fluid Tank | %bars% (%fluid%)" + name: "Igneous Composite Portable Fluid Tank" + lore: |- + Can be placed down and connected with pipes + Retains contents when broken + Right click with a bucket to add/remove fluids (only works with water or lava) + Fluid: %amount%/%capacity% (%fluid%) + Allowed temperatures: %temperatures% + waila: "Igneous Composite Portable Fluid Tank | %bars% (%fluid%)" portable_fluid_tank_steel: name: "Steel Portable Fluid Tank" @@ -687,29 +706,6 @@ item: Right click to set the displayed item Shift right click to rotate the item - pit_kiln: - name: "Pit Kiln" - lore: |- - Multiblock - A primitive and inefficient high-temperature smelting method - Right click to insert items - Break to retrieve the items - Complete the multiblock with a valid recipe inside to start the smelting process - Capacity: %capacity% items - Smelting time: %smelting_time% - - Components - 1x - 8x Block of Coal - 20x Coarse Dirt - 1x Campfire (%campfire%x speed) - ...or 1x Fire (%fire%x speed) - ...or 1x Soul Campfire (%soul_campfire%x speed) - ...or 1x Soul Fire (%soul_fire%x speed) - 9x Podzol (%podzol%x yield) - ...or 9x Coarse Dirt (%coarse_dirt%x yield) - waila: "Pit Kiln | %info% | %nitems% items" - portability_catalyst: name: "Portability Catalyst" @@ -1323,6 +1319,13 @@ item: Capacity: %capacity% Temperatures: %temperatures% + fluid_tank_casing_obsidian: + name: "Obsidian Fluid Tank Casing" + lore: |- + Fluid Tank multiblock component + Capacity: %capacity% + Temperatures: %temperatures% + fluid_tank_casing_igneous_composite: name: "Igneous Composite Fluid Tank Casing" lore: |- @@ -2364,6 +2367,36 @@ item: waila: "Palladium Condenser | %duration-if-any%" waila_format: "| %duration%" + crude_alloy_furnace: + name: "Crude Alloy Furnace" + lore: |- + Smelts alloys + Crude and inefficient, but does the job + waila: "Crude Alloy Furnace%info%" + info: " | %progress%" + + kiln: + name: "Kiln" + lore: |- + A more efficient way to smelt metals + Each kiln recipe has a minimum temperature + Constantly burns fuel to heat itself up + Takes time to heat up and cool down + + Components + 1x + 1x + 1x + 1x + 2x + 6x Mud Bricks + 12x Mud Brick Wall + + waila: "Kiln | %temperature-bar% %temperature%%progress%" + + slag: + name: "Slag" + wooden_silo: name: "Wooden Silo" lore: |- @@ -2553,9 +2586,7 @@ waila: cargo_splitter: left: "<#efae15>Left" right: "<#2386c4>Right" - pit_kiln: - invalid_recipe: "Invalid recipe" - smelting: "%time% remaining" + kiln: " | %progress%" research: baking: "<#e2b42b>Baking" @@ -2589,6 +2620,7 @@ research: smelting_1: "<#ff6b0f>Smelting I" smelting_2: "<#ff6b0f>Smelting II" smelting_3: "<#ff6b0f>Smelting III" + smelting_4: "<#ff6b0f>Smelting IV" drilling_1: "<#4f4641>Drilling I" drilling_2: "<#4f4641>Drilling II" drilling_3: "<#4f4641>Drilling III" @@ -2689,10 +2721,10 @@ guide: chance: "Chance: %chance%" press: "Pressing time: %time%" magic-altar: "Ritual time: %time%" - melting: "Temperature: %temperature%" - casting: "Temperature: %temperature%" + temperature: "Temperature: %temperature%" drilling: "Cycle time: %time%" molding: "Molding cycles: %molding-cycles%" + kiln: "Melting time: %time%" hammer: "Uses: %uses%" button: info: @@ -2711,9 +2743,6 @@ guide: manual_core: name: "Manual Core" lore: "" - pit_kiln: - name: "Pit Kiln" - lore: "" bronze_age: name: "Bronze Age" lore: "" @@ -2738,17 +2767,6 @@ guide: palladium_flight_ring: name: "Palladium Flight Ring" lore: "" - pit_kiln: - kiln: - name: "The Pit Kiln" - lore: |- - The pit kiln is the earliest form of advanced smelting available to you - construction: - name: "Constructing the Pit Kiln" - lore: "" - crafting: - name: "Crafting with the Pit Kiln" - lore: "" bloomery: bloomer: name: "The Bloomery" @@ -2762,7 +2780,7 @@ message: clear: "Clear" fluid_hatch: no_casing: "No casing" - no_multiblock: "No multiblock" + no_fluid: "No fluid" working: "%bars% (%fluid%)" biorefinery: no_fuel: "No fuel" @@ -2842,6 +2860,7 @@ gui: left: "Left" right: "Right" none: "None" + fuel: "Fuel" side-priority: name: "Priority: %priority%" lore: |- @@ -2951,6 +2970,12 @@ gui: hammer: "Hammer" screwdriver: "Screwdriver" redstone_soldering_iron: "Redstone Soldering Iron" + fuel-left: "Fuel left" + no-fuel-left: "No fuel" + no-recipe: "No recipe" + temperature: "Temperature" + kiln: + temperature: " Temperature: %temperature%" cast-border: "Mold Item" casting-control: name: "Casting Control" @@ -2975,3 +3000,6 @@ inventory: right: "Right" filtered: "Filtered" unfiltered: "Unfiltered" + input1: "Input 1" + input2: "Input 2" + input3: "Input 3" diff --git a/src/main/resources/recipes/minecraft/crafting_shaped.yml b/src/main/resources/recipes/minecraft/crafting_shaped.yml index 5fe14fcf8..918b2e2e8 100644 --- a/src/main/resources/recipes/minecraft/crafting_shaped.yml +++ b/src/main/resources/recipes/minecraft/crafting_shaped.yml @@ -510,6 +510,17 @@ pylon:fluid_pipe_bronze: pylon:fluid_pipe_bronze: 8 category: building +pylon:fluid_pipe_obsidian: + pattern: + - "OOO" + - " " + - "OOO" + key: + O: minecraft:obsidian + result: + pylon:fluid_pipe_obsidian: 8 + category: building + pylon:fluid_pipe_igneous_composite: pattern: - "OOO" @@ -599,6 +610,17 @@ pylon:portable_fluid_tank_bronze: result: pylon:portable_fluid_tank_bronze category: building +pylon:portable_fluid_tank_obsidian: + pattern: + - "CGC" + - "G G" + - "CGC" + key: + C: minecraft:obsidian + G: minecraft:glass_pane + result: pylon:portable_fluid_tank_obsidian + category: building + pylon:portable_fluid_tank_igneous_composite: pattern: - "CGC" @@ -699,6 +721,17 @@ pylon:fluid_tank_casing_bronze: result: pylon:fluid_tank_casing_bronze category: building +pylon:fluid_tank_casing_obsidian: + pattern: + - "G G" + - "C C" + - "G G" + key: + C: minecraft:obsidian + G: minecraft:glass_pane + result: pylon:fluid_tank_casing_obsidian + category: building + pylon:fluid_tank_casing_igneous_composite: pattern: - "G G" @@ -1150,14 +1183,28 @@ pylon:smeltery_burner: result: pylon:smeltery_burner category: building -pylon:pit_kiln: +pylon:crude_alloy_furnace: pattern: - - "B B" - - "B B" + - "BBB" + - "CFC" - "BBB" + key: + B: minecraft:brick + C: minecraft:copper_ingot + F: minecraft:blast_furnace + result: pylon:crude_alloy_furnace + category: building + +pylon:kiln: + pattern: + - "MBM" + - "BFB" + - "MBM" key: B: minecraft:bricks - result: pylon:pit_kiln + M: minecraft:mud_bricks + F: minecraft:blast_furnace + result: pylon:kiln category: building pylon:explosive_target: diff --git a/src/main/resources/recipes/pylon/crude_alloy_furnace.yml b/src/main/resources/recipes/pylon/crude_alloy_furnace.yml new file mode 100644 index 000000000..28502040f --- /dev/null +++ b/src/main/resources/recipes/pylon/crude_alloy_furnace.yml @@ -0,0 +1,8 @@ +pylon:crude_bronze: + input1: + minecraft:copper_ingot: 2 + input2: + pylon:tin_ingot: 1 + result: + pylon:bronze_ingot: 2 + time-ticks: 320 \ No newline at end of file diff --git a/src/main/resources/recipes/pylon/grindstone.yml b/src/main/resources/recipes/pylon/grindstone.yml index 277c20581..e6d3aa56d 100644 --- a/src/main/resources/recipes/pylon/grindstone.yml +++ b/src/main/resources/recipes/pylon/grindstone.yml @@ -188,11 +188,20 @@ pylon:blaze_powder: minecraft:blaze_powder: 3 cycles: 5 -pylon:fine_sediment: +pylon:fine_sediment_from_sand: input: minecraft:sand results: pylon:fine_sediment: 3 cycles: 1 + particle-data: minecraft:sand + +pylon:gravel_from_slag: + input: pylon:slag + results: + minecraft:gravel: 3 + cycles: 1 + priority: -1 + particle-data: minecraft:gray_concrete pylon:clay_ball: input: minecraft:clay diff --git a/src/main/resources/recipes/pylon/kiln.yml b/src/main/resources/recipes/pylon/kiln.yml new file mode 100644 index 000000000..e0994982b --- /dev/null +++ b/src/main/resources/recipes/pylon/kiln.yml @@ -0,0 +1,77 @@ +pylon:sulfur: + input1: minecraft:redstone + output-fluid: pylon:sulfur + output-fluid-amount: 100 + output-item: pylon:slag + temperature: 115 + time-ticks: 80 + +pylon:bronze: + input1: + minecraft:copper_ingot: 2 + input2: + pylon:tin_ingot: 1 + output-fluid: pylon:bronze + output-fluid-amount: 432 + output-item: + pylon:slag: 2 + temperature: 950 + time-ticks: 240 + priority: 1 + +pylon:coal_to_carbon: + input1: + pylon:coal_dust: 2 + output-item: pylon:carbon + temperature: 1020 + time-ticks: 180 + +pylon:refractory_brick: + input1: pylon:unfired_refractory_brick + output-item: pylon:refractory_brick + temperature: 1180 + time-ticks: 300 + +pylon:tin_melting: + input1: + pylon:crushed_raw_tin: 2 + output-fluid: pylon:tin + output-fluid-amount: 432 + output-item: + pylon:slag: 2 + temperature: 230 + time-ticks: 180 + priority: 1 + +pylon:copper_melting: + input1: + pylon:crushed_raw_copper: 2 + output-fluid: pylon:copper + output-fluid-amount: 432 + output-item: + pylon:slag: 2 + temperature: 1080 + time-ticks: 180 + priority: 1 + +pylon:iron_melting: + input1: + pylon:crushed_raw_iron: 2 + output-fluid: pylon:iron + output-fluid-amount: 432 + output-item: + pylon:slag: 2 + temperature: 1060 + time-ticks: 180 + priority: 1 + +pylon:gold_melting: + input1: + pylon:crushed_raw_gold: 2 + output-fluid: pylon:iron + output-fluid-amount: 432 + output-item: + pylon:slag: 2 + temperature: 1060 + time-ticks: 180 + priority: 1 diff --git a/src/main/resources/recipes/pylon/pit_kiln.yml b/src/main/resources/recipes/pylon/pit_kiln.yml deleted file mode 100644 index 1caeddac8..000000000 --- a/src/main/resources/recipes/pylon/pit_kiln.yml +++ /dev/null @@ -1,37 +0,0 @@ -pylon:coal_to_carbon: - inputs: - - pylon:coal_dust: 2 - outputs: - - pylon:carbon - -pylon:redstone_smelting: - inputs: - - minecraft:redstone - outputs: - - pylon:sulfur - priority: 1 - -pylon:bronze: - inputs: - - minecraft:copper_ingot: 2 - - pylon:tin_ingot - outputs: - - pylon:bronze_ingot: 2 - -pylon:copper_smelting: - inputs: - - pylon:crushed_raw_copper - outputs: - - minecraft:copper_ingot - -pylon:gold_smelting: - inputs: - - pylon:crushed_raw_gold - outputs: - - minecraft:gold_ingot - -pylon:refractory_brick: - inputs: - - pylon:unfired_refractory_brick - outputs: - - pylon:refractory_brick \ No newline at end of file diff --git a/src/main/resources/recipes/pylon/smeltery.yml b/src/main/resources/recipes/pylon/smeltery.yml index 128e303fb..d4d84c82b 100644 --- a/src/main/resources/recipes/pylon/smeltery.yml +++ b/src/main/resources/recipes/pylon/smeltery.yml @@ -1,7 +1,7 @@ pylon:bronze: inputs: - pylon:copper: 0.88 - pylon:tin: 0.12 + pylon:copper: 0.85 + pylon:tin: 0.15 outputs: pylon:bronze: 1 temperature: 950 diff --git a/src/main/resources/researches.yml b/src/main/resources/researches.yml index 3980f19ab..54f639426 100644 --- a/src/main/resources/researches.yml +++ b/src/main/resources/researches.yml @@ -99,10 +99,7 @@ smelting_1: item: pylon:smeltery_controller cost: 5 unlocks: - - pylon:pit_kiln - - pylon:carbon - - pylon:sulfur - - pylon:sulfur_block + - pylon:crude_alloy_kiln - pylon:bronze_ingot - pylon:bronze_dust - pylon:bronze_sheet @@ -110,6 +107,15 @@ smelting_1: - pylon:bronze_block smelting_2: + item: pylon:smeltery_controller + cost: 20 + unlocks: + - pylon:kiln + - pylon:carbon + - pylon:sulfur + - pylon:sulfur_block + +smelting_3: item: pylon:smeltery_controller cost: 35 unlocks: @@ -138,7 +144,7 @@ smelting_2: - pylon:mold_pipe - pylon:forming_table -smelting_3: +smelting_4: item: pylon:smeltery_controller cost: 50 unlocks: @@ -197,7 +203,7 @@ irrigation: fluid_handling_1: item: pylon:fluid_pipe_copper - cost: 10 + cost: 5 unlocks: - pylon:fluid_pipe_copper - pylon:portable_fluid_tank_copper @@ -208,7 +214,7 @@ fluid_handling_1: fluid_handling_2: item: pylon:fluid_pipe_copper - cost: 20 + cost: 10 unlocks: - pylon:fluid_pipe_bronze - pylon:portable_fluid_tank_bronze @@ -221,8 +227,11 @@ fluid_handling_2: fluid_handling_3: item: pylon:fluid_pipe_copper - cost: 30 + cost: 20 unlocks: + - pylon:fluid_pipe_obsidian + - pylon:portable_fluid_tank_obsidian + - pylon:fluid_tank_casing_obsidian - pylon:fluid_pipe_igneous_composite - pylon:portable_fluid_tank_igneous_composite - pylon:fluid_tank_casing_igneous_composite diff --git a/src/main/resources/settings/crude_alloy_furnace.yml b/src/main/resources/settings/crude_alloy_furnace.yml new file mode 100644 index 000000000..eadac4ca6 --- /dev/null +++ b/src/main/resources/settings/crude_alloy_furnace.yml @@ -0,0 +1 @@ +tick-interval: 10 \ No newline at end of file diff --git a/src/main/resources/settings/fluid_pipe_igneous_composite.yml b/src/main/resources/settings/fluid_pipe_igneous_composite.yml index a9e4e3287..2d570e6c7 100644 --- a/src/main/resources/settings/fluid_pipe_igneous_composite.yml +++ b/src/main/resources/settings/fluid_pipe_igneous_composite.yml @@ -1,3 +1,3 @@ material: black_terracotta -fluid-per-second: 200.0 +fluid-per-second: 500.0 allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/fluid_pipe_obsidian.yml b/src/main/resources/settings/fluid_pipe_obsidian.yml new file mode 100644 index 000000000..be79a9a70 --- /dev/null +++ b/src/main/resources/settings/fluid_pipe_obsidian.yml @@ -0,0 +1,3 @@ +material: black_terracotta +fluid-per-second: 300.0 +allowed-temperatures: [hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/fluid_tank_casing_igneous_composite.yml b/src/main/resources/settings/fluid_tank_casing_igneous_composite.yml index c7c5b1585..a3c732651 100644 --- a/src/main/resources/settings/fluid_tank_casing_igneous_composite.yml +++ b/src/main/resources/settings/fluid_tank_casing_igneous_composite.yml @@ -1,2 +1,2 @@ -capacity: 6000.0 +capacity: 15000.0 allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/fluid_tank_casing_obsidian.yml b/src/main/resources/settings/fluid_tank_casing_obsidian.yml new file mode 100644 index 000000000..e96f9fb13 --- /dev/null +++ b/src/main/resources/settings/fluid_tank_casing_obsidian.yml @@ -0,0 +1,2 @@ +capacity: 9000.0 +allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/fluid_tank_casing_steel.yml b/src/main/resources/settings/fluid_tank_casing_steel.yml index a3c732651..1e9c9d9fd 100644 --- a/src/main/resources/settings/fluid_tank_casing_steel.yml +++ b/src/main/resources/settings/fluid_tank_casing_steel.yml @@ -1,2 +1,2 @@ -capacity: 15000.0 +capacity: 24000.0 allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/kiln.yml b/src/main/resources/settings/kiln.yml new file mode 100644 index 000000000..04a7efedd --- /dev/null +++ b/src/main/resources/settings/kiln.yml @@ -0,0 +1,4 @@ +tick-interval: 10 +min-temperature: 20 +max-temperature: 1200 +heating-rate: 60.0 diff --git a/src/main/resources/settings/portable_fluid_tank_igneous_composite.yml b/src/main/resources/settings/portable_fluid_tank_igneous_composite.yml index 246852332..ca5d29c52 100644 --- a/src/main/resources/settings/portable_fluid_tank_igneous_composite.yml +++ b/src/main/resources/settings/portable_fluid_tank_igneous_composite.yml @@ -1,2 +1,2 @@ -capacity: 4000.0 +capacity: 10000.0 allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/portable_fluid_tank_obsidian.yml b/src/main/resources/settings/portable_fluid_tank_obsidian.yml new file mode 100644 index 000000000..9d2bb0717 --- /dev/null +++ b/src/main/resources/settings/portable_fluid_tank_obsidian.yml @@ -0,0 +1,2 @@ +capacity: 6000.0 +allowed-temperatures: [hot] # can be cold (cryogenic), normal, or hot (molten) diff --git a/src/main/resources/settings/portable_fluid_tank_steel.yml b/src/main/resources/settings/portable_fluid_tank_steel.yml index ca5d29c52..e8ee1198e 100644 --- a/src/main/resources/settings/portable_fluid_tank_steel.yml +++ b/src/main/resources/settings/portable_fluid_tank_steel.yml @@ -1,2 +1,2 @@ -capacity: 10000.0 +capacity: 16000.0 allowed-temperatures: [normal, hot] # can be cold (cryogenic), normal, or hot (molten)