Backend/serverCommunication/minecraft.go

331 lines
9.2 KiB
Go

package serverCommunication
import (
"errors"
"time"
"github.com/gofiber/websocket/v2"
"krakatoa.net/backend/modules/cache"
"krakatoa.net/backend/modules/kraProtocol"
"krakatoa.net/backend/modules/logger"
"krakatoa.net/backend/modules/structs"
)
func HandleMinecraftMessage(conn *websocket.Conn, msg []byte) {
status, cmdID, dest, playerUuid, cmdNumber, args := kraProtocol.DecodeJavaMessage(msg)
mcClient := GetMinecraftClientByConn(conn)
if mcClient == nil {
logger.Minecraft.Warnln("mcClient is nil")
return
}
if status == kraProtocol.StatusErrTryAgain {
logger.Minecraft.Warnln("err StatusErrTryAgain cmdID", cmdID, "cmdNumber", cmdNumber)
return
}
if status == kraProtocol.StatusErrNoPerms {
logger.Minecraft.Warnln("err StatusErrNoPerms cmdID", cmdID, "cmdNumber", cmdNumber)
return
}
if status == kraProtocol.StatusErrArgLenTooBig {
logger.Minecraft.Warnln("err StatusErrArgLenTooBig cmdID", cmdID, "cmdNumber", cmdNumber)
return
}
if status == kraProtocol.StatusMessageAlreadyInQueue {
logger.Minecraft.Warnln("rec StatusMessageAlreadyInQueue cmdID", cmdID, "cmdNumber", cmdNumber)
return
}
if status == kraProtocol.StatusReply {
if isCmdIDInList(mcClient.CmdIDs, cmdID) {
mcClient.RemoveCmdID(cmdID)
}
logger.Minecraft.Debugln(mcClient.IsCmdIDInSendMessagesQueue(cmdID))
if mcClient.IsCmdIDInSendMessagesQueue(cmdID) {
queueMsg, err := mcClient.GetMessageFromSendQueueByCmdID(cmdID)
logger.Minecraft.Debugln("IsCmdIDInSendMessagesQueue queueMsg", queueMsg.OriginDest, queueMsg.OriginCmdID)
if err != nil {
return
}
if queueMsg.OriginDest == kraProtocol.DestVoice || queueMsg.OriginDest == kraProtocol.DestMobile {
webClient := GetWebClientByUuid(playerUuid)
if webClient == nil {
logger.Minecraft.Warn("webClient is nil")
return
}
raw := kraProtocol.EncodeWebMessage(kraProtocol.StatusReply, queueMsg.OriginCmdID, cmdNumber, args)
var err error
if queueMsg.OriginDest == kraProtocol.DestVoice {
err = webClient.SendBinaryMessage(webClient.VoiceConn, raw)
} else {
err = webClient.SendBinaryMessage(webClient.MobileConn, raw)
}
if err != nil {
logger.Minecraft.Println("failed to send message")
}
}
mcClient.RemoveMessageFromSendQueueByCmdID(cmdID)
// TODO: handle ack answer (send answer to mobile or handle her)
}
return
}
var raw []byte
var err error
// queue handling when message already in process
if status == kraProtocol.StatusGet {
// cmdID already in queue
logger.Minecraft.Debugln("cmdIDList", mcClient.CmdIDs)
if isCmdIDInList(mcClient.CmdIDs, cmdID) {
raw := kraProtocol.EncodeJavaMessage(kraProtocol.StatusMessageAlreadyInQueue, cmdID, dest, playerUuid, cmdNumber, args)
err = mcClient.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("write err", err)
}
return
}
// not in queue, add to queue
mcClient.CmdIDs = append(mcClient.CmdIDs, cmdID)
}
// dest handling
if dest == kraProtocol.DestBackend {
resArgs := minecraftCommandHandler(cmdNumber, playerUuid)
if status == kraProtocol.StatusGet {
raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, cmdID, 0, playerUuid, cmdNumber, resArgs)
err = mcClient.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("write:", err)
}
}
} else if dest == kraProtocol.DestVoice || dest == kraProtocol.DestMobile { // forwarding messsage to voice or mobile
webClient := GetWebClientByUuid(playerUuid)
if webClient == nil || dest == kraProtocol.DestVoice && webClient.VoiceConn == nil || dest == kraProtocol.DestMobile && webClient.MobileConn == nil {
raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusErrTryAgain, cmdID, 0, playerUuid, cmdNumber, args)
err = mcClient.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("write:", err)
}
return
}
if status == kraProtocol.StatusGet {
webClient := GetWebClientByUuid(playerUuid)
var webCmdID int
if dest == kraProtocol.DestVoice {
webCmdID = structs.GenerateWebCmdID(webClient.CurrentVoiceCmdIDIndexByBackend)
webClient.CurrentVoiceCmdIDIndexByBackend = webCmdID
logger.Minecraft.Debugln("webCmdID", webCmdID)
// TODO: Get minecraft server dest from func
a := &structs.A{WebCmdID: webCmdID, CmdIDFromMinecraftServer: cmdID, DestFromMinecraftServer: 10}
webClient.VoiceCmdIDsByBackend = append(webClient.VoiceCmdIDsByBackend, a)
logger.Minecraft.Debugln("VoiceCMDIDsByBackend", webClient.VoiceCmdIDsByBackend)
} else { // dest mobile
webCmdID = structs.GenerateWebCmdID(webClient.CurrentMobileVoiceCmdIDIndexByBackend)
webClient.CurrentMobileVoiceCmdIDIndexByBackend = webCmdID
logger.Minecraft.Debugln("webCmdID", webCmdID)
// TODO: Get minecraft server dest from func
a := &structs.A{WebCmdID: webCmdID, CmdIDFromMinecraftServer: cmdID, DestFromMinecraftServer: 10}
webClient.MobileCmdIDsByBackend = append(webClient.MobileCmdIDsByBackend, a)
logger.Minecraft.Debugln("MobileCMDIDsByBackend", webClient.MobileCmdIDsByBackend)
}
raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusGet, webCmdID, cmdNumber, args)
if dest == kraProtocol.DestVoice { // TODO: correct dest
webClient.SendVoiceQueueMessages = append(webClient.SendVoiceQueueMessages, &structs.SendQueueMessage{MessageRaw: raw, CmdID: webCmdID, TrySendCount: 0, OriginDest: 111111, OriginCmdID: cmdID, Time: time.Now()})
} else {
webClient.SendMobileQueueMessages = append(webClient.SendMobileQueueMessages, &structs.SendQueueMessage{MessageRaw: raw, CmdID: webCmdID, TrySendCount: 0, Time: time.Now()})
}
} else {
raw = kraProtocol.EncodeWebMessage(kraProtocol.StatusSend, 0, cmdNumber, args)
}
if dest == kraProtocol.DestVoice {
webClient.SendBinaryMessage(webClient.VoiceConn, raw)
} else {
webClient.SendBinaryMessage(webClient.MobileConn, raw)
}
} else if dest == kraProtocol.DestProxy {
client := GetMinecraftClientByName("proxy-1")
if client == nil {
raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusErrTryAgain, cmdID, 0, playerUuid, cmdNumber, "")
err = mcClient.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("write:", err)
}
return
}
if status == kraProtocol.StatusGet {
raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusReply, cmdID, dest, playerUuid, cmdNumber, args)
} else {
raw = kraProtocol.EncodeJavaMessage(kraProtocol.StatusSend, 0, dest, playerUuid, cmdNumber, args)
}
err = client.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("write:", err)
}
} else { // TODO: handle messages -> GameServer-1 to GameServer-2
logger.Minecraft.Debugln("dest not found", dest)
}
}
func GetMinecraftClientByName(Name string) *structs.MinecraftClient {
for name, client := range cache.MinecraftClients {
if name == Name {
logger.Minecraft.Debugln("return mc client", client.Name)
return client
}
}
logger.Minecraft.Warnln("mc client nil")
return nil
}
func GetMinecraftClientByConn(conn *websocket.Conn) *structs.MinecraftClient {
for _, client := range cache.MinecraftClients {
if client.Conn == conn {
return client
}
}
return nil
}
func getMinecraftServerNameByDest(dest int) string {
if dest == kraProtocol.DestProxy {
return "proxy-1"
} else { // get players current server from db if dest is 11
return "lobby-1"
}
}
func minecraftCommandHandler(cmdNumber int, playerUuid string) (args string) {
switch cmdNumber {
case 10: // testing
return IsVoiceAndMobileSocketConnected(playerUuid)
default:
return "default"
}
}
// Deprecated: only for testing, use SendMessageToMinecraftServer instead
func SendMessageToServer(dest int, playerUuid string, args string) {
mcClient := GetMinecraftClientByName(getMinecraftServerNameByDest(dest))
raw := kraProtocol.EncodeJavaMessage(10, 1, 2, playerUuid, 15, args)
if mcClient != nil {
mcClient.SendBinaryMessage(raw)
}
}
func SendMessageToMinecraftServer(originDest int, originCmdID int, status int, dest int, playerUuid string, cmdNumber int, args string) error {
cmdID := kraProtocol.DefaultCmdID
serverName := getMinecraftServerNameByDest(dest)
mcClient := GetMinecraftClientByName(serverName)
if mcClient == nil {
return errors.New("mcClient nil")
}
if status == kraProtocol.StatusGet {
cmdID = mcClient.GenerateMinecraftCmdID()
}
raw := kraProtocol.EncodeJavaMessage(status, cmdID, dest, playerUuid, cmdNumber, args)
err := mcClient.SendBinaryMessage(raw)
if err != nil {
logger.Minecraft.Warnln("err", err)
return errors.New("write err: " + err.Error())
}
if status == kraProtocol.StatusGet {
mcClient.AddMessageToSendQueue(originDest, originCmdID, raw, cmdID)
}
return nil
}
func GenerateDestForNewMinecraftClient() int {
availableDestFound := false
newDest := 10
for {
if !availableDestFound {
if isDestInUsageFromOneMinecraftClient(newDest) {
logger.Minecraft.Debugln("found dest", newDest)
availableDestFound = true
break
} else {
logger.Minecraft.Debugln("count dest up")
newDest++
}
}
}
logger.Minecraft.Debugln("finally found this dest", newDest)
return newDest
}
func isDestInUsageFromOneMinecraftClient(dest int) bool {
for _, mcClient := range cache.MinecraftClients {
if mcClient.Dest == dest {
return false
}
}
return true
}