Skip to content

Commit 2e83f14

Browse files
Add QR2 kick order to ensure the peer is disconnected from the game session
1 parent 434eed1 commit 2e83f14

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

gpcm/kick.go

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,47 @@
11
package gpcm
22

3-
import "wwfc/common"
3+
import (
4+
"strconv"
5+
"time"
6+
"wwfc/common"
7+
"wwfc/qr2"
8+
)
9+
10+
// Expects a global mutex to be locked
11+
// This function will return all sessions that are matched with the player `profileID`
12+
func getSessionsMatchedWithPlayer(gameName string, profileID uint32) []*GameSpySession {
13+
14+
var matchedPlayers []*GameSpySession
15+
16+
// Check if the user is part of a group
17+
var foundGroup *qr2.GroupInfo
18+
groups := qr2.GetGroups([]string{gameName}, []string{}, false)
19+
for _, group := range groups {
20+
for _, playerInfo := range group.Players {
21+
pid, err := strconv.ParseUint(playerInfo.ProfileID, 10, 32)
22+
if err == nil {
23+
if uint32(pid) == profileID {
24+
foundGroup = &group
25+
break
26+
}
27+
}
28+
}
29+
}
30+
31+
// If the user is part of a group, send a kick order to all players in the group
32+
if foundGroup != nil {
33+
for _, playerInfo := range foundGroup.Players {
34+
pid, err := strconv.ParseUint(playerInfo.ProfileID, 10, 32)
35+
if err == nil {
36+
if session, exists := sessions[uint32(pid)]; exists {
37+
matchedPlayers = append(matchedPlayers, session)
38+
}
39+
}
40+
}
41+
}
42+
43+
return matchedPlayers
44+
}
445

546
func kickPlayer(profileID uint32, reason string) {
647
if session, exists := sessions[profileID]; exists {
@@ -31,12 +72,23 @@ func kickPlayer(profileID uint32, reason string) {
3172
return
3273
}
3374

75+
players := getSessionsMatchedWithPlayer(session.GameName, profileID)
3476
session.replyError(GPError{
3577
ErrorCode: ErrConnectionClosed.ErrorCode,
3678
ErrorString: "The player was kicked from the server. Reason: " + reason,
3779
Fatal: true,
3880
WWFCMessage: errorMessage,
3981
})
82+
83+
// After 3 seconds, send kick order to all players in the group
84+
// This is to prevent the restricted player from staying in the group if he ignores the GPCM kick
85+
go func(players []*GameSpySession) {
86+
time.AfterFunc(3*time.Second, func() {
87+
for _, player := range players {
88+
qr2.OrderKickFromGroup(player.User.ProfileId, profileID)
89+
}
90+
})
91+
}(players)
4092
}
4193
}
4294

@@ -52,12 +104,23 @@ func KickPlayerCustomMessage(profileID uint32, reason string, message WWFCErrorM
52104
defer mutex.Unlock()
53105

54106
if session, exists := sessions[profileID]; exists {
107+
players := getSessionsMatchedWithPlayer(session.GameName, profileID)
55108
session.replyError(GPError{
56109
ErrorCode: ErrConnectionClosed.ErrorCode,
57110
ErrorString: "The player was kicked from the server. Reason: " + reason,
58111
Fatal: true,
59112
WWFCMessage: message,
60113
Reason: reason,
61114
})
115+
116+
// After 3 seconds, send kick order to all players in the group
117+
// This is to prevent the restricted player from staying in the group if he ignores the GPCM kick
118+
go func(players []*GameSpySession) {
119+
time.AfterFunc(3*time.Second, func() {
120+
for _, player := range players {
121+
qr2.OrderKickFromGroup(player.User.ProfileId, profileID)
122+
}
123+
})
124+
}(players)
62125
}
63126
}

qr2/group.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,3 +583,29 @@ func loadGroups() error {
583583

584584
return nil
585585
}
586+
587+
func OrderKickFromGroup(profileID uint32, profileToKick uint32) {
588+
moduleName := "QR2:OrderKickFromGroup/" + strconv.FormatUint(uint64(profileID), 10)
589+
590+
login, exists := logins[profileID]
591+
if !exists || login == nil {
592+
return
593+
}
594+
595+
session := login.session
596+
if session == nil {
597+
return
598+
}
599+
600+
mutex.Lock()
601+
defer mutex.Unlock()
602+
603+
message := createResponseHeader(ClientKickPeerOrder, session.SessionID)
604+
message = append(message, 0) // padding for 4 byte alignment
605+
message = binary.BigEndian.AppendUint32(message, profileToKick)
606+
_, err := masterConn.WriteTo(message, &session.Addr)
607+
if err != nil {
608+
logging.Error(moduleName, "Error sending message:", err.Error())
609+
}
610+
611+
}

qr2/main.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@ const (
2424
AvailableRequest = 0x09
2525
ClientRegisteredReply = 0x0A
2626

27-
ClientExploitReply = 0x10
27+
ClientExploitReply = 0x10
28+
ClientKickPeerOrder = 0x11
2829
)
2930

3031
var (

0 commit comments

Comments
 (0)