From b6e086332db3eae428b0488db3ccd18313ad8ee6 Mon Sep 17 00:00:00 2001 From: CoderJoe Date: Thu, 5 Mar 2026 22:05:55 -0600 Subject: [PATCH 1/4] Add fluid container block with 10-unit capacity and directional I/O FluidContainer extends FluidBlock with multi-unit storage (up to 10), directional input/output, type locking, and 4 visual fill levels (empty, low, medium, full). Integrates with pipes and pumps for pulling and dispensing fluid. --- .../com/coderjoe/atlas/NexoIntegration.kt | 30 +++- .../com/coderjoe/atlas/fluid/FluidBlock.kt | 6 +- .../coderjoe/atlas/fluid/FluidBlockData.kt | 12 +- .../coderjoe/atlas/fluid/FluidBlockDialog.kt | 20 ++- .../atlas/fluid/FluidBlockInitializer.kt | 8 + .../atlas/fluid/FluidBlockListener.kt | 49 +++++- .../atlas/fluid/FluidBlockPersistence.kt | 13 +- .../atlas/fluid/block/FluidContainer.kt | 155 ++++++++++++++++++ .../coderjoe/atlas/fluid/block/FluidPipe.kt | 7 + 9 files changed, 283 insertions(+), 17 deletions(-) create mode 100644 src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt diff --git a/src/main/kotlin/com/coderjoe/atlas/NexoIntegration.kt b/src/main/kotlin/com/coderjoe/atlas/NexoIntegration.kt index 4572ee8..77cab81 100644 --- a/src/main/kotlin/com/coderjoe/atlas/NexoIntegration.kt +++ b/src/main/kotlin/com/coderjoe/atlas/NexoIntegration.kt @@ -95,7 +95,35 @@ class NexoIntegration(private val plugin: JavaPlugin) { "fluid_pipe_side_filled_lava_up", "fluid_pipe_side_filled_lava_down", "fluid_pipe_side_filled_lava_left", - "fluid_pipe_side_filled_lava_right" + "fluid_pipe_side_filled_lava_right", + "fluid_container_front", + "fluid_container_back", + "fluid_container_side", + "fluid_container_top", + "fluid_container_front_water_low", + "fluid_container_back_water_low", + "fluid_container_side_water_low", + "fluid_container_top_water_low", + "fluid_container_front_water_medium", + "fluid_container_back_water_medium", + "fluid_container_side_water_medium", + "fluid_container_top_water_medium", + "fluid_container_front_water_full", + "fluid_container_back_water_full", + "fluid_container_side_water_full", + "fluid_container_top_water_full", + "fluid_container_front_lava_low", + "fluid_container_back_lava_low", + "fluid_container_side_lava_low", + "fluid_container_top_lava_low", + "fluid_container_front_lava_medium", + "fluid_container_back_lava_medium", + "fluid_container_side_lava_medium", + "fluid_container_top_lava_medium", + "fluid_container_front_lava_full", + "fluid_container_back_lava_full", + "fluid_container_side_lava_full", + "fluid_container_top_lava_full" ) for (textureName in textures) { val textureFile = File(texturesFolder, "$textureName.png") diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlock.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlock.kt index abd9894..407ecba 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlock.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlock.kt @@ -20,15 +20,15 @@ abstract class FluidBlock( internal var testPlugin: JavaPlugin? = null } - fun hasFluid(): Boolean = storedFluid != FluidType.NONE + open fun hasFluid(): Boolean = storedFluid != FluidType.NONE - fun storeFluid(type: FluidType): Boolean { + open fun storeFluid(type: FluidType): Boolean { if (storedFluid != FluidType.NONE) return false storedFluid = type return true } - fun removeFluid(): FluidType { + open fun removeFluid(): FluidType { val fluid = storedFluid storedFluid = FluidType.NONE return fluid diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockData.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockData.kt index e2f9b55..18450e5 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockData.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockData.kt @@ -1,5 +1,6 @@ package com.coderjoe.atlas.fluid +import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe import com.coderjoe.atlas.fluid.block.FluidPump import org.bukkit.Location @@ -13,13 +14,19 @@ data class FluidBlockData( val y: Int, val z: Int, val fluidType: String, - val facing: String? = null + val facing: String? = null, + val storedAmount: Int? = null ) { companion object { fun fromFluidBlock(fluidBlock: FluidBlock, blockId: String): FluidBlockData { val loc = fluidBlock.location val facing = when (fluidBlock) { is FluidPipe -> fluidBlock.facing.name + is FluidContainer -> fluidBlock.facing.name + else -> null + } + val storedAmount = when (fluidBlock) { + is FluidContainer -> fluidBlock.storedAmount else -> null } return FluidBlockData( @@ -29,7 +36,8 @@ data class FluidBlockData( y = loc.blockY, z = loc.blockZ, fluidType = fluidBlock.storedFluid.name, - facing = facing + facing = facing, + storedAmount = storedAmount ) } } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt index 79d9f4d..bf03f36 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt @@ -1,5 +1,6 @@ package com.coderjoe.atlas.fluid +import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe import com.coderjoe.atlas.fluid.block.FluidPump import io.papermc.paper.dialog.Dialog @@ -93,14 +94,23 @@ object FluidBlockDialog { private fun getBlockDisplayName(fluidBlock: FluidBlock): String = when (fluidBlock) { 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() }})" else -> "Fluid Block" } private fun buildFluidInfo(fluidBlock: FluidBlock): Component { - val fluidName = when (fluidBlock.storedFluid) { - FluidType.WATER -> "Water" - FluidType.LAVA -> "Lava" - FluidType.NONE -> "Empty" + val fluidName = if (fluidBlock is FluidContainer && fluidBlock.storedAmount > 0) { + when (fluidBlock.storedFluid) { + FluidType.WATER -> "Water (${fluidBlock.storedAmount}/${FluidContainer.MAX_CAPACITY})" + FluidType.LAVA -> "Lava (${fluidBlock.storedAmount}/${FluidContainer.MAX_CAPACITY})" + FluidType.NONE -> "Empty" + } + } else { + when (fluidBlock.storedFluid) { + FluidType.WATER -> "Water" + FluidType.LAVA -> "Lava" + FluidType.NONE -> "Empty" + } } val fluidColor = when (fluidBlock.storedFluid) { @@ -119,6 +129,8 @@ object FluidBlockDialog { .color(NamedTextColor.GRAY) is FluidPipe -> Component.text("Pipe - transports fluid in facing direction") .color(NamedTextColor.GRAY) + is FluidContainer -> Component.text("Container - stores up to ${FluidContainer.MAX_CAPACITY} units of fluid") + .color(NamedTextColor.GRAY) else -> Component.text("Fluid block") .color(NamedTextColor.GRAY) } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializer.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializer.kt index 0970fd6..9a26598 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializer.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializer.kt @@ -1,5 +1,6 @@ package com.coderjoe.atlas.fluid +import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe import com.coderjoe.atlas.fluid.block.FluidPump import org.bukkit.plugin.java.JavaPlugin @@ -37,6 +38,13 @@ object FluidBlockInitializer { } } + plugin.logger.info("Registering FluidContainer variants...") + for (variantId in FluidContainer.ALL_VARIANT_IDS) { + FluidBlockFactory.register(variantId) { location, facing -> + FluidContainer(location, facing) + } + } + val registeredBlocks = FluidBlockFactory.getRegisteredBlockIds() plugin.logger.info("Initialized ${registeredBlocks.size} fluid block type(s): ${registeredBlocks.joinToString(", ")}") plugin.logger.info("FluidBlockInitializer complete") diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockListener.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockListener.kt index 6337a93..c80026d 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockListener.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockListener.kt @@ -1,5 +1,6 @@ package com.coderjoe.atlas.fluid +import com.coderjoe.atlas.fluid.block.FluidContainer import com.coderjoe.atlas.fluid.block.FluidPipe import com.coderjoe.atlas.fluid.block.FluidPump import com.nexomc.nexo.api.NexoBlocks @@ -39,6 +40,32 @@ class FluidBlockListener( return } + // Handle fluid_container base item: swap to directional variant + if (blockId == FluidContainer.BLOCK_ID) { + val facing = getPlayerFacing(event) + val variantId = FluidContainer.DIRECTIONAL_IDS[facing] + if (variantId == null) { + plugin.logger.warning("No directional variant for facing $facing") + return + } + + plugin.logger.info("Swapping fluid_container to directional variant: $variantId (facing $facing)") + + val location = event.block.location.clone() + plugin.server.scheduler.runTask(plugin, Runnable { + location.block.setType(Material.AIR, false) + NexoBlocks.place(variantId, location) + + val fluidBlock = FluidBlockFactory.createFluidBlock(variantId, location, facing) + if (fluidBlock != null) { + registry.registerFluidBlock(fluidBlock, variantId) + } else { + plugin.logger.warning("Failed to create fluid block for variant: $variantId") + } + }) + return + } + // Handle fluid_pipe base item: swap to directional variant if (blockId == FluidPipe.BLOCK_ID) { val facing = getPlayerFacing(event) @@ -65,11 +92,22 @@ class FluidBlockListener( return } - // Handle directional variant placed directly - val facing = FluidPipe.facingFromBlockId(blockId) - if (facing != null) { - plugin.logger.info("Directional fluid pipe placed: $blockId (facing $facing)") - val fluidBlock = FluidBlockFactory.createFluidBlock(blockId, event.block.location, facing) + // Handle directional variant placed directly (pipe) + val pipeFacing = FluidPipe.facingFromBlockId(blockId) + if (pipeFacing != null) { + plugin.logger.info("Directional fluid pipe placed: $blockId (facing $pipeFacing)") + val fluidBlock = FluidBlockFactory.createFluidBlock(blockId, event.block.location, pipeFacing) + if (fluidBlock != null) { + registry.registerFluidBlock(fluidBlock, blockId) + } + return + } + + // Handle directional variant placed directly (container) + val containerFacing = FluidContainer.facingFromBlockId(blockId) + if (containerFacing != null) { + plugin.logger.info("Directional fluid container placed: $blockId (facing $containerFacing)") + val fluidBlock = FluidBlockFactory.createFluidBlock(blockId, event.block.location, containerFacing) if (fluidBlock != null) { registry.registerFluidBlock(fluidBlock, blockId) } @@ -97,6 +135,7 @@ class FluidBlockListener( val baseItemId = when (fluidBlock) { is FluidPump -> FluidPump.BLOCK_ID is FluidPipe -> FluidPipe.BLOCK_ID + is FluidContainer -> FluidContainer.BLOCK_ID else -> null } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockPersistence.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockPersistence.kt index 390d954..1dc4695 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockPersistence.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockPersistence.kt @@ -1,5 +1,6 @@ package com.coderjoe.atlas.fluid +import com.coderjoe.atlas.fluid.block.FluidContainer import org.bukkit.configuration.file.YamlConfiguration import org.bukkit.plugin.java.JavaPlugin import java.io.File @@ -28,6 +29,9 @@ class FluidBlockPersistence(private val plugin: JavaPlugin) { if (data.facing != null) { map["facing"] = data.facing } + if (data.storedAmount != null) { + map["storedAmount"] = data.storedAmount + } blockDataList.add(map) } @@ -65,8 +69,9 @@ class FluidBlockPersistence(private val plugin: JavaPlugin) { val z = (blockDataMap["z"] as? Number)?.toInt() ?: continue val fluidType = blockDataMap["fluidType"] as? String ?: "NONE" val facing = blockDataMap["facing"] as? String + val storedAmount = (blockDataMap["storedAmount"] as? Number)?.toInt() - val data = FluidBlockData(blockId, world, x, y, z, fluidType, facing) + val data = FluidBlockData(blockId, world, x, y, z, fluidType, facing, storedAmount) val location = data.toLocation(plugin) if (location == null) { @@ -78,7 +83,11 @@ class FluidBlockPersistence(private val plugin: JavaPlugin) { val fluidBlock = FluidBlockFactory.createFluidBlock(blockId, location, data.toBlockFace()) if (fluidBlock != null) { - fluidBlock.storedFluid = data.toFluidType() + if (fluidBlock is FluidContainer && data.storedAmount != null) { + fluidBlock.restoreState(data.toFluidType(), data.storedAmount) + } else { + fluidBlock.storedFluid = data.toFluidType() + } registry.registerFluidBlock(fluidBlock, blockId) loadedCount++ } else { diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt new file mode 100644 index 0000000..4ea37a9 --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidContainer.kt @@ -0,0 +1,155 @@ +package com.coderjoe.atlas.fluid.block + +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 FluidContainer(location: Location, val facing: BlockFace) : FluidBlock(location) { + + var storedAmount: Int = 0 + private set + + override val updateIntervalTicks: Long = 20L + + companion object { + const val BLOCK_ID = "fluid_container" + const val MAX_CAPACITY = 10 + + val DIRECTIONAL_IDS = mapOf( + BlockFace.NORTH to "fluid_container_north", + BlockFace.SOUTH to "fluid_container_south", + BlockFace.EAST to "fluid_container_east", + BlockFace.WEST to "fluid_container_west", + BlockFace.UP to "fluid_container_up", + BlockFace.DOWN to "fluid_container_down" + ) + + val ID_TO_FACING = DIRECTIONAL_IDS.entries.associate { (face, id) -> id to face } + + private val FILL_LEVELS = listOf("low", "medium", "full") + private val FLUID_TYPES = listOf("water", "lava") + + val FILLED_IDS: Map>> = BlockFace.values() + .filter { DIRECTIONAL_IDS.containsKey(it) } + .associateWith { face -> + val dir = face.name.lowercase() + mapOf( + FluidType.WATER to mapOf( + "low" to "fluid_container_${dir}_water_low", + "medium" to "fluid_container_${dir}_water_medium", + "full" to "fluid_container_${dir}_water_full" + ), + FluidType.LAVA to mapOf( + "low" to "fluid_container_${dir}_lava_low", + "medium" to "fluid_container_${dir}_lava_medium", + "full" to "fluid_container_${dir}_lava_full" + ) + ) + } + + val ALL_VARIANT_IDS: List = buildList { + addAll(DIRECTIONAL_IDS.values) + for (face in FILLED_IDS.keys) { + for (fluidMap in FILLED_IDS[face]!!.values) { + addAll(fluidMap.values) + } + } + } + + fun facingFromBlockId(blockId: String): BlockFace? { + ID_TO_FACING[blockId]?.let { return it } + for ((face, fluidMap) in FILLED_IDS) { + for (levelMap in fluidMap.values) { + if (blockId in levelMap.values) return face + } + } + return null + } + } + + override fun hasFluid(): Boolean = storedAmount > 0 + + override fun storeFluid(type: FluidType): Boolean { + if (storedAmount >= MAX_CAPACITY) return false + if (storedFluid != FluidType.NONE && storedFluid != type) return false + storedFluid = type + storedAmount++ + return true + } + + override fun removeFluid(): FluidType { + if (storedAmount <= 0) return FluidType.NONE + val fluid = storedFluid + storedAmount-- + if (storedAmount == 0) { + storedFluid = FluidType.NONE + } + return fluid + } + + fun canRemoveFluidFrom(direction: BlockFace): Boolean { + return direction == facing && hasFluid() + } + + fun getFillLevel(): String = when (storedAmount) { + 0 -> "empty" + in 1..3 -> "low" + in 4..7 -> "medium" + else -> "full" + } + + override fun getVisualStateBlockId(): String { + if (storedAmount == 0 || storedFluid == FluidType.NONE) { + return DIRECTIONAL_IDS[facing]!! + } + return FILLED_IDS[facing]!![storedFluid]!![getFillLevel()]!! + } + + override fun fluidUpdate() { + if (storedAmount >= MAX_CAPACITY) return + + val registry = FluidBlockRegistry.instance ?: return + val behind = facing.oppositeFace + val source = registry.getAdjacentFluidBlock(location, behind) ?: return + + when (source) { + is FluidPump -> { + if (source.canRemoveFluidFrom(facing)) { + val fluid = source.removeFluid() + if (storeFluid(fluid)) { + plugin.logger.info("FluidContainer at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidPump") + } else { + source.storeFluid(fluid) + } + } + } + is FluidPipe -> { + if (source.hasFluid()) { + val fluid = source.removeFluid() + if (storeFluid(fluid)) { + plugin.logger.info("FluidContainer at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidPipe") + } else { + source.storeFluid(fluid) + } + } + } + is FluidContainer -> { + if (source.canRemoveFluidFrom(facing)) { + val fluid = source.removeFluid() + if (storeFluid(fluid)) { + plugin.logger.info("FluidContainer at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidContainer") + } else { + source.storeFluid(fluid) + } + } + } + } + } + + fun restoreState(type: FluidType, amount: Int) { + storedFluid = type + storedAmount = amount.coerceIn(0, MAX_CAPACITY) + } +} 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 575391b..56c7575 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPipe.kt @@ -73,6 +73,13 @@ class FluidPipe(location: Location, val facing: BlockFace) : FluidBlock(location plugin.logger.info("FluidPipe at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidPipe") } } + is FluidContainer -> { + if (source.canRemoveFluidFrom(facing)) { + val fluid = source.removeFluid() + storeFluid(fluid) + plugin.logger.info("FluidPipe at ${location.blockX},${location.blockY},${location.blockZ} pulled ${fluid.name} from FluidContainer") + } + } } } } From f523f97ce4929ef0ee666105aa67c5c4e06f43ff Mon Sep 17 00:00:00 2001 From: CoderJoe Date: Thu, 5 Mar 2026 22:06:03 -0600 Subject: [PATCH 2/4] Add fluid container textures with distinct fill levels 28 textures: glass tank with metal frame showing empty, low, medium, and full states for both water and lava, across front/back/side/top faces. --- .../atlas/textures/block/fluid_container_back.png | Bin 0 -> 278 bytes .../block/fluid_container_back_lava_full.png | Bin 0 -> 213 bytes .../block/fluid_container_back_lava_low.png | Bin 0 -> 313 bytes .../block/fluid_container_back_lava_medium.png | Bin 0 -> 304 bytes .../block/fluid_container_back_water_full.png | Bin 0 -> 214 bytes .../block/fluid_container_back_water_low.png | Bin 0 -> 316 bytes .../block/fluid_container_back_water_medium.png | Bin 0 -> 306 bytes .../textures/block/fluid_container_front.png | Bin 0 -> 288 bytes .../block/fluid_container_front_lava_full.png | Bin 0 -> 233 bytes .../block/fluid_container_front_lava_low.png | Bin 0 -> 316 bytes .../block/fluid_container_front_lava_medium.png | Bin 0 -> 301 bytes .../block/fluid_container_front_water_full.png | Bin 0 -> 233 bytes .../block/fluid_container_front_water_low.png | Bin 0 -> 319 bytes .../block/fluid_container_front_water_medium.png | Bin 0 -> 304 bytes .../atlas/textures/block/fluid_container_side.png | Bin 0 -> 237 bytes .../block/fluid_container_side_lava_full.png | Bin 0 -> 168 bytes .../block/fluid_container_side_lava_low.png | Bin 0 -> 283 bytes .../block/fluid_container_side_lava_medium.png | Bin 0 -> 273 bytes .../block/fluid_container_side_water_full.png | Bin 0 -> 168 bytes .../block/fluid_container_side_water_low.png | Bin 0 -> 281 bytes .../block/fluid_container_side_water_medium.png | Bin 0 -> 275 bytes .../atlas/textures/block/fluid_container_top.png | Bin 0 -> 222 bytes .../block/fluid_container_top_lava_full.png | Bin 0 -> 180 bytes .../block/fluid_container_top_lava_low.png | Bin 0 -> 270 bytes .../block/fluid_container_top_lava_medium.png | Bin 0 -> 283 bytes .../block/fluid_container_top_water_full.png | Bin 0 -> 180 bytes .../block/fluid_container_top_water_low.png | Bin 0 -> 273 bytes .../block/fluid_container_top_water_medium.png | Bin 0 -> 290 bytes 28 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_lava_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_lava_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_lava_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_water_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_water_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_water_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_lava_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_lava_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_lava_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_medium.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_full.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_low.png create mode 100644 src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_medium.png diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back.png new file mode 100644 index 0000000000000000000000000000000000000000..40c60ea4cb1590a692c4c3b480d980d579890c53 GIT binary patch literal 278 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJyPhtNAr*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!Gs`ZL+!yeUticUGET6Fz0{EI6s2HR zIl)2`q`DWB4Vi!Xj-5b0UQ*tT#Mn}p-u$BggiG)XYC aGVEF|FLm#2%3`2L89ZJ6T-G@yGywo|zizw$ literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_lava_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_back_lava_full.png new file mode 100644 index 0000000000000000000000000000000000000000..aa2514ceae20d69c2181278edf89da4d68304667 GIT binary patch literal 213 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJIi4<#Ar*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Pt_*Ujyc>14yo5wbzIYX_Dk*Y$4BS1AnWx*7*c+-=GP5!ipVSq4(C>a8=uQStS3j3^P6o;-p$00bfnDk|mVo;-p$00bfnDk|mV32au#l?3?q+~FA+ba18&1;90f*2G2U$*vg@Y~%n8?utO6{bGQ{4em22(CLL_z#h z#Q~H8rcnnlj5=U|0n>!0O_0 z@&s?k)ARFenk*Pt?%hb4w`BQKCHG~sn={nf7}9$;Wz7RYYEQ_9}q;BB(Y z>cGp(g~dTfR=#Vft(m6oDY$$W^9s(06@t%SBrUnJMrVl?!`*@jPp5=D_2FUWnQ`Kx z$t>;(j7xnjQB4$l&mbnzd}$i5D<8wxAao;-p$00bfnDk|mVE;9G08o)QPyhg0q!`;${l{|v O0000o;-p$00bfnDk|mV!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!!0O_0 z@&s?k)ARFenk*Pt_*Ujyc>14yo5wbzIYX_Dko;-p$00bfnDk|mV zJQLCa>6!+%LoMI2Z4;bNw=}RF&2nT%5bGHX2fzTanqiir1G<$19$tP}9YAU{u#jUp zD8Ye(8{H8gaZ)Tt2?0{G60&8aT8^9s7(s19P?PLX%p(*7X$|a_$gM|dk})ta^e_wn zV1ctvpL;`JtL2nIBt|x*H((ld0K=#QM!Ex7U<|vP0po;-p$00bfnDk|mV=X!5qe(^0VP2X}aZ@p zz(lS_4=+EeIDmy5O`rq^3T|{qke(13$PWQ@%gC`D1jq^jN-d>I2v7?!QO%@L2apMv z7zP+HjXHo~q&t8G#<05?KvsQD6$gNNsRIQ70arSE*T|!P00000NkvXXu0mjfq&aOM literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_full.png new file mode 100644 index 0000000000000000000000000000000000000000..3ae7c34590dfcb34942564116d5c6b2dd99395ed GIT binary patch literal 233 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ4W2HJAr*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Pt?%hb4w`BQKCHG~sn={nf7}9$;Wz7RYYUQ^LL>VA0K& zmkSFDxtMm6wQ>P5OLbR7=f>QY6_UZQzs2-}V znWpY|u=gEDk&u$GCEtNG$(=hJT4UG)l3p&*>X_jsd%)mT1JtgB15C*Weq}K~VhGSL bUBJMw@|J##O>=xD(CrMKu6{1-oD!M<%!gMZ literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_low.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_low.png new file mode 100644 index 0000000000000000000000000000000000000000..f737cbe9c2932127c6dae50d1ed63cebf279f9cc GIT binary patch literal 319 zcmV-F0l@x=P)o;-p$00bfnDk|mV zJQLCa>6!+%LoMI2Z4;bNw=}RF&2nT%5bGHX2fzTanqiir1G<$19$tP}9YAU{u#jUp zD8Ye(8{H8gaZ)Tt2?0{G60&8aT8^9s7(s19P?PL?NH>asv<94OO4p+_$rubD*!>9vBx&v5X43Q(#%?Hc@pdxXg007K$1k2AF RCOrTE002ovPDHLkV1h#paku~g literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_medium.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_front_water_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..f0fecfe0ac4e4fd56bffa98fdd50a14e54da61de GIT binary patch literal 304 zcmV-00nh%4P)o;-p$00bfnDk|mV*$YFj2#DN*uvNjsuV_ zr4%rctI@;Dk17seAx9G^!GVGs-4UcFL=Yf51kf!b$8r!LD+DODlqw-WEx<%IlSUmt zCSYP1V8Ar$0EUt702UZST{|%0MttzC;$K?6hXBS^QJ}s0000!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob4rtXXRq4YxUpH7VGeqo5>&K-BYPBi&L$^ z->{?qO;OFX$ysv3RT~71=1ACSJ~IrwT@>^~gKvS`hDlkLUCeHm88~{DF|ygrnrPY! zq_sW<${5UIOGq%`HFywcGmFgu#0t1rB*G3tNhcKI04{K0P<;RZ literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_full.png new file mode 100644 index 0000000000000000000000000000000000000000..986586e8bb2ab9fb5985b6f84340ddcf5da5fe03 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJd`}n0kcv6UA=eCkoi}J`V0H00 zd4jj&>G^p!O%@C+d@J)UI{i1^J!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob4rtXXRq4YxUpH7VGeqo5>&K-BYPBi&L$^ z->{?qO;OFX$ysv3RT~71=1ACSJ~IrwT@>^~gKvS`hDlkLUCeHm88~{DF|ygrnrPY! zq_sW<${5UIOGq%`HR#!5a)2qhV*Y2xYxT_!dApqRbR+I`tZgx$cv z;ERC(+mRKDp1Ry~N`J|$k~VCZW0YvRWX05AwuurqC){huyu!${m`~y*Ujob5KK4Du eTuD443=C$gev3SGO}q^BErX}4pUXO@geCxR(`WGj literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_medium.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_lava_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..b87aeaf0df190565bce5408cc413ce9ce6286e32 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ8=fwXAr*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob4rtXXRq4YxUpH7VGeqo5>&K-BYPBi&L$^ z->{?qO;OFX$ysv3RT~71=1ACSJ~IrwT@>^~gKvS`hDlkLUCeHm4|Mo4>lnB_o4rPw zCqLjxz>m2+MLhSO*A$#m{_L35X~=(+k%x!JmZyc$Fv}z8G*kLqyY^RcJPONwB6u~k zo=$O8anoC1o*-4qaCikXn}k8HRYT$xMrNKFZn6gqUNtbX^(?sev7y}0v8R!VAt+fi UWm2S17SN9jp00i_>zopr0DVPbi~s-t literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_full.png new file mode 100644 index 0000000000000000000000000000000000000000..cd36d4578128b331bd2acd82ce512d6d5f1f7293 GIT binary patch literal 168 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJd`}n0kcv6UA=eCkoi}J`V0H00 zd4jj&>G^p!O%@C+_im)jJF-0D$%&F;r!0>^?jYtxGbPw040^2^60a~a^UQFQJz(&v zfsxH;F<*j2=>Z1jWr6GlJyr<~jF(q1OSs7zT#`M&@k*Az;!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob4rtXXRq4YxUpH7VGeqo5>&K-BYPBi&L$^ z->{?qO;OFX$ysv3RT~71=1ACSJ~IrwT@>^~gKvS`hDlkLUCeHm88~{DF|ygrnrPY! zq_sW<${5UIOGq%`HR#!5a)2q>MCNzblGq9*Hz5cts2bWKn+~_!Sf>h9zrYj8@Jvkov2TWcuv<0&Fl&~8#RUK!(XUS^F b2K2hu1*SWnd1J+aer51<^>bP0l+XkKy!&T_ literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_medium.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_side_water_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..cf13a0a31f0b473d46d55d83546d4e09e94b7716 GIT binary patch literal 275 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJTb?eCAr*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob4rtXXRq4YxUpH7VGeqo5>&K-BYPBi&L$^ z->{?qO;OFX$ysv3RT~71=1ACSJ~IrwT@>^~gKvS`hDlkLUCeHm4|Mo4>lhr{qkhO- zVqT5wB&VmvMg|5ZGKY2h&pcPTWFx|EU|{gYK!EMY3Pn#{?w*fdkM1@9AyQ;ypdlRO z+!ZxJN}zWl_Y2+`Zn6gqUNtbX`7Gv3kSIOCz`QJw-Jr)Rp@C6(MY+v`xxoU-3m6#I X3CQxEe*QuO=t~AqS3j3^P6!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!_RelF{r5}E*R(oPfr literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_full.png new file mode 100644 index 0000000000000000000000000000000000000000..18107ebe9034cd7aa23acfe8f0f6b25fe52d33af GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJYEKu(kcv6UA=eCkoi}J`V0H00 zd4jj&>G^p!O%@C+d@J)UJpE6<&10Lzopr076_fl>h($ literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_low.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_low.png new file mode 100644 index 0000000000000000000000000000000000000000..a344191b3a68ff14bf9310ca0ddebae3035dca50 GIT binary patch literal 270 zcmV+p0rCEcP)o;-p$00bfnDk|mVof^=?gn)!8$fDb`C@qv22Tf5NIoc*1sqF!#fwUaO0i$VPWVZ>QJ$W=B4ggsS0B}RY UdyoTf+yDRo07*qoM6N<$g7!LN%>V!Z literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_medium.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_lava_medium.png new file mode 100644 index 0000000000000000000000000000000000000000..817d51581635fa7162d7b072c2dd9592721450c6 GIT binary patch literal 283 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJN1iT@Ar*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!t4uEWpI((;9-%ZE@P30@x{|YDW};(r4m@CwlptN z(0V^x%%eYNhw0x)c8w*|{a<9Te{{dhAgnhXs^?&a<$(s483j9g;u<)opLX++N{}&e zEmYa!>(RexM#Ag@m!*tqF?x$dC3M+2zHu*Gy!CeGUC%_PZFA&o7ahE*R`c!2#Rdz8 b6io*Aj8}za+h@iCeaqnK>gTe~DWM4fcp_?h literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_full.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_full.png new file mode 100644 index 0000000000000000000000000000000000000000..b78ad841d3d61abebc0299deb5c05e777d52faad GIT binary patch literal 180 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJYEKu(kcv6UA=eCkoi}J`V0H00 zd4jj&>G^p!O%@C+_im)jTeAGAlKZmR%^7NKjBGxO`4S{b4|tR_a98b#soTNE zVZb}(=wiMGM!1TE15C+1Vn>--XRw`l7Rc_vD14ZKd70pQ1~G|b2X3VR{n7;t3|$5i VS<2B1Sb@%9@O1TaS?83{1OP6kHs=5U literal 0 HcmV?d00001 diff --git a/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_low.png b/src/main/resources/nexo/pack/assets/atlas/textures/block/fluid_container_top_water_low.png new file mode 100644 index 0000000000000000000000000000000000000000..ffe55376c33e41593f7448a4d2fe872ca1683a76 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ8=fwXAr*6yL#`S8I&aX>!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!!0O_0 z@&s?k)ARFenk*Ptl(@CDo<4b!ci>0Aob9Crs{1!vU`W`}7^43?Ka8yl{=(g5@{gQu&X%Q~loCIH_^anb+) literal 0 HcmV?d00001 From cf47e71c35402dc41124e9acb409855b295a967a Mon Sep 17 00:00:00 2001 From: CoderJoe Date: Thu, 5 Mar 2026 22:06:10 -0600 Subject: [PATCH 3/4] Add 43 Nexo CHORUSBLOCK entries and crafting recipe for fluid container 42 directional/fill-state variants plus 1 base inventory item. Recipe: 4 iron ingots + 4 glass + 1 bucket. --- .../resources/nexo/items/atlas_blocks.yml | 1246 +++++++++++++++++ .../nexo/recipes/shapeless/atlas_recipes.yml | 15 + 2 files changed, 1261 insertions(+) diff --git a/src/main/resources/nexo/items/atlas_blocks.yml b/src/main/resources/nexo/items/atlas_blocks.yml index d38440a..ba632ac 100644 --- a/src/main/resources/nexo/items/atlas_blocks.yml +++ b/src/main/resources/nexo/items/atlas_blocks.yml @@ -1402,3 +1402,1249 @@ fluid_pipe_down_filled_lava: loots: - nexo_item: fluid_pipe probability: 1.0 + +# ==================== Fluid Container ==================== + +fluid_container: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube_all + textures: + all: atlas:block/fluid_container_side + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 1 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 + +fluid_container_north: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front + south: atlas:block/fluid_container_back + east: atlas:block/fluid_container_side + west: atlas:block/fluid_container_side + up: atlas:block/fluid_container_top + down: atlas:block/fluid_container_top + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 2 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back + south: atlas:block/fluid_container_front + east: atlas:block/fluid_container_side + west: atlas:block/fluid_container_side + up: atlas:block/fluid_container_top + down: atlas:block/fluid_container_top + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 3 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side + south: atlas:block/fluid_container_side + east: atlas:block/fluid_container_front + west: atlas:block/fluid_container_back + up: atlas:block/fluid_container_top + down: atlas:block/fluid_container_top + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 4 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side + south: atlas:block/fluid_container_side + east: atlas:block/fluid_container_back + west: atlas:block/fluid_container_front + up: atlas:block/fluid_container_top + down: atlas:block/fluid_container_top + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 5 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side + south: atlas:block/fluid_container_side + east: atlas:block/fluid_container_side + west: atlas:block/fluid_container_side + up: atlas:block/fluid_container_front + down: atlas:block/fluid_container_back + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 6 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side + south: atlas:block/fluid_container_side + east: atlas:block/fluid_container_side + west: atlas:block/fluid_container_side + up: atlas:block/fluid_container_back + down: atlas:block/fluid_container_front + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 7 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_water_low + south: atlas:block/fluid_container_back_water_low + east: atlas:block/fluid_container_side_water_low + west: atlas:block/fluid_container_side_water_low + up: atlas:block/fluid_container_top_water_low + down: atlas:block/fluid_container_top_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 8 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_water_medium + south: atlas:block/fluid_container_back_water_medium + east: atlas:block/fluid_container_side_water_medium + west: atlas:block/fluid_container_side_water_medium + up: atlas:block/fluid_container_top_water_medium + down: atlas:block/fluid_container_top_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 9 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_water_full + south: atlas:block/fluid_container_back_water_full + east: atlas:block/fluid_container_side_water_full + west: atlas:block/fluid_container_side_water_full + up: atlas:block/fluid_container_top_water_full + down: atlas:block/fluid_container_top_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 10 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_lava_low + south: atlas:block/fluid_container_back_lava_low + east: atlas:block/fluid_container_side_lava_low + west: atlas:block/fluid_container_side_lava_low + up: atlas:block/fluid_container_top_lava_low + down: atlas:block/fluid_container_top_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 11 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_lava_medium + south: atlas:block/fluid_container_back_lava_medium + east: atlas:block/fluid_container_side_lava_medium + west: atlas:block/fluid_container_side_lava_medium + up: atlas:block/fluid_container_top_lava_medium + down: atlas:block/fluid_container_top_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 12 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_north_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_front_lava_full + south: atlas:block/fluid_container_back_lava_full + east: atlas:block/fluid_container_side_lava_full + west: atlas:block/fluid_container_side_lava_full + up: atlas:block/fluid_container_top_lava_full + down: atlas:block/fluid_container_top_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 13 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_water_low + south: atlas:block/fluid_container_front_water_low + east: atlas:block/fluid_container_side_water_low + west: atlas:block/fluid_container_side_water_low + up: atlas:block/fluid_container_top_water_low + down: atlas:block/fluid_container_top_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 14 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_water_medium + south: atlas:block/fluid_container_front_water_medium + east: atlas:block/fluid_container_side_water_medium + west: atlas:block/fluid_container_side_water_medium + up: atlas:block/fluid_container_top_water_medium + down: atlas:block/fluid_container_top_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 15 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_water_full + south: atlas:block/fluid_container_front_water_full + east: atlas:block/fluid_container_side_water_full + west: atlas:block/fluid_container_side_water_full + up: atlas:block/fluid_container_top_water_full + down: atlas:block/fluid_container_top_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 16 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_lava_low + south: atlas:block/fluid_container_front_lava_low + east: atlas:block/fluid_container_side_lava_low + west: atlas:block/fluid_container_side_lava_low + up: atlas:block/fluid_container_top_lava_low + down: atlas:block/fluid_container_top_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 17 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_lava_medium + south: atlas:block/fluid_container_front_lava_medium + east: atlas:block/fluid_container_side_lava_medium + west: atlas:block/fluid_container_side_lava_medium + up: atlas:block/fluid_container_top_lava_medium + down: atlas:block/fluid_container_top_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 18 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_south_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_back_lava_full + south: atlas:block/fluid_container_front_lava_full + east: atlas:block/fluid_container_side_lava_full + west: atlas:block/fluid_container_side_lava_full + up: atlas:block/fluid_container_top_lava_full + down: atlas:block/fluid_container_top_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 19 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_low + south: atlas:block/fluid_container_side_water_low + east: atlas:block/fluid_container_front_water_low + west: atlas:block/fluid_container_back_water_low + up: atlas:block/fluid_container_top_water_low + down: atlas:block/fluid_container_top_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 20 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_medium + south: atlas:block/fluid_container_side_water_medium + east: atlas:block/fluid_container_front_water_medium + west: atlas:block/fluid_container_back_water_medium + up: atlas:block/fluid_container_top_water_medium + down: atlas:block/fluid_container_top_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 21 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_full + south: atlas:block/fluid_container_side_water_full + east: atlas:block/fluid_container_front_water_full + west: atlas:block/fluid_container_back_water_full + up: atlas:block/fluid_container_top_water_full + down: atlas:block/fluid_container_top_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 22 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_low + south: atlas:block/fluid_container_side_lava_low + east: atlas:block/fluid_container_front_lava_low + west: atlas:block/fluid_container_back_lava_low + up: atlas:block/fluid_container_top_lava_low + down: atlas:block/fluid_container_top_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 23 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_medium + south: atlas:block/fluid_container_side_lava_medium + east: atlas:block/fluid_container_front_lava_medium + west: atlas:block/fluid_container_back_lava_medium + up: atlas:block/fluid_container_top_lava_medium + down: atlas:block/fluid_container_top_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 24 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_east_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_full + south: atlas:block/fluid_container_side_lava_full + east: atlas:block/fluid_container_front_lava_full + west: atlas:block/fluid_container_back_lava_full + up: atlas:block/fluid_container_top_lava_full + down: atlas:block/fluid_container_top_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 25 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_low + south: atlas:block/fluid_container_side_water_low + east: atlas:block/fluid_container_back_water_low + west: atlas:block/fluid_container_front_water_low + up: atlas:block/fluid_container_top_water_low + down: atlas:block/fluid_container_top_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 26 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_medium + south: atlas:block/fluid_container_side_water_medium + east: atlas:block/fluid_container_back_water_medium + west: atlas:block/fluid_container_front_water_medium + up: atlas:block/fluid_container_top_water_medium + down: atlas:block/fluid_container_top_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 27 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_full + south: atlas:block/fluid_container_side_water_full + east: atlas:block/fluid_container_back_water_full + west: atlas:block/fluid_container_front_water_full + up: atlas:block/fluid_container_top_water_full + down: atlas:block/fluid_container_top_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 28 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_low + south: atlas:block/fluid_container_side_lava_low + east: atlas:block/fluid_container_back_lava_low + west: atlas:block/fluid_container_front_lava_low + up: atlas:block/fluid_container_top_lava_low + down: atlas:block/fluid_container_top_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 29 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_medium + south: atlas:block/fluid_container_side_lava_medium + east: atlas:block/fluid_container_back_lava_medium + west: atlas:block/fluid_container_front_lava_medium + up: atlas:block/fluid_container_top_lava_medium + down: atlas:block/fluid_container_top_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 30 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_west_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_full + south: atlas:block/fluid_container_side_lava_full + east: atlas:block/fluid_container_back_lava_full + west: atlas:block/fluid_container_front_lava_full + up: atlas:block/fluid_container_top_lava_full + down: atlas:block/fluid_container_top_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 31 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_low + south: atlas:block/fluid_container_side_water_low + east: atlas:block/fluid_container_side_water_low + west: atlas:block/fluid_container_side_water_low + up: atlas:block/fluid_container_front_water_low + down: atlas:block/fluid_container_back_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 32 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_medium + south: atlas:block/fluid_container_side_water_medium + east: atlas:block/fluid_container_side_water_medium + west: atlas:block/fluid_container_side_water_medium + up: atlas:block/fluid_container_front_water_medium + down: atlas:block/fluid_container_back_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 33 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_full + south: atlas:block/fluid_container_side_water_full + east: atlas:block/fluid_container_side_water_full + west: atlas:block/fluid_container_side_water_full + up: atlas:block/fluid_container_front_water_full + down: atlas:block/fluid_container_back_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 34 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_low + south: atlas:block/fluid_container_side_lava_low + east: atlas:block/fluid_container_side_lava_low + west: atlas:block/fluid_container_side_lava_low + up: atlas:block/fluid_container_front_lava_low + down: atlas:block/fluid_container_back_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 35 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_medium + south: atlas:block/fluid_container_side_lava_medium + east: atlas:block/fluid_container_side_lava_medium + west: atlas:block/fluid_container_side_lava_medium + up: atlas:block/fluid_container_front_lava_medium + down: atlas:block/fluid_container_back_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 36 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_up_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_full + south: atlas:block/fluid_container_side_lava_full + east: atlas:block/fluid_container_side_lava_full + west: atlas:block/fluid_container_side_lava_full + up: atlas:block/fluid_container_front_lava_full + down: atlas:block/fluid_container_back_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 37 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_water_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_low + south: atlas:block/fluid_container_side_water_low + east: atlas:block/fluid_container_side_water_low + west: atlas:block/fluid_container_side_water_low + up: atlas:block/fluid_container_back_water_low + down: atlas:block/fluid_container_front_water_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 38 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_water_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_medium + south: atlas:block/fluid_container_side_water_medium + east: atlas:block/fluid_container_side_water_medium + west: atlas:block/fluid_container_side_water_medium + up: atlas:block/fluid_container_back_water_medium + down: atlas:block/fluid_container_front_water_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 39 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_water_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_water_full + south: atlas:block/fluid_container_side_water_full + east: atlas:block/fluid_container_side_water_full + west: atlas:block/fluid_container_side_water_full + up: atlas:block/fluid_container_back_water_full + down: atlas:block/fluid_container_front_water_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 40 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_lava_low: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_low + south: atlas:block/fluid_container_side_lava_low + east: atlas:block/fluid_container_side_lava_low + west: atlas:block/fluid_container_side_lava_low + up: atlas:block/fluid_container_back_lava_low + down: atlas:block/fluid_container_front_lava_low + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 41 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_lava_medium: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_medium + south: atlas:block/fluid_container_side_lava_medium + east: atlas:block/fluid_container_side_lava_medium + west: atlas:block/fluid_container_side_lava_medium + up: atlas:block/fluid_container_back_lava_medium + down: atlas:block/fluid_container_front_lava_medium + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 42 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 +fluid_container_down_lava_full: + itemname: "Fluid Container" + material: paper + Pack: + generate_model: true + parent_model: block/cube + textures: + north: atlas:block/fluid_container_side_lava_full + south: atlas:block/fluid_container_side_lava_full + east: atlas:block/fluid_container_side_lava_full + west: atlas:block/fluid_container_side_lava_full + up: atlas:block/fluid_container_back_lava_full + down: atlas:block/fluid_container_front_lava_full + Mechanics: + custom_block: + type: CHORUSBLOCK + custom_variation: 43 + hardness: 3 + block_sounds: + break_sound: block.glass.break + place_sound: block.glass.place + hit_sound: block.glass.hit + step_sound: block.glass.step + fall_sound: block.glass.fall + drop: + silktouch: false + loots: + - nexo_item: fluid_container + probability: 1.0 diff --git a/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml b/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml index 6724925..9c5665b 100644 --- a/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml +++ b/src/main/resources/nexo/recipes/shapeless/atlas_recipes.yml @@ -77,3 +77,18 @@ fluid_pipe_recipe: A: amount: 1 minecraft_type: IRON_INGOT + +fluid_container_recipe: + result: + nexo_item: fluid_container + amount: 1 + ingredients: + A: + amount: 4 + minecraft_type: IRON_INGOT + B: + amount: 4 + minecraft_type: GLASS + C: + amount: 1 + minecraft_type: BUCKET From e1cf94cdcc3eafd65c2ea4f71b7a2847e78987fe Mon Sep 17 00:00:00 2001 From: CoderJoe Date: Thu, 5 Mar 2026 22:06:15 -0600 Subject: [PATCH 4/4] Add 37 FluidContainer tests and update block count assertions --- .../com/coderjoe/atlas/AtlasPluginTest.kt | 4 +- .../atlas/fluid/FluidBlockInitializerTest.kt | 4 +- .../atlas/fluid/FluidContainerTest.kt | 406 ++++++++++++++++++ 3 files changed, 410 insertions(+), 4 deletions(-) create mode 100644 src/test/kotlin/com/coderjoe/atlas/fluid/FluidContainerTest.kt diff --git a/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt b/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt index 0b091a6..bd5466e 100644 --- a/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt @@ -32,9 +32,9 @@ class AtlasPluginTest { } @Test - fun `fluid system initializes with 21 block types`() { + fun `fluid system initializes with 63 block types`() { FluidBlockInitializer.initialize(TestHelper.mockPlugin) - assertEquals(21, FluidBlockFactory.getRegisteredBlockIds().size) + assertEquals(63, FluidBlockFactory.getRegisteredBlockIds().size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidBlockInitializerTest.kt index 431b9ee..b3dd804 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 FluidBlockInitializerTest { FluidBlockInitializer.initialize(TestHelper.mockPlugin) val ids = FluidBlockFactory.getRegisteredBlockIds() - // 3 pump + 6 directional pipe + 6 water-filled + 6 lava-filled = 21 - assertEquals(21, ids.size) + // 3 pump + 6 directional pipe + 6 water-filled + 6 lava-filled + 42 container = 63 + assertEquals(63, ids.size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidContainerTest.kt b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidContainerTest.kt new file mode 100644 index 0000000..0fa6c78 --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidContainerTest.kt @@ -0,0 +1,406 @@ +package com.coderjoe.atlas.fluid + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callFluidUpdate +import com.coderjoe.atlas.fluid.block.FluidContainer +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.fluid.block.FluidPump +import org.bukkit.block.BlockFace +import org.junit.jupiter.api.* +import org.junit.jupiter.api.Assertions.* + +class FluidContainerTest { + + @BeforeEach + fun setup() { + TestHelper.setup() + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + // --- Store/Remove multi-unit --- + + @Test + fun `store fluid increments amount`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + assertTrue(container.storeFluid(FluidType.WATER)) + assertEquals(1, container.storedAmount) + assertEquals(FluidType.WATER, container.storedFluid) + } + + @Test + fun `store multiple units of same fluid`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + for (i in 1..5) { + assertTrue(container.storeFluid(FluidType.WATER)) + } + assertEquals(5, container.storedAmount) + } + + @Test + fun `store up to max capacity`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + for (i in 1..FluidContainer.MAX_CAPACITY) { + assertTrue(container.storeFluid(FluidType.WATER)) + } + assertEquals(FluidContainer.MAX_CAPACITY, container.storedAmount) + } + + @Test + fun `store rejects when full`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + for (i in 1..FluidContainer.MAX_CAPACITY) { + container.storeFluid(FluidType.WATER) + } + assertFalse(container.storeFluid(FluidType.WATER)) + assertEquals(FluidContainer.MAX_CAPACITY, container.storedAmount) + } + + @Test + fun `store rejects different fluid type`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + assertFalse(container.storeFluid(FluidType.LAVA)) + assertEquals(1, container.storedAmount) + assertEquals(FluidType.WATER, container.storedFluid) + } + + @Test + fun `remove fluid decrements amount`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + container.storeFluid(FluidType.WATER) + container.storeFluid(FluidType.WATER) + + val removed = container.removeFluid() + assertEquals(FluidType.WATER, removed) + assertEquals(2, container.storedAmount) + } + + @Test + fun `remove fluid clears type at zero`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + + val removed = container.removeFluid() + assertEquals(FluidType.WATER, removed) + assertEquals(0, container.storedAmount) + assertEquals(FluidType.NONE, container.storedFluid) + } + + @Test + fun `remove from empty returns NONE`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals(FluidType.NONE, container.removeFluid()) + } + + @Test + fun `hasFluid returns true when amount greater than zero`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + assertFalse(container.hasFluid()) + container.storeFluid(FluidType.WATER) + assertTrue(container.hasFluid()) + } + + // --- canRemoveFluidFrom --- + + @Test + fun `canRemoveFluidFrom returns true for front face`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + assertTrue(container.canRemoveFluidFrom(BlockFace.NORTH)) + } + + @Test + fun `canRemoveFluidFrom returns false for non-front face`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + assertFalse(container.canRemoveFluidFrom(BlockFace.SOUTH)) + assertFalse(container.canRemoveFluidFrom(BlockFace.EAST)) + } + + @Test + fun `canRemoveFluidFrom returns false when empty`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + assertFalse(container.canRemoveFluidFrom(BlockFace.NORTH)) + } + + // --- Fill level --- + + @Test + fun `fill level empty at 0`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals("empty", container.getFillLevel()) + } + + @Test + fun `fill level low at 1 to 3`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + for (i in 1..3) { + container.storeFluid(FluidType.WATER) + assertEquals("low", container.getFillLevel(), "Expected low at amount $i") + } + } + + @Test + fun `fill level medium at 4 to 7`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + repeat(4) { container.storeFluid(FluidType.WATER) } + assertEquals("medium", container.getFillLevel()) + repeat(3) { container.storeFluid(FluidType.WATER) } + assertEquals("medium", container.getFillLevel()) + } + + @Test + fun `fill level full at 8 to 10`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + repeat(8) { container.storeFluid(FluidType.WATER) } + assertEquals("full", container.getFillLevel()) + repeat(2) { container.storeFluid(FluidType.WATER) } + assertEquals("full", container.getFillLevel()) + } + + // --- Visual state --- + + @Test + fun `visual state empty for all directions`() { + for ((face, id) in FluidContainer.DIRECTIONAL_IDS) { + val container = FluidContainer(TestHelper.createLocation(), face) + assertEquals(id, container.getVisualStateBlockId()) + } + } + + @Test + fun `visual state water low`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + assertEquals("fluid_container_north_water_low", container.getVisualStateBlockId()) + } + + @Test + fun `visual state water medium`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.SOUTH) + repeat(5) { container.storeFluid(FluidType.WATER) } + assertEquals("fluid_container_south_water_medium", container.getVisualStateBlockId()) + } + + @Test + fun `visual state water full`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.EAST) + repeat(10) { container.storeFluid(FluidType.WATER) } + assertEquals("fluid_container_east_water_full", container.getVisualStateBlockId()) + } + + @Test + fun `visual state lava low`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.WEST) + container.storeFluid(FluidType.LAVA) + assertEquals("fluid_container_west_lava_low", container.getVisualStateBlockId()) + } + + @Test + fun `visual state returns empty after draining all fluid`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.UP) + container.storeFluid(FluidType.WATER) + container.removeFluid() + assertEquals("fluid_container_up", container.getVisualStateBlockId()) + } + + // --- facingFromBlockId --- + + @Test + fun `facingFromBlockId returns correct face for directional IDs`() { + for ((face, id) in FluidContainer.DIRECTIONAL_IDS) { + assertEquals(face, FluidContainer.facingFromBlockId(id)) + } + } + + @Test + fun `facingFromBlockId returns correct face for filled variant IDs`() { + assertEquals(BlockFace.NORTH, FluidContainer.facingFromBlockId("fluid_container_north_water_low")) + assertEquals(BlockFace.SOUTH, FluidContainer.facingFromBlockId("fluid_container_south_lava_full")) + } + + @Test + fun `facingFromBlockId returns null for unknown`() { + assertNull(FluidContainer.facingFromBlockId("unknown_block")) + } + + // --- ALL_VARIANT_IDS --- + + @Test + fun `ALL_VARIANT_IDS contains 42 entries`() { + assertEquals(42, FluidContainer.ALL_VARIANT_IDS.size) + } + + @Test + fun `ALL_VARIANT_IDS contains all directional IDs`() { + for (id in FluidContainer.DIRECTIONAL_IDS.values) { + assertTrue(id in FluidContainer.ALL_VARIANT_IDS, "Missing $id") + } + } + + // --- Directional pull --- + + @Test + fun `container pulls from pipe behind it`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.SOUTH) + val pipe = FluidPipe(TestHelper.createLocation(0.0, 64.0, -1.0), BlockFace.SOUTH) + pipe.storeFluid(FluidType.WATER) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south") + + container.callFluidUpdate() + assertEquals(FluidType.WATER, container.storedFluid) + assertEquals(1, container.storedAmount) + assertEquals(FluidType.NONE, pipe.storedFluid) + } + + @Test + fun `container pulls from pump behind it`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 1.0), BlockFace.SOUTH) + val pump = FluidPump(TestHelper.createLocation(0.0, 64.0, 0.0)) + pump.storeFluid(FluidType.WATER) + + val cauldronField = FluidPump::class.java.getDeclaredField("cauldronFace") + cauldronField.isAccessible = true + cauldronField.set(pump, BlockFace.NORTH) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, pump, "fluid_pump") + + container.callFluidUpdate() + assertEquals(FluidType.WATER, container.storedFluid) + assertEquals(1, container.storedAmount) + } + + @Test + fun `container pulls from another container behind it`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val container1 = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.SOUTH) + container1.storeFluid(FluidType.LAVA) + + val container2 = FluidContainer(TestHelper.createLocation(0.0, 64.0, 1.0), BlockFace.SOUTH) + + TestHelper.addToRegistry(fluidRegistry, container1, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, container2, "fluid_container_south") + + container2.callFluidUpdate() + assertEquals(FluidType.LAVA, container2.storedFluid) + assertEquals(1, container2.storedAmount) + assertEquals(0, container1.storedAmount) + } + + @Test + fun `container does not pull when full`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.SOUTH) + repeat(FluidContainer.MAX_CAPACITY) { container.storeFluid(FluidType.WATER) } + + val pipe = FluidPipe(TestHelper.createLocation(0.0, 64.0, -1.0), BlockFace.SOUTH) + pipe.storeFluid(FluidType.WATER) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south") + + container.callFluidUpdate() + assertTrue(pipe.hasFluid()) // pipe still has fluid + } + + @Test + fun `container rejects mismatched fluid from pipe`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.SOUTH) + container.storeFluid(FluidType.WATER) + + val pipe = FluidPipe(TestHelper.createLocation(0.0, 64.0, -1.0), BlockFace.SOUTH) + pipe.storeFluid(FluidType.LAVA) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south") + + container.callFluidUpdate() + assertTrue(pipe.hasFluid()) // pipe keeps its lava since container rejected it + assertEquals(1, container.storedAmount) // container unchanged + } + + // --- Pipe pulling from container --- + + @Test + fun `pipe pulls from container front face`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + // Container facing SOUTH (front=SOUTH), pipe at z=1 facing SOUTH (pulls from NORTH=z-1=container) + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.SOUTH) + container.storeFluid(FluidType.WATER) + + val pipe = FluidPipe(TestHelper.createLocation(0.0, 64.0, 1.0), BlockFace.SOUTH) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_south") + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south") + + pipe.callFluidUpdate() + assertEquals(FluidType.WATER, pipe.storedFluid) + assertEquals(0, container.storedAmount) + } + + @Test + fun `pipe cannot pull from container non-front face`() { + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + // Container facing NORTH (front=NORTH), pipe behind at z=1 facing SOUTH pulls from NORTH=z-1 + // But container faces NORTH, so front is NORTH. Pipe pulling from SOUTH direction won't match. + val container = FluidContainer(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + container.storeFluid(FluidType.WATER) + + // Pipe at z=1, facing SOUTH, pulls from behind (NORTH side = z-1 = container) + // It calls canRemoveFluidFrom(SOUTH) on container — container facing NORTH, so front is NORTH, not SOUTH + val pipe = FluidPipe(TestHelper.createLocation(0.0, 64.0, 1.0), BlockFace.SOUTH) + + TestHelper.addToRegistry(fluidRegistry, container, "fluid_container_north") + TestHelper.addToRegistry(fluidRegistry, pipe, "fluid_pipe_south") + + pipe.callFluidUpdate() + assertEquals(FluidType.NONE, pipe.storedFluid) // could not pull + assertEquals(1, container.storedAmount) // unchanged + } + + // --- Persistence --- + + @Test + fun `restoreState sets type and amount`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.restoreState(FluidType.LAVA, 7) + assertEquals(FluidType.LAVA, container.storedFluid) + assertEquals(7, container.storedAmount) + } + + @Test + fun `restoreState clamps to max capacity`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.NORTH) + container.restoreState(FluidType.WATER, 99) + assertEquals(FluidContainer.MAX_CAPACITY, container.storedAmount) + } + + @Test + fun `FluidBlockData captures container facing and storedAmount`() { + val container = FluidContainer(TestHelper.createLocation(), BlockFace.EAST) + repeat(5) { container.storeFluid(FluidType.WATER) } + + val data = FluidBlockData.fromFluidBlock(container, "fluid_container_east") + assertEquals("EAST", data.facing) + assertEquals(5, data.storedAmount) + assertEquals("WATER", data.fluidType) + } +}