Skip to content

Fix state ID issues by handling container click packets#266

Merged
twisti-dev merged 2 commits intoversion/1.21.11from
fix/packet-lore
Mar 28, 2026
Merged

Fix state ID issues by handling container click packets#266
twisti-dev merged 2 commits intoversion/1.21.11from
fix/packet-lore

Conversation

@twisti-dev
Copy link
Copy Markdown
Contributor

This pull request introduces a minor version bump and adds a new packet handler to the PacketLoreListener in the Bukkit server module. The main focus is on improving how container click packets are processed, likely to address an issue with state IDs.

Version bump:

  • Updated the project version in gradle.properties from 1.21.11-2.71.0 to 1.21.11-2.71.1.

Packet handling improvements:

  • Added a new onContainerClickPacket method to PacketLoreListener that intercepts ServerboundContainerClickPacket packets, checks for mismatched container state IDs, and adjusts the state ID if necessary to prevent issues.
  • Imported ServerPlayer to support the new packet handler logic.

@twisti-dev twisti-dev self-assigned this Mar 28, 2026
Copilot AI review requested due to automatic review settings March 28, 2026 12:15
@twisti-dev twisti-dev merged commit e34d079 into version/1.21.11 Mar 28, 2026
6 checks passed
@twisti-dev twisti-dev deleted the fix/packet-lore branch March 28, 2026 12:16
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR bumps the library version and extends the Bukkit server PacketLoreListener with a new serverbound container-click packet handler intended to mitigate container stateId desync issues during lore packet modifications.

Changes:

  • Bumped project version from 1.21.11-2.71.0 to 1.21.11-2.71.1.
  • Added a @ServerboundListener for ServerboundContainerClickPacket that rewrites the packet’s stateId based on the player’s current container state.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
surf-api-bukkit/surf-api-bukkit-server/src/main/kotlin/dev/slne/surf/surfapi/bukkit/server/packet/lore/PacketLoreListener.kt Adds serverbound container-click interception and stateId rewriting logic.
gradle.properties Version bump to 1.21.11-2.71.1.

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,
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stateId adjustment logic appears inverted: it modifies the packet when event.stateId() already matches player.containerMenu.stateId, which guarantees the resulting packet will now mismatch the current menu stateId. If the goal is to fix desyncs, this should instead detect a mismatch and rewrite the packet’s stateId to the current menu stateId (or otherwise align it), not decrement when it matches.

Suggested change
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 uses AI. Check for mistakes.
val currentStateId = container.stateId

val brokenStateId = if (event.stateId() == currentStateId) {
currentStateId - 1
Copy link

Copilot AI Mar 28, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currentStateId - 1 can produce -1 when container.stateId is 0 (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.

Suggested change
currentStateId - 1
(currentStateId - 1).coerceAtLeast(0)

Copilot uses AI. Check for mistakes.
Comment on lines +132 to +151
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()
)
Copy link

Copilot AI Mar 28, 2026

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants