Skip to content
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

Added Held Slot handler #430

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
11 changes: 10 additions & 1 deletion server/player/handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package player

import (
"net"

"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/cmd"
"github.com/df-mc/dragonfly/server/entity"
Expand All @@ -11,7 +13,6 @@ import (
"github.com/df-mc/dragonfly/server/player/skin"
"github.com/df-mc/dragonfly/server/world"
"github.com/go-gl/mathgl/mgl64"
"net"
)

// Handler handles events that are called by a player. Implementations of Handler may be used to listen to
Expand Down Expand Up @@ -108,6 +109,11 @@ 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 @@ -134,6 +140,9 @@ var _ Handler = (*NopHandler)(nil)
// HandleItemDrop ...
func (NopHandler) HandleItemDrop(*event.Context, *entity.Item) {}

// HandleHeldSlotChange ...
func (NopHandler) HandleHeldSlotChange(event *event.Context, slot int) {}

// HandleMove ...
func (NopHandler) HandleMove(*event.Context, mgl64.Vec3, float64, float64) {}

Expand Down
44 changes: 38 additions & 6 deletions server/player/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@ package player

import (
"fmt"
"math"
"math/rand"
"net"
"strings"
"sync"
"time"

"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/cmd"
Expand All @@ -28,12 +35,6 @@ import (
"github.com/google/uuid"
"go.uber.org/atomic"
"golang.org/x/text/language"
"math"
"math/rand"
"net"
"strings"
"sync"
"time"
)

// Player is an implementation of a player entity. It has methods that implement the behaviour that players
Expand Down Expand Up @@ -367,6 +368,37 @@ func (p *Player) Transfer(address string) (err error) {
return
}

// SetHeldSlot updates the held slot of the player with the slot passed. It also verifies that the item within the spot
Copy link
Member

Choose a reason for hiding this comment

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

Should remove the middle sentence in this doc.

// is the correct item.
// This invokes the HandleHeldSlotChange handler.
func (p *Player) SetHeldSlot(slot int, expected item.Stack) error {
Copy link
Member

Choose a reason for hiding this comment

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

Passing an expected item stack no longer makes sense here, should be removed.

if slot > 8 {
Copy link
Member

Choose a reason for hiding this comment

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

Why'd you remove all the documentation for this method?

return fmt.Errorf("new held slot exceeds hotbar range 0-8: slot is %v", slot)
}

if p.heldSlot.Swap(uint32(slot)) == uint32(slot) {
return nil
}

p.ReleaseItem()
Copy link
Member

Choose a reason for hiding this comment

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

Should just set (Player).usingItem to false here.


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

if !clientSideItem.Equal(actual) {
return fmt.Errorf("client side item isn't equal to expected slot item")
Copy link
Member

Choose a reason for hiding this comment

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

This code no longer belongs here now that it's a player method, should be moved to packet handling (check a0bb8dd).

}

ctx := event.C()
p.handler().HandleHeldSlotChange(ctx, slot)

ctx.Continue(func() {
p.session().SetHeldSlot(slot)
})

return nil
}

// 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 @@ -23,6 +23,7 @@ type Controllable interface {
cmd.Source
chat.Subscriber
SetHeldItems(right, left item.Stack)
SetHeldSlot(slot int, expected item.Stack) error

Move(deltaPos mgl64.Vec3, deltaYaw, deltaPitch float64)
Speed() float64
Expand Down
7 changes: 4 additions & 3 deletions server/session/handler_inventory_transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package session

import (
"fmt"

"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/event"
"github.com/sandertv/gophertunnel/minecraft/protocol"
Expand Down Expand Up @@ -30,17 +31,17 @@ 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 err := s.c.SetHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); 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 err := s.c.SetHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); 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 err := s.c.SetHeldSlot(int(data.HotBarSlot), stackToItem(data.HeldItem.Stack)); err != nil {
return err
}
return h.handleReleaseItemTransaction(s)
Expand Down
3 changes: 2 additions & 1 deletion server/session/handler_mob_equipment.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package session

import (
"fmt"

"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
)
Expand All @@ -21,7 +22,7 @@ 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))
return s.c.SetHeldSlot(int(pk.InventorySlot), stackToItem(pk.NewItem.Stack))
default:
return fmt.Errorf("only main inventory should be involved in slot chnage, got window ID %v", pk.WindowID)
}
Expand Down
39 changes: 5 additions & 34 deletions server/session/player.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package session
import (
"encoding/json"
"fmt"
"math"
"net"
"time"
_ "unsafe" // Imported for compiler directives.

"github.com/df-mc/dragonfly/server/block"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/entity"
Expand All @@ -18,10 +23,6 @@ import (
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"go.uber.org/atomic"
"math"
"net"
"time"
_ "unsafe" // Imported for compiler directives.
)

// StopShowingEntity stops showing a world.Entity to the Session. It will be completely invisible until a call to
Expand Down Expand Up @@ -491,36 +492,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
}
// The user swapped changed held slots so stop using item right away.
s.c.ReleaseItem()

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
}

// stackFromItem converts an item.Stack to its network ItemStack representation.
func stackFromItem(it item.Stack) protocol.ItemStack {
if it.Empty() {
Expand Down