Files
Frodding/raknet/datagram.go
2026-03-03 15:05:55 +03:00

123 lines
2.1 KiB
Go

package raknet
type Datagram struct {
SeqNum uint32
Frames []*Frame
}
func (d *Datagram) Encode() []byte {
s := NewStream()
s.WriteByte(0x84)
s.WriteUint24LE(d.SeqNum)
for _, f := range d.Frames {
f.Encode(s)
}
return s.Bytes()
}
func DecodeDatagram(data []byte) (*Datagram, error) {
s := NewStreamBytes(data)
_, err := s.ReadByte()
if err != nil {
return nil, err
}
seq, err := s.ReadUint24LE()
if err != nil {
return nil, err
}
d := &Datagram{SeqNum: seq}
for s.Len() >= 3 {
f, err := DecodeFrame(s)
if err != nil {
break
}
d.Frames = append(d.Frames, f)
}
return d, nil
}
func (d *Datagram) Size() int {
size := 4
for _, f := range d.Frames {
size += f.Size()
}
return size
}
func EncodeACK(seqNums []uint32) []byte {
return encodeAckNack(0xc0, seqNums)
}
func EncodeNACK(seqNums []uint32) []byte {
return encodeAckNack(0xa0, seqNums)
}
func encodeAckNack(id byte, seqNums []uint32) []byte {
if len(seqNums) == 0 {
s := NewStream()
s.WriteByte(id)
s.WriteUint16BE(0)
return s.Bytes()
}
type run struct{ start, end uint32 }
var runs []run
cur := run{seqNums[0], seqNums[0]}
for _, n := range seqNums[1:] {
if n == cur.end+1 {
cur.end = n
} else {
runs = append(runs, cur)
cur = run{n, n}
}
}
runs = append(runs, cur)
s := NewStream()
s.WriteByte(id)
s.WriteUint16BE(uint16(len(runs)))
for _, r := range runs {
if r.start == r.end {
s.WriteBool(true)
s.WriteUint24LE(r.start)
} else {
s.WriteBool(false)
s.WriteUint24LE(r.start)
s.WriteUint24LE(r.end)
}
}
return s.Bytes()
}
func DecodeACKNACK(data []byte) ([]uint32, error) {
s := NewStreamBytes(data)
s.Skip(1)
count, err := s.ReadUint16BE()
if err != nil {
return nil, err
}
var nums []uint32
for i := 0; i < int(count); i++ {
single, err := s.ReadBool()
if err != nil {
return nil, err
}
start, err := s.ReadUint24LE()
if err != nil {
return nil, err
}
if single {
nums = append(nums, start)
} else {
end, err := s.ReadUint24LE()
if err != nil {
return nil, err
}
for n := start; n <= end; n++ {
nums = append(nums, n)
}
}
}
return nums, nil
}