package gameserver import ( "encoding/binary" "errors" "fmt" ) const ( HeadMagic uint32 = 0x9D74C714 TailMagic uint32 = 0xD7A152C8 ) // NetPacket is the framed protocol inside the KCP stream. type NetPacket struct { CmdType uint16 Head []byte Body []byte } var ErrMalformedPacket = errors.New("malformed packet") func (p *NetPacket) Encode() []byte { out := make([]byte, 0, 12+len(p.Head)+len(p.Body)) var be32 [4]byte var be16 [2]byte binary.BigEndian.PutUint32(be32[:], HeadMagic) out = append(out, be32[:]...) binary.BigEndian.PutUint16(be16[:], p.CmdType) out = append(out, be16[:]...) binary.BigEndian.PutUint16(be16[:], uint16(len(p.Head))) out = append(out, be16[:]...) binary.BigEndian.PutUint32(be32[:], uint32(len(p.Body))) out = append(out, be32[:]...) out = append(out, p.Head...) out = append(out, p.Body...) binary.BigEndian.PutUint32(be32[:], TailMagic) out = append(out, be32[:]...) return out } // DecodeNetPacket parses one framed packet (must be a complete packet). func DecodeNetPacket(data []byte) (*NetPacket, error) { if len(data) < 16 { return nil, fmt.Errorf("%w: too short (%d)", ErrMalformedPacket, len(data)) } if binary.BigEndian.Uint32(data[0:4]) != HeadMagic { return nil, fmt.Errorf("%w: bad head magic", ErrMalformedPacket) } cmdType := binary.BigEndian.Uint16(data[4:6]) headLen := int(binary.BigEndian.Uint16(data[6:8])) bodyLen := int(binary.BigEndian.Uint32(data[8:12])) if len(data) < 12+headLen+bodyLen+4 { return nil, fmt.Errorf("%w: truncated", ErrMalformedPacket) } if binary.BigEndian.Uint32(data[12+headLen+bodyLen:]) != TailMagic { return nil, fmt.Errorf("%w: bad tail magic", ErrMalformedPacket) } return &NetPacket{ CmdType: cmdType, Head: data[12 : 12+headLen], Body: data[12+headLen : 12+headLen+bodyLen], }, nil } // NetOperation is the 20-byte handshake control packet. type NetOperation struct { Head uint32 Param1 uint32 Param2 uint32 Data uint32 Tail uint32 } const ( NetOpConnectHead uint32 = 0xFF NetOpConnectTail uint32 = 0xFFFFFFFF NetOpAcceptHead uint32 = 0x145 NetOpAcceptTail uint32 = 0x14514545 NetOpDropHead uint32 = 0x194 NetOpDropTail uint32 = 0x19419494 ) func DecodeNetOperation(data []byte) (*NetOperation, error) { if len(data) < 20 { return nil, fmt.Errorf("%w: netop too short", ErrMalformedPacket) } return &NetOperation{ Head: binary.BigEndian.Uint32(data[0:4]), Param1: binary.BigEndian.Uint32(data[4:8]), Param2: binary.BigEndian.Uint32(data[8:12]), Data: binary.BigEndian.Uint32(data[12:16]), Tail: binary.BigEndian.Uint32(data[16:20]), }, nil } func (o *NetOperation) Encode() []byte { out := make([]byte, 20) binary.BigEndian.PutUint32(out[0:4], o.Head) binary.BigEndian.PutUint32(out[4:8], o.Param1) binary.BigEndian.PutUint32(out[8:12], o.Param2) binary.BigEndian.PutUint32(out[12:16], o.Data) binary.BigEndian.PutUint32(out[16:20], o.Tail) return out }