Skip to content

Commit c5a45f5

Browse files
committed
FIX generals auto-match
1 parent ecd081c commit c5a45f5

2 files changed

Lines changed: 23 additions & 2 deletions

File tree

app/servers/automatch/base.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,3 +108,21 @@ def pick_random_map_index(common_bitset: str) -> int:
108108
"""Pick a random map index from a common bitset. Returns -1 if none available."""
109109
indices = [i for i, c in enumerate(common_bitset) if c == "1"]
110110
return random.choice(indices) if indices else -1
111+
112+
113+
# GameSpy peerchat username encoding (piMangleIP / piDemangleUser)
114+
# Format: X<8 encoded chars>X|<profileID>
115+
# The game decodes the bot's username to validate the sender before accepting
116+
# any MBOT: messages. An invalid username causes all messages to be silently dropped.
117+
118+
_GAMESPY_XOR_KEY = 0xC3801DC7
119+
_GAMESPY_ALPHABET = "aFl4uOD9sfWq1vGp"
120+
_HEX_CHARS = "0123456789abcdef"
121+
122+
123+
def encode_gamespy_username(ip: int, profile_id: int) -> str:
124+
"""Encode an IP + profile ID into GameSpy peerchat username format."""
125+
xored = ip ^ _GAMESPY_XOR_KEY
126+
hex_str = f"{xored:08x}"
127+
encoded = "".join(_GAMESPY_ALPHABET[_HEX_CHARS.index(c)] for c in hex_str)
128+
return f"X{encoded}X|{profile_id}"

app/servers/automatch/games/generals.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import time
55
from dataclasses import dataclass, field
66

7-
from app.servers.automatch.base import BasePlayer, GameFactory, find_common_maps, pick_random_map_index
7+
from app.servers.automatch.base import BasePlayer, GameFactory, encode_gamespy_username, find_common_maps, pick_random_map_index
88

99

1010
@dataclass
@@ -26,7 +26,10 @@ class GeneralsGameFactory(GameFactory):
2626

2727
game_id = "generals_zh"
2828
nickname = "qmbot"
29-
username = "0|0"
29+
# Username must be GameSpy-encoded: X<encoded_ip>X|<profile_id>
30+
# The game decodes this via piDemangleUser before accepting any MBOT: messages.
31+
# encode_gamespy_username(0x0A000001, 17461195) -> "X1fsaFv1DX|17461195"
32+
username = encode_gamespy_username(0x0A000001, 17461195)
3033
channels = ["#GPG!597", "#GPG!392"]
3134
match_interval = 2.0
3235
valid_num_players = [2, 4, 6, 8]

0 commit comments

Comments
 (0)