Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@ org.jetbrains.dokka.experimental.gradle.pluginMode=V2Enabled
javaVersion=25
mcVersion=1.21.11
group=dev.slne.surf
version=1.21.11-2.71.0
version=1.21.11-2.71.1
relocationPrefix=dev.slne.surf.surfapi.libs
snapshot=false
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
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.
} else {
event.stateId()
}

if (brokenStateId == event.stateId()) return event

return ServerboundContainerClickPacket(
event.containerId(),
brokenStateId,
Comment on lines +134 to +145
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.
event.slotNum(),
event.buttonNum(),
event.clickType(),
event.changedSlots(),
event.carriedItem()
)
Comment on lines +132 to +151
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.
}

@ClientboundListener
fun onSetCursorItemPacket(event: ClientboundSetCursorItemPacket): ClientboundSetCursorItemPacket {
val original = event.contents
Expand Down
Loading