Make packet a module and import huffman
This commit is contained in:
parent
17047eac70
commit
4d307dc990
28
.github/workflows/main.yml
vendored
Normal file
28
.github/workflows/main.yml
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
name: Go
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ "master" ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ "master" ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Set up Go
|
||||||
|
uses: actions/setup-go@v4
|
||||||
|
with:
|
||||||
|
go-version: '1.22'
|
||||||
|
|
||||||
|
- name: Build
|
||||||
|
run: go build -v ./...
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test -v ./...
|
||||||
|
|
||||||
|
- name: Format
|
||||||
|
run: diff -u <(echo -n) <(gofmt -d ./)
|
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -1 +1,3 @@
|
||||||
teeworlds_client
|
teeworlds_client
|
||||||
|
teeworlds
|
||||||
|
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -1,3 +1,5 @@
|
||||||
module github.com/teeworlds-go/teeworlds
|
module github.com/teeworlds-go/teeworlds
|
||||||
|
|
||||||
go 1.22.3
|
go 1.22.3
|
||||||
|
|
||||||
|
require github.com/teeworlds-go/huffman v1.0.0 // indirect
|
||||||
|
|
2
go.sum
Normal file
2
go.sum
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
github.com/teeworlds-go/huffman v1.0.0 h1:XSNMNAJZb+njNrPACsxcDrrLDXTGjZZt35FqLAuHi4I=
|
||||||
|
github.com/teeworlds-go/huffman v1.0.0/go.mod h1:kjaXpL6C6xL7CM+tWPNYjdEgVZB2GumKhx7rCDdXArU=
|
56
packet.go
56
packet.go
|
@ -1,56 +0,0 @@
|
||||||
package main
|
|
||||||
|
|
||||||
const (
|
|
||||||
packetFlagControl = 1
|
|
||||||
packetFlagResend = 2
|
|
||||||
packetFlagCompression = 4
|
|
||||||
packetFlagConnless = 8
|
|
||||||
)
|
|
||||||
|
|
||||||
type PacketFlags struct {
|
|
||||||
connless bool
|
|
||||||
compression bool
|
|
||||||
resend bool
|
|
||||||
control bool
|
|
||||||
}
|
|
||||||
|
|
||||||
type PacketHeader struct {
|
|
||||||
flags PacketFlags
|
|
||||||
ack int
|
|
||||||
numChunks int
|
|
||||||
token [4]byte
|
|
||||||
}
|
|
||||||
|
|
||||||
func (header *PacketHeader) unpack(packet []byte) {
|
|
||||||
header.flags.unpack(packet)
|
|
||||||
header.ack = (int(packet[0]&0x3) << 8) | int(packet[1])
|
|
||||||
header.numChunks = int(packet[2])
|
|
||||||
copy(header.token[:], packet[3:7])
|
|
||||||
}
|
|
||||||
|
|
||||||
func (flags *PacketFlags) unpack(packetHeaderRaw []byte) {
|
|
||||||
flagBits := packetHeaderRaw[0] >> 2
|
|
||||||
flags.control = (flagBits & packetFlagControl) != 0
|
|
||||||
flags.resend = (flagBits & packetFlagResend) != 0
|
|
||||||
flags.compression = (flagBits & packetFlagCompression) != 0
|
|
||||||
flags.connless = (flagBits & packetFlagConnless) != 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (flags *PacketFlags) pack() []byte {
|
|
||||||
data := 0
|
|
||||||
|
|
||||||
if flags.control {
|
|
||||||
data |= packetFlagControl
|
|
||||||
}
|
|
||||||
if flags.resend {
|
|
||||||
data |= packetFlagResend
|
|
||||||
}
|
|
||||||
if flags.compression {
|
|
||||||
data |= packetFlagCompression
|
|
||||||
}
|
|
||||||
if flags.connless {
|
|
||||||
data |= packetFlagConnless
|
|
||||||
}
|
|
||||||
|
|
||||||
return []byte{byte(data)}
|
|
||||||
}
|
|
56
packet/packet.go
Normal file
56
packet/packet.go
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
package packet
|
||||||
|
|
||||||
|
const (
|
||||||
|
packetFlagControl = 1
|
||||||
|
packetFlagResend = 2
|
||||||
|
packetFlagCompression = 4
|
||||||
|
packetFlagConnless = 8
|
||||||
|
)
|
||||||
|
|
||||||
|
type PacketFlags struct {
|
||||||
|
Connless bool
|
||||||
|
Compression bool
|
||||||
|
Resend bool
|
||||||
|
Control bool
|
||||||
|
}
|
||||||
|
|
||||||
|
type PacketHeader struct {
|
||||||
|
Flags PacketFlags
|
||||||
|
Ack int
|
||||||
|
NumChunks int
|
||||||
|
Token [4]byte
|
||||||
|
}
|
||||||
|
|
||||||
|
func (header *PacketHeader) Unpack(packet []byte) {
|
||||||
|
header.Flags.Unpack(packet)
|
||||||
|
header.Ack = (int(packet[0]&0x3) << 8) | int(packet[1])
|
||||||
|
header.NumChunks = int(packet[2])
|
||||||
|
copy(header.Token[:], packet[3:7])
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *PacketFlags) Unpack(packetHeaderRaw []byte) {
|
||||||
|
flagBits := packetHeaderRaw[0] >> 2
|
||||||
|
flags.Control = (flagBits & packetFlagControl) != 0
|
||||||
|
flags.Resend = (flagBits & packetFlagResend) != 0
|
||||||
|
flags.Compression = (flagBits & packetFlagCompression) != 0
|
||||||
|
flags.Connless = (flagBits & packetFlagConnless) != 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (flags *PacketFlags) Pack() []byte {
|
||||||
|
data := 0
|
||||||
|
|
||||||
|
if flags.Control {
|
||||||
|
data |= packetFlagControl
|
||||||
|
}
|
||||||
|
if flags.Resend {
|
||||||
|
data |= packetFlagResend
|
||||||
|
}
|
||||||
|
if flags.Compression {
|
||||||
|
data |= packetFlagCompression
|
||||||
|
}
|
||||||
|
if flags.Connless {
|
||||||
|
data |= packetFlagConnless
|
||||||
|
}
|
||||||
|
|
||||||
|
return []byte{byte(data)}
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package main
|
package packet
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"reflect"
|
"reflect"
|
||||||
|
@ -10,13 +10,13 @@ import (
|
||||||
|
|
||||||
func TestPackFlagsUnset(t *testing.T) {
|
func TestPackFlagsUnset(t *testing.T) {
|
||||||
flags := PacketFlags{
|
flags := PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: false,
|
Compression: false,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: false,
|
Control: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
got := flags.pack()
|
got := flags.Pack()
|
||||||
want := []byte{0b0000}
|
want := []byte{0b0000}
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
@ -26,13 +26,13 @@ func TestPackFlagsUnset(t *testing.T) {
|
||||||
|
|
||||||
func TestPackFlagsCompressionSet(t *testing.T) {
|
func TestPackFlagsCompressionSet(t *testing.T) {
|
||||||
flags := PacketFlags{
|
flags := PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: true,
|
Compression: true,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: false,
|
Control: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
got := flags.pack()
|
got := flags.Pack()
|
||||||
want := []byte{0b0100}
|
want := []byte{0b0100}
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
@ -42,13 +42,13 @@ func TestPackFlagsCompressionSet(t *testing.T) {
|
||||||
|
|
||||||
func TestPackFlagsAllSet(t *testing.T) {
|
func TestPackFlagsAllSet(t *testing.T) {
|
||||||
flags := PacketFlags{
|
flags := PacketFlags{
|
||||||
connless: true,
|
Connless: true,
|
||||||
compression: true,
|
Compression: true,
|
||||||
resend: true,
|
Resend: true,
|
||||||
control: true,
|
Control: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
got := flags.pack()
|
got := flags.Pack()
|
||||||
want := []byte{0b1111}
|
want := []byte{0b1111}
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
|
@ -61,13 +61,13 @@ func TestPackFlagsAllSet(t *testing.T) {
|
||||||
func TestUnpackFlagsAllSet(t *testing.T) {
|
func TestUnpackFlagsAllSet(t *testing.T) {
|
||||||
got := PacketFlags{}
|
got := PacketFlags{}
|
||||||
want := PacketFlags{
|
want := PacketFlags{
|
||||||
connless: true,
|
Connless: true,
|
||||||
compression: true,
|
Compression: true,
|
||||||
resend: true,
|
Resend: true,
|
||||||
control: true,
|
Control: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack([]byte{0b00111100})
|
got.Unpack([]byte{0b00111100})
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
||||||
|
@ -77,13 +77,13 @@ func TestUnpackFlagsAllSet(t *testing.T) {
|
||||||
func TestUnpackFlagsControlSet(t *testing.T) {
|
func TestUnpackFlagsControlSet(t *testing.T) {
|
||||||
got := PacketFlags{}
|
got := PacketFlags{}
|
||||||
want := PacketFlags{
|
want := PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: false,
|
Compression: false,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: true,
|
Control: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack([]byte{0b00000100})
|
got.Unpack([]byte{0b00000100})
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
||||||
|
@ -93,13 +93,13 @@ func TestUnpackFlagsControlSet(t *testing.T) {
|
||||||
func TestUnpackFlagsUnset(t *testing.T) {
|
func TestUnpackFlagsUnset(t *testing.T) {
|
||||||
got := PacketFlags{}
|
got := PacketFlags{}
|
||||||
want := PacketFlags{
|
want := PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: false,
|
Compression: false,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: false,
|
Control: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack([]byte{0b00000000})
|
got.Unpack([]byte{0b00000000})
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
||||||
|
@ -111,18 +111,18 @@ func TestUnpackFlagsUnset(t *testing.T) {
|
||||||
func TestUnpackCloseWithReason(t *testing.T) {
|
func TestUnpackCloseWithReason(t *testing.T) {
|
||||||
got := PacketHeader{}
|
got := PacketHeader{}
|
||||||
want := PacketHeader{
|
want := PacketHeader{
|
||||||
flags: PacketFlags{
|
Flags: PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: false,
|
Compression: false,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: true,
|
Control: true,
|
||||||
},
|
},
|
||||||
ack: 10,
|
Ack: 10,
|
||||||
numChunks: 0,
|
NumChunks: 0,
|
||||||
token: [4]byte{0xcf, 0x2e, 0xde, 0x1d},
|
Token: [4]byte{0xcf, 0x2e, 0xde, 0x1d},
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack(slices.Concat([]byte{0x04, 0x0a, 0x00, 0xcf, 0x2e, 0xde, 0x1d, 0x04}, []byte("shutdown"), []byte{0x00}))
|
got.Unpack(slices.Concat([]byte{0x04, 0x0a, 0x00, 0xcf, 0x2e, 0xde, 0x1d, 0x04}, []byte("shutdown"), []byte{0x00}))
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
||||||
|
@ -132,18 +132,18 @@ func TestUnpackCloseWithReason(t *testing.T) {
|
||||||
func TestUnpackHeaderFlagsControlSet(t *testing.T) {
|
func TestUnpackHeaderFlagsControlSet(t *testing.T) {
|
||||||
got := PacketHeader{}
|
got := PacketHeader{}
|
||||||
want := PacketHeader{
|
want := PacketHeader{
|
||||||
flags: PacketFlags{
|
Flags: PacketFlags{
|
||||||
connless: false,
|
Connless: false,
|
||||||
compression: false,
|
Compression: false,
|
||||||
resend: false,
|
Resend: false,
|
||||||
control: true,
|
Control: true,
|
||||||
},
|
},
|
||||||
ack: 0,
|
Ack: 0,
|
||||||
numChunks: 0,
|
NumChunks: 0,
|
||||||
token: [4]byte{0xff, 0xff, 0xff, 0xff},
|
Token: [4]byte{0xff, 0xff, 0xff, 0xff},
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack([]byte{0b00000100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
|
got.Unpack([]byte{0b00000100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
||||||
|
@ -153,18 +153,18 @@ func TestUnpackHeaderFlagsControlSet(t *testing.T) {
|
||||||
func TestUnpackHeaderFlagsAllSet(t *testing.T) {
|
func TestUnpackHeaderFlagsAllSet(t *testing.T) {
|
||||||
got := PacketHeader{}
|
got := PacketHeader{}
|
||||||
want := PacketHeader{
|
want := PacketHeader{
|
||||||
flags: PacketFlags{
|
Flags: PacketFlags{
|
||||||
connless: true,
|
Connless: true,
|
||||||
compression: true,
|
Compression: true,
|
||||||
resend: true,
|
Resend: true,
|
||||||
control: true,
|
Control: true,
|
||||||
},
|
},
|
||||||
ack: 0,
|
Ack: 0,
|
||||||
numChunks: 0,
|
NumChunks: 0,
|
||||||
token: [4]byte{0xff, 0xff, 0xff, 0xff},
|
Token: [4]byte{0xff, 0xff, 0xff, 0xff},
|
||||||
}
|
}
|
||||||
|
|
||||||
got.unpack([]byte{0b00111100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
|
got.Unpack([]byte{0b00111100, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff})
|
||||||
|
|
||||||
if !reflect.DeepEqual(got, want) {
|
if !reflect.DeepEqual(got, want) {
|
||||||
t.Errorf("got %v, wanted %v", got, want)
|
t.Errorf("got %v, wanted %v", got, want)
|
19
teeworlds.go
19
teeworlds.go
|
@ -8,6 +8,9 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"slices"
|
"slices"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/teeworlds-go/huffman"
|
||||||
|
"github.com/teeworlds-go/teeworlds/packet"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -160,7 +163,10 @@ func byteSliceToString(s []byte) string {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (client *TeeworldsClient) onMessage(data []byte) {
|
func (client *TeeworldsClient) onMessage(data []byte) {
|
||||||
if isCtrlMsg(data) {
|
header := packet.PacketHeader{}
|
||||||
|
header.Unpack(data)
|
||||||
|
|
||||||
|
if header.Flags.Control {
|
||||||
ctrlMsg := data[7]
|
ctrlMsg := data[7]
|
||||||
fmt.Printf("got ctrl msg %d\n", ctrlMsg)
|
fmt.Printf("got ctrl msg %d\n", ctrlMsg)
|
||||||
if ctrlMsg == msgCtrlToken {
|
if ctrlMsg == msgCtrlToken {
|
||||||
|
@ -181,10 +187,19 @@ func (client *TeeworldsClient) onMessage(data []byte) {
|
||||||
} else {
|
} else {
|
||||||
fmt.Printf("unknown control message: %x\n", data)
|
fmt.Printf("unknown control message: %x\n", data)
|
||||||
}
|
}
|
||||||
|
} else if header.Flags.Compression {
|
||||||
|
payload := data[8:]
|
||||||
|
fmt.Printf("got compressed data: %v\n", payload)
|
||||||
|
huff := huffman.Huffman{}
|
||||||
|
decompressed, err := huff.Decompress(payload)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("huffman error: %v\n", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
fmt.Printf("got decompressed: %v\n", decompressed)
|
||||||
} else if isMapChange(data) {
|
} else if isMapChange(data) {
|
||||||
fmt.Println("got map change")
|
fmt.Println("got map change")
|
||||||
client.sendReady()
|
client.sendReady()
|
||||||
|
|
||||||
} else if isConReady(data) {
|
} else if isConReady(data) {
|
||||||
fmt.Println("got ready")
|
fmt.Println("got ready")
|
||||||
client.sendStartInfo()
|
client.sendStartInfo()
|
||||||
|
|
Loading…
Reference in a new issue