github.com/df-mc/dragonfly@v0.9.13/server/session/handler_player_auth_input.go (about)

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