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

     1  package session
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/df-mc/dragonfly/server/block/cube"
     6  	"github.com/sandertv/gophertunnel/minecraft/protocol"
     7  	"github.com/sandertv/gophertunnel/minecraft/protocol/packet"
     8  )
     9  
    10  // PlayerActionHandler handles the PlayerAction packet.
    11  type PlayerActionHandler struct{}
    12  
    13  // Handle ...
    14  func (*PlayerActionHandler) Handle(p packet.Packet, s *Session) error {
    15  	pk := p.(*packet.PlayerAction)
    16  
    17  	return handlePlayerAction(pk.ActionType, pk.BlockFace, pk.BlockPosition, pk.EntityRuntimeID, s)
    18  }
    19  
    20  // handlePlayerAction handles an action performed by a player, found in packet.PlayerAction and packet.PlayerAuthInput.
    21  func handlePlayerAction(action int32, face int32, pos protocol.BlockPos, entityRuntimeID uint64, s *Session) error {
    22  	if entityRuntimeID != selfEntityRuntimeID {
    23  		return errSelfRuntimeID
    24  	}
    25  	switch action {
    26  	case protocol.PlayerActionRespawn, protocol.PlayerActionDimensionChangeDone:
    27  		// Don't do anything for these actions.
    28  	case protocol.PlayerActionStopSleeping:
    29  		if mode := s.c.GameMode(); !mode.Visible() && !mode.HasCollision() {
    30  			// As of v1.19.50, the client sends this packet when switching to spectator mode... even if it wasn't
    31  			// sleeping in the first place. This accounts for that.
    32  			return nil
    33  		}
    34  	case protocol.PlayerActionStartBreak, protocol.PlayerActionContinueDestroyBlock:
    35  		s.swingingArm.Store(true)
    36  		defer s.swingingArm.Store(false)
    37  
    38  		s.breakingPos = cube.Pos{int(pos[0]), int(pos[1]), int(pos[2])}
    39  		s.c.StartBreaking(s.breakingPos, cube.Face(face))
    40  	case protocol.PlayerActionAbortBreak:
    41  		s.c.AbortBreaking()
    42  	case protocol.PlayerActionPredictDestroyBlock, protocol.PlayerActionStopBreak:
    43  		s.swingingArm.Store(true)
    44  		defer s.swingingArm.Store(false)
    45  		s.c.FinishBreaking()
    46  	case protocol.PlayerActionCrackBreak:
    47  		s.swingingArm.Store(true)
    48  		defer s.swingingArm.Store(false)
    49  
    50  		newPos := cube.Pos{int(pos[0]), int(pos[1]), int(pos[2])}
    51  
    52  		// Sometimes no new position will be sent using a StartBreak action, so we need to detect a change in the
    53  		// block to be broken by comparing positions.
    54  		if newPos != s.breakingPos {
    55  			s.breakingPos = newPos
    56  			s.c.StartBreaking(newPos, cube.Face(face))
    57  			return nil
    58  		}
    59  		s.c.ContinueBreaking(cube.Face(face))
    60  	case protocol.PlayerActionStartItemUseOn, protocol.PlayerActionStopItemUseOn:
    61  		// TODO: Properly utilize these actions.
    62  	case protocol.PlayerActionStartBuildingBlock:
    63  		// Don't do anything for this action.
    64  	case protocol.PlayerActionCreativePlayerDestroyBlock:
    65  	// Don't do anything for this action.
    66  	case protocol.PlayerActionMissedSwing:
    67  		s.swingingArm.Store(true)
    68  		defer s.swingingArm.Store(false)
    69  		s.c.PunchAir()
    70  	default:
    71  		return fmt.Errorf("unhandled ActionType %v", action)
    72  	}
    73  	return nil
    74  }