diff --git a/src/main/kotlin/com/coderjoe/atlas/Atlas.kt b/src/main/kotlin/com/coderjoe/atlas/Atlas.kt index 50507be..27e83ee 100644 --- a/src/main/kotlin/com/coderjoe/atlas/Atlas.kt +++ b/src/main/kotlin/com/coderjoe/atlas/Atlas.kt @@ -181,7 +181,10 @@ class Atlas : JavaPlugin() { com.coderjoe.atlas.power.block.PowerCable.descriptor, com.coderjoe.atlas.power.block.LavaGenerator.descriptor, com.coderjoe.atlas.power.block.AutoSmelter.descriptor, - com.coderjoe.atlas.power.block.MultiPowerCable.descriptor + com.coderjoe.atlas.power.block.MultiPowerCable.descriptor, + com.coderjoe.atlas.power.block.CobblestoneGenerator.descriptor, + com.coderjoe.atlas.power.block.ObsidianGenerator.descriptor, + com.coderjoe.atlas.power.block.PowerMerger.descriptor ).associateBy { it.baseBlockId } } @@ -189,7 +192,8 @@ class Atlas : JavaPlugin() { return listOf( com.coderjoe.atlas.fluid.block.FluidPump.descriptor, com.coderjoe.atlas.fluid.block.FluidPipe.descriptor, - com.coderjoe.atlas.fluid.block.FluidContainer.descriptor + com.coderjoe.atlas.fluid.block.FluidContainer.descriptor, + com.coderjoe.atlas.fluid.block.FluidMerger.descriptor ).associateBy { it.baseBlockId } } } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt index 75b5eb1..d7c6c13 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt @@ -4,6 +4,7 @@ import com.coderjoe.atlas.core.AtlasBlockDialog import com.coderjoe.atlas.core.BlockRegistry import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.fluid.block.FluidMerger import com.coderjoe.atlas.fluid.block.FluidPump import io.papermc.paper.dialog.Dialog import io.papermc.paper.registry.data.dialog.ActionButton @@ -71,6 +72,7 @@ object FluidBlockDialog { is FluidPump -> "Fluid Pump" is FluidPipe -> "Fluid Pipe (${fluidBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" is FluidContainer -> "Fluid Container (${fluidBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" + is FluidMerger -> "Fluid Merger (${fluidBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" else -> "Fluid Block" } @@ -107,6 +109,8 @@ object FluidBlockDialog { .color(NamedTextColor.GRAY) is FluidContainer -> Component.text("Container - stores up to ${FluidContainer.MAX_CAPACITY} units of fluid") .color(NamedTextColor.GRAY) + is FluidMerger -> Component.text("Merger - merges fluid from all sides, outputs in facing direction") + .color(NamedTextColor.GRAY) else -> Component.text("Fluid block") .color(NamedTextColor.GRAY) } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt index 67d8df8..9a1af2f 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt @@ -160,6 +160,16 @@ class FluidContainer(location: Location, override val facing: BlockFace) : Fluid } } } + is FluidMerger -> { + if (source.hasFluid()) { + val fluid = source.removeFluid() + if (storeFluid(fluid)) { + plugin.logger.atlasInfo("FluidContainer at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidMerger") + } else { + source.storeFluid(fluid) + } + } + } } } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidMerger.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidMerger.kt new file mode 100644 index 0000000..0fca43d --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidMerger.kt @@ -0,0 +1,117 @@ +package com.coderjoe.atlas.fluid.block + +import com.coderjoe.atlas.atlasInfo +import com.coderjoe.atlas.core.BlockDescriptor +import com.coderjoe.atlas.core.PlacementType +import com.coderjoe.atlas.fluid.FluidBlock +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import org.bukkit.Location +import org.bukkit.block.BlockFace + +class FluidMerger(location: Location, override val facing: BlockFace) : FluidBlock(location) { + + override val updateIntervalTicks: Long = 20L + + companion object { + const val BLOCK_ID = "fluid_merger" + + val DIRECTIONAL_IDS = mapOf( + BlockFace.NORTH to "fluid_merger_north", + BlockFace.SOUTH to "fluid_merger_south", + BlockFace.EAST to "fluid_merger_east", + BlockFace.WEST to "fluid_merger_west", + BlockFace.UP to "fluid_merger_up", + BlockFace.DOWN to "fluid_merger_down" + ) + + val WATER_FILLED_IDS = mapOf( + BlockFace.NORTH to "fluid_merger_north_filled", + BlockFace.SOUTH to "fluid_merger_south_filled", + BlockFace.EAST to "fluid_merger_east_filled", + BlockFace.WEST to "fluid_merger_west_filled", + BlockFace.UP to "fluid_merger_up_filled", + BlockFace.DOWN to "fluid_merger_down_filled" + ) + + val LAVA_FILLED_IDS = mapOf( + BlockFace.NORTH to "fluid_merger_north_filled_lava", + BlockFace.SOUTH to "fluid_merger_south_filled_lava", + BlockFace.EAST to "fluid_merger_east_filled_lava", + BlockFace.WEST to "fluid_merger_west_filled_lava", + BlockFace.UP to "fluid_merger_up_filled_lava", + BlockFace.DOWN to "fluid_merger_down_filled_lava" + ) + + val ID_TO_FACING = DIRECTIONAL_IDS.entries.associate { (face, id) -> id to face } + + fun facingFromBlockId(blockId: String): BlockFace? = ID_TO_FACING[blockId] + + val descriptor = BlockDescriptor( + baseBlockId = BLOCK_ID, + displayName = "Fluid Merger", + description = "Merger - merges fluid from all sides, outputs in facing direction", + placementType = PlacementType.DIRECTIONAL, + directionalVariants = DIRECTIONAL_IDS, + allRegistrableIds = DIRECTIONAL_IDS.values.toList() + WATER_FILLED_IDS.values.toList() + LAVA_FILLED_IDS.values.toList(), + constructor = { loc, facing -> FluidMerger(loc, facing) } + ) + } + + override val baseBlockId: String = BLOCK_ID + + override fun getVisualStateBlockId(): String = when (storedFluid) { + FluidType.WATER -> WATER_FILLED_IDS[facing]!! + FluidType.LAVA -> LAVA_FILLED_IDS[facing]!! + FluidType.NONE -> DIRECTIONAL_IDS[facing]!! + } + + override fun fluidUpdate() { + if (hasFluid()) return + + val registry = FluidBlockRegistry.instance ?: return + + // Pull fluid from all faces except the output (facing) direction + val inputFaces = listOf(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN) + .filter { it != facing } + + for (face in inputFaces) { + val source = registry.getAdjacentFluidBlock(location, face) ?: continue + + when (source) { + is FluidPump -> { + if (source.canRemoveFluidFrom(face.oppositeFace) && source.hasFluid()) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.atlasInfo("FluidMerger at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidPump at ${face.name}") + return + } + } + is FluidPipe -> { + if (source.hasFluid()) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.atlasInfo("FluidMerger at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidPipe at ${face.name}") + return + } + } + is FluidContainer -> { + if (source.canRemoveFluidFrom(face.oppositeFace) && source.hasFluid()) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.atlasInfo("FluidMerger at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidContainer at ${face.name}") + return + } + } + is FluidMerger -> { + if (source.hasFluid()) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.atlasInfo("FluidMerger at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidMerger at ${face.name}") + return + } + } + } + } + } +} diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt index 92a8b4a..d3708c0 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt @@ -95,6 +95,13 @@ class FluidPipe(location: Location, override val facing: BlockFace) : FluidBlock plugin.logger.atlasInfo("FluidPipe at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidContainer") } } + is FluidMerger -> { + if (source.hasFluid()) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.atlasInfo("FluidPipe at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidMerger") + } + } } } } diff --git a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt index 5459e8b..6c88a3f 100644 --- a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt +++ b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt @@ -8,6 +8,9 @@ import com.coderjoe.atlas.power.block.PowerCable import com.coderjoe.atlas.power.block.SmallBattery import com.coderjoe.atlas.power.block.SmallDrill import com.coderjoe.atlas.power.block.MultiPowerCable +import com.coderjoe.atlas.power.block.CobblestoneGenerator +import com.coderjoe.atlas.power.block.ObsidianGenerator +import com.coderjoe.atlas.power.block.PowerMerger import com.coderjoe.atlas.power.block.SmallSolarPanel import io.papermc.paper.dialog.Dialog import io.papermc.paper.registry.data.dialog.ActionButton @@ -129,6 +132,9 @@ object PowerBlockDialog { is LavaGenerator -> "Lava Generator" is AutoSmelter -> "Auto Smelter (${powerBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" is MultiPowerCable -> "Multi Power Cable (${powerBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" + is CobblestoneGenerator -> "Cobblestone Generator" + is ObsidianGenerator -> "Obsidian Generator" + is PowerMerger -> "Power Merger (${powerBlock.facing.name.lowercase().replaceFirstChar { it.uppercase() }})" else -> "Power Block" } @@ -177,6 +183,12 @@ object PowerBlockDialog { .color(NamedTextColor.GRAY) is MultiPowerCable -> Component.text("Cable - distributes power to all adjacent faces") .color(NamedTextColor.GRAY) + is CobblestoneGenerator -> Component.text("Machine - consumes ${CobblestoneGenerator.POWER_COST} power + water + lava → cobblestone") + .color(NamedTextColor.GRAY) + is ObsidianGenerator -> Component.text("Machine - consumes ${ObsidianGenerator.POWER_COST} power + water + lava → obsidian") + .color(NamedTextColor.GRAY) + is PowerMerger -> Component.text("Cable - merges power from all sides, outputs in facing direction") + .color(NamedTextColor.GRAY) else -> Component.text("Power block") .color(NamedTextColor.GRAY) } diff --git a/src/main/kotlin/com/coderjoe/atlas/power/block/CobblestoneGenerator.kt b/src/main/kotlin/com/coderjoe/atlas/power/block/CobblestoneGenerator.kt new file mode 100644 index 0000000..3b7f304 --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/power/block/CobblestoneGenerator.kt @@ -0,0 +1,118 @@ +package com.coderjoe.atlas.power.block + +import com.coderjoe.atlas.atlasInfo +import com.coderjoe.atlas.core.BlockDescriptor +import com.coderjoe.atlas.core.PlacementType +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import com.coderjoe.atlas.fluid.block.FluidContainer +import com.coderjoe.atlas.fluid.block.FluidMerger +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.fluid.block.FluidPump +import com.coderjoe.atlas.power.PowerBlock +import com.coderjoe.atlas.power.PowerBlockRegistry +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.block.BlockFace +import org.bukkit.inventory.ItemStack + +class CobblestoneGenerator(location: Location) : PowerBlock(location, maxStorage = 2) { + + override val canReceivePower: Boolean = true + override val updateIntervalTicks: Long = 20L + + companion object { + const val BLOCK_ID = "cobblestone_generator" + const val BLOCK_ID_ACTIVE = "cobblestone_generator_active" + const val POWER_COST = 2 + + private val ADJACENT_FACES = listOf( + BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, + BlockFace.WEST, BlockFace.UP, BlockFace.DOWN + ) + + val descriptor = BlockDescriptor( + baseBlockId = BLOCK_ID, + displayName = "Cobblestone Generator", + description = "Machine - consumes $POWER_COST power + water + lava → cobblestone", + placementType = PlacementType.SIMPLE, + directionalVariants = emptyMap(), + allRegistrableIds = listOf(BLOCK_ID, BLOCK_ID_ACTIVE), + constructor = { loc, _ -> CobblestoneGenerator(loc) } + ) + } + + override val baseBlockId: String = BLOCK_ID + + override fun getVisualStateBlockId(): String = when { + currentPower >= POWER_COST -> BLOCK_ID_ACTIVE + else -> BLOCK_ID + } + + override fun powerUpdate() { + // Pull power from adjacent blocks + if (canAcceptPower()) { + val registry = PowerBlockRegistry.instance ?: return + val neighbors = registry.getAdjacentPowerBlocks(location) + for (neighbor in neighbors) { + if (!canAcceptPower()) break + if (neighbor.hasPower()) { + val pulled = neighbor.removePower(1) + if (pulled > 0) { + addPower(pulled) + } + } + } + } + + if (currentPower < POWER_COST) return + + val fluidRegistry = FluidBlockRegistry.instance ?: return + + // Check that BOTH water and lava are available before consuming either + var waterSource: Pair? = null + var lavaSource: Pair? = null + + for (face in ADJACENT_FACES) { + val source = fluidRegistry.getAdjacentFluidBlock(location, face) ?: continue + if (waterSource == null && hasFluidAvailable(source, face, FluidType.WATER)) { + waterSource = Pair(source, face) + } else if (lavaSource == null && hasFluidAvailable(source, face, FluidType.LAVA)) { + lavaSource = Pair(source, face) + } + if (waterSource != null && lavaSource != null) break + } + + if (waterSource == null || lavaSource == null) return + + // Both available — consume atomically + pullFluid(waterSource.first, waterSource.second) + pullFluid(lavaSource.first, lavaSource.second) + removePower(POWER_COST) + + val world = location.world ?: return + val dropLocation = location.clone().add(0.5, 1.0, 0.5) + world.dropItemNaturally(dropLocation, ItemStack(Material.COBBLESTONE)) + + plugin.logger.atlasInfo("CobblestoneGenerator at ${location.blockX},${location.blockY},${location.blockZ} produced 1 cobblestone") + } + + private fun hasFluidAvailable(source: com.coderjoe.atlas.fluid.FluidBlock, face: BlockFace, fluidType: FluidType): Boolean { + return when (source) { + is FluidPump -> source.canRemoveFluidFrom(face.oppositeFace) && source.storedFluid == fluidType + is FluidPipe -> source.hasFluid() && source.storedFluid == fluidType + is FluidContainer -> source.canRemoveFluidFrom(face.oppositeFace) && source.storedFluid == fluidType + is FluidMerger -> source.hasFluid() && source.storedFluid == fluidType + else -> false + } + } + + private fun pullFluid(source: com.coderjoe.atlas.fluid.FluidBlock, face: BlockFace) { + when (source) { + is FluidPump -> source.removeFluid() + is FluidPipe -> source.removeFluid() + is FluidContainer -> source.removeFluid() + is FluidMerger -> source.removeFluid() + } + } +} diff --git a/src/main/kotlin/com/coderjoe/atlas/power/block/LavaGenerator.kt b/src/main/kotlin/com/coderjoe/atlas/power/block/LavaGenerator.kt index f07dff1..53dd541 100644 --- a/src/main/kotlin/com/coderjoe/atlas/power/block/LavaGenerator.kt +++ b/src/main/kotlin/com/coderjoe/atlas/power/block/LavaGenerator.kt @@ -6,6 +6,7 @@ import com.coderjoe.atlas.core.PlacementType import com.coderjoe.atlas.fluid.FluidBlockRegistry import com.coderjoe.atlas.fluid.FluidType import com.coderjoe.atlas.fluid.block.FluidContainer +import com.coderjoe.atlas.fluid.block.FluidMerger import com.coderjoe.atlas.fluid.block.FluidPipe import com.coderjoe.atlas.fluid.block.FluidPump import com.coderjoe.atlas.power.PowerBlock @@ -84,6 +85,12 @@ class LavaGenerator(location: Location) : PowerBlock(location, maxStorage = 50) return true } } + is FluidMerger -> { + if (source.hasFluid() && source.storedFluid == FluidType.LAVA) { + source.removeFluid() + return true + } + } } return false } diff --git a/src/main/kotlin/com/coderjoe/atlas/power/block/ObsidianGenerator.kt b/src/main/kotlin/com/coderjoe/atlas/power/block/ObsidianGenerator.kt new file mode 100644 index 0000000..5934a37 --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/power/block/ObsidianGenerator.kt @@ -0,0 +1,118 @@ +package com.coderjoe.atlas.power.block + +import com.coderjoe.atlas.atlasInfo +import com.coderjoe.atlas.core.BlockDescriptor +import com.coderjoe.atlas.core.PlacementType +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import com.coderjoe.atlas.fluid.block.FluidContainer +import com.coderjoe.atlas.fluid.block.FluidMerger +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.fluid.block.FluidPump +import com.coderjoe.atlas.power.PowerBlock +import com.coderjoe.atlas.power.PowerBlockRegistry +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.block.BlockFace +import org.bukkit.inventory.ItemStack + +class ObsidianGenerator(location: Location) : PowerBlock(location, maxStorage = 100) { + + override val canReceivePower: Boolean = true + override val updateIntervalTicks: Long = 20L + + companion object { + const val BLOCK_ID = "obsidian_generator" + const val BLOCK_ID_ACTIVE = "obsidian_generator_active" + const val POWER_COST = 100 + + private val ADJACENT_FACES = listOf( + BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, + BlockFace.WEST, BlockFace.UP, BlockFace.DOWN + ) + + val descriptor = BlockDescriptor( + baseBlockId = BLOCK_ID, + displayName = "Obsidian Generator", + description = "Machine - consumes $POWER_COST power + water + lava → obsidian", + placementType = PlacementType.SIMPLE, + directionalVariants = emptyMap(), + allRegistrableIds = listOf(BLOCK_ID, BLOCK_ID_ACTIVE), + constructor = { loc, _ -> ObsidianGenerator(loc) } + ) + } + + override val baseBlockId: String = BLOCK_ID + + override fun getVisualStateBlockId(): String = when { + currentPower >= POWER_COST -> BLOCK_ID_ACTIVE + else -> BLOCK_ID + } + + override fun powerUpdate() { + // Pull power from adjacent blocks + if (canAcceptPower()) { + val registry = PowerBlockRegistry.instance ?: return + val neighbors = registry.getAdjacentPowerBlocks(location) + for (neighbor in neighbors) { + if (!canAcceptPower()) break + if (neighbor.hasPower()) { + val pulled = neighbor.removePower(1) + if (pulled > 0) { + addPower(pulled) + } + } + } + } + + if (currentPower < POWER_COST) return + + val fluidRegistry = FluidBlockRegistry.instance ?: return + + // Check that BOTH water and lava are available before consuming either + var waterSource: Pair? = null + var lavaSource: Pair? = null + + for (face in ADJACENT_FACES) { + val source = fluidRegistry.getAdjacentFluidBlock(location, face) ?: continue + if (waterSource == null && hasFluidAvailable(source, face, FluidType.WATER)) { + waterSource = Pair(source, face) + } else if (lavaSource == null && hasFluidAvailable(source, face, FluidType.LAVA)) { + lavaSource = Pair(source, face) + } + if (waterSource != null && lavaSource != null) break + } + + if (waterSource == null || lavaSource == null) return + + // Both available — consume atomically + pullFluid(waterSource.first, waterSource.second) + pullFluid(lavaSource.first, lavaSource.second) + removePower(POWER_COST) + + val world = location.world ?: return + val dropLocation = location.clone().add(0.5, 1.0, 0.5) + world.dropItemNaturally(dropLocation, ItemStack(Material.OBSIDIAN)) + + plugin.logger.atlasInfo("ObsidianGenerator at ${location.blockX},${location.blockY},${location.blockZ} produced 1 obsidian") + } + + private fun hasFluidAvailable(source: com.coderjoe.atlas.fluid.FluidBlock, face: BlockFace, fluidType: FluidType): Boolean { + return when (source) { + is FluidPump -> source.canRemoveFluidFrom(face.oppositeFace) && source.storedFluid == fluidType + is FluidPipe -> source.hasFluid() && source.storedFluid == fluidType + is FluidContainer -> source.canRemoveFluidFrom(face.oppositeFace) && source.storedFluid == fluidType + is FluidMerger -> source.hasFluid() && source.storedFluid == fluidType + else -> false + } + } + + private fun pullFluid(source: com.coderjoe.atlas.fluid.FluidBlock, face: BlockFace) { + when (source) { + is FluidPump -> source.removeFluid() + is FluidPipe -> source.removeFluid() + is FluidContainer -> source.removeFluid() + is FluidMerger -> source.removeFluid() + } + } +} diff --git a/src/main/kotlin/com/coderjoe/atlas/power/block/PowerMerger.kt b/src/main/kotlin/com/coderjoe/atlas/power/block/PowerMerger.kt new file mode 100644 index 0000000..7b26ce3 --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/power/block/PowerMerger.kt @@ -0,0 +1,78 @@ +package com.coderjoe.atlas.power.block + +import com.coderjoe.atlas.atlasInfo +import com.coderjoe.atlas.core.BlockDescriptor +import com.coderjoe.atlas.core.PlacementType +import com.coderjoe.atlas.power.PowerBlock +import com.coderjoe.atlas.power.PowerBlockRegistry +import org.bukkit.Location +import org.bukkit.block.BlockFace + +class PowerMerger(location: Location, override val facing: BlockFace) : PowerBlock(location, maxStorage = 2) { + + override val canReceivePower: Boolean = false + override val updateIntervalTicks: Long = 20L + + companion object { + const val BLOCK_ID = "power_merger" + + val DIRECTIONAL_IDS = mapOf( + BlockFace.NORTH to "power_merger_north", + BlockFace.SOUTH to "power_merger_south", + BlockFace.EAST to "power_merger_east", + BlockFace.WEST to "power_merger_west", + BlockFace.UP to "power_merger_up", + BlockFace.DOWN to "power_merger_down" + ) + + val POWERED_IDS = mapOf( + BlockFace.NORTH to "power_merger_north_powered", + BlockFace.SOUTH to "power_merger_south_powered", + BlockFace.EAST to "power_merger_east_powered", + BlockFace.WEST to "power_merger_west_powered", + BlockFace.UP to "power_merger_up_powered", + BlockFace.DOWN to "power_merger_down_powered" + ) + + val ID_TO_FACING = (DIRECTIONAL_IDS.entries.associate { (face, id) -> id to face } + + POWERED_IDS.entries.associate { (face, id) -> id to face }) + + fun facingFromBlockId(blockId: String): BlockFace? = ID_TO_FACING[blockId] + + val descriptor = BlockDescriptor( + baseBlockId = BLOCK_ID, + displayName = "Power Merger", + description = "Cable - merges power from all sides, outputs in facing direction", + placementType = PlacementType.DIRECTIONAL, + directionalVariants = DIRECTIONAL_IDS, + allRegistrableIds = DIRECTIONAL_IDS.values.toList() + POWERED_IDS.values.toList(), + constructor = { loc, facing -> PowerMerger(loc, facing) } + ) + } + + override val baseBlockId: String = BLOCK_ID + + override fun getVisualStateBlockId(): String = + if (currentPower > 0) POWERED_IDS[facing]!! + else DIRECTIONAL_IDS[facing]!! + + override fun powerUpdate() { + val registry = PowerBlockRegistry.instance ?: return + + // Pull power from all faces except the output (facing) direction + val inputFaces = listOf(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN) + .filter { it != facing } + + for (face in inputFaces) { + if (currentPower >= maxStorage) break + val source = registry.getAdjacentPowerBlock(location, face) ?: continue + if (source.hasPower()) { + val pulled = source.removePower(1) + if (pulled > 0) { + addPower(pulled) + plugin.logger.atlasInfo("PowerMerger at ${location.blockX},${location.blockY},${location.blockZ} pulled $pulled power from ${source::class.simpleName} at ${face.name} (now $currentPower/$maxStorage)") + } + } + } + } +} diff --git a/src/main/resources/nexo/items/atlas_blocks.yml b/src/main/resources/nexo/items/atlas_blocks.yml index 78cd2bf..f4cabe7 100644 --- a/src/main/resources/nexo/items/atlas_blocks.yml +++ b/src/main/resources/nexo/items/atlas_blocks.yml @@ -2649,6 +2649,572 @@ fluid_container_down_lava_full: - nexo_item: fluid_container probability: 1.0 +# ─── Fluid Merger ──────────────────────────────────────────────── +fluid_merger: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube_all + textures: + all: atlas:block/fluid_merger_side + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 184 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_north: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_front + south: atlas:block/fluid_merger_back + east: atlas:block/fluid_merger_side + west: atlas:block/fluid_merger_side + up: atlas:block/fluid_merger_top + down: atlas:block/fluid_merger_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 185 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_south: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_back + south: atlas:block/fluid_merger_front + east: atlas:block/fluid_merger_side + west: atlas:block/fluid_merger_side + up: atlas:block/fluid_merger_top + down: atlas:block/fluid_merger_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 186 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_east: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side + south: atlas:block/fluid_merger_side + east: atlas:block/fluid_merger_front + west: atlas:block/fluid_merger_back + up: atlas:block/fluid_merger_top + down: atlas:block/fluid_merger_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 187 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_west: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side + south: atlas:block/fluid_merger_side + east: atlas:block/fluid_merger_back + west: atlas:block/fluid_merger_front + up: atlas:block/fluid_merger_top + down: atlas:block/fluid_merger_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 188 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_up: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side + south: atlas:block/fluid_merger_side + east: atlas:block/fluid_merger_side + west: atlas:block/fluid_merger_side + up: atlas:block/fluid_merger_front + down: atlas:block/fluid_merger_back + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 189 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_down: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side + south: atlas:block/fluid_merger_side + east: atlas:block/fluid_merger_side + west: atlas:block/fluid_merger_side + up: atlas:block/fluid_merger_back + down: atlas:block/fluid_merger_front + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 190 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_north_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_front_water + south: atlas:block/fluid_merger_back_water + east: atlas:block/fluid_merger_side_water + west: atlas:block/fluid_merger_side_water + up: atlas:block/fluid_merger_top_water + down: atlas:block/fluid_merger_bottom_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 191 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_south_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_back_water + south: atlas:block/fluid_merger_front_water + east: atlas:block/fluid_merger_side_water + west: atlas:block/fluid_merger_side_water + up: atlas:block/fluid_merger_top_water + down: atlas:block/fluid_merger_bottom_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 192 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_east_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_water + south: atlas:block/fluid_merger_side_water + east: atlas:block/fluid_merger_front_water + west: atlas:block/fluid_merger_back_water + up: atlas:block/fluid_merger_top_water + down: atlas:block/fluid_merger_bottom_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 193 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_west_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_water + south: atlas:block/fluid_merger_side_water + east: atlas:block/fluid_merger_back_water + west: atlas:block/fluid_merger_front_water + up: atlas:block/fluid_merger_top_water + down: atlas:block/fluid_merger_bottom_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 194 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_up_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_water + south: atlas:block/fluid_merger_side_water + east: atlas:block/fluid_merger_side_water + west: atlas:block/fluid_merger_side_water + up: atlas:block/fluid_merger_front_water + down: atlas:block/fluid_merger_back_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 195 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_down_filled: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_water + south: atlas:block/fluid_merger_side_water + east: atlas:block/fluid_merger_side_water + west: atlas:block/fluid_merger_side_water + up: atlas:block/fluid_merger_back_water + down: atlas:block/fluid_merger_front_water + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 196 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_north_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_front_lava + south: atlas:block/fluid_merger_back_lava + east: atlas:block/fluid_merger_side_lava + west: atlas:block/fluid_merger_side_lava + up: atlas:block/fluid_merger_top_lava + down: atlas:block/fluid_merger_bottom_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 197 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_south_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_back_lava + south: atlas:block/fluid_merger_front_lava + east: atlas:block/fluid_merger_side_lava + west: atlas:block/fluid_merger_side_lava + up: atlas:block/fluid_merger_top_lava + down: atlas:block/fluid_merger_bottom_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 198 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_east_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_lava + south: atlas:block/fluid_merger_side_lava + east: atlas:block/fluid_merger_front_lava + west: atlas:block/fluid_merger_back_lava + up: atlas:block/fluid_merger_top_lava + down: atlas:block/fluid_merger_bottom_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 199 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_west_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_lava + south: atlas:block/fluid_merger_side_lava + east: atlas:block/fluid_merger_back_lava + west: atlas:block/fluid_merger_front_lava + up: atlas:block/fluid_merger_top_lava + down: atlas:block/fluid_merger_bottom_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 200 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_up_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_lava + south: atlas:block/fluid_merger_side_lava + east: atlas:block/fluid_merger_side_lava + west: atlas:block/fluid_merger_side_lava + up: atlas:block/fluid_merger_front_lava + down: atlas:block/fluid_merger_back_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 201 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + +fluid_merger_down_filled_lava: + itemname: "Fluid Merger" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_merger_side_lava + south: atlas:block/fluid_merger_side_lava + east: atlas:block/fluid_merger_side_lava + west: atlas:block/fluid_merger_side_lava + up: atlas:block/fluid_merger_back_lava + down: atlas:block/fluid_merger_front_lava + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 202 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_merger + probability: 1.0 + # ─── Lava Generator ─────────────────────────────────────────────── lava_generator: itemname: "Lava Generator" @@ -2657,17 +3223,523 @@ lava_generator: generate_model: true parent_model: block/cube textures: - north: atlas:block/lava_generator_side - south: atlas:block/lava_generator_side - east: atlas:block/lava_generator_side - west: atlas:block/lava_generator_side - up: atlas:block/lava_generator_top - down: atlas:block/lava_generator_bottom + north: atlas:block/lava_generator_side + south: atlas:block/lava_generator_side + east: atlas:block/lava_generator_side + west: atlas:block/lava_generator_side + up: atlas:block/lava_generator_top + down: atlas:block/lava_generator_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 152 + hardness: 5 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: lava_generator + probability: 1.0 + +lava_generator_active: + itemname: "Lava Generator" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/lava_generator_side_active + south: atlas:block/lava_generator_side_active + east: atlas:block/lava_generator_side_active + west: atlas:block/lava_generator_side_active + up: atlas:block/lava_generator_top_active + down: atlas:block/lava_generator_bottom + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 153 + hardness: 5 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: lava_generator + probability: 1.0 + +# ─── Conveyor Belt ──────────────────────────────────────────────── +conveyor_belt: + itemname: "Conveyor Belt" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/conveyor_belt + textures: + north: atlas:block/conveyor_belt_front + south: atlas:block/conveyor_belt_back + east: atlas:block/conveyor_belt_side + west: atlas:block/conveyor_belt_side + up: atlas:block/conveyor_belt_top_north + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 44 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: conveyor_belt + probability: 1.0 + +conveyor_belt_north: + itemname: "Conveyor Belt" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/conveyor_belt + textures: + north: atlas:block/conveyor_belt_front + south: atlas:block/conveyor_belt_back + east: atlas:block/conveyor_belt_side + west: atlas:block/conveyor_belt_side + up: atlas:block/conveyor_belt_top_north + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 45 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: conveyor_belt + probability: 1.0 + +conveyor_belt_south: + itemname: "Conveyor Belt" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/conveyor_belt + textures: + north: atlas:block/conveyor_belt_back + south: atlas:block/conveyor_belt_front + east: atlas:block/conveyor_belt_side + west: atlas:block/conveyor_belt_side + up: atlas:block/conveyor_belt_top_south + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 46 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: conveyor_belt + probability: 1.0 + +conveyor_belt_east: + itemname: "Conveyor Belt" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/conveyor_belt + textures: + north: atlas:block/conveyor_belt_side + south: atlas:block/conveyor_belt_side + east: atlas:block/conveyor_belt_front + west: atlas:block/conveyor_belt_back + up: atlas:block/conveyor_belt_top_east + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 47 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: conveyor_belt + probability: 1.0 + +conveyor_belt_west: + itemname: "Conveyor Belt" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/conveyor_belt + textures: + north: atlas:block/conveyor_belt_side + south: atlas:block/conveyor_belt_side + east: atlas:block/conveyor_belt_back + west: atlas:block/conveyor_belt_front + up: atlas:block/conveyor_belt_top_west + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 48 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: conveyor_belt + probability: 1.0 + +auto_smelter: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ns + textures: + north: atlas:block/auto_smelter_front + south: atlas:block/auto_smelter_back + east: atlas:block/auto_smelter_side + west: atlas:block/auto_smelter_side + up: atlas:block/auto_smelter_top_north + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 49 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_north: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ns + textures: + north: atlas:block/auto_smelter_front + south: atlas:block/auto_smelter_back + east: atlas:block/auto_smelter_side + west: atlas:block/auto_smelter_side + up: atlas:block/auto_smelter_top_north + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 50 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_south: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ns + textures: + north: atlas:block/auto_smelter_back + south: atlas:block/auto_smelter_front + east: atlas:block/auto_smelter_side + west: atlas:block/auto_smelter_side + up: atlas:block/auto_smelter_top_south + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 51 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_east: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ew + textures: + north: atlas:block/auto_smelter_side + south: atlas:block/auto_smelter_side + east: atlas:block/auto_smelter_front + west: atlas:block/auto_smelter_back + up: atlas:block/auto_smelter_top_east + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 52 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_west: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ew + textures: + north: atlas:block/auto_smelter_side + south: atlas:block/auto_smelter_side + east: atlas:block/auto_smelter_back + west: atlas:block/auto_smelter_front + up: atlas:block/auto_smelter_top_west + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 53 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_north_on: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ns_on + textures: + north: atlas:block/auto_smelter_front + south: atlas:block/auto_smelter_back + east: atlas:block/auto_smelter_side + west: atlas:block/auto_smelter_side + up: atlas:block/auto_smelter_top_north + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 54 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_south_on: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ns_on + textures: + north: atlas:block/auto_smelter_back + south: atlas:block/auto_smelter_front + east: atlas:block/auto_smelter_side + west: atlas:block/auto_smelter_side + up: atlas:block/auto_smelter_top_south + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 55 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_east_on: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ew_on + textures: + north: atlas:block/auto_smelter_side + south: atlas:block/auto_smelter_side + east: atlas:block/auto_smelter_front + west: atlas:block/auto_smelter_back + up: atlas:block/auto_smelter_top_east + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 56 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +auto_smelter_west_on: + itemname: "Auto Smelter" + material: paper + Pack: + generate_model: true + parent_model: atlas:block/auto_smelter_ew_on + textures: + north: atlas:block/auto_smelter_side + south: atlas:block/auto_smelter_side + east: atlas:block/auto_smelter_back + west: atlas:block/auto_smelter_front + up: atlas:block/auto_smelter_top_west + down: atlas:block/conveyor_belt_bottom + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 57 + hardness: 3 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: auto_smelter + probability: 1.0 + +multi_power_cable: + itemname: "Multi Power Cable" + material: paper + Pack: + generate_model: true + parent_model: block/cube_all + textures: + all: atlas:block/multi_power_cable_side + Mechanics: + custom_block: + type: NOTEBLOCK + custom_variation: 154 + hardness: 2 + block_sounds: + break_sound: block.metal.break + place_sound: block.metal.place + hit_sound: block.metal.hit + step_sound: block.metal.step + fall_sound: block.metal.fall + drop: + silktouch: false + loots: + - nexo_item: multi_power_cable + probability: 1.0 + +multi_power_cable_north: + itemname: "Multi Power Cable" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/multi_power_cable_front + south: atlas:block/multi_power_cable_back + east: atlas:block/multi_power_cable_side + west: atlas:block/multi_power_cable_side + up: atlas:block/multi_power_cable_cap + down: atlas:block/multi_power_cable_cap Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 152 - hardness: 5 + custom_variation: 155 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2677,27 +3749,27 @@ lava_generator: drop: silktouch: false loots: - - nexo_item: lava_generator + - nexo_item: multi_power_cable probability: 1.0 -lava_generator_active: - itemname: "Lava Generator" +multi_power_cable_south: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/lava_generator_side_active - south: atlas:block/lava_generator_side_active - east: atlas:block/lava_generator_side_active - west: atlas:block/lava_generator_side_active - up: atlas:block/lava_generator_top_active - down: atlas:block/lava_generator_bottom + north: atlas:block/multi_power_cable_back + south: atlas:block/multi_power_cable_front + east: atlas:block/multi_power_cable_side + west: atlas:block/multi_power_cable_side + up: atlas:block/multi_power_cable_cap + down: atlas:block/multi_power_cable_cap Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 153 - hardness: 5 + custom_variation: 156 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2707,28 +3779,27 @@ lava_generator_active: drop: silktouch: false loots: - - nexo_item: lava_generator + - nexo_item: multi_power_cable probability: 1.0 -# ─── Conveyor Belt ──────────────────────────────────────────────── -conveyor_belt: - itemname: "Conveyor Belt" +multi_power_cable_east: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/conveyor_belt + parent_model: block/cube textures: - north: atlas:block/conveyor_belt_front - south: atlas:block/conveyor_belt_back - east: atlas:block/conveyor_belt_side - west: atlas:block/conveyor_belt_side - up: atlas:block/conveyor_belt_top_north - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side + south: atlas:block/multi_power_cable_side + east: atlas:block/multi_power_cable_front + west: atlas:block/multi_power_cable_back + up: atlas:block/multi_power_cable_cap + down: atlas:block/multi_power_cable_cap Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 44 - hardness: 3 + type: NOTEBLOCK + custom_variation: 157 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2738,27 +3809,27 @@ conveyor_belt: drop: silktouch: false loots: - - nexo_item: conveyor_belt + - nexo_item: multi_power_cable probability: 1.0 -conveyor_belt_north: - itemname: "Conveyor Belt" +multi_power_cable_west: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/conveyor_belt + parent_model: block/cube textures: - north: atlas:block/conveyor_belt_front - south: atlas:block/conveyor_belt_back - east: atlas:block/conveyor_belt_side - west: atlas:block/conveyor_belt_side - up: atlas:block/conveyor_belt_top_north - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side + south: atlas:block/multi_power_cable_side + east: atlas:block/multi_power_cable_back + west: atlas:block/multi_power_cable_front + up: atlas:block/multi_power_cable_cap + down: atlas:block/multi_power_cable_cap Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 45 - hardness: 3 + type: NOTEBLOCK + custom_variation: 158 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2768,27 +3839,27 @@ conveyor_belt_north: drop: silktouch: false loots: - - nexo_item: conveyor_belt + - nexo_item: multi_power_cable probability: 1.0 -conveyor_belt_south: - itemname: "Conveyor Belt" +multi_power_cable_up: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/conveyor_belt + parent_model: block/cube textures: - north: atlas:block/conveyor_belt_back - south: atlas:block/conveyor_belt_front - east: atlas:block/conveyor_belt_side - west: atlas:block/conveyor_belt_side - up: atlas:block/conveyor_belt_top_south - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side + south: atlas:block/multi_power_cable_side + east: atlas:block/multi_power_cable_side + west: atlas:block/multi_power_cable_side + up: atlas:block/multi_power_cable_front + down: atlas:block/multi_power_cable_back Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 46 - hardness: 3 + type: NOTEBLOCK + custom_variation: 159 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2798,27 +3869,27 @@ conveyor_belt_south: drop: silktouch: false loots: - - nexo_item: conveyor_belt + - nexo_item: multi_power_cable probability: 1.0 -conveyor_belt_east: - itemname: "Conveyor Belt" +multi_power_cable_down: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/conveyor_belt + parent_model: block/cube textures: - north: atlas:block/conveyor_belt_side - south: atlas:block/conveyor_belt_side - east: atlas:block/conveyor_belt_front - west: atlas:block/conveyor_belt_back - up: atlas:block/conveyor_belt_top_east - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side + south: atlas:block/multi_power_cable_side + east: atlas:block/multi_power_cable_side + west: atlas:block/multi_power_cable_side + up: atlas:block/multi_power_cable_back + down: atlas:block/multi_power_cable_front Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 47 - hardness: 3 + type: NOTEBLOCK + custom_variation: 160 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2828,27 +3899,27 @@ conveyor_belt_east: drop: silktouch: false loots: - - nexo_item: conveyor_belt + - nexo_item: multi_power_cable probability: 1.0 -conveyor_belt_west: - itemname: "Conveyor Belt" +multi_power_cable_north_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/conveyor_belt + parent_model: block/cube textures: - north: atlas:block/conveyor_belt_side - south: atlas:block/conveyor_belt_side - east: atlas:block/conveyor_belt_back - west: atlas:block/conveyor_belt_front - up: atlas:block/conveyor_belt_top_west - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_front_powered + south: atlas:block/multi_power_cable_back_powered + east: atlas:block/multi_power_cable_side_powered + west: atlas:block/multi_power_cable_side_powered + up: atlas:block/multi_power_cable_cap_powered + down: atlas:block/multi_power_cable_cap_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 48 - hardness: 3 + type: NOTEBLOCK + custom_variation: 161 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2858,27 +3929,27 @@ conveyor_belt_west: drop: silktouch: false loots: - - nexo_item: conveyor_belt + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter: - itemname: "Auto Smelter" +multi_power_cable_south_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ns + parent_model: block/cube textures: - north: atlas:block/auto_smelter_front - south: atlas:block/auto_smelter_back - east: atlas:block/auto_smelter_side - west: atlas:block/auto_smelter_side - up: atlas:block/auto_smelter_top_north - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_back_powered + south: atlas:block/multi_power_cable_front_powered + east: atlas:block/multi_power_cable_side_powered + west: atlas:block/multi_power_cable_side_powered + up: atlas:block/multi_power_cable_cap_powered + down: atlas:block/multi_power_cable_cap_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 49 - hardness: 3 + type: NOTEBLOCK + custom_variation: 162 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2888,27 +3959,27 @@ auto_smelter: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter_north: - itemname: "Auto Smelter" +multi_power_cable_east_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ns + parent_model: block/cube textures: - north: atlas:block/auto_smelter_front - south: atlas:block/auto_smelter_back - east: atlas:block/auto_smelter_side - west: atlas:block/auto_smelter_side - up: atlas:block/auto_smelter_top_north - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side_powered + south: atlas:block/multi_power_cable_side_powered + east: atlas:block/multi_power_cable_front_powered + west: atlas:block/multi_power_cable_back_powered + up: atlas:block/multi_power_cable_cap_powered + down: atlas:block/multi_power_cable_cap_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 50 - hardness: 3 + type: NOTEBLOCK + custom_variation: 163 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2918,27 +3989,27 @@ auto_smelter_north: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter_south: - itemname: "Auto Smelter" +multi_power_cable_west_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ns + parent_model: block/cube textures: - north: atlas:block/auto_smelter_back - south: atlas:block/auto_smelter_front - east: atlas:block/auto_smelter_side - west: atlas:block/auto_smelter_side - up: atlas:block/auto_smelter_top_south - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side_powered + south: atlas:block/multi_power_cable_side_powered + east: atlas:block/multi_power_cable_back_powered + west: atlas:block/multi_power_cable_front_powered + up: atlas:block/multi_power_cable_cap_powered + down: atlas:block/multi_power_cable_cap_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 51 - hardness: 3 + type: NOTEBLOCK + custom_variation: 164 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -2948,57 +4019,57 @@ auto_smelter_south: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter_east: - itemname: "Auto Smelter" +multi_power_cable_up_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ew + parent_model: block/cube textures: - north: atlas:block/auto_smelter_side - south: atlas:block/auto_smelter_side - east: atlas:block/auto_smelter_front - west: atlas:block/auto_smelter_back - up: atlas:block/auto_smelter_top_east - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side_powered + south: atlas:block/multi_power_cable_side_powered + east: atlas:block/multi_power_cable_side_powered + west: atlas:block/multi_power_cable_side_powered + up: atlas:block/multi_power_cable_front_powered + down: atlas:block/multi_power_cable_back_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 52 - hardness: 3 + type: NOTEBLOCK + custom_variation: 165 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place hit_sound: block.metal.hit - step_sound: block.metal.step + step_sound: block.metal.hit fall_sound: block.metal.fall drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter_west: - itemname: "Auto Smelter" +multi_power_cable_down_powered: + itemname: "Multi Power Cable" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ew + parent_model: block/cube textures: - north: atlas:block/auto_smelter_side - south: atlas:block/auto_smelter_side - east: atlas:block/auto_smelter_back - west: atlas:block/auto_smelter_front - up: atlas:block/auto_smelter_top_west - down: atlas:block/conveyor_belt_bottom + north: atlas:block/multi_power_cable_side_powered + south: atlas:block/multi_power_cable_side_powered + east: atlas:block/multi_power_cable_side_powered + west: atlas:block/multi_power_cable_side_powered + up: atlas:block/multi_power_cable_back_powered + down: atlas:block/multi_power_cable_front_powered Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 53 - hardness: 3 + type: NOTEBLOCK + custom_variation: 166 + hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -3008,27 +4079,28 @@ auto_smelter_west: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: multi_power_cable probability: 1.0 -auto_smelter_north_on: - itemname: "Auto Smelter" +# ─── Cobblestone Generator ────────────────────────────────────── +cobblestone_generator: + itemname: "Cobblestone Generator" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ns_on + parent_model: block/cube textures: - north: atlas:block/auto_smelter_front - south: atlas:block/auto_smelter_back - east: atlas:block/auto_smelter_side - west: atlas:block/auto_smelter_side - up: atlas:block/auto_smelter_top_north - down: atlas:block/conveyor_belt_bottom + north: atlas:block/cobblestone_generator_side + south: atlas:block/cobblestone_generator_side + east: atlas:block/cobblestone_generator_side + west: atlas:block/cobblestone_generator_side + up: atlas:block/cobblestone_generator_top + down: atlas:block/cobblestone_generator_bottom Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 54 - hardness: 3 + type: NOTEBLOCK + custom_variation: 167 + hardness: 5 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -3038,27 +4110,27 @@ auto_smelter_north_on: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: cobblestone_generator probability: 1.0 -auto_smelter_south_on: - itemname: "Auto Smelter" +cobblestone_generator_active: + itemname: "Cobblestone Generator" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ns_on + parent_model: block/cube textures: - north: atlas:block/auto_smelter_back - south: atlas:block/auto_smelter_front - east: atlas:block/auto_smelter_side - west: atlas:block/auto_smelter_side - up: atlas:block/auto_smelter_top_south - down: atlas:block/conveyor_belt_bottom + north: atlas:block/cobblestone_generator_side_active + south: atlas:block/cobblestone_generator_side_active + east: atlas:block/cobblestone_generator_side_active + west: atlas:block/cobblestone_generator_side_active + up: atlas:block/cobblestone_generator_top_active + down: atlas:block/cobblestone_generator_bottom Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 55 - hardness: 3 + type: NOTEBLOCK + custom_variation: 168 + hardness: 5 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -3068,27 +4140,28 @@ auto_smelter_south_on: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: cobblestone_generator probability: 1.0 -auto_smelter_east_on: - itemname: "Auto Smelter" +# ─── Obsidian Generator ───────────────────────────────────────── +obsidian_generator: + itemname: "Obsidian Generator" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ew_on + parent_model: block/cube textures: - north: atlas:block/auto_smelter_side - south: atlas:block/auto_smelter_side - east: atlas:block/auto_smelter_front - west: atlas:block/auto_smelter_back - up: atlas:block/auto_smelter_top_east - down: atlas:block/conveyor_belt_bottom + north: atlas:block/obsidian_generator_side + south: atlas:block/obsidian_generator_side + east: atlas:block/obsidian_generator_side + west: atlas:block/obsidian_generator_side + up: atlas:block/obsidian_generator_top + down: atlas:block/obsidian_generator_bottom Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 56 - hardness: 3 + type: NOTEBLOCK + custom_variation: 169 + hardness: 5 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -3098,27 +4171,27 @@ auto_smelter_east_on: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: obsidian_generator probability: 1.0 -auto_smelter_west_on: - itemname: "Auto Smelter" +obsidian_generator_active: + itemname: "Obsidian Generator" material: paper Pack: generate_model: true - parent_model: atlas:block/auto_smelter_ew_on + parent_model: block/cube textures: - north: atlas:block/auto_smelter_side - south: atlas:block/auto_smelter_side - east: atlas:block/auto_smelter_back - west: atlas:block/auto_smelter_front - up: atlas:block/auto_smelter_top_west - down: atlas:block/conveyor_belt_bottom + north: atlas:block/obsidian_generator_side_active + south: atlas:block/obsidian_generator_side_active + east: atlas:block/obsidian_generator_side_active + west: atlas:block/obsidian_generator_side_active + up: atlas:block/obsidian_generator_top_active + down: atlas:block/obsidian_generator_bottom Mechanics: custom_block: - type: CHORUSBLOCK - custom_variation: 57 - hardness: 3 + type: NOTEBLOCK + custom_variation: 170 + hardness: 5 block_sounds: break_sound: block.metal.break place_sound: block.metal.place @@ -3128,21 +4201,22 @@ auto_smelter_west_on: drop: silktouch: false loots: - - nexo_item: auto_smelter + - nexo_item: obsidian_generator probability: 1.0 -multi_power_cable: - itemname: "Multi Power Cable" +# ─── Power Merger ──────────────────────────────────────────────── +power_merger: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube_all textures: - all: atlas:block/multi_power_cable_side + all: atlas:block/power_merger_side Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 154 + custom_variation: 171 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3153,26 +4227,26 @@ multi_power_cable: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_north: - itemname: "Multi Power Cable" +power_merger_north: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_front - south: atlas:block/multi_power_cable_back - east: atlas:block/multi_power_cable_side - west: atlas:block/multi_power_cable_side - up: atlas:block/multi_power_cable_cap - down: atlas:block/multi_power_cable_cap + north: atlas:block/power_merger_front + south: atlas:block/power_merger_back + east: atlas:block/power_merger_side + west: atlas:block/power_merger_side + up: atlas:block/power_merger_top + down: atlas:block/power_merger_bottom Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 155 + custom_variation: 172 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3183,26 +4257,26 @@ multi_power_cable_north: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_south: - itemname: "Multi Power Cable" +power_merger_south: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_back - south: atlas:block/multi_power_cable_front - east: atlas:block/multi_power_cable_side - west: atlas:block/multi_power_cable_side - up: atlas:block/multi_power_cable_cap - down: atlas:block/multi_power_cable_cap + north: atlas:block/power_merger_back + south: atlas:block/power_merger_front + east: atlas:block/power_merger_side + west: atlas:block/power_merger_side + up: atlas:block/power_merger_top + down: atlas:block/power_merger_bottom Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 156 + custom_variation: 173 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3213,26 +4287,26 @@ multi_power_cable_south: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_east: - itemname: "Multi Power Cable" +power_merger_east: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side - south: atlas:block/multi_power_cable_side - east: atlas:block/multi_power_cable_front - west: atlas:block/multi_power_cable_back - up: atlas:block/multi_power_cable_cap - down: atlas:block/multi_power_cable_cap + north: atlas:block/power_merger_side + south: atlas:block/power_merger_side + east: atlas:block/power_merger_front + west: atlas:block/power_merger_back + up: atlas:block/power_merger_top + down: atlas:block/power_merger_bottom Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 157 + custom_variation: 174 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3243,26 +4317,26 @@ multi_power_cable_east: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_west: - itemname: "Multi Power Cable" +power_merger_west: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side - south: atlas:block/multi_power_cable_side - east: atlas:block/multi_power_cable_back - west: atlas:block/multi_power_cable_front - up: atlas:block/multi_power_cable_cap - down: atlas:block/multi_power_cable_cap + north: atlas:block/power_merger_side + south: atlas:block/power_merger_side + east: atlas:block/power_merger_back + west: atlas:block/power_merger_front + up: atlas:block/power_merger_top + down: atlas:block/power_merger_bottom Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 158 + custom_variation: 175 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3273,26 +4347,26 @@ multi_power_cable_west: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_up: - itemname: "Multi Power Cable" +power_merger_up: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side - south: atlas:block/multi_power_cable_side - east: atlas:block/multi_power_cable_side - west: atlas:block/multi_power_cable_side - up: atlas:block/multi_power_cable_front - down: atlas:block/multi_power_cable_back + north: atlas:block/power_merger_side + south: atlas:block/power_merger_side + east: atlas:block/power_merger_side + west: atlas:block/power_merger_side + up: atlas:block/power_merger_front + down: atlas:block/power_merger_back Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 159 + custom_variation: 176 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3303,26 +4377,26 @@ multi_power_cable_up: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_down: - itemname: "Multi Power Cable" +power_merger_down: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side - south: atlas:block/multi_power_cable_side - east: atlas:block/multi_power_cable_side - west: atlas:block/multi_power_cable_side - up: atlas:block/multi_power_cable_back - down: atlas:block/multi_power_cable_front + north: atlas:block/power_merger_side + south: atlas:block/power_merger_side + east: atlas:block/power_merger_side + west: atlas:block/power_merger_side + up: atlas:block/power_merger_back + down: atlas:block/power_merger_front Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 160 + custom_variation: 177 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3333,26 +4407,26 @@ multi_power_cable_down: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_north_powered: - itemname: "Multi Power Cable" +power_merger_north_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_front_powered - south: atlas:block/multi_power_cable_back_powered - east: atlas:block/multi_power_cable_side_powered - west: atlas:block/multi_power_cable_side_powered - up: atlas:block/multi_power_cable_cap_powered - down: atlas:block/multi_power_cable_cap_powered + north: atlas:block/power_merger_front_powered + south: atlas:block/power_merger_back_powered + east: atlas:block/power_merger_side_powered + west: atlas:block/power_merger_side_powered + up: atlas:block/power_merger_top_powered + down: atlas:block/power_merger_bottom_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 161 + custom_variation: 178 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3363,26 +4437,26 @@ multi_power_cable_north_powered: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_south_powered: - itemname: "Multi Power Cable" +power_merger_south_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_back_powered - south: atlas:block/multi_power_cable_front_powered - east: atlas:block/multi_power_cable_side_powered - west: atlas:block/multi_power_cable_side_powered - up: atlas:block/multi_power_cable_cap_powered - down: atlas:block/multi_power_cable_cap_powered + north: atlas:block/power_merger_back_powered + south: atlas:block/power_merger_front_powered + east: atlas:block/power_merger_side_powered + west: atlas:block/power_merger_side_powered + up: atlas:block/power_merger_top_powered + down: atlas:block/power_merger_bottom_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 162 + custom_variation: 179 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3393,26 +4467,26 @@ multi_power_cable_south_powered: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_east_powered: - itemname: "Multi Power Cable" +power_merger_east_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side_powered - south: atlas:block/multi_power_cable_side_powered - east: atlas:block/multi_power_cable_front_powered - west: atlas:block/multi_power_cable_back_powered - up: atlas:block/multi_power_cable_cap_powered - down: atlas:block/multi_power_cable_cap_powered + north: atlas:block/power_merger_side_powered + south: atlas:block/power_merger_side_powered + east: atlas:block/power_merger_front_powered + west: atlas:block/power_merger_back_powered + up: atlas:block/power_merger_top_powered + down: atlas:block/power_merger_bottom_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 163 + custom_variation: 180 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3423,26 +4497,26 @@ multi_power_cable_east_powered: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_west_powered: - itemname: "Multi Power Cable" +power_merger_west_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side_powered - south: atlas:block/multi_power_cable_side_powered - east: atlas:block/multi_power_cable_back_powered - west: atlas:block/multi_power_cable_front_powered - up: atlas:block/multi_power_cable_cap_powered - down: atlas:block/multi_power_cable_cap_powered + north: atlas:block/power_merger_side_powered + south: atlas:block/power_merger_side_powered + east: atlas:block/power_merger_back_powered + west: atlas:block/power_merger_front_powered + up: atlas:block/power_merger_top_powered + down: atlas:block/power_merger_bottom_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 164 + custom_variation: 181 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3453,56 +4527,56 @@ multi_power_cable_west_powered: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_up_powered: - itemname: "Multi Power Cable" +power_merger_up_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side_powered - south: atlas:block/multi_power_cable_side_powered - east: atlas:block/multi_power_cable_side_powered - west: atlas:block/multi_power_cable_side_powered - up: atlas:block/multi_power_cable_front_powered - down: atlas:block/multi_power_cable_back_powered + north: atlas:block/power_merger_side_powered + south: atlas:block/power_merger_side_powered + east: atlas:block/power_merger_side_powered + west: atlas:block/power_merger_side_powered + up: atlas:block/power_merger_front_powered + down: atlas:block/power_merger_back_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 165 + custom_variation: 182 hardness: 2 block_sounds: break_sound: block.metal.break place_sound: block.metal.place hit_sound: block.metal.hit - step_sound: block.metal.hit + step_sound: block.metal.step fall_sound: block.metal.fall drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 -multi_power_cable_down_powered: - itemname: "Multi Power Cable" +power_merger_down_powered: + itemname: "Power Merger" material: paper Pack: generate_model: true parent_model: block/cube textures: - north: atlas:block/multi_power_cable_side_powered - south: atlas:block/multi_power_cable_side_powered - east: atlas:block/multi_power_cable_side_powered - west: atlas:block/multi_power_cable_side_powered - up: atlas:block/multi_power_cable_back_powered - down: atlas:block/multi_power_cable_front_powered + north: atlas:block/power_merger_side_powered + south: atlas:block/power_merger_side_powered + east: atlas:block/power_merger_side_powered + west: atlas:block/power_merger_side_powered + up: atlas:block/power_merger_back_powered + down: atlas:block/power_merger_front_powered Mechanics: custom_block: type: NOTEBLOCK - custom_variation: 166 + custom_variation: 183 hardness: 2 block_sounds: break_sound: block.metal.break @@ -3513,5 +4587,5 @@ multi_power_cable_down_powered: drop: silktouch: false loots: - - nexo_item: multi_power_cable + - nexo_item: power_merger probability: 1.0 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_bottom.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_bottom.png new file mode 100644 index 0000000..d8d8ef8 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_bottom.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side.png new file mode 100644 index 0000000..008f191 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side_active.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side_active.png new file mode 100644 index 0000000..cd80297 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_side_active.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top.png new file mode 100644 index 0000000..663f266 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top_active.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top_active.png new file mode 100644 index 0000000..2d848cc Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/cobblestone_generator_top_active.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back.png new file mode 100644 index 0000000..c8d182e Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_lava.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_lava.png new file mode 100644 index 0000000..7e73e63 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_lava.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_water.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_water.png new file mode 100644 index 0000000..b00b792 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_back_water.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom.png new file mode 100644 index 0000000..42051d4 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_lava.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_lava.png new file mode 100644 index 0000000..89816fb Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_lava.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_water.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_water.png new file mode 100644 index 0000000..61a2694 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_bottom_water.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front.png new file mode 100644 index 0000000..bff1a4e Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_lava.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_lava.png new file mode 100644 index 0000000..ce263aa Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_lava.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_water.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_water.png new file mode 100644 index 0000000..4c1f82f Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_front_water.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side.png new file mode 100644 index 0000000..d99b7fb Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_lava.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_lava.png new file mode 100644 index 0000000..7652c79 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_lava.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_water.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_water.png new file mode 100644 index 0000000..95161bc Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_side_water.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top.png new file mode 100644 index 0000000..fd8982a Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_lava.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_lava.png new file mode 100644 index 0000000..67268a8 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_lava.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_water.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_water.png new file mode 100644 index 0000000..f4d5b83 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_merger_top_water.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_bottom.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_bottom.png new file mode 100644 index 0000000..3d8ccca Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_bottom.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side.png new file mode 100644 index 0000000..a7ccf2d Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side_active.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side_active.png new file mode 100644 index 0000000..687b8e7 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_side_active.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top.png new file mode 100644 index 0000000..f0772b8 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top_active.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top_active.png new file mode 100644 index 0000000..a8941d8 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/obsidian_generator_top_active.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back.png new file mode 100644 index 0000000..a06eb86 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back_powered.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back_powered.png new file mode 100644 index 0000000..6135be0 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_back_powered.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom.png new file mode 100644 index 0000000..9ca4f37 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom_powered.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom_powered.png new file mode 100644 index 0000000..bb1b05f Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_bottom_powered.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front.png new file mode 100644 index 0000000..f489fcb Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front_powered.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front_powered.png new file mode 100644 index 0000000..0bb875e Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_front_powered.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side.png new file mode 100644 index 0000000..f5c05a0 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side_powered.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side_powered.png new file mode 100644 index 0000000..a9c8a7b Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_side_powered.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top.png new file mode 100644 index 0000000..8dc5975 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top.png differ diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top_powered.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top_powered.png new file mode 100644 index 0000000..9b876b7 Binary files /dev/null and b/src/main/resources/nexo/pack/assets/atlas/textures/block/power_merger_top_powered.png differ diff --git a/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml b/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml index c4c2763..30c82c0 100644 --- a/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml +++ b/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml @@ -195,3 +195,75 @@ auto_smelter_recipe: minecraft_type: REDSTONE G: minecraft_type: FURNACE + +cobblestone_generator_recipe: + result: + nexo_item: cobblestone_generator + amount: 1 + ingredients: + A: + minecraft_type: IRON_INGOT + B: + minecraft_type: IRON_INGOT + C: + minecraft_type: IRON_INGOT + D: + minecraft_type: REDSTONE + E: + minecraft_type: REDSTONE + F: + minecraft_type: REDSTONE + G: + minecraft_type: COBBLESTONE + +fluid_merger_recipe: + result: + nexo_item: fluid_merger + amount: 1 + ingredients: + A: + minecraft_type: IRON_INGOT + B: + minecraft_type: IRON_INGOT + C: + minecraft_type: IRON_INGOT + D: + minecraft_type: IRON_INGOT + E: + minecraft_type: BUCKET + +power_merger_recipe: + result: + nexo_item: power_merger + amount: 1 + ingredients: + A: + minecraft_type: COPPER_INGOT + B: + minecraft_type: COPPER_INGOT + C: + minecraft_type: COPPER_INGOT + D: + minecraft_type: COPPER_INGOT + E: + minecraft_type: REDSTONE + +obsidian_generator_recipe: + result: + nexo_item: obsidian_generator + amount: 1 + ingredients: + A: + minecraft_type: IRON_INGOT + B: + minecraft_type: IRON_INGOT + C: + minecraft_type: IRON_INGOT + D: + minecraft_type: REDSTONE + E: + minecraft_type: REDSTONE + F: + minecraft_type: REDSTONE + G: + minecraft_type: OBSIDIAN diff --git a/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt b/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt index c0c656a..37b989b 100644 --- a/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt @@ -30,13 +30,13 @@ class AtlasPluginTest { @Test fun `power system initializes with 27 block types`() { TestHelper.initPowerFactory() - assertEquals(39, PowerBlockFactory.getRegisteredBlockIds().size) + assertEquals(55, PowerBlockFactory.getRegisteredBlockIds().size) } @Test fun `fluid system initializes with 63 block types`() { TestHelper.initFluidFactory() - assertEquals(63, FluidBlockFactory.getRegisteredBlockIds().size) + assertEquals(81, FluidBlockFactory.getRegisteredBlockIds().size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt b/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt index de4fddd..2e33f55 100644 --- a/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt +++ b/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt @@ -7,6 +7,7 @@ import com.coderjoe.atlas.fluid.FluidBlockFactory import com.coderjoe.atlas.fluid.FluidBlockRegistry import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.fluid.block.FluidMerger import com.coderjoe.atlas.fluid.block.FluidPump import com.coderjoe.atlas.power.PowerBlock import com.coderjoe.atlas.power.PowerBlockFactory @@ -21,6 +22,9 @@ import com.coderjoe.atlas.power.block.PowerCable import com.coderjoe.atlas.power.block.SmallBattery import com.coderjoe.atlas.power.block.SmallDrill import com.coderjoe.atlas.power.block.MultiPowerCable +import com.coderjoe.atlas.power.block.CobblestoneGenerator +import com.coderjoe.atlas.power.block.ObsidianGenerator +import com.coderjoe.atlas.power.block.PowerMerger import com.coderjoe.atlas.power.block.SmallSolarPanel import io.mockk.* import org.bukkit.Location @@ -173,14 +177,15 @@ object TestHelper { SmallSolarPanel.descriptor, SmallDrill.descriptor, SmallBattery.descriptor, PowerCable.descriptor, LavaGenerator.descriptor, AutoSmelter.descriptor, - MultiPowerCable.descriptor + MultiPowerCable.descriptor, CobblestoneGenerator.descriptor, + ObsidianGenerator.descriptor, PowerMerger.descriptor )) } fun initFluidFactory() { FluidBlockFactory.registerFromDescriptors(listOf( FluidPump.descriptor, FluidPipe.descriptor, - FluidContainer.descriptor + FluidContainer.descriptor, FluidMerger.descriptor )) } diff --git a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt index 1eda9f4..23fcd5f 100644 --- a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt @@ -24,8 +24,8 @@ class FluidBlockRegistrationTest { TestHelper.initFluidFactory() val ids = FluidBlockFactory.getRegisteredBlockIds() - // 3 pump + 6 directional pipe + 6 water-filled + 6 lava-filled + 42 container = 63 - assertEquals(63, ids.size) + // 3 pump + 6 directional pipe + 6 water-filled + 6 lava-filled + 42 container + 18 fluid merger = 81 + assertEquals(81, ids.size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidMergerTest.kt b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidMergerTest.kt new file mode 100644 index 0000000..de2f041 --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidMergerTest.kt @@ -0,0 +1,152 @@ +package com.coderjoe.atlas.fluid + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callFluidUpdate +import com.coderjoe.atlas.fluid.block.FluidMerger +import com.coderjoe.atlas.fluid.block.FluidPipe +import org.bukkit.block.BlockFace +import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.* + +class FluidMergerTest { + + private lateinit var registry: FluidBlockRegistry + + @BeforeEach + fun setup() { + TestHelper.setup() + registry = FluidBlockRegistry(TestHelper.mockPlugin) + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + @Test + fun `visual state empty when no fluid`() { + val merger = FluidMerger(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals("fluid_merger_north", merger.getVisualStateBlockId()) + } + + @Test + fun `visual state water when holding water`() { + val merger = FluidMerger(TestHelper.createLocation(), BlockFace.NORTH) + merger.storeFluid(FluidType.WATER) + assertEquals("fluid_merger_north_filled", merger.getVisualStateBlockId()) + } + + @Test + fun `visual state lava when holding lava`() { + val merger = FluidMerger(TestHelper.createLocation(), BlockFace.NORTH) + merger.storeFluid(FluidType.LAVA) + assertEquals("fluid_merger_north_filled_lava", merger.getVisualStateBlockId()) + } + + @Test + fun `visual state varies by facing direction`() { + for ((face, expectedId) in FluidMerger.DIRECTIONAL_IDS) { + val merger = FluidMerger(TestHelper.createLocation(), face) + assertEquals(expectedId, merger.getVisualStateBlockId()) + } + } + + @Test + fun `pulls fluid from non-facing pipe`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = FluidMerger(mergerLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, merger, "fluid_merger_north") + + // Pipe to the south (not facing direction) + val pipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.NORTH) + pipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(registry, pipe, "fluid_pipe_north_filled") + + merger.callFluidUpdate() + + assertTrue(merger.hasFluid()) + assertEquals(FluidType.WATER, merger.storedFluid) + assertFalse(pipe.hasFluid()) + } + + @Test + fun `does not pull fluid from facing direction`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = FluidMerger(mergerLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, merger, "fluid_merger_north") + + // Pipe to the north (facing direction — should NOT pull from here) + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.SOUTH) + pipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(registry, pipe, "fluid_pipe_south_filled") + + merger.callFluidUpdate() + + assertFalse(merger.hasFluid()) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `does not pull when already holding fluid`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = FluidMerger(mergerLoc, BlockFace.NORTH) + merger.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(registry, merger, "fluid_merger_north_filled") + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.NORTH) + pipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(registry, pipe, "fluid_pipe_north_filled_lava") + + merger.callFluidUpdate() + + assertEquals(FluidType.WATER, merger.storedFluid) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `pulls from multiple input directions`() { + // First pull from east + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = FluidMerger(mergerLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, merger, "fluid_merger_north") + + val pipeLoc = TestHelper.createLocation(1.0, 64.0, 0.0) + val pipe = FluidPipe(pipeLoc, BlockFace.WEST) + pipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(registry, pipe, "fluid_pipe_west_filled_lava") + + merger.callFluidUpdate() + + assertTrue(merger.hasFluid()) + assertEquals(FluidType.LAVA, merger.storedFluid) + assertFalse(pipe.hasFluid()) + } + + @Test + fun `downstream pipe can pull from merger`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = FluidMerger(mergerLoc, BlockFace.NORTH) + merger.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(registry, merger, "fluid_merger_north_filled") + + // Merger holds fluid; downstream blocks pull via their own update + assertTrue(merger.hasFluid()) + val fluid = merger.removeFluid() + assertEquals(FluidType.WATER, fluid) + assertFalse(merger.hasFluid()) + } + + @Test + fun `descriptor has correct properties`() { + val desc = FluidMerger.descriptor + assertEquals("fluid_merger", desc.baseBlockId) + assertEquals("Fluid Merger", desc.displayName) + assertEquals(18, desc.allRegistrableIds.size) + assertTrue(desc.allRegistrableIds.contains("fluid_merger_north")) + assertTrue(desc.allRegistrableIds.contains("fluid_merger_north_filled")) + assertTrue(desc.allRegistrableIds.contains("fluid_merger_north_filled_lava")) + } +} diff --git a/src/test/kotlin/com/coderjoe/atlas/power/CobblestoneGeneratorTest.kt b/src/test/kotlin/com/coderjoe/atlas/power/CobblestoneGeneratorTest.kt new file mode 100644 index 0000000..56b3fc3 --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/power/CobblestoneGeneratorTest.kt @@ -0,0 +1,180 @@ +package com.coderjoe.atlas.power + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callPowerUpdate +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.power.block.CobblestoneGenerator +import org.bukkit.block.BlockFace +import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.* + +class CobblestoneGeneratorTest { + + @BeforeEach + fun setup() { + TestHelper.setup() + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + @Test + fun `cobblestone generator maxStorage is 2`() { + val gen = CobblestoneGenerator(TestHelper.createLocation()) + assertEquals(2, gen.maxStorage) + } + + @Test + fun `cobblestone generator canReceivePower is true`() { + val gen = CobblestoneGenerator(TestHelper.createLocation()) + assertTrue(gen.canAcceptPower()) + } + + @Test + fun `visual state idle when insufficient power`() { + val gen = CobblestoneGenerator(TestHelper.createLocation()) + assertEquals("cobblestone_generator", gen.getVisualStateBlockId()) + } + + @Test + fun `visual state active when power at cost`() { + val gen = CobblestoneGenerator(TestHelper.createLocation()) + gen.currentPower = 2 + assertEquals("cobblestone_generator_active", gen.getVisualStateBlockId()) + } + + @Test + fun `does not generate when only water available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = CobblestoneGenerator(genLoc) + gen.currentPower = 2 + TestHelper.addToRegistry(powerRegistry, gen, "cobblestone_generator") + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.SOUTH) + pipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south_filled_water") + + gen.callPowerUpdate() + + assertEquals(2, gen.currentPower) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `does not generate when only lava available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = CobblestoneGenerator(genLoc) + gen.currentPower = 2 + TestHelper.addToRegistry(powerRegistry, gen, "cobblestone_generator") + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.SOUTH) + pipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south_filled_lava") + + gen.callPowerUpdate() + + assertEquals(2, gen.currentPower) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `does not generate when insufficient power`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = CobblestoneGenerator(genLoc) + gen.currentPower = 1 + TestHelper.addToRegistry(powerRegistry, gen, "cobblestone_generator") + + val waterPipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val waterPipe = FluidPipe(waterPipeLoc, BlockFace.SOUTH) + waterPipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, waterPipe, "fluid_pipe_south_filled_water") + + val lavaPipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val lavaPipe = FluidPipe(lavaPipeLoc, BlockFace.NORTH) + lavaPipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, lavaPipe, "fluid_pipe_north_filled_lava") + + gen.callPowerUpdate() + + assertEquals(1, gen.currentPower) + assertTrue(waterPipe.hasFluid()) + assertTrue(lavaPipe.hasFluid()) + } + + @Test + fun `consumes water, lava, and power when all available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = CobblestoneGenerator(genLoc) + gen.currentPower = 2 + TestHelper.addToRegistry(powerRegistry, gen, "cobblestone_generator") + + val waterPipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val waterPipe = FluidPipe(waterPipeLoc, BlockFace.SOUTH) + waterPipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, waterPipe, "fluid_pipe_south_filled_water") + + val lavaPipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val lavaPipe = FluidPipe(lavaPipeLoc, BlockFace.NORTH) + lavaPipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, lavaPipe, "fluid_pipe_north_filled_lava") + + try { + gen.callPowerUpdate() + } catch (_: Throwable) { + // ItemStack constructor triggers Registry init in test environment + } + + assertEquals(0, gen.currentPower) + assertFalse(waterPipe.hasFluid()) + assertFalse(lavaPipe.hasFluid()) + } + + @Test + fun `descriptor has correct properties`() { + val desc = CobblestoneGenerator.descriptor + assertEquals("cobblestone_generator", desc.baseBlockId) + assertEquals("Cobblestone Generator", desc.displayName) + assertEquals(2, desc.allRegistrableIds.size) + assertTrue(desc.allRegistrableIds.contains("cobblestone_generator")) + assertTrue(desc.allRegistrableIds.contains("cobblestone_generator_active")) + } + + @Test + fun `pulls power from adjacent blocks`() { + FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = CobblestoneGenerator(genLoc) + TestHelper.addToRegistry(powerRegistry, gen, "cobblestone_generator") + + val batteryLoc = TestHelper.createLocation(1.0, 64.0, 0.0) + val battery = com.coderjoe.atlas.power.block.SmallBattery(batteryLoc, BlockFace.DOWN) + battery.currentPower = 5 + TestHelper.addToRegistry(powerRegistry, battery, "small_battery") + + gen.callPowerUpdate() + + // Pulls 1 power per neighbor per tick + assertEquals(1, gen.currentPower) + assertEquals(4, battery.currentPower) + } +} diff --git a/src/test/kotlin/com/coderjoe/atlas/power/ObsidianGeneratorTest.kt b/src/test/kotlin/com/coderjoe/atlas/power/ObsidianGeneratorTest.kt new file mode 100644 index 0000000..ccc73e3 --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/power/ObsidianGeneratorTest.kt @@ -0,0 +1,181 @@ +package com.coderjoe.atlas.power + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callPowerUpdate +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.power.block.ObsidianGenerator +import org.bukkit.block.BlockFace +import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.* + +class ObsidianGeneratorTest { + + @BeforeEach + fun setup() { + TestHelper.setup() + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + @Test + fun `obsidian generator maxStorage is 100`() { + val gen = ObsidianGenerator(TestHelper.createLocation()) + assertEquals(100, gen.maxStorage) + } + + @Test + fun `obsidian generator canReceivePower is true`() { + val gen = ObsidianGenerator(TestHelper.createLocation()) + assertTrue(gen.canAcceptPower()) + } + + @Test + fun `visual state idle when insufficient power`() { + val gen = ObsidianGenerator(TestHelper.createLocation()) + gen.currentPower = 99 + assertEquals("obsidian_generator", gen.getVisualStateBlockId()) + } + + @Test + fun `visual state active when power at cost`() { + val gen = ObsidianGenerator(TestHelper.createLocation()) + gen.currentPower = 100 + assertEquals("obsidian_generator_active", gen.getVisualStateBlockId()) + } + + @Test + fun `does not generate when only water available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = ObsidianGenerator(genLoc) + gen.currentPower = 100 + TestHelper.addToRegistry(powerRegistry, gen, "obsidian_generator") + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.SOUTH) + pipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south_filled_water") + + gen.callPowerUpdate() + + assertEquals(100, gen.currentPower) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `does not generate when only lava available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = ObsidianGenerator(genLoc) + gen.currentPower = 100 + TestHelper.addToRegistry(powerRegistry, gen, "obsidian_generator") + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.SOUTH) + pipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south_filled_lava") + + gen.callPowerUpdate() + + assertEquals(100, gen.currentPower) + assertTrue(pipe.hasFluid()) + } + + @Test + fun `does not generate when insufficient power`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = ObsidianGenerator(genLoc) + gen.currentPower = 99 + TestHelper.addToRegistry(powerRegistry, gen, "obsidian_generator") + + val waterPipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val waterPipe = FluidPipe(waterPipeLoc, BlockFace.SOUTH) + waterPipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, waterPipe, "fluid_pipe_south_filled_water") + + val lavaPipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val lavaPipe = FluidPipe(lavaPipeLoc, BlockFace.NORTH) + lavaPipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, lavaPipe, "fluid_pipe_north_filled_lava") + + gen.callPowerUpdate() + + assertEquals(99, gen.currentPower) + assertTrue(waterPipe.hasFluid()) + assertTrue(lavaPipe.hasFluid()) + } + + @Test + fun `consumes water, lava, and power when all available`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = ObsidianGenerator(genLoc) + gen.currentPower = 100 + TestHelper.addToRegistry(powerRegistry, gen, "obsidian_generator") + + val waterPipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val waterPipe = FluidPipe(waterPipeLoc, BlockFace.SOUTH) + waterPipe.storeFluid(FluidType.WATER) + TestHelper.addToRegistry(fluidRegistry, waterPipe, "fluid_pipe_south_filled_water") + + val lavaPipeLoc = TestHelper.createLocation(0.0, 64.0, 1.0) + val lavaPipe = FluidPipe(lavaPipeLoc, BlockFace.NORTH) + lavaPipe.storeFluid(FluidType.LAVA) + TestHelper.addToRegistry(fluidRegistry, lavaPipe, "fluid_pipe_north_filled_lava") + + try { + gen.callPowerUpdate() + } catch (_: Throwable) { + // ItemStack constructor triggers Registry init in test environment + } + + assertEquals(0, gen.currentPower) + assertFalse(waterPipe.hasFluid()) + assertFalse(lavaPipe.hasFluid()) + } + + @Test + fun `descriptor has correct properties`() { + val desc = ObsidianGenerator.descriptor + assertEquals("obsidian_generator", desc.baseBlockId) + assertEquals("Obsidian Generator", desc.displayName) + assertEquals(2, desc.allRegistrableIds.size) + assertTrue(desc.allRegistrableIds.contains("obsidian_generator")) + assertTrue(desc.allRegistrableIds.contains("obsidian_generator_active")) + } + + @Test + fun `accumulates power over multiple ticks`() { + FluidBlockRegistry(TestHelper.mockPlugin) + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + + val genLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val gen = ObsidianGenerator(genLoc) + TestHelper.addToRegistry(powerRegistry, gen, "obsidian_generator") + + val batteryLoc = TestHelper.createLocation(1.0, 64.0, 0.0) + val battery = com.coderjoe.atlas.power.block.SmallBattery(batteryLoc, BlockFace.DOWN) + battery.currentPower = 10 + TestHelper.addToRegistry(powerRegistry, battery, "small_battery") + + gen.callPowerUpdate() + + // Should pull power but not yet have enough to generate + assertTrue(gen.currentPower > 0) + assertTrue(gen.currentPower < 100) + } +} diff --git a/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt b/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt index e2f5b7c..7132f52 100644 --- a/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt @@ -26,8 +26,8 @@ class PowerBlockRegistrationTest { TestHelper.initPowerFactory() val ids = PowerBlockFactory.getRegisteredBlockIds() - // 1 solar + 6 drill + 4 battery + 6 cable + 2 lava generator + 8 auto smelter + 12 multi power cable = 39 - assertEquals(39, ids.size) + // 1 solar + 6 drill + 4 battery + 6 cable + 2 lava generator + 8 auto smelter + 12 multi power cable + 2 cobblestone generator + 2 obsidian generator + 12 power merger = 55 + assertEquals(55, ids.size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/power/PowerMergerTest.kt b/src/test/kotlin/com/coderjoe/atlas/power/PowerMergerTest.kt new file mode 100644 index 0000000..f40ce36 --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/power/PowerMergerTest.kt @@ -0,0 +1,144 @@ +package com.coderjoe.atlas.power + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callPowerUpdate +import com.coderjoe.atlas.power.block.PowerMerger +import com.coderjoe.atlas.power.block.SmallSolarPanel +import org.bukkit.block.BlockFace +import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.* + +class PowerMergerTest { + + private lateinit var registry: PowerBlockRegistry + + @BeforeEach + fun setup() { + TestHelper.setup() + registry = PowerBlockRegistry(TestHelper.mockPlugin) + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + @Test + fun `maxStorage is 2`() { + val merger = PowerMerger(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals(2, merger.maxStorage) + } + + @Test + fun `canReceivePower is false`() { + // PowerMerger does not use canReceivePower — it pulls manually from non-facing sides + val merger = PowerMerger(TestHelper.createLocation(), BlockFace.NORTH) + assertFalse(merger.canAcceptPower()) + } + + @Test + fun `visual state unpowered when no power`() { + val merger = PowerMerger(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals("power_merger_north", merger.getVisualStateBlockId()) + } + + @Test + fun `visual state powered when has power`() { + val merger = PowerMerger(TestHelper.createLocation(), BlockFace.NORTH) + merger.currentPower = 1 + assertEquals("power_merger_north_powered", merger.getVisualStateBlockId()) + } + + @Test + fun `visual state varies by facing direction`() { + for ((face, expectedId) in PowerMerger.DIRECTIONAL_IDS) { + val merger = PowerMerger(TestHelper.createLocation(), face) + assertEquals(expectedId, merger.getVisualStateBlockId()) + } + } + + @Test + fun `pulls power from non-facing sides`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = PowerMerger(mergerLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, merger, "power_merger_north") + + // Source to the south (opposite of facing — behind) + val source1 = SmallSolarPanel(TestHelper.createLocation(0.0, 64.0, 1.0)) + source1.currentPower = 1 + TestHelper.addToRegistry(registry, source1, "small_solar_panel") + + // Source to the east (side) + val source2 = SmallSolarPanel(TestHelper.createLocation(1.0, 64.0, 0.0)) + source2.currentPower = 1 + TestHelper.addToRegistry(registry, source2, "small_solar_panel") + + merger.callPowerUpdate() + + assertEquals(2, merger.currentPower) + assertEquals(0, source1.currentPower) + assertEquals(0, source2.currentPower) + } + + @Test + fun `does not pull power from facing direction`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = PowerMerger(mergerLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, merger, "power_merger_north") + + // Source to the north (facing direction — should NOT pull from here) + val source = SmallSolarPanel(TestHelper.createLocation(0.0, 64.0, -1.0)) + source.currentPower = 1 + TestHelper.addToRegistry(registry, source, "small_solar_panel") + + merger.callPowerUpdate() + + assertEquals(0, merger.currentPower) + assertEquals(1, source.currentPower) + } + + @Test + fun `stops pulling when full`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = PowerMerger(mergerLoc, BlockFace.NORTH) + merger.currentPower = 2 + TestHelper.addToRegistry(registry, merger, "power_merger_north") + + val source = SmallSolarPanel(TestHelper.createLocation(0.0, 64.0, 1.0)) + source.currentPower = 1 + TestHelper.addToRegistry(registry, source, "small_solar_panel") + + merger.callPowerUpdate() + + assertEquals(2, merger.currentPower) + assertEquals(1, source.currentPower) + } + + @Test + fun `descriptor has correct properties`() { + val desc = PowerMerger.descriptor + assertEquals("power_merger", desc.baseBlockId) + assertEquals("Power Merger", desc.displayName) + assertEquals(12, desc.allRegistrableIds.size) + assertTrue(desc.allRegistrableIds.contains("power_merger_north")) + assertTrue(desc.allRegistrableIds.contains("power_merger_north_powered")) + } + + @Test + fun `downstream block can pull from merger in facing direction`() { + val mergerLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val merger = PowerMerger(mergerLoc, BlockFace.NORTH) + merger.currentPower = 2 + TestHelper.addToRegistry(registry, merger, "power_merger_north") + + // Consumer to the north (facing direction) that pulls from adjacent + val consumer = com.coderjoe.atlas.power.block.SmallDrill(TestHelper.createLocation(0.0, 64.0, -1.0), BlockFace.DOWN) + TestHelper.addToRegistry(registry, consumer, "small_drill_down") + + // The merger stores power; downstream blocks pull from it via their own update + assertTrue(merger.hasPower()) + val pulled = merger.removePower(1) + assertEquals(1, pulled) + assertEquals(1, merger.currentPower) + } +}