diff --git a/README.md b/README.md
index a5e63f4..f8a8044 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
# Iron Chests (StationAPI)
-
+
Basic port of Iron Chests for b1.7.3 with Fabric and [StationAPI](https://github.com/ModificationStation/StationAPI).
@@ -13,4 +13,4 @@ unashamedly stole code
## Features
- [x] Iron, Gold and Diamond Chest
- [ ] Other modded metal chests (Silver, copper, dimando?)
-- [ ] Chest upgrades
\ No newline at end of file
+- [x] Chest upgrades
\ No newline at end of file
diff --git a/gradle.properties b/gradle.properties
index 36163e6..c76ced4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -15,7 +15,7 @@ howmanyitems_version=5.2.1
modmenu_version=v1.8.5-beta.3
# Mod Properties
-next_version=0.1.0
+next_version=0.2.0
maven_group=net.zekromaster.minecraft
archives_base_name=IronChestsStationAPI
diff --git a/src/main/java/net/zekromaster/minecraft/ironchests/mixin/ChestMixin.java b/src/main/java/net/zekromaster/minecraft/ironchests/mixin/ChestMixin.java
new file mode 100644
index 0000000..b71db29
--- /dev/null
+++ b/src/main/java/net/zekromaster/minecraft/ironchests/mixin/ChestMixin.java
@@ -0,0 +1,30 @@
+package net.zekromaster.minecraft.ironchests.mixin;
+
+import net.minecraft.block.ChestBlock;
+import net.minecraft.block.entity.ChestBlockEntity;
+import net.minecraft.entity.player.PlayerEntity;
+import net.minecraft.world.World;
+import net.zekromaster.minecraft.ironchests.ChestUpgrade;
+import org.spongepowered.asm.mixin.Mixin;
+import org.spongepowered.asm.mixin.injection.At;
+import org.spongepowered.asm.mixin.injection.Inject;
+import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
+
+@Mixin(ChestBlock.class)
+public class ChestMixin {
+
+ @Inject(method = "onUse", at=@At("HEAD"), cancellable = true)
+ void onUseMixin(World world, int x, int y, int z, PlayerEntity player, CallbackInfoReturnable cir) {
+ var chest = (ChestBlockEntity) world.getBlockEntity(x, y, z);
+ var hand = player.getHand();
+ if (hand != null) {
+ if (hand.getItem() instanceof ChestUpgrade upgrade) {
+ if (upgrade.upgrade(world, x, y, z, player, chest)) {
+ hand.count--;
+ }
+ cir.setReturnValue(true);
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/net/zekromaster/minecraft/ironchests/block-entity.kt b/src/main/kotlin/net/zekromaster/minecraft/ironchests/block.kt
similarity index 55%
rename from src/main/kotlin/net/zekromaster/minecraft/ironchests/block-entity.kt
rename to src/main/kotlin/net/zekromaster/minecraft/ironchests/block.kt
index e70441a..cf8a15d 100644
--- a/src/main/kotlin/net/zekromaster/minecraft/ironchests/block-entity.kt
+++ b/src/main/kotlin/net/zekromaster/minecraft/ironchests/block.kt
@@ -1,18 +1,24 @@
package net.zekromaster.minecraft.ironchests
+import net.mine_diver.unsafeevents.listener.EventListener
import net.minecraft.block.Block
import net.minecraft.block.entity.BlockEntity
import net.minecraft.block.entity.ChestBlockEntity
import net.minecraft.block.material.Material
import net.minecraft.entity.ItemEntity
import net.minecraft.entity.player.PlayerEntity
+import net.minecraft.item.Item
import net.minecraft.item.ItemStack
import net.minecraft.nbt.NbtCompound
import net.minecraft.screen.GenericContainerScreenHandler
import net.minecraft.world.World
import net.modificationstation.stationapi.api.block.BlockState
+import net.modificationstation.stationapi.api.event.block.entity.BlockEntityRegisterEvent
+import net.modificationstation.stationapi.api.event.recipe.RecipeRegisterEvent
+import net.modificationstation.stationapi.api.event.registry.BlockRegistryEvent
import net.modificationstation.stationapi.api.gui.screen.container.GuiHelper
import net.modificationstation.stationapi.api.item.ItemPlacementContext
+import net.modificationstation.stationapi.api.recipe.CraftingRegistry
import net.modificationstation.stationapi.api.state.StateManager
import net.modificationstation.stationapi.api.state.property.EnumProperty
import net.modificationstation.stationapi.api.template.block.TemplateBlockWithEntity
@@ -21,13 +27,74 @@ import net.modificationstation.stationapi.api.util.math.Direction
import net.zekromaster.minecraft.ironchests.mixin.ChestInventoryAccessor
import java.util.*
import java.util.function.Predicate
-import kotlin.math.floor
-class IronChestBlockEntity(material: IronChestMaterial): ChestBlockEntity() {
- constructor(): this(IronChestMaterial.IRON)
+object IronChestsBlockEntrypoint {
+ @JvmStatic @get:JvmName("ironChest")
+ lateinit var IRON_CHEST: IronChestBlock
+ private set
+ @JvmStatic @get:JvmName("goldChest")
+ lateinit var GOLD_CHEST: IronChestBlock
+ private set
+ @JvmStatic @get:JvmName("diamondChest")
+ lateinit var DIAMOND_CHEST: IronChestBlock
+ private set
+
+ @EventListener
+ fun registerBlocks(event: BlockRegistryEvent) {
+ IRON_CHEST = IronChestBlock(Identifier.of("ironchests:iron_chest"), IronChestMaterial.IRON)
+ IRON_CHEST.setTranslationKey(Identifier.of("ironchests:iron_chest"))
+ GOLD_CHEST = IronChestBlock(Identifier.of("ironchests:gold_chest"), IronChestMaterial.GOLD)
+ GOLD_CHEST.setTranslationKey(Identifier.of("ironchests:gold_chest"))
+ DIAMOND_CHEST = IronChestBlock(Identifier.of("ironchests:diamond_chest"), IronChestMaterial.DIAMOND)
+ DIAMOND_CHEST.setTranslationKey(Identifier.of("ironchests:diamond_chest"))
+ }
+
+ @EventListener
+ internal fun registerTileEntities(event: BlockEntityRegisterEvent) {
+ event.register(
+ IronChestBlockEntity::class.java,
+ "ironchest"
+ )
+ }
- private var material = material
+ @EventListener
+ internal fun registerRecipes(event: RecipeRegisterEvent) {
+ val type = RecipeRegisterEvent.Vanilla.fromType(event.recipeId)
+
+ if (type == RecipeRegisterEvent.Vanilla.CRAFTING_SHAPED) {
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(IRON_CHEST),
+ "iii", "ici", "iii",
+ 'i', ItemStack(Item.IRON_INGOT),
+ 'c', ItemStack(Block.CHEST)
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(GOLD_CHEST),
+ "iii", "ici", "iii",
+ 'i', ItemStack(Item.GOLD_INGOT),
+ 'c', ItemStack(IRON_CHEST)
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(DIAMOND_CHEST),
+ "gig", "ici", "gig",
+ 'i', ItemStack(Item.DIAMOND),
+ 'c', ItemStack(GOLD_CHEST),
+ 'g', ItemStack(Block.GLASS)
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(DIAMOND_CHEST),
+ "igi", "gcg", "igi",
+ 'i', ItemStack(Item.DIAMOND),
+ 'c', ItemStack(GOLD_CHEST),
+ 'g', ItemStack(Block.GLASS)
+ )
+ }
+ }
+}
+
+class IronChestBlockEntity @JvmOverloads constructor(material: IronChestMaterial = IronChestMaterial.IRON): ChestBlockEntity() {
+ var material = material
set(x) = run {
field = x
updateInventorySize()
@@ -37,6 +104,7 @@ class IronChestBlockEntity(material: IronChestMaterial): ChestBlockEntity() {
override fun getName(): String = material.chestName
init {
+ @Suppress("CAST_NEVER_SUCCEEDS")
(this as ChestInventoryAccessor).inventory = arrayOfNulls(material.size)
}
@@ -51,7 +119,8 @@ class IronChestBlockEntity(material: IronChestMaterial): ChestBlockEntity() {
}
private fun updateInventorySize() {
- (this as ChestInventoryAccessor).inventory.copyOf(material.size)
+ @Suppress("CAST_NEVER_SUCCEEDS")
+ (this as ChestInventoryAccessor).inventory = inventory.copyOf(material.size)
}
}
@@ -75,16 +144,7 @@ class IronChestBlock(identifier: Identifier, private val chestMaterial: IronChes
super.appendProperties(builder)
}
- override fun getPlacementState(context: ItemPlacementContext): BlockState {
- val direction: Int = floor((context.player!!.yaw * 4.0f / 360.0f).toDouble() + 0.5).toInt() and 3
- return when (direction) {
- 0 -> defaultState.with(FACING, Direction.NORTH)
- 1 -> defaultState.with(FACING, Direction.EAST)
- 2 -> defaultState.with(FACING, Direction.SOUTH)
- 3 -> defaultState.with(FACING, Direction.WEST)
- else -> defaultState.with(FACING, Direction.NORTH)
- }
- }
+ override fun getPlacementState(context: ItemPlacementContext): BlockState = defaultState.with(FACING, context.player!!.placementFacing())
override fun createBlockEntity(): BlockEntity {
return IronChestBlockEntity(chestMaterial)
@@ -125,7 +185,20 @@ class IronChestBlock(identifier: Identifier, private val chestMaterial: IronChes
override fun onUse(world: World, x: Int, y: Int, z: Int, player: PlayerEntity): Boolean {
val entity = world.getBlockEntity(x, y, z) ?: return true
- if (entity !is IronChestBlockEntity || world.shouldSuffocate(x, y+1, z) || world.isRemote) {
+
+ if (entity !is IronChestBlockEntity || world.isRemote) {
+ return true
+ }
+
+ val handheldItem = player.hand?.item
+ if (handheldItem is ChestUpgrade) {
+ if (handheldItem.upgrade(world, x, y, z, player, entity)) {
+ player.hand!!.count--
+ }
+ return true
+ }
+
+ if (world.shouldSuffocate(x, y+1, z)) {
return true
}
diff --git a/src/main/kotlin/net/zekromaster/minecraft/ironchests/entrypoints.kt b/src/main/kotlin/net/zekromaster/minecraft/ironchests/entrypoints.kt
deleted file mode 100644
index f65fb22..0000000
--- a/src/main/kotlin/net/zekromaster/minecraft/ironchests/entrypoints.kt
+++ /dev/null
@@ -1,113 +0,0 @@
-package net.zekromaster.minecraft.ironchests
-
-import net.mine_diver.unsafeevents.listener.EventListener
-import net.minecraft.block.Block
-import net.minecraft.client.gui.screen.Screen
-import net.minecraft.entity.player.PlayerEntity
-import net.minecraft.inventory.Inventory
-import net.minecraft.item.Item
-import net.minecraft.item.ItemStack
-import net.modificationstation.stationapi.api.event.block.entity.BlockEntityRegisterEvent
-import net.modificationstation.stationapi.api.event.recipe.RecipeRegisterEvent
-import net.modificationstation.stationapi.api.event.registry.BlockRegistryEvent
-import net.modificationstation.stationapi.api.event.registry.GuiHandlerRegistryEvent
-import net.modificationstation.stationapi.api.recipe.CraftingRegistry
-import net.modificationstation.stationapi.api.util.Identifier
-import uk.co.benjiweber.expressions.tuple.BiTuple
-import java.util.function.BiFunction
-import java.util.function.Supplier
-
-object IronChests {
-
- @JvmStatic @get:JvmName("ironChest")
- lateinit var IRON_CHEST: IronChestBlock
- private set
- @JvmStatic @get:JvmName("goldChest")
- lateinit var GOLD_CHEST: IronChestBlock
- private set
- @JvmStatic @get:JvmName("diamondChest")
- lateinit var DIAMOND_CHEST: IronChestBlock
- private set
-
- @EventListener
- internal fun registerBlocks(event: BlockRegistryEvent) {
- IRON_CHEST = IronChestBlock(Identifier.of("ironchests:iron_chest"), IronChestMaterial.IRON)
- IRON_CHEST.setTranslationKey(Identifier.of("ironchests:iron_chest"))
- GOLD_CHEST = IronChestBlock(Identifier.of("ironchests:gold_chest"), IronChestMaterial.GOLD)
- GOLD_CHEST.setTranslationKey(Identifier.of("ironchests:gold_chest"))
- DIAMOND_CHEST = IronChestBlock(Identifier.of("ironchests:diamond_chest"), IronChestMaterial.DIAMOND)
- DIAMOND_CHEST.setTranslationKey(Identifier.of("ironchests:diamond_chest"))
- }
-
- @EventListener
- internal fun registerTileEntities(event: BlockEntityRegisterEvent) {
- event.register(
- IronChestBlockEntity::class.java,
- "ironchest"
- )
- }
-
- @EventListener
- internal fun registerRecipes(event: RecipeRegisterEvent) {
- val type = RecipeRegisterEvent.Vanilla.fromType(event.recipeId)
-
- if (type == RecipeRegisterEvent.Vanilla.CRAFTING_SHAPED) {
- CraftingRegistry.addShapedRecipe(
- ItemStack(IRON_CHEST),
- "iii", "ici", "iii",
- 'i', ItemStack(Item.IRON_INGOT),
- 'c', ItemStack(Block.CHEST)
- )
- CraftingRegistry.addShapedRecipe(
- ItemStack(GOLD_CHEST),
- "iii", "ici", "iii",
- 'i', ItemStack(Item.GOLD_INGOT),
- 'c', ItemStack(IRON_CHEST)
- )
- CraftingRegistry.addShapedRecipe(
- ItemStack(DIAMOND_CHEST),
- "gig", "ici", "gig",
- 'i', ItemStack(Item.DIAMOND),
- 'c', ItemStack(GOLD_CHEST),
- 'g', ItemStack(Block.GLASS)
- )
- CraftingRegistry.addShapedRecipe(
- ItemStack(DIAMOND_CHEST),
- "igi", "gcg", "igi",
- 'i', ItemStack(Item.DIAMOND),
- 'c', ItemStack(GOLD_CHEST),
- 'g', ItemStack(Block.GLASS)
- )
- }
- }
-
-}
-
-
-internal object RegisterGUIs {
-
- private class OpenInventory(private val material: IronChestMaterial): BiFunction {
- override fun apply(player: PlayerEntity, inventory: Inventory): Screen =
- IronChestScreen(player.inventory, inventory, material)
- }
-
- private data class IronChestFactory(val material: IronChestMaterial): Supplier {
- override fun get(): IronChestBlockEntity = IronChestBlockEntity(material)
- }
-
- @EventListener
- fun registerGUIs(event: GuiHandlerRegistryEvent) {
- event.registry.registerValueNoMessage(Identifier.of("ironchests:gui_iron"), BiTuple.of(
- OpenInventory(IronChestMaterial.IRON),
- IronChestFactory(IronChestMaterial.IRON)
- ))
- event.registry.registerValueNoMessage(Identifier.of("ironchests:gui_gold"), BiTuple.of(
- OpenInventory(IronChestMaterial.GOLD),
- IronChestFactory(IronChestMaterial.GOLD)
- ))
- event.registry.registerValueNoMessage(Identifier.of("ironchests:gui_diamond"), BiTuple.of(
- OpenInventory(IronChestMaterial.DIAMOND),
- IronChestFactory(IronChestMaterial.DIAMOND)
- ))
- }
-}
\ No newline at end of file
diff --git a/src/main/kotlin/net/zekromaster/minecraft/ironchests/gui.kt b/src/main/kotlin/net/zekromaster/minecraft/ironchests/gui.kt
index 98edd17..0dfb1a6 100644
--- a/src/main/kotlin/net/zekromaster/minecraft/ironchests/gui.kt
+++ b/src/main/kotlin/net/zekromaster/minecraft/ironchests/gui.kt
@@ -2,13 +2,50 @@ package net.zekromaster.minecraft.ironchests
import net.fabricmc.api.EnvType
import net.fabricmc.api.Environment
+import net.mine_diver.unsafeevents.listener.EventListener
+import net.minecraft.client.gui.screen.Screen
import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.inventory.Inventory
import net.minecraft.screen.ScreenHandler
import net.minecraft.screen.slot.Slot
+import net.modificationstation.stationapi.api.event.registry.GuiHandlerRegistryEvent
+import net.modificationstation.stationapi.api.util.Identifier
import org.lwjgl.opengl.GL11
+import uk.co.benjiweber.expressions.tuple.BiTuple
+import java.util.function.BiFunction
+import java.util.function.Supplier
+internal object RegisterGUIs {
+
+ private class OpenInventory(private val material: IronChestMaterial): BiFunction {
+ override fun apply(player: PlayerEntity, inventory: Inventory): Screen =
+ IronChestScreen(player.inventory, inventory, material)
+ }
+
+ private data class IronChestFactory(val material: IronChestMaterial): Supplier {
+ override fun get(): IronChestBlockEntity = IronChestBlockEntity(material)
+ }
+
+ @EventListener
+ fun registerGUIs(event: GuiHandlerRegistryEvent) {
+ event.registry.registerValueNoMessage(
+ Identifier.of("ironchests:gui_iron"), BiTuple.of(
+ OpenInventory(IronChestMaterial.IRON),
+ IronChestFactory(IronChestMaterial.IRON)
+ ))
+ event.registry.registerValueNoMessage(
+ Identifier.of("ironchests:gui_gold"), BiTuple.of(
+ OpenInventory(IronChestMaterial.GOLD),
+ IronChestFactory(IronChestMaterial.GOLD)
+ ))
+ event.registry.registerValueNoMessage(
+ Identifier.of("ironchests:gui_diamond"), BiTuple.of(
+ OpenInventory(IronChestMaterial.DIAMOND),
+ IronChestFactory(IronChestMaterial.DIAMOND)
+ ))
+ }
+}
private fun IronChestMaterial.gui() =
when (this) {
@@ -22,10 +59,6 @@ private enum class GUIType(val material: IronChestMaterial, val width: Int, val
IRON(IronChestMaterial.IRON, 184, 202, "ironchest.png"),
GOLD(IronChestMaterial.GOLD, 184, 256, "goldchest.png"),
DIAMOND(IronChestMaterial.DIAMOND, 238, 256, "diamondchest.png");
-
- fun handler(playerInventory: Inventory, inventory: Inventory): ScreenHandler =
- IronChestScreenHandler(this, playerInventory, inventory, width, height)
-
}
private class IronChestScreenHandler(
diff --git a/src/main/kotlin/net/zekromaster/minecraft/ironchests/upgrades.kt b/src/main/kotlin/net/zekromaster/minecraft/ironchests/upgrades.kt
new file mode 100644
index 0000000..c84c178
--- /dev/null
+++ b/src/main/kotlin/net/zekromaster/minecraft/ironchests/upgrades.kt
@@ -0,0 +1,131 @@
+package net.zekromaster.minecraft.ironchests
+
+import net.mine_diver.unsafeevents.listener.EventListener
+import net.minecraft.block.Block
+import net.minecraft.block.entity.ChestBlockEntity
+import net.minecraft.entity.player.PlayerEntity
+import net.minecraft.item.Item
+import net.minecraft.item.ItemStack
+import net.minecraft.world.World
+import net.modificationstation.stationapi.api.event.recipe.RecipeRegisterEvent
+import net.modificationstation.stationapi.api.event.registry.ItemRegistryEvent
+import net.modificationstation.stationapi.api.recipe.CraftingRegistry
+import net.modificationstation.stationapi.api.registry.ItemRegistry
+import net.modificationstation.stationapi.api.tag.TagKey
+import net.modificationstation.stationapi.api.template.item.TemplateItem
+import net.modificationstation.stationapi.api.util.Identifier
+import net.modificationstation.stationapi.api.util.math.Direction
+import net.zekromaster.minecraft.ironchests.IronChestBlock.Companion.FACING
+import net.zekromaster.minecraft.ironchests.IronChestMaterial.*
+import net.zekromaster.minecraft.ironchests.IronChestsBlockEntrypoint.DIAMOND_CHEST
+import net.zekromaster.minecraft.ironchests.IronChestsBlockEntrypoint.GOLD_CHEST
+import net.zekromaster.minecraft.ironchests.IronChestsBlockEntrypoint.IRON_CHEST
+import net.zekromaster.minecraft.ironchests.mixin.ChestInventoryAccessor
+
+object IronChestsUpgradesEntrypoint {
+
+ @JvmStatic @get:JvmName("woodToIron")
+ lateinit var WOOD_TO_IRON: ChestUpgrade
+ private set
+ @JvmStatic @get:JvmName("ironToGold")
+ lateinit var IRON_TO_GOLD: ChestUpgrade
+ private set
+ @JvmStatic @get:JvmName("goldToDiamond")
+ lateinit var GOLD_TO_DIAMOND: ChestUpgrade
+ private set
+
+ @EventListener
+ fun registerItems(event: ItemRegistryEvent) {
+ Identifier.of("ironchests:upgrades/wood_to_iron").apply {
+ WOOD_TO_IRON = WoodToIronUpgrade(this, IRON)
+ WOOD_TO_IRON.setTranslationKey(this)
+ }
+ Identifier.of("ironchests:upgrades/iron_to_gold").apply {
+ IRON_TO_GOLD = IronToIronUpgrade(this, IRON, GOLD)
+ IRON_TO_GOLD.setTranslationKey(this)
+ }
+ Identifier.of("ironchests:upgrades/gold_to_diamond").apply {
+ GOLD_TO_DIAMOND = IronToIronUpgrade(this, GOLD, DIAMOND)
+ GOLD_TO_DIAMOND.setTranslationKey(this)
+ }
+ }
+
+ @EventListener
+ internal fun registerRecipes(event: RecipeRegisterEvent) {
+ val type = RecipeRegisterEvent.Vanilla.fromType(event.recipeId)
+
+ if (type == RecipeRegisterEvent.Vanilla.CRAFTING_SHAPED) {
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(WOOD_TO_IRON),
+ "iii", "ici", "iii",
+ 'i', ItemStack(Item.IRON_INGOT),
+ 'c', TagKey.of(ItemRegistry.KEY, Identifier.of("planks"))
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(IRON_TO_GOLD),
+ "iii", "ici", "iii",
+ 'i', ItemStack(Item.GOLD_INGOT),
+ 'c', ItemStack(Item.IRON_INGOT)
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(GOLD_TO_DIAMOND),
+ "gig", "ici", "gig",
+ 'i', ItemStack(Item.DIAMOND),
+ 'c', ItemStack(Item.GOLD_INGOT),
+ 'g', ItemStack(Block.GLASS)
+ )
+ CraftingRegistry.addShapedRecipe(
+ ItemStack(GOLD_TO_DIAMOND),
+ "igi", "gcg", "igi",
+ 'i', ItemStack(Item.DIAMOND),
+ 'c', ItemStack(Item.GOLD_INGOT),
+ 'g', ItemStack(Block.GLASS)
+ )
+ }
+ }
+}
+
+fun IronChestMaterial.block(): Block =
+ when (this) {
+ IRON -> IRON_CHEST
+ GOLD -> GOLD_CHEST
+ DIAMOND -> DIAMOND_CHEST
+ }
+
+sealed class ChestUpgrade(identifier: Identifier, private val destination: IronChestMaterial): TemplateItem(identifier) {
+ fun upgrade(world: World, x: Int, y: Int, z: Int, player: PlayerEntity, blockEntity: ChestBlockEntity): Boolean {
+ if (canUpgrade(blockEntity)) {
+ val oldBlockState = world.getBlockState(x, y, z)
+ val oldContents = (blockEntity as ChestInventoryAccessor).inventory.copyOf()
+ val oldBlock = blockEntity.block
+
+ (blockEntity as ChestInventoryAccessor).inventory = arrayOfNulls(blockEntity.size())
+ world.setBlock(x, y, z, destination.block().id)
+
+ if (oldBlock is IronChestBlock) {
+ world.setBlockState(x, y, z, world.getBlockState(x, y, z).with(FACING, oldBlockState.get(FACING) ?: Direction.NORTH))
+ } else {
+ world.setBlockState(x, y, z, world.getBlockState(x, y, z).with(FACING, player.placementFacing()))
+ }
+
+ val newEntity = world.getBlockEntity(x, y, z) as IronChestBlockEntity
+ @Suppress("CAST_NEVER_SUCCEEDS")
+ (newEntity as ChestInventoryAccessor).inventory = oldContents.copyOf(newEntity.size())
+ world.setBlockDirty(x, y, z)
+ blockEntity.markDirty()
+ return true
+ }
+ return false
+ }
+
+ protected abstract fun canUpgrade(blockEntity: ChestBlockEntity): Boolean
+
+}
+
+class WoodToIronUpgrade(identifier: Identifier, destination: IronChestMaterial): ChestUpgrade(identifier, destination) {
+ override fun canUpgrade(blockEntity: ChestBlockEntity) = blockEntity.block == Block.CHEST
+}
+
+class IronToIronUpgrade(identifier: Identifier, val starting: IronChestMaterial, destination: IronChestMaterial): ChestUpgrade(identifier, destination) {
+ override fun canUpgrade(blockEntity: ChestBlockEntity): Boolean = blockEntity is IronChestBlockEntity && blockEntity.material == starting
+}
\ No newline at end of file
diff --git a/src/main/kotlin/net/zekromaster/minecraft/ironchests/util.kt b/src/main/kotlin/net/zekromaster/minecraft/ironchests/util.kt
index ebd77cb..641ef9f 100644
--- a/src/main/kotlin/net/zekromaster/minecraft/ironchests/util.kt
+++ b/src/main/kotlin/net/zekromaster/minecraft/ironchests/util.kt
@@ -1,5 +1,9 @@
package net.zekromaster.minecraft.ironchests
+import net.minecraft.entity.player.PlayerEntity
+import net.modificationstation.stationapi.api.util.math.Direction
+import kotlin.math.floor
+
data class IronChestGrid(val rows: Int, val columns: Int) {
val size = rows * columns
}
@@ -22,4 +26,15 @@ enum class IronChestMaterial(val id: String, val grid: IronChestGrid) {
}
}
-}
\ No newline at end of file
+}
+
+fun PlayerEntity.placementFacing(): Direction {
+ val direction = floor((this.yaw * 4.0f / 360.0f).toDouble() + 0.5).toInt() and 3
+ return when (direction) {
+ 0 -> Direction.NORTH
+ 1 -> Direction.EAST
+ 2 -> Direction.SOUTH
+ 3 -> Direction.WEST
+ else -> Direction.NORTH
+ }
+}
diff --git a/src/main/resources/assets/ironchests/stationapi/lang/en_US.lang b/src/main/resources/assets/ironchests/stationapi/lang/en_US.lang
index c4fe27c..d5df130 100644
--- a/src/main/resources/assets/ironchests/stationapi/lang/en_US.lang
+++ b/src/main/resources/assets/ironchests/stationapi/lang/en_US.lang
@@ -1,3 +1,7 @@
tile.@.iron_chest.name=Iron Chest
tile.@.gold_chest.name=Gold Chest
-tile.@.diamond_chest.name=Diamond Chest
\ No newline at end of file
+tile.@.diamond_chest.name=Diamond Chest
+
+item.@.upgrades/wood_to_iron.name=Wood to Iron Upgrade
+item.@.upgrades/iron_to_gold.name=Iron to Gold Upgrade
+item.@.upgrades/gold_to_diamond.name=Gold to Diamond Upgrade
\ No newline at end of file
diff --git a/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/gold_to_diamond.json b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/gold_to_diamond.json
new file mode 100644
index 0000000..63bc5a9
--- /dev/null
+++ b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/gold_to_diamond.json
@@ -0,0 +1,6 @@
+{
+ "parent": "item/generated",
+ "textures": {
+ "layer0": "ironchests:item/upgrades/gold_to_diamond"
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/iron_to_gold.json b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/iron_to_gold.json
new file mode 100644
index 0000000..8923928
--- /dev/null
+++ b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/iron_to_gold.json
@@ -0,0 +1,6 @@
+{
+ "parent": "item/generated",
+ "textures": {
+ "layer0": "ironchests:item/upgrades/iron_to_gold"
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/wood_to_iron.json b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/wood_to_iron.json
new file mode 100644
index 0000000..410911c
--- /dev/null
+++ b/src/main/resources/assets/ironchests/stationapi/models/item/upgrades/wood_to_iron.json
@@ -0,0 +1,6 @@
+{
+ "parent": "item/generated",
+ "textures": {
+ "layer0": "ironchests:item/upgrades/wood_to_iron"
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/gold_to_diamond.png b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/gold_to_diamond.png
new file mode 100644
index 0000000..219a27f
Binary files /dev/null and b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/gold_to_diamond.png differ
diff --git a/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/iron_to_gold.png b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/iron_to_gold.png
new file mode 100644
index 0000000..b150a65
Binary files /dev/null and b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/iron_to_gold.png differ
diff --git a/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/wood_to_iron.png b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/wood_to_iron.png
new file mode 100644
index 0000000..2ea329a
Binary files /dev/null and b/src/main/resources/assets/ironchests/stationapi/textures/item/upgrades/wood_to_iron.png differ
diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json
index 9ff0228..417bb9c 100644
--- a/src/main/resources/fabric.mod.json
+++ b/src/main/resources/fabric.mod.json
@@ -22,7 +22,11 @@
},
{
"adapter": "kotlin",
- "value": "net.zekromaster.minecraft.ironchests.IronChests"
+ "value": "net.zekromaster.minecraft.ironchests.IronChestsBlockEntrypoint"
+ },
+ {
+ "adapter": "kotlin",
+ "value": "net.zekromaster.minecraft.ironchests.IronChestsUpgradesEntrypoint"
}
],
"stationapi:event_bus_client": [],
diff --git a/src/main/resources/ironchests.mixins.json b/src/main/resources/ironchests.mixins.json
index b50abba..22b2e77 100644
--- a/src/main/resources/ironchests.mixins.json
+++ b/src/main/resources/ironchests.mixins.json
@@ -4,7 +4,8 @@
"package": "net.zekromaster.minecraft.ironchests.mixin",
"compatibilityLevel": "JAVA_17",
"mixins": [
- "ChestInventoryAccessor"
+ "ChestInventoryAccessor",
+ "ChestMixin"
],
"server": [],
"client": [],