106 lines
2.9 KiB
Go
106 lines
2.9 KiB
Go
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
|
||
|
|
}
|