container: simple action

This commit is contained in:
Bixilon 2022-02-23 20:55:39 +01:00
parent a5f8e2cddc
commit 21a3769c3c
No known key found for this signature in database
GPG Key ID: 5CAD791931B09AC4
7 changed files with 124 additions and 35 deletions

View File

@ -14,6 +14,8 @@
package de.bixilon.minosoft.data.inventory.click
@Deprecated("ToDo")
class FastMoveContainerAction : ContainerAction {
class FastMoveContainerAction(
val slot: Int,
) : ContainerAction {
private val mode: Int get() = 1
}

View File

@ -13,19 +13,77 @@
package de.bixilon.minosoft.data.inventory.click
@Deprecated("ToDo")
import de.bixilon.minosoft.data.inventory.stack.ItemStack
import de.bixilon.minosoft.data.registries.other.containers.Container
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.c2s.play.container.ContainerClickC2SP
class SimpleContainerAction(
val slot: Int,
val action: SimpleContainerActions,
val slot: Int?,
val count: ContainerCounts,
) : ContainerAction {
private val mode: Int get() = 0
private val button: Int
get() = action.ordinal
get() = count.ordinal
private fun pickItem(connection: PlayConnection, containerId: Int, container: Container) {
val item = container[slot ?: return] ?: return
// ToDo: Check course of binding
val previous = item.copy()
val floatingItem: ItemStack
if (count == ContainerCounts.ALL) {
container.remove(slot)
floatingItem = item
} else {
// half
val stayCount = maxOf(item.item.count / 2, 1)
item.item.count = stayCount
floatingItem = previous.copy(count = previous.item.count - stayCount)
}
container.floatingItem = floatingItem
connection.sendPacket(ContainerClickC2SP(containerId, container.serverRevision, slot, 0, count.ordinal, container.createAction(this), mapOf(slot to item), previous))
}
enum class SimpleContainerActions {
LEFT_MOUSE_CLICK,
RIGHT_MOUSE_CLICK,
private fun putItem(connection: PlayConnection, containerId: Int, container: Container, floatingItem: ItemStack) {
floatingItem.lock()
val target = container.slots[slot]
try {
if (count == ContainerCounts.ALL) {
floatingItem.item._count = 0
} else {
floatingItem.item._count-- // don't use decrease, item + container is already locked
}
if (slot == null || target == null) {
return connection.sendPacket(ContainerClickC2SP(containerId, container.serverRevision, null, 0, count.ordinal, container.createAction(this), mapOf(), null))
}
if (target.typeEquals(floatingItem)) {
// merge
val subtract = minOf(target.item.item.maxStackSize - target.item._count, floatingItem.item._count)
target.item._count += subtract
floatingItem.item._count -= subtract
if (!floatingItem._valid) {
container.floatingItem = null
}
return
}
// swap
container.floatingItem = target
container.slots[slot] = floatingItem
} finally {
floatingItem.commit()
target?.lock() // lock to prevent exception
target?.commit()
}
}
override fun invoke(connection: PlayConnection, containerId: Int, container: Container) {
val floatingItem = container.floatingItem ?: return pickItem(connection, containerId, container)
return putItem(connection, containerId, container, floatingItem)
}
enum class ContainerCounts {
ALL,
PART,
;
}
}

View File

@ -186,6 +186,10 @@ class ItemStack {
return Objects.hash(item, _display, _durability, _enchanting, _hide, _nbt)
}
private fun _equals(other: ItemStack): Boolean {
return _display == other._display && _durability == other._durability && _enchanting == other._enchanting && _hide == other._hide && _nbt == other._nbt
}
override fun equals(other: Any?): Boolean {
if (other !is ItemStack) {
return false
@ -193,7 +197,14 @@ class ItemStack {
if (other.hashCode() != this.hashCode()) {
return false
}
return item == other.item && _display == other._display && _durability == other._durability && _enchanting == other._enchanting && _hide == other._hide && _nbt == other._nbt
return item == other.item && _equals(other)
}
fun typeEquals(other: ItemStack?): Boolean {
if (other == null) {
return false
}
return item.item == other.item.item && _equals(other)
}
override fun toString(): String {

View File

@ -17,13 +17,15 @@ import de.bixilon.kutil.collections.CollectionUtil.synchronizedBiMapOf
import de.bixilon.kutil.collections.CollectionUtil.toSynchronizedMap
import de.bixilon.kutil.collections.map.bi.SynchronizedBiMap
import de.bixilon.kutil.concurrent.lock.SimpleLock
import de.bixilon.kutil.watcher.DataWatcher.Companion.observe
import de.bixilon.kutil.watcher.DataWatcher.Companion.watched
import de.bixilon.kutil.watcher.map.MapDataWatcher
import de.bixilon.kutil.watcher.map.MapDataWatcher.Companion.watchedMap
import de.bixilon.minosoft.data.inventory.click.ContainerAction
import de.bixilon.minosoft.data.inventory.stack.ItemStack
import de.bixilon.minosoft.data.inventory.stack.property.HolderProperty
import de.bixilon.minosoft.data.text.ChatComponent
import de.bixilon.minosoft.protocol.network.connection.play.PlayConnection
import de.bixilon.minosoft.protocol.packets.c2s.play.container.CloseContainerC2SP
open class Container(
protected val connection: PlayConnection,
@ -32,7 +34,7 @@ open class Container(
val hasTitle: Boolean = false,
) : Iterable<Map.Entry<Int, ItemStack>> {
@Deprecated("Should not be accessed dirctly")
val slots: MutableMap<Int, ItemStack> by MapDataWatcher.watchedMap(mutableMapOf())
val slots: MutableMap<Int, ItemStack> by watchedMap(mutableMapOf())
val lock = SimpleLock()
var revision by watched(0L)
var serverRevision = 0
@ -40,6 +42,10 @@ open class Container(
var actions: SynchronizedBiMap<Int, ContainerAction> = synchronizedBiMapOf()
var floatingItem: ItemStack? by watched(null)
init {
this::floatingItem.observe(this) { it?.holder?.container = this }
}
fun _validate() {
var itemsRemoved = 0
for ((slot, itemStack) in slots.toSynchronizedMap()) {
@ -175,6 +181,13 @@ open class Container(
actions.remove(actionId)?.revert(connection, connection.player.containers.getKey(this) ?: return, this)
}
fun onClose() {
floatingItem = null // ToDo: Does not seem correct
// minecraft behavior, when opening the inventory an open packet is never sent, but a close is
connection.sendPacket(CloseContainerC2SP(connection.player.containers.getKey(this) ?: return))
}
override fun iterator(): Iterator<Map.Entry<Int, ItemStack>> {
return slots.toSynchronizedMap().iterator()
}

View File

@ -14,6 +14,10 @@
package de.bixilon.minosoft.gui.rendering.gui.elements.items
import de.bixilon.kutil.watcher.map.MapDataWatcher.Companion.observeMap
import de.bixilon.minosoft.data.abilities.Gamemodes
import de.bixilon.minosoft.data.inventory.click.CloneContainerAction
import de.bixilon.minosoft.data.inventory.click.FastMoveContainerAction
import de.bixilon.minosoft.data.inventory.click.SimpleContainerAction
import de.bixilon.minosoft.data.registries.other.containers.Container
import de.bixilon.minosoft.gui.rendering.gui.GUIRenderer
import de.bixilon.minosoft.gui.rendering.gui.atlas.Vec2iBinding
@ -21,6 +25,7 @@ import de.bixilon.minosoft.gui.rendering.gui.elements.Element
import de.bixilon.minosoft.gui.rendering.gui.gui.AbstractLayout
import de.bixilon.minosoft.gui.rendering.gui.gui.dragged.Dragged
import de.bixilon.minosoft.gui.rendering.gui.gui.dragged.elements.item.FloatingItem
import de.bixilon.minosoft.gui.rendering.gui.input.ModifierKeys
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseActions
import de.bixilon.minosoft.gui.rendering.gui.input.mouse.MouseButtons
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
@ -28,6 +33,7 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.EMPTY
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
import de.bixilon.minosoft.util.delegate.RenderingDelegate.observeRendering
import glm_.vec2.Vec2i
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
@ -73,6 +79,11 @@ class ContainerItemsElement(
this._size = size
container::slots.observeMap(this) { update = true; }
container::floatingItem.observeRendering(this) {
this.floatingItem?.close()
this.floatingItem = null
this.floatingItem = FloatingItem(guiRenderer, it ?: return@observeRendering).apply { show() }
}
}
override fun forceRender(offset: Vec2i, consumer: GUIVertexConsumer, options: GUIVertexOptions?) {
@ -119,32 +130,29 @@ class ContainerItemsElement(
}
override fun onMouseAction(position: Vec2i, button: MouseButtons, action: MouseActions): Boolean {
// this is not in items element, because you can also click into "nothing"
val consumed = super<AbstractLayout>.onMouseAction(position, button, action)
if (action != MouseActions.PRESS || (button != MouseButtons.LEFT && button != MouseButtons.RIGHT)) {
if (action != MouseActions.PRESS) {
return consumed
}
val shiftDown = guiRenderer.isKeyDown(ModifierKeys.SHIFT)
val activeElement = activeElement
val stack = activeElement?.stack
val containerId = renderWindow.connection.player.containers.getKey(container) ?: return consumed
var floatingItem = this.floatingItem
if ((floatingItem != null && floatingItem.visible) || stack?._valid != true) {
return consumed
if (button == MouseButtons.MIDDLE) {
if (guiRenderer.connection.player.gamemode != Gamemodes.CREATIVE) {
return true
}
container.invokeAction(CloneContainerAction(activeElement?.slotId ?: return true))
return true
}
if (button == MouseButtons.LEFT || button == MouseButtons.RIGHT) {
container.invokeAction(if (shiftDown) {
FastMoveContainerAction(activeElement?.slotId ?: return true)
} else {
SimpleContainerAction(activeElement?.slotId, if (button == MouseButtons.LEFT) SimpleContainerAction.ContainerCounts.ALL else SimpleContainerAction.ContainerCounts.PART)
})
return true
}
// val clickAction: ContainerClickActions
// val stackToFloat: ItemStack
// if (button == MouseButtons.LEFT) {
// stackToFloat = stack
// clickAction = ContainerClickActions.LEFT_MOUSE_CLICK
// } else {
// stackToFloat = stack.copy(count = maxOf(stack.item.count / 2, 1))
// clickAction = ContainerClickActions.RIGHT_MOUSE_CLICK
// stack.item.count = stack.item.count - stackToFloat.item.count
// }
// renderWindow.connection.sendPacket(ContainerClickC2SP(containerId, container.serverRevision, activeElement.slotId, clickAction, container.createAction(), mapOf(activeElement.slotId to stack), stack))
// floatingItem = FloatingItem(guiRenderer, activeElement.slotId, stackToFloat)
// this.floatingItem = floatingItem
// floatingItem.show()
return true
}

View File

@ -23,7 +23,6 @@ import glm_.vec2.Vec2i
class FloatingItem(
guiRenderer: GUIRenderer,
val sourceId: Int,
val stack: ItemStack,
size: Vec2i = RawItemElement.DEFAULT_SIZE,
) : Dragged(guiRenderer) {

View File

@ -26,7 +26,6 @@ import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexConsumer
import de.bixilon.minosoft.gui.rendering.gui.mesh.GUIVertexOptions
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isGreater
import de.bixilon.minosoft.gui.rendering.util.vec.vec2.Vec2iUtil.isSmaller
import de.bixilon.minosoft.protocol.packets.c2s.play.container.CloseContainerC2SP
import glm_.vec2.Vec2i
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
@ -70,7 +69,6 @@ abstract class ContainerScreen(
override fun onClose() {
super.onClose()
// minecraft behavior, when opening the inventory an open packet is never sent, but a close is
renderWindow.connection.sendPacket(CloseContainerC2SP(renderWindow.connection.player.containers.getKey(container) ?: return))
container.onClose()
}
}