The example from the readme now actually works

This commit is contained in:
ChillerDragon 2024-06-24 11:48:28 +08:00
parent 60f9e182a8
commit a0020d8eef
10 changed files with 165 additions and 15 deletions

1
.gitignore vendored
View file

@ -1,3 +1,4 @@
teeworlds_client teeworlds_client
teeworlds teeworlds
go-teeworlds-protocol

View file

@ -28,14 +28,20 @@ func main() {
// read incoming traffic // read incoming traffic
// you can also alter packet here before it will be processed by the internal state machine // you can also alter packet here before it will be processed by the internal state machine
client.OnPacket(func(packet *protocol7.Packet) { //
// return false to drop the packet
client.OnPacket(func(packet *protocol7.Packet) bool {
fmt.Printf("got packet with %d messages\n", len(packet.Messages)) fmt.Printf("got packet with %d messages\n", len(packet.Messages))
return true
}) })
// inspect outgoing traffic // inspect outgoing traffic
// you can also alter packet here before it will be sent to the server // you can also alter packet here before it will be sent to the server
client.OnSend(func(packet *protocol7.Packet) { //
// return false to drop the packet
client.OnSend(func(packet *protocol7.Packet) bool {
fmt.Printf("sending packet with %d messages\n", len(packet.Messages)) fmt.Printf("sending packet with %d messages\n", len(packet.Messages))
return true
}) })
client.OnChat(func(msg *messages7.SvChat, defaultAction teeworlds7.DefaultAction) { client.OnChat(func(msg *messages7.SvChat, defaultAction teeworlds7.DefaultAction) {

57
messages7/cl_say.go Normal file
View file

@ -0,0 +1,57 @@
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 ClSay struct {
ChunkHeader *chunk7.ChunkHeader
Mode network7.ChatMode
TargetId int
Message string
}
func (msg *ClSay) MsgId() int {
return network7.MsgGameClSay
}
func (msg *ClSay) MsgType() network7.MsgType {
return network7.TypeNet
}
func (msg *ClSay) System() bool {
return false
}
func (msg *ClSay) Vital() bool {
return true
}
func (msg *ClSay) Pack() []byte {
return slices.Concat(
packer.PackInt(int(msg.Mode)),
packer.PackInt(msg.TargetId),
packer.PackStr(msg.Message),
)
}
func (msg *ClSay) Unpack(u *packer.Unpacker) error {
msg.Mode = network7.ChatMode(u.GetInt())
msg.TargetId = u.GetInt()
msg.Message = u.GetString()
return nil
}
func (msg *ClSay) Header() *chunk7.ChunkHeader {
return msg.ChunkHeader
}
func (msg *ClSay) SetHeader(header *chunk7.ChunkHeader) {
msg.ChunkHeader = header
}

View file

@ -285,6 +285,7 @@ func (packet *Packet) Unpack(data []byte) (err error) {
return nil return nil
} }
// TODO: return error if maxium packet size is exceeded
func (packet *Packet) Pack(connection *Session) []byte { func (packet *Packet) Pack(connection *Session) []byte {
payload := []byte{} payload := []byte{}
control := false control := false
@ -297,6 +298,7 @@ func (packet *Packet) Pack(connection *Session) []byte {
} }
packet.Header.NumChunks = len(packet.Messages) packet.Header.NumChunks = len(packet.Messages)
packet.Header.Ack = connection.Ack
if control { if control {
packet.Header.Flags = PacketFlags{ packet.Header.Flags = PacketFlags{

View file

@ -140,6 +140,7 @@ func TestRepackUnknownMessages(t *testing.T) {
err := packet.Unpack(dump) err := packet.Unpack(dump)
require.NoError(t, err) require.NoError(t, err)
conn.Ack = packet.Header.Ack
repack := packet.Pack(&conn) repack := packet.Pack(&conn)
require.Equal(t, dump, repack) require.Equal(t, dump, repack)
} }

View file

@ -17,6 +17,7 @@ type Session struct {
PeerAck int PeerAck int
} }
// TODO: should this be removed? All of this could be set in Packet.Pack()
func (connection *Session) BuildResponse() *Packet { func (connection *Session) BuildResponse() *Packet {
return &Packet{ return &Packet{
Header: PacketHeader{ Header: PacketHeader{
@ -26,7 +27,7 @@ func (connection *Session) BuildResponse() *Packet {
Resend: false, Resend: false,
Control: false, Control: false,
}, },
Ack: connection.Ack, Ack: 0, // will be set in Packet.Pack()
NumChunks: 0, // will be set in Packet.Pack() NumChunks: 0, // will be set in Packet.Pack()
Token: connection.ServerToken, Token: connection.ServerToken,
}, },

View file

@ -15,8 +15,8 @@ type DefaultAction func()
// // key is the network7.MessageId // // key is the network7.MessageId
// UserMsgCallbacks map[int]UserMsgCallback // UserMsgCallbacks map[int]UserMsgCallback
type UserMsgCallbacks struct { type UserMsgCallbacks struct {
PacketIn func(*protocol7.Packet) PacketIn func(*protocol7.Packet) bool
PacketOut func(*protocol7.Packet) PacketOut func(*protocol7.Packet) bool
MsgUnknown func(*messages7.Unknown, DefaultAction) MsgUnknown func(*messages7.Unknown, DefaultAction)
InternalError func(error) InternalError func(error)

View file

@ -39,7 +39,9 @@ func (client *Client) processMessage(msg messages7.NetMessage, response *protoco
func (client *Client) processPacket(packet *protocol7.Packet) error { func (client *Client) processPacket(packet *protocol7.Packet) error {
if client.Callbacks.PacketIn != nil { if client.Callbacks.PacketIn != nil {
client.Callbacks.PacketIn(packet) if client.Callbacks.PacketIn(packet) == false {
return nil
}
} }
response := client.Session.BuildResponse() response := client.Session.BuildResponse()

View file

@ -1,6 +1,8 @@
package teeworlds7 package teeworlds7
import ( import (
"fmt"
"github.com/teeworlds-go/go-teeworlds-protocol/messages7" "github.com/teeworlds-go/go-teeworlds-protocol/messages7"
"github.com/teeworlds-go/go-teeworlds-protocol/network7" "github.com/teeworlds-go/go-teeworlds-protocol/network7"
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7" "github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
@ -10,14 +12,77 @@ import (
// low level access for experts // low level access for experts
// ---------------------------- // ----------------------------
func (client *Client) SendPacket(packet *protocol7.Packet) { // flish()boo {
//
// ifhf lenesusue
// packte:=}{}
// SendPkacte8)
//
// }
//
// if now > lastsnend d+9191 {
// if !flush() {
// keepalive
// }
// }A
// TODO: append queued messages to packet messages here func (client *Client) SendPacket(packet *protocol7.Packet) error {
if packet.Header.Flags.Resend == false && len(packet.Messages) == 0 && len(client.QueuedMessages) == 0 {
return fmt.Errorf("Failed to send packet: payload is empty.")
}
gotNet := false
numCtrlMsgs := 0
for _, msg := range packet.Messages {
if msg.MsgType() == network7.TypeControl {
numCtrlMsgs++
} else if msg.MsgType() == network7.TypeNet {
gotNet = true
} else {
return fmt.Errorf("Failed to send packet: only game, system and control messages are supported.")
}
}
if gotNet && numCtrlMsgs > 0 {
return fmt.Errorf("Failed to send packet: can not mix control messages with others.")
}
if numCtrlMsgs > 1 {
// TODO: should this automatically split it up into multiple packets?
return fmt.Errorf("Failed to send packet: can only send one control message at a time.")
}
// If the user queued a game message and then sends a control message
// before the queue got processed we send two packets in the correct order
// For example in this case:
//
// client.SendChat("bye") // queue game chunk
// client.Disconnect() // SendPacket(ctrl) -> first flush out the game chunk packet then send the control packet
//
if numCtrlMsgs > 0 && len(client.QueuedMessages) > 0 {
// TODO: we could apply compression here
// flushPacket.Header.Flags.Compression = true
flushPacket := client.Session.BuildResponse()
client.SendPacket(flushPacket)
}
for _, queuedChunk := range client.QueuedMessages {
// TODO: check if we exceed packet size and only put in as many chunks as we can
// also use a more performant queue implementation then if we unshift it partially
// popping of one element from the queue should not reallocate the entire queued messages slice
packet.Messages = append(packet.Messages, queuedChunk)
}
client.QueuedMessages = nil
if client.Callbacks.PacketOut != nil { if client.Callbacks.PacketOut != nil {
client.Callbacks.PacketOut(packet) if client.Callbacks.PacketOut(packet) == false {
return nil
}
} }
client.Conn.Write(packet.Pack(&client.Session)) client.Conn.Write(packet.Pack(&client.Session))
return nil
} }
// WARNING! this is does not send chat messages // WARNING! this is does not send chat messages
@ -25,7 +90,18 @@ func (client *Client) SendPacket(packet *protocol7.Packet) {
// //
// if you want to send a chat message use SendChat() // if you want to send a chat message use SendChat()
func (client *Client) SendMessage(msg messages7.NetMessage) { func (client *Client) SendMessage(msg messages7.NetMessage) {
// TODO: set vital header and stuff if msg.MsgType() == network7.TypeControl {
packet := client.Session.BuildResponse()
packet.Header.Flags.Control = true
packet.Messages = append(packet.Messages, msg)
client.SendPacket(packet)
return
}
if msg.MsgType() == network7.TypeConnless {
// TODO: connless
panic("connless messages are not supported yet")
}
client.QueuedMessages = append(client.QueuedMessages, msg) client.QueuedMessages = append(client.QueuedMessages, msg)
} }
@ -37,7 +113,7 @@ func (client *Client) SendMessage(msg messages7.NetMessage) {
// see also SendChatTeam() // see also SendChatTeam()
func (client *Client) SendChat(msg string) { func (client *Client) SendChat(msg string) {
client.SendMessage( client.SendMessage(
&messages7.SvChat{ &messages7.ClSay{
Mode: network7.ChatAll, Mode: network7.ChatAll,
Message: msg, Message: msg,
TargetId: -1, TargetId: -1,
@ -49,7 +125,7 @@ func (client *Client) SendChat(msg string) {
// see also SendChat() // see also SendChat()
func (client *Client) SendChatTeam(msg string) { func (client *Client) SendChatTeam(msg string) {
client.SendMessage( client.SendMessage(
&messages7.SvChat{ &messages7.ClSay{
Mode: network7.ChatTeam, Mode: network7.ChatTeam,
Message: msg, Message: msg,
TargetId: -1, TargetId: -1,
@ -61,7 +137,7 @@ func (client *Client) SendChatTeam(msg string) {
// see also SendChatTeam() // see also SendChatTeam()
func (client *Client) SendWhisper(targetId int, msg string) { func (client *Client) SendWhisper(targetId int, msg string) {
client.SendMessage( client.SendMessage(
&messages7.SvChat{ &messages7.ClSay{
Mode: network7.ChatWhisper, Mode: network7.ChatWhisper,
Message: msg, Message: msg,
TargetId: targetId, TargetId: targetId,

View file

@ -16,13 +16,17 @@ func (client *Client) OnError(callback func(err error)) {
// inspect outgoing traffic // inspect outgoing traffic
// and alter it before it gets sent to the server // and alter it before it gets sent to the server
func (client *Client) OnSend(callback func(packet *protocol7.Packet)) { //
// return false to drop the packet
func (client *Client) OnSend(callback func(packet *protocol7.Packet) bool) {
client.Callbacks.PacketOut = callback client.Callbacks.PacketOut = callback
} }
// read incoming traffic // read incoming traffic
// and alter it before it hits the internal state machine // and alter it before it hits the internal state machine
func (client *Client) OnPacket(callback func(packet *protocol7.Packet)) { //
// return false to drop the packet
func (client *Client) OnPacket(callback func(packet *protocol7.Packet) bool) {
client.Callbacks.PacketIn = callback client.Callbacks.PacketIn = callback
} }