mirror of
https://github.com/WiiLink24/wfc-server.git
synced 2026-08-28 03:24:06 -05:00
QR2: Track groups / rooms
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"strings"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
"wwfc/qr2"
|
||||
)
|
||||
|
||||
func (g *GameSpySession) isFriendAdded(profileId uint32) bool {
|
||||
@@ -182,6 +183,12 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
|
||||
return
|
||||
}
|
||||
|
||||
if len(msg) < msgDataIndex+1 {
|
||||
logging.Error(g.ModuleName, "Invalid message length; message:", msg)
|
||||
g.replyError(ErrMessage)
|
||||
return
|
||||
}
|
||||
|
||||
cmd := msg[msgDataIndex]
|
||||
msgDataIndex++
|
||||
|
||||
@@ -232,6 +239,18 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
|
||||
return
|
||||
}
|
||||
|
||||
if cmd == common.MatchReservation {
|
||||
if common.IPFormatNoPortToInt(g.Conn.RemoteAddr().String()) == int32(msgMatchData.Reservation.PublicIP) {
|
||||
g.QR2IP = uint64(msgMatchData.Reservation.PublicIP) | (uint64(msgMatchData.Reservation.PublicPort) << 32)
|
||||
}
|
||||
} else if cmd == common.MatchResvOK {
|
||||
if common.IPFormatNoPortToInt(g.Conn.RemoteAddr().String()) == int32(msgMatchData.ResvOK.PublicIP) {
|
||||
g.QR2IP = uint64(msgMatchData.ResvOK.PublicIP) | (uint64(msgMatchData.ResvOK.PublicPort) << 32)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Replace public IP with QR2 search ID
|
||||
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
@@ -248,6 +267,29 @@ func (g *GameSpySession) bestieMessage(command common.GameSpyCommand) {
|
||||
return
|
||||
}
|
||||
|
||||
if cmd == common.MatchReservation {
|
||||
g.ReservationPID = uint32(toProfileId)
|
||||
} else if cmd == common.MatchResvOK || cmd == common.MatchResvDeny || cmd == common.MatchResvWait {
|
||||
if toSession.ReservationPID != g.User.ProfileId {
|
||||
logging.Error(g.ModuleName, "Destination", aurora.Cyan(toProfileId), "has no reservation with the sender")
|
||||
g.replyError(ErrMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if cmd == common.MatchResvOK {
|
||||
if g.QR2IP == 0 || toSession.QR2IP == 0 {
|
||||
logging.Error(g.ModuleName, "Missing QR2 IP")
|
||||
g.replyError(ErrMessage)
|
||||
return
|
||||
}
|
||||
|
||||
if !qr2.ProcessGPResvOK(*msgMatchData.ResvOK, g.QR2IP, g.User.ProfileId, toSession.QR2IP, uint32(toProfileId)) {
|
||||
g.replyError(ErrMessage)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sendMessageToSession("1", g.User.ProfileId, toSession, msg)
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ type GameSpySession struct {
|
||||
LocString string
|
||||
FriendList []uint32
|
||||
AuthFriendList []uint32
|
||||
|
||||
QR2IP uint64
|
||||
ReservationPID uint32
|
||||
}
|
||||
|
||||
var (
|
||||
|
||||
81
qr2/group.go
Normal file
81
qr2/group.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package qr2
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/logrusorgru/aurora/v3"
|
||||
"strconv"
|
||||
"wwfc/common"
|
||||
"wwfc/logging"
|
||||
)
|
||||
|
||||
type Group struct {
|
||||
GroupID uint32
|
||||
ServerAID uint8
|
||||
Players map[uint8]*Session
|
||||
}
|
||||
|
||||
var groups = map[*Group]bool{}
|
||||
|
||||
func processResvOK(moduleName string, cmd common.MatchCommandDataResvOK, sender, destination *Session) bool {
|
||||
group := sender.GroupPointer
|
||||
if group == nil {
|
||||
logging.Notice(moduleName, "Creating new group", aurora.Cyan(cmd.GroupID), "/", aurora.Cyan(cmd.ProfileID))
|
||||
group = &Group{
|
||||
GroupID: cmd.GroupID,
|
||||
ServerAID: uint8(cmd.SenderAID),
|
||||
Players: map[uint8]*Session{uint8(cmd.SenderAID): sender},
|
||||
}
|
||||
sender.GroupPointer = group
|
||||
groups[group] = true
|
||||
}
|
||||
|
||||
if uint8(cmd.SenderAID) != sender.GroupAID {
|
||||
logging.Error(moduleName, "ResvOK: Invalid sender AID")
|
||||
return false
|
||||
}
|
||||
|
||||
// TODO: Check if the sender is the actual server (host) once host migration works
|
||||
|
||||
// Keep group ID updated
|
||||
sender.GroupPointer.GroupID = cmd.GroupID
|
||||
|
||||
logging.Info(moduleName, "New AID", aurora.Cyan(uint8(cmd.ReceiverNewAID)), "in group", aurora.Cyan(group.GroupID))
|
||||
group.Players[uint8(cmd.ReceiverNewAID)] = destination
|
||||
destination.GroupPointer = group
|
||||
destination.GroupAID = uint8(cmd.ReceiverNewAID)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func ProcessGPResvOK(cmd common.MatchCommandDataResvOK, senderIP uint64, senderPid uint32, destIP uint64, destPid uint32) bool {
|
||||
senderPidStr := strconv.FormatUint(uint64(senderPid), 10)
|
||||
destPidStr := strconv.FormatUint(uint64(destPid), 10)
|
||||
|
||||
moduleName := "QR2:GPMsg:" + senderPidStr + "->" + destPidStr
|
||||
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
from := sessionByPublicIP[senderIP]
|
||||
if from == nil {
|
||||
logging.Error(moduleName, "Sender IP does not exist:", aurora.Cyan(fmt.Sprintf("%012x", senderIP)))
|
||||
return false
|
||||
}
|
||||
|
||||
to := sessionByPublicIP[destIP]
|
||||
if to == nil {
|
||||
logging.Error(moduleName, "Destination IP does not exist:", aurora.Cyan(fmt.Sprintf("%012x", destIP)))
|
||||
return false
|
||||
}
|
||||
|
||||
// Validate dwc_pid values
|
||||
if !from.setProfileID(moduleName, senderPidStr) {
|
||||
return false
|
||||
}
|
||||
|
||||
if !to.setProfileID(moduleName, destPidStr) {
|
||||
return false
|
||||
}
|
||||
|
||||
return processResvOK(moduleName, cmd, from, to)
|
||||
}
|
||||
@@ -226,7 +226,26 @@ func SendClientMessage(senderIP string, destSearchID uint64, message []byte) {
|
||||
cookie := binary.BigEndian.Uint32(message[0x2:0x6])
|
||||
logging.Notice(moduleName, "Send NN cookie", aurora.Cyan(cookie), "to", aurora.BrightCyan(destPid))
|
||||
} else {
|
||||
common.LogMatchCommand(moduleName, destPid, message[8], matchData)
|
||||
cmd := message[8]
|
||||
common.LogMatchCommand(moduleName, destPid, cmd, matchData)
|
||||
|
||||
if cmd == common.MatchReservation {
|
||||
sender.ReservationID = receiver.SearchID
|
||||
} else if cmd == common.MatchResvOK || cmd == common.MatchResvDeny || cmd == common.MatchResvWait {
|
||||
if receiver.ReservationID != sender.SearchID {
|
||||
logging.Error(moduleName, "Destination has no reservation with the sender")
|
||||
return
|
||||
}
|
||||
|
||||
if cmd == common.MatchResvOK {
|
||||
mutex.Lock()
|
||||
if !processResvOK(moduleName, *matchData.ResvOK, sender, receiver) {
|
||||
mutex.Unlock()
|
||||
return
|
||||
}
|
||||
mutex.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
payload := createResponseHeader(ClientMessageRequest, destSessionID)
|
||||
|
||||
@@ -28,6 +28,9 @@ type Session struct {
|
||||
Endianness byte // Some fields depend on the client's endianness
|
||||
Data map[string]string
|
||||
PacketCount uint32
|
||||
ReservationID uint64
|
||||
GroupPointer *Group
|
||||
GroupAID uint8
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -43,10 +46,23 @@ func removeSession(sessionId uint32) {
|
||||
mutex.Lock()
|
||||
defer mutex.Unlock()
|
||||
|
||||
if sessions[sessionId] == nil {
|
||||
session := sessions[sessionId]
|
||||
if session == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if session.GroupPointer != nil {
|
||||
delete(session.GroupPointer.Players, session.GroupAID)
|
||||
|
||||
if len(session.GroupPointer.Players) == 0 {
|
||||
logging.Notice("QR2", "Deleting group", aurora.Cyan(session.GroupPointer.GroupID))
|
||||
delete(groups, session.GroupPointer)
|
||||
} else if session.GroupPointer.ServerAID == session.GroupAID {
|
||||
logging.Notice("QR2", "Server down in group", aurora.Cyan(session.GroupPointer.GroupID))
|
||||
// TODO: Search for new host via dwc_hoststate
|
||||
}
|
||||
}
|
||||
|
||||
// Delete search ID lookup
|
||||
delete(sessionBySearchID, sessions[sessionId].SearchID)
|
||||
|
||||
@@ -85,6 +101,7 @@ func setSessionData(sessionId uint32, payload map[string]string, addr net.Addr)
|
||||
Endianness: ClientNoEndian,
|
||||
Data: payload,
|
||||
PacketCount: 0,
|
||||
ReservationID: 0,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +114,7 @@ func setSessionData(sessionId uint32, payload map[string]string, addr net.Addr)
|
||||
|
||||
// Set search ID
|
||||
for {
|
||||
searchID := uint64(rand.Int63n(0x400 << 32))
|
||||
searchID := uint64(rand.Int63n((0x400<<32)-1) + 1)
|
||||
if _, exists := sessionBySearchID[searchID]; !exists {
|
||||
session.SearchID = searchID
|
||||
session.Data["+searchid"] = strconv.FormatUint(searchID, 10)
|
||||
|
||||
Reference in New Issue
Block a user