diff --git a/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivity.kt b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivity.kt index 889b255..54e1321 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivity.kt @@ -1,9 +1,17 @@ package net.shadowfacts.phycon import net.fabricmc.api.ModInitializer +import net.fabricmc.fabric.api.container.ContainerFactory +import net.fabricmc.fabric.api.container.ContainerProviderRegistry +import net.minecraft.container.Container +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.util.Identifier +import net.minecraft.util.PacketByteBuf import net.shadowfacts.phycon.init.PhyBlockEntities import net.shadowfacts.phycon.init.PhyBlocks import net.shadowfacts.phycon.init.PhyItems +import net.shadowfacts.phycon.network.block.terminal.TerminalBlock +import net.shadowfacts.phycon.network.block.terminal.TerminalContainer /** * @author shadowfacts @@ -16,5 +24,13 @@ object PhysicalConnectivity: ModInitializer { PhyBlocks.init() PhyBlockEntities.init() PhyItems.init() + ContainerProviderRegistry.INSTANCE.registerFactory(TerminalContainer.ID, ContainerFactory(::createTerminalContainer)) } -} \ No newline at end of file + + private fun createTerminalContainer(syncId: Int, identifier: Identifier, player: PlayerEntity, buf: PacketByteBuf): Container { + val pos = buf.readBlockPos() + val terminalEntity = PhyBlocks.TERMINAL.getBlockEntity(player.world, pos)!! + return TerminalContainer(syncId, player.inventory, terminalEntity) + } + +} diff --git a/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt new file mode 100644 index 0000000..60b1fc4 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/PhysicalConnectivityClient.kt @@ -0,0 +1,22 @@ +package net.shadowfacts.phycon + +import net.fabricmc.api.ClientModInitializer +import net.fabricmc.fabric.api.client.screen.ContainerScreenFactory +import net.fabricmc.fabric.api.client.screen.ScreenProviderRegistry +import net.minecraft.client.MinecraftClient +import net.minecraft.util.Identifier +import net.shadowfacts.phycon.network.block.terminal.TerminalContainer +import net.shadowfacts.phycon.network.block.terminal.TerminalScreen + +/** + * @author shadowfacts + */ +object PhysicalConnectivityClient: ClientModInitializer { + override fun onInitializeClient() { + ScreenProviderRegistry.INSTANCE.registerFactory(TerminalContainer.ID, ContainerScreenFactory(::createTerminalScreen)) + } + + fun createTerminalScreen(container: TerminalContainer): TerminalScreen { + return TerminalScreen(container, MinecraftClient.getInstance().player.inventory) + } +} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt index 8a068d7..6658866 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlock.kt @@ -31,8 +31,8 @@ class TerminalBlock: BlockWithEntity(Settings.of(Material.M override fun createBlockEntity(world: BlockView) = TerminalBlockEntity() - override fun activate(blockState_1: BlockState?, world_1: World?, blockPos_1: BlockPos?, playerEntity_1: PlayerEntity?, hand_1: Hand?, blockHitResult_1: BlockHitResult?): Boolean { - getBlockEntity(world_1!!, blockPos_1!!)!!.onActivate() + override fun activate(state: BlockState, world: World, pos: BlockPos, player: PlayerEntity, hand: Hand, hitResult: BlockHitResult): Boolean { + getBlockEntity(world, pos)!!.onActivate(player) return true } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt index 03f3197..3307e8e 100644 --- a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalBlockEntity.kt @@ -2,7 +2,13 @@ package net.shadowfacts.phycon.network.block.terminal import alexiil.mc.lib.attributes.item.GroupedItemInv import alexiil.mc.lib.attributes.item.ItemStackCollections +import net.fabricmc.fabric.api.container.ContainerProviderRegistry +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.inventory.BasicInventory +import net.minecraft.inventory.Inventory +import net.minecraft.inventory.InventoryListener import net.minecraft.item.ItemStack +import net.minecraft.nbt.CompoundTag import net.shadowfacts.phycon.api.packet.Packet import net.shadowfacts.phycon.api.util.MACAddress import net.shadowfacts.phycon.init.PhyBlockEntities @@ -10,13 +16,20 @@ import net.shadowfacts.phycon.network.DeviceBlockEntity import net.shadowfacts.phycon.network.packet.DeviceRemovedPacket import net.shadowfacts.phycon.network.packet.ReadInventoryPacket import net.shadowfacts.phycon.network.packet.RequestInventoryPacket +import net.shadowfacts.phycon.util.fromTag +import net.shadowfacts.phycon.util.toTag /** * @author shadowfacts */ -class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) { +class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL), InventoryListener { private val inventoryCache = mutableMapOf() + val internalBuffer = BasicInventory(18) + + init { + internalBuffer.addListener(this) + } override fun handlePacket(packet: Packet) { when (packet) { @@ -46,11 +59,30 @@ class TerminalBlockEntity: DeviceBlockEntity(PhyBlockEntities.TERMINAL) { return net } - fun onActivate() { + fun onActivate(player: PlayerEntity) { if (!world!!.isClient) { inventoryCache.clear() enqueueToSingle(RequestInventoryPacket(macAddress)) + ContainerProviderRegistry.INSTANCE.openContainer(TerminalContainer.ID, player) { buf -> + buf.writeBlockPos(pos) + } } } + override fun onInvChange(inv: Inventory) { + if (inv == internalBuffer) { + markDirty() + } + } + + override fun toTag(tag: CompoundTag): CompoundTag { + tag.put("InternalBuffer", internalBuffer.toTag()) + return super.toTag(tag) + } + + override fun fromTag(tag: CompoundTag) { + super.fromTag(tag) + internalBuffer.fromTag(tag.getList("InternalBuffer", 10)) + } + } diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalContainer.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalContainer.kt new file mode 100644 index 0000000..9483196 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalContainer.kt @@ -0,0 +1,42 @@ +package net.shadowfacts.phycon.network.block.terminal + +import net.minecraft.container.Container +import net.minecraft.container.Slot +import net.minecraft.entity.player.PlayerEntity +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.util.Identifier +import net.shadowfacts.phycon.PhysicalConnectivity + +/** + * @author shadowfacts + */ +class TerminalContainer(syncId: Int, playerInv: PlayerInventory, val terminal: TerminalBlockEntity): Container(null, syncId) { + + companion object { + val ID = Identifier(PhysicalConnectivity.MODID, "terminal") + } + + init { + // internal buffer + for (y in 0 until 6) { + for (x in 0 until 3) { + addSlot(Slot(terminal.internalBuffer, y * 3 + x, 8 + x * 18, 18 + y * 18)) + } + } + + // player inv + for (y in 0 until 3) { + for (x in 0 until 9) { + addSlot(Slot(playerInv, x + y * 9 + 9, 66 + x * 18, 140 + y * 18)) + } + } + // hotbar + for (x in 0 until 9) { + addSlot(Slot(playerInv, x, 66 + x * 18, 198)) + } + } + + override fun canUse(player: PlayerEntity): Boolean { + return true + } +} diff --git a/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt new file mode 100644 index 0000000..23c6386 --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/network/block/terminal/TerminalScreen.kt @@ -0,0 +1,40 @@ +package net.shadowfacts.phycon.network.block.terminal + +import com.mojang.blaze3d.platform.GlStateManager +import net.minecraft.client.gui.screen.ingame.AbstractContainerScreen +import net.minecraft.entity.player.PlayerInventory +import net.minecraft.text.LiteralText +import net.minecraft.util.Identifier +import net.shadowfacts.phycon.PhysicalConnectivity + +/** + * @author shadowfacts + */ +// todo: translate title +class TerminalScreen(container: TerminalContainer, playerInv: PlayerInventory): AbstractContainerScreen(container, playerInv, LiteralText("Terminal")) { + companion object { + val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") + } + + init { + containerWidth = 252 + containerHeight = 222 + } + + override fun drawForeground(mouseX: Int, mouseY: Int) { + font.draw(title.asFormattedString(), 65f, 6f, 0x404040) + font.draw(playerInventory.displayName.asFormattedString(), 65f, containerHeight - 94f, 0x404040) + // todo: translate this + font.draw("Buffer", 7f, 6f, 0x404040) + } + + override fun drawBackground(delta: Float, mouseX: Int, mouseY: Int) { + GlStateManager.color4f(1f, 1f, 1f, 1f) + minecraft!!.textureManager.bindTexture(BACKGROUND) + val x = (width - containerWidth) / 2 + val y = (height - containerHeight) / 2 + blit(x, y, 0, 0, containerWidth, containerHeight) + + } + +} diff --git a/src/main/kotlin/net/shadowfacts/phycon/util/nbt.kt b/src/main/kotlin/net/shadowfacts/phycon/util/nbt.kt new file mode 100644 index 0000000..47a6d3e --- /dev/null +++ b/src/main/kotlin/net/shadowfacts/phycon/util/nbt.kt @@ -0,0 +1,34 @@ +package net.shadowfacts.phycon.util + +import net.minecraft.inventory.BasicInventory +import net.minecraft.item.ItemStack +import net.minecraft.nbt.CompoundTag +import net.minecraft.nbt.ListTag +import java.lang.RuntimeException + +/** + * @author shadowfacts + */ +fun BasicInventory.toTag(): ListTag { + val list = ListTag() + for (slot in 0 until invSize) { + val stack = getInvStack(slot) + if (!stack.isEmpty) { + val stackTag = stack.toTag(CompoundTag()) + stackTag.putInt("Slot", slot) + list.add(stackTag) + } + } + return list +} + +fun BasicInventory.fromTag(list: ListTag) { + if (list.listType != 10) throw RuntimeException("Can't decode BasicInventory from list tag that does not contain compound tags") + this.clear() + for (tag in list) { + val compound = tag as CompoundTag + val stack = ItemStack.fromTag(compound) + val slot = compound.getInt("Slot") + setInvStack(slot, stack) + } +} diff --git a/src/main/resources/assets/phycon/textures/gui/terminal.png b/src/main/resources/assets/phycon/textures/gui/terminal.png new file mode 100644 index 0000000..7fd4d13 Binary files /dev/null and b/src/main/resources/assets/phycon/textures/gui/terminal.png differ diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index bcde358..793fb9d 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -19,6 +19,12 @@ "adapter": "kotlin", "value": "net.shadowfacts.phycon.PhysicalConnectivity" } + ], + "client": [ + { + "adapter": "kotlin", + "value": "net.shadowfacts.phycon.PhysicalConnectivityClient" + } ] }, "mixins": [ @@ -29,4 +35,4 @@ "fabric": "*", "fabric-language-kotlin": ">=1.3.50" } -} \ No newline at end of file +}