diff --git a/src/main/kotlin/com/coderjoe/atlas/Atlas.kt b/src/main/kotlin/com/coderjoe/atlas/Atlas.kt index 1240b1f..32ad11c 100644 --- a/src/main/kotlin/com/coderjoe/atlas/Atlas.kt +++ b/src/main/kotlin/com/coderjoe/atlas/Atlas.kt @@ -35,6 +35,7 @@ import com.coderjoe.atlas.transport.block.ConveyorBelt import com.coderjoe.atlas.utility.block.AutoSmelter import com.coderjoe.atlas.utility.block.CobblestoneFactory import com.coderjoe.atlas.utility.block.Crusher +import com.coderjoe.atlas.utility.block.ExperienceExtractor import com.coderjoe.atlas.utility.block.ObsidianFactory import com.coderjoe.atlas.utility.block.SmallDrill import com.coderjoe.atlas.utility.block.SoftTouchDrill @@ -214,6 +215,7 @@ class Atlas : JavaPlugin() { Crusher.descriptor, PowerMerger.descriptor, SoftTouchDrill.descriptor, + ExperienceExtractor.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 48bfcd8..1328d0d 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidBlockDialog.kt @@ -60,12 +60,15 @@ object FluidBlockDialog { when (fluidBlock.storedFluid) { FluidType.WATER -> "Water (${fluidBlock.storedAmount}/${FluidContainer.MAX_CAPACITY})" FluidType.LAVA -> "Lava (${fluidBlock.storedAmount}/${FluidContainer.MAX_CAPACITY})" + FluidType.EXPERIENCE -> + "Liquid Experience (${fluidBlock.storedAmount}/${FluidContainer.MAX_CAPACITY})" FluidType.NONE -> "Empty" } } else { when (fluidBlock.storedFluid) { FluidType.WATER -> "Water" FluidType.LAVA -> "Lava" + FluidType.EXPERIENCE -> "Liquid Experience" FluidType.NONE -> "Empty" } } @@ -74,6 +77,7 @@ object FluidBlockDialog { when (fluidBlock.storedFluid) { FluidType.WATER -> NamedTextColor.AQUA FluidType.LAVA -> NamedTextColor.GOLD + FluidType.EXPERIENCE -> NamedTextColor.GREEN FluidType.NONE -> NamedTextColor.GRAY } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidType.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidType.kt index 8743ed8..b0641bb 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/FluidType.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/FluidType.kt @@ -3,5 +3,6 @@ package com.coderjoe.atlas.fluid enum class FluidType { WATER, LAVA, + EXPERIENCE, NONE, } diff --git a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPump.kt b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPump.kt index 7bc48d6..425cdd5 100644 --- a/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPump.kt +++ b/src/main/kotlin/com/coderjoe/atlas/fluid/block/FluidPump.kt @@ -60,6 +60,7 @@ class FluidPump(location: Location) : FluidBlock(location) { when (storedFluid) { FluidType.WATER -> BLOCK_ID_ACTIVE FluidType.LAVA -> BLOCK_ID_ACTIVE_LAVA + FluidType.EXPERIENCE -> BLOCK_ID_ACTIVE FluidType.NONE -> BLOCK_ID } diff --git a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt index 6a623dd..d469d1e 100644 --- a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt +++ b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockDialog.kt @@ -12,6 +12,7 @@ import com.coderjoe.atlas.power.block.SmallSolarPanel import com.coderjoe.atlas.utility.block.AutoSmelter import com.coderjoe.atlas.utility.block.CobblestoneFactory import com.coderjoe.atlas.utility.block.Crusher +import com.coderjoe.atlas.utility.block.ExperienceExtractor import com.coderjoe.atlas.utility.block.ObsidianFactory import com.coderjoe.atlas.utility.block.SmallDrill import com.coderjoe.atlas.utility.block.SoftTouchDrill @@ -136,6 +137,7 @@ object PowerBlockDialog { is ObsidianFactory -> "Obsidian Factory" is Crusher -> "Crusher (${powerBlock.facing.displayName()})" is PowerMerger -> "Power Merger (${powerBlock.facing.displayName()})" + is ExperienceExtractor -> "Experience Extractor (${powerBlock.facing.displayName()})" else -> "Power Block" } @@ -215,6 +217,12 @@ object PowerBlockDialog { is PowerMerger -> Component.text("Cable - merges power from all sides, outputs in facing direction") .color(NamedTextColor.GRAY) + is ExperienceExtractor -> + Component.text( + "Machine - extracts XP from items via hopper, outputs Liquid Experience, " + + "consumes ${ExperienceExtractor.POWER_PER_EXTRACT} power/item", + ) + .color(NamedTextColor.GRAY) else -> Component.text("Power block") .color(NamedTextColor.GRAY) diff --git a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockPersistence.kt b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockPersistence.kt index fee4085..24d9c57 100644 --- a/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockPersistence.kt +++ b/src/main/kotlin/com/coderjoe/atlas/power/PowerBlockPersistence.kt @@ -1,6 +1,7 @@ package com.coderjoe.atlas.power import com.coderjoe.atlas.core.BlockPersistence +import com.coderjoe.atlas.utility.block.ExperienceExtractor import com.coderjoe.atlas.utility.block.SmallDrill import org.bukkit.plugin.java.JavaPlugin @@ -19,6 +20,9 @@ class PowerBlockPersistence(plugin: JavaPlugin) { if (block is SmallDrill) { map["enabled"] = block.enabled } + if (block is ExperienceExtractor) { + map["storedXp"] = block.storedXp + } map }, restore = { block, data -> @@ -29,6 +33,9 @@ class PowerBlockPersistence(plugin: JavaPlugin) { block.enabled = enabled } } + if (block is ExperienceExtractor) { + block.storedXp = (data["storedXp"] as? Number)?.toDouble() ?: 0.0 + } }, ) diff --git a/src/main/kotlin/com/coderjoe/atlas/utility/block/ExperienceExtractor.kt b/src/main/kotlin/com/coderjoe/atlas/utility/block/ExperienceExtractor.kt new file mode 100644 index 0000000..982f92a --- /dev/null +++ b/src/main/kotlin/com/coderjoe/atlas/utility/block/ExperienceExtractor.kt @@ -0,0 +1,181 @@ +package com.coderjoe.atlas.utility.block + +import com.coderjoe.atlas.atlasInfo +import com.coderjoe.atlas.coordinates +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.power.PowerBlock +import org.bukkit.Location +import org.bukkit.Material +import org.bukkit.block.BlockFace +import org.bukkit.block.Hopper + +class ExperienceExtractor( + location: Location, + facing: BlockFace = BlockFace.NORTH, +) : PowerBlock(location, maxStorage = 12) { + override val canReceivePower: Boolean = true + override val updateIntervalTicks: Long = 20L + override val baseBlockId: String = BLOCK_ID + + var direction: BlockFace = if (facing == BlockFace.SELF) BlockFace.NORTH else facing + + override val facing: BlockFace get() = direction + + var storedXp: Double = 0.0 + + companion object { + const val BLOCK_ID = "atlas:experience_extractor" + const val BLOCK_ID_ACTIVE = "atlas:experience_extractor_active" + const val POWER_PER_EXTRACT = 3 + const val MAX_XP_BUFFER = 10.0 + const val DEFAULT_XP = 0.01 + + val XP_VALUES: Map = + mapOf( + // Ores - 1 XP + Material.COAL_ORE to 1.0, + Material.DEEPSLATE_COAL_ORE to 1.0, + Material.IRON_ORE to 1.0, + Material.DEEPSLATE_IRON_ORE to 1.0, + Material.COPPER_ORE to 1.0, + Material.DEEPSLATE_COPPER_ORE to 1.0, + Material.GOLD_ORE to 1.0, + Material.DEEPSLATE_GOLD_ORE to 1.0, + Material.NETHER_GOLD_ORE to 1.0, + Material.REDSTONE_ORE to 1.0, + Material.DEEPSLATE_REDSTONE_ORE to 1.0, + Material.LAPIS_ORE to 1.0, + Material.DEEPSLATE_LAPIS_ORE to 1.0, + Material.NETHER_QUARTZ_ORE to 1.0, + // Raw ores & minerals - 1 XP + Material.RAW_IRON to 1.0, + Material.RAW_GOLD to 1.0, + Material.RAW_COPPER to 1.0, + Material.COAL to 1.0, + Material.CHARCOAL to 1.0, + Material.LAPIS_LAZULI to 1.0, + Material.REDSTONE to 1.0, + Material.QUARTZ to 1.0, + // Cooked food - 2 XP + Material.COOKED_BEEF to 2.0, + Material.COOKED_PORKCHOP to 2.0, + Material.COOKED_CHICKEN to 2.0, + Material.COOKED_MUTTON to 2.0, + Material.COOKED_RABBIT to 2.0, + Material.COOKED_SALMON to 2.0, + Material.COOKED_COD to 2.0, + Material.BAKED_POTATO to 2.0, + // Monster drops - 3 XP + Material.BONE to 3.0, + Material.GUNPOWDER to 3.0, + Material.SPIDER_EYE to 3.0, + Material.ROTTEN_FLESH to 3.0, + Material.SLIME_BALL to 3.0, + Material.MAGMA_CREAM to 3.0, + Material.PHANTOM_MEMBRANE to 3.0, + Material.GHAST_TEAR to 3.0, + // Valuable ores & drops - 5 XP + Material.DIAMOND_ORE to 5.0, + Material.DEEPSLATE_DIAMOND_ORE to 5.0, + Material.EMERALD_ORE to 5.0, + Material.DEEPSLATE_EMERALD_ORE to 5.0, + Material.BLAZE_ROD to 5.0, + Material.ENDER_PEARL to 5.0, + Material.DIAMOND to 5.0, + Material.EMERALD to 5.0, + Material.SHULKER_SHELL to 5.0, + // Very valuable - 8 XP + Material.NETHER_STAR to 8.0, + Material.ENCHANTED_BOOK to 8.0, + ) + + val descriptor = + BlockDescriptor( + baseBlockId = BLOCK_ID, + displayName = "Experience Extractor", + description = "Extracts XP from items via hopper, outputs Liquid Experience fluid", + placementType = PlacementType.DIRECTIONAL, + additionalBlockIds = listOf(BLOCK_ID_ACTIVE), + constructor = { loc, face -> ExperienceExtractor(loc, face) }, + ) + } + + override fun getVisualStateBlockId(): String = + when { + storedXp > 0.0 || currentPower > 0 -> BLOCK_ID_ACTIVE + else -> BLOCK_ID + } + + override fun powerUpdate() { + pullPowerFromNeighbors() + + pushXpFluid() + pullFromHoppers() + + updatePoweredState() + } + + private fun pushXpFluid() { + if (storedXp < 1.0) return + + val fluidRegistry = FluidBlockRegistry.instance ?: return + val target = fluidRegistry.getAdjacentFluidBlock(location, facing) ?: return + + if (target.storeFluid(FluidType.EXPERIENCE)) { + storedXp -= 1.0 + plugin.logger.atlasInfo( + "ExperienceExtractor at ${location.coordinates} " + + "pushed 1 experience fluid (buffer: $storedXp)", + ) + } + } + + private fun pullFromHoppers() { + if (storedXp >= MAX_XP_BUFFER) return + if (currentPower < POWER_PER_EXTRACT) return + + val world = location.world ?: return + + for (face in ADJACENT_FACES) { + if (storedXp >= MAX_XP_BUFFER) break + if (currentPower < POWER_PER_EXTRACT) break + + val adjacentBlock = + world.getBlockAt( + location.blockX + face.modX, + location.blockY + face.modY, + location.blockZ + face.modZ, + ) + + val hopper = adjacentBlock.state as? Hopper ?: continue + val inventory = hopper.inventory + + for (slot in 0 until inventory.size) { + if (storedXp >= MAX_XP_BUFFER) break + if (currentPower < POWER_PER_EXTRACT) break + + val stack = inventory.getItem(slot) ?: continue + if (stack.type == Material.AIR) continue + val xpValue = XP_VALUES[stack.type] ?: DEFAULT_XP + + removePower(POWER_PER_EXTRACT) + storedXp += xpValue + + if (stack.amount > 1) { + stack.amount = stack.amount - 1 + inventory.setItem(slot, stack) + } else { + inventory.setItem(slot, null) + } + + plugin.logger.atlasInfo( + "ExperienceExtractor at ${location.coordinates} " + + "consumed ${stack.type.name}, gained $xpValue XP (buffer: $storedXp)", + ) + } + } + } +} diff --git a/src/main/resources/atlas/configuration/experience_extractor.yml b/src/main/resources/atlas/configuration/experience_extractor.yml new file mode 100644 index 0000000..6a0d76f --- /dev/null +++ b/src/main/resources/atlas/configuration/experience_extractor.yml @@ -0,0 +1,213 @@ +items: + atlas:experience_extractor: + material: paper + data: + item-name: "Experience Extractor" + model: minecraft:block/custom/experience_extractor + behavior: + type: block_item + block: + loot: + template: default:loot_table/self + settings: + hardness: 4.0 + resistance: 4.0 + is-suffocating: true + is-redstone-conductor: false + push-reaction: push_only + tags: ["minecraft:mineable/pickaxe"] + sounds: + break: minecraft:block.metal.break + step: minecraft:block.metal.step + place: minecraft:block.metal.place + hit: minecraft:block.metal.hit + fall: minecraft:block.metal.fall + states: + properties: + facing: + type: horizontal_direction + default: north + powered: + type: boolean + default: false + appearances: + north: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_front + south: minecraft:block/custom/experience_extractor_back + east: minecraft:block/custom/experience_extractor_side + west: minecraft:block/custom/experience_extractor_side + up: minecraft:block/custom/experience_extractor_top_north + down: minecraft:block/custom/experience_extractor_housing + south: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_south + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_back + south: minecraft:block/custom/experience_extractor_front + east: minecraft:block/custom/experience_extractor_side + west: minecraft:block/custom/experience_extractor_side + up: minecraft:block/custom/experience_extractor_top_south + down: minecraft:block/custom/experience_extractor_housing + east: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_east + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_side + south: minecraft:block/custom/experience_extractor_side + east: minecraft:block/custom/experience_extractor_front + west: minecraft:block/custom/experience_extractor_back + up: minecraft:block/custom/experience_extractor_top_east + down: minecraft:block/custom/experience_extractor_housing + west: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_west + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_side + south: minecraft:block/custom/experience_extractor_side + east: minecraft:block/custom/experience_extractor_back + west: minecraft:block/custom/experience_extractor_front + up: minecraft:block/custom/experience_extractor_top_west + down: minecraft:block/custom/experience_extractor_housing + north_powered: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_powered + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_front_active + south: minecraft:block/custom/experience_extractor_back + east: minecraft:block/custom/experience_extractor_side + west: minecraft:block/custom/experience_extractor_side + up: minecraft:block/custom/experience_extractor_top_active + down: minecraft:block/custom/experience_extractor_housing + south_powered: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_south_powered + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_back + south: minecraft:block/custom/experience_extractor_front_active + east: minecraft:block/custom/experience_extractor_side + west: minecraft:block/custom/experience_extractor_side + up: minecraft:block/custom/experience_extractor_top_active + down: minecraft:block/custom/experience_extractor_housing + east_powered: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_east_powered + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_side + south: minecraft:block/custom/experience_extractor_side + east: minecraft:block/custom/experience_extractor_front_active + west: minecraft:block/custom/experience_extractor_back + up: minecraft:block/custom/experience_extractor_top_active + down: minecraft:block/custom/experience_extractor_housing + west_powered: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_west_powered + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_side + south: minecraft:block/custom/experience_extractor_side + east: minecraft:block/custom/experience_extractor_back + west: minecraft:block/custom/experience_extractor_front_active + up: minecraft:block/custom/experience_extractor_top_active + down: minecraft:block/custom/experience_extractor_housing + variants: + facing=north,powered=false: + appearance: north + facing=south,powered=false: + appearance: south + facing=east,powered=false: + appearance: east + facing=west,powered=false: + appearance: west + facing=north,powered=true: + appearance: north_powered + facing=south,powered=true: + appearance: south_powered + facing=east,powered=true: + appearance: east_powered + facing=west,powered=true: + appearance: west_powered + + atlas:experience_extractor_active: + material: paper + data: + item-name: "Experience Extractor" + model: minecraft:block/custom/experience_extractor_powered + behavior: + type: block_item + block: + loot: + pools: + - rolls: 1 + entries: + - type: item + item: atlas:experience_extractor + settings: + hardness: 4.0 + resistance: 4.0 + is-suffocating: true + is-redstone-conductor: false + push-reaction: push_only + tags: ["minecraft:mineable/pickaxe"] + sounds: + break: minecraft:block.metal.break + step: minecraft:block.metal.step + place: minecraft:block.metal.place + hit: minecraft:block.metal.hit + fall: minecraft:block.metal.fall + state: + auto-state: solid + model: + path: minecraft:block/custom/experience_extractor_powered + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/experience_extractor_front_active + south: minecraft:block/custom/experience_extractor_back + east: minecraft:block/custom/experience_extractor_side + west: minecraft:block/custom/experience_extractor_side + up: minecraft:block/custom/experience_extractor_top_active + down: minecraft:block/custom/experience_extractor_housing + +recipes: + atlas:experience_extractor: + type: shapeless + category: misc + unlock-on-ingredient-obtained: true + ingredients: + - minecraft:glass_bottle + - minecraft:glass_bottle + - minecraft:blaze_powder + - minecraft:blaze_powder + - minecraft:iron_ingot + - minecraft:iron_ingot + - minecraft:redstone + - minecraft:diamond + result: + id: atlas:experience_extractor + count: 1 diff --git a/src/main/resources/atlas/configuration/fluid_container.yml b/src/main/resources/atlas/configuration/fluid_container.yml index d75c6e4..bc05f0c 100644 --- a/src/main/resources/atlas/configuration/fluid_container.yml +++ b/src/main/resources/atlas/configuration/fluid_container.yml @@ -29,7 +29,7 @@ items: default: north fluid: type: string - values: [none, water, lava] + values: [none, water, lava, experience] default: none fill_level: type: int @@ -37,7 +37,7 @@ items: default: 0 appearances: north: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container generation: @@ -50,22 +50,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container y: 180 east: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container y: 90 west: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container y: 270 up: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up generation: @@ -78,7 +78,7 @@ items: up: minecraft:block/custom/fluid_container_front down: minecraft:block/custom/fluid_container_back down: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down generation: @@ -91,7 +91,7 @@ items: up: minecraft:block/custom/fluid_container_back down: minecraft:block/custom/fluid_container_front north_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_low generation: @@ -104,22 +104,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_low y: 180 east_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_low y: 90 west_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_low y: 270 up_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_water_low generation: @@ -132,7 +132,7 @@ items: up: minecraft:block/custom/fluid_container_front_water_low down: minecraft:block/custom/fluid_container_back_water_low down_water_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_water_low generation: @@ -145,7 +145,7 @@ items: up: minecraft:block/custom/fluid_container_back_water_low down: minecraft:block/custom/fluid_container_front_water_low north_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_medium generation: @@ -158,22 +158,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_medium y: 180 east_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_medium y: 90 west_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_medium y: 270 up_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_water_medium generation: @@ -186,7 +186,7 @@ items: up: minecraft:block/custom/fluid_container_front_water_medium down: minecraft:block/custom/fluid_container_back_water_medium down_water_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_water_medium generation: @@ -199,7 +199,7 @@ items: up: minecraft:block/custom/fluid_container_back_water_medium down: minecraft:block/custom/fluid_container_front_water_medium north_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_full generation: @@ -212,22 +212,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_full y: 180 east_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_full y: 90 west_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_water_full y: 270 up_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_water_full generation: @@ -240,7 +240,7 @@ items: up: minecraft:block/custom/fluid_container_front_water_full down: minecraft:block/custom/fluid_container_back_water_full down_water_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_water_full generation: @@ -253,7 +253,7 @@ items: up: minecraft:block/custom/fluid_container_back_water_full down: minecraft:block/custom/fluid_container_front_water_full north_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_low generation: @@ -266,22 +266,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_low y: 180 east_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_low y: 90 west_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_low y: 270 up_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_lava_low generation: @@ -294,7 +294,7 @@ items: up: minecraft:block/custom/fluid_container_front_lava_low down: minecraft:block/custom/fluid_container_back_lava_low down_lava_low: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_lava_low generation: @@ -307,7 +307,7 @@ items: up: minecraft:block/custom/fluid_container_back_lava_low down: minecraft:block/custom/fluid_container_front_lava_low north_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_medium generation: @@ -320,22 +320,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_medium y: 180 east_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_medium y: 90 west_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_medium y: 270 up_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_lava_medium generation: @@ -348,7 +348,7 @@ items: up: minecraft:block/custom/fluid_container_front_lava_medium down: minecraft:block/custom/fluid_container_back_lava_medium down_lava_medium: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_lava_medium generation: @@ -361,7 +361,7 @@ items: up: minecraft:block/custom/fluid_container_back_lava_medium down: minecraft:block/custom/fluid_container_front_lava_medium north_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_full generation: @@ -374,22 +374,22 @@ items: up: minecraft:block/custom/fluid_container_top down: minecraft:block/custom/fluid_container_top south_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_full y: 180 east_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_full y: 90 west_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_lava_full y: 270 up_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_up_lava_full generation: @@ -402,7 +402,7 @@ items: up: minecraft:block/custom/fluid_container_front_lava_full down: minecraft:block/custom/fluid_container_back_lava_full down_lava_full: - auto-state: non_tintable_leaves + auto-state: solid model: path: minecraft:block/custom/fluid_container_down_lava_full generation: @@ -414,6 +414,168 @@ items: west: minecraft:block/custom/fluid_container_side_lava_full up: minecraft:block/custom/fluid_container_back_lava_full down: minecraft:block/custom/fluid_container_front_lava_full + north_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_low + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_front_xp_low + south: minecraft:block/custom/fluid_container_back_xp_low + east: minecraft:block/custom/fluid_container_side_xp_low + west: minecraft:block/custom/fluid_container_side_xp_low + up: minecraft:block/custom/fluid_container_top + down: minecraft:block/custom/fluid_container_top + south_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_low + y: 180 + east_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_low + y: 90 + west_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_low + y: 270 + up_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_up_xp_low + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_low + south: minecraft:block/custom/fluid_container_side_xp_low + east: minecraft:block/custom/fluid_container_side_xp_low + west: minecraft:block/custom/fluid_container_side_xp_low + up: minecraft:block/custom/fluid_container_front_xp_low + down: minecraft:block/custom/fluid_container_back_xp_low + down_xp_low: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_down_xp_low + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_low + south: minecraft:block/custom/fluid_container_side_xp_low + east: minecraft:block/custom/fluid_container_side_xp_low + west: minecraft:block/custom/fluid_container_side_xp_low + up: minecraft:block/custom/fluid_container_back_xp_low + down: minecraft:block/custom/fluid_container_front_xp_low + north_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_medium + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_front_xp_medium + south: minecraft:block/custom/fluid_container_back_xp_medium + east: minecraft:block/custom/fluid_container_side_xp_medium + west: minecraft:block/custom/fluid_container_side_xp_medium + up: minecraft:block/custom/fluid_container_top + down: minecraft:block/custom/fluid_container_top + south_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_medium + y: 180 + east_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_medium + y: 90 + west_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_medium + y: 270 + up_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_up_xp_medium + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_medium + south: minecraft:block/custom/fluid_container_side_xp_medium + east: minecraft:block/custom/fluid_container_side_xp_medium + west: minecraft:block/custom/fluid_container_side_xp_medium + up: minecraft:block/custom/fluid_container_front_xp_medium + down: minecraft:block/custom/fluid_container_back_xp_medium + down_xp_medium: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_down_xp_medium + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_medium + south: minecraft:block/custom/fluid_container_side_xp_medium + east: minecraft:block/custom/fluid_container_side_xp_medium + west: minecraft:block/custom/fluid_container_side_xp_medium + up: minecraft:block/custom/fluid_container_back_xp_medium + down: minecraft:block/custom/fluid_container_front_xp_medium + north_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_full + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_front_xp_full + south: minecraft:block/custom/fluid_container_back_xp_full + east: minecraft:block/custom/fluid_container_side_xp_full + west: minecraft:block/custom/fluid_container_side_xp_full + up: minecraft:block/custom/fluid_container_top + down: minecraft:block/custom/fluid_container_top + south_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_full + y: 180 + east_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_full + y: 90 + west_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_xp_full + y: 270 + up_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_up_xp_full + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_full + south: minecraft:block/custom/fluid_container_side_xp_full + east: minecraft:block/custom/fluid_container_side_xp_full + west: minecraft:block/custom/fluid_container_side_xp_full + up: minecraft:block/custom/fluid_container_front_xp_full + down: minecraft:block/custom/fluid_container_back_xp_full + down_xp_full: + auto-state: solid + model: + path: minecraft:block/custom/fluid_container_down_xp_full + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_container_side_xp_full + south: minecraft:block/custom/fluid_container_side_xp_full + east: minecraft:block/custom/fluid_container_side_xp_full + west: minecraft:block/custom/fluid_container_side_xp_full + up: minecraft:block/custom/fluid_container_back_xp_full + down: minecraft:block/custom/fluid_container_front_xp_full variants: facing=north,fluid=none,fill_level=0: appearance: north @@ -559,6 +721,54 @@ items: appearance: up_lava_full facing=down,fluid=lava,fill_level=3: appearance: down_lava_full + facing=north,fluid=experience,fill_level=0: + appearance: north + facing=south,fluid=experience,fill_level=0: + appearance: south + facing=east,fluid=experience,fill_level=0: + appearance: east + facing=west,fluid=experience,fill_level=0: + appearance: west + facing=up,fluid=experience,fill_level=0: + appearance: up + facing=down,fluid=experience,fill_level=0: + appearance: down + facing=north,fluid=experience,fill_level=1: + appearance: north_xp_low + facing=south,fluid=experience,fill_level=1: + appearance: south_xp_low + facing=east,fluid=experience,fill_level=1: + appearance: east_xp_low + facing=west,fluid=experience,fill_level=1: + appearance: west_xp_low + facing=up,fluid=experience,fill_level=1: + appearance: up_xp_low + facing=down,fluid=experience,fill_level=1: + appearance: down_xp_low + facing=north,fluid=experience,fill_level=2: + appearance: north_xp_medium + facing=south,fluid=experience,fill_level=2: + appearance: south_xp_medium + facing=east,fluid=experience,fill_level=2: + appearance: east_xp_medium + facing=west,fluid=experience,fill_level=2: + appearance: west_xp_medium + facing=up,fluid=experience,fill_level=2: + appearance: up_xp_medium + facing=down,fluid=experience,fill_level=2: + appearance: down_xp_medium + facing=north,fluid=experience,fill_level=3: + appearance: north_xp_full + facing=south,fluid=experience,fill_level=3: + appearance: south_xp_full + facing=east,fluid=experience,fill_level=3: + appearance: east_xp_full + facing=west,fluid=experience,fill_level=3: + appearance: west_xp_full + facing=up,fluid=experience,fill_level=3: + appearance: up_xp_full + facing=down,fluid=experience,fill_level=3: + appearance: down_xp_full recipes: atlas:fluid_container: diff --git a/src/main/resources/atlas/configuration/fluid_merger.yml b/src/main/resources/atlas/configuration/fluid_merger.yml index 08f38d5..d2ae93f 100644 --- a/src/main/resources/atlas/configuration/fluid_merger.yml +++ b/src/main/resources/atlas/configuration/fluid_merger.yml @@ -29,7 +29,7 @@ items: default: north fluid: type: string - values: [none, water, lava] + values: [none, water, lava, experience] default: none appearances: north: @@ -194,6 +194,60 @@ items: west: minecraft:block/custom/fluid_merger_side_lava up: minecraft:block/custom/fluid_merger_back_lava down: minecraft:block/custom/fluid_merger_front_lava + north_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_merger_front_xp + south: minecraft:block/custom/fluid_merger_back_xp + east: minecraft:block/custom/fluid_merger_side_xp + west: minecraft:block/custom/fluid_merger_side_xp + up: minecraft:block/custom/fluid_merger_top_xp + down: minecraft:block/custom/fluid_merger_bottom_xp + south_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_xp + y: 180 + east_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_xp + y: 90 + west_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_xp + y: 270 + up_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_up_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_merger_side_xp + south: minecraft:block/custom/fluid_merger_side_xp + east: minecraft:block/custom/fluid_merger_side_xp + west: minecraft:block/custom/fluid_merger_side_xp + up: minecraft:block/custom/fluid_merger_front_xp + down: minecraft:block/custom/fluid_merger_back_xp + down_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_merger_down_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_merger_side_xp + south: minecraft:block/custom/fluid_merger_side_xp + east: minecraft:block/custom/fluid_merger_side_xp + west: minecraft:block/custom/fluid_merger_side_xp + up: minecraft:block/custom/fluid_merger_back_xp + down: minecraft:block/custom/fluid_merger_front_xp variants: facing=north,fluid=none: appearance: north @@ -231,6 +285,18 @@ items: appearance: up_lava facing=down,fluid=lava: appearance: down_lava + facing=north,fluid=experience: + appearance: north_experience + facing=south,fluid=experience: + appearance: south_experience + facing=east,fluid=experience: + appearance: east_experience + facing=west,fluid=experience: + appearance: west_experience + facing=up,fluid=experience: + appearance: up_experience + facing=down,fluid=experience: + appearance: down_experience recipes: atlas:fluid_merger: diff --git a/src/main/resources/atlas/configuration/fluid_pipe.yml b/src/main/resources/atlas/configuration/fluid_pipe.yml index d4dff9d..ff644e7 100644 --- a/src/main/resources/atlas/configuration/fluid_pipe.yml +++ b/src/main/resources/atlas/configuration/fluid_pipe.yml @@ -29,7 +29,7 @@ items: default: north fluid: type: string - values: [none, water, lava] + values: [none, water, lava, experience] default: none appearances: north: @@ -194,6 +194,60 @@ items: west: minecraft:block/custom/fluid_pipe_side_filled_lava_left up: minecraft:block/custom/fluid_pipe_back_filled_lava down: minecraft:block/custom/fluid_pipe_front_filled_lava + north_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_pipe_front_filled_xp + south: minecraft:block/custom/fluid_pipe_back_filled_xp + east: minecraft:block/custom/fluid_pipe_side_filled_xp_right + west: minecraft:block/custom/fluid_pipe_side_filled_xp_left + up: minecraft:block/custom/fluid_pipe_side_filled_xp_up + down: minecraft:block/custom/fluid_pipe_side_filled_xp_down + south_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_xp + y: 180 + east_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_xp + y: 90 + west_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_xp + y: 270 + up_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_up_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_pipe_side_filled_xp_up + south: minecraft:block/custom/fluid_pipe_side_filled_xp_down + east: minecraft:block/custom/fluid_pipe_side_filled_xp_right + west: minecraft:block/custom/fluid_pipe_side_filled_xp_left + up: minecraft:block/custom/fluid_pipe_front_filled_xp + down: minecraft:block/custom/fluid_pipe_back_filled_xp + down_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_pipe_down_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_pipe_side_filled_xp_down + south: minecraft:block/custom/fluid_pipe_side_filled_xp_up + east: minecraft:block/custom/fluid_pipe_side_filled_xp_right + west: minecraft:block/custom/fluid_pipe_side_filled_xp_left + up: minecraft:block/custom/fluid_pipe_back_filled_xp + down: minecraft:block/custom/fluid_pipe_front_filled_xp variants: facing=north,fluid=none: appearance: north @@ -231,6 +285,18 @@ items: appearance: up_lava facing=down,fluid=lava: appearance: down_lava + facing=north,fluid=experience: + appearance: north_experience + facing=south,fluid=experience: + appearance: south_experience + facing=east,fluid=experience: + appearance: east_experience + facing=west,fluid=experience: + appearance: west_experience + facing=up,fluid=experience: + appearance: up_experience + facing=down,fluid=experience: + appearance: down_experience recipes: atlas:fluid_pipe: diff --git a/src/main/resources/atlas/configuration/fluid_splitter.yml b/src/main/resources/atlas/configuration/fluid_splitter.yml index a39910e..a7250b9 100644 --- a/src/main/resources/atlas/configuration/fluid_splitter.yml +++ b/src/main/resources/atlas/configuration/fluid_splitter.yml @@ -29,7 +29,7 @@ items: default: north fluid: type: string - values: [none, water, lava] + values: [none, water, lava, experience] default: none appearances: north: @@ -194,6 +194,60 @@ items: west: minecraft:block/custom/fluid_splitter_side_lava up: minecraft:block/custom/fluid_splitter_front_lava down: minecraft:block/custom/fluid_splitter_back_lava + north_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_splitter_front_xp + south: minecraft:block/custom/fluid_splitter_back_xp + east: minecraft:block/custom/fluid_splitter_side_xp + west: minecraft:block/custom/fluid_splitter_side_xp + up: minecraft:block/custom/fluid_splitter_top_xp + down: minecraft:block/custom/fluid_splitter_bottom_xp + south_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_xp + y: 180 + east_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_xp + y: 90 + west_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_xp + y: 270 + up_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_up_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_splitter_side_xp + south: minecraft:block/custom/fluid_splitter_side_xp + east: minecraft:block/custom/fluid_splitter_side_xp + west: minecraft:block/custom/fluid_splitter_side_xp + up: minecraft:block/custom/fluid_splitter_back_xp + down: minecraft:block/custom/fluid_splitter_front_xp + down_experience: + auto-state: solid + model: + path: minecraft:block/custom/fluid_splitter_down_xp + generation: + parent: minecraft:block/cube + textures: + north: minecraft:block/custom/fluid_splitter_side_xp + south: minecraft:block/custom/fluid_splitter_side_xp + east: minecraft:block/custom/fluid_splitter_side_xp + west: minecraft:block/custom/fluid_splitter_side_xp + up: minecraft:block/custom/fluid_splitter_front_xp + down: minecraft:block/custom/fluid_splitter_back_xp variants: facing=north,fluid=none: appearance: north @@ -231,6 +285,18 @@ items: appearance: up_lava facing=down,fluid=lava: appearance: down_lava + facing=north,fluid=experience: + appearance: north_experience + facing=south,fluid=experience: + appearance: south_experience + facing=east,fluid=experience: + appearance: east_experience + facing=west,fluid=experience: + appearance: west_experience + facing=up,fluid=experience: + appearance: up_experience + facing=down,fluid=experience: + appearance: down_experience recipes: atlas:fluid_splitter: diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_back.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_back.png new file mode 100644 index 0000000..9f40192 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_back.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front.png new file mode 100644 index 0000000..c1f373c Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front_active.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front_active.png new file mode 100644 index 0000000..e306553 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_front_active.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_housing.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_housing.png new file mode 100644 index 0000000..0b3c6c8 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_housing.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_side.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_side.png new file mode 100644 index 0000000..9860b81 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_side.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_active.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_active.png new file mode 100644 index 0000000..3bfc60e Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_active.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_east.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_east.png new file mode 100644 index 0000000..6459df2 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_east.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_north.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_north.png new file mode 100644 index 0000000..c6bf4ba Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_north.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_south.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_south.png new file mode 100644 index 0000000..9ac196f Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_south.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_west.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_west.png new file mode 100644 index 0000000..4f153ea Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/experience_extractor_top_west.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_full.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_full.png new file mode 100644 index 0000000..35ee71d Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_full.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_low.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_low.png new file mode 100644 index 0000000..40c48a4 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_low.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_medium.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_medium.png new file mode 100644 index 0000000..f8e7933 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_back_xp_medium.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_full.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_full.png new file mode 100644 index 0000000..5143b03 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_full.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_low.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_low.png new file mode 100644 index 0000000..c0000a6 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_low.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_medium.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_medium.png new file mode 100644 index 0000000..a4083ac Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_front_xp_medium.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_full.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_full.png new file mode 100644 index 0000000..1a1aca7 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_full.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_low.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_low.png new file mode 100644 index 0000000..6bcb8d1 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_low.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_medium.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_medium.png new file mode 100644 index 0000000..2986b06 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_side_xp_medium.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_full.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_full.png new file mode 100644 index 0000000..a6626ee Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_full.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_low.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_low.png new file mode 100644 index 0000000..feb4f4f Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_low.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_medium.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_medium.png new file mode 100644 index 0000000..f10f345 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_container_top_xp_medium.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_back_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_back_xp.png new file mode 100644 index 0000000..eb0c210 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_back_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_bottom_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_bottom_xp.png new file mode 100644 index 0000000..eb0c210 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_bottom_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_front_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_front_xp.png new file mode 100644 index 0000000..e3712d9 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_front_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_side_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_side_xp.png new file mode 100644 index 0000000..eb0c210 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_side_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_top_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_top_xp.png new file mode 100644 index 0000000..eb0c210 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_merger_top_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_back_filled_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_back_filled_xp.png new file mode 100644 index 0000000..344940a Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_back_filled_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_front_filled_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_front_filled_xp.png new file mode 100644 index 0000000..1d48901 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_front_filled_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_down.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_down.png new file mode 100644 index 0000000..722f825 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_down.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_left.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_left.png new file mode 100644 index 0000000..4b79fe2 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_left.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_right.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_right.png new file mode 100644 index 0000000..dac8135 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_right.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_up.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_up.png new file mode 100644 index 0000000..4fe15c5 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_pipe_side_filled_xp_up.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_back_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_back_xp.png new file mode 100644 index 0000000..eb0c210 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_back_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_bottom_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_bottom_xp.png new file mode 100644 index 0000000..11ad606 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_bottom_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_front_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_front_xp.png new file mode 100644 index 0000000..e3712d9 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_front_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_side_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_side_xp.png new file mode 100644 index 0000000..e3712d9 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_side_xp.png differ diff --git a/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_top_xp.png b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_top_xp.png new file mode 100644 index 0000000..e3712d9 Binary files /dev/null and b/src/main/resources/atlas/resourcepack/assets/minecraft/textures/block/custom/fluid_splitter_top_xp.png differ diff --git a/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt b/src/test/kotlin/com/coderjoe/atlas/AtlasPluginTest.kt index 6776148..0d06dd2 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 `power system initializes with 18 block types`() { + fun `power system initializes with 21 block types`() { TestHelper.initPowerFactory() - assertEquals(19, PowerBlockFactory.getRegisteredBlockIds().size) + assertEquals(21, PowerBlockFactory.getRegisteredBlockIds().size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt b/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt index 390770c..69accb4 100644 --- a/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt +++ b/src/test/kotlin/com/coderjoe/atlas/TestHelper.kt @@ -26,6 +26,7 @@ import com.coderjoe.atlas.transport.block.ConveyorBelt import com.coderjoe.atlas.utility.block.AutoSmelter import com.coderjoe.atlas.utility.block.CobblestoneFactory import com.coderjoe.atlas.utility.block.Crusher +import com.coderjoe.atlas.utility.block.ExperienceExtractor import com.coderjoe.atlas.utility.block.ObsidianFactory import com.coderjoe.atlas.utility.block.SmallDrill import com.coderjoe.atlas.utility.block.SoftTouchDrill @@ -206,6 +207,7 @@ object TestHelper { ObsidianFactory.descriptor, Crusher.descriptor, PowerMerger.descriptor, SoftTouchDrill.descriptor, + ExperienceExtractor.descriptor, ), ) } diff --git a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidTypeTest.kt b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidTypeTest.kt index 0327076..47ff2b9 100644 --- a/src/test/kotlin/com/coderjoe/atlas/fluid/FluidTypeTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/fluid/FluidTypeTest.kt @@ -8,9 +8,10 @@ class FluidTypeTest { @Test fun `all enum values exist`() { val values = FluidType.values() - assertEquals(3, values.size) + assertEquals(4, values.size) assertTrue(values.contains(FluidType.WATER)) assertTrue(values.contains(FluidType.LAVA)) + assertTrue(values.contains(FluidType.EXPERIENCE)) assertTrue(values.contains(FluidType.NONE)) } diff --git a/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt b/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt index d7da5a8..fe2464e 100644 --- a/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt +++ b/src/test/kotlin/com/coderjoe/atlas/power/PowerBlockInitializerTest.kt @@ -40,8 +40,9 @@ class PowerBlockInitializerTest { // Crusher: 1 // PowerMerger: 1 // SoftTouchDrill: 1 - // Total: 19 - assertEquals(19, ids.size) + // ExperienceExtractor: 2 (base + active) + // Total: 21 + assertEquals(21, ids.size) } @Test diff --git a/src/test/kotlin/com/coderjoe/atlas/utility/ExperienceExtractorTest.kt b/src/test/kotlin/com/coderjoe/atlas/utility/ExperienceExtractorTest.kt new file mode 100644 index 0000000..d8f6e5f --- /dev/null +++ b/src/test/kotlin/com/coderjoe/atlas/utility/ExperienceExtractorTest.kt @@ -0,0 +1,416 @@ +package com.coderjoe.atlas.utility + +import com.coderjoe.atlas.TestHelper +import com.coderjoe.atlas.TestHelper.callPowerUpdate +import com.coderjoe.atlas.core.PlacementType +import com.coderjoe.atlas.fluid.FluidBlockRegistry +import com.coderjoe.atlas.fluid.FluidType +import com.coderjoe.atlas.fluid.block.FluidPipe +import com.coderjoe.atlas.power.PowerBlockFactory +import com.coderjoe.atlas.power.PowerBlockRegistry +import com.coderjoe.atlas.utility.block.ExperienceExtractor +import io.mockk.every +import io.mockk.mockk +import io.mockk.verify +import org.bukkit.Material +import org.bukkit.block.Block +import org.bukkit.block.BlockFace +import org.bukkit.block.Hopper +import org.bukkit.inventory.Inventory +import org.bukkit.inventory.ItemStack +import org.junit.jupiter.api.AfterEach +import org.junit.jupiter.api.Assertions.assertDoesNotThrow +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test + +class ExperienceExtractorTest { + @BeforeEach + fun setup() { + TestHelper.setup() + } + + @AfterEach + fun teardown() { + TestHelper.teardown() + } + + private fun mockHopperAt( + x: Int, + y: Int, + z: Int, + items: Array, + ): Hopper { + val block = mockk(relaxed = true) + val hopper = mockk(relaxed = true) + val inventory = mockk(relaxed = true) + + every { TestHelper.mockWorld.getBlockAt(x, y, z) } returns block + every { block.state } returns hopper + every { hopper.inventory } returns inventory + every { inventory.size } returns items.size + for (i in items.indices) { + every { inventory.getItem(i) } returns items[i] + } + + return hopper + } + + private fun mockNonHopperAt( + x: Int, + y: Int, + z: Int, + ) { + val block = mockk(relaxed = true) + val blockState = mockk(relaxed = true) + every { TestHelper.mockWorld.getBlockAt(x, y, z) } returns block + every { block.state } returns blockState + } + + private fun setupAdjacentNonHoppers( + centerX: Int = 0, + centerY: Int = 64, + centerZ: Int = 0, + excludeFaces: Set = emptySet(), + ) { + for (face in listOf(BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST, BlockFace.UP, BlockFace.DOWN)) { + if (face in excludeFaces) continue + mockNonHopperAt( + centerX + face.modX, + centerY + face.modY, + centerZ + face.modZ, + ) + } + } + + @Test + fun `extractor has correct facing`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.EAST) + assertEquals(BlockFace.EAST, extractor.facing) + } + + @Test + fun `extractor defaults to NORTH when SELF`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.SELF) + assertEquals(BlockFace.NORTH, extractor.facing) + } + + @Test + fun `extractor base block ID is correct`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals("atlas:experience_extractor", extractor.baseBlockId) + } + + @Test + fun `descriptor has correct properties`() { + val desc = ExperienceExtractor.descriptor + assertEquals("atlas:experience_extractor", desc.baseBlockId) + assertEquals("Experience Extractor", desc.displayName) + assertEquals(PlacementType.DIRECTIONAL, desc.placementType) + } + + @Test + fun `descriptor includes active variant`() { + val desc = ExperienceExtractor.descriptor + assertTrue(desc.additionalBlockIds.contains("atlas:experience_extractor_active")) + } + + @Test + fun `max storage is 12`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + assertEquals(12, extractor.maxStorage) + } + + @Test + fun `canReceivePower is true`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + assertTrue(extractor.canAcceptPower()) + } + + @Test + fun `visual state returns base when no power and no xp`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + extractor.currentPower = 0 + extractor.storedXp = 0.0 + assertEquals("atlas:experience_extractor", extractor.getVisualStateBlockId()) + } + + @Test + fun `visual state returns active when has power`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + extractor.currentPower = 3 + assertEquals("atlas:experience_extractor_active", extractor.getVisualStateBlockId()) + } + + @Test + fun `visual state returns active when has stored xp`() { + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + extractor.currentPower = 0 + extractor.storedXp = 2.0 + assertEquals("atlas:experience_extractor_active", extractor.getVisualStateBlockId()) + } + + @Test + fun `base ID is registered`() { + TestHelper.initPowerFactory() + assertTrue(PowerBlockFactory.isRegistered("atlas:experience_extractor")) + } + + @Test + fun `active ID is registered`() { + TestHelper.initPowerFactory() + assertTrue(PowerBlockFactory.isRegistered("atlas:experience_extractor_active")) + } + + @Test + fun `factory creates ExperienceExtractor from base ID`() { + TestHelper.initPowerFactory() + val block = + PowerBlockFactory.createPowerBlock( + "atlas:experience_extractor", + TestHelper.createLocation(), + BlockFace.SOUTH, + ) + assertTrue(block is ExperienceExtractor) + assertEquals(BlockFace.SOUTH, block!!.facing) + } + + @Test + fun `power update does not throw with no adjacent hoppers`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(), BlockFace.NORTH) + setupAdjacentNonHoppers() + + assertDoesNotThrow { + extractor.callPowerUpdate() + } + } + + @Test + fun `pulls item from adjacent hopper and gains xp`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 3 + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COAL + every { mockStack.amount } returns 1 + + val hopper = mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(0, extractor.currentPower) + assertEquals(1.0, extractor.storedXp) + } + + @Test + fun `removes single item from hopper inventory`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 3 + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COAL + every { mockStack.amount } returns 1 + + val hopper = mockHopperAt(0, 65, 0, arrayOf(mockStack)) + val inventory = hopper.inventory + + extractor.callPowerUpdate() + + verify { inventory.setItem(0, null) } + } + + @Test + fun `decrements hopper item stack when amount greater than 1`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 3 + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COAL + every { mockStack.amount } returns 5 + + mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + verify { mockStack.amount = 4 } + } + + @Test + fun `does not pull items without power`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 0 + setupAdjacentNonHoppers(excludeFaces = setOf(BlockFace.UP)) + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COAL + every { mockStack.amount } returns 1 + + mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(0.0, extractor.storedXp) + } + + @Test + fun `unlisted items give default xp`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 6 + setupAdjacentNonHoppers(excludeFaces = setOf(BlockFace.UP)) + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COBBLESTONE + every { mockStack.amount } returns 1 + + mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(3, extractor.currentPower) + assertEquals(ExperienceExtractor.DEFAULT_XP, extractor.storedXp) + } + + @Test + fun `pushes experience fluid to adjacent fluid block in facing direction`() { + val powerRegistry = PowerBlockRegistry(TestHelper.mockPlugin) + val fluidRegistry = FluidBlockRegistry(TestHelper.mockPlugin) + + val extractorLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val extractor = ExperienceExtractor(extractorLoc, BlockFace.NORTH) + extractor.storedXp = 3.0 + TestHelper.addToRegistry(powerRegistry, extractor, ExperienceExtractor.BLOCK_ID) + setupAdjacentNonHoppers() + + val pipeLoc = TestHelper.createLocation(0.0, 64.0, -1.0) + val pipe = FluidPipe(pipeLoc, BlockFace.NORTH) + TestHelper.addToRegistry(fluidRegistry, pipe, FluidPipe.BLOCK_ID) + + extractor.callPowerUpdate() + + assertEquals(2.0, extractor.storedXp) + assertEquals(FluidType.EXPERIENCE, pipe.storedFluid) + } + + @Test + fun `does not push fluid when no adjacent fluid block`() { + PowerBlockRegistry(TestHelper.mockPlugin) + FluidBlockRegistry(TestHelper.mockPlugin) + + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.storedXp = 3.0 + setupAdjacentNonHoppers() + + extractor.callPowerUpdate() + + assertEquals(3.0, extractor.storedXp) + } + + @Test + fun `does not consume items when xp buffer is full`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 6 + extractor.storedXp = ExperienceExtractor.MAX_XP_BUFFER + setupAdjacentNonHoppers(excludeFaces = setOf(BlockFace.UP)) + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.COAL + every { mockStack.amount } returns 1 + + mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(6, extractor.currentPower) + } + + @Test + fun `xp values map contains expected categories`() { + val xpValues = ExperienceExtractor.XP_VALUES + + // Ore blocks + assertEquals(1.0, xpValues[Material.IRON_ORE]) + assertEquals(1.0, xpValues[Material.DEEPSLATE_IRON_ORE]) + assertEquals(1.0, xpValues[Material.COAL_ORE]) + assertEquals(1.0, xpValues[Material.COPPER_ORE]) + assertEquals(1.0, xpValues[Material.GOLD_ORE]) + // Raw ores & minerals + assertEquals(1.0, xpValues[Material.RAW_IRON]) + assertEquals(1.0, xpValues[Material.RAW_GOLD]) + assertEquals(1.0, xpValues[Material.COAL]) + // Food + assertEquals(2.0, xpValues[Material.COOKED_BEEF]) + assertEquals(2.0, xpValues[Material.COOKED_CHICKEN]) + // Monster drops + assertEquals(3.0, xpValues[Material.BONE]) + assertEquals(3.0, xpValues[Material.GUNPOWDER]) + // Valuable ores & drops + assertEquals(5.0, xpValues[Material.DIAMOND_ORE]) + assertEquals(5.0, xpValues[Material.DEEPSLATE_DIAMOND_ORE]) + assertEquals(5.0, xpValues[Material.BLAZE_ROD]) + assertEquals(5.0, xpValues[Material.DIAMOND]) + // Very valuable + assertEquals(8.0, xpValues[Material.NETHER_STAR]) + } + + @Test + fun `pulls power from adjacent blocks`() { + val registry = PowerBlockRegistry(TestHelper.mockPlugin) + val extractorLoc = TestHelper.createLocation(0.0, 64.0, 0.0) + val extractor = ExperienceExtractor(extractorLoc, BlockFace.NORTH) + TestHelper.addToRegistry(registry, extractor, ExperienceExtractor.BLOCK_ID) + setupAdjacentNonHoppers() + + val batteryLoc = TestHelper.createLocation(1.0, 64.0, 0.0) + val battery = com.coderjoe.atlas.power.block.SmallBattery(batteryLoc, BlockFace.WEST) + battery.currentPower = 5 + TestHelper.addToRegistry(registry, battery, "atlas:small_battery") + + extractor.callPowerUpdate() + + assertTrue(extractor.currentPower > 0) + assertTrue(battery.currentPower < 5) + } + + @Test + fun `pulls ore blocks from hopper`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 3 + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.IRON_ORE + every { mockStack.amount } returns 1 + + val hopper = mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(1.0, extractor.storedXp) + } + + @Test + fun `higher value items give more xp`() { + PowerBlockRegistry(TestHelper.mockPlugin) + val extractor = ExperienceExtractor(TestHelper.createLocation(0.0, 64.0, 0.0), BlockFace.NORTH) + extractor.currentPower = 3 + setupAdjacentNonHoppers(excludeFaces = setOf(BlockFace.UP)) + + val mockStack = mockk(relaxed = true) + every { mockStack.type } returns Material.NETHER_STAR + every { mockStack.amount } returns 1 + + mockHopperAt(0, 65, 0, arrayOf(mockStack)) + + extractor.callPowerUpdate() + + assertEquals(8.0, extractor.storedXp) + } +}