| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- /*
- ** Command & Conquer Generals(tm)
- ** Copyright 2025 Electronic Arts Inc.
- **
- ** This program is free software: you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation, either version 3 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
- #include "global.h"
- #include "matcher.h"
- #include "encrypt.h"
- #include "timezone.h"
- #include "debug.h"
- #ifdef _WINDOWS
- #define usleep(x) Sleep((x)/100000)
- #endif
- MatcherClass::MatcherClass(void)
- {
- m_lastRotation = 0;
- m_baseNick = "matcher";
- m_joinSuccess = false;
- done = 0;
- m_rotateLogs = false;
- quiet = false;
- }
- Wstring MatcherClass::getString(const Wstring& key)
- {
- Wstring res;
- Global.GetString(key, res);
- return res;
- }
- void logIt(const char *Txt)
- {
- // intentionally crash if we can't open it
- FILE *fp = fopen("logIt.txt", "w");
- fputs(Txt, fp);
- fclose(fp);
- }
- void MatcherClass::readLoop(void)
- {
- int delay = -1;
- Global.config.getInt("ROTATEDELAY", delay);
- DBGMSG("ROTATEDELAY: " << delay);
- do
- {
- static time_t lastLogTime = 0;
- time_t now = time(NULL);
- if (now > lastLogTime + 300)
- {
- lastLogTime = now;
- INFMSG("still here" << endl);
- }
- logIt("peerThink\n");
- peerThink(m_peer);
- logIt("peerIsConnected\n");
- if (peerIsConnected(m_peer))
- {
- logIt("checkMatches()\n");
- checkMatches();
- logIt("checkMatches() done\n");
- }
- else
- done = true;
- msleep(1);
- // rotate logs if it's time
- if (delay != -1)
- {
- #ifdef _UNIX
- Xtime xtime;
- time_t curtime;
- curtime = time(NULL);
- // get the number of seconds that have passed since midnight
- // of the current day.
- curtime -= TimezoneOffset();
- time_t timeofday = curtime % (delay);
- if ((timeofday > 0) && (timeofday <= 300))
- {
- rotateOutput();
- rotateParanoid();
- }
- #endif
- }
- }
- while (!done);
- DBGMSG("Bailing out of readLoop!" << endl);
- INFMSG("Bailing out of readLoop!" << endl);
- ERRMSG("Bailing out of readLoop!" << endl);
- }
- /////////////////////////////////////////////////////////////////////////////
- static void DisconnectedCallback ( PEER peer, const char * reason, void * param)
- {
- DBGMSG("Disconnected: " << reason);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleDisconnect( reason );
- }
- static void RoomMessageCallback ( PEER peer, RoomType roomType, const char * nick, const char * message, MessageType messageType, void * param)
- {
- DBGMSG("(PUBLIC) " << nick << ": " << message);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleRoomMessage( nick, message, messageType );
- }
- static void PlayerMessageCallback ( PEER peer, const char * nick, const char * message, MessageType messageType, void * param)
- {
- DBGMSG("(PRIVATE) " << nick << ": " << message);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handlePlayerMessage( nick, message, messageType );
- }
- static void PlayerJoinedCallback ( PEER peer, RoomType roomType, const char * nick, void * param)
- {
- DBGMSG(nick << " joined the room");
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handlePlayerJoined( nick );
- }
- static void PlayerLeftCallback ( PEER peer, RoomType roomType, const char * nick, const char * reason, void * param)
- {
- DBGMSG(nick << " left the room");
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handlePlayerLeft( nick );
- }
- static void PlayerChangedNickCallback ( PEER peer, RoomType roomType, const char * oldNick, const char * newNick, void * param)
- {
- INFMSG(oldNick << " changed nicks to " << newNick);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handlePlayerChangedNick( oldNick, newNick );
- }
- static void EnumPlayersCallback ( PEER peer, PEERBool success, RoomType roomType, int index, const char * nick, int flags, void * param)
- {
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handlePlayerEnum( success == PEERTrue, index, nick, flags);
- }
- static int s_groupID = 0;
- static void ListGroupRoomsCallback ( PEER peer, PEERBool success, int groupID, SBServer server, const char * name, int numWaiting, int maxWaiting, int numGames, int numPlaying, void * param)
- {
- if (success && name && !strcasecmp(name, "QuickMatch"))
- {
- s_groupID = groupID;
- }
- }
- static void ConnectCallback ( PEER peer, PEERBool success, void * param)
- {
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleConnect( success == PEERTrue );
- }
- static void JoinCallback ( PEER peer, PEERBool success, PEERJoinResult result, RoomType roomType, void * param)
- {
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleJoin( success == PEERTrue );
- }
- static void NickErrorCallback ( PEER peer, int type, const char * badNick, void * param)
- {
- ERRMSG("Nick error with " << badNick);
- if(type == PEER_IN_USE)
- {
- int len = strlen(badNick);
- std::string nickStr = badNick;
- int newVal = 0;
- if (badNick[len-1] == '}' && badNick[len-3] == '{' && isdigit(badNick[len-2]))
- {
- newVal = badNick[len-2] - '0' + 1;
- nickStr.erase(len-3, 3);
- }
- nickStr.append("{");
- char tmp[2];
- tmp[0] = '0'+newVal;
- tmp[1] = '\0';
- nickStr.append(tmp);
- nickStr.append("}");
- DBGMSG("Nickname taken: was "<<badNick<<", new val = "<<newVal<<", new nick = "<<nickStr.c_str());
- if (newVal < 10)
- {
- // Retry the connect with a similar nick.
- peerRetryWithNick(peer, nickStr.c_str());
- }
- else
- {
- // Cancel the connect.
- peerRetryWithNick(peer, NULL);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleNickError( badNick );
- }
- }
- else
- {
- // Cancel the connect.
- peerRetryWithNick(peer, NULL);
- MatcherClass *matcher = (MatcherClass *)param;
- if (matcher)
- matcher->handleNickError( badNick );
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- void callbackEach( CHAT chat, CHATBool success, int index, const char *channel,
- const char *topic, int numUsers, void *param )
- {
- DEBUG_LOG(("Chat channel success: %d\n", success));
- if (!success)
- {
- return;
- }
- DEBUG_LOG(("Channel[%d]: %s (%s), %d users\n",
- index, channel, topic, numUsers));
- }
- void callbackAll( CHAT chat, CHATBool success, int numChannels, const char **channels,
- const char **topics, int *numUsers, void *param )
- {
- DEBUG_LOG(("Chat channels success: %d\n", success));
- if (!success)
- {
- return;
- }
- DEBUG_LOG(("%d channels found\n", numChannels));
- for (int i=0; i<numChannels; ++i)
- {
- DEBUG_LOG(("Channel[%d]: %s (%s), %d users\n",
- i, channels[i], topics[i], numUsers[i]));
- }
- }
- void MatcherClass::handleConnect( bool success )
- {
- m_connectSuccess = success;
- //DEBUG_LOG(("Enumerating chat channels\n"));
- //chatEnumChannels( peerGetChat(m_peer), "", callbackEach, callbackAll, NULL, CHATTrue );
- //DEBUG_LOG(("Done enumerating chat channels\n"));
- }
- void MatcherClass::handleGroupRoomList( bool success, int groupID, const char *name )
- {
- }
- void MatcherClass::handleJoin( bool success )
- {
- m_joinSuccess = success;
- if (m_joinSuccess)
- {
- DBGMSG("Joined room - listing players");
- peerEnumPlayers(m_peer, GroupRoom, EnumPlayersCallback, this);
- }
- }
- void MatcherClass::handleNickError( const char *badNick )
- {
- exit(1);
- }
- static void AuthenticateCDKeyCallback
- (
- PEER peer,
- int result,
- const char * message,
- void * param
- )
- {
- bool *val = (bool *)param;
- if (val)
- {
- *val = (result >= 1);
- }
- }
- void MatcherClass::connectAndLoop(void)
- {
- // Game-specific initializations, if neccessary
- init();
- // Check for possible quit from init()-based self-tests
- if (done)
- return ;
- // Defaults.
- ////////////
- Wstring title = "gmtest";
- Wstring secretKey = "HA6zkS";
- Wstring serialNo = "";
- m_profileID = 0;
- Global.config.getString("Nick", m_baseNick, "LOGIN");
- DBGMSG("base nick is " << m_baseNick.get());
- m_baseNick.toLower();
- Global.config.getString("Title", title, "LOGIN");
- Global.config.getString("SecretKey", secretKey, "LOGIN");
- Global.config.getInt("ProfileID", m_profileID, "LOGIN");
- Global.config.getString("CDKey", serialNo, "LOGIN");
- PEERCallbacks callbacks;
- PEERBool pingRooms[NumRooms];
- PEERBool crossPingRooms[NumRooms];
- // Setup the callbacks.
- ///////////////////////
- memset(&callbacks, 0, sizeof(PEERCallbacks));
- callbacks.disconnected = DisconnectedCallback;
- callbacks.playerChangedNick = PlayerChangedNickCallback;
- callbacks.playerJoined = PlayerJoinedCallback;
- callbacks.playerLeft = PlayerLeftCallback;
- callbacks.roomMessage = RoomMessageCallback;
- callbacks.playerMessage = PlayerMessageCallback;
- callbacks.param = this;
- // Init.
- ////////
- m_peer = peerInitialize(&callbacks);
- if(!m_peer)
- {
- ERRMSG("Failed to init peer object" << endl);
- return;
- }
- // Ping/cross-ping in no room.
- /////////////////////////////////
- pingRooms[TitleRoom] = PEERFalse;
- pingRooms[GroupRoom] = PEERFalse;
- pingRooms[StagingRoom] = PEERFalse;
- crossPingRooms[TitleRoom] = PEERFalse;
- crossPingRooms[GroupRoom] = PEERFalse;
- crossPingRooms[StagingRoom] = PEERFalse;
- // Set the title.
- /////////////////
- if(!peerSetTitle(m_peer, title.get(), secretKey.get(), title.get(), secretKey.get(), 0, 30, PEERTrue, pingRooms, crossPingRooms))
- {
- peerShutdown(m_peer);
- ERRMSG("Failed to set the title" << endl);
- return;
- }
- // Connect.
- ///////////
- m_connectSuccess = false;
- m_nick = m_baseNick.get();
- peerConnect(m_peer, m_baseNick.get(), m_profileID, NickErrorCallback, ConnectCallback, this, PEERTrue);
- if(!m_connectSuccess)
- {
- peerShutdown(m_peer);
- ERRMSG("Failed to connect" << endl);
- return;
- }
- bool cdOk = false;
- peerAuthenticateCDKey(m_peer, serialNo.get(), AuthenticateCDKeyCallback, &cdOk, PEERTrue);
- if (!cdOk)
- {
- peerShutdown(m_peer);
- ERRMSG("Failed to auth CDKey " << serialNo.get() << endl);
- return;
- }
- m_groupID = 0;
- peerListGroupRooms(m_peer, NULL, ListGroupRoomsCallback, &m_groupID, PEERTrue);
- m_groupID = s_groupID;
- DBGMSG("QuickMatch room is " << m_groupID);
- // Join the title room.
- ///////////////////////
- peerJoinGroupRoom(m_peer, m_groupID, JoinCallback, this, PEERTrue);
- if(!m_joinSuccess)
- {
- peerDisconnect(m_peer);
- peerShutdown(m_peer);
- ERRMSG("Failed to join the title room" << endl);
- return;
- }
- // Connected, so lets do our thing
- readLoop();
- peerDisconnect(m_peer);
- peerShutdown(m_peer);
- }
|