From 0a88246a9aac55f4938e5640ef49882ad8d4f6d0 Mon Sep 17 00:00:00 2001 From: ChillerDragon Date: Sun, 23 Jun 2024 12:19:27 +0800 Subject: [PATCH] Finish 0.7 system messages --- messages7/auth_challenge.go | 43 +++++++++++++ messages7/auth_response.go | 43 +++++++++++++ messages7/auth_result.go | 43 +++++++++++++ messages7/auth_start.go | 43 +++++++++++++ messages7/error.go | 43 +++++++++++++ messages7/info.go | 40 ++++++++++--- messages7/input.go | 80 +++++++++++++++++++++++++ messages7/map_data.go | 45 ++++++++++++++ messages7/maplist_entry_add.go | 49 +++++++++++++++ messages7/maplist_entry_rem.go | 49 +++++++++++++++ messages7/ping.go | 42 +++++++++++++ messages7/ping_reply.go | 42 +++++++++++++ messages7/rcon_auth.go | 49 +++++++++++++++ messages7/rcon_auth_off.go | 42 +++++++++++++ messages7/rcon_auth_on.go | 42 +++++++++++++ messages7/rcon_cmd.go | 49 +++++++++++++++ messages7/rcon_cmd_add.go | 55 +++++++++++++++++ messages7/rcon_cmd_rem.go | 49 +++++++++++++++ messages7/rcon_line.go | 49 +++++++++++++++ messages7/request_map_data.go | 42 +++++++++++++ messages7/server_info.go | 79 ++++++++++++++++++++++++ messages7/snap.go | 67 +++++++++++++++++++++ messages7/snap_small.go | 43 +++++++++++++ network7/network7.go | 51 +++++++++++++--- protocol7/connection.go | 28 ++++++++- protocol7/packet.go | 106 ++++++++++++++++++++++++++++++++- 26 files changed, 1291 insertions(+), 22 deletions(-) create mode 100644 messages7/auth_challenge.go create mode 100644 messages7/auth_response.go create mode 100644 messages7/auth_result.go create mode 100644 messages7/auth_start.go create mode 100644 messages7/error.go create mode 100644 messages7/input.go create mode 100644 messages7/map_data.go create mode 100644 messages7/maplist_entry_add.go create mode 100644 messages7/maplist_entry_rem.go create mode 100644 messages7/ping.go create mode 100644 messages7/ping_reply.go create mode 100644 messages7/rcon_auth.go create mode 100644 messages7/rcon_auth_off.go create mode 100644 messages7/rcon_auth_on.go create mode 100644 messages7/rcon_cmd.go create mode 100644 messages7/rcon_cmd_add.go create mode 100644 messages7/rcon_cmd_rem.go create mode 100644 messages7/rcon_line.go create mode 100644 messages7/request_map_data.go create mode 100644 messages7/server_info.go create mode 100644 messages7/snap.go create mode 100644 messages7/snap_small.go diff --git a/messages7/auth_challenge.go b/messages7/auth_challenge.go new file mode 100644 index 0000000..396d073 --- /dev/null +++ b/messages7/auth_challenge.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type AuthChallenge struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg AuthChallenge) MsgId() int { + return network7.MsgSysAuthChallenge +} + +func (msg AuthChallenge) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg AuthChallenge) System() bool { + return true +} + +func (msg AuthChallenge) Vital() bool { + return true +} + +func (msg AuthChallenge) Pack() []byte { + return []byte{} +} + +func (msg *AuthChallenge) Unpack(u *packer.Unpacker) { +} + +func (msg *AuthChallenge) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *AuthChallenge) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/auth_response.go b/messages7/auth_response.go new file mode 100644 index 0000000..1ed1ea1 --- /dev/null +++ b/messages7/auth_response.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type AuthResponse struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg AuthResponse) MsgId() int { + return network7.MsgSysAuthResponse +} + +func (msg AuthResponse) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg AuthResponse) System() bool { + return true +} + +func (msg AuthResponse) Vital() bool { + return true +} + +func (msg AuthResponse) Pack() []byte { + return []byte{} +} + +func (msg *AuthResponse) Unpack(u *packer.Unpacker) { +} + +func (msg *AuthResponse) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *AuthResponse) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/auth_result.go b/messages7/auth_result.go new file mode 100644 index 0000000..e4d25b1 --- /dev/null +++ b/messages7/auth_result.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type AuthResult struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg AuthResult) MsgId() int { + return network7.MsgSysAuthResult +} + +func (msg AuthResult) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg AuthResult) System() bool { + return true +} + +func (msg AuthResult) Vital() bool { + return true +} + +func (msg AuthResult) Pack() []byte { + return []byte{} +} + +func (msg *AuthResult) Unpack(u *packer.Unpacker) { +} + +func (msg *AuthResult) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *AuthResult) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/auth_start.go b/messages7/auth_start.go new file mode 100644 index 0000000..2cba389 --- /dev/null +++ b/messages7/auth_start.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type AuthStart struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg AuthStart) MsgId() int { + return network7.MsgSysAuthStart +} + +func (msg AuthStart) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg AuthStart) System() bool { + return true +} + +func (msg AuthStart) Vital() bool { + return true +} + +func (msg AuthStart) Pack() []byte { + return []byte{} +} + +func (msg *AuthStart) Unpack(u *packer.Unpacker) { +} + +func (msg *AuthStart) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *AuthStart) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/error.go b/messages7/error.go new file mode 100644 index 0000000..2d056d4 --- /dev/null +++ b/messages7/error.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type Error struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg Error) MsgId() int { + return network7.MsgSysError +} + +func (msg Error) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg Error) System() bool { + return true +} + +func (msg Error) Vital() bool { + return true +} + +func (msg Error) Pack() []byte { + return []byte{} +} + +func (msg *Error) Unpack(u *packer.Unpacker) { +} + +func (msg *Error) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *Error) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/info.go b/messages7/info.go index c758a93..be5ea85 100644 --- a/messages7/info.go +++ b/messages7/info.go @@ -1,6 +1,8 @@ package messages7 import ( + "slices" + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" "github.com/teeworlds-go/go-teeworlds-protocol/network7" "github.com/teeworlds-go/go-teeworlds-protocol/packer" @@ -8,6 +10,28 @@ import ( type Info struct { ChunkHeader *chunk7.ChunkHeader + + // The official name is "NetVersion" but a more fitting name in my opinion would be "Protocol Version". + // The variable C++ implementations GAME_NETVERSION always expands to "0.7 802f1be60a05665f" + // If the server gets another string it actually rejects the connection. This is what prohibits 0.6 clients to join 0.7 servers. + // + // Recommended value is network7.NetVersion + Version string + + // Password to enter password protected servers + // If the server does not require a password it will ignore this string + // + // Recommended value is "" + Password string + + // Another version field which does not have to match the servers version to establish a connection. + // The first version field makes sure that client and server use the same major protocol and are compatible. + // This "Client Version" field then informs the server about the clients minor version. + // The server can use it to activate some non protocol breaking features that were introduced in minor releases. + // + // The official teeworlds 0.7.5 client sends the value 0x0705 + // So the recommended value is network7.ClientVersion + ClientVersion int } func (msg Info) MsgId() int { @@ -27,17 +51,17 @@ func (msg Info) Vital() bool { } func (msg Info) Pack() []byte { - return []byte{ - 0x30, 0x2E, 0x37, 0x20, 0x38, 0x30, 0x32, 0x66, - 0x31, 0x62, 0x65, 0x36, 0x30, 0x61, 0x30, 0x35, 0x36, 0x36, 0x35, 0x66, - 0x00, 0x6D, 0x79, 0x5F, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6F, 0x72, 0x64, - 0x5F, 0x31, 0x32, 0x33, 0x00, 0x85, 0x1C, 0x00, - } + return slices.Concat( + packer.PackStr(msg.Version), + packer.PackStr(msg.Password), + packer.PackInt(msg.ClientVersion), + ) } func (msg *Info) Unpack(u *packer.Unpacker) { - // TODO: implement - panic("not implemented") + msg.Version = u.GetString() + msg.Password = u.GetString() + msg.ClientVersion = u.GetInt() } func (msg *Info) Header() *chunk7.ChunkHeader { diff --git a/messages7/input.go b/messages7/input.go new file mode 100644 index 0000000..1749f3a --- /dev/null +++ b/messages7/input.go @@ -0,0 +1,80 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type Input struct { + ChunkHeader *chunk7.ChunkHeader + + AckGameTick int + PredictionTick int + Size int + + Direction int + TargetX int + TargetY int + Jump int + Fire int + Hook int + PlayerFlags int + WantedWeapon network7.Weapon + NextWeapon network7.Weapon + PrevWeapon network7.Weapon +} + +func (msg Input) MsgId() int { + return network7.MsgSysInput +} + +func (msg Input) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg Input) System() bool { + return true +} + +func (msg Input) Vital() bool { + return false +} + +func (msg Input) Pack() []byte { + return slices.Concat( + packer.PackInt(msg.Direction), + packer.PackInt(msg.TargetX), + packer.PackInt(msg.TargetY), + packer.PackInt(msg.Jump), + packer.PackInt(msg.Fire), + packer.PackInt(msg.Hook), + packer.PackInt(msg.PlayerFlags), + packer.PackInt(int(msg.WantedWeapon)), + packer.PackInt(int(msg.NextWeapon)), + packer.PackInt(int(msg.PrevWeapon)), + ) +} + +func (msg *Input) Unpack(u *packer.Unpacker) { + msg.Direction = u.GetInt() + msg.TargetX = u.GetInt() + msg.TargetY = u.GetInt() + msg.Jump = u.GetInt() + msg.Fire = u.GetInt() + msg.Hook = u.GetInt() + msg.PlayerFlags = u.GetInt() + msg.WantedWeapon = network7.Weapon(u.GetInt()) + msg.NextWeapon = network7.Weapon(u.GetInt()) + msg.PrevWeapon = network7.Weapon(u.GetInt()) +} + +func (msg *Input) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *Input) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/map_data.go b/messages7/map_data.go new file mode 100644 index 0000000..baa3f6a --- /dev/null +++ b/messages7/map_data.go @@ -0,0 +1,45 @@ +package messages7 + +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" +) + +type MapData struct { + ChunkHeader *chunk7.ChunkHeader + + Data []byte +} + +func (msg MapData) MsgId() int { + return network7.MsgSysMapData +} + +func (msg MapData) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg MapData) System() bool { + return true +} + +func (msg MapData) Vital() bool { + return true +} + +func (msg MapData) Pack() []byte { + return msg.Data +} + +func (msg *MapData) Unpack(u *packer.Unpacker) { + msg.Data = u.Rest() +} + +func (msg *MapData) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *MapData) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/maplist_entry_add.go b/messages7/maplist_entry_add.go new file mode 100644 index 0000000..311b385 --- /dev/null +++ b/messages7/maplist_entry_add.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type MaplistEntryAdd struct { + ChunkHeader *chunk7.ChunkHeader + + MapName string +} + +func (msg MaplistEntryAdd) MsgId() int { + return network7.MsgSysMaplistEntryAdd +} + +func (msg MaplistEntryAdd) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg MaplistEntryAdd) System() bool { + return true +} + +func (msg MaplistEntryAdd) Vital() bool { + return true +} + +func (msg MaplistEntryAdd) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.MapName), + ) +} + +func (msg *MaplistEntryAdd) Unpack(u *packer.Unpacker) { + msg.MapName = u.GetString() +} + +func (msg *MaplistEntryAdd) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *MaplistEntryAdd) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/maplist_entry_rem.go b/messages7/maplist_entry_rem.go new file mode 100644 index 0000000..22df6f1 --- /dev/null +++ b/messages7/maplist_entry_rem.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type MaplistEntryRem struct { + ChunkHeader *chunk7.ChunkHeader + + MapName string +} + +func (msg MaplistEntryRem) MsgId() int { + return network7.MsgSysMaplistEntryRem +} + +func (msg MaplistEntryRem) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg MaplistEntryRem) System() bool { + return true +} + +func (msg MaplistEntryRem) Vital() bool { + return true +} + +func (msg MaplistEntryRem) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.MapName), + ) +} + +func (msg *MaplistEntryRem) Unpack(u *packer.Unpacker) { + msg.MapName = u.GetString() +} + +func (msg *MaplistEntryRem) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *MaplistEntryRem) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/ping.go b/messages7/ping.go new file mode 100644 index 0000000..3d20aff --- /dev/null +++ b/messages7/ping.go @@ -0,0 +1,42 @@ +package messages7 + +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" +) + +type Ping struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg Ping) MsgId() int { + return network7.MsgSysPing +} + +func (msg Ping) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg Ping) System() bool { + return true +} + +func (msg Ping) Vital() bool { + return true +} + +func (msg Ping) Pack() []byte { + return []byte{} +} + +func (msg *Ping) Unpack(u *packer.Unpacker) { +} + +func (msg *Ping) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *Ping) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/ping_reply.go b/messages7/ping_reply.go new file mode 100644 index 0000000..e20e7b7 --- /dev/null +++ b/messages7/ping_reply.go @@ -0,0 +1,42 @@ +package messages7 + +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" +) + +type PingReply struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg PingReply) MsgId() int { + return network7.MsgSysPingReply +} + +func (msg PingReply) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg PingReply) System() bool { + return true +} + +func (msg PingReply) Vital() bool { + return true +} + +func (msg PingReply) Pack() []byte { + return []byte{} +} + +func (msg *PingReply) Unpack(u *packer.Unpacker) { +} + +func (msg *PingReply) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *PingReply) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_auth.go b/messages7/rcon_auth.go new file mode 100644 index 0000000..b3981b8 --- /dev/null +++ b/messages7/rcon_auth.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type RconAuth struct { + ChunkHeader *chunk7.ChunkHeader + + Password string +} + +func (msg RconAuth) MsgId() int { + return network7.MsgSysRconAuth +} + +func (msg RconAuth) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconAuth) System() bool { + return true +} + +func (msg RconAuth) Vital() bool { + return true +} + +func (msg RconAuth) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Password), + ) +} + +func (msg *RconAuth) Unpack(u *packer.Unpacker) { + msg.Password = u.GetString() +} + +func (msg *RconAuth) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconAuth) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_auth_off.go b/messages7/rcon_auth_off.go new file mode 100644 index 0000000..f577b49 --- /dev/null +++ b/messages7/rcon_auth_off.go @@ -0,0 +1,42 @@ +package messages7 + +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" +) + +type RconAuthOff struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg RconAuthOff) MsgId() int { + return network7.MsgSysRconAuthOff +} + +func (msg RconAuthOff) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconAuthOff) System() bool { + return true +} + +func (msg RconAuthOff) Vital() bool { + return true +} + +func (msg RconAuthOff) Pack() []byte { + return []byte{} +} + +func (msg *RconAuthOff) Unpack(u *packer.Unpacker) { +} + +func (msg *RconAuthOff) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconAuthOff) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_auth_on.go b/messages7/rcon_auth_on.go new file mode 100644 index 0000000..b035d06 --- /dev/null +++ b/messages7/rcon_auth_on.go @@ -0,0 +1,42 @@ +package messages7 + +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" +) + +type RconAuthOn struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg RconAuthOn) MsgId() int { + return network7.MsgSysRconAuthOn +} + +func (msg RconAuthOn) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconAuthOn) System() bool { + return true +} + +func (msg RconAuthOn) Vital() bool { + return true +} + +func (msg RconAuthOn) Pack() []byte { + return []byte{} +} + +func (msg *RconAuthOn) Unpack(u *packer.Unpacker) { +} + +func (msg *RconAuthOn) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconAuthOn) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_cmd.go b/messages7/rcon_cmd.go new file mode 100644 index 0000000..0f2be90 --- /dev/null +++ b/messages7/rcon_cmd.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type RconCmd struct { + ChunkHeader *chunk7.ChunkHeader + + Command string +} + +func (msg RconCmd) MsgId() int { + return network7.MsgSysRconCmd +} + +func (msg RconCmd) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconCmd) System() bool { + return true +} + +func (msg RconCmd) Vital() bool { + return true +} + +func (msg RconCmd) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Command), + ) +} + +func (msg *RconCmd) Unpack(u *packer.Unpacker) { + msg.Command = u.GetString() +} + +func (msg *RconCmd) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconCmd) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_cmd_add.go b/messages7/rcon_cmd_add.go new file mode 100644 index 0000000..b864378 --- /dev/null +++ b/messages7/rcon_cmd_add.go @@ -0,0 +1,55 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type RconCmdAdd struct { + ChunkHeader *chunk7.ChunkHeader + + Name string + Help string + Params string +} + +func (msg RconCmdAdd) MsgId() int { + return network7.MsgSysRconCmdAdd +} + +func (msg RconCmdAdd) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconCmdAdd) System() bool { + return true +} + +func (msg RconCmdAdd) Vital() bool { + return true +} + +func (msg RconCmdAdd) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Name), + packer.PackStr(msg.Help), + packer.PackStr(msg.Params), + ) +} + +func (msg *RconCmdAdd) Unpack(u *packer.Unpacker) { + msg.Name = u.GetString() + msg.Help = u.GetString() + msg.Params = u.GetString() +} + +func (msg *RconCmdAdd) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconCmdAdd) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_cmd_rem.go b/messages7/rcon_cmd_rem.go new file mode 100644 index 0000000..c473ceb --- /dev/null +++ b/messages7/rcon_cmd_rem.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type RconCmdRem struct { + ChunkHeader *chunk7.ChunkHeader + + Name string +} + +func (msg RconCmdRem) MsgId() int { + return network7.MsgSysRconCmdRem +} + +func (msg RconCmdRem) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconCmdRem) System() bool { + return true +} + +func (msg RconCmdRem) Vital() bool { + return true +} + +func (msg RconCmdRem) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Name), + ) +} + +func (msg *RconCmdRem) Unpack(u *packer.Unpacker) { + msg.Name = u.GetString() +} + +func (msg *RconCmdRem) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconCmdRem) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/rcon_line.go b/messages7/rcon_line.go new file mode 100644 index 0000000..18580bd --- /dev/null +++ b/messages7/rcon_line.go @@ -0,0 +1,49 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type RconLine struct { + ChunkHeader *chunk7.ChunkHeader + + Line string +} + +func (msg RconLine) MsgId() int { + return network7.MsgSysRconLine +} + +func (msg RconLine) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RconLine) System() bool { + return true +} + +func (msg RconLine) Vital() bool { + return true +} + +func (msg RconLine) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Line), + ) +} + +func (msg *RconLine) Unpack(u *packer.Unpacker) { + msg.Line = u.GetString() +} + +func (msg *RconLine) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RconLine) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/request_map_data.go b/messages7/request_map_data.go new file mode 100644 index 0000000..3273315 --- /dev/null +++ b/messages7/request_map_data.go @@ -0,0 +1,42 @@ +package messages7 + +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" +) + +type RequestMapData struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg RequestMapData) MsgId() int { + return network7.MsgSysRequestMapData +} + +func (msg RequestMapData) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg RequestMapData) System() bool { + return true +} + +func (msg RequestMapData) Vital() bool { + return true +} + +func (msg RequestMapData) Pack() []byte { + return []byte{} +} + +func (msg *RequestMapData) Unpack(u *packer.Unpacker) { +} + +func (msg *RequestMapData) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *RequestMapData) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/server_info.go b/messages7/server_info.go new file mode 100644 index 0000000..28077b1 --- /dev/null +++ b/messages7/server_info.go @@ -0,0 +1,79 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type ServerInfo struct { + ChunkHeader *chunk7.ChunkHeader + + Version string + Name string + Hostname string + MapName string + GameType string + Flags int + SkillLevel int + PlayerCount int + PlayerSlots int + ClientCount int + MaxClients int +} + +func (msg ServerInfo) MsgId() int { + return network7.MsgSysServerInfo +} + +func (msg ServerInfo) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg ServerInfo) System() bool { + return true +} + +func (msg ServerInfo) Vital() bool { + return true +} + +func (msg ServerInfo) Pack() []byte { + return slices.Concat( + packer.PackStr(msg.Version), + packer.PackStr(msg.Name), + packer.PackStr(msg.Hostname), + packer.PackStr(msg.MapName), + packer.PackStr(msg.GameType), + packer.PackInt(msg.Flags), + packer.PackInt(msg.SkillLevel), + packer.PackInt(msg.PlayerCount), + packer.PackInt(msg.PlayerSlots), + packer.PackInt(msg.ClientCount), + packer.PackInt(msg.MaxClients), + ) +} + +func (msg *ServerInfo) Unpack(u *packer.Unpacker) { + 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() + msg.PlayerSlots = u.GetInt() + msg.ClientCount = u.GetInt() + msg.MaxClients = u.GetInt() +} + +func (msg *ServerInfo) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *ServerInfo) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/snap.go b/messages7/snap.go new file mode 100644 index 0000000..2aff0f6 --- /dev/null +++ b/messages7/snap.go @@ -0,0 +1,67 @@ +package messages7 + +import ( + "slices" + + "github.com/teeworlds-go/go-teeworlds-protocol/chunk7" + "github.com/teeworlds-go/go-teeworlds-protocol/network7" + "github.com/teeworlds-go/go-teeworlds-protocol/packer" +) + +type Snap struct { + ChunkHeader *chunk7.ChunkHeader + + GameTick int + DeltaTick int + NumParts int + Part int + Crc int + PartSize int + Data []byte +} + +func (msg Snap) MsgId() int { + return network7.MsgSysSnap +} + +func (msg Snap) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg Snap) System() bool { + return true +} + +func (msg Snap) Vital() bool { + return false +} + +func (msg Snap) Pack() []byte { + return slices.Concat( + packer.PackInt(msg.GameTick), + packer.PackInt(msg.DeltaTick), + packer.PackInt(msg.NumParts), + packer.PackInt(msg.Part), + packer.PackInt(msg.Crc), + packer.PackInt(msg.PartSize), + msg.Data[:], + ) +} + +func (msg *Snap) Unpack(u *packer.Unpacker) { + msg.GameTick = u.GetInt() + msg.DeltaTick = u.GetInt() + msg.NumParts = u.GetInt() + msg.Part = u.GetInt() + msg.Crc = u.GetInt() + msg.PartSize = u.GetInt() + msg.Data = u.Rest() +} + +func (msg *Snap) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *Snap) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/messages7/snap_small.go b/messages7/snap_small.go new file mode 100644 index 0000000..67b5b56 --- /dev/null +++ b/messages7/snap_small.go @@ -0,0 +1,43 @@ +package messages7 + +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" +) + +// this message is unused in the official 0.7.5 implementation +type SnapSmall struct { + ChunkHeader *chunk7.ChunkHeader +} + +func (msg SnapSmall) MsgId() int { + return network7.MsgSysSnapSmall +} + +func (msg SnapSmall) MsgType() network7.MsgType { + return network7.TypeNet +} + +func (msg SnapSmall) System() bool { + return true +} + +func (msg SnapSmall) Vital() bool { + return false +} + +func (msg SnapSmall) Pack() []byte { + return []byte{} +} + +func (msg *SnapSmall) Unpack(u *packer.Unpacker) { +} + +func (msg *SnapSmall) Header() *chunk7.ChunkHeader { + return msg.ChunkHeader +} + +func (msg *SnapSmall) SetHeader(header *chunk7.ChunkHeader) { + msg.ChunkHeader = header +} diff --git a/network7/network7.go b/network7/network7.go index af6b1e5..a85d1d0 100644 --- a/network7/network7.go +++ b/network7/network7.go @@ -1,7 +1,9 @@ package network7 const ( - MaxClients = 64 + MaxClients = 64 + NetVersion = "0.7 802f1be60a05665f" + ClientVersion = 0x0705 MsgCtrlKeepAlive = 0x00 MsgCtrlConnect = 0x01 @@ -9,14 +11,36 @@ const ( MsgCtrlToken = 0x05 MsgCtrlClose = 0x04 - MsgSysInfo = 1 - MsgSysMapChange = 2 - MsgSysConReady = 5 - MsgSysSnapEmpty = 7 - MsgSysSnapSingle = 8 - MsgSysInputTiming = 10 - MsgSysReady = 18 - MsgSysEnterGame = 19 + MsgSysInfo = 1 + MsgSysMapChange = 2 + MsgSysMapData = 3 + MsgSysServerInfo = 4 + MsgSysConReady = 5 + MsgSysSnap = 6 + MsgSysSnapEmpty = 7 + MsgSysSnapSingle = 8 + MsgSysSnapSmall = 9 + MsgSysInputTiming = 10 + MsgSysRconAuthOn = 11 + MsgSysRconAuthOff = 12 + MsgSysRconLine = 13 + MsgSysRconCmdAdd = 14 + MsgSysRconCmdRem = 15 + MsgSysAuthChallenge = 16 // unused + MsgSysAuthResult = 17 // unused + MsgSysReady = 18 + MsgSysEnterGame = 19 + MsgSysInput = 20 + MsgSysRconCmd = 21 + MsgSysRconAuth = 22 + MsgSysRequestMapData = 23 + MsgSysAuthStart = 24 // unused + MsgSysAuthResponse = 25 // unused + MsgSysPing = 26 + MsgSysPingReply = 27 + MsgSysError = 28 // unused + MsgSysMaplistEntryAdd = 29 + MsgSysMaplistEntryRem = 30 MsgGameSvMotd = 1 MsgGameSvChat = 3 @@ -27,6 +51,15 @@ const ( TypeControl MsgType = 1 TypeNet MsgType = 2 TypeConnless MsgType = 3 + + WeaponHammer Weapon = 0 + WeaponGun Weapon = 1 + WeaponShotgun Weapon = 2 + WeaponGrenade Weapon = 3 + WeaponLaser Weapon = 4 + WeaponNinja Weapon = 5 + NumWeapons Weapon = 6 ) type MsgType int +type Weapon int diff --git a/protocol7/connection.go b/protocol7/connection.go index 3ebc4d4..f90c5b6 100644 --- a/protocol7/connection.go +++ b/protocol7/connection.go @@ -111,16 +111,34 @@ func (connection *Connection) OnSystemMsg(msg messages7.NetMessage, response *Pa case *messages7.MapChange: fmt.Println("got map change") response.Messages = append(response.Messages, &messages7.Ready{}) + case *messages7.MapData: + fmt.Printf("got map chunk %x\n", msg.Data) + case *messages7.ServerInfo: + fmt.Printf("connected to server with name '%s'\n", msg.Name) case *messages7.ConReady: fmt.Println("got ready") response.Messages = append(response.Messages, connection.MsgStartInfo()) + case *messages7.Snap: + // fmt.Printf("got snap tick=%d\n", msg.GameTick) + 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{}) case *messages7.SnapEmpty: // fmt.Printf("got snap empty tick=%d\n", msg.GameTick) + response.Messages = append(response.Messages, &messages7.CtrlKeepAlive{}) case *messages7.InputTiming: // fmt.Printf("timing time left=%d\n", msg.TimeLeft) + case *messages7.RconAuthOn: + fmt.Println("you are now authenticated in rcon") + case *messages7.RconAuthOff: + fmt.Println("you are no longer authenticated in rcon") + case *messages7.RconLine: + fmt.Printf("[rcon] %s\n", msg.Line) + case *messages7.RconCmdAdd: + // fmt.Printf("got rcon cmd=%s %s %s\n", msg.Name, msg.Params, msg.Help) + case *messages7.RconCmdRem: + // fmt.Printf("removed cmd=%s\n", msg.Name) case *messages7.Unknown: // TODO: msg id of unknown messages should not be -1 fmt.Println("TODO: why is the msg id -1???") @@ -203,8 +221,14 @@ func (connection *Connection) OnPacket(packet *Packet) *Packet { ) case *messages7.CtrlAccept: fmt.Println("got accept") - // TODO: don't hardcode info - response.Messages = append(response.Messages, &messages7.Info{}) + response.Messages = append( + response.Messages, + &messages7.Info{ + Version: network7.NetVersion, + Password: "", + ClientVersion: network7.ClientVersion, + }, + ) case *messages7.CtrlClose: fmt.Printf("disconnected (%s)\n", msg.Reason) os.Exit(0) diff --git a/protocol7/packet.go b/protocol7/packet.go index 9122489..733eabe 100644 --- a/protocol7/packet.go +++ b/protocol7/packet.go @@ -81,26 +81,126 @@ func PackChunk(msg messages7.NetMessage, connection *Connection) []byte { } func (packet *Packet) unpackSystem(msgId int, chunk chunk7.Chunk, u *packer.Unpacker) bool { - if msgId == network7.MsgSysMapChange { + if msgId == network7.MsgSysInfo { + msg := &messages7.Info{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysMapChange { msg := &messages7.MapChange{ChunkHeader: &chunk.Header} msg.Unpack(u) packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysMapData { + msg := &messages7.MapData{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysServerInfo { + msg := &messages7.ServerInfo{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) } else if msgId == network7.MsgSysConReady { msg := &messages7.ConReady{ChunkHeader: &chunk.Header} msg.Unpack(u) packet.Messages = append(packet.Messages, msg) - } else if msgId == network7.MsgSysSnapSingle { - msg := &messages7.SnapSingle{ChunkHeader: &chunk.Header} + } else if msgId == network7.MsgSysSnap { + msg := &messages7.Snap{ChunkHeader: &chunk.Header} msg.Unpack(u) packet.Messages = append(packet.Messages, msg) } else if msgId == network7.MsgSysSnapEmpty { msg := &messages7.SnapEmpty{ChunkHeader: &chunk.Header} msg.Unpack(u) packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysSnapSingle { + msg := &messages7.SnapSingle{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysSnapSmall { + msg := &messages7.SnapSmall{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) } else if msgId == network7.MsgSysInputTiming { msg := &messages7.InputTiming{ChunkHeader: &chunk.Header} msg.Unpack(u) packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconAuthOn { + msg := &messages7.RconAuthOn{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconAuthOff { + msg := &messages7.RconAuthOff{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconLine { + msg := &messages7.RconLine{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconCmdAdd { + msg := &messages7.RconCmdAdd{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconCmdRem { + msg := &messages7.RconCmdRem{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysAuthChallenge { + msg := &messages7.AuthChallenge{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysAuthResult { + msg := &messages7.AuthResult{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysReady { + msg := &messages7.Ready{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysEnterGame { + msg := &messages7.EnterGame{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysInput { + msg := &messages7.Input{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconCmd { + msg := &messages7.RconCmd{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRconAuth { + msg := &messages7.RconAuth{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysRequestMapData { + msg := &messages7.RequestMapData{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysAuthStart { + msg := &messages7.AuthStart{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysAuthResponse { + msg := &messages7.AuthResponse{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysPing { + msg := &messages7.Ping{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysPingReply { + msg := &messages7.PingReply{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysError { + msg := &messages7.Error{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysMaplistEntryAdd { + msg := &messages7.MaplistEntryAdd{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) + } else if msgId == network7.MsgSysMaplistEntryRem { + msg := &messages7.MaplistEntryRem{ChunkHeader: &chunk.Header} + msg.Unpack(u) + packet.Messages = append(packet.Messages, msg) } else { return false }