multiserver/active_object.go

183 lines
3.6 KiB
Go

package main
import (
"bytes"
"encoding/binary"
"io"
"log"
"github.com/anon55555/mt/rudp"
)
const (
AoCmdSetProps = iota
AoCmdUpdatePos
AoCmdSetTextureMod
AoCmdSetSprite
AoCmdPunched
AoCmdUpdateArmorGroups
AoCmdSetAnimation
AoCmdSetBonePos
AoCmdAttachTo
AoCmdSetPhysicsOverride
AoCmdObsolete1
AoCmdSpawnInfant
AoCmdSetAnimSpeed
)
func processAoRmAdd(c *Conn, r *bytes.Reader) []byte {
w := &bytes.Buffer{}
countRm := ReadUint16(r)
WriteUint16(w, countRm)
var aoRm []uint16
for i := uint16(0); i < countRm; i++ {
id := ReadUint16(r)
if id == c.localPlayerCao {
id = c.currentPlayerCao
}
WriteUint16(w, id)
aoRm = append(aoRm, id)
}
countAdd := ReadUint16(r)
WriteUint16(w, countAdd)
var aoAdd []uint16
for i := uint16(0); i < countAdd; i++ {
id := ReadUint16(r)
objType := ReadUint8(r)
initData := ReadBytes32(r)
dr := bytes.NewReader(initData)
dr.Seek(1, io.SeekStart)
name := string(ReadBytes16(dr))
if name == c.Username() {
if c.initAoReceived {
// Read the messages from the packet
// They need to be forwarded
dr.Seek(30, io.SeekCurrent)
msgcountByte, _ := dr.ReadByte()
msgcount := uint8(msgcountByte)
var msgs [][]byte
for j := uint8(0); j < msgcount; j++ {
dr.Seek(2, io.SeekCurrent)
msglenBytes := make([]byte, 2)
dr.Read(msglenBytes)
msglen := binary.BigEndian.Uint16(msglenBytes)
msg := make([]byte, msglen)
dr.Read(msg)
msgs = append(msgs, msg)
}
// Generate message packet
msgpkt := []byte{0x00, ToClientActiveObjectMessages}
for _, msg := range msgs {
msgdata := make([]byte, 4+len(msg))
binary.BigEndian.PutUint16(msgdata[0:2], c.localPlayerCao)
binary.BigEndian.PutUint16(msgdata[2:4], uint16(len(msg)))
copy(msgdata[4:], aoMsgReplaceIDs(c, msg))
msgpkt = append(msgpkt, msgdata...)
}
ack, err := c.Send(rudp.Pkt{Reader: bytes.NewReader(msgpkt)})
if err != nil {
log.Print(err)
}
<-ack
data := w.Bytes()
binary.BigEndian.PutUint16(data[4+countRm*2:6+countRm*2], countAdd-1)
w = bytes.NewBuffer(data)
c.currentPlayerCao = id
continue
} else {
c.initAoReceived = true
c.localPlayerCao = id
c.currentPlayerCao = id
}
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
}
if name != c.Username() {
aoAdd = append(aoAdd, id)
}
WriteUint16(w, id)
WriteUint8(w, objType)
WriteBytes32(w, initData)
}
c.redirectMu.Lock()
for i := range aoAdd {
if aoAdd[i] != 0 {
c.aoIDs[aoAdd[i]] = true
}
}
for i := range aoRm {
c.aoIDs[aoRm[i]] = false
}
c.redirectMu.Unlock()
return w.Bytes()
}
func processAoMsgs(c *Conn, r *bytes.Reader) []byte {
w := &bytes.Buffer{}
for r.Len() >= 4 {
id := ReadUint16(r)
msg := aoMsgReplaceIDs(c, ReadBytes16(r))
if id == c.currentPlayerCao {
id = c.localPlayerCao
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
}
WriteUint16(w, id)
WriteBytes16(w, msg)
}
return w.Bytes()
}
func aoMsgReplaceIDs(c *Conn, data []byte) []byte {
switch cmd := data[0]; cmd {
case AoCmdAttachTo:
id := binary.BigEndian.Uint16(data[1:3])
if id == c.currentPlayerCao {
id = c.localPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
}
case AoCmdSpawnInfant:
id := binary.BigEndian.Uint16(data[1:3])
if id == c.currentPlayerCao {
id = c.localPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
} else if id == c.localPlayerCao {
id = c.currentPlayerCao
binary.BigEndian.PutUint16(data[1:3], id)
}
}
return data
}