Skip to content
Open
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
14 changes: 14 additions & 0 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -1583,6 +1583,7 @@ func (p *Player) UseItem() {
func (p *Player) ReleaseItem() {
if !p.usingItem || !p.canRelease() || !p.GameMode().AllowsInteraction() {
p.usingItem = false
p.resyncInventory()
return
}
p.usingItem = false
Expand All @@ -1591,13 +1592,26 @@ func (p *Player) ReleaseItem() {
i, _ := p.HeldItems()
ctx := event.C(p)
if p.Handler().HandleItemRelease(ctx, i, dur); ctx.Cancelled() {
p.resyncInventory()
return
}
i.Item().(item.Releasable).Release(p, p.tx, useCtx, dur)
p.handleUseContext(useCtx)
if len(useCtx.ConsumedItems) == 0 {
// Nothing was consumed, so revert the item the client predicted the release would use.
p.resyncInventory()
}
p.updateState()
}

// resyncInventory resends the inventory to revert a release the client predicted but the server did not
// carry out. A consumed item already updates the client through its inventory slot change.
func (p *Player) resyncInventory() {
if s := p.session(); s != session.Nop {
s.ResyncInventory()
}
}

// canRelease returns whether the player can release the item currently held in the main hand.
func (p *Player) canRelease() bool {
held, left := p.HeldItems()
Expand Down
7 changes: 7 additions & 0 deletions server/session/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,13 @@ func (s *Session) sendArmourTrimData() {
s.writePacket(&packet.TrimData{Patterns: trimPatterns, Materials: trimMaterials})
}

// ResyncInventory resends the main and off-hand inventories to the client. It reverts a client-side
// prediction the server did not carry out, such as an arrow a released bow did not consume.
func (s *Session) ResyncInventory() {
s.sendInv(s.inv, protocol.WindowIDInventory)
s.sendInv(s.offHand, protocol.WindowIDOffHand)
}

// sendInv sends the inventory passed to the client with the window ID.
func (s *Session) sendInv(inv *inventory.Inventory, windowID uint32) {
pk := &packet.InventoryContent{
Expand Down