up3
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
Build and deploy / Build (push) Has been cancelled
Build and deploy / Update Contributors (push) Has been cancelled
Build and deploy / Deploy (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,182 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math"
|
||||
|
||||
"github.com/df-mc/dragonfly/server/block/cube"
|
||||
"github.com/df-mc/dragonfly/server/world"
|
||||
"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"
|
||||
)
|
||||
|
||||
// PlayerAuthInputHandler handles the PlayerAuthInput packet.
|
||||
type PlayerAuthInputHandler struct{}
|
||||
|
||||
// Handle ...
|
||||
func (h PlayerAuthInputHandler) Handle(p packet.Packet, s *Session, tx *world.Tx, c Controllable) error {
|
||||
pk := p.(*packet.PlayerAuthInput)
|
||||
if err := h.handleMovement(pk, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
return h.handleActions(pk, s, tx, c)
|
||||
}
|
||||
|
||||
// handleMovement handles the movement part of the packet.PlayerAuthInput.
|
||||
func (h PlayerAuthInputHandler) handleMovement(pk *packet.PlayerAuthInput, s *Session, c Controllable) error {
|
||||
yaw, pitch := c.Rotation().Elem()
|
||||
pos := 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.conf.Log.Debug("process packet: PlayerAuthInput: found nan/inf values. assuming server-side values", "pos", fmt.Sprint(pk.Position), "yaw", pk.Yaw, "head-yaw", pk.HeadYaw, "pitch", pk.Pitch)
|
||||
*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.moving = true
|
||||
c.Move(deltaPos, deltaYaw, deltaPitch)
|
||||
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, tx *world.Tx, c Controllable) error {
|
||||
if pk.InputData.Load(packet.InputFlagPerformItemInteraction) {
|
||||
if err := h.handleUseItemData(pk.ItemInteractionData, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if pk.InputData.Load(packet.InputFlagPerformBlockActions) {
|
||||
if err := h.handleBlockActions(pk.BlockActions, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
h.handleInputFlags(pk.InputData, s, c)
|
||||
|
||||
if pk.InputData.Load(packet.InputFlagPerformItemStackRequest) {
|
||||
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, tx, c); 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.conf.Log.Debug("process packet: PlayerAuthInput: resolve item stack request: " + err.Error())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// handleInputFlags handles the toggleable input flags set in a PlayerAuthInput packet.
|
||||
func (h PlayerAuthInputHandler) handleInputFlags(flags protocol.Bitset, s *Session, c Controllable) {
|
||||
if flags.Load(packet.InputFlagStartSprinting) {
|
||||
c.StartSprinting()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopSprinting) {
|
||||
c.StopSprinting()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartSneaking) {
|
||||
c.StartSneaking()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopSneaking) {
|
||||
c.StopSneaking()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartSwimming) {
|
||||
c.StartSwimming()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopSwimming) {
|
||||
c.StopSwimming()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartGliding) {
|
||||
c.StartGliding()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopGliding) {
|
||||
c.StopGliding()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartJumping) {
|
||||
c.Jump()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartCrawling) {
|
||||
c.StartCrawling()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopCrawling) {
|
||||
c.StopCrawling()
|
||||
}
|
||||
if flags.Load(packet.InputFlagMissedSwing) {
|
||||
s.swingingArm.Store(true)
|
||||
defer s.swingingArm.Store(false)
|
||||
c.PunchAir()
|
||||
}
|
||||
if flags.Load(packet.InputFlagStartFlying) {
|
||||
if !c.GameMode().AllowsFlying() {
|
||||
s.conf.Log.Debug("process packet: PlayerAuthInput: flying flag enabled while unable to fly")
|
||||
s.SendAbilities(c)
|
||||
} else {
|
||||
c.StartFlying()
|
||||
}
|
||||
}
|
||||
if flags.Load(packet.InputFlagStopFlying) {
|
||||
c.StopFlying()
|
||||
}
|
||||
}
|
||||
|
||||
// handleUseItemData handles the protocol.UseItemTransactionData found in a packet.PlayerAuthInput.
|
||||
func (h PlayerAuthInputHandler) handleUseItemData(data protocol.UseItemTransactionData, s *Session, c Controllable) error {
|
||||
s.swingingArm.Store(true)
|
||||
defer s.swingingArm.Store(false)
|
||||
|
||||
held, _ := c.HeldItems()
|
||||
if !held.Equal(stackToItem(s.br, data.HeldItem.Stack)) {
|
||||
s.conf.Log.Debug("process packet: PlayerAuthInput: UseItemTransaction: mismatch between actual held item and client held item")
|
||||
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:
|
||||
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, c Controllable) error {
|
||||
for _, action := range a {
|
||||
if err := handlePlayerAction(action.Action, action.Face, action.BlockPos, selfEntityRuntimeID, s, c); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user