Skip to content

Commit

Permalink
player/player.go: Added SetHeldSlot and held slot handler.
Browse files Browse the repository at this point in the history
  • Loading branch information
JustTalDevelops committed Jul 20, 2022
1 parent a038de7 commit 4b22eaa
Show file tree
Hide file tree
Showing 6 changed files with 48 additions and 33 deletions.
3 changes: 3 additions & 0 deletions server/player/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ type Handler interface {
// HandleItemPickup handles the player picking up an item from the ground. The item stack laying on the
// ground is passed. ctx.Cancel() may be called to prevent the player from picking up the item.
HandleItemPickup(ctx *event.Context, i item.Stack)
// HandleHeldSlotChange handles the player changing the slot they are currently holding.
HandleHeldSlotChange(ctx *event.Context, slot int)
// HandleItemDrop handles the player dropping an item on the ground. The dropped item entity is passed.
// ctx.Cancel() may be called to prevent the player from dropping the entity.Item passed on the ground.
// e.Item() may be called to obtain the item stack dropped.
Expand All @@ -142,6 +144,7 @@ type NopHandler struct{}
var _ Handler = (*NopHandler)(nil)

func (NopHandler) HandleItemDrop(*event.Context, *entity.Item) {}
func (NopHandler) HandleHeldSlotChange(*event.Context, int) {}
func (NopHandler) HandleMove(*event.Context, mgl64.Vec3, float64, float64) {}
func (NopHandler) HandleJump() {}
func (NopHandler) HandleTeleport(*event.Context, mgl64.Vec3) {}
Expand Down
23 changes: 23 additions & 0 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,29 @@ func (p *Player) Transfer(address string) error {
return nil
}

// SetHeldSlot updates the held slot of the player using the slot provided. It also calls the slot change handler.
func (p *Player) SetHeldSlot(slot int) error {
// The slot that the player might have selected must be within the hotbar: The held item cannot be in a
// different place in the inventory.
if slot > 8 {

This comment has been minimized.

Copy link
@T14Raptor

T14Raptor Jul 20, 2022

Member

Should have a < 0 check too.

return fmt.Errorf("new held slot exceeds hotbar range 0-8: slot is %v", slot)
}
if p.heldSlot.Swap(uint32(slot)) == uint32(slot) {
// Old slot was the same as new slot, so don't do anything.
return nil
}

p.usingItem.Store(false)

ctx := event.C()
p.Handler().HandleHeldSlotChange(ctx, slot)
if ctx.Cancelled() {
// The slot change was cancelled, so don't do anything.
return nil
}
return p.session().SetHeldSlot(slot)
}

// SendCommandOutput sends the output of a command to the player.
func (p *Player) SendCommandOutput(output *cmd.Output) {
p.session().SendCommandOutput(output)
Expand Down
1 change: 1 addition & 0 deletions server/session/controllable.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ type Controllable interface {
Locale() language.Tag

SetHeldItems(right, left item.Stack)
SetHeldSlot(slot int) error

Move(deltaPos mgl64.Vec3, deltaYaw, deltaPitch float64)
Speed() float64
Expand Down
16 changes: 12 additions & 4 deletions server/session/handler_inventory_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ type InventoryTransactionHandler struct{}
// Handle ...
func (h *InventoryTransactionHandler) Handle(p packet.Packet, s *Session) error {
pk := p.(*packet.InventoryTransaction)

switch data := pk.TransactionData.(type) {
case *protocol.NormalTransactionData:
h.resendInventories(s)
Expand All @@ -30,17 +29,26 @@ func (h *InventoryTransactionHandler) Handle(p packet.Packet, s *Session) error
h.resendInventories(s)
return nil
case *protocol.UseItemOnEntityTransactionData:
if err := s.UpdateHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); err != nil {
if held, _ := s.c.HeldItems(); !held.Equal(stackToItem(data.HeldItem.Stack)) {

This comment has been minimized.

Copy link
@T14Raptor

T14Raptor Jul 20, 2022

Member

Would remove all these checks.

return nil
}
if err := s.c.SetHeldSlot(int(data.HotBarSlot)); err != nil {
return err
}
return h.handleUseItemOnEntityTransaction(data, s)
case *protocol.UseItemTransactionData:
if err := s.UpdateHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); err != nil {
if held, _ := s.c.HeldItems(); !held.Equal(stackToItem(data.HeldItem.Stack)) {
return nil
}
if err := s.SetHeldSlot(int(data.HotBarSlot)); err != nil {
return err
}
return h.handleUseItemTransaction(data, s)
case *protocol.ReleaseItemTransactionData:
if err := s.UpdateHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); err != nil {
if held, _ := s.c.HeldItems(); !held.Equal(stackToItem(data.HeldItem.Stack)) {
return nil
}
if err := s.SetHeldSlot(int(data.HotBarSlot)); err != nil {
return err
}
return h.handleReleaseItemTransaction(s)
Expand Down
10 changes: 9 additions & 1 deletion server/session/handler_mob_equipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,15 @@ func (*MobEquipmentHandler) Handle(p packet.Packet, s *Session) error {
// This window ID is expected, but we don't handle it.
return nil
case protocol.WindowIDInventory:
return s.UpdateHeldSlot(int(pk.InventorySlot), stackToItem(pk.NewItem.Stack))
// The item the client claims to have must be identical to the one we have registered server-side.
actual, _ := s.inv.Item(int(pk.InventorySlot))
clientSide := stackToItem(pk.NewItem.Stack)
if !actual.Equal(clientSide) {
// Only ever debug these as they are frequent and expected to happen whenever client and server get
// out of sync.
s.log.Debugf("failed processing packet from %v (%v): *packet.MobEquipment: client-side item must be identical to server-side item, but got differences: client: %v vs server: %v", s.conn.RemoteAddr(), s.c.Name(), clientSide, actual)
}
return s.c.SetHeldSlot(int(pk.InventorySlot))
default:
return fmt.Errorf("only main inventory should be involved in slot chnage, got window ID %v", pk.WindowID)
}
Expand Down
28 changes: 0 additions & 28 deletions server/session/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,34 +586,6 @@ func (s *Session) SetHeldSlot(slot int) error {
return nil
}

// UpdateHeldSlot updates the held slot of the Session to the slot passed. It also verifies that the item in that slot
// matches an expected item stack.
func (s *Session) UpdateHeldSlot(slot int, expected item.Stack) error {
// The slot that the player might have selected must be within the hotbar: The held item cannot be in a
// different place in the inventory.
if slot > 8 {
return fmt.Errorf("new held slot exceeds hotbar range 0-8: slot is %v", slot)
}
if s.heldSlot.Swap(uint32(slot)) == uint32(slot) {
// Old slot was the same as new slot, so don't do anything.
return nil
}

clientSideItem := expected
actual, _ := s.inv.Item(slot)

// The item the client claims to have must be identical to the one we have registered server-side.
if !clientSideItem.Equal(actual) {
// Only ever debug these as they are frequent and expected to happen whenever client and server get
// out of sync.
s.log.Debugf("failed processing packet from %v (%v): failed changing held slot: client-side item must be identical to server-side item, but got differences: client: %v vs server: %v", s.conn.RemoteAddr(), s.c.Name(), clientSideItem, actual)
}
for _, viewer := range s.c.World().Viewers(s.c.Position()) {
viewer.ViewEntityItems(s.c)
}
return nil
}

// SendExperience sends the experience level and progress from the given experience manager to the player.
func (s *Session) SendExperience(e *entity.ExperienceManager) {
level, progress := e.Level(), e.Progress()
Expand Down

0 comments on commit 4b22eaa

Please sign in to comment.