From 7e6fc7c9339df0810c69198d6f6b8753fc0d39fd Mon Sep 17 00:00:00 2001 From: Bixilon Date: Sat, 23 Oct 2021 15:48:36 +0200 Subject: [PATCH] container revision fixes, item rendering: render material color quad --- .../minosoft/data/inventory/ItemStack.kt | 41 ++++++++++++++++++- .../registries/other/containers/Container.kt | 29 ++++++++++--- .../elements/items/ContainerItemsElement.kt | 12 ++++-- .../gui/elements/items/ItemElement.kt | 17 ++++++-- .../hud/elements/hotbar/HotbarBaseElement.kt | 6 +-- .../gui/rendering/input/camera/Camera.kt | 15 +++++-- .../packets/s2c/play/ContainerItemSetS2CP.kt | 3 +- 7 files changed, 101 insertions(+), 22 deletions(-) diff --git a/src/main/java/de/bixilon/minosoft/data/inventory/ItemStack.kt b/src/main/java/de/bixilon/minosoft/data/inventory/ItemStack.kt index a8c64d0fc..d3d204b2c 100644 --- a/src/main/java/de/bixilon/minosoft/data/inventory/ItemStack.kt +++ b/src/main/java/de/bixilon/minosoft/data/inventory/ItemStack.kt @@ -42,6 +42,7 @@ import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import de.bixilon.minosoft.util.nbt.tag.NBTUtil.compoundCast import de.bixilon.minosoft.util.nbt.tag.NBTUtil.getAndRemove import de.bixilon.minosoft.util.nbt.tag.NBTUtil.listCast +import java.util.* class ItemStack( val item: Item, @@ -54,7 +55,7 @@ class ItemStack( unbreakable: Boolean = false, durability: Int = 0, val nbt: MutableMap = synchronizedMapOf(), - val container: Container? = null, + container: Container? = null, hideFlags: Int = 0, ) : TextFormattable { var count = count @@ -105,6 +106,17 @@ class ItemStack( field = value apply() } + var container = container + set(value) { + if (field != null && value != null) { + throw IllegalStateException("Item already in a different container!") + } + if (field === value) { + return + } + field = value + apply() + } // ToDo: Apply if enchantments, lore or nbt changes @@ -319,6 +331,33 @@ class ItemStack( val damageable: Boolean get() = item.maxDamage > 0 || !unbreakable + + override fun hashCode(): Int { + return Objects.hash(item, count, durability, nbt) + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + if (other !is ItemStack) { + return false + } + if (hashCode() != other.hashCode()) { + return false + } + return item == other.item + && count == other.count + && durability == other.durability + && enchantments == other.enchantments + && nbt == other.nbt + && lore == other.lore + && customDisplayName == other.customDisplayName + && repairCost == other.repairCost + && unbreakable == other.unbreakable + && hideFlags == other.hideFlags + } + companion object { private const val HIDE_ENCHANTMENT_BIT = 0 private const val HIDE_MODIFIERS_BIT = 1 diff --git a/src/main/java/de/bixilon/minosoft/data/registries/other/containers/Container.kt b/src/main/java/de/bixilon/minosoft/data/registries/other/containers/Container.kt index 61647cff8..702e231dc 100644 --- a/src/main/java/de/bixilon/minosoft/data/registries/other/containers/Container.kt +++ b/src/main/java/de/bixilon/minosoft/data/registries/other/containers/Container.kt @@ -41,6 +41,7 @@ open class Container( for ((slot, itemStack) in slots.toSynchronizedMap()) { if (itemStack.count <= 0 || itemStack.durability < 0) { slots.remove(slot) + itemStack.container = null changes = true } } @@ -53,13 +54,29 @@ open class Container( return slots[slotId] } - operator fun set(slotId: Int, itemStack: ItemStack?) { - if (itemStack == null) { - slots.remove(slotId) ?: return - } else { - slots[slotId] = itemStack // ToDo: Check for changes - } + fun remove(slotId: Int): ItemStack? { + val itemStack = slots.remove(slotId) ?: return null + itemStack.container = null revision++ + return itemStack + } + + /** + * @return The previous item + */ + operator fun set(slotId: Int, itemStack: ItemStack?): ItemStack? { + if (itemStack == null) { + return remove(slotId) + } + val previous = slots[slotId] + if (previous == itemStack) { + return previous + } + slots[slotId] = itemStack // ToDo: Check for changes + itemStack.container = this + + revision++ + return previous } fun clear() { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ContainerItemsElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ContainerItemsElement.kt index 2c4edbbbb..c6cd2dfb4 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ContainerItemsElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ContainerItemsElement.kt @@ -9,6 +9,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions import de.bixilon.minosoft.util.KUtil.synchronizedMapOf import de.bixilon.minosoft.util.KUtil.toSynchronizedMap import glm_.vec2.Vec2i +import java.lang.Integer.max class ContainerItemsElement( hudRenderer: HUDRenderer, @@ -24,17 +25,20 @@ class ContainerItemsElement( } override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int { + var maxZ = 0 for ((_, data) in itemElements.toSynchronizedMap()) { - data.element.render(offset + data.offset, z, consumer, options) + maxZ = max(maxZ, data.element.render(offset + data.offset, z, consumer, options)) } - return 2 + return maxZ } override fun silentApply(): Boolean { - if (this.revision == container.revision) { + val revision = container.revision + if (this.revision == revision) { return false } + this.revision = revision var changes = false for ((slot, binding) in slots) { @@ -56,7 +60,7 @@ class ContainerItemsElement( changes = true } else { if (data.element.item == item) { - if (data.element.poll()) { + if (data.element.silentApply()) { changes = true } } else { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ItemElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ItemElement.kt index 8cfcc8df1..225f5a872 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ItemElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/elements/items/ItemElement.kt @@ -1,6 +1,7 @@ package de.bixilon.minosoft.gui.rendering.gui.elements.items import de.bixilon.minosoft.data.inventory.ItemStack +import de.bixilon.minosoft.data.registries.items.block.BlockItem import de.bixilon.minosoft.data.text.ChatColors import de.bixilon.minosoft.data.text.TextComponent import de.bixilon.minosoft.gui.rendering.gui.elements.Element @@ -9,6 +10,7 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.HorizontalAlignments.Compa import de.bixilon.minosoft.gui.rendering.gui.elements.Pollable import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments import de.bixilon.minosoft.gui.rendering.gui.elements.VerticalAlignments.Companion.getOffset +import de.bixilon.minosoft.gui.rendering.gui.elements.primitive.ColorElement import de.bixilon.minosoft.gui.rendering.gui.elements.text.TextElement import de.bixilon.minosoft.gui.rendering.gui.hud.HUDRenderer import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer @@ -41,15 +43,22 @@ class ItemElement( } override fun forceRender(offset: Vec2i, z: Int, consumer: GUIVertexConsumer, options: GUIVertexOptions?): Int { - if (item == null) { - return 0 - } + val item = item ?: return 0 val size = size val countSize = countText.size countText.render(offset + Vec2i(HorizontalAlignments.RIGHT.getOffset(size.x, countSize.x), VerticalAlignments.BOTTOM.getOffset(size.y, countSize.y)), z + 1, consumer, options) + var color = ChatColors.WHITE + if (item.item is BlockItem) { + item.item.block?.defaultState?.material?.color?.let { color = it } + } + + val image = ColorElement(hudRenderer, _size, color) + + image.render(offset, z + 1, consumer, options) + // ToDo: Render model - return 2 + return TextElement.LAYERS + 1 } override fun poll(): Boolean { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt index 9bfde8406..47c699861 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/gui/hud/elements/hotbar/HotbarBaseElement.kt @@ -46,14 +46,14 @@ class HotbarBaseElement(hudRenderer: HUDRenderer) : Element(hudRenderer), Pollab base.render(offset + HORIZONTAL_MARGIN, z, consumer, options) baseAtlasElement.slots[selectedSlot + PlayerInventory.HOTBAR_OFFSET]?.let { - frame.render(offset + it.start - HORIZONTAL_MARGIN + FRAME_OFFSET, z + 2, consumer, options) + frame.render(offset + it.start - HORIZONTAL_MARGIN + FRAME_OFFSET, z + 1, consumer, options) } - inventoryElement.render(offset, z, consumer, options) + val inventoryZ = inventoryElement.render(offset, z + 2, consumer, options) // ToDo: Item rendering - return 2 // bar + frame + return 2 + inventoryZ// bar + frame } override fun poll(): Boolean { diff --git a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt index abd96a44b..e15ba458b 100644 --- a/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt +++ b/src/main/java/de/bixilon/minosoft/gui/rendering/input/camera/Camera.kt @@ -216,11 +216,20 @@ class Camera( connection.registerEvent(CallbackEventInvoker.of { recalculateViewProjectionMatrix() }) - fun dropItem(type: BlockBreakC2SP.BreakType) { + fun dropItem(stack: Boolean) { val time = System.currentTimeMillis() if (time - lastDropPacketSent < ProtocolDefinition.TICK_TIME) { return } + val type = if (stack) { + connection.player.inventory.getHotbarSlot()?.count = 0 + BlockBreakC2SP.BreakType.DROP_ITEM_STACK + } else { + connection.player.inventory.getHotbarSlot()?.let { + it.count-- + } + BlockBreakC2SP.BreakType.DROP_ITEM + } connection.sendPacket(BlockBreakC2SP(type, connection.player.positionInfo.blockPosition)) lastDropPacketSent = time } @@ -230,13 +239,13 @@ class Camera( mutableMapOf( KeyAction.PRESS to mutableSetOf(KeyCodes.KEY_Q), ), - )) { dropItem(BlockBreakC2SP.BreakType.DROP_ITEM) } + )) { dropItem(false) } renderWindow.inputHandler.registerKeyCallback(DROP_ITEM_STACK_KEYBINDING, KeyBinding( mutableMapOf( KeyAction.PRESS to mutableSetOf(KeyCodes.KEY_Q), KeyAction.MODIFIER to mutableSetOf(KeyCodes.KEY_LEFT_CONTROL) ), - )) { dropItem(BlockBreakC2SP.BreakType.DROP_ITEM_STACK) } + )) { dropItem(true) } frustum.recalculate() connection.fireEvent(FrustumChangeEvent(renderWindow, frustum)) } diff --git a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerItemSetS2CP.kt b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerItemSetS2CP.kt index 70a8f93ad..8261771f8 100644 --- a/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerItemSetS2CP.kt +++ b/src/main/java/de/bixilon/minosoft/protocol/packets/s2c/play/ContainerItemSetS2CP.kt @@ -34,10 +34,11 @@ class ContainerItemSetS2CP(buffer: PlayInByteBuffer) : PlayS2CPacket() { override fun handle(connection: PlayConnection) { connection.player.containers[containerId]?.set(slot, itemStack) + // ToDo: Check for changes connection.fireEvent(ContainerSlotChangeEvent(connection, this)) } override fun log() { - Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Container item set (containerId=$containerId, slot=$slot, itemStack=$itemStack)" } + Log.log(LogMessageType.NETWORK_PACKETS_IN, level = LogLevels.VERBOSE) { "Container item set (containerId=$containerId, revision=$revision, slot=$slot, itemStack=$itemStack)" } } }