Add struct for startinfo

This commit is contained in:
ChillerDragon 2024-06-19 12:13:57 +08:00
parent 2ca8a03034
commit c568a471d3
9 changed files with 344 additions and 31 deletions

View file

@ -10,6 +10,17 @@ type ChunkFlags struct {
Resend bool
}
func (flags *ChunkFlags) ToInt() int {
v := 0
if flags.Resend {
v |= chunkFlagResend
}
if flags.Vital {
v |= chunkFlagVital
}
return v
}
type ChunkHeader struct {
Flags ChunkFlags
Size int
@ -23,6 +34,21 @@ type Chunk struct {
Data []byte
}
func (header *ChunkHeader) Pack() []byte {
len := 2
if header.Flags.Vital {
len = 3
}
data := make([]byte, len)
data[0] = (byte(header.Flags.ToInt()&0x03) << 6) | ((byte(header.Size) >> 6) & 0x3f)
data[1] = (byte(header.Size) & 0x3f)
if header.Flags.Vital {
data[1] |= (byte(header.Seq) >> 2) & 0xc0
data[2] = byte(header.Seq) & 0xff
}
return data
}
func (header *ChunkHeader) Unpack(data []byte) {
flagBits := (data[0] >> 6) & 0x03
header.Flags.Vital = (flagBits & chunkFlagVital) != 0

81
messages/cl_start_info.go Normal file
View file

@ -0,0 +1,81 @@
package message
import (
"slices"
"github.com/teeworlds-go/teeworlds/packer"
)
type ClStartInfo struct {
Name string
Clan string
Country int
Body string
Marking string
Decoration string
Hands string
Feet string
Eyes string
CustomColorBody bool
CustomColorMarking bool
CustomColorDecoration bool
CustomColorHands bool
CustomColorFeet bool
CustomColorEyes bool
ColorBody int
ColorMarking int
ColorDecoration int
ColorHands int
ColorFeet int
ColorEyes int
}
func (info *ClStartInfo) Pack() []byte {
return slices.Concat(
packer.PackStr(info.Name),
packer.PackStr(info.Clan),
packer.PackInt(info.Country),
packer.PackStr(info.Body),
packer.PackStr(info.Marking),
packer.PackStr(info.Decoration),
packer.PackStr(info.Hands),
packer.PackStr(info.Feet),
packer.PackStr(info.Eyes),
packer.PackBool(info.CustomColorBody),
packer.PackBool(info.CustomColorMarking),
packer.PackBool(info.CustomColorDecoration),
packer.PackBool(info.CustomColorHands),
packer.PackBool(info.CustomColorFeet),
packer.PackBool(info.CustomColorEyes),
packer.PackInt(info.ColorBody),
packer.PackInt(info.ColorMarking),
packer.PackInt(info.ColorDecoration),
packer.PackInt(info.ColorHands),
packer.PackInt(info.ColorFeet),
packer.PackInt(info.ColorEyes),
)
}
func (info *ClStartInfo) Unpack(u *packer.Unpacker) {
info.Name = u.GetString()
info.Clan = u.GetString()
info.Country = u.GetInt()
info.Body = u.GetString()
info.Marking = u.GetString()
info.Decoration = u.GetString()
info.Hands = u.GetString()
info.Feet = u.GetString()
info.Eyes = u.GetString()
info.CustomColorBody = u.GetInt() != 0
info.CustomColorMarking = u.GetInt() != 0
info.CustomColorDecoration = u.GetInt() != 0
info.CustomColorHands = u.GetInt() != 0
info.CustomColorFeet = u.GetInt() != 0
info.CustomColorEyes = u.GetInt() != 0
info.ColorBody = u.GetInt()
info.ColorMarking = u.GetInt()
info.ColorDecoration = u.GetInt()
info.ColorHands = u.GetInt()
info.ColorFeet = u.GetInt()
info.ColorEyes = u.GetInt()
}

View file

@ -0,0 +1,124 @@
package message
import (
"reflect"
"testing"
"github.com/teeworlds-go/teeworlds/packer"
)
func TestPackStartInfo(t *testing.T) {
want := []byte{
0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x00,
0x00, 0x40, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x77, 0x61, 0x72,
0x64, 0x00, 0x64, 0x75, 0x6f, 0x64, 0x6f, 0x6e, 0x6e, 0x79, 0x00,
0x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x73,
0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x73, 0x74, 0x61,
0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x80, 0xfc, 0xaf, 0x05, 0xeb, 0x83, 0xd0, 0x0a, 0x80, 0xfe,
0x07, 0x80, 0xfe, 0x07, 0x80, 0xfe, 0x07, 0x80, 0xfe, 0x07,
}
info := ClStartInfo{
Name: "gopher",
Clan: "",
Country: -1,
Body: "greensward",
Marking: "duodonny",
Decoration: "",
Hands: "standard",
Feet: "standard",
Eyes: "standard",
CustomColorBody: true,
CustomColorMarking: true,
CustomColorDecoration: false,
CustomColorHands: false,
CustomColorFeet: false,
CustomColorEyes: false,
ColorBody: 5635840,
ColorMarking: -11141356,
ColorDecoration: 65408,
ColorHands: 65408,
ColorFeet: 65408,
ColorEyes: 65408,
}
got := info.Pack()
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestUnpackStartInfo(t *testing.T) {
u := packer.Unpacker{}
u.Reset([]byte{
0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x00,
0x00, 0x40, 0x67, 0x72, 0x65, 0x65, 0x6e, 0x73, 0x77, 0x61, 0x72,
0x64, 0x00, 0x64, 0x75, 0x6f, 0x64, 0x6f, 0x6e, 0x6e, 0x79, 0x00,
0x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x73,
0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x73, 0x74, 0x61,
0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x80, 0xfc, 0xaf, 0x05, 0xeb, 0x83, 0xd0, 0x0a, 0x80, 0xfe,
0x07, 0x80, 0xfe, 0x07, 0x80, 0xfe, 0x07, 0x80, 0xfe, 0x07,
})
info := ClStartInfo{}
info.Unpack(&u)
{
got := info.Eyes
want := "standard"
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
got = info.Decoration
want = ""
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
got = info.Marking
want = "duodonny"
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
}
{
got := info.ColorDecoration
want := 65408
if got != want {
t.Errorf("got %v, wanted %v", got, want)
}
}
wantedInfo := ClStartInfo{
Name: "gopher",
Clan: "",
Country: -1,
Body: "greensward",
Marking: "duodonny",
Decoration: "",
Hands: "standard",
Feet: "standard",
Eyes: "standard",
CustomColorBody: true,
CustomColorMarking: true,
CustomColorDecoration: false,
CustomColorHands: false,
CustomColorFeet: false,
CustomColorEyes: false,
ColorBody: 5635840,
ColorMarking: -11141356,
ColorDecoration: 65408,
ColorHands: 65408,
ColorFeet: 65408,
ColorEyes: 65408,
}
if !reflect.DeepEqual(info, wantedInfo) {
t.Errorf("got %v, wanted %v", info, wantedInfo)
}
}

View file

@ -111,6 +111,20 @@ func (u *Unpacker) GetInt() int {
return res
}
func PackStr(str string) []byte {
return slices.Concat(
[]byte(str),
[]byte{0x00},
)
}
func PackBool(b bool) []byte {
if b {
return []byte{0x01}
}
return []byte{0x00}
}
func PackInt(num int) []byte {
res := []byte{0x00}
idx := 0

View file

@ -7,6 +7,24 @@ import (
// pack
func TestPackEmptyString(t *testing.T) {
got := PackStr("")
want := []byte{0x00}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestPackSimpleString(t *testing.T) {
got := PackStr("foo")
want := []byte{'f', 'o', 'o', 0x00}
if !reflect.DeepEqual(got, want) {
t.Errorf("got %v, wanted %v", got, want)
}
}
func TestPackSmallPositiveInts(t *testing.T) {
got := PackInt(1)
want := []byte{0x01}

View file

@ -35,6 +35,7 @@ const (
msgGameSvChat = 3
msgGameReadyToEnter = 8
msgGameSvClientInfo = 18
msgGameClStartInfo = 27
)
func ctrlToken(myToken []byte) []byte {
@ -80,12 +81,19 @@ type TeeworldsClient struct {
serverToken [4]byte
conn net.Conn
// The amount of vital chunks received
Ack int
// The amount of vital chunks sent
Sequence int
// The amount of vital chunks acknowledged by the peer
PeerAck int
Players []Player
}
func (client TeeworldsClient) sendCtrlMsg(data []byte) {
func (client *TeeworldsClient) sendCtrlMsg(data []byte) {
header := packet.PacketHeader{
Flags: packet.PacketFlags{
Connless: false,
@ -102,17 +110,51 @@ func (client TeeworldsClient) sendCtrlMsg(data []byte) {
client.conn.Write(packet)
}
func (client TeeworldsClient) sendKeepAlive() {
func (client *TeeworldsClient) sendKeepAlive() {
client.sendCtrlMsg([]byte{msgCtrlKeepAlive})
}
func (client TeeworldsClient) sendReady() {
func (client *TeeworldsClient) sendReady() {
ready := []byte{0x40, 0x01, 0x02, 0x25}
client.Sequence++
client.sendPacket(ready, 1)
}
func (client TeeworldsClient) sendPacket(payload []byte, numChunks int) {
type ChunkArgs struct {
MsgId int
System bool
Flags chunk.ChunkFlags
Payload []byte
}
func (client *TeeworldsClient) packChunk(c ChunkArgs) []byte {
c.MsgId <<= 1
if c.System {
c.MsgId |= 1
}
client.Sequence++
msgAndSys := packer.PackInt(c.MsgId)
chunkHeader := chunk.ChunkHeader{
Flags: c.Flags,
Size: len(msgAndSys) + len(c.Payload),
Seq: client.Sequence,
}
data := slices.Concat(
chunkHeader.Pack(),
msgAndSys,
c.Payload,
)
fmt.Printf("packed chunk: %x\n", data)
return data
}
func (client *TeeworldsClient) sendPacket(payload []byte, numChunks int) {
header := packet.PacketHeader{
Flags: packet.PacketFlags{
Connless: false,
@ -129,29 +171,53 @@ func (client TeeworldsClient) sendPacket(payload []byte, numChunks int) {
client.conn.Write(packet)
}
func (client TeeworldsClient) sendInfo() {
func (client *TeeworldsClient) sendInfo() {
info := []byte{0x40, 0x28, 0x01, 0x03, 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}
client.Sequence++
client.sendPacket(info, 1)
}
func (client TeeworldsClient) sendStartInfo() {
info := []byte{
0x41, 0x14, 0x03, 0x36, 0x67, 0x6f, 0x70, 0x68, 0x65, 0x72, 0x00, 0x00, 0x40, 0x67, 0x72, 0x65,
0x65, 0x6e, 0x73, 0x77, 0x61, 0x72, 0x64, 0x00, 0x64, 0x75, 0x6f, 0x64, 0x6f, 0x6e, 0x6e, 0x79,
0x00, 0x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x73, 0x74, 0x61, 0x6e, 0x64,
0x61, 0x72, 0x64, 0x00, 0x73, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x00, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x80, 0xfc, 0xaf, 0x05, 0xeb, 0x83, 0xd0, 0x0a, 0x80, 0xfe, 0x07, 0x80, 0xfe,
0x07, 0x80, 0xfe, 0x07, 0x80, 0xfe, 0x07,
func (client *TeeworldsClient) sendStartInfo() {
info := message.ClStartInfo{
Name: "gopher",
Clan: "",
Country: 0,
Body: "greensward",
Marking: "duodonny",
Decoration: "",
Hands: "standard",
Feet: "standard",
Eyes: "standard",
CustomColorBody: false,
CustomColorMarking: false,
CustomColorDecoration: false,
CustomColorHands: false,
CustomColorFeet: false,
CustomColorEyes: false,
ColorBody: 0,
ColorMarking: 0,
ColorDecoration: 0,
ColorHands: 0,
ColorFeet: 0,
ColorEyes: 0,
}
client.sendPacket(info, 1)
payload := client.packChunk(ChunkArgs{
MsgId: msgGameClStartInfo,
Flags: chunk.ChunkFlags{
Vital: true,
},
Payload: info.Pack(),
})
client.sendPacket(payload, 1)
}
func (client TeeworldsClient) sendEnterGame() {
func (client *TeeworldsClient) sendEnterGame() {
enter := []byte{
0x40, 0x01, 0x04, 0x27,
}

View file

@ -1,16 +0,0 @@
package main
import (
"testing"
)
func TestIsCtrlMsg(t *testing.T) {
data := []byte{0x04, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0x04}
got := isCtrlMsg(data)
want := true
if got != want {
t.Errorf("got %t, wanted %t", got, want)
}
}