Compare commits
10 commits
fc4a3becde
...
f6a0c56b9b
Author | SHA1 | Date | |
---|---|---|---|
ChillerDragon | f6a0c56b9b | ||
ChillerDragon | 94c6798e8b | ||
ChillerDragon | 0492ca26ec | ||
ChillerDragon | 01adf6a404 | ||
ChillerDragon | 6c36291648 | ||
ChillerDragon | 3ecb2a32aa | ||
ChillerDragon | 141865538f | ||
ChillerDragon | 0edc8b334b | ||
ChillerDragon | 72b008f6d8 | ||
ChillerDragon | 8acb893165 |
29
.github/workflows/main.yml
vendored
29
.github/workflows/main.yml
vendored
|
@ -31,7 +31,11 @@ jobs:
|
|||
go-version: '1.22'
|
||||
|
||||
- name: Build go snippets in readme
|
||||
run: ./scripts/compile_readme_snippets.sh
|
||||
run: |
|
||||
mkdir -p ~/.local/bin/
|
||||
wget -O ~/.local/bin/lintdown.sh https://raw.githubusercontent.com/ChillerDragon/lintdown.sh/master/lintdown.sh
|
||||
chmod +x ~/.local/bin/lintdown.sh
|
||||
lintdown.sh README.md
|
||||
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
@ -58,3 +62,26 @@ jobs:
|
|||
|
||||
- name: Format
|
||||
run: diff -u <(echo -n) <(gofmt -d ./)
|
||||
|
||||
|
||||
teeworlds:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Check game messages
|
||||
run: |
|
||||
if errors="$(grep -FA1 'System()' $(grep MsgGame -lr messages7/) | grep "return true")"
|
||||
then
|
||||
printf '%s\n' "$errors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Check system messages
|
||||
run: |
|
||||
if errors="$(grep -FA1 'System()' $(grep MsgSys -lr messages7/) | grep "return false")"
|
||||
then
|
||||
printf '%s\n' "$errors"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
27
.github/workflows/shell.yml
vendored
27
.github/workflows/shell.yml
vendored
|
@ -1,27 +0,0 @@
|
|||
name: Shell
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "master" ]
|
||||
pull_request:
|
||||
branches: [ "master" ]
|
||||
|
||||
jobs:
|
||||
bash:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Prepare
|
||||
run: |
|
||||
sudo apt-get update -y
|
||||
sudo apt-get install shellcheck
|
||||
mkdir -p ~/.local/bin/
|
||||
wget -O ~/.local/bin/shfmt https://github.com/mvdan/sh/releases/download/v3.8.0/shfmt_v3.8.0_linux_amd64
|
||||
chmod +x ~/.local/bin/shfmt
|
||||
|
||||
- name: Shellcheck
|
||||
run: find . -type f -name '*.sh' -print0 | xargs -0 shellcheck
|
||||
- name: Shell format (shfmt)
|
||||
run: find . -type f -name '*.sh' -print0 | xargs -0 shfmt -d
|
||||
|
|
@ -1,5 +1,11 @@
|
|||
package chunk7
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
const (
|
||||
chunkFlagVital = 1
|
||||
chunkFlagResend = 2
|
||||
|
@ -49,13 +55,49 @@ func (header *ChunkHeader) Pack() []byte {
|
|||
return data
|
||||
}
|
||||
|
||||
func (header *ChunkHeader) Unpack(data []byte) {
|
||||
func (header *ChunkHeader) Unpack(u *packer.Unpacker) error {
|
||||
data, err := u.GetRaw(2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
flagBits := (data[0] >> 6) & 0x03
|
||||
header.Flags.Vital = (flagBits & chunkFlagVital) != 0
|
||||
header.Flags.Resend = (flagBits & chunkFlagResend) != 0
|
||||
header.Size = (int(data[0]&0x3F) << 6) | (int(data[1]) & 0x3F)
|
||||
|
||||
if header.Flags.Vital {
|
||||
thirdByte, err := u.GetByte()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Seq = int((data[1]&0xC0)<<2) | int(thirdByte)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// TODO: give this a better name
|
||||
//
|
||||
// but it would be nice to have two unpack methods for all structs
|
||||
//
|
||||
// Unpack(u *packer.Unpacker)
|
||||
// UnpackTodoFindAGoodName(data []byte)
|
||||
//
|
||||
// See https://github.com/teeworlds-go/go-teeworlds-protocol/issues/5
|
||||
func (header *ChunkHeader) UnpackRaw(data []byte) error {
|
||||
if len(data) < 2 {
|
||||
return fmt.Errorf("size=%d not enough data to read chunk header", len(data))
|
||||
}
|
||||
|
||||
flagBits := (data[0] >> 6) & 0x03
|
||||
header.Flags.Vital = (flagBits & chunkFlagVital) != 0
|
||||
header.Flags.Resend = (flagBits & chunkFlagResend) != 0
|
||||
header.Size = (int(data[0]&0x3F) << 6) | (int(data[1]) & 0x3F)
|
||||
|
||||
if header.Flags.Vital {
|
||||
if len(data) < 3 {
|
||||
return fmt.Errorf("size=%d not enough data to read vital chunk header", len(data))
|
||||
}
|
||||
header.Seq = int((data[1]&0xC0)<<2) | int(data[2])
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ func TestBrokenNonVitalHeader(t *testing.T) {
|
|||
|
||||
header := ChunkHeader{}
|
||||
// {0x40, 0x3a, 0x01}
|
||||
header.Unpack([]byte{0x3a, 0x01})
|
||||
header.UnpackRaw([]byte{0x3a, 0x01})
|
||||
|
||||
want := ChunkHeader{
|
||||
Flags: ChunkFlags{
|
||||
|
@ -33,7 +33,7 @@ func TestVitalHeaderMapChange(t *testing.T) {
|
|||
// verified with libtw2 wireshark dissector
|
||||
|
||||
header := ChunkHeader{}
|
||||
header.Unpack([]byte{0x40, 0x3a, 0x01})
|
||||
header.UnpackRaw([]byte{0x40, 0x3a, 0x01})
|
||||
|
||||
want := ChunkHeader{
|
||||
Flags: ChunkFlags{
|
||||
|
@ -51,7 +51,7 @@ func TestVitalHeaderMapChange(t *testing.T) {
|
|||
|
||||
func TestVitalHeader(t *testing.T) {
|
||||
header := ChunkHeader{}
|
||||
header.Unpack([]byte{0x40, 0x10, 0x0a})
|
||||
header.UnpackRaw([]byte{0x40, 0x10, 0x0a})
|
||||
want := ChunkHeader{
|
||||
Flags: ChunkFlags{
|
||||
Vital: true,
|
||||
|
|
|
@ -11,7 +11,8 @@ func UnpackChunks(data []byte) []Chunk {
|
|||
|
||||
for i < payloadSize {
|
||||
chunk := Chunk{}
|
||||
chunk.Header.Unpack(data[i:])
|
||||
// TODO: can we use ChunkHeader.Unpack(u) here to simplify the code?
|
||||
chunk.Header.UnpackRaw(data[i:])
|
||||
i += 2 // header
|
||||
if chunk.Header.Flags.Vital {
|
||||
i++
|
||||
|
|
|
@ -60,8 +60,12 @@ func main() {
|
|||
})
|
||||
|
||||
// if you do not implement OnError it will throw on error
|
||||
client.OnError(func(err error) {
|
||||
client.OnError(func(err error) bool {
|
||||
fmt.Print(err)
|
||||
|
||||
// return false to consume the error
|
||||
// return true to pass it on to the next error handler (likely throws in the end)
|
||||
return false
|
||||
})
|
||||
|
||||
go func() {
|
||||
|
|
|
@ -43,7 +43,7 @@ func (msg *ClSay) Pack() []byte {
|
|||
func (msg *ClSay) Unpack(u *packer.Unpacker) error {
|
||||
msg.Mode = network7.ChatMode(u.GetInt())
|
||||
msg.TargetId = u.GetInt()
|
||||
msg.Message = u.GetString()
|
||||
msg.Message, _ = u.GetString()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -77,15 +77,15 @@ func (msg *ClStartInfo) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *ClStartInfo) Unpack(u *packer.Unpacker) error {
|
||||
msg.Name = u.GetString()
|
||||
msg.Clan = u.GetString()
|
||||
msg.Name, _ = u.GetString()
|
||||
msg.Clan, _ = u.GetString()
|
||||
msg.Country = u.GetInt()
|
||||
msg.Body = u.GetString()
|
||||
msg.Marking = u.GetString()
|
||||
msg.Decoration = u.GetString()
|
||||
msg.Hands = u.GetString()
|
||||
msg.Feet = u.GetString()
|
||||
msg.Eyes = u.GetString()
|
||||
msg.Body, _ = u.GetString()
|
||||
msg.Marking, _ = u.GetString()
|
||||
msg.Decoration, _ = u.GetString()
|
||||
msg.Hands, _ = u.GetString()
|
||||
msg.Feet, _ = u.GetString()
|
||||
msg.Eyes, _ = u.GetString()
|
||||
msg.CustomColorBody = u.GetInt() != 0
|
||||
msg.CustomColorMarking = u.GetInt() != 0
|
||||
msg.CustomColorDecoration = u.GetInt() != 0
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *CtrlClose) Pack() []byte {
|
|||
|
||||
func (msg *CtrlClose) Unpack(u *packer.Unpacker) error {
|
||||
// TODO: sanitize
|
||||
msg.Reason = u.GetString()
|
||||
msg.Reason, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -59,8 +59,8 @@ func (msg *Info) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *Info) Unpack(u *packer.Unpacker) error {
|
||||
msg.Version = u.GetString()
|
||||
msg.Password = u.GetString()
|
||||
msg.Version, _ = u.GetString()
|
||||
msg.Password, _ = u.GetString()
|
||||
msg.ClientVersion = u.GetInt()
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ func (msg *MapChange) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *MapChange) Unpack(u *packer.Unpacker) error {
|
||||
msg.Name = u.GetString()
|
||||
msg.Name, _ = u.GetString()
|
||||
msg.Crc = u.GetInt()
|
||||
msg.Size = u.GetInt()
|
||||
msg.NumResponseChunksPerRequest = u.GetInt()
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *MaplistEntryAdd) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *MaplistEntryAdd) Unpack(u *packer.Unpacker) error {
|
||||
msg.MapName = u.GetString()
|
||||
msg.MapName, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *MaplistEntryRem) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *MaplistEntryRem) Unpack(u *packer.Unpacker) error {
|
||||
msg.MapName = u.GetString()
|
||||
msg.MapName, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *RconAuth) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *RconAuth) Unpack(u *packer.Unpacker) error {
|
||||
msg.Password = u.GetString()
|
||||
msg.Password, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *RconCmd) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *RconCmd) Unpack(u *packer.Unpacker) error {
|
||||
msg.Command = u.GetString()
|
||||
msg.Command, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -41,9 +41,9 @@ func (msg *RconCmdAdd) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *RconCmdAdd) Unpack(u *packer.Unpacker) error {
|
||||
msg.Name = u.GetString()
|
||||
msg.Help = u.GetString()
|
||||
msg.Params = u.GetString()
|
||||
msg.Name, _ = u.GetString()
|
||||
msg.Help, _ = u.GetString()
|
||||
msg.Params, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *RconCmdRem) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *RconCmdRem) Unpack(u *packer.Unpacker) error {
|
||||
msg.Name = u.GetString()
|
||||
msg.Name, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *RconLine) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *RconLine) Unpack(u *packer.Unpacker) error {
|
||||
msg.Line = u.GetString()
|
||||
msg.Line, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -57,11 +57,11 @@ func (msg *ServerInfo) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *ServerInfo) Unpack(u *packer.Unpacker) error {
|
||||
msg.Version = u.GetString()
|
||||
msg.Name = u.GetString()
|
||||
msg.Hostname = u.GetString()
|
||||
msg.MapName = u.GetString()
|
||||
msg.GameType = u.GetString()
|
||||
msg.Version, _ = u.GetString()
|
||||
msg.Name, _ = u.GetString()
|
||||
msg.Hostname, _ = u.GetString()
|
||||
msg.MapName, _ = u.GetString()
|
||||
msg.GameType, _ = u.GetString()
|
||||
msg.Flags = u.GetInt()
|
||||
msg.SkillLevel = u.GetInt()
|
||||
msg.PlayerCount = u.GetInt()
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"github.com/teeworlds-go/go-teeworlds-protocol/chunk7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/snapshot7"
|
||||
)
|
||||
|
||||
type SnapSingle struct {
|
||||
|
@ -15,7 +16,11 @@ type SnapSingle struct {
|
|||
DeltaTick int
|
||||
Crc int
|
||||
PartSize int
|
||||
Data []byte
|
||||
|
||||
// TODO: remove data when snapshot packing works
|
||||
// as of right now Data and Snapshot are the same thing
|
||||
Data []byte
|
||||
Snapshot snapshot7.Snapshot
|
||||
}
|
||||
|
||||
func (msg *SnapSingle) MsgId() int {
|
||||
|
@ -50,6 +55,14 @@ func (msg *SnapSingle) Unpack(u *packer.Unpacker) error {
|
|||
msg.Crc = u.GetInt()
|
||||
msg.PartSize = u.GetInt()
|
||||
msg.Data = u.Rest()
|
||||
|
||||
// genius
|
||||
u.Reset(msg.Data)
|
||||
err := msg.Snapshot.Unpack(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -33,7 +33,7 @@ func (msg *SvBroadcast) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *SvBroadcast) Unpack(u *packer.Unpacker) error {
|
||||
msg.Message = u.GetString()
|
||||
msg.Message, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ func (msg *SvChat) Unpack(u *packer.Unpacker) error {
|
|||
msg.Mode = network7.ChatMode(u.GetInt())
|
||||
msg.ClientId = u.GetInt()
|
||||
msg.TargetId = u.GetInt()
|
||||
msg.Message = u.GetString()
|
||||
msg.Message, _ = u.GetString()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -86,15 +86,15 @@ func (info *SvClientInfo) Unpack(u *packer.Unpacker) error {
|
|||
info.ClientId = u.GetInt()
|
||||
info.Local = u.GetInt() != 0
|
||||
info.Team = u.GetInt()
|
||||
info.Name = u.GetString()
|
||||
info.Clan = u.GetString()
|
||||
info.Name, _ = u.GetString()
|
||||
info.Clan, _ = u.GetString()
|
||||
info.Country = u.GetInt()
|
||||
info.Body = u.GetString()
|
||||
info.Marking = u.GetString()
|
||||
info.Decoration = u.GetString()
|
||||
info.Hands = u.GetString()
|
||||
info.Feet = u.GetString()
|
||||
info.Eyes = u.GetString()
|
||||
info.Body, _ = u.GetString()
|
||||
info.Marking, _ = u.GetString()
|
||||
info.Decoration, _ = u.GetString()
|
||||
info.Hands, _ = u.GetString()
|
||||
info.Feet, _ = u.GetString()
|
||||
info.Eyes, _ = u.GetString()
|
||||
info.CustomColorBody = u.GetInt() != 0
|
||||
info.CustomColorMarking = u.GetInt() != 0
|
||||
info.CustomColorDecoration = u.GetInt() != 0
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
type SvEmoticon struct {
|
||||
ChunkHeader *chunk7.ChunkHeader
|
||||
|
||||
ClientId int
|
||||
Emoticon network7.Emote
|
||||
}
|
||||
|
||||
|
@ -32,11 +33,13 @@ func (msg *SvEmoticon) Vital() bool {
|
|||
|
||||
func (msg *SvEmoticon) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(msg.ClientId),
|
||||
packer.PackInt(int(msg.Emoticon)),
|
||||
)
|
||||
}
|
||||
|
||||
func (msg *SvEmoticon) Unpack(u *packer.Unpacker) error {
|
||||
msg.ClientId = u.GetInt()
|
||||
msg.Emoticon = network7.Emote(u.GetInt())
|
||||
|
||||
return nil
|
||||
|
|
88
messages7/sv_emoticon_test.go
Normal file
88
messages7/sv_emoticon_test.go
Normal file
|
@ -0,0 +1,88 @@
|
|||
package messages7_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||
)
|
||||
|
||||
func TestFullPacket(t *testing.T) {
|
||||
packet := protocol7.Packet{}
|
||||
packet.Messages = append(
|
||||
packet.Messages,
|
||||
&messages7.SvEmoticon{
|
||||
ClientId: 0,
|
||||
Emoticon: network7.EmoteGhost,
|
||||
},
|
||||
)
|
||||
|
||||
{
|
||||
// if this test breaks because the session tokens are actually used
|
||||
// this is not necessarily a bad thing
|
||||
session := &protocol7.Session{
|
||||
ServerToken: [4]byte{0x55, 0x55, 0x55, 0x55},
|
||||
ClientToken: [4]byte{0xfa, 0xfa, 0xfa, 0xfa},
|
||||
}
|
||||
|
||||
want := []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x40, 0x03, 0x01, 0x14, 0x00, 0x07}
|
||||
got := packet.Pack(session)
|
||||
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSvEmoticonStandalone(t *testing.T) {
|
||||
// simple pack
|
||||
emoticon := &messages7.SvEmoticon{
|
||||
ClientId: 0,
|
||||
Emoticon: network7.EmoteExclamation,
|
||||
}
|
||||
|
||||
{
|
||||
want := []byte{0x00, 0x01}
|
||||
got := emoticon.Pack()
|
||||
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
// repack
|
||||
u := &packer.Unpacker{}
|
||||
u.Reset(emoticon.Pack())
|
||||
emoticon.Unpack(u)
|
||||
|
||||
{
|
||||
want := network7.EmoteExclamation
|
||||
got := emoticon.Emoticon
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSvEmoticonStandaloneCrazyGirlEdition(t *testing.T) {
|
||||
// simple pack
|
||||
emoticon := &messages7.SvEmoticon{
|
||||
ClientId: -99999,
|
||||
Emoticon: 999,
|
||||
}
|
||||
|
||||
{
|
||||
want := []byte{222, 154, 12, 167, 15}
|
||||
got := emoticon.Pack()
|
||||
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
// repack
|
||||
u := &packer.Unpacker{}
|
||||
u.Reset(emoticon.Pack())
|
||||
emoticon.Unpack(u)
|
||||
|
||||
{
|
||||
want := network7.Emote(999)
|
||||
got := emoticon.Emoticon
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
|
@ -33,7 +33,7 @@ func (msg *SvMotd) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *SvMotd) Unpack(u *packer.Unpacker) error {
|
||||
msg.Message = u.GetString()
|
||||
msg.Message, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ func (msg *SvVoteOptionAdd) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *SvVoteOptionAdd) Unpack(u *packer.Unpacker) error {
|
||||
msg.Description = u.GetString()
|
||||
msg.Description, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ func (msg *SvVoteOptionListAdd) Unpack(u *packer.Unpacker) error {
|
|||
msg.NumOptions = u.GetInt()
|
||||
msg.Descriptions = make([]string, msg.NumOptions)
|
||||
for i := 0; i < msg.NumOptions; i++ {
|
||||
msg.Descriptions[i] = u.GetString()
|
||||
msg.Descriptions[i], _ = u.GetString()
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
37
messages7/sv_vote_option_list_add_test.go
Normal file
37
messages7/sv_vote_option_list_add_test.go
Normal file
|
@ -0,0 +1,37 @@
|
|||
package messages7_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/chunk7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
func TestVoteListAdd(t *testing.T) {
|
||||
// unpack
|
||||
fullChunk := []byte{0x40, 0x06, 0x06, 0x18, 0x01, 0x66, 0x6f, 0x6f, 0x00}
|
||||
u := &packer.Unpacker{}
|
||||
u.Reset(fullChunk)
|
||||
|
||||
header := &chunk7.ChunkHeader{}
|
||||
header.Unpack(u)
|
||||
|
||||
msg, sys, err := u.GetMsgAndSys()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, network7.MsgGameSvVoteOptionListAdd, msg)
|
||||
require.Equal(t, false, sys)
|
||||
|
||||
listAdd := &messages7.SvVoteOptionListAdd{ChunkHeader: header}
|
||||
listAdd.Unpack(u)
|
||||
|
||||
require.Equal(t, 1, listAdd.NumOptions)
|
||||
require.Equal(t, 1, len(listAdd.Descriptions))
|
||||
require.Equal(t, "foo", listAdd.Descriptions[0])
|
||||
require.Equal(t, 0, u.RemainingSize())
|
||||
|
||||
// pack
|
||||
require.Equal(t, []byte{1, 'f', 'o', 'o', 0x00}, listAdd.Pack())
|
||||
}
|
|
@ -37,7 +37,7 @@ func (msg *SvVoteOptionRemove) Pack() []byte {
|
|||
}
|
||||
|
||||
func (msg *SvVoteOptionRemove) Unpack(u *packer.Unpacker) error {
|
||||
msg.Description = u.GetString()
|
||||
msg.Description, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -48,8 +48,8 @@ func (msg *SvVoteSet) Unpack(u *packer.Unpacker) error {
|
|||
msg.ClientId = u.GetInt()
|
||||
msg.Type = network7.Vote(u.GetInt())
|
||||
msg.Timeout = u.GetInt()
|
||||
msg.Description = u.GetString()
|
||||
msg.Reason = u.GetString()
|
||||
msg.Description, _ = u.GetString()
|
||||
msg.Reason, _ = u.GetString()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
26
network6/network6.go
Normal file
26
network6/network6.go
Normal file
|
@ -0,0 +1,26 @@
|
|||
package network6
|
||||
|
||||
const (
|
||||
ObjInvalid = 0
|
||||
ObjPlayerInput = 1
|
||||
ObjProjectile = 2
|
||||
ObjLaser = 3
|
||||
ObjPickup = 4
|
||||
ObjFlag = 5
|
||||
ObjGameInfo = 6
|
||||
ObjGameData = 7
|
||||
ObjCharacterCore = 8
|
||||
ObjCharacter = 9
|
||||
ObjPlayerInfo = 10
|
||||
ObjClientInfo = 11
|
||||
ObjSpectatorInfo = 12
|
||||
ObjCommon = 13
|
||||
ObjExplosion = 14
|
||||
ObjSpawn = 15
|
||||
ObjHammerhit = 16
|
||||
ObjDeath = 17
|
||||
ObjSoundGlobal = 18
|
||||
ObjSoundWorld = 19
|
||||
ObjDamageInd = 20
|
||||
NumSnapObjects = 21
|
||||
)
|
|
@ -13,6 +13,11 @@ const (
|
|||
TeamRed GameTeam = 0
|
||||
TeamBlue GameTeam = 1
|
||||
|
||||
SpecFreeview Spec = 0
|
||||
SpecPlayer Spec = 1
|
||||
SpecFlagred Spec = 2
|
||||
SpecFlagblue Spec = 3
|
||||
|
||||
VoteUnknown Vote = 0
|
||||
VoteStartOp Vote = 1
|
||||
VoteStartKick Vote = 2
|
||||
|
@ -21,6 +26,22 @@ const (
|
|||
VoteEndPass Vote = 5
|
||||
VoteEndFail Vote = 6
|
||||
|
||||
PickupHealth Pickup = 0
|
||||
PickupArmor Pickup = 1
|
||||
PickupGrenade Pickup = 2
|
||||
PickupShotgun Pickup = 3
|
||||
PickupLaser Pickup = 4
|
||||
PickupNinja Pickup = 5
|
||||
PickupGun Pickup = 6
|
||||
PickupHammer Pickup = 7
|
||||
|
||||
GamestateflagWarmup GameStateFlag = 1
|
||||
GamestateflagSuddendeath GameStateFlag = 2
|
||||
GamestateflagRoundover GameStateFlag = 4
|
||||
GamestateflagGameover GameStateFlag = 8
|
||||
GamestateflagPaused GameStateFlag = 16
|
||||
GamestateflagStartcountdown GameStateFlag = 32
|
||||
|
||||
// oop!
|
||||
EmoteOop Emote = 0
|
||||
// !
|
||||
|
@ -53,6 +74,33 @@ const (
|
|||
MsgCtrlToken = 0x05
|
||||
MsgCtrlClose = 0x04
|
||||
|
||||
ObjInvalid = 0
|
||||
ObjPlayerInput = 1
|
||||
ObjProjectile = 2
|
||||
ObjLaser = 3
|
||||
ObjPickup = 4
|
||||
ObjFlag = 5
|
||||
ObjGameData = 6
|
||||
ObjGameDataTeam = 7
|
||||
ObjGameDataFlag = 8
|
||||
ObjCharacterCore = 9
|
||||
ObjCharacter = 10
|
||||
ObjPlayerInfo = 11
|
||||
ObjSpectatorInfo = 12
|
||||
ObjDeClientInfo = 13
|
||||
ObjDeGameInfo = 14
|
||||
ObjDeTuneParams = 15
|
||||
ObjCommon = 16
|
||||
ObjExplosion = 17
|
||||
ObjSpawn = 18
|
||||
ObjHammerHit = 19
|
||||
ObjDeath = 20
|
||||
ObjSoundWorld = 21
|
||||
ObjDamage = 22
|
||||
ObjPlayerInfoRace = 23
|
||||
ObjGameDataRace = 24
|
||||
NumNetobjtypes = 25
|
||||
|
||||
// TODO: these should preferrably all be devide dinto different type dintegers
|
||||
// same as ChatMode, etc. so that the user can easily see which integer to pass
|
||||
// to which function as which parameter
|
||||
|
@ -147,7 +195,10 @@ const (
|
|||
NumWeapons Weapon = 6
|
||||
)
|
||||
|
||||
type GameStateFlag int
|
||||
type Spec int
|
||||
type Vote int
|
||||
type Pickup int
|
||||
type Emote int
|
||||
type ChatMode int
|
||||
type GameTeam int
|
||||
|
|
105
object7/character.go
Normal file
105
object7/character.go
Normal file
|
@ -0,0 +1,105 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Character struct {
|
||||
ItemId int
|
||||
|
||||
Tick int
|
||||
X int
|
||||
Y int
|
||||
VelX int
|
||||
VelY int
|
||||
Angle int
|
||||
Direction int
|
||||
Jumped int
|
||||
HookedPlayer int
|
||||
HookState int
|
||||
HookTick int
|
||||
HookX int
|
||||
HookY int
|
||||
HookDx int
|
||||
HookDy int
|
||||
Health int
|
||||
Armor int
|
||||
AmmoCount int
|
||||
Weapon int
|
||||
Emote int
|
||||
AttackTick int
|
||||
TriggeredEvents int
|
||||
}
|
||||
|
||||
func (o *Character) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Character) TypeId() int {
|
||||
return network7.ObjCharacter
|
||||
}
|
||||
|
||||
func (o *Character) Size() int {
|
||||
return reflect.TypeOf(Character{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Character) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.Tick),
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.VelX),
|
||||
packer.PackInt(o.VelY),
|
||||
packer.PackInt(o.Angle),
|
||||
packer.PackInt(o.Direction),
|
||||
packer.PackInt(o.Jumped),
|
||||
packer.PackInt(o.HookedPlayer),
|
||||
packer.PackInt(o.HookState),
|
||||
packer.PackInt(o.HookTick),
|
||||
packer.PackInt(o.HookX),
|
||||
packer.PackInt(o.HookY),
|
||||
packer.PackInt(o.HookDx),
|
||||
packer.PackInt(o.HookDy),
|
||||
packer.PackInt(o.Health),
|
||||
packer.PackInt(o.Armor),
|
||||
packer.PackInt(o.AmmoCount),
|
||||
packer.PackInt(o.Weapon),
|
||||
packer.PackInt(o.Emote),
|
||||
packer.PackInt(o.AttackTick),
|
||||
packer.PackInt(o.TriggeredEvents),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Character) Unpack(u *packer.Unpacker) error {
|
||||
o.Tick = u.GetInt()
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.VelX = u.GetInt()
|
||||
o.VelY = u.GetInt()
|
||||
o.Angle = u.GetInt()
|
||||
o.Direction = u.GetInt()
|
||||
o.Jumped = u.GetInt()
|
||||
o.HookedPlayer = u.GetInt()
|
||||
o.HookState = u.GetInt()
|
||||
o.HookTick = u.GetInt()
|
||||
o.HookX = u.GetInt()
|
||||
o.HookY = u.GetInt()
|
||||
o.HookDx = u.GetInt()
|
||||
o.HookDy = u.GetInt()
|
||||
o.Health = u.GetInt()
|
||||
o.Armor = u.GetInt()
|
||||
o.AmmoCount = u.GetInt()
|
||||
o.Weapon = u.GetInt()
|
||||
o.Emote = u.GetInt()
|
||||
o.AttackTick = u.GetInt()
|
||||
o.TriggeredEvents = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
64
object7/damage.go
Normal file
64
object7/damage.go
Normal file
|
@ -0,0 +1,64 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
// damage indicicator
|
||||
// displayed as yellow stars around the tee receiving damage
|
||||
type Damage struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
// affected player receiving damage
|
||||
ClientId int
|
||||
Angle int
|
||||
HealthAmount int
|
||||
ArmorAmount int
|
||||
// true if the damage receiver the damage dealer
|
||||
Self bool
|
||||
}
|
||||
|
||||
func (o *Damage) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Damage) TypeId() int {
|
||||
return network7.ObjDamage
|
||||
}
|
||||
|
||||
func (o *Damage) Size() int {
|
||||
return reflect.TypeOf(Damage{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Damage) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.ClientId),
|
||||
packer.PackInt(o.Angle),
|
||||
packer.PackInt(o.HealthAmount),
|
||||
packer.PackInt(o.ArmorAmount),
|
||||
packer.PackBool(o.Self),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Damage) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.ClientId = u.GetInt()
|
||||
o.Angle = u.GetInt()
|
||||
o.HealthAmount = u.GetInt()
|
||||
o.ArmorAmount = u.GetInt()
|
||||
o.Self = u.GetInt() != 0
|
||||
|
||||
return nil
|
||||
}
|
48
object7/death.go
Normal file
48
object7/death.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Death struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
ClientId int
|
||||
}
|
||||
|
||||
func (o *Death) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Death) TypeId() int {
|
||||
return network7.ObjDeath
|
||||
}
|
||||
|
||||
func (o *Death) Size() int {
|
||||
return reflect.TypeOf(Death{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Death) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.ClientId),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Death) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.ClientId = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
45
object7/explosion.go
Normal file
45
object7/explosion.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Explosion struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func (o *Explosion) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Explosion) TypeId() int {
|
||||
return network7.ObjExplosion
|
||||
}
|
||||
|
||||
func (o *Explosion) Size() int {
|
||||
return reflect.TypeOf(Explosion{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Explosion) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Explosion) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
48
object7/flag.go
Normal file
48
object7/flag.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Flag struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
Team network7.GameTeam
|
||||
}
|
||||
|
||||
func (o *Flag) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Flag) TypeId() int {
|
||||
return network7.ObjFlag
|
||||
}
|
||||
|
||||
func (o *Flag) Size() int {
|
||||
return reflect.TypeOf(Flag{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Flag) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(int(o.Team)),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Flag) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.Team = network7.GameTeam(u.GetInt())
|
||||
|
||||
return nil
|
||||
}
|
53
object7/game_data.go
Normal file
53
object7/game_data.go
Normal file
|
@ -0,0 +1,53 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type GameData struct {
|
||||
ItemId int
|
||||
|
||||
GameStartTick int
|
||||
// TODO: add struct to wrap these flags
|
||||
// use network7.GameStateFlag bit operations to turn it into a bunch of booleans
|
||||
|
||||
// GameStateFlags GameStateFlagsStruct
|
||||
FlagsRaw int
|
||||
|
||||
GameStateEndTick int
|
||||
}
|
||||
|
||||
func (o *GameData) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *GameData) TypeId() int {
|
||||
return network7.ObjGameData
|
||||
}
|
||||
|
||||
func (o *GameData) Size() int {
|
||||
return reflect.TypeOf(GameData{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *GameData) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.GameStartTick),
|
||||
packer.PackInt(o.FlagsRaw),
|
||||
packer.PackInt(o.GameStateEndTick),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *GameData) Unpack(u *packer.Unpacker) error {
|
||||
o.GameStartTick = u.GetInt()
|
||||
o.FlagsRaw = u.GetInt()
|
||||
o.GameStateEndTick = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
63
object7/game_data_flag.go
Normal file
63
object7/game_data_flag.go
Normal file
|
@ -0,0 +1,63 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type GameDataFlag struct {
|
||||
ItemId int
|
||||
|
||||
// It is either the client id of the carrier so 0-64 or one of those values
|
||||
//
|
||||
// -3 - FLAG_MISSING
|
||||
// -2 - FLAG_ATSTAND
|
||||
// -1 - FLAG_TAKEN
|
||||
FlagCarrierRed int
|
||||
|
||||
// It is either the client id of the carrier so 0-64 or one of those values
|
||||
//
|
||||
// -3 - FLAG_MISSING
|
||||
// -2 - FLAG_ATSTAND
|
||||
// -1 - FLAG_TAKEN
|
||||
FlagCarrierBlue int
|
||||
|
||||
FlagDropTickRed int
|
||||
FlagDropTickBlue int
|
||||
}
|
||||
|
||||
func (o *GameDataFlag) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *GameDataFlag) TypeId() int {
|
||||
return network7.ObjGameDataFlag
|
||||
}
|
||||
|
||||
func (o *GameDataFlag) Size() int {
|
||||
return reflect.TypeOf(GameDataFlag{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *GameDataFlag) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.FlagCarrierRed),
|
||||
packer.PackInt(o.FlagCarrierBlue),
|
||||
packer.PackInt(o.FlagDropTickRed),
|
||||
packer.PackInt(o.FlagDropTickBlue),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *GameDataFlag) Unpack(u *packer.Unpacker) error {
|
||||
o.FlagCarrierRed = u.GetInt()
|
||||
o.FlagCarrierBlue = u.GetInt()
|
||||
o.FlagDropTickRed = u.GetInt()
|
||||
o.FlagDropTickBlue = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
56
object7/game_data_race.go
Normal file
56
object7/game_data_race.go
Normal file
|
@ -0,0 +1,56 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
// this is a new snap item that was added after the 0.7 release
|
||||
// so for backwards compability it includes a size field
|
||||
// and older clients ignore it
|
||||
//
|
||||
// this message is not used by official servers
|
||||
// and is part of an effort to support community made race modifications
|
||||
type GameDataRace struct {
|
||||
ItemId int
|
||||
|
||||
BestTime int
|
||||
Precision int
|
||||
RaceFlags int
|
||||
}
|
||||
|
||||
func (o *GameDataRace) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *GameDataRace) TypeId() int {
|
||||
return network7.ObjGameDataRace
|
||||
}
|
||||
|
||||
func (o *GameDataRace) Size() int {
|
||||
// TODO: is this correct? is this just payload size or does it contain the size field as well?
|
||||
return reflect.TypeOf(GameDataRace{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *GameDataRace) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
packer.PackInt(o.Size()),
|
||||
|
||||
packer.PackInt(o.BestTime),
|
||||
packer.PackInt(o.Precision),
|
||||
packer.PackInt(o.RaceFlags),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *GameDataRace) Unpack(u *packer.Unpacker) error {
|
||||
o.BestTime = u.GetInt()
|
||||
o.Precision = u.GetInt()
|
||||
o.RaceFlags = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
45
object7/game_data_team.go
Normal file
45
object7/game_data_team.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type GameDataTeam struct {
|
||||
ItemId int
|
||||
|
||||
TeamscoreRed int
|
||||
TeamscoreBlue int
|
||||
}
|
||||
|
||||
func (o *GameDataTeam) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *GameDataTeam) TypeId() int {
|
||||
return network7.ObjGameDataTeam
|
||||
}
|
||||
|
||||
func (o *GameDataTeam) Size() int {
|
||||
return reflect.TypeOf(GameDataTeam{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *GameDataTeam) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.TeamscoreRed),
|
||||
packer.PackInt(o.TeamscoreBlue),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *GameDataTeam) Unpack(u *packer.Unpacker) error {
|
||||
o.TeamscoreRed = u.GetInt()
|
||||
o.TeamscoreBlue = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
45
object7/hammer_hit.go
Normal file
45
object7/hammer_hit.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type HammerHit struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func (o *HammerHit) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *HammerHit) TypeId() int {
|
||||
return network7.ObjHammerHit
|
||||
}
|
||||
|
||||
func (o *HammerHit) Size() int {
|
||||
return reflect.TypeOf(HammerHit{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *HammerHit) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *HammerHit) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
54
object7/laser.go
Normal file
54
object7/laser.go
Normal file
|
@ -0,0 +1,54 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Laser struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
FromX int
|
||||
FromY int
|
||||
StartTick int
|
||||
}
|
||||
|
||||
func (o *Laser) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Laser) TypeId() int {
|
||||
return network7.ObjLaser
|
||||
}
|
||||
|
||||
func (o *Laser) Size() int {
|
||||
return reflect.TypeOf(Laser{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Laser) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.FromX),
|
||||
packer.PackInt(o.FromY),
|
||||
packer.PackInt(o.StartTick),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Laser) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.FromX = u.GetInt()
|
||||
o.FromY = u.GetInt()
|
||||
o.StartTick = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
79
object7/laser_test.go
Normal file
79
object7/laser_test.go
Normal file
|
@ -0,0 +1,79 @@
|
|||
package object7_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/object7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
func TestLaserStandalone(t *testing.T) {
|
||||
// simple pack
|
||||
laser := &object7.Laser{
|
||||
ItemId: 1,
|
||||
X: 200,
|
||||
Y: 301,
|
||||
FromX: 20,
|
||||
FromY: 40,
|
||||
StartTick: 7812,
|
||||
}
|
||||
|
||||
{
|
||||
// this is not verified against anything
|
||||
want := []byte{3, 1, 136, 3, 173, 4, 20, 40, 132, 122}
|
||||
got := laser.Pack()
|
||||
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
// repack
|
||||
u := &packer.Unpacker{}
|
||||
u.Reset(laser.Pack())
|
||||
typeId := u.GetInt()
|
||||
require.Equal(t, network7.ObjLaser, typeId)
|
||||
itemId := u.GetInt()
|
||||
require.Equal(t, 1, itemId)
|
||||
laser.Unpack(u)
|
||||
|
||||
require.Equal(t, 200, laser.X)
|
||||
require.Equal(t, 301, laser.Y)
|
||||
require.Equal(t, 20, laser.FromX)
|
||||
require.Equal(t, 40, laser.FromY)
|
||||
require.Equal(t, 7812, laser.StartTick)
|
||||
}
|
||||
|
||||
func TestLaserStandaloneAllZeros(t *testing.T) {
|
||||
// simple pack
|
||||
laser := &object7.Laser{
|
||||
ItemId: 0,
|
||||
X: 0,
|
||||
Y: 0,
|
||||
FromX: 0,
|
||||
FromY: 0,
|
||||
StartTick: 0,
|
||||
}
|
||||
|
||||
{
|
||||
want := []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
|
||||
got := laser.Pack()
|
||||
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
// repack
|
||||
u := &packer.Unpacker{}
|
||||
u.Reset(laser.Pack())
|
||||
typeId := u.GetInt()
|
||||
require.Equal(t, network7.ObjLaser, typeId)
|
||||
itemId := u.GetInt()
|
||||
require.Equal(t, 0, itemId)
|
||||
laser.Unpack(u)
|
||||
|
||||
{
|
||||
want := 0
|
||||
got := laser.X
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
48
object7/pickup.go
Normal file
48
object7/pickup.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Pickup struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
Type network7.Pickup
|
||||
}
|
||||
|
||||
func (o *Pickup) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Pickup) TypeId() int {
|
||||
return network7.ObjPickup
|
||||
}
|
||||
|
||||
func (o *Pickup) Size() int {
|
||||
return reflect.TypeOf(Pickup{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Pickup) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(int(o.Type)),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Pickup) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.Type = network7.Pickup(u.GetInt())
|
||||
|
||||
return nil
|
||||
}
|
49
object7/player_info.go
Normal file
49
object7/player_info.go
Normal file
|
@ -0,0 +1,49 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type PlayerInfo struct {
|
||||
ItemId int
|
||||
|
||||
// TODO: parse flags
|
||||
PlayerFlags int
|
||||
Score int
|
||||
Latency int
|
||||
}
|
||||
|
||||
func (o *PlayerInfo) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *PlayerInfo) TypeId() int {
|
||||
return network7.ObjPlayerInfo
|
||||
}
|
||||
|
||||
func (o *PlayerInfo) Size() int {
|
||||
return reflect.TypeOf(PlayerInfo{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *PlayerInfo) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.PlayerFlags),
|
||||
packer.PackInt(o.Score),
|
||||
packer.PackInt(o.Latency),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *PlayerInfo) Unpack(u *packer.Unpacker) error {
|
||||
o.PlayerFlags = u.GetInt()
|
||||
o.Score = u.GetInt()
|
||||
o.Latency = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
50
object7/player_info_race.go
Normal file
50
object7/player_info_race.go
Normal file
|
@ -0,0 +1,50 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
// this is a new snap item that was added after the 0.7 release
|
||||
// so for backwards compability it includes a size field
|
||||
// and older clients ignore it
|
||||
//
|
||||
// this message is not used by official servers
|
||||
// and is part of an effort to support community made race modifications
|
||||
type PlayerInfoRace struct {
|
||||
ItemId int
|
||||
|
||||
RaceStartTick int
|
||||
}
|
||||
|
||||
func (o *PlayerInfoRace) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *PlayerInfoRace) TypeId() int {
|
||||
return network7.ObjPlayerInfoRace
|
||||
}
|
||||
|
||||
func (o *PlayerInfoRace) Size() int {
|
||||
// TODO: is this correct? is this just payload size or does it contain the size field as well?
|
||||
return reflect.TypeOf(PlayerInfoRace{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *PlayerInfoRace) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
packer.PackInt(o.Size()),
|
||||
|
||||
packer.PackInt(o.RaceStartTick),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *PlayerInfoRace) Unpack(u *packer.Unpacker) error {
|
||||
o.RaceStartTick = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
73
object7/player_input.go
Normal file
73
object7/player_input.go
Normal file
|
@ -0,0 +1,73 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
// this object is never included in the snap
|
||||
// the same order of ints is sent in the system message input
|
||||
//
|
||||
// but technically this item is unused
|
||||
type PlayerInput struct {
|
||||
ItemId int
|
||||
|
||||
Direction int
|
||||
TargetX int
|
||||
TargetY int
|
||||
Jump int
|
||||
Fire int
|
||||
Hook int
|
||||
PlayerFlags int
|
||||
WantedWeapon int
|
||||
NextWeapon int
|
||||
PrevWeapon int
|
||||
}
|
||||
|
||||
func (o *PlayerInput) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *PlayerInput) TypeId() int {
|
||||
return network7.ObjPlayerInput
|
||||
}
|
||||
|
||||
func (o *PlayerInput) Size() int {
|
||||
return reflect.TypeOf(PlayerInput{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *PlayerInput) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.Direction),
|
||||
packer.PackInt(o.TargetX),
|
||||
packer.PackInt(o.TargetY),
|
||||
packer.PackInt(o.Jump),
|
||||
packer.PackInt(o.Fire),
|
||||
packer.PackInt(o.Hook),
|
||||
packer.PackInt(o.PlayerFlags),
|
||||
packer.PackInt(o.WantedWeapon),
|
||||
packer.PackInt(o.NextWeapon),
|
||||
packer.PackInt(o.PrevWeapon),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *PlayerInput) Unpack(u *packer.Unpacker) error {
|
||||
o.Direction = u.GetInt()
|
||||
o.TargetX = u.GetInt()
|
||||
o.TargetY = u.GetInt()
|
||||
o.Jump = u.GetInt()
|
||||
o.Fire = u.GetInt()
|
||||
o.Hook = u.GetInt()
|
||||
o.PlayerFlags = u.GetInt()
|
||||
o.WantedWeapon = u.GetInt()
|
||||
o.NextWeapon = u.GetInt()
|
||||
o.PrevWeapon = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
57
object7/projectile.go
Normal file
57
object7/projectile.go
Normal file
|
@ -0,0 +1,57 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Projectile struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
VelX int
|
||||
VelY int
|
||||
Type int
|
||||
StartTick int
|
||||
}
|
||||
|
||||
func (o *Projectile) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Projectile) TypeId() int {
|
||||
return network7.ObjProjectile
|
||||
}
|
||||
|
||||
func (o *Projectile) Size() int {
|
||||
return reflect.TypeOf(Projectile{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Projectile) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.VelX),
|
||||
packer.PackInt(o.VelY),
|
||||
packer.PackInt(o.Type),
|
||||
packer.PackInt(o.StartTick),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Projectile) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.VelX = u.GetInt()
|
||||
o.VelY = u.GetInt()
|
||||
o.Type = u.GetInt()
|
||||
o.StartTick = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
70
object7/snap_object.go
Normal file
70
object7/snap_object.go
Normal file
|
@ -0,0 +1,70 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type SnapObject interface {
|
||||
// id separating this snap item from other items with same type
|
||||
// the ids are unique per type
|
||||
// for players it matches their ClientId
|
||||
Id() int
|
||||
|
||||
// type of the snap item
|
||||
TypeId() int
|
||||
|
||||
// number of packed integers
|
||||
// not the number of bytes
|
||||
Size() int
|
||||
|
||||
Pack() []byte
|
||||
Unpack(u *packer.Unpacker) error
|
||||
}
|
||||
|
||||
// Comes without payload
|
||||
// you have to call item.Unpack(u) manually after getting it
|
||||
func NewObject(typeId int, itemId int) SnapObject {
|
||||
if typeId == network7.ObjProjectile {
|
||||
return &Projectile{ItemId: itemId}
|
||||
} else if typeId == network7.ObjLaser {
|
||||
return &Laser{ItemId: itemId}
|
||||
} else if typeId == network7.ObjFlag {
|
||||
return &Flag{ItemId: itemId}
|
||||
} else if typeId == network7.ObjPickup {
|
||||
return &Pickup{ItemId: itemId}
|
||||
} else if typeId == network7.ObjGameData {
|
||||
return &GameData{ItemId: itemId}
|
||||
} else if typeId == network7.ObjGameDataTeam {
|
||||
return &GameDataTeam{ItemId: itemId}
|
||||
} else if typeId == network7.ObjGameDataFlag {
|
||||
return &GameDataFlag{ItemId: itemId}
|
||||
} else if typeId == network7.ObjCharacter {
|
||||
return &Character{ItemId: itemId}
|
||||
} else if typeId == network7.ObjPlayerInfo {
|
||||
return &PlayerInfo{ItemId: itemId}
|
||||
} else if typeId == network7.ObjSpectatorInfo {
|
||||
return &SpectatorInfo{ItemId: itemId}
|
||||
} else if typeId == network7.ObjExplosion {
|
||||
return &Explosion{ItemId: itemId}
|
||||
} else if typeId == network7.ObjSpawn {
|
||||
return &Spawn{ItemId: itemId}
|
||||
} else if typeId == network7.ObjHammerHit {
|
||||
return &HammerHit{ItemId: itemId}
|
||||
} else if typeId == network7.ObjDeath {
|
||||
return &Death{ItemId: itemId}
|
||||
} else if typeId == network7.ObjSoundWorld {
|
||||
return &SoundWorld{ItemId: itemId}
|
||||
} else if typeId == network7.ObjDamage {
|
||||
return &Damage{ItemId: itemId}
|
||||
}
|
||||
|
||||
// TODO: add this panic and remove it again once all tests pass
|
||||
// log.Panicf("unknown item type %d\n", typeId)
|
||||
|
||||
unknown := &Unknown{
|
||||
ItemId: itemId,
|
||||
ItemType: typeId,
|
||||
}
|
||||
return unknown
|
||||
}
|
48
object7/sound_world.go
Normal file
48
object7/sound_world.go
Normal file
|
@ -0,0 +1,48 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type SoundWorld struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
SoundId int
|
||||
}
|
||||
|
||||
func (o *SoundWorld) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *SoundWorld) TypeId() int {
|
||||
return network7.ObjSoundWorld
|
||||
}
|
||||
|
||||
func (o *SoundWorld) Size() int {
|
||||
return reflect.TypeOf(SoundWorld{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *SoundWorld) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
packer.PackInt(o.SoundId),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *SoundWorld) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
o.SoundId = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
45
object7/spawn.go
Normal file
45
object7/spawn.go
Normal file
|
@ -0,0 +1,45 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type Spawn struct {
|
||||
ItemId int
|
||||
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func (o *Spawn) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Spawn) TypeId() int {
|
||||
return network7.ObjSpawn
|
||||
}
|
||||
|
||||
func (o *Spawn) Size() int {
|
||||
return reflect.TypeOf(Spawn{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *Spawn) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *Spawn) Unpack(u *packer.Unpacker) error {
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
51
object7/spectator_info.go
Normal file
51
object7/spectator_info.go
Normal file
|
@ -0,0 +1,51 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
type SpectatorInfo struct {
|
||||
ItemId int
|
||||
|
||||
SpecMode network7.Spec
|
||||
SpectatorID int
|
||||
X int
|
||||
Y int
|
||||
}
|
||||
|
||||
func (o *SpectatorInfo) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *SpectatorInfo) TypeId() int {
|
||||
return network7.ObjSpectatorInfo
|
||||
}
|
||||
|
||||
func (o *SpectatorInfo) Size() int {
|
||||
return reflect.TypeOf(SpectatorInfo{}).NumField() - 1
|
||||
}
|
||||
|
||||
func (o *SpectatorInfo) Pack() []byte {
|
||||
return slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
|
||||
packer.PackInt(int(o.SpecMode)),
|
||||
packer.PackInt(o.SpectatorID),
|
||||
packer.PackInt(o.X),
|
||||
packer.PackInt(o.Y),
|
||||
)
|
||||
}
|
||||
|
||||
func (o *SpectatorInfo) Unpack(u *packer.Unpacker) error {
|
||||
o.SpecMode = network7.Spec(u.GetInt())
|
||||
o.SpectatorID = u.GetInt()
|
||||
o.X = u.GetInt()
|
||||
o.Y = u.GetInt()
|
||||
|
||||
return nil
|
||||
}
|
55
object7/unknown.go
Normal file
55
object7/unknown.go
Normal file
|
@ -0,0 +1,55 @@
|
|||
package object7
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
// used for protocol forward compability
|
||||
// an imaginary protocol version 0.7.6 could add a new snap item
|
||||
// it would have an unknown type id followed by a size field
|
||||
// we just consume size amount of integers and store it in this unknown struct
|
||||
// then we move onto the next item
|
||||
type Unknown struct {
|
||||
ItemId int
|
||||
ItemType int
|
||||
ItemSize int
|
||||
|
||||
Fields []int
|
||||
}
|
||||
|
||||
func (o *Unknown) Id() int {
|
||||
return o.ItemId
|
||||
}
|
||||
|
||||
func (o *Unknown) TypeId() int {
|
||||
return o.ItemType
|
||||
}
|
||||
|
||||
func (o *Unknown) Size() int {
|
||||
return o.ItemSize
|
||||
}
|
||||
|
||||
func (o *Unknown) Pack() []byte {
|
||||
data := slices.Concat(
|
||||
packer.PackInt(o.TypeId()),
|
||||
packer.PackInt(o.Id()),
|
||||
packer.PackInt(o.Size()),
|
||||
)
|
||||
for _, f := range o.Fields {
|
||||
data = append(data, packer.PackInt(f)...)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
func (o *Unknown) Unpack(u *packer.Unpacker) error {
|
||||
o.ItemSize = u.GetInt()
|
||||
o.Fields = make([]int, o.Size())
|
||||
|
||||
for i := 0; i < o.Size(); i++ {
|
||||
o.Fields[i] = u.GetInt()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
package packer
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"slices"
|
||||
)
|
||||
|
||||
|
@ -20,10 +22,33 @@ func (u *Unpacker) byte() byte {
|
|||
}
|
||||
|
||||
// consume one byte
|
||||
func (u *Unpacker) getByte() byte {
|
||||
func (u *Unpacker) GetByte() (byte, error) {
|
||||
if u.RemainingSize() < 1 {
|
||||
return 0x00, errors.New("GetByte not enough data")
|
||||
}
|
||||
b := u.data[u.idx]
|
||||
u.idx++
|
||||
return b
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (u *Unpacker) GetMsgAndSys() (msgId int, system bool, err error) {
|
||||
msg := u.GetInt()
|
||||
sys := msg&1 != 0
|
||||
msg >>= 1
|
||||
return msg, sys, nil
|
||||
}
|
||||
|
||||
func (u *Unpacker) GetRaw(size int) ([]byte, error) {
|
||||
if size < 0 {
|
||||
return nil, fmt.Errorf("GetRaw called with negative size %d", size)
|
||||
}
|
||||
end := u.idx + size
|
||||
if end > u.Size() {
|
||||
return nil, fmt.Errorf("GetRaw can not read size %d not enough data", size)
|
||||
}
|
||||
b := u.data[u.idx:end]
|
||||
u.idx += size
|
||||
return b, nil
|
||||
}
|
||||
|
||||
func (u *Unpacker) Data() []byte {
|
||||
|
@ -31,7 +56,17 @@ func (u *Unpacker) Data() []byte {
|
|||
}
|
||||
|
||||
func (u *Unpacker) Rest() []byte {
|
||||
return u.data[u.idx:]
|
||||
rest := u.data[u.idx:]
|
||||
u.idx = u.Size()
|
||||
return rest
|
||||
}
|
||||
|
||||
func (u *Unpacker) Size() int {
|
||||
return len(u.data)
|
||||
}
|
||||
|
||||
func (u *Unpacker) RemainingSize() int {
|
||||
return u.Size() - u.idx
|
||||
}
|
||||
|
||||
const (
|
||||
|
@ -40,13 +75,16 @@ const (
|
|||
SanitizeSkipWhitespaces = 4
|
||||
)
|
||||
|
||||
func (u *Unpacker) GetStringSanitized(sanitizeType int) string {
|
||||
func (u *Unpacker) GetStringSanitized(sanitizeType int) (string, error) {
|
||||
bytes := []byte{}
|
||||
|
||||
skipping := sanitizeType&SanitizeSkipWhitespaces != 0
|
||||
|
||||
for {
|
||||
b := u.getByte()
|
||||
b, err := u.GetByte()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if b == 0x00 {
|
||||
break
|
||||
}
|
||||
|
@ -71,10 +109,10 @@ func (u *Unpacker) GetStringSanitized(sanitizeType int) string {
|
|||
bytes = append(bytes, b)
|
||||
}
|
||||
|
||||
return string(bytes)
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
func (u *Unpacker) GetString() string {
|
||||
func (u *Unpacker) GetString() (string, error) {
|
||||
return u.GetStringSanitized(Sanitize)
|
||||
}
|
||||
|
||||
|
@ -187,3 +225,10 @@ func UnpackInt(data []byte) int {
|
|||
res ^= -sign
|
||||
return res
|
||||
}
|
||||
|
||||
func UnpackMsgAndSys(data []byte) (msgId int, system bool) {
|
||||
msg := UnpackInt(data)
|
||||
sys := msg&1 != 0
|
||||
msg >>= 1
|
||||
return msg, sys
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
)
|
||||
|
||||
// rest
|
||||
// rest and remaining size
|
||||
|
||||
func TestUnpackRest(t *testing.T) {
|
||||
u := Unpacker{}
|
||||
|
@ -16,6 +16,10 @@ func TestUnpackRest(t *testing.T) {
|
|||
want := 1
|
||||
got := u.GetInt()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
want = 2
|
||||
got = u.RemainingSize()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -23,6 +27,12 @@ func TestUnpackRest(t *testing.T) {
|
|||
got := u.Rest()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
{
|
||||
want := 0
|
||||
got := u.RemainingSize()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
||||
|
||||
// client info
|
||||
|
@ -58,12 +68,12 @@ func TestUnpackClientInfo(t *testing.T) {
|
|||
{
|
||||
// name
|
||||
want := "gopher"
|
||||
got := u.GetString()
|
||||
got, _ := u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
// clan
|
||||
want = ""
|
||||
got = u.GetString()
|
||||
got, _ = u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
|
@ -77,7 +87,7 @@ func TestUnpackClientInfo(t *testing.T) {
|
|||
{
|
||||
// body
|
||||
want := "greensward"
|
||||
got := u.GetString()
|
||||
got, _ := u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
}
|
||||
|
@ -110,7 +120,7 @@ func TestUnpackString(t *testing.T) {
|
|||
u.Reset([]byte{'f', 'o', 'o', 0x00})
|
||||
|
||||
want := "foo"
|
||||
got := u.GetString()
|
||||
got, _ := u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
|
@ -119,11 +129,11 @@ func TestUnpackTwoStrings(t *testing.T) {
|
|||
u.Reset([]byte{'f', 'o', 'o', 0x00, 'b', 'a', 'r', 0x00})
|
||||
|
||||
want := "foo"
|
||||
got := u.GetString()
|
||||
got, _ := u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
want = "bar"
|
||||
got = u.GetString()
|
||||
got, _ = u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
}
|
||||
|
@ -146,11 +156,11 @@ func TestUnpackMixed(t *testing.T) {
|
|||
// strings
|
||||
{
|
||||
want := "foo"
|
||||
got := u.GetString()
|
||||
got, _ := u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
|
||||
want = "bar"
|
||||
got = u.GetString()
|
||||
got, _ = u.GetString()
|
||||
require.Equal(t, want, got)
|
||||
}
|
||||
|
||||
|
|
|
@ -171,12 +171,30 @@ func (packet *Packet) unpackGame(msgId int, chunk chunk7.Chunk, u *packer.Unpack
|
|||
var msg messages7.NetMessage
|
||||
|
||||
switch msgId {
|
||||
case network7.MsgGameSvReadyToEnter:
|
||||
msg = &messages7.SvReadyToEnter{}
|
||||
case network7.MsgGameSvMotd:
|
||||
msg = &messages7.SvMotd{}
|
||||
case network7.MsgGameSvBroadcast:
|
||||
msg = &messages7.SvBroadcast{}
|
||||
case network7.MsgGameSvChat:
|
||||
msg = &messages7.SvChat{}
|
||||
case network7.MsgGameSvTeam:
|
||||
msg = &messages7.SvTeam{}
|
||||
case network7.MsgGameSvKillMsg:
|
||||
msg = &messages7.SvKillMsg{}
|
||||
case network7.MsgGameSvTuneParams:
|
||||
msg = &messages7.SvTuneParams{}
|
||||
case network7.MsgGameSvExtraProjectile:
|
||||
msg = &messages7.SvExtraProjectile{}
|
||||
case network7.MsgGameSvReadyToEnter:
|
||||
msg = &messages7.SvReadyToEnter{}
|
||||
case network7.MsgGameSvWeaponPickup:
|
||||
msg = &messages7.SvWeaponPickup{}
|
||||
case network7.MsgGameSvEmoticon:
|
||||
msg = &messages7.SvEmoticon{}
|
||||
case network7.MsgGameSvVoteClearOptions:
|
||||
msg = &messages7.SvVoteClearOptions{}
|
||||
case network7.MsgGameSvVoteOptionListAdd:
|
||||
msg = &messages7.SvVoteOptionListAdd{}
|
||||
case network7.MsgGameSvClientInfo:
|
||||
msg = &messages7.SvClientInfo{}
|
||||
default:
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
mkdir -p tmp
|
||||
awk '/^```go$/ {p=1}; p; /^```$/ {p=0;print"--- --- ---"}' README.md |
|
||||
grep -vE '^```(go)?$' |
|
||||
csplit \
|
||||
-z -s - '/--- --- ---/' \
|
||||
'{*}' \
|
||||
--suppress-matched \
|
||||
-f tmp/readme_snippet_ -b '%02d.go'
|
||||
|
||||
for snippet in ./tmp/readme_snippet_*.go; do
|
||||
echo "building $snippet ..."
|
||||
go build -v -o tmp/tmp "$snippet" || exit 1
|
||||
done
|
||||
|
||||
for snippet in ./tmp/readme_snippet_*.go; do
|
||||
echo "checking format $snippet ..."
|
||||
if ! diff -u <(echo -n) <(gofmt -d "$snippet"); then
|
||||
exit 1
|
||||
fi
|
||||
done
|
266
snapshot7/full_ddnet_server_test.go
Normal file
266
snapshot7/full_ddnet_server_test.go
Normal file
|
@ -0,0 +1,266 @@
|
|||
package snapshot7_test
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||
)
|
||||
|
||||
// --------------------------------
|
||||
// snap single
|
||||
// --------------------------------
|
||||
|
||||
func TestDDNetFullServerSnapSingle(t *testing.T) {
|
||||
// vanilla client connected to almost full ddnet rus server
|
||||
// dumped with tcpdump
|
||||
// libtw2 dissector details
|
||||
// this is the n-th snapshot that is a snap single the prior snapshots were partials snaps
|
||||
//
|
||||
// User Datagram Protocol, Src Port: 8316, Dst Port: 51479
|
||||
// Teeworlds 0.7 Protocol packet
|
||||
// Teeworlds 0.7 Protocol chunk: sys.snap_single
|
||||
// Header (non-vital)
|
||||
// Message: sys.snap_single
|
||||
// Tick: 11271652
|
||||
// Delta tick: 22
|
||||
// Crc: 1032529567
|
||||
// Data (114 bytes)
|
||||
dump := []byte{
|
||||
0x10, 0x04, 0x01, 0x1f, 0x5a, 0x5e, 0xd8,
|
||||
0x28, 0x15, 0xa6, 0x6c, 0xfb, 0x4a, 0xd3, 0xd6, 0xd3, 0xe0, 0x54, 0x85, 0x09, 0x72, 0xc4,
|
||||
0x0d, 0x2e, 0xb6, 0xe9, 0x2f, 0xbc, 0xfd, 0xb9, 0x5d, 0xd0, 0x35, 0x5d, 0x5e, 0xcf, 0xb5, 0x35,
|
||||
0xeb, 0x92, 0xe8, 0xbe, 0xbb, 0x9f, 0xd1, 0x7f, 0x17, 0x24, 0x2d, 0xb8, 0xfa, 0x7f, 0x5f, 0xf5,
|
||||
0x38, 0x7b, 0x7a, 0xc1, 0x47, 0x73, 0xeb, 0x4a, 0xd0, 0x62, 0x02, 0x17, 0x6d, 0xd9, 0xe2, 0x58,
|
||||
0x57, 0x68, 0xc9, 0xe6, 0x35, 0xf9, 0x0a, 0xd3, 0xd6, 0x7b, 0xf6, 0x5d, 0x90, 0xb4, 0x10, 0xfa,
|
||||
0x9a, 0x7c, 0x85, 0x69, 0xeb, 0xbf, 0xe1, 0x2b, 0x4d, 0x5b, 0xef, 0x1e, 0x4f, 0xea, 0x85, 0xe2,
|
||||
0x06,
|
||||
}
|
||||
|
||||
conn := protocol7.Session{}
|
||||
|
||||
packet := protocol7.Packet{}
|
||||
err := packet.Unpack(dump)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn.Ack = packet.Header.Ack
|
||||
repack := packet.Pack(&conn)
|
||||
require.Equal(t, dump, repack)
|
||||
}
|
||||
|
||||
func TestSvEmoticonAndSnapSingle(t *testing.T) {
|
||||
// Teeworlds 0.7 Protocol packet
|
||||
// Teeworlds 0.7 Protocol chunk: game.sv_emoticon
|
||||
// Header (vital: 234)
|
||||
// Message: game.sv_emoticon
|
||||
// Client id: 39
|
||||
// Emoticon: exclamation
|
||||
// Teeworlds 0.7 Protocol chunk: sys.snap_single
|
||||
// Header (non-vital)
|
||||
// Message: sys.snap_single
|
||||
// Tick: 11271828
|
||||
// Delta tick: 24
|
||||
// Crc: 1021386082
|
||||
// Data (190 bytes)
|
||||
dump := []byte{
|
||||
0x10, 0x05, 0x02, 0x1f, 0x5a, 0x5e,
|
||||
0xd8, 0x4a, 0x16, 0xd4, 0x0d, 0x2f, 0x0b, 0x2d, 0xfc, 0x4d, 0x19, 0xae, 0xd4, 0xb4, 0xf5, 0x10,
|
||||
0x9f, 0xa1, 0x48, 0x8b, 0x2b, 0xbb, 0xd1, 0x15, 0x48, 0x5a, 0xce, 0x52, 0xed, 0xef, 0x97, 0x58,
|
||||
0xef, 0xa2, 0x29, 0x6d, 0x82, 0xb7, 0x6b, 0xb6, 0x91, 0x1a, 0x1b, 0x4e, 0x72, 0xbb, 0x1d, 0x7d,
|
||||
0xcf, 0x71, 0x04, 0x55, 0x09, 0x5f, 0x21, 0xfe, 0x2e, 0x48, 0x5a, 0xb8, 0xa8, 0xff, 0x87, 0x42,
|
||||
0x26, 0x55, 0xa2, 0x9e, 0xeb, 0x22, 0x2d, 0x37, 0xc6, 0xb0, 0xa4, 0x33, 0x9e, 0x96, 0x1b, 0x0b,
|
||||
0xfc, 0xab, 0xaa, 0x87, 0x37, 0x5c, 0xa9, 0x69, 0xeb, 0x19, 0x92, 0xe8, 0x3b, 0x56, 0x3e, 0x0b,
|
||||
0x5b, 0x80, 0x73, 0xea, 0xb4, 0x50, 0xaa, 0x54, 0x6f, 0x49, 0xa2, 0x0b, 0xac, 0x38, 0x15, 0x3c,
|
||||
0x66, 0x71, 0xc4, 0x5d, 0x90, 0xb4, 0x80, 0xd7, 0x03, 0x60, 0x53, 0x14, 0xa7, 0x5e, 0xf8, 0x90,
|
||||
0xa7, 0x17, 0x3c, 0xa1, 0x17, 0xbe, 0x2e, 0x54, 0xa0, 0xde, 0x0f, 0xe4, 0x2d, 0xe8, 0xcc, 0x44,
|
||||
0xc2, 0x2f, 0x85, 0x36, 0x7f, 0x17, 0x24, 0x2d, 0x84, 0xfe, 0x9f, 0x25, 0x52, 0xaf, 0x57, 0xdc,
|
||||
0x00,
|
||||
}
|
||||
|
||||
conn := protocol7.Session{}
|
||||
|
||||
packet := protocol7.Packet{}
|
||||
err := packet.Unpack(dump)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn.Ack = packet.Header.Ack
|
||||
repack := packet.Pack(&conn)
|
||||
|
||||
fmt.Printf("repack: %x\n", repack)
|
||||
fmt.Printf("dump: %x\n", dump)
|
||||
|
||||
require.Equal(t, dump, repack)
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
// multi part snaps
|
||||
// --------------------------------
|
||||
|
||||
// func TestVoteOptionListAddPlusTwoSnaps(t *testing.T) {
|
||||
// // vanilla client connected to almost full ddnet rus server
|
||||
// // dumped with tcpdump
|
||||
// //
|
||||
// // these are two consecutive packets
|
||||
// // - packet1: vote_list, snap (part 1/2)
|
||||
// // - packet2: snap (part 2/2)
|
||||
//
|
||||
// // Teeworlds 0.7 Protocol packet
|
||||
// // Teeworlds 0.7 Protocol chunk: game.sv_vote_option_list_add
|
||||
// // Teeworlds 0.7 Protocol chunk: sys.snap
|
||||
// // Header (non-vital)
|
||||
// // Message: sys.snap
|
||||
// // Tick: 11271610
|
||||
// // Delta tick: 11271611
|
||||
// // Num parts: 2
|
||||
// // Part: 0
|
||||
// // Crc: 986678629
|
||||
// // Data (900 bytes)
|
||||
// dumpVoteListAndPart1 := []byte{
|
||||
// 0x10, 0x04, 0x02, 0x1f, 0x5a, 0x5e,
|
||||
// 0xd8, 0x5a, 0xd9, 0x55, 0x86, 0xd8, 0xb5, 0xf6, 0x35, 0x1c, 0x0d, 0xe7, 0x8a, 0xc3, 0xda, 0x35,
|
||||
// 0xab, 0xf0, 0x03, 0x6b, 0x5b, 0xc2, 0xda, 0x75, 0x8e, 0x86, 0x52, 0x5f, 0x7c, 0x0d, 0x6b, 0xd7,
|
||||
// 0x6c, 0x62, 0x97, 0x87, 0x83, 0x13, 0x5c, 0x3b, 0x27, 0xc0, 0x99, 0x2d, 0xe5, 0x04, 0xd6, 0xb6,
|
||||
// 0x18, 0xca, 0x59, 0x53, 0xe8, 0x5a, 0x39, 0x81, 0x8e, 0x5c, 0x8b, 0x6b, 0x63, 0x6d, 0x4b, 0x58,
|
||||
// 0xf3, 0xc8, 0x32, 0x8e, 0x66, 0xed, 0x9a, 0x69, 0xba, 0x27, 0x47, 0xfb, 0xa4, 0x38, 0xd4, 0xe5,
|
||||
// 0x6b, 0x58, 0xbb, 0x66, 0x15, 0x7e, 0x60, 0x6d, 0x4b, 0x58, 0xfb, 0xe2, 0x6b, 0xa0, 0x54, 0x6b,
|
||||
// 0x9f, 0x58, 0xbb, 0x66, 0x13, 0xbb, 0x3c, 0x1c, 0x9c, 0xe0, 0x03, 0x5b, 0xe4, 0x4a, 0xb8, 0x12,
|
||||
// 0xbc, 0x59, 0xdb, 0x62, 0x28, 0x67, 0x2d, 0x9b, 0xaf, 0x65, 0x8b, 0x5c, 0x09, 0xd7, 0xc2, 0xda,
|
||||
// 0x96, 0xb0, 0xd6, 0xda, 0x32, 0x8e, 0x66, 0xed, 0x9a, 0x69, 0xba, 0xa7, 0xd6, 0xae, 0xc3, 0xb9,
|
||||
// 0x2f, 0x3e, 0xb1, 0x76, 0xcd, 0x2a, 0xfc, 0xc0, 0xda, 0x96, 0xb0, 0xf6, 0x85, 0xa3, 0xa1, 0xd4,
|
||||
// 0x75, 0x5f, 0x58, 0xbb, 0x66, 0x13, 0xbb, 0xfc, 0xff, 0xf4, 0x34, 0x1c, 0x0e, 0x1c, 0x63, 0xda,
|
||||
// 0x7a, 0xf7, 0x72, 0x8c, 0x69, 0xeb, 0x45, 0x06, 0x8a, 0x99, 0x56, 0x69, 0x6e, 0x1a, 0xe9, 0x43,
|
||||
// 0x2f, 0x56, 0x59, 0xd2, 0xc2, 0x33, 0x0d, 0xc5, 0x33, 0xa9, 0xf8, 0x8e, 0x69, 0xf0, 0x52, 0xc8,
|
||||
// 0x11, 0x4f, 0x6a, 0xa0, 0xd0, 0x6f, 0x1a, 0x44, 0xef, 0x1e, 0x06, 0x7c, 0x4b, 0x15, 0x36, 0xe9,
|
||||
// 0x4a, 0x5a, 0x78, 0x7e, 0x74, 0x65, 0x28, 0x94, 0xe6, 0x51, 0xaf, 0xb8, 0xfb, 0x49, 0x51, 0x50,
|
||||
// 0xb7, 0x42, 0x0d, 0x69, 0xca, 0xa1, 0xd8, 0xd5, 0x9c, 0xa4, 0x18, 0x7d, 0x17, 0x24, 0x2d, 0x3c,
|
||||
// 0x5d, 0x29, 0xa6, 0xf9, 0x3e, 0x8c, 0xde, 0x57, 0xca, 0xb0, 0xc4, 0x51, 0x52, 0xa9, 0xc1, 0xba,
|
||||
// 0xee, 0xb3, 0x9e, 0x4e, 0xa0, 0xd8, 0xc4, 0x74, 0x9d, 0xbc, 0x24, 0x2d, 0x3c, 0xfe, 0x54, 0xe5,
|
||||
// 0x6a, 0xd3, 0x90, 0xbb, 0x32, 0x4c, 0x3e, 0xe4, 0xca, 0xa8, 0xf8, 0x26, 0xf2, 0x11, 0xa0, 0xe7,
|
||||
// 0x2f, 0xf5, 0xa6, 0x21, 0x75, 0xee, 0xba, 0x57, 0xd2, 0xc2, 0xf3, 0xd9, 0x67, 0xa9, 0xf3, 0xb1,
|
||||
// 0x9d, 0xa2, 0x0f, 0x49, 0x2d, 0x0b, 0x47, 0x6a, 0x7c, 0xa5, 0x2b, 0xb5, 0x05, 0x77, 0x8c, 0xf9,
|
||||
// 0xc1, 0x87, 0x71, 0xac, 0xbb, 0x1c, 0x24, 0x2d, 0x3c, 0x28, 0x56, 0x3c, 0x3f, 0xba, 0x06, 0xa1,
|
||||
// 0xd1, 0x35, 0x98, 0x20, 0x63, 0xfe, 0x26, 0x60, 0x5a, 0x39, 0xe2, 0x07, 0x87, 0x81, 0xe5, 0x96,
|
||||
// 0x24, 0xe5, 0x5d, 0x26, 0x69, 0xe1, 0x29, 0x9e, 0xaf, 0x4b, 0x3d, 0x5d, 0xc1, 0x11, 0xb8, 0x1c,
|
||||
// 0xc3, 0xd9, 0x86, 0xe3, 0xe8, 0x4a, 0xa6, 0x89, 0xf5, 0x8a, 0x69, 0x10, 0x17, 0xe0, 0xfa, 0xa7,
|
||||
// 0x28, 0x69, 0xe1, 0xb9, 0xcc, 0xb6, 0x69, 0xa5, 0xc0, 0xe1, 0x31, 0xce, 0x8a, 0x27, 0x53, 0x98,
|
||||
// 0x00, 0x5c, 0xaa, 0xf2, 0x95, 0x8e, 0x89, 0x65, 0xb8, 0x87, 0xaa, 0xdd, 0x75, 0xb9, 0xa4, 0x85,
|
||||
// 0x27, 0x9d, 0x2a, 0x4d, 0xc0, 0xd7, 0xd1, 0x77, 0x54, 0xe9, 0x23, 0x85, 0x76, 0xaa, 0xe2, 0xe5,
|
||||
// 0x9a, 0x74, 0x9d, 0xc0, 0xb5, 0x05, 0x0d, 0xca, 0x71, 0x88, 0xca, 0x92, 0x16, 0x2d, 0x5c, 0x05,
|
||||
// 0xab, 0xb2, 0x0f, 0x43, 0x26, 0x40, 0x9b, 0x87, 0xb4, 0xe0, 0x67, 0x39, 0x34, 0xe1, 0xf9, 0x0f,
|
||||
// 0xab, 0x91, 0x9d, 0xae, 0xa4, 0x45, 0xb1, 0x3f, 0x36, 0x7c, 0xc8, 0x15, 0xe9, 0x4a, 0x5a, 0xa0,
|
||||
// 0x98, 0x0f, 0x22, 0x63, 0x52, 0xa3, 0x41, 0xf5, 0xfe, 0x22, 0x54, 0x69, 0xd4, 0x95, 0xae, 0xa4,
|
||||
// 0x85, 0x10, 0xfb, 0x5b, 0xb4, 0xcd, 0x11, 0xcd, 0x4b, 0x57, 0xd2, 0xc2, 0x42, 0xcc, 0xc7, 0x02,
|
||||
// 0x35, 0x6a, 0x68, 0xda, 0x7a, 0x7f, 0xaf, 0x61, 0xf8, 0xf0, 0x74, 0x25, 0x2d, 0x3c, 0x81, 0xfd,
|
||||
// 0xed, 0x29, 0x1a, 0x3e, 0xc6, 0x74, 0x25, 0x2d, 0xec, 0x62, 0x3e, 0x76, 0x94, 0xe1, 0x6a, 0x8e,
|
||||
// 0xe8, 0xfd, 0x6d, 0x2a, 0xa5, 0x2b, 0x69, 0x61, 0x23, 0xe6, 0x63, 0x83, 0x96, 0xf8, 0xc6, 0xb4,
|
||||
// 0xf5, 0xfe, 0x6e, 0x61, 0xf9, 0xd6, 0x67, 0x4c, 0x57, 0xd2, 0xc2, 0x4d, 0xec, 0x4f, 0x02, 0x9f,
|
||||
// 0x6d, 0x69, 0xba, 0x92, 0x16, 0x44, 0xcc, 0x87, 0x20, 0x3f, 0xfe, 0xa6, 0xad, 0xf7, 0x67, 0x36,
|
||||
// 0x58, 0xa8, 0x94, 0xae, 0xa4, 0x05, 0x53, 0xcc, 0x87, 0x89, 0x9a, 0x5c, 0xd9, 0xb4, 0xf5, 0xfe,
|
||||
// 0xfa, 0x4a, 0xe9, 0x4a, 0x5a, 0xe8, 0xc5, 0x7c, 0xf4, 0xa8, 0xd0, 0x95, 0x39, 0x49, 0xef, 0xef,
|
||||
// 0x1f, 0xb8, 0x66, 0x95, 0xd2, 0x95, 0xb4, 0xf0, 0x17, 0xf3, 0xf1, 0x47, 0x3f, 0xd0, 0xa4, 0x7a,
|
||||
// 0xbd, 0xbf, 0xbc, 0x52, 0xba, 0x92, 0x16, 0x72, 0x81, 0xf9, 0xc8, 0x51, 0x57, 0x7c, 0xd7, 0x35,
|
||||
// 0xe8, 0xfd, 0x9d, 0x50, 0xa5, 0xce, 0xd7, 0xa4, 0x2b, 0x69, 0xe1, 0x88, 0xf9, 0x38, 0x68, 0x22,
|
||||
// 0xbe, 0x37, 0x6d, 0xbd, 0x3f, 0x7d, 0xa5, 0x74, 0x25, 0x2d, 0xe8, 0xc5, 0x7c, 0xe8, 0x51, 0xa3,
|
||||
// 0xe5, 0x54, 0xaf, 0xf7, 0x77, 0x57, 0xa3, 0x0a, 0x95, 0x31, 0x5d, 0x49, 0x0b, 0x77, 0x62, 0x7f,
|
||||
// 0x75, 0x9a, 0xd2, 0xa9, 0x43, 0xba, 0x92, 0x16, 0x6a, 0x31, 0x1f, 0x35, 0xaa, 0xb0, 0xc4, 0xf7,
|
||||
// 0x7a, 0x7f, 0x53, 0x29, 0xba, 0xdc, 0x07, 0xe9, 0x4a, 0x5a, 0x98, 0x12, 0xf3, 0x31, 0x85, 0x74,
|
||||
// 0x39, 0x9b, 0xb6, 0xde, 0x9f, 0x5b, 0x29, 0x5d, 0x49, 0x0b, 0xae, 0xc0, 0xfe, 0xaa, 0x2a, 0xa5,
|
||||
// 0x2b, 0x69, 0xa1, 0x4a, 0xcc, 0x47, 0x15, 0xba, 0x5c, 0xf1, 0x4d, 0x5b, 0xef, 0x0f, 0x5f, 0x29,
|
||||
// 0x5d, 0x49, 0x0b, 0x78, 0xb1, 0xbf, 0x6f, 0x79, 0xc9, 0xd4, 0x35, 0x91, 0xae, 0xa4, 0x85, 0x6f,
|
||||
// 0x62, 0x3e, 0xbe, 0x21, 0x80, 0x4b, 0xf5, 0x7a, 0x7f, 0x1a, 0xa5, 0xb3, 0xb0, 0xa6, 0x2b, 0x69,
|
||||
// 0x41, 0x43, 0xcc, 0x87, 0x06, 0xfa, 0xc8, 0xd5, 0x54, 0xa7, 0xf7, 0xe7, 0x53, 0x9a, 0x69, 0x43,
|
||||
// 0x69, 0xba, 0x92, 0x16, 0x7c, 0xc4, 0x7c, 0xf8, 0x20, 0x3f, 0xa9, 0xa4, 0x7a, 0xbd, 0x3f, 0xa4,
|
||||
// 0x16, 0x0a, 0x64, 0x4b, 0x57, 0xd2, 0x02, 0x22, 0xb0, 0x3f, 0xcf, 0x86, 0x62, 0x06, 0xa6, 0x2b,
|
||||
// 0x69, 0xc1, 0x53, 0xcc, 0x87, 0x27, 0xda, 0xf6, 0x21, 0xd3, 0xd6, 0xfb, 0x4b, 0xa8, 0x94, 0xae,
|
||||
// 0xa4, 0x85, 0x04, 0x31, 0x1f, 0x09, 0xc8, 0xa9, 0x1f, 0x35, 0xa8, 0xde, 0x1f, 0x5a, 0xa5, 0x74,
|
||||
// 0x25, 0x2d, 0xa0, 0x89, 0xf9, 0x40, 0x43, 0x9a, 0x92, 0x54, 0xaf, 0xf7, 0x57, 0x50, 0x29, 0x5d,
|
||||
// 0x49, 0x0b, 0x05, 0x62, 0x3e, 0x0a, 0x90, 0x03, 0xc7, 0xbb, 0x06, 0xbd, 0xbf, 0xb9, 0x52, 0xba,
|
||||
// 0x92, 0x16, 0x66, 0x31, 0x1f, 0x33, 0x6a, 0x72, 0x65, 0xd3, 0xd6, 0xfb, 0x2b, 0xd7, 0xc2, 0x5f,
|
||||
// 0x2a, 0xd2, 0x95, 0xb4, 0x50, 0x16, 0xf3, 0x51, 0x46, 0xb8, 0xae, 0x6c, 0xda, 0x7a, 0x7f, 0x97,
|
||||
// 0xda, 0x86, 0x9e, 0x47, 0xe9, 0x4a, 0x5a, 0xb8, 0x24, 0x30, 0x1f, 0x97, 0xd0, 0xc7, 0xd2, 0xf9,
|
||||
// 0x5e, 0xef, 0xcf, 0xba, 0x52, 0xba, 0x92, 0x16, 0xac, 0xc5, 0x7c, 0x58, 0xa3, 0x14, 0x8e, 0xb8,
|
||||
// 0x06, 0xbd, 0x3f, 0xa3, 0x4a, 0xe9, 0x4a, 0x5a, 0x30, 0x12, 0xd8, 0x5f, 0x77, 0x2d, 0xbe, 0xb6,
|
||||
// 0x8f, 0x31, 0x5d, 0x49, 0x0b, 0xdd, 0x62, 0x3e, 0x8a, 0x1b,
|
||||
// }
|
||||
//
|
||||
// // User Datagram Protocol, Src Port: 8316, Dst Port: 51479
|
||||
// // Teeworlds 0.7 Protocol packet
|
||||
// // Teeworlds 0.7 Protocol chunk: sys.snap
|
||||
// // Header (non-vital)
|
||||
// // Message: sys.snap
|
||||
// // Tick: 11271610
|
||||
// // Delta tick: 11271611
|
||||
// // Num parts: 2
|
||||
// // Part: 1
|
||||
// // Crc: 986678629
|
||||
// // Data (556 bytes)
|
||||
// dumpPart2 := []byte{
|
||||
//
|
||||
// 0x10, 0x04, 0x01, 0x1f, 0x5a, 0x5e,
|
||||
// 0xd8, 0xc4, 0xb4, 0x38, 0x1c, 0x38, 0xc6, 0xb4, 0xf5, 0xee, 0xe5, 0x18, 0xd3, 0xd6, 0x0b, 0x64,
|
||||
// 0xa0, 0x98, 0x69, 0x95, 0xe6, 0x26, 0x8d, 0xe8, 0x46, 0x97, 0x9b, 0x98, 0xea, 0xf5, 0xfe, 0xa6,
|
||||
// 0x57, 0x4a, 0x57, 0xd2, 0xc2, 0x74, 0x31, 0x1f, 0xd3, 0x91, 0x1f, 0xc7, 0x98, 0xb6, 0xde, 0x1f,
|
||||
// 0x46, 0xa5, 0x74, 0x25, 0x2d, 0x60, 0x88, 0xf9, 0xc0, 0x40, 0x96, 0xb4, 0xf8, 0x5e, 0xef, 0xaf,
|
||||
// 0xa8, 0x52, 0xba, 0x92, 0x16, 0x8a, 0xc4, 0x7c, 0x14, 0xa1, 0x42, 0x5f, 0x9b, 0xea, 0xf5, 0xfe,
|
||||
// 0xda, 0x4b, 0xa7, 0x7a, 0x57, 0xa4, 0x2b, 0x69, 0xa1, 0x5d, 0xcc, 0x47, 0x3b, 0xfa, 0x4e, 0xea,
|
||||
// 0xa8, 0x5e, 0xef, 0x2f, 0xab, 0x52, 0xba, 0x92, 0x16, 0xb2, 0xc4, 0x7c, 0x64, 0xa1, 0x14, 0xbe,
|
||||
// 0x31, 0x6d, 0xbd, 0xbf, 0x35, 0x54, 0x5f, 0x75, 0x2d, 0xe9, 0x4a, 0x5a, 0x58, 0xc5, 0x7c, 0xac,
|
||||
// 0x68, 0xdb, 0x87, 0x4c, 0x5b, 0xef, 0xaf, 0xd3, 0xb6, 0x25, 0x28, 0x4f, 0x57, 0xd2, 0x42, 0x47,
|
||||
// 0xcc, 0x47, 0x07, 0xfd, 0xe0, 0x2b, 0xa8, 0x5e, 0xef, 0x2f, 0x31, 0x2d, 0xdf, 0xb1, 0x4a, 0x57,
|
||||
// 0xd2, 0x42, 0xa2, 0x98, 0x8f, 0x44, 0xd4, 0xc4, 0x9f, 0xef, 0xf5, 0xfe, 0x7e, 0x55, 0x4a, 0x57,
|
||||
// 0xd2, 0xc2, 0x2f, 0x31, 0x1f, 0xbf, 0x90, 0xa6, 0x24, 0xd5, 0xeb, 0xfd, 0x69, 0xa7, 0x45, 0xd5,
|
||||
// 0xaa, 0xd3, 0x95, 0xb4, 0xa0, 0x2d, 0xe6, 0x43, 0x1b, 0x5d, 0xd0, 0x35, 0xbe, 0xd7, 0xfb, 0xdb,
|
||||
// 0x9a, 0xa6, 0x2b, 0xa5, 0x00, 0xd3, 0x95, 0xb4, 0xb0, 0x55, 0xcc, 0xc7, 0x56, 0xa4, 0x6b, 0xb9,
|
||||
// 0x06, 0xd5, 0xfb, 0xbb, 0x58, 0x1b, 0x55, 0xd8, 0xd2, 0x74, 0x25, 0x2d, 0x5c, 0x14, 0xf3, 0x71,
|
||||
// 0x11, 0xa9, 0x70, 0x8c, 0x69, 0xeb, 0xfd, 0x2d, 0x0b, 0x0b, 0x45, 0xba, 0x2c, 0x5d, 0x49, 0x0b,
|
||||
// 0xcb, 0x04, 0xe6, 0x63, 0x19, 0x6a, 0xf1, 0x15, 0x7c, 0xaf, 0xf7, 0x77, 0xbd, 0x52, 0xba, 0x92,
|
||||
// 0x16, 0xae, 0x8b, 0xf9, 0xb8, 0x8e, 0x50, 0x4d, 0xd3, 0xb4, 0xf5, 0xfe, 0x3e, 0x55, 0x4a, 0x57,
|
||||
// 0xd2, 0xc2, 0x27, 0x31, 0x1f, 0x9f, 0xd0, 0x44, 0xbe, 0xce, 0xf7, 0x7a, 0x7f, 0xad, 0x2b, 0xa5,
|
||||
// 0x2b, 0x69, 0xa1, 0xb5, 0x98, 0x8f, 0xd6, 0xe8, 0x82, 0xdf, 0xa8, 0x5e, 0xef, 0xef, 0x6b, 0x2a,
|
||||
// 0xa5, 0x2b, 0x69, 0xe1, 0x6b, 0xc4, 0x7c, 0x7c, 0x0d, 0xca, 0xa0, 0x46, 0x75, 0x7a, 0x7f, 0xea,
|
||||
// 0xaa, 0x94, 0xae, 0xa4, 0x05, 0x75, 0x89, 0xf9, 0x50, 0x17, 0xda, 0xa6, 0x0a, 0xaa, 0xd3, 0xfb,
|
||||
// 0xd3, 0xa1, 0x6d, 0x28, 0xb3, 0x2c, 0x5d, 0x49, 0x0b, 0x3a, 0x08, 0xd1, 0xdf, 0xb4, 0x84, 0x95,
|
||||
// 0x4a, 0xa5, 0x74, 0x25, 0x2d, 0x4c, 0x8b, 0x98, 0x8f, 0x69, 0x41, 0x5d, 0xb9, 0x5a, 0x83, 0xea,
|
||||
// 0xf5, 0x5c, 0x57, 0x71, 0x8c, 0x69, 0xeb, 0x4d, 0x3a, 0x7e, 0xd0, 0xe5, 0x81, 0xe0, 0x1b, 0x9b,
|
||||
// 0x95, 0x36, 0xe9, 0x98, 0xd4, 0xe5, 0xeb, 0xf5, 0xd1, 0xbe, 0x0b, 0x92, 0x16, 0x5c, 0x3d, 0x00,
|
||||
// 0x36, 0xc5, 0xaf, 0xa4, 0x17, 0x2e, 0xe3, 0x18, 0xd3, 0xd6, 0x53, 0x51, 0xa5, 0xd0, 0xf7, 0x39,
|
||||
// 0x8e, 0xe9, 0xd2, 0x99, 0x2b, 0xd5, 0x53, 0x53, 0xa5, 0xb2, 0xef, 0x5d, 0x40, 0xaa, 0xb3, 0x38,
|
||||
// 0xde, 0x05, 0x49, 0x0b, 0xa1, 0x07, 0xc0, 0xa6, 0x28, 0xee, 0x1a, 0x3c, 0xd9, 0x3d, 0x3d, 0x1d,
|
||||
// 0x68, 0x72, 0x8c, 0x69, 0xeb, 0x7d, 0x86, 0xf8, 0x41, 0xaa, 0x4a, 0x19, 0xe8, 0x57, 0x4a, 0xef,
|
||||
// 0x33, 0xc4, 0x0f, 0x52, 0x75, 0x01, 0xa9, 0xce, 0xe2, 0xed, 0xbb, 0x20, 0x69, 0x41, 0x07, 0x3d,
|
||||
// 0x00, 0x36, 0x45, 0x68, 0xa7, 0x4a, 0xe4, 0x68, 0xc5, 0x0d,
|
||||
// }
|
||||
//
|
||||
// // packet 1
|
||||
// {
|
||||
// conn := protocol7.Session{}
|
||||
//
|
||||
// packet := protocol7.Packet{}
|
||||
// err := packet.Unpack(dumpVoteListAndPart1)
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// conn.Ack = packet.Header.Ack
|
||||
// repack := packet.Pack(&conn)
|
||||
//
|
||||
// fmt.Printf(" want: %x\n", dumpVoteListAndPart1)
|
||||
// fmt.Printf("repack: %x\n", repack)
|
||||
//
|
||||
// require.Equal(t, dumpVoteListAndPart1, repack)
|
||||
// }
|
||||
//
|
||||
// // packet 2
|
||||
// {
|
||||
// conn := protocol7.Session{}
|
||||
//
|
||||
// packet := protocol7.Packet{}
|
||||
// err := packet.Unpack(dumpPart2)
|
||||
// require.NoError(t, err)
|
||||
//
|
||||
// conn.Ack = packet.Header.Ack
|
||||
// repack := packet.Pack(&conn)
|
||||
// require.Equal(t, dumpPart2, repack)
|
||||
// }
|
||||
//
|
||||
// // TODO: combine the snap parts together into one full snap
|
||||
// }
|
47
snapshot7/simple_localhost_test.go
Normal file
47
snapshot7/simple_localhost_test.go
Normal file
|
@ -0,0 +1,47 @@
|
|||
package snapshot7_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||
)
|
||||
|
||||
func TestSmallVanillaServerSnapSingle(t *testing.T) {
|
||||
// snapshot captured with tcpdump
|
||||
// generated by a vanilla teeworlds 0.7.5 server
|
||||
// used the go-teeworlds-protocol sample client to connect to the server
|
||||
// the package is compressed so the raw bytes are a bit non obvious to look at
|
||||
//
|
||||
// libtw2 dissector details
|
||||
// Teeworlds 0.7 Protocol packet
|
||||
// Teeworlds 0.7 Protocol chunk: sys.snap_single
|
||||
// Header (non-vital)
|
||||
// Message: sys.snap_single
|
||||
// Tick: 1510
|
||||
// Delta tick: 1511
|
||||
// Crc: 16269
|
||||
// Data (103 bytes)
|
||||
//
|
||||
dump := []byte{
|
||||
0x10, 0x04, 0x01, 0x01, 0x02, 0x03, 0x04,
|
||||
0xe8, 0x93, 0x29, 0x4b, 0x7c, 0x18, 0xe2, 0xe3, 0x47, 0x0d, 0x46, 0x86, 0xb0, 0xbc, 0xd7,
|
||||
0x24, 0x0d, 0x93, 0x5e, 0x0f, 0x4d, 0xf2, 0x31, 0xe9, 0x09, 0x4f, 0x98, 0x84, 0x98, 0xf4, 0x2c,
|
||||
0x3c, 0x0b, 0x93, 0x3c, 0x4d, 0x7a, 0x9e, 0xe7, 0x06, 0xeb, 0x9b, 0x49, 0x0f, 0xed, 0x61, 0xb9,
|
||||
0xb0, 0x5e, 0x3b, 0x9a, 0x84, 0x87, 0xf5, 0xd0, 0x26, 0x54, 0x37, 0xec, 0x76, 0x92, 0x37, 0xef,
|
||||
0xf5, 0x0d, 0x3e, 0x26, 0xe5, 0x54, 0xbc, 0x40, 0x5c, 0x69, 0x93, 0x72, 0x58, 0x6f, 0x7d, 0x3d,
|
||||
0xde, 0x3f, 0x59, 0x71, 0x03,
|
||||
}
|
||||
|
||||
conn := protocol7.Session{}
|
||||
|
||||
packet := protocol7.Packet{}
|
||||
err := packet.Unpack(dump)
|
||||
require.NoError(t, err)
|
||||
|
||||
conn.Ack = packet.Header.Ack
|
||||
repack := packet.Pack(&conn)
|
||||
require.Equal(t, dump, repack)
|
||||
|
||||
// TODO: test if snap items were parsed correctly
|
||||
}
|
58
snapshot7/snapshot7.go
Normal file
58
snapshot7/snapshot7.go
Normal file
|
@ -0,0 +1,58 @@
|
|||
package snapshot7
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/object7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||
)
|
||||
|
||||
const (
|
||||
MaxType = 0x7fff
|
||||
MaxId = 0xffff
|
||||
MaxParts = 64
|
||||
MaxSize = MaxParts * 1024
|
||||
)
|
||||
|
||||
type Snapshot struct {
|
||||
NumRemovedItems int
|
||||
NumItemDeltas int
|
||||
|
||||
Items []object7.SnapObject
|
||||
}
|
||||
|
||||
func (snap *Snapshot) Unpack(u *packer.Unpacker) error {
|
||||
// TODO: add all the error checking the C++ reference implementation has
|
||||
|
||||
snap.NumRemovedItems = u.GetInt()
|
||||
snap.NumItemDeltas = u.GetInt()
|
||||
u.GetInt() // _zero
|
||||
|
||||
// TODO: copy non deleted items from a delta snapshot
|
||||
|
||||
for i := 0; i < snap.NumRemovedItems; i++ {
|
||||
deleted := u.GetInt()
|
||||
fmt.Printf("deleted item key = %d\n", deleted)
|
||||
|
||||
// TODO: don't copy those from the delta snapshot
|
||||
}
|
||||
|
||||
for i := 0; i < snap.NumItemDeltas; i++ {
|
||||
itemType := u.GetInt()
|
||||
itemId := u.GetInt()
|
||||
|
||||
item := object7.NewObject(itemType, itemId)
|
||||
err := item.Unpack(u)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO: update old items
|
||||
}
|
||||
|
||||
if u.RemainingSize() > 0 {
|
||||
return fmt.Errorf("unexpected remaining size %d after snapshot unpack\n", u.RemainingSize())
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -3,6 +3,7 @@ package teeworlds7
|
|||
import (
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/snapshot7"
|
||||
)
|
||||
|
||||
// Processes the incoming packet
|
||||
|
@ -10,90 +11,117 @@ import (
|
|||
// It might send a response packet
|
||||
type DefaultAction func()
|
||||
|
||||
// Internal method to call user hooks and register default behavior for a given message
|
||||
// Example:
|
||||
//
|
||||
// userMsgCallback(
|
||||
//
|
||||
// client.Callbacks.GameSvMotd,
|
||||
// &messages7.SvMotd{},
|
||||
// func() { fmt.Println("default action") },
|
||||
//
|
||||
// )
|
||||
func userMsgCallback[T any](userCallbacks []func(T, DefaultAction), msg T, defaultAction DefaultAction) {
|
||||
if len(userCallbacks) == 0 {
|
||||
defaultAction()
|
||||
return
|
||||
}
|
||||
|
||||
for _, callback := range userCallbacks {
|
||||
callback(msg, defaultAction)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: this should be a map but the type checker broke me
|
||||
//
|
||||
// // key is the network7.MessageId
|
||||
// UserMsgCallbacks map[int]UserMsgCallback
|
||||
type UserMsgCallbacks struct {
|
||||
PacketIn func(*protocol7.Packet) bool
|
||||
PacketOut func(*protocol7.Packet) bool
|
||||
MsgUnknown func(*messages7.Unknown, DefaultAction)
|
||||
InternalError func(error)
|
||||
// return false to drop the packet
|
||||
PacketIn []func(*protocol7.Packet) bool
|
||||
// return false to drop the packet
|
||||
PacketOut []func(*protocol7.Packet) bool
|
||||
// return false to drop the error (ignore it)
|
||||
//
|
||||
// return true to pass the error on and finally throw
|
||||
InternalError []func(error) bool
|
||||
MsgUnknown []func(*messages7.Unknown, DefaultAction)
|
||||
Snapshot []func(*snapshot7.Snapshot, DefaultAction)
|
||||
|
||||
CtrlKeepAlive func(*messages7.CtrlKeepAlive, DefaultAction)
|
||||
CtrlConnect func(*messages7.CtrlConnect, DefaultAction)
|
||||
CtrlAccept func(*messages7.CtrlAccept, DefaultAction)
|
||||
CtrlToken func(*messages7.CtrlToken, DefaultAction)
|
||||
CtrlClose func(*messages7.CtrlClose, DefaultAction)
|
||||
CtrlKeepAlive []func(*messages7.CtrlKeepAlive, DefaultAction)
|
||||
CtrlConnect []func(*messages7.CtrlConnect, DefaultAction)
|
||||
CtrlAccept []func(*messages7.CtrlAccept, DefaultAction)
|
||||
CtrlToken []func(*messages7.CtrlToken, DefaultAction)
|
||||
CtrlClose []func(*messages7.CtrlClose, DefaultAction)
|
||||
|
||||
SysInfo func(*messages7.Info, DefaultAction)
|
||||
SysMapChange func(*messages7.MapChange, DefaultAction)
|
||||
SysMapData func(*messages7.MapData, DefaultAction)
|
||||
SysServerInfo func(*messages7.ServerInfo, DefaultAction)
|
||||
SysConReady func(*messages7.ConReady, DefaultAction)
|
||||
SysSnap func(*messages7.Snap, DefaultAction)
|
||||
SysSnapEmpty func(*messages7.SnapEmpty, DefaultAction)
|
||||
SysSnapSingle func(*messages7.SnapSingle, DefaultAction)
|
||||
SysSnapSmall func(*messages7.SnapSmall, DefaultAction)
|
||||
SysInputTiming func(*messages7.InputTiming, DefaultAction)
|
||||
SysRconAuthOn func(*messages7.RconAuthOn, DefaultAction)
|
||||
SysRconAuthOff func(*messages7.RconAuthOff, DefaultAction)
|
||||
SysRconLine func(*messages7.RconLine, DefaultAction)
|
||||
SysRconCmdAdd func(*messages7.RconCmdAdd, DefaultAction)
|
||||
SysRconCmdRem func(*messages7.RconCmdRem, DefaultAction)
|
||||
SysAuthChallenge func(*messages7.AuthChallenge, DefaultAction)
|
||||
SysAuthResult func(*messages7.AuthResult, DefaultAction)
|
||||
SysReady func(*messages7.Ready, DefaultAction)
|
||||
SysEnterGame func(*messages7.EnterGame, DefaultAction)
|
||||
SysInput func(*messages7.Input, DefaultAction)
|
||||
SysRconCmd func(*messages7.RconCmd, DefaultAction)
|
||||
SysRconAuth func(*messages7.RconAuth, DefaultAction)
|
||||
SysRequestMapData func(*messages7.RequestMapData, DefaultAction)
|
||||
SysAuthStart func(*messages7.AuthStart, DefaultAction)
|
||||
SysAuthResponse func(*messages7.AuthResponse, DefaultAction)
|
||||
SysPing func(*messages7.Ping, DefaultAction)
|
||||
SysPingReply func(*messages7.PingReply, DefaultAction)
|
||||
SysError func(*messages7.Error, DefaultAction)
|
||||
SysMaplistEntryAdd func(*messages7.MaplistEntryAdd, DefaultAction)
|
||||
SysMaplistEntryRem func(*messages7.MaplistEntryRem, DefaultAction)
|
||||
SysInfo []func(*messages7.Info, DefaultAction)
|
||||
SysMapChange []func(*messages7.MapChange, DefaultAction)
|
||||
SysMapData []func(*messages7.MapData, DefaultAction)
|
||||
SysServerInfo []func(*messages7.ServerInfo, DefaultAction)
|
||||
SysConReady []func(*messages7.ConReady, DefaultAction)
|
||||
SysSnap []func(*messages7.Snap, DefaultAction)
|
||||
SysSnapEmpty []func(*messages7.SnapEmpty, DefaultAction)
|
||||
SysSnapSingle []func(*messages7.SnapSingle, DefaultAction)
|
||||
SysSnapSmall []func(*messages7.SnapSmall, DefaultAction)
|
||||
SysInputTiming []func(*messages7.InputTiming, DefaultAction)
|
||||
SysRconAuthOn []func(*messages7.RconAuthOn, DefaultAction)
|
||||
SysRconAuthOff []func(*messages7.RconAuthOff, DefaultAction)
|
||||
SysRconLine []func(*messages7.RconLine, DefaultAction)
|
||||
SysRconCmdAdd []func(*messages7.RconCmdAdd, DefaultAction)
|
||||
SysRconCmdRem []func(*messages7.RconCmdRem, DefaultAction)
|
||||
SysAuthChallenge []func(*messages7.AuthChallenge, DefaultAction)
|
||||
SysAuthResult []func(*messages7.AuthResult, DefaultAction)
|
||||
SysReady []func(*messages7.Ready, DefaultAction)
|
||||
SysEnterGame []func(*messages7.EnterGame, DefaultAction)
|
||||
SysInput []func(*messages7.Input, DefaultAction)
|
||||
SysRconCmd []func(*messages7.RconCmd, DefaultAction)
|
||||
SysRconAuth []func(*messages7.RconAuth, DefaultAction)
|
||||
SysRequestMapData []func(*messages7.RequestMapData, DefaultAction)
|
||||
SysAuthStart []func(*messages7.AuthStart, DefaultAction)
|
||||
SysAuthResponse []func(*messages7.AuthResponse, DefaultAction)
|
||||
SysPing []func(*messages7.Ping, DefaultAction)
|
||||
SysPingReply []func(*messages7.PingReply, DefaultAction)
|
||||
SysError []func(*messages7.Error, DefaultAction)
|
||||
SysMaplistEntryAdd []func(*messages7.MaplistEntryAdd, DefaultAction)
|
||||
SysMaplistEntryRem []func(*messages7.MaplistEntryRem, DefaultAction)
|
||||
|
||||
GameSvMotd func(*messages7.SvMotd, DefaultAction)
|
||||
GameSvBroadcast func(*messages7.SvBroadcast, DefaultAction)
|
||||
GameSvChat func(*messages7.SvChat, DefaultAction)
|
||||
GameSvTeam func(*messages7.SvTeam, DefaultAction)
|
||||
// GameSvKillMsg func(*messages7.SvKillMsg, DefaultAction)
|
||||
// GameSvTuneParams func(*messages7.SvTuneParams, DefaultAction)
|
||||
// GameSvExtraProjectile func(*messages7.SvExtraProjectile, DefaultAction)
|
||||
GameReadyToEnter func(*messages7.SvReadyToEnter, DefaultAction)
|
||||
// GameWeaponPickup func(*messages7.SvWeaponPickup, DefaultAction)
|
||||
// GameEmoticon func(*messages7.SvEmoticon, DefaultAction)
|
||||
// GameSvVoteClearoptions func(*messages7.SvVoteClearoptions, DefaultAction)
|
||||
// GameSvVoteOptionlistadd func(*messages7.SvVoteOptionlistadd, DefaultAction)
|
||||
// GameSvVotePptionadd func(*messages7.SvVotePptionadd, DefaultAction)
|
||||
// GameSvVoteOptionremove func(*messages7.SvVoteOptionremove, DefaultAction)
|
||||
// GameSvVoteSet func(*messages7.SvVoteSet, DefaultAction)
|
||||
// GameSvVoteStatus func(*messages7.SvVoteStatus, DefaultAction)
|
||||
// GameSvServerSettings func(*messages7.SvServerSettings, DefaultAction)
|
||||
GameSvClientInfo func(*messages7.SvClientInfo, DefaultAction)
|
||||
// GameSvGameInfo func(*messages7.SvGameInfo, DefaultAction)
|
||||
// GameSvClientDrop func(*messages7.SvClientDrop, DefaultAction)
|
||||
// GameSvGameMsg func(*messages7.SvGameMsg, DefaultAction)
|
||||
// GameDeClientEnter func(*messages7.DeClientEnter, DefaultAction)
|
||||
// GameDeClientLeave func(*messages7.DeClientLeave, DefaultAction)
|
||||
// GameClSay func(*messages7.ClSay, DefaultAction)
|
||||
// GameClSetTeam func(*messages7.ClSetTeam, DefaultAction)
|
||||
// GameClSetSpectatorMode func(*messages7.ClSetSpectatorMode, DefaultAction)
|
||||
GameClStartInfo func(*messages7.ClStartInfo, DefaultAction)
|
||||
// GameClKill func(*messages7.ClKill, DefaultAction)
|
||||
// GameClReadyChange func(*messages7.ClReadyChange, DefaultAction)
|
||||
// GameClEmoticon func(*messages7.ClEmoticon, DefaultAction)
|
||||
// GameClVote func(*messages7.ClVote, DefaultAction)
|
||||
// GameClCallVote func(*messages7.ClCallVote, DefaultAction)
|
||||
// GameSvSkinChange func(*messages7.SvSkinChange, DefaultAction)
|
||||
// GameClSkinChange func(*messages7.ClSkinChange, DefaultAction)
|
||||
// GameSvRaceFinish func(*messages7.SvRaceFinish, DefaultAction)
|
||||
// GameSvCheckpoint func(*messages7.SvCheckpoint, DefaultAction)
|
||||
// GameSvCommandInfo func(*messages7.SvCommandInfo, DefaultAction)
|
||||
// GameSvCommandInfoRemove func(*messages7.SvCommandInfoRemove, DefaultAction)
|
||||
// GameClCommand func(*messages7.ClCommand, DefaultAction)
|
||||
GameSvMotd []func(*messages7.SvMotd, DefaultAction)
|
||||
GameSvBroadcast []func(*messages7.SvBroadcast, DefaultAction)
|
||||
GameSvChat []func(*messages7.SvChat, DefaultAction)
|
||||
GameSvTeam []func(*messages7.SvTeam, DefaultAction)
|
||||
// GameSvKillMsg []func(*messages7.SvKillMsg, DefaultAction)
|
||||
// GameSvTuneParams []func(*messages7.SvTuneParams, DefaultAction)
|
||||
// GameSvExtraProjectile []func(*messages7.SvExtraProjectile, DefaultAction)
|
||||
GameSvReadyToEnter []func(*messages7.SvReadyToEnter, DefaultAction)
|
||||
// GameWeaponPickup []func(*messages7.SvWeaponPickup, DefaultAction)
|
||||
// GameEmoticon []func(*messages7.SvEmoticon, DefaultAction)
|
||||
// GameSvVoteClearoptions []func(*messages7.SvVoteClearoptions, DefaultAction)
|
||||
// GameSvVoteOptionlistadd []func(*messages7.SvVoteOptionlistadd, DefaultAction)
|
||||
// GameSvVotePptionadd []func(*messages7.SvVotePptionadd, DefaultAction)
|
||||
// GameSvVoteOptionremove []func(*messages7.SvVoteOptionremove, DefaultAction)
|
||||
// GameSvVoteSet []func(*messages7.SvVoteSet, DefaultAction)
|
||||
// GameSvVoteStatus []func(*messages7.SvVoteStatus, DefaultAction)
|
||||
// GameSvServerSettings []func(*messages7.SvServerSettings, DefaultAction)
|
||||
GameSvClientInfo []func(*messages7.SvClientInfo, DefaultAction)
|
||||
// GameSvGameInfo []func(*messages7.SvGameInfo, DefaultAction)
|
||||
// GameSvClientDrop []func(*messages7.SvClientDrop, DefaultAction)
|
||||
// GameSvGameMsg []func(*messages7.SvGameMsg, DefaultAction)
|
||||
// GameDeClientEnter []func(*messages7.DeClientEnter, DefaultAction)
|
||||
// GameDeClientLeave []func(*messages7.DeClientLeave, DefaultAction)
|
||||
// GameClSay []func(*messages7.ClSay, DefaultAction)
|
||||
// GameClSetTeam []func(*messages7.ClSetTeam, DefaultAction)
|
||||
// GameClSetSpectatorMode []func(*messages7.ClSetSpectatorMode, DefaultAction)
|
||||
GameClStartInfo []func(*messages7.ClStartInfo, DefaultAction)
|
||||
// GameClKill []func(*messages7.ClKill, DefaultAction)
|
||||
// GameClReadyChange []func(*messages7.ClReadyChange, DefaultAction)
|
||||
// GameClEmoticon []func(*messages7.ClEmoticon, DefaultAction)
|
||||
// GameClVote []func(*messages7.ClVote, DefaultAction)
|
||||
// GameClCallVote []func(*messages7.ClCallVote, DefaultAction)
|
||||
// GameSvSkinChange []func(*messages7.SvSkinChange, DefaultAction)
|
||||
// GameClSkinChange []func(*messages7.ClSkinChange, DefaultAction)
|
||||
// GameSvRaceFinish []func(*messages7.SvRaceFinish, DefaultAction)
|
||||
// GameSvCheckpoint []func(*messages7.SvCheckpoint, DefaultAction)
|
||||
// GameSvCommandInfo []func(*messages7.SvCommandInfo, DefaultAction)
|
||||
// GameSvCommandInfoRemove []func(*messages7.SvCommandInfoRemove, DefaultAction)
|
||||
// GameClCommand []func(*messages7.ClCommand, DefaultAction)
|
||||
}
|
||||
|
|
|
@ -39,9 +39,11 @@ type Client struct {
|
|||
}
|
||||
|
||||
func (client *Client) throwError(err error) {
|
||||
if client.Callbacks.InternalError != nil {
|
||||
client.Callbacks.InternalError(err)
|
||||
return
|
||||
for _, callback := range client.Callbacks.InternalError {
|
||||
if callback(err) == false {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -11,70 +11,40 @@ import (
|
|||
func (client *Client) processGame(netMsg messages7.NetMessage, response *protocol7.Packet) bool {
|
||||
switch msg := netMsg.(type) {
|
||||
case *messages7.SvMotd:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.GameSvMotd, msg, func() {
|
||||
if msg.Message != "" {
|
||||
fmt.Printf("[motd] %s\n", msg.Message)
|
||||
}
|
||||
}
|
||||
if client.Callbacks.GameSvMotd == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.GameSvMotd(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.SvBroadcast:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.GameSvBroadcast, msg, func() {
|
||||
fmt.Printf("[broadcast] %s\n", msg.Message)
|
||||
}
|
||||
if client.Callbacks.GameSvBroadcast == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.GameSvBroadcast(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.SvChat:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.GameSvChat, msg, func() {
|
||||
if msg.ClientId < 0 || msg.ClientId > network7.MaxClients {
|
||||
fmt.Printf("[chat] *** %s\n", msg.Message)
|
||||
return
|
||||
}
|
||||
name := client.Game.Players[msg.ClientId].Info.Name
|
||||
fmt.Printf("[chat] <%s> %s\n", name, msg.Message)
|
||||
}
|
||||
if client.Callbacks.GameSvChat == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.GameSvChat(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.SvClientInfo:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.GameSvClientInfo, msg, func() {
|
||||
client.Game.Players[msg.ClientId].Info = *msg
|
||||
fmt.Printf("got client info id=%d name=%s\n", msg.ClientId, msg.Name)
|
||||
}
|
||||
if client.Callbacks.GameSvClientInfo == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.GameSvClientInfo(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.SvReadyToEnter:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.GameSvReadyToEnter, msg, func() {
|
||||
fmt.Println("got ready to enter")
|
||||
response.Messages = append(response.Messages, &messages7.EnterGame{})
|
||||
}
|
||||
if client.Callbacks.GameReadyToEnter == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.GameReadyToEnter(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.Unknown:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.MsgUnknown, msg, func() {
|
||||
// TODO: msg id of unknown messages should not be -1
|
||||
fmt.Println("TODO: why is the msg id -1???")
|
||||
printUnknownMessage(msg, "unknown game")
|
||||
}
|
||||
if client.Callbacks.MsgUnknown == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.MsgUnknown(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
default:
|
||||
printUnknownMessage(netMsg, "unprocessed game")
|
||||
return false
|
||||
|
|
|
@ -38,8 +38,8 @@ func (client *Client) processMessage(msg messages7.NetMessage, response *protoco
|
|||
}
|
||||
|
||||
func (client *Client) processPacket(packet *protocol7.Packet) error {
|
||||
if client.Callbacks.PacketIn != nil {
|
||||
if client.Callbacks.PacketIn(packet) == false {
|
||||
for _, callback := range client.Callbacks.PacketIn {
|
||||
if callback(packet) == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
@ -55,26 +55,16 @@ func (client *Client) processPacket(packet *protocol7.Packet) error {
|
|||
// TODO: is this shadow nasty?
|
||||
switch msg := msg.(type) {
|
||||
case *messages7.CtrlKeepAlive:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.CtrlKeepAlive, msg, func() {
|
||||
fmt.Println("got keep alive")
|
||||
}
|
||||
if client.Callbacks.CtrlKeepAlive == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.CtrlKeepAlive(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.CtrlConnect:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.CtrlConnect, msg, func() {
|
||||
fmt.Println("we got connect as a client. this should never happen lol.")
|
||||
fmt.Println("who is tryint to connect to us? We are not a server!")
|
||||
}
|
||||
if client.Callbacks.CtrlConnect == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.CtrlConnect(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.CtrlAccept:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.CtrlAccept, msg, func() {
|
||||
fmt.Println("got accept")
|
||||
response.Messages = append(
|
||||
response.Messages,
|
||||
|
@ -85,23 +75,13 @@ func (client *Client) processPacket(packet *protocol7.Packet) error {
|
|||
},
|
||||
)
|
||||
client.SendPacket(response)
|
||||
}
|
||||
if client.Callbacks.CtrlAccept == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.CtrlAccept(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.CtrlClose:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.CtrlClose, msg, func() {
|
||||
fmt.Printf("disconnected (%s)\n", msg.Reason)
|
||||
}
|
||||
if client.Callbacks.CtrlClose == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.CtrlClose(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.CtrlToken:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.CtrlToken, msg, func() {
|
||||
fmt.Printf("got server token %x\n", msg.Token)
|
||||
client.Session.ServerToken = msg.Token
|
||||
response.Header.Token = msg.Token
|
||||
|
@ -112,21 +92,11 @@ func (client *Client) processPacket(packet *protocol7.Packet) error {
|
|||
},
|
||||
)
|
||||
client.SendPacket(response)
|
||||
}
|
||||
if client.Callbacks.CtrlToken == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.CtrlToken(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.Unknown:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.MsgUnknown, msg, func() {
|
||||
printUnknownMessage(msg, "unknown control")
|
||||
}
|
||||
if client.Callbacks.MsgUnknown == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.MsgUnknown(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
return fmt.Errorf("unknown control message: %d\n", msg.MsgId())
|
||||
default:
|
||||
return fmt.Errorf("unprocessed control message: %d\n", msg.MsgId())
|
||||
|
|
|
@ -10,35 +10,20 @@ import (
|
|||
func (client *Client) processSystem(netMsg messages7.NetMessage, response *protocol7.Packet) bool {
|
||||
switch msg := netMsg.(type) {
|
||||
case *messages7.MapChange:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysMapChange, msg, func() {
|
||||
fmt.Println("got map change")
|
||||
response.Messages = append(response.Messages, &messages7.Ready{})
|
||||
}
|
||||
if client.Callbacks.SysMapChange == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysMapChange(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.MapData:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysMapData, msg, func() {
|
||||
fmt.Printf("got map chunk %x\n", msg.Data)
|
||||
}
|
||||
if client.Callbacks.SysMapData == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysMapData(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.ServerInfo:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysServerInfo, msg, func() {
|
||||
fmt.Printf("connected to server with name '%s'\n", msg.Name)
|
||||
}
|
||||
if client.Callbacks.SysServerInfo == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysServerInfo(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.ConReady:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysConReady, msg, func() {
|
||||
fmt.Println("connected, sending info")
|
||||
info := &messages7.ClStartInfo{
|
||||
Name: client.Name,
|
||||
|
@ -64,86 +49,49 @@ func (client *Client) processSystem(netMsg messages7.NetMessage, response *proto
|
|||
ColorEyes: 0,
|
||||
}
|
||||
response.Messages = append(response.Messages, info)
|
||||
}
|
||||
if client.Callbacks.SysConReady == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysConReady(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.Snap:
|
||||
// fmt.Printf("got snap tick=%d\n", msg.GameTick)
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
userMsgCallback(client.Callbacks.SysSnap, msg, func() {
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
})
|
||||
case *messages7.SnapSingle:
|
||||
// fmt.Printf("got snap single tick=%d\n", msg.GameTick)
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
userMsgCallback(client.Callbacks.SysSnapSingle, msg, func() {
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
})
|
||||
case *messages7.SnapEmpty:
|
||||
// fmt.Printf("got snap empty tick=%d\n", msg.GameTick)
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
userMsgCallback(client.Callbacks.SysSnapEmpty, msg, func() {
|
||||
response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{})
|
||||
})
|
||||
case *messages7.InputTiming:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysInputTiming, msg, func() {
|
||||
fmt.Printf("timing time left=%d\n", msg.TimeLeft)
|
||||
}
|
||||
if client.Callbacks.SysInputTiming == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysInputTiming(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.RconAuthOn:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysRconAuthOn, msg, func() {
|
||||
fmt.Println("you are now authenticated in rcon")
|
||||
}
|
||||
if client.Callbacks.SysRconAuthOn == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysRconAuthOn(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.RconAuthOff:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysRconAuthOff, msg, func() {
|
||||
fmt.Println("you are no longer authenticated in rcon")
|
||||
}
|
||||
if client.Callbacks.SysRconAuthOff == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysRconAuthOff(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.RconLine:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysRconLine, msg, func() {
|
||||
fmt.Printf("[rcon] %s\n", msg.Line)
|
||||
}
|
||||
if client.Callbacks.SysRconLine == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysRconLine(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.RconCmdAdd:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysRconCmdAdd, msg, func() {
|
||||
fmt.Printf("got rcon cmd=%s %s %s\n", msg.Name, msg.Params, msg.Help)
|
||||
}
|
||||
if client.Callbacks.SysRconCmdAdd == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysRconCmdAdd(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.RconCmdRem:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.SysRconCmdRem, msg, func() {
|
||||
fmt.Printf("removed cmd=%s\n", msg.Name)
|
||||
}
|
||||
if client.Callbacks.SysRconCmdRem == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.SysRconCmdRem(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
case *messages7.Unknown:
|
||||
defaultAction := func() {
|
||||
userMsgCallback(client.Callbacks.MsgUnknown, msg, func() {
|
||||
// TODO: msg id of unknown messages should not be -1
|
||||
fmt.Println("TODO: why is the msg id -1???")
|
||||
printUnknownMessage(msg, "unknown system")
|
||||
}
|
||||
if client.Callbacks.MsgUnknown == nil {
|
||||
defaultAction()
|
||||
} else {
|
||||
client.Callbacks.MsgUnknown(msg, defaultAction)
|
||||
}
|
||||
})
|
||||
default:
|
||||
printUnknownMessage(netMsg, "unprocessed system")
|
||||
return false
|
||||
|
|
|
@ -12,20 +12,6 @@ import (
|
|||
// low level access for experts
|
||||
// ----------------------------
|
||||
|
||||
// flish()boo {
|
||||
//
|
||||
// ifhf lenesusue
|
||||
// packte:=}{}
|
||||
// SendPkacte8)
|
||||
//
|
||||
// }
|
||||
//
|
||||
// if now > lastsnend d+9191 {
|
||||
// if !flush() {
|
||||
// keepalive
|
||||
// }
|
||||
// }A
|
||||
|
||||
func (client *Client) SendPacket(packet *protocol7.Packet) error {
|
||||
if packet.Header.Flags.Resend == false && len(packet.Messages) == 0 && len(client.QueuedMessages) == 0 {
|
||||
return fmt.Errorf("Failed to send packet: payload is empty.")
|
||||
|
@ -76,11 +62,12 @@ func (client *Client) SendPacket(packet *protocol7.Packet) error {
|
|||
}
|
||||
client.QueuedMessages = nil
|
||||
|
||||
if client.Callbacks.PacketOut != nil {
|
||||
if client.Callbacks.PacketOut(packet) == false {
|
||||
for _, callback := range client.Callbacks.PacketOut {
|
||||
if callback(packet) == false {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
client.Conn.Write(packet.Pack(&client.Session))
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ package teeworlds7
|
|||
import (
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||
"github.com/teeworlds-go/go-teeworlds-protocol/snapshot7"
|
||||
)
|
||||
|
||||
// --------------------------------
|
||||
|
@ -10,8 +11,11 @@ import (
|
|||
// --------------------------------
|
||||
|
||||
// if not implemented by the user the application might throw and exit
|
||||
func (client *Client) OnError(callback func(err error)) {
|
||||
client.Callbacks.InternalError = callback
|
||||
//
|
||||
// return false to drop the error
|
||||
// return true if you did not handle the error and it should be passed on (will crash unless someone else catches it)
|
||||
func (client *Client) OnError(callback func(err error) bool) {
|
||||
client.Callbacks.InternalError = append(client.Callbacks.InternalError, callback)
|
||||
}
|
||||
|
||||
// inspect outgoing traffic
|
||||
|
@ -19,7 +23,7 @@ func (client *Client) OnError(callback func(err error)) {
|
|||
//
|
||||
// return false to drop the packet
|
||||
func (client *Client) OnSend(callback func(packet *protocol7.Packet) bool) {
|
||||
client.Callbacks.PacketOut = callback
|
||||
client.Callbacks.PacketOut = append(client.Callbacks.PacketOut, callback)
|
||||
}
|
||||
|
||||
// read incoming traffic
|
||||
|
@ -27,11 +31,17 @@ func (client *Client) OnSend(callback func(packet *protocol7.Packet) bool) {
|
|||
//
|
||||
// return false to drop the packet
|
||||
func (client *Client) OnPacket(callback func(packet *protocol7.Packet) bool) {
|
||||
client.Callbacks.PacketIn = callback
|
||||
client.Callbacks.PacketIn = append(client.Callbacks.PacketIn, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnUnknown(callback func(msg *messages7.Unknown, defaultAction DefaultAction)) {
|
||||
client.Callbacks.MsgUnknown = callback
|
||||
client.Callbacks.MsgUnknown = append(client.Callbacks.MsgUnknown, callback)
|
||||
}
|
||||
|
||||
// will be called when a snap, snap single or empty snapshot is received
|
||||
// if you want to know which type of snapshot was received look at OnMsgSnap(), OnMsgSnapEmpty(), OnMsgSnapSingle(), OnMsgSnapSmall()
|
||||
func (client *Client) OnSnapshot(callback func(snap *snapshot7.Snapshot, defaultAction DefaultAction)) {
|
||||
client.Callbacks.Snapshot = append(client.Callbacks.Snapshot, callback)
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
|
@ -39,24 +49,24 @@ func (client *Client) OnUnknown(callback func(msg *messages7.Unknown, defaultAct
|
|||
// --------------------------------
|
||||
|
||||
func (client *Client) OnKeepAlive(callback func(msg *messages7.CtrlKeepAlive, defaultAction DefaultAction)) {
|
||||
client.Callbacks.CtrlKeepAlive = callback
|
||||
client.Callbacks.CtrlKeepAlive = append(client.Callbacks.CtrlKeepAlive, callback)
|
||||
}
|
||||
|
||||
// This is just misleading. It should never be called. This message is only received by the server.
|
||||
// func (client *Client) OnCtrlConnect(callback func(msg *messages7.CtrlConnect, defaultAction DefaultAction)) {
|
||||
// client.Callbacks.CtrlConnect = callback
|
||||
// client.Callbacks.CtrlConnect = append(// client.Callbacks, callback)
|
||||
// }
|
||||
|
||||
func (client *Client) OnAccept(callback func(msg *messages7.CtrlAccept, defaultAction DefaultAction)) {
|
||||
client.Callbacks.CtrlAccept = callback
|
||||
client.Callbacks.CtrlAccept = append(client.Callbacks.CtrlAccept, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnDisconnect(callback func(msg *messages7.CtrlClose, defaultAction DefaultAction)) {
|
||||
client.Callbacks.CtrlClose = callback
|
||||
client.Callbacks.CtrlClose = append(client.Callbacks.CtrlClose, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnToken(callback func(msg *messages7.CtrlToken, defaultAction DefaultAction)) {
|
||||
client.Callbacks.CtrlToken = callback
|
||||
client.Callbacks.CtrlToken = append(client.Callbacks.CtrlToken, callback)
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
|
@ -64,19 +74,19 @@ func (client *Client) OnToken(callback func(msg *messages7.CtrlToken, defaultAct
|
|||
// --------------------------------
|
||||
|
||||
func (client *Client) OnMotd(callback func(msg *messages7.SvMotd, defaultAction DefaultAction)) {
|
||||
client.Callbacks.GameSvMotd = callback
|
||||
client.Callbacks.GameSvMotd = append(client.Callbacks.GameSvMotd, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnBroadcast(callback func(msg *messages7.SvBroadcast, defaultAction DefaultAction)) {
|
||||
client.Callbacks.GameSvBroadcast = callback
|
||||
client.Callbacks.GameSvBroadcast = append(client.Callbacks.GameSvBroadcast, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnChat(callback func(msg *messages7.SvChat, defaultAction DefaultAction)) {
|
||||
client.Callbacks.GameSvChat = callback
|
||||
client.Callbacks.GameSvChat = append(client.Callbacks.GameSvChat, callback)
|
||||
}
|
||||
|
||||
func (client *Client) OnTeam(callback func(msg *messages7.SvTeam, defaultAction DefaultAction)) {
|
||||
client.Callbacks.GameSvTeam = callback
|
||||
client.Callbacks.GameSvTeam = append(client.Callbacks.GameSvTeam, callback)
|
||||
}
|
||||
|
||||
// --------------------------------
|
||||
|
@ -84,5 +94,25 @@ func (client *Client) OnTeam(callback func(msg *messages7.SvTeam, defaultAction
|
|||
// --------------------------------
|
||||
|
||||
func (client *Client) OnMapChange(callback func(msg *messages7.MapChange, defaultAction DefaultAction)) {
|
||||
client.Callbacks.SysMapChange = callback
|
||||
client.Callbacks.SysMapChange = append(client.Callbacks.SysMapChange, callback)
|
||||
}
|
||||
|
||||
// You probably want to use OnSnapshot() instead
|
||||
func (client *Client) OnMsgSnap(callback func(msg *messages7.Snap, defaultAction DefaultAction)) {
|
||||
client.Callbacks.SysSnap = append(client.Callbacks.SysSnap, callback)
|
||||
}
|
||||
|
||||
// You probably want to use OnSnapshot() instead
|
||||
func (client *Client) OnMsgSnapEmpty(callback func(msg *messages7.SnapEmpty, defaultAction DefaultAction)) {
|
||||
client.Callbacks.SysSnapEmpty = append(client.Callbacks.SysSnapEmpty, callback)
|
||||
}
|
||||
|
||||
// You probably want to use OnSnapshot() instead
|
||||
func (client *Client) OnMsgSnapSingle(callback func(msg *messages7.SnapSingle, defaultAction DefaultAction)) {
|
||||
client.Callbacks.SysSnapSingle = append(client.Callbacks.SysSnapSingle, callback)
|
||||
}
|
||||
|
||||
// You probably want to use OnSnapshot() instead
|
||||
func (client *Client) OnMsgSnapSmall(callback func(msg *messages7.SnapSmall, defaultAction DefaultAction)) {
|
||||
client.Callbacks.SysSnapSmall = append(client.Callbacks.SysSnapSmall, callback)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue