go-teeworlds-protocol/teeworlds7/user_actions.go

133 lines
3.7 KiB
Go

package teeworlds7
import (
"fmt"
"github.com/teeworlds-go/go-teeworlds-protocol/messages7"
"github.com/teeworlds-go/go-teeworlds-protocol/network7"
"github.com/teeworlds-go/go-teeworlds-protocol/protocol7"
)
// ----------------------------
// low level access for experts
// ----------------------------
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(packet) == false {
return nil
}
}
client.Conn.Write(packet.Pack(&client.Session))
return nil
}
// WARNING! this is does not send chat messages
// this sends a network chunk and is for expert users
//
// if you want to send a chat message use SendChat()
func (client *Client) SendMessage(msg messages7.NetMessage) {
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)
}
// ----------------------------
// high level actions
// ----------------------------
// see also SendWhisper()
// see also SendChatTeam()
func (client *Client) SendChat(msg string) {
client.SendMessage(
&messages7.ClSay{
Mode: network7.ChatAll,
Message: msg,
TargetId: -1,
},
)
}
// see also SendWhisper()
// see also SendChat()
func (client *Client) SendChatTeam(msg string) {
client.SendMessage(
&messages7.ClSay{
Mode: network7.ChatTeam,
Message: msg,
TargetId: -1,
},
)
}
// see also SendChat()
// see also SendChatTeam()
func (client *Client) SendWhisper(targetId int, msg string) {
client.SendMessage(
&messages7.ClSay{
Mode: network7.ChatWhisper,
Message: msg,
TargetId: targetId,
},
)
}