Move decode of complex packets into their own package
This commit is contained in:
110
net/ptypes/chunk.go
Normal file
110
net/ptypes/chunk.go
Normal file
@ -0,0 +1,110 @@
|
||||
// Package ptypes implements encoding and decoding for high-level packets.
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/Tnze/go-mc/nbt"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// ChunkData is a clientbound packet which describes a chunk.
|
||||
type ChunkData struct {
|
||||
X, Z pk.Int
|
||||
FullChunk pk.Boolean
|
||||
PrimaryBitMask pk.VarInt
|
||||
Heightmaps struct{}
|
||||
Biomes biomesData
|
||||
Data chunkData
|
||||
BlockEntities blockEntities
|
||||
}
|
||||
|
||||
func (p *ChunkData) Decode(pkt pk.Packet) error {
|
||||
r := bytes.NewReader(pkt.Data)
|
||||
if err := p.X.Decode(r); err != nil {
|
||||
return fmt.Errorf("X: %v", err)
|
||||
}
|
||||
if err := p.Z.Decode(r); err != nil {
|
||||
return fmt.Errorf("Z: %v", err)
|
||||
}
|
||||
if err := p.FullChunk.Decode(r); err != nil {
|
||||
return fmt.Errorf("full chunk: %v", err)
|
||||
}
|
||||
if err := p.PrimaryBitMask.Decode(r); err != nil {
|
||||
return fmt.Errorf("bit mask: %v", err)
|
||||
}
|
||||
if err := (pk.NBT{V: &p.Heightmaps}).Decode(r); err != nil {
|
||||
return fmt.Errorf("heightmaps: %v", err)
|
||||
}
|
||||
|
||||
// Biome data is only present for full chunks.
|
||||
if p.FullChunk {
|
||||
if err := p.Biomes.Decode(r); err != nil {
|
||||
return fmt.Errorf("heightmaps: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
if err := p.Data.Decode(r); err != nil {
|
||||
return fmt.Errorf("data: %v", err)
|
||||
}
|
||||
if err := p.BlockEntities.Decode(r); err != nil {
|
||||
return fmt.Errorf("block entities: %v", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type biomesData struct {
|
||||
data []pk.VarInt
|
||||
}
|
||||
|
||||
func (b *biomesData) Decode(r pk.DecodeReader) error {
|
||||
var nobd pk.VarInt // Number of Biome Datums
|
||||
if err := nobd.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
b.data = make([]pk.VarInt, nobd)
|
||||
|
||||
for i := 0; i < int(nobd); i++ {
|
||||
var d pk.VarInt
|
||||
if err := d.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
b.data[i] = d
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type chunkData []byte
|
||||
type blockEntities []blockEntity
|
||||
type blockEntity struct{}
|
||||
|
||||
// Decode implement net.packet.FieldDecoder
|
||||
func (c *chunkData) Decode(r pk.DecodeReader) error {
|
||||
var sz pk.VarInt
|
||||
if err := sz.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
*c = make([]byte, sz)
|
||||
if _, err := r.Read(*c); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Decode implement net.packet.FieldDecoder
|
||||
func (b *blockEntities) Decode(r pk.DecodeReader) error {
|
||||
var sz pk.VarInt // Number of BlockEntities
|
||||
if err := sz.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
*b = make(blockEntities, sz)
|
||||
decoder := nbt.NewDecoder(r)
|
||||
for i := 0; i < int(sz); i++ {
|
||||
if err := decoder.Decode(&(*b)[i]); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
54
net/ptypes/inventory.go
Normal file
54
net/ptypes/inventory.go
Normal file
@ -0,0 +1,54 @@
|
||||
// Package ptypes implements encoding and decoding for high-level packets.
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
|
||||
"github.com/Tnze/go-mc/bot/world/entity"
|
||||
"github.com/Tnze/go-mc/nbt"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// SetSlot is a clientbound packet which configures an inventory slot.
|
||||
// A window ID of -1 represents the cursor, and a window ID of 0 represents
|
||||
// the players inventory.
|
||||
type SetSlot struct {
|
||||
WindowID pk.Byte
|
||||
Slot pk.Short
|
||||
SlotData entity.Slot
|
||||
}
|
||||
|
||||
func (p *SetSlot) Decode(pkt pk.Packet) error {
|
||||
if err := pkt.Scan(&p.WindowID, &p.Slot, &p.SlotData); err != nil && !errors.Is(err, nbt.ErrEND) {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WindowItems is a clientbound packet describing the contents of multiple
|
||||
// inventory slots in a window/inventory.
|
||||
type WindowItems struct {
|
||||
WindowID pk.Byte
|
||||
Slots []entity.Slot
|
||||
}
|
||||
|
||||
func (p *WindowItems) Decode(pkt pk.Packet) error {
|
||||
r := bytes.NewReader(pkt.Data)
|
||||
if err := p.WindowID.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var count pk.Short
|
||||
if err := count.Decode(r); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
p.Slots = make([]entity.Slot, int(count))
|
||||
for i := 0; i < int(count); i++ {
|
||||
if err := p.Slots[i].Decode(r); err != nil && !errors.Is(err, nbt.ErrEND) {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
91
net/ptypes/misc.go
Normal file
91
net/ptypes/misc.go
Normal file
@ -0,0 +1,91 @@
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
|
||||
"github.com/Tnze/go-mc/chat"
|
||||
"github.com/Tnze/go-mc/data"
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// SoundEffect is a clientbound packet used to play a specific sound ID
|
||||
// on the client.
|
||||
type SoundEffect struct {
|
||||
Sound pk.VarInt
|
||||
Category pk.VarInt
|
||||
X, Y, Z pk.Int
|
||||
Volume, Pitch pk.Float
|
||||
}
|
||||
|
||||
func (p *SoundEffect) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.Sound, &p.Category, &p.X, &p.Y, &p.Z, &p.Volume, &p.Pitch)
|
||||
}
|
||||
|
||||
// NamedSoundEffect is a clientbound packet used to play a sound with the
|
||||
// specified name on the client.
|
||||
type NamedSoundEffect struct {
|
||||
Sound pk.String
|
||||
Category pk.VarInt
|
||||
X, Y, Z pk.Int
|
||||
Volume, Pitch pk.Float
|
||||
}
|
||||
|
||||
func (p *NamedSoundEffect) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.Sound, &p.Category, &p.X, &p.Y, &p.Z, &p.Volume, &p.Pitch)
|
||||
}
|
||||
|
||||
// ChatMessageClientbound represents a chat message forwarded by the server.
|
||||
type ChatMessageClientbound struct {
|
||||
S chat.Message
|
||||
Pos pk.Byte
|
||||
Sender pk.UUID
|
||||
}
|
||||
|
||||
func (p *ChatMessageClientbound) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.S, &p.Pos, &p.Sender)
|
||||
}
|
||||
|
||||
// UpdateHealth encodes player health/food information from the server.
|
||||
type UpdateHealth struct {
|
||||
Health pk.Float
|
||||
Food pk.VarInt
|
||||
FoodSaturation pk.Float
|
||||
}
|
||||
|
||||
func (p *UpdateHealth) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.Health, &p.Food, &p.FoodSaturation)
|
||||
}
|
||||
|
||||
// PluginData encodes the custom data encoded in a plugin message.
|
||||
type PluginData []byte
|
||||
|
||||
func (p PluginData) Encode() []byte {
|
||||
return []byte(p)
|
||||
}
|
||||
|
||||
func (p *PluginData) Decode(r pk.DecodeReader) error {
|
||||
data, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*p = data
|
||||
return nil
|
||||
}
|
||||
|
||||
// PluginMessage represents a packet with a customized payload.
|
||||
type PluginMessage struct {
|
||||
Channel pk.Identifier
|
||||
Data PluginData
|
||||
}
|
||||
|
||||
func (p *PluginMessage) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.Channel, &p.Data)
|
||||
}
|
||||
|
||||
func (p *PluginMessage) Encode() pk.Packet {
|
||||
return pk.Marshal(
|
||||
data.CustomPayloadServerbound,
|
||||
p.Channel,
|
||||
p.Data,
|
||||
)
|
||||
}
|
35
net/ptypes/motion.go
Normal file
35
net/ptypes/motion.go
Normal file
@ -0,0 +1,35 @@
|
||||
// Package ptypes implements encoding and decoding for high-level packets.
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// PositionAndLookClientbound describes the location and orientation of
|
||||
// the player.
|
||||
type PositionAndLookClientbound struct {
|
||||
X, Y, Z pk.Double
|
||||
Yaw, Pitch pk.Float
|
||||
Flags pk.Byte
|
||||
TeleportID pk.VarInt
|
||||
}
|
||||
|
||||
func (p *PositionAndLookClientbound) RelativeX() bool {
|
||||
return p.Flags&0x01 != 0
|
||||
}
|
||||
func (p *PositionAndLookClientbound) RelativeY() bool {
|
||||
return p.Flags&0x02 != 0
|
||||
}
|
||||
func (p *PositionAndLookClientbound) RelativeZ() bool {
|
||||
return p.Flags&0x04 != 0
|
||||
}
|
||||
func (p *PositionAndLookClientbound) RelativeYaw() bool {
|
||||
return p.Flags&0x08 != 0
|
||||
}
|
||||
func (p *PositionAndLookClientbound) RelativePitch() bool {
|
||||
return p.Flags&0x10 != 0
|
||||
}
|
||||
|
||||
func (p *PositionAndLookClientbound) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.X, &p.Y, &p.Z, &p.Yaw, &p.Pitch, &p.Flags, &p.TeleportID)
|
||||
}
|
32
net/ptypes/world.go
Normal file
32
net/ptypes/world.go
Normal file
@ -0,0 +1,32 @@
|
||||
package ptypes
|
||||
|
||||
import (
|
||||
pk "github.com/Tnze/go-mc/net/packet"
|
||||
)
|
||||
|
||||
// JoinGame encodes global/world information from the server.
|
||||
type JoinGame struct {
|
||||
PlayerEntity pk.Int
|
||||
Hardcore pk.Boolean
|
||||
Gamemode pk.UnsignedByte
|
||||
PrevGamemode pk.UnsignedByte
|
||||
WorldCount pk.VarInt
|
||||
WorldNames pk.Identifier
|
||||
//DimensionCodec pk.NBT
|
||||
Dimension pk.Int
|
||||
WorldName pk.Identifier
|
||||
HashedSeed pk.Long
|
||||
maxPlayers pk.VarInt // Now ignored
|
||||
ViewDistance pk.VarInt
|
||||
RDI pk.Boolean // Reduced Debug Info
|
||||
ERS pk.Boolean // Enable respawn screen
|
||||
IsDebug pk.Boolean
|
||||
IsFlat pk.Boolean
|
||||
}
|
||||
|
||||
func (p *JoinGame) Decode(pkt pk.Packet) error {
|
||||
return pkt.Scan(&p.PlayerEntity, &p.Hardcore, &p.Gamemode, &p.PrevGamemode,
|
||||
&p.WorldCount, &p.WorldNames, &p.Dimension,
|
||||
&p.WorldName, &p.HashedSeed, &p.maxPlayers, &p.ViewDistance,
|
||||
&p.RDI, &p.ERS, &p.IsDebug, &p.IsFlat)
|
||||
}
|
Reference in New Issue
Block a user