diff --git a/messages7/snap_single.go b/messages7/snap_single.go index 71ba708..c092423 100644 --- a/messages7/snap_single.go +++ b/messages7/snap_single.go @@ -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 } diff --git a/network6/network6.go b/network6/network6.go new file mode 100644 index 0000000..8e2d376 --- /dev/null +++ b/network6/network6.go @@ -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 +) diff --git a/network7/network7.go b/network7/network7.go index 7b4cc6c..7920974 100644 --- a/network7/network7.go +++ b/network7/network7.go @@ -21,6 +21,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 +69,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 +190,9 @@ const ( NumWeapons Weapon = 6 ) +type GameStateFlag int type Vote int +type Pickup int type Emote int type ChatMode int type GameTeam int diff --git a/object7/character.go b/object7/character.go new file mode 100644 index 0000000..b952b2a --- /dev/null +++ b/object7/character.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/flag.go b/object7/flag.go new file mode 100644 index 0000000..22af572 --- /dev/null +++ b/object7/flag.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/game_data.go b/object7/game_data.go new file mode 100644 index 0000000..0f93fe4 --- /dev/null +++ b/object7/game_data.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/game_data_flag.go b/object7/game_data_flag.go new file mode 100644 index 0000000..c9964f4 --- /dev/null +++ b/object7/game_data_flag.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/game_data_team.go b/object7/game_data_team.go new file mode 100644 index 0000000..c249ed2 --- /dev/null +++ b/object7/game_data_team.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/pickup.go b/object7/pickup.go new file mode 100644 index 0000000..1b84f46 --- /dev/null +++ b/object7/pickup.go @@ -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 + PickupType network7.Pickup +} + +func (o *Pickup) Id() int { + return o.ItemId +} + +func (o *Pickup) Type() 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.Type()), + packer.PackInt(o.Id()), + + packer.PackInt(o.X), + packer.PackInt(o.Y), + packer.PackInt(int(o.PickupType)), + ) +} + +func (o *Pickup) Unpack(u *packer.Unpacker) error { + o.X = u.GetInt() + o.Y = u.GetInt() + o.PickupType = network7.Pickup(u.GetInt()) + + return nil +} diff --git a/object7/player_info.go b/object7/player_info.go new file mode 100644 index 0000000..d596988 --- /dev/null +++ b/object7/player_info.go @@ -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) Type() 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.Type()), + 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 +} diff --git a/object7/snap_object.go b/object7/snap_object.go new file mode 100644 index 0000000..7be5789 --- /dev/null +++ b/object7/snap_object.go @@ -0,0 +1,49 @@ +package object7 + +import ( + "log" + + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type SnapObject interface { + Id() int + Type() 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(itemType int, itemId int) SnapObject { + if itemType == network7.ObjFlag { + return &Flag{ItemId: itemId} + } else if itemType == network7.ObjPickup { + return &Pickup{ItemId: itemId} + } else if itemType == network7.ObjGameData { + return &GameData{ItemId: itemId} + } else if itemType == network7.ObjGameDataTeam { + return &GameDataTeam{ItemId: itemId} + } else if itemType == network7.ObjGameDataFlag { + return &GameDataFlag{ItemId: itemId} + } else if itemType == network7.ObjCharacter { + return &Character{ItemId: itemId} + } else if itemType == network7.ObjPlayerInfo { + return &PlayerInfo{ItemId: itemId} + } + + // TODO: remove this is just for debugging + log.Fatalf("unknown item type %d\n", itemType) + + unknown := &Unknown{ + ItemId: itemId, + ItemType: itemType, + } + return unknown +} diff --git a/object7/unknown.go b/object7/unknown.go new file mode 100644 index 0000000..3dafeb3 --- /dev/null +++ b/object7/unknown.go @@ -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) Type() int { + return o.ItemType +} + +func (o *Unknown) Size() int { + return o.ItemSize +} + +func (o *Unknown) Pack() []byte { + data := slices.Concat( + packer.PackInt(o.Type()), + 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 +} diff --git a/packer/packer.go b/packer/packer.go index 15973f3..ffd254d 100644 --- a/packer/packer.go +++ b/packer/packer.go @@ -31,7 +31,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 ( diff --git a/packer/packer_state_test.go b/packer/packer_state_test.go index a541712..08a1be3 100644 --- a/packer/packer_state_test.go +++ b/packer/packer_state_test.go @@ -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 diff --git a/snapshot7/snapshot7.go b/snapshot7/snapshot7.go new file mode 100644 index 0000000..c14f80e --- /dev/null +++ b/snapshot7/snapshot7.go @@ -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 +} diff --git a/snapshot7/snapshot_test.go b/snapshot7/snapshot_test.go new file mode 100644 index 0000000..312cd89 --- /dev/null +++ b/snapshot7/snapshot_test.go @@ -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 TestRepackSnapshot(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 +} diff --git a/teeworlds7/callbacks.go b/teeworlds7/callbacks.go index 6d2f44b..ee8ac0f 100644 --- a/teeworlds7/callbacks.go +++ b/teeworlds7/callbacks.go @@ -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 @@ -19,6 +20,7 @@ type UserMsgCallbacks struct { PacketOut func(*protocol7.Packet) bool MsgUnknown func(*messages7.Unknown, DefaultAction) InternalError func(error) + Snapshot func(*snapshot7.Snapshot, DefaultAction) CtrlKeepAlive func(*messages7.CtrlKeepAlive, DefaultAction) CtrlConnect func(*messages7.CtrlConnect, DefaultAction) diff --git a/teeworlds7/user_hooks.go b/teeworlds7/user_hooks.go index 0437fed..13354af 100644 --- a/teeworlds7/user_hooks.go +++ b/teeworlds7/user_hooks.go @@ -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" ) // -------------------------------- @@ -34,6 +35,12 @@ func (client *Client) OnUnknown(callback func(msg *messages7.Unknown, defaultAct 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 = callback +} + // -------------------------------- // control messages // -------------------------------- @@ -86,3 +93,23 @@ 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 } + +// You probably want to use OnSnapshot() instead +func (client *Client) OnMsgSnap(callback func(msg *messages7.Snap, defaultAction DefaultAction)) { + 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 = callback +} + +// You probably want to use OnSnapshot() instead +func (client *Client) OnMsgSnapSingle(callback func(msg *messages7.SnapSingle, defaultAction DefaultAction)) { + 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 = callback +}