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 }