multiserver/redirect.go

400 lines
8.2 KiB
Go
Raw Permalink Normal View History

2021-01-24 05:00:26 -08:00
package main
import (
2021-03-10 10:02:09 -08:00
"bytes"
"compress/zlib"
"encoding/binary"
2021-03-02 08:37:40 -08:00
"fmt"
"log"
2021-03-13 08:32:48 -08:00
"math"
"net"
"github.com/anon55555/mt/rudp"
)
2021-03-29 09:57:30 -07:00
var onRedirectDone []func(*Conn, string, bool)
2021-01-14 07:27:42 -08:00
2021-01-17 12:43:23 -08:00
// RegisterOnRedirectDone registers a callback function that is called
2021-03-29 09:57:30 -07:00
// when the Conn.Redirect method exits
func RegisterOnRedirectDone(function func(*Conn, string, bool)) {
2021-01-14 07:27:42 -08:00
onRedirectDone = append(onRedirectDone, function)
}
func processRedirectDone(c *Conn, newsrv *string) {
success := c.ServerName() == *newsrv
2021-01-14 07:27:42 -08:00
2021-01-24 05:56:04 -08:00
successstr := "false"
if success {
successstr = "true"
}
rpcSrvMu.Lock()
for srv := range rpcSrvs {
2021-05-02 04:12:24 -07:00
srv.doRPC("->REDIRECTED "+c.Username()+" "+*newsrv+" "+successstr, "--")
2021-01-24 05:56:04 -08:00
}
rpcSrvMu.Unlock()
2021-01-14 07:27:42 -08:00
for i := range onRedirectDone {
onRedirectDone[i](c, *newsrv, success)
2021-01-14 07:27:42 -08:00
}
}
2021-03-29 09:57:30 -07:00
// Redirect sends the Conn to the minetest server named newsrv
func (c *Conn) Redirect(newsrv string) error {
c.redirectMu.Lock()
defer c.redirectMu.Unlock()
2021-01-10 13:37:42 -08:00
defer processRedirectDone(c, &newsrv)
2021-03-09 13:23:41 -08:00
straddr, ok := ConfKey("servers:" + newsrv + ":address").(string)
2021-01-19 09:57:58 -08:00
if !ok {
grp, ok := ConfKey("groups:" + newsrv).([]interface{})
if !ok {
return fmt.Errorf("server or group %s does not exist", newsrv)
}
smallestCnt := int(^uint(0) >> 1)
for _, srv := range grp {
cnt := len(ConnsServer(srv.(string)))
if cnt < smallestCnt {
if c.ServerName() == srv.(string) {
return fmt.Errorf("already connected to server %s", srv.(string))
}
smallestCnt = cnt
newsrv = srv.(string)
}
}
straddr, ok = ConfKey("servers:" + newsrv + ":address").(string)
if !ok {
return fmt.Errorf("server %s does not exist", newsrv)
}
}
2021-03-29 09:57:30 -07:00
if c.ServerName() == newsrv {
2021-03-02 08:37:40 -08:00
return fmt.Errorf("already connected to server %s", newsrv)
}
2021-01-19 09:57:58 -08:00
srvaddr, err := net.ResolveUDPAddr("udp", straddr)
if err != nil {
return err
}
conn, err := net.DialUDP("udp", nil, srvaddr)
if err != nil {
return err
}
2021-03-29 09:57:30 -07:00
srv, err := Connect(conn)
if err != nil {
return err
}
fin := make(chan *Conn)
2021-03-29 09:57:30 -07:00
go Init(c, srv, true, false, fin)
2021-03-14 05:52:31 -07:00
initOk := <-fin
if initOk == nil {
srv.Close()
return fmt.Errorf("initialization with server %s failed", newsrv)
}
2021-02-13 09:33:02 -08:00
// Reset formspec style
data := []byte{
0x00, ToClientFormspecPrepend,
0x00, 0x00,
}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-02-13 09:33:02 -08:00
// Remove active objects
2021-03-29 09:57:30 -07:00
data = make([]byte, 6+len(c.aoIDs)*2)
data[0] = uint8(0x00)
2021-01-14 10:06:40 -08:00
data[1] = uint8(ToClientActiveObjectRemoveAdd)
2021-03-29 09:57:30 -07:00
binary.BigEndian.PutUint16(data[2:4], uint16(len(c.aoIDs)))
2021-02-13 10:52:41 -08:00
si := 4
2021-03-29 09:57:30 -07:00
for ao := range c.aoIDs {
2021-02-13 10:52:41 -08:00
binary.BigEndian.PutUint16(data[si:2+si], ao)
si += 2
}
2021-03-29 09:57:30 -07:00
2021-02-13 10:52:41 -08:00
binary.BigEndian.PutUint16(data[si:2+si], uint16(0))
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-02-13 09:33:02 -08:00
if err != nil {
return err
}
2021-03-29 09:57:30 -07:00
c.aoIDs = make(map[uint16]bool)
2021-02-13 09:33:02 -08:00
2021-03-10 10:02:09 -08:00
// Remove MapBlocks
2021-03-29 09:57:30 -07:00
for _, block := range c.blocks {
2021-03-10 10:02:09 -08:00
x := block[0]
y := block[1]
z := block[2]
blockdata := make([]byte, 5)
blockdata[0] = uint8(0)
binary.BigEndian.PutUint16(blockdata[1:3], uint16(0xFFFF))
blockdata[3] = uint8(2)
blockdata[4] = uint8(2)
nodes := make([]byte, 16384)
for i := uint32(0); i < NodeCount; i++ {
binary.BigEndian.PutUint16(nodes[2*i:2+2*i], uint16(ContentIgnore))
nodes[2*NodeCount+i] = uint8(0)
nodes[3*NodeCount+i] = uint8(0)
}
var compBuf bytes.Buffer
zw := zlib.NewWriter(&compBuf)
zw.Write(nodes)
zw.Close()
compNodes := compBuf.Bytes()
w := bytes.NewBuffer([]byte{0x00, ToClientBlockdata})
WriteUint16(w, uint16(x))
WriteUint16(w, uint16(y))
WriteUint16(w, uint16(z))
w.Write(blockdata)
w.Write(compNodes)
_, err = c.Send(rudp.Pkt{Reader: w})
2021-03-10 10:02:09 -08:00
if err != nil {
return err
}
}
2021-03-29 09:57:30 -07:00
c.blocks = [][3]int16{}
2021-03-10 10:02:09 -08:00
2021-02-13 10:52:41 -08:00
// Remove HUDs
data = []byte{0, ToClientHudSetParam, 0, 1, 0, 4, 0, 0, 0, 8}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
2021-02-13 10:52:41 -08:00
if err != nil {
return err
}
data = []byte{0, ToClientHudSetParam, 0, 2, 0, 0}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
2021-02-13 10:52:41 -08:00
if err != nil {
return err
}
data = []byte{0, ToClientHudSetParam, 0, 3, 0, 0}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
2021-02-13 10:52:41 -08:00
if err != nil {
return err
}
2021-03-29 09:57:30 -07:00
for hud := range c.huds {
2021-02-13 10:52:41 -08:00
data = make([]byte, 6)
data[0] = uint8(0x00)
2021-04-02 05:19:11 -07:00
data[1] = uint8(ToClientHudRM)
2021-02-13 10:52:41 -08:00
binary.BigEndian.PutUint32(data[2:6], hud)
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{
Reader: bytes.NewReader(data),
PktInfo: rudp.PktInfo{
Channel: 1,
},
})
2021-02-13 10:52:41 -08:00
if err != nil {
return err
}
}
2021-03-29 09:57:30 -07:00
c.huds = make(map[uint32]bool)
2021-02-21 03:04:54 -08:00
// Stop looped sounds
2021-03-29 09:57:30 -07:00
for sound := range c.sounds {
2021-02-21 03:04:54 -08:00
data = make([]byte, 6)
data[0] = uint8(0x00)
data[1] = uint8(ToClientStopSound)
binary.BigEndian.PutUint32(data[2:6], uint32(sound))
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
2021-02-21 03:04:54 -08:00
}
2021-03-29 09:57:30 -07:00
c.sounds = make(map[int32]bool)
2021-02-21 03:04:54 -08:00
// Stop day/night ratio override
data = []byte{0, 0, 0}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
return err
}
2021-03-12 08:29:38 -08:00
// Reset eye offset
data = []byte{}
for i := 0; i < 24; i++ {
2021-03-12 08:29:38 -08:00
data = append(data, uint8(0))
}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-12 08:29:38 -08:00
if err != nil {
return err
}
2021-03-13 07:44:03 -08:00
// Reset sky
2021-03-29 09:57:30 -07:00
switch c.ProtoVer() {
2021-03-13 07:44:03 -08:00
case 39:
data = []byte{
0, ToClientSetSky,
0, 0, 0, 0,
0, 7, 114, 101, 103, 117, 108, 97, 114,
1,
255, 255, 255, 255,
255, 255, 255, 255,
0, 7, 100, 101, 102, 97, 117, 108, 116,
255, 97, 181, 245,
255, 144, 211, 245,
255, 180, 186, 250,
255, 186, 193, 240,
255, 0, 107, 255,
255, 64, 144, 255,
255, 100, 100, 100,
}
default:
data = []byte{
0, ToClientSetSky,
0, 0, 0, 0,
0, 7, 114, 101, 103, 117, 108, 97, 114,
0, 0,
}
}
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-13 07:44:03 -08:00
if err != nil {
return err
}
2021-03-13 08:32:48 -08:00
// Reset sun
data = []byte{
1,
0, 7, 115, 117, 110, 46, 112, 110, 103,
0, 15, 115, 117, 110, 95, 116, 111, 110, 101, 109, 97, 112, 46, 112, 110, 103,
0, 13, 115, 117, 110, 114, 105, 115, 101, 98, 103, 46, 112, 110, 103,
}
sunscale := make([]byte, 4)
binary.BigEndian.PutUint32(sunscale[0:4], math.Float32bits(1))
data = append(data, sunscale...)
2021-03-13 08:36:48 -08:00
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-13 08:36:48 -08:00
if err != nil {
return err
}
// Reset moon
data = []byte{
1,
0, 8, 109, 111, 111, 110, 46, 112, 110, 103,
0, 16, 109, 111, 111, 110, 95, 116, 111, 110, 101, 109, 97, 112, 46, 112, 110, 103,
}
moonscale := make([]byte, 4)
2021-03-13 08:41:47 -08:00
binary.BigEndian.PutUint32(moonscale, math.Float32bits(1))
2021-03-13 08:36:48 -08:00
data = append(data, moonscale...)
2021-03-13 08:41:47 -08:00
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-13 08:41:47 -08:00
if err != nil {
return err
}
// Reset stars
data = []byte{
1,
0, 0, 3, 232,
105, 235, 235, 255,
}
starscale := make([]byte, 4)
binary.BigEndian.PutUint32(starscale, math.Float32bits(1))
data = append(data, starscale...)
2021-03-13 08:32:48 -08:00
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-13 08:32:48 -08:00
if err != nil {
return err
}
2021-03-13 08:49:13 -08:00
// Reset cloud params
w := bytes.NewBuffer([]byte{0x00, ToClientCloudParams})
WriteUint32(w, math.Float32bits(0))
w.Write([]byte{0, 0, 0, 0, 0, 0, 0, 0})
WriteUint32(w, math.Float32bits(0))
WriteUint32(w, math.Float32bits(0))
WriteUint32(w, math.Float32bits(0))
WriteUint32(w, math.Float32bits(0))
2021-03-13 08:49:13 -08:00
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-03-13 08:49:13 -08:00
if err != nil {
return err
}
// Update detached inventories
2021-01-16 10:31:07 -08:00
if len(detachedinvs[newsrv]) > 0 {
for i := range detachedinvs[newsrv] {
2021-02-13 09:33:02 -08:00
data = make([]byte, 2+len(detachedinvs[newsrv][i]))
2021-01-16 10:31:07 -08:00
data[0] = uint8(0x00)
data[1] = uint8(ToClientDetachedInventory)
copy(data[2:], detachedinvs[newsrv][i])
2021-03-29 09:57:30 -07:00
_, err = c.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
2021-01-16 10:31:07 -08:00
if err != nil {
return err
}
}
}
2021-03-29 09:57:30 -07:00
c.Server().stopForwarding()
2021-03-29 09:57:30 -07:00
c.SetServer(srv)
2021-03-29 09:57:30 -07:00
go Proxy(c, srv)
go Proxy(srv, c)
// Rejoin mod channels
2021-03-29 09:57:30 -07:00
for ch := range c.modChs {
data := make([]byte, 4+len(ch))
data[0] = uint8(0x00)
data[1] = uint8(ToServerModChannelJoin)
binary.BigEndian.PutUint16(data[2:4], uint16(len(ch)))
copy(data[4:], []byte(ch))
2021-03-29 09:57:30 -07:00
_, err = srv.Send(rudp.Pkt{Reader: bytes.NewReader(data)})
if err != nil {
log.Print(err)
}
}
2021-03-29 09:57:30 -07:00
log.Print(c.Addr().String() + " redirected to " + newsrv)
return nil
}