diff --git a/bot/ingame.go b/bot/ingame.go index cf0105a..c67792f 100644 --- a/bot/ingame.go +++ b/bot/ingame.go @@ -132,36 +132,60 @@ func (c *Client) handlePacket(p pk.Packet) (disconnect bool, err error) { } case data.AbilitiesClientbound: err = handlePlayerAbilitiesPacket(c, p) + case data.UpdateHealth: + err = handleUpdateHealthPacket(c, p) + case data.ChatClientbound: + err = handleChatMessagePacket(c, p) + case data.HeldItemSlotClientbound: err = handleHeldItemPacket(c, p) + case data.WindowItems: + err = handleWindowItemsPacket(c, p) + + case data.DeclareRecipes: + // handleDeclareRecipesPacket(g, reader) + case data.KeepAliveClientbound: + err = handleKeepAlivePacket(c, p) + + case data.SpawnEntity: + err = handleSpawnEntityPacket(c, p) + case data.NamedEntitySpawn: + err = handleSpawnPlayerPacket(c, p) + case data.SpawnEntityLiving: + err = handleSpawnLivingEntityPacket(c, p) + case data.Animation: + err = handleEntityAnimationPacket(c, p) + case data.EntityStatus: + err = handleEntityStatusPacket(c, p) + case data.EntityDestroy: + err = handleDestroyEntitiesPacket(c, p) + case data.RelEntityMove: + err = handleEntityPositionPacket(c, p) + case data.EntityMoveLook: + err = handleEntityPositionLookPacket(c, p) + case data.EntityLook: + err = handleEntityLookPacket(c, p) + case data.Entity: + err = handleEntityMovePacket(c, p) + case data.UpdateLight: err = c.Events.updateSeenPackets(seenUpdateLight) case data.MapChunk: err = handleChunkDataPacket(c, p) + case data.BlockChange: + err = handleBlockChangePacket(c, p) + case data.MultiBlockChange: + err = handleMultiBlockChangePacket(c, p) + case data.UnloadChunk: + err = handleUnloadChunkPacket(c, p) + case data.PositionClientbound: err = handlePlayerPositionAndLookPacket(c, p) sendPlayerPositionAndLookPacket(c) // to confirm the position if err2 := c.Events.updateSeenPackets(seenPlayerPositionAndLook); err == nil { err = err2 } - case data.DeclareRecipes: - // handleDeclareRecipesPacket(g, reader) - case data.KeepAliveClientbound: - err = handleKeepAlivePacket(c, p) - case data.Entity: - //handleEntityPacket(g, reader) - case data.NamedEntitySpawn: - // err = handleSpawnPlayerPacket(g, reader) - case data.WindowItems: - err = handleWindowItemsPacket(c, p) - case data.UpdateHealth: - err = handleUpdateHealthPacket(c, p) - case data.ChatClientbound: - err = handleChatMessagePacket(c, p) - case data.BlockChange: - err = handleBlockChangePacket(c, p) - case data.MultiBlockChange: - err = handleMultiBlockChangePacket(c, p) + case data.KickDisconnect: err = handleDisconnectPacket(c, p) disconnect = true @@ -179,6 +203,110 @@ func (c *Client) handlePacket(p pk.Packet) (disconnect bool, err error) { return } +func handleSpawnEntityPacket(c *Client, p pk.Packet) error { + var se ptypes.SpawnEntity + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("SpawnEntity: %+v\n", se) + return nil +} + +func handleSpawnLivingEntityPacket(c *Client, p pk.Packet) error { + var se ptypes.SpawnLivingEntity + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("SpawnLivingEntity: %+v\n", se) + return nil +} + +func handleSpawnPlayerPacket(c *Client, p pk.Packet) error { + var se ptypes.SpawnPlayer + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("SpawnPlayer: %+v\n", se) + return nil +} + +func handleEntityPositionPacket(c *Client, p pk.Packet) error { + var se ptypes.EntityPosition + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("EntityPosition: %+v\n", se) + return nil +} + +func handleEntityPositionLookPacket(c *Client, p pk.Packet) error { + var se ptypes.EntityPositionLook + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("EntityPositionLook: %+v\n", se) + return nil +} + +func handleEntityLookPacket(c *Client, p pk.Packet) error { + var se ptypes.EntityRotation + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("EntityRotation: %+v\n", se) + return nil +} + +func handleEntityMovePacket(c *Client, p pk.Packet) error { + var id pk.VarInt + if err := p.Scan(&id); err != nil { + return err + } + fmt.Printf("EntityMove (probs didnt for players): %+v\n", id) + return nil +} + +func handleEntityAnimationPacket(c *Client, p pk.Packet) error { + var se ptypes.EntityAnimationClientbound + if err := se.Decode(p); err != nil { + return err + } + fmt.Printf("EntityAnimationClientbound: %+v\n", se) + return nil +} + +func handleEntityStatusPacket(c *Client, p pk.Packet) error { + var ( + id pk.Int + status pk.Byte + ) + if err := p.Scan(&id, &status); err != nil { + return err + } + fmt.Printf("EntityStatus: %v, %v\n", id, status) + return nil +} + +func handleDestroyEntitiesPacket(c *Client, p pk.Packet) error { + var ( + count pk.VarInt + r = bytes.NewReader(p.Data) + ) + if err := count.Decode(r); err != nil { + return err + } + + entities := make([]pk.VarInt, int(count)) + for i := 0; i < int(count); i++ { + if err := entities[i].Decode(r); err != nil { + return err + } + } + + fmt.Printf("DestroyEntities: %v\n", entities) + return nil +} + func handleSoundEffect(c *Client, p pk.Packet) error { var s ptypes.SoundEffect if err := s.Decode(p); err != nil { @@ -463,6 +591,19 @@ func handleHeldItemPacket(c *Client, p pk.Packet) error { return nil } +func handleUnloadChunkPacket(c *Client, p pk.Packet) error { + if !c.settings.ReceiveMap { + return nil + } + + var x, z pk.Int + if err := p.Scan(&x, &z); err != nil { + return err + } + c.Wd.UnloadChunk(world.ChunkLoc{X: int(x) >> 4, Z: int(z) >> 4}) + return nil +} + func handleChunkDataPacket(c *Client, p pk.Packet) error { if err := c.Events.updateSeenPackets(seenChunkData); err != nil { return err diff --git a/bot/world/world.go b/bot/world/world.go index 5221d36..31625ad 100644 --- a/bot/world/world.go +++ b/bot/world/world.go @@ -68,6 +68,10 @@ func (w *World) GetBlockStatus(x, y, z int) BlockStatus { return 0 } +func (w *World) UnloadChunk(loc ChunkLoc) { + delete(w.Chunks, loc) +} + func (w *World) UnaryBlockUpdate(pos pk.Position, bStateID BlockStatus) bool { c := w.Chunks[ChunkLoc{X: pos.X >> 4, Z: pos.Z >> 4}] if c == nil { diff --git a/net/packet/types.go b/net/packet/types.go index cf2a1c7..6ec8a8d 100644 --- a/net/packet/types.go +++ b/net/packet/types.go @@ -2,10 +2,11 @@ package packet import ( "errors" - "github.com/google/uuid" "io" "math" + "github.com/google/uuid" + "github.com/Tnze/go-mc/nbt" ) @@ -364,6 +365,16 @@ func (p *Position) Decode(r DecodeReader) error { return nil } +//Decodes an Angle +func (b *Angle) Decode(r DecodeReader) error { + v, err := r.ReadByte() + if err != nil { + return err + } + *b = Angle(v) + return nil +} + //Encode a Float func (f Float) Encode() []byte { return Int(math.Float32bits(float32(f))).Encode() diff --git a/net/ptypes/entities.go b/net/ptypes/entities.go new file mode 100644 index 0000000..47f07bf --- /dev/null +++ b/net/ptypes/entities.go @@ -0,0 +1,95 @@ +package ptypes + +import pk "github.com/Tnze/go-mc/net/packet" + +// SpawnEntity is a clientbound packet used to spawn a non-mob entity. +type SpawnEntity struct { + ID pk.VarInt + UUID pk.UUID + Type pk.VarInt + X, Y, Z pk.Int + Pitch, Yaw pk.Angle + Data pk.Int + VelX, VelY, VelZ pk.Short +} + +func (p *SpawnEntity) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.UUID, &p.Type, + &p.X, &p.Y, &p.Z, &p.Pitch, &p.Yaw, + &p.Data, &p.VelX, &p.VelY, &p.VelZ) +} + +// SpawnPlayer is a clientbound packet used to describe a player entering +// visible range. +type SpawnPlayer struct { + ID pk.VarInt + UUID pk.UUID + X, Y, Z pk.Double + Yaw, Pitch pk.Angle +} + +func (p *SpawnPlayer) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.UUID, &p.X, &p.Y, &p.Z, &p.Yaw, &p.Pitch) +} + +// SpawnLivingEntity is a clientbound packet used to spawn a mob. +type SpawnLivingEntity struct { + ID pk.VarInt + UUID pk.UUID + Type pk.VarInt + X, Y, Z pk.Double + Yaw, Pitch pk.Angle + HeadPitch pk.Angle + VelX, VelY, VelZ pk.Short +} + +func (p *SpawnLivingEntity) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.UUID, &p.Type, + &p.X, &p.Y, &p.Z, &p.Yaw, &p.Pitch, + &p.HeadPitch, &p.VelX, &p.VelY, &p.VelZ) +} + +// EntityAnimationClientbound updates the animationf state of an entity. +type EntityAnimationClientbound struct { + ID pk.VarInt + Animation pk.UnsignedByte +} + +func (p *EntityAnimationClientbound) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.Animation) +} + +// EntityPosition is a clientbound packet used to update an entities position. +type EntityPosition struct { + ID pk.VarInt + X, Y, Z pk.Short // Deltas + OnGround pk.Boolean +} + +func (p *EntityPosition) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.X, &p.Y, &p.Z, &p.OnGround) +} + +// EntityPosition is a clientbound packet used to update an entities position +// and its rotation. +type EntityPositionLook struct { + ID pk.VarInt + X, Y, Z pk.Short // Deltas + Yaw, Pitch pk.Angle + OnGround pk.Boolean +} + +func (p *EntityPositionLook) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.X, &p.Y, &p.Z, &p.Yaw, &p.Pitch, &p.OnGround) +} + +// EntityRotation is a clientbound packet used to update an entities rotation. +type EntityRotation struct { + ID pk.VarInt + Yaw, Pitch pk.Angle + OnGround pk.Boolean +} + +func (p *EntityRotation) Decode(pkt pk.Packet) error { + return pkt.Scan(&p.ID, &p.Yaw, &p.Pitch, &p.OnGround) +}