-
Notifications
You must be signed in to change notification settings - Fork 150
/
handler_player_auth_input.go
165 lines (147 loc) · 6.1 KB
/
handler_player_auth_input.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
package session
import (
"fmt"
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/go-gl/mathgl/mgl32"
"github.com/go-gl/mathgl/mgl64"
"github.com/sandertv/gophertunnel/minecraft/protocol"
"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
"math"
)
// PlayerAuthInputHandler handles the PlayerAuthInput packet.
type PlayerAuthInputHandler struct{}
// Handle ...
func (h PlayerAuthInputHandler) Handle(p packet.Packet, s *Session) error {
pk := p.(*packet.PlayerAuthInput)
if err := h.handleMovement(pk, s); err != nil {
return err
}
return h.handleActions(pk, s)
}
// handleMovement handles the movement part of the packet.PlayerAuthInput.
func (h PlayerAuthInputHandler) handleMovement(pk *packet.PlayerAuthInput, s *Session) error {
yaw, pitch := s.c.Rotation().Elem()
pos := s.c.Position()
reference := []float64{pitch, yaw, yaw, pos[0], pos[1], pos[2]}
for i, v := range [...]*float32{&pk.Pitch, &pk.Yaw, &pk.HeadYaw, &pk.Position[0], &pk.Position[1], &pk.Position[2]} {
f := float64(*v)
if math.IsNaN(f) || math.IsInf(f, 1) || math.IsInf(f, 0) {
// Sometimes, the PlayerAuthInput packet is in fact sent with NaN/INF after being teleported (to another
// world), see #425. For this reason, we don't actually return an error if this happens, because this will
// result in the player being kicked. Just log it and replace the NaN value with the one we have tracked
// server-side.
s.log.Debugf("failed processing packet from %v (%v): %T: must not have nan/inf values, but got %v (%v, %v, %v). assuming server-side values\n", s.conn.RemoteAddr(), s.c.Name(), pk, pk.Position, pk.Pitch, pk.Yaw, pk.HeadYaw)
*v = float32(reference[i])
}
}
pk.Position = pk.Position.Sub(mgl32.Vec3{0, 1.62}) // Sub the base offset of players from the pos.
newPos := vec32To64(pk.Position)
deltaPos, deltaYaw, deltaPitch := newPos.Sub(pos), float64(pk.Yaw)-yaw, float64(pk.Pitch)-pitch
if mgl64.FloatEqual(deltaPos.Len(), 0) && mgl64.FloatEqual(deltaYaw, 0) && mgl64.FloatEqual(deltaPitch, 0) {
// The PlayerAuthInput packet is sent every tick, so don't do anything if the position and rotation
// were unchanged.
return nil
}
if expected := s.teleportPos.Load(); expected != nil {
if newPos.Sub(*expected).Len() > 1 {
// The player has moved before it received the teleport packet. Ignore this movement entirely and
// wait for the client to sync itself back to the server. Once we get a movement that is close
// enough to the teleport position, we'll allow the player to move around again.
return nil
}
s.teleportPos.Store(nil)
}
s.c.Move(deltaPos, deltaYaw, deltaPitch)
if !mgl64.FloatEqual(deltaPos.Len(), 0) {
s.chunkLoader.Move(newPos)
s.writePacket(&packet.NetworkChunkPublisherUpdate{
Position: protocol.BlockPos{int32(pk.Position[0]), int32(pk.Position[1]), int32(pk.Position[2])},
Radius: uint32(s.chunkRadius) << 4,
})
}
return nil
}
// handleActions handles the actions with the world that are present in the PlayerAuthInput packet.
func (h PlayerAuthInputHandler) handleActions(pk *packet.PlayerAuthInput, s *Session) error {
if pk.InputData&packet.InputFlagPerformItemInteraction != 0 {
if err := h.handleUseItemData(pk.ItemInteractionData, s); err != nil {
return err
}
}
if pk.InputData&packet.InputFlagPerformBlockActions != 0 {
if err := h.handleBlockActions(pk.BlockActions, s); err != nil {
return err
}
}
h.handleInputFlags(pk.InputData, s)
if pk.InputData&packet.InputFlagPerformItemStackRequest != 0 {
s.inTransaction.Store(true)
defer s.inTransaction.Store(false)
// As of 1.18 this is now used for sending item stack requests such as when mining a block.
sh := s.handlers[packet.IDItemStackRequest].(*ItemStackRequestHandler)
if err := sh.handleRequest(pk.ItemStackRequest, s); err != nil {
// Item stacks being out of sync isn't uncommon, so don't error. Just debug the error and let the
// revert do its work.
s.log.Debugf("failed processing packet from %v (%v): PlayerAuthInput: error resolving item stack request: %v", s.conn.RemoteAddr(), s.c.Name(), err)
}
}
return nil
}
// handleInputFlags handles the toggleable input flags set in a PlayerAuthInput packet.
func (h PlayerAuthInputHandler) handleInputFlags(flags uint64, s *Session) {
if flags&packet.InputFlagStartSprinting != 0 {
s.c.StartSprinting()
}
if flags&packet.InputFlagStopSprinting != 0 {
s.c.StopSprinting()
}
if flags&packet.InputFlagStartSneaking != 0 {
s.c.StartSneaking()
}
if flags&packet.InputFlagStopSneaking != 0 {
s.c.StopSneaking()
}
if flags&packet.InputFlagStartSwimming != 0 {
s.c.StartSwimming()
}
if flags&packet.InputFlagStopSwimming != 0 {
s.c.StopSwimming()
}
if flags&packet.InputFlagStartGliding != 0 {
s.c.StartGliding()
}
if flags&packet.InputFlagStopGliding != 0 {
s.c.StopGliding()
}
if flags&packet.InputFlagStartJumping != 0 {
s.c.Jump()
}
}
// handleUseItemData handles the protocol.UseItemTransactionData found in a packet.PlayerAuthInput.
func (h PlayerAuthInputHandler) handleUseItemData(data protocol.UseItemTransactionData, s *Session) error {
s.swingingArm.Store(true)
defer s.swingingArm.Store(false)
held, _ := s.c.HeldItems()
if !held.Equal(stackToItem(data.HeldItem.Stack)) {
s.log.Debugf("failed processing item interaction from %v (%v): PlayerAuthInput: actual held and client held item mismatch", s.conn.RemoteAddr(), s.c.Name())
return nil
}
pos := cube.Pos{int(data.BlockPosition[0]), int(data.BlockPosition[1]), int(data.BlockPosition[2])}
// Seems like this is only used for breaking blocks at the moment.
switch data.ActionType {
case protocol.UseItemActionBreakBlock:
s.c.BreakBlock(pos)
default:
return fmt.Errorf("unhandled UseItem ActionType for PlayerAuthInput packet %v", data.ActionType)
}
return nil
}
// handleBlockActions handles a slice of protocol.PlayerBlockAction present in a PlayerAuthInput packet.
func (h PlayerAuthInputHandler) handleBlockActions(a []protocol.PlayerBlockAction, s *Session) error {
for _, action := range a {
if err := handlePlayerAction(action.Action, action.Face, action.BlockPos, selfEntityRuntimeID, s); err != nil {
return err
}
}
return nil
}