First draft of snap unpacking
This commit is contained in:
parent
8acb893165
commit
72b008f6d8
|
@ -6,6 +6,7 @@ import (
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/chunk7"
|
"github.com/teeworlds-go/go-teeworlds-protocol/chunk7"
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
"github.com/teeworlds-go/go-teeworlds-protocol/packer"
|
||||||
|
"github.com/teeworlds-go/go-teeworlds-protocol/snapshot7"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SnapSingle struct {
|
type SnapSingle struct {
|
||||||
|
@ -15,7 +16,11 @@ type SnapSingle struct {
|
||||||
DeltaTick int
|
DeltaTick int
|
||||||
Crc int
|
Crc int
|
||||||
PartSize 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 {
|
func (msg *SnapSingle) MsgId() int {
|
||||||
|
@ -50,6 +55,14 @@ func (msg *SnapSingle) Unpack(u *packer.Unpacker) error {
|
||||||
msg.Crc = u.GetInt()
|
msg.Crc = u.GetInt()
|
||||||
msg.PartSize = u.GetInt()
|
msg.PartSize = u.GetInt()
|
||||||
msg.Data = u.Rest()
|
msg.Data = u.Rest()
|
||||||
|
|
||||||
|
// genius
|
||||||
|
u.Reset(msg.Data)
|
||||||
|
err := msg.Snapshot.Unpack(u)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
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
|
||||||
|
)
|
|
@ -21,6 +21,22 @@ const (
|
||||||
VoteEndPass Vote = 5
|
VoteEndPass Vote = 5
|
||||||
VoteEndFail Vote = 6
|
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!
|
// oop!
|
||||||
EmoteOop Emote = 0
|
EmoteOop Emote = 0
|
||||||
// !
|
// !
|
||||||
|
@ -53,6 +69,33 @@ const (
|
||||||
MsgCtrlToken = 0x05
|
MsgCtrlToken = 0x05
|
||||||
MsgCtrlClose = 0x04
|
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
|
// 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
|
// same as ChatMode, etc. so that the user can easily see which integer to pass
|
||||||
// to which function as which parameter
|
// to which function as which parameter
|
||||||
|
@ -147,7 +190,9 @@ const (
|
||||||
NumWeapons Weapon = 6
|
NumWeapons Weapon = 6
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type GameStateFlag int
|
||||||
type Vote int
|
type Vote int
|
||||||
|
type Pickup int
|
||||||
type Emote int
|
type Emote int
|
||||||
type ChatMode int
|
type ChatMode int
|
||||||
type GameTeam 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) 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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
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
|
||||||
|
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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
49
object7/snap_object.go
Normal file
49
object7/snap_object.go
Normal file
|
@ -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
|
||||||
|
}
|
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) 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
|
||||||
|
}
|
|
@ -31,7 +31,17 @@ func (u *Unpacker) Data() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Unpacker) Rest() []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 (
|
const (
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
"github.com/teeworlds-go/go-teeworlds-protocol/internal/testutils/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
// rest
|
// rest and remaining size
|
||||||
|
|
||||||
func TestUnpackRest(t *testing.T) {
|
func TestUnpackRest(t *testing.T) {
|
||||||
u := Unpacker{}
|
u := Unpacker{}
|
||||||
|
@ -16,6 +16,10 @@ func TestUnpackRest(t *testing.T) {
|
||||||
want := 1
|
want := 1
|
||||||
got := u.GetInt()
|
got := u.GetInt()
|
||||||
require.Equal(t, want, got)
|
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()
|
got := u.Rest()
|
||||||
require.Equal(t, want, got)
|
require.Equal(t, want, got)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
want := 0
|
||||||
|
got := u.RemainingSize()
|
||||||
|
require.Equal(t, want, got)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// client info
|
// client info
|
||||||
|
|
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
|
||||||
|
}
|
47
snapshot7/snapshot_test.go
Normal file
47
snapshot7/snapshot_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 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
|
||||||
|
}
|
|
@ -3,6 +3,7 @@ package teeworlds7
|
||||||
import (
|
import (
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
||||||
|
"github.com/teeworlds-go/go-teeworlds-protocol/snapshot7"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Processes the incoming packet
|
// Processes the incoming packet
|
||||||
|
@ -19,6 +20,7 @@ type UserMsgCallbacks struct {
|
||||||
PacketOut func(*protocol7.Packet) bool
|
PacketOut func(*protocol7.Packet) bool
|
||||||
MsgUnknown func(*messages7.Unknown, DefaultAction)
|
MsgUnknown func(*messages7.Unknown, DefaultAction)
|
||||||
InternalError func(error)
|
InternalError func(error)
|
||||||
|
Snapshot func(*snapshot7.Snapshot, DefaultAction)
|
||||||
|
|
||||||
CtrlKeepAlive func(*messages7.CtrlKeepAlive, DefaultAction)
|
CtrlKeepAlive func(*messages7.CtrlKeepAlive, DefaultAction)
|
||||||
CtrlConnect func(*messages7.CtrlConnect, DefaultAction)
|
CtrlConnect func(*messages7.CtrlConnect, DefaultAction)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package teeworlds7
|
||||||
import (
|
import (
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
|
||||||
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
|
"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
|
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
|
// 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)) {
|
func (client *Client) OnMapChange(callback func(msg *messages7.MapChange, defaultAction DefaultAction)) {
|
||||||
client.Callbacks.SysMapChange = callback
|
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
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue