-
Notifications
You must be signed in to change notification settings - Fork 0
Fix state ID issues by handling container click packets #266
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -15,6 +15,7 @@ import it.unimi.dsi.fastutil.objects.ObjectLists | |||||||||||||||||||||||||||||||||||||||||||||
| import net.kyori.adventure.text.format.TextDecoration | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.core.component.DataComponents | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.network.protocol.game.* | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.server.level.ServerPlayer | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.world.item.ItemStack | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.world.item.component.CustomData | ||||||||||||||||||||||||||||||||||||||||||||||
| import net.minecraft.world.item.component.ItemLore | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -121,6 +122,35 @@ object PacketLoreListener : PacketListener { | |||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| @ServerboundListener | ||||||||||||||||||||||||||||||||||||||||||||||
| fun onContainerClickPacket( | ||||||||||||||||||||||||||||||||||||||||||||||
| event: ServerboundContainerClickPacket, | ||||||||||||||||||||||||||||||||||||||||||||||
| player: ServerPlayer | ||||||||||||||||||||||||||||||||||||||||||||||
| ): ServerboundContainerClickPacket { | ||||||||||||||||||||||||||||||||||||||||||||||
| if (!hasAnyHandlers()) return event | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| val container = player.containerMenu | ||||||||||||||||||||||||||||||||||||||||||||||
| val currentStateId = container.stateId | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| val brokenStateId = if (event.stateId() == currentStateId) { | ||||||||||||||||||||||||||||||||||||||||||||||
| currentStateId - 1 | ||||||||||||||||||||||||||||||||||||||||||||||
| } else { | ||||||||||||||||||||||||||||||||||||||||||||||
| event.stateId() | ||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| if (brokenStateId == event.stateId()) return event | ||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||
| return ServerboundContainerClickPacket( | ||||||||||||||||||||||||||||||||||||||||||||||
| event.containerId(), | ||||||||||||||||||||||||||||||||||||||||||||||
| brokenStateId, | ||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+134
to
+145
|
||||||||||||||||||||||||||||||||||||||||||||||
| val brokenStateId = if (event.stateId() == currentStateId) { | |
| currentStateId - 1 | |
| } else { | |
| event.stateId() | |
| } | |
| if (brokenStateId == event.stateId()) return event | |
| return ServerboundContainerClickPacket( | |
| event.containerId(), | |
| brokenStateId, | |
| val eventStateId = event.stateId() | |
| // If the packet already matches the current container state, leave it unchanged. | |
| if (eventStateId == currentStateId) return event | |
| // Otherwise, rewrite the packet to align its stateId with the current container state. | |
| return ServerboundContainerClickPacket( | |
| event.containerId(), | |
| currentStateId, |
Copilot
AI
Mar 28, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This listener is invoked from the Netty channel pipeline (see PlayerChannelInjector.PacketHandler.channelRead), before Minecraft’s packet handling is rescheduled onto the main thread. Accessing player.containerMenu/stateId here can be racy/non-thread-safe and may read stale state; consider moving this logic to a main-thread interception point or avoiding direct reads of mutable player/menu state in a Netty-thread packet listener.
| val container = player.containerMenu | |
| val currentStateId = container.stateId | |
| val brokenStateId = if (event.stateId() == currentStateId) { | |
| currentStateId - 1 | |
| } else { | |
| event.stateId() | |
| } | |
| if (brokenStateId == event.stateId()) return event | |
| return ServerboundContainerClickPacket( | |
| event.containerId(), | |
| brokenStateId, | |
| event.slotNum(), | |
| event.buttonNum(), | |
| event.clickType(), | |
| event.changedSlots(), | |
| event.carriedItem() | |
| ) | |
| // Avoid accessing player.containerMenu/stateId from the Netty thread; just pass the packet through. | |
| return event |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
currentStateId - 1can produce-1whencontainer.stateIdis0(which is a valid initial value for menus). Sending a negative stateId may be outside the protocol’s expected range and can lead to unexpected server behavior; consider clamping/wrapping or avoiding decrement entirely.