multiserver/chat.go

227 lines
4.9 KiB
Go
Raw Permalink Normal View History

2021-01-24 05:00:26 -08:00
package main
2021-01-14 04:40:31 -08:00
import (
2021-03-29 09:57:30 -07:00
"bytes"
2021-01-14 04:40:31 -08:00
"encoding/binary"
2021-03-29 09:57:30 -07:00
"io"
2021-01-14 04:40:31 -08:00
"log"
"strings"
"time"
"unicode/utf16"
"github.com/anon55555/mt/rudp"
2021-01-14 04:40:31 -08:00
)
2021-02-28 10:56:44 -08:00
var ChatCommandPrefix string = "#"
2021-01-17 12:43:23 -08:00
2021-01-14 04:40:31 -08:00
type chatCommand struct {
2021-03-06 06:40:51 -08:00
help string
2021-01-14 04:40:31 -08:00
privs map[string]bool
console bool
2021-03-29 09:57:30 -07:00
function func(*Conn, string)
2021-01-14 04:40:31 -08:00
}
var chatCommands map[string]chatCommand
2021-03-29 09:57:30 -07:00
var onChatMsg []func(*Conn, string) bool
2021-01-14 04:40:31 -08:00
2021-03-29 09:57:30 -07:00
var onServerChatMsg []func(*Conn, string) bool
2021-01-17 02:08:34 -08:00
2021-01-17 12:43:23 -08:00
// RegisterChatCommand registers a callback function that is called
// when a client executes the command and has the required privileges
func RegisterChatCommand(name, help string, privs map[string]bool, console bool, function func(*Conn, string)) {
2021-03-06 06:40:51 -08:00
chatCommands[name] = chatCommand{
help: help,
privs: privs,
console: console,
2021-03-06 06:40:51 -08:00
function: function,
}
2021-01-14 04:40:31 -08:00
}
2021-03-06 06:40:51 -08:00
// Help returns the help string of a chatCommand
func (c chatCommand) Help() string { return c.help }
2021-01-17 12:43:23 -08:00
// RegisterOnChatMessage registers a callback function that is called
// when a client sends a chat message
// If a callback function returns true the message is not forwarded
// to the minetest server
2021-03-29 09:57:30 -07:00
func RegisterOnChatMessage(function func(*Conn, string) bool) {
2021-01-14 04:40:31 -08:00
onChatMsg = append(onChatMsg, function)
}
2021-01-17 12:43:23 -08:00
// RegisterOnServerChatMessage registers a callback function
// that is called when a server sends a chat message
// If a callback function returns true the message is not forwarded
// to the minetest clients
2021-03-29 09:57:30 -07:00
func RegisterOnServerChatMessage(function func(*Conn, string) bool) {
2021-01-17 02:08:34 -08:00
onServerChatMsg = append(onServerChatMsg, function)
}
func processChatMessage(c *Conn, r *bytes.Reader) bool {
r.Seek(2, io.SeekCurrent)
2021-03-29 09:57:30 -07:00
wstr := make([]byte, r.Len())
r.Read(wstr)
2021-03-29 09:57:30 -07:00
s := string(narrow(wstr))
2021-01-17 12:43:23 -08:00
if strings.HasPrefix(s, ChatCommandPrefix) {
2021-01-14 04:40:31 -08:00
// Chat command
2021-01-17 12:43:23 -08:00
s = strings.Replace(s, ChatCommandPrefix, "", 1)
2021-01-14 04:40:31 -08:00
params := strings.Split(s, " ")
log.Print(c.Username(), " issued command: ", s)
2021-01-14 04:40:31 -08:00
// Priv check
2021-03-29 09:57:30 -07:00
allow, err := c.CheckPrivs(chatCommands[params[0]].privs)
2021-01-14 04:40:31 -08:00
if err != nil {
log.Print(err)
return true
}
if !allow {
str := "You do not have permission to run this command! Required privileges: " + strings.Replace(encodePrivs(chatCommands[params[0]].privs), "|", " ", -1)
wstr := wider([]byte(str))
2021-04-01 11:41:54 -07:00
w := bytes.NewBuffer([]byte{0x00, ToClientChatMessage})
WriteUint8(w, 1)
WriteUint8(w, 0)
WriteBytes16(w, []byte{})
WriteUint16(w, uint16(len(str)))
w.Write(wstr)
WriteUint64(w, uint64(time.Now().Unix()))
ack, err := c.Send(rudp.Pkt{Reader: w})
2021-01-14 04:40:31 -08:00
if err != nil {
log.Print(err)
}
<-ack
return true
}
// Callback
2021-01-14 08:21:24 -08:00
// Existance check
if chatCommands[params[0]].function == nil {
str := "Unknown command " + params[0] + "."
wstr := wider([]byte(str))
2021-04-01 11:41:54 -07:00
w := bytes.NewBuffer([]byte{0x00, ToClientChatMessage})
WriteUint8(w, 1)
WriteUint8(w, 0)
WriteBytes16(w, []byte{})
WriteUint16(w, uint16(len(str)))
w.Write(wstr)
WriteUint64(w, uint64(time.Now().Unix()))
ack, err := c.Send(rudp.Pkt{Reader: w})
2021-01-14 08:21:24 -08:00
if err != nil {
log.Print(err)
}
<-ack
return true
}
2021-03-29 09:57:30 -07:00
chatCommands[params[0]].function(c, strings.Join(params[1:], " "))
2021-01-14 04:40:31 -08:00
return true
} else {
// Regular message
2021-01-14 13:08:01 -08:00
noforward := false
2021-01-14 04:40:31 -08:00
for i := range onChatMsg {
2021-03-29 09:57:30 -07:00
if onChatMsg[i](c, s) {
2021-01-14 13:08:01 -08:00
noforward = true
2021-01-14 04:40:31 -08:00
}
}
2021-01-14 13:08:01 -08:00
return noforward
2021-01-14 04:40:31 -08:00
}
}
2021-03-29 09:57:30 -07:00
func processServerChatMessage(c *Conn, pkt rudp.Pkt) bool {
r := ByteReader(pkt)
r.Seek(4, io.SeekStart)
wstr := make([]byte, r.Len())
r.Read(wstr)
s := string(narrow(wstr))
noforward := false
for i := range onServerChatMsg {
2021-03-29 09:57:30 -07:00
if onServerChatMsg[i](c, s) {
noforward = true
2021-01-17 02:08:34 -08:00
}
}
2021-04-01 11:41:54 -07:00
return noforward
2021-01-17 02:08:34 -08:00
}
2021-03-29 09:57:30 -07:00
// SendChatMsg sends a chat message to a Conn if it isn't a server
func (c *Conn) SendChatMsg(msg string) {
if c.IsSrv() {
2021-01-17 12:43:23 -08:00
return
}
2021-01-14 04:40:31 -08:00
wstr := wider([]byte(msg))
2021-04-01 11:41:54 -07:00
w := bytes.NewBuffer([]byte{0x00, ToClientChatMessage})
WriteUint8(w, 1)
WriteUint8(w, 0)
WriteBytes16(w, []byte{})
WriteUint16(w, uint16(len(msg)))
w.Write(wstr)
WriteUint64(w, uint64(time.Now().Unix()))
ack, err := c.Send(rudp.Pkt{Reader: w})
2021-01-14 04:40:31 -08:00
if err != nil {
log.Print(err)
}
<-ack
}
2021-03-29 09:57:30 -07:00
// ChatSendAll sends a chat message to all connected client Conns
2021-01-14 07:27:42 -08:00
func ChatSendAll(msg string) {
2021-03-29 09:57:30 -07:00
for _, c := range Conns() {
go c.SendChatMsg(msg)
2021-01-14 04:40:31 -08:00
}
}
2021-03-06 06:40:51 -08:00
// Colorize prepends a color escape sequence to a string
func Colorize(text, color string) string {
return string(0x1b) + "(c@" + color + ")" + text + string(0x1b) + "(c@#FFF)"
}
2021-01-14 04:40:31 -08:00
func narrow(b []byte) []byte {
if len(b)%2 != 0 {
return nil
}
e := make([]uint16, len(b)/2)
for i := 0; i < len(b); i += 2 {
e[i/2] = binary.BigEndian.Uint16(b[i : 2+i])
}
return []byte(string(utf16.Decode(e)))
}
func wider(b []byte) []byte {
r := make([]byte, len(b)*2)
e := utf16.Encode([]rune(string(b)))
for i := range e {
binary.BigEndian.PutUint16(r[i*2:2+i*2], e[i])
}
return r
}
2021-01-14 10:06:40 -08:00
func init() {
chatCommands = make(map[string]chatCommand)
2021-02-28 10:56:44 -08:00
// Read cmd prefix from config
2021-03-09 13:23:41 -08:00
prefix, ok := ConfKey("command_prefix").(string)
2021-02-28 10:56:44 -08:00
if ok {
ChatCommandPrefix = prefix
}
2021-01-14 10:06:40 -08:00
}