WOLGameInfo.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /******************************************************************************
  19. *
  20. * FILE
  21. * $Archive: /Commando/Code/Commando/WOLGameInfo.cpp $
  22. *
  23. * DESCRIPTION
  24. *
  25. * PROGRAMMER
  26. * $Author: Steve_t $
  27. *
  28. * VERSION INFO
  29. * $Revision: 18 $
  30. * $Modtime: 10/31/02 4:30p $
  31. *
  32. ******************************************************************************/
  33. #include "WOLGameInfo.h"
  34. #include "GameData.h"
  35. #include "CNetwork.h"
  36. #include <WWOnline\WOLUser.h>
  37. #include <WWOnline\WOLChannel.h>
  38. #include <WWOnline\PingProfile.h>
  39. #include <WWLib\RealCRC.h>
  40. #include "modpackagemgr.h"
  41. using namespace WWOnline;
  42. /******************************************************************************
  43. *
  44. * NAME
  45. * WOLGameInfo::WOLGameInfo
  46. *
  47. * DESCRIPTION
  48. * Default constructor
  49. *
  50. * INPUTS
  51. * NONE
  52. *
  53. * RESULT
  54. * NONE
  55. *
  56. ******************************************************************************/
  57. WOLGameInfo::WOLGameInfo(void) :
  58. mIsDataValid(false),
  59. mIsMapValid(true),
  60. mPingTime(-1)
  61. {
  62. }
  63. /******************************************************************************
  64. *
  65. * NAME
  66. * WOLGameInfo::WOLGameInfo
  67. *
  68. * DESCRIPTION
  69. * Import information about the game.
  70. *
  71. * INPUTS
  72. * Game - Game to import information from.
  73. *
  74. * RESULT
  75. * NONE
  76. *
  77. ******************************************************************************/
  78. WOLGameInfo::WOLGameInfo(const cGameData& theGame)
  79. {
  80. ImportFromGame(theGame);
  81. }
  82. /******************************************************************************
  83. *
  84. * NAME
  85. * WOLGameInfo::WOLGameInfo
  86. *
  87. * DESCRIPTION
  88. * Import information about the game from a channel.
  89. *
  90. * INPUTS
  91. * Channel - Channel to import game information from.
  92. *
  93. * RESULT
  94. * NONE
  95. *
  96. ******************************************************************************/
  97. WOLGameInfo::WOLGameInfo(const RefPtr<ChannelData>& channel)
  98. {
  99. ImportFromChannel(channel);
  100. }
  101. /******************************************************************************
  102. *
  103. * NAME
  104. * WOLGameInfo::~WOLGameInfo
  105. *
  106. * DESCRIPTION
  107. * Destructor
  108. *
  109. * INPUTS
  110. * NONE
  111. *
  112. * RESULT
  113. * NONE
  114. *
  115. ******************************************************************************/
  116. WOLGameInfo::~WOLGameInfo(void)
  117. {
  118. }
  119. /******************************************************************************
  120. *
  121. * NAME
  122. * WOLGameInfo::Reset
  123. *
  124. * DESCRIPTION
  125. *
  126. * INPUTS
  127. * NONE
  128. *
  129. * RESULT
  130. * NONE
  131. *
  132. ******************************************************************************/
  133. void WOLGameInfo::Reset(void)
  134. {
  135. mIsDataValid = false;
  136. mIsMapValid = true;
  137. mVersion = 0;
  138. mGameType = 0;
  139. mMapName[0] = 0;
  140. mModName[0] = 0;
  141. mTitle[0] = 0;
  142. mMinPlayers = 0;
  143. mMaxPlayers = 0;
  144. mNumPlayers = 0;
  145. mClanID1 = 0;
  146. mClanID2 = 0;
  147. mIsMod = false;
  148. mIsLaddered = false;
  149. mIsPassworded = false;
  150. mIsQuickmatch = false;
  151. mIsDedicated = false;
  152. mIsFriendlyFire = false;
  153. mIsFreeWeapons = false;
  154. mIsTeamRemix = false;
  155. mIsTeamChange = false;
  156. mIsClanGame = false;
  157. mIsRepairBuildings = false;
  158. mIsDriverGunner = false;
  159. mSpawnWeapons = false;
  160. mPingTime = -1;
  161. }
  162. /******************************************************************************
  163. *
  164. * NAME
  165. * WOLGameInfo::ImportFromGame
  166. *
  167. * DESCRIPTION
  168. * Import information about the game.
  169. *
  170. * INPUTS
  171. * Game - Game to import information from.
  172. *
  173. * RESULT
  174. * NONE
  175. *
  176. ******************************************************************************/
  177. void WOLGameInfo::ImportFromGame(const cGameData& theGame)
  178. {
  179. Reset();
  180. mIsDataValid = true;
  181. mIsMapValid = true;
  182. mVersion = theGame.Get_Version_Number();
  183. mGameType = theGame.Get_Game_Type();
  184. strncpy(mMapName, theGame.Get_Map_Name(), MAX_TEXT_LENGTH);
  185. mMapName[MAX_TEXT_LENGTH - 1] = 0;
  186. strncpy(mModName, theGame.Get_Mod_Name(), MAX_TEXT_LENGTH);
  187. mModName[MAX_TEXT_LENGTH - 1] = 0;
  188. wcstombs(mTitle, theGame.Get_Game_Title(), MAX_TEXT_LENGTH);
  189. mTitle[MAX_TEXT_LENGTH - 1] = 0;
  190. mMinPlayers = theGame.Get_Min_Players();
  191. mMaxPlayers = theGame.Get_Max_Players();
  192. mNumPlayers = theGame.Get_Current_Players();
  193. mClanID1 = theGame.Get_Clan(0);
  194. mClanID2 = theGame.Get_Clan(1);
  195. const WCHAR* password = theGame.Get_Password();
  196. mIsPassworded = ((password != NULL) && (wcslen(password) > 0));
  197. mIsLaddered = theGame.IsLaddered.Get();
  198. mIsQuickmatch = theGame.Is_QuickMatch_Server();
  199. mIsDedicated = theGame.IsDedicated.Get();
  200. mIsFriendlyFire = theGame.IsFriendlyFirePermitted.Get();
  201. mIsFreeWeapons = theGame.IsFreeWeapons.Get();
  202. mIsTeamRemix = theGame.RemixTeams.Get();
  203. mIsTeamChange = theGame.IsTeamChangingAllowed.Get();
  204. mIsClanGame = theGame.IsClanGame.Get();
  205. // C&C mode flags
  206. mIsRepairBuildings = theGame.CanRepairBuildings.Get();
  207. mIsDriverGunner = theGame.DriverIsAlwaysGunner.Get();
  208. mSpawnWeapons = theGame.SpawnWeapons.Get();
  209. mIsMod = (theGame.Get_Mod_Name().Is_Empty() == false);
  210. mPingTime = -1;
  211. }
  212. /******************************************************************************
  213. *
  214. * NAME
  215. * WOLGameInfo::ImportFromChannel
  216. *
  217. * DESCRIPTION
  218. * Import information about the game from a channel.
  219. *
  220. * INPUTS
  221. * Channel - Channel to import game information from.
  222. *
  223. * RESULT
  224. * NONE
  225. *
  226. ******************************************************************************/
  227. void WOLGameInfo::ImportFromChannel(const RefPtr<ChannelData>& channel)
  228. {
  229. Reset();
  230. if (channel.IsValid() == false)
  231. {
  232. mIsDataValid = false;
  233. return;
  234. }
  235. //ST - Test code
  236. //if (channel->GetName() != WideStringClass(L"ladtest07")) {
  237. // mIsDataValid = false;
  238. // return;
  239. //}
  240. const char* exInfo = channel->GetExtraInfo();
  241. if ((exInfo == NULL) || (exInfo && (strlen(exInfo) != 36)))
  242. {
  243. WWDEBUG_SAY(("WOLERROR: Channel ExInfo NULL or wrong size\n"));
  244. mIsDataValid = false;
  245. return;
  246. }
  247. // Assume the data will be valid
  248. mIsDataValid = true;
  249. // Extract ExInfo settings
  250. unsigned long fileCRC = 0;
  251. unsigned long version = 0;
  252. unsigned long clanID1 = 0;
  253. unsigned long clanID2 = 0;
  254. unsigned char gameType = 0;
  255. unsigned char gameFlags1 = 0;
  256. unsigned char gameFlags2 = 0;
  257. unsigned char modMapIndex = 0;
  258. int count = sscanf(exInfo, "%08lX%08lX%08lX%08lX%c%c%c%c", &version, &fileCRC,
  259. &clanID1, &clanID2, &gameType, &gameFlags1, &gameFlags2, &modMapIndex);
  260. // There should be 8 parameters in the exinfo
  261. if (count != 8)
  262. {
  263. WWDEBUG_SAY(("WOLERROR: Channel ExInfo malformed\n"));
  264. mIsDataValid = false;
  265. }
  266. if (version != cNetwork::Get_Exe_Key()) {
  267. mIsDataValid = false;
  268. return;
  269. }
  270. mVersion = version;
  271. mGameType = (cGameData::GameTypeEnum)(gameType - '0');
  272. if (mGameType != cGameData::GAME_TYPE_CNC)
  273. {
  274. WWDEBUG_SAY(("WOLERROR: GameType '%d' out of range\n", mGameType));
  275. mIsDataValid = false;
  276. }
  277. // Extract game flags
  278. mIsLaddered = (channel->GetTournament() != 0);
  279. mIsPassworded = channel->IsPassworded();
  280. mIsDedicated = ((gameFlags1 & 0x40) == 0x40);
  281. mIsFriendlyFire = ((gameFlags1 & 0x10) == 0x10);
  282. mIsFreeWeapons = ((gameFlags1 & 0x08) == 0x08);
  283. mIsTeamRemix = ((gameFlags1 & 0x04) == 0x04);
  284. mIsTeamChange = ((gameFlags1 & 0x02) == 0x02);
  285. mIsClanGame = ((gameFlags1 & 0x01) == 0x01);
  286. mIsMod = ((gameFlags2 & 0x40) == 0x40);
  287. mSpawnWeapons = ((gameFlags2 & 0x04) == 0x04);
  288. mIsRepairBuildings = ((gameFlags2 & 0x02) == 0x02);
  289. mIsDriverGunner = ((gameFlags2 & 0x01) == 0x01);
  290. // Find the mod and map names from their CRC
  291. StringClass mapName(0, true);
  292. mapName = "<Unknown>";
  293. StringClass modName(0, true);
  294. bool got_map_name = true;
  295. if (mIsMod)
  296. {
  297. // Get the true index (+32 put the index into the printable range)
  298. modMapIndex -= 32;
  299. // Find mod based on its crc and get map filename based on the index.
  300. if (ModPackageMgrClass::Get_Mod_Map_Name_From_CRC_Index(fileCRC, modMapIndex, &modName, &mapName) == false)
  301. {
  302. //mIsDataValid = false;
  303. got_map_name = false;
  304. }
  305. }
  306. else
  307. {
  308. // Find mod based on its crc and get map filename based on the index.
  309. if (ModPackageMgrClass::Get_Mod_Map_Name_From_CRC (0, fileCRC, &modName, &mapName) == false)
  310. {
  311. //mIsDataValid = false;
  312. got_map_name = false;
  313. }
  314. }
  315. strncpy(mModName, modName, MAX_TEXT_LENGTH);
  316. mModName[MAX_TEXT_LENGTH - 1] = 0;
  317. strncpy(mMapName, mapName, MAX_TEXT_LENGTH);
  318. mMapName[MAX_TEXT_LENGTH - 1] = 0;
  319. mMinPlayers = channel->GetMinUsers();
  320. mMaxPlayers = channel->GetMaxUsers();
  321. mNumPlayers = channel->GetCurrentUsers();
  322. // Do not count the host as a player for dedicated servers.
  323. if (mIsDedicated)
  324. {
  325. WWASSERT(mNumPlayers > 0);
  326. --mNumPlayers;
  327. WWASSERT(mMaxPlayers > 0);
  328. --mMaxPlayers;
  329. }
  330. mClanID1 = clanID1;
  331. mClanID2 = clanID2;
  332. const char* topic = channel->GetTopic();
  333. if (topic == NULL)
  334. {
  335. WWDEBUG_SAY(("WOLERROR: Channel Topic is NULL\n"));
  336. mIsDataValid = false;
  337. }
  338. // Quickmatch settings are marked by a pipe '|' character
  339. mIsQuickmatch = (strchr(topic, '|') != NULL);
  340. // Extract game title from topic
  341. unsigned int titleLength = (topic[0] - 0x20);
  342. WWASSERT(titleLength <= 32);
  343. titleLength = min<unsigned int>(titleLength, 32);
  344. ++topic;
  345. strncpy(mTitle, topic, titleLength);
  346. mTitle[titleLength] = 0;
  347. WWASSERT(strlen(mTitle) == titleLength);
  348. topic += titleLength;
  349. unsigned int mapLength = (topic[0] - 0x20);
  350. WWASSERT(mapLength <= 16);
  351. mapLength = min<unsigned int>(mapLength, 16);
  352. ++topic;
  353. if (!got_map_name) {
  354. strncpy(mMapName, topic, mapLength);
  355. mMapName[mapLength] = 0;
  356. WWASSERT(strlen(mMapName) == mapLength);
  357. mIsMapValid = false;
  358. }
  359. topic += mapLength;
  360. // Calculate ping
  361. PingProfile pings;
  362. DecodePingProfile(topic, pings);
  363. const PingProfile& localPings = GetLocalPingProfile();
  364. mPingTime = ComparePingProfile(localPings, pings);
  365. }
  366. /******************************************************************************
  367. *
  368. * NAME
  369. * WOLGameInfo::ExportToChannel
  370. *
  371. * DESCRIPTION
  372. * Export game information into a channel.
  373. *
  374. * INPUTS
  375. * Channel - Channel to export game information into.
  376. *
  377. * RESULT
  378. * NONE
  379. *
  380. ******************************************************************************/
  381. void WOLGameInfo::ExportToChannel(const RefPtr<ChannelData>& channel)
  382. {
  383. if (channel.IsValid() && mIsDataValid)
  384. {
  385. // If this is a dedicated server then the max players must be incremented
  386. // by one to account for the host.
  387. unsigned int maxPlayers = (mIsDedicated == true) ? (mMaxPlayers + 1) : mMaxPlayers;
  388. // Set the channels min and max players
  389. channel->SetMinMaxUsers(mMinPlayers, maxPlayers);
  390. // Set the tournament type
  391. unsigned int tournamentType = (mIsLaddered ? 1 : 0);
  392. channel->SetTournament(tournamentType);
  393. //-------------------------------------------------------------------------
  394. // Encode ExInfo
  395. //-------------------------------------------------------------------------
  396. // For flags bit 6 must be set to keep the overall value at least a space character
  397. unsigned char gameFlags1 = 0x20;
  398. gameFlags1 |= mIsDedicated ? 0x40 : 0x00;
  399. gameFlags1 |= mIsFriendlyFire ? 0x10 : 0x00;
  400. gameFlags1 |= mIsFreeWeapons ? 0x08 : 0x00;
  401. gameFlags1 |= mIsTeamRemix ? 0x04 : 0x00;
  402. gameFlags1 |= mIsTeamChange ? 0x02 : 0x00;
  403. gameFlags1 |= mIsClanGame ? 0x01 : 0x00;
  404. unsigned char gameFlags2 = 0x20;
  405. gameFlags2 |= mIsMod ? 0x40 : 0x00;
  406. gameFlags2 |= mSpawnWeapons ? 0x04: 0x00;
  407. gameFlags2 |= mIsRepairBuildings ? 0x02: 0x00;
  408. gameFlags2 |= mIsDriverGunner ? 0x01: 0x00;
  409. // The file CRC is either the map name or the mod name depending on if
  410. // the mod flag is set.
  411. unsigned long fileCRC = 0;
  412. unsigned char modMapIndex = 0;
  413. if (mIsMod)
  414. {
  415. ModPackageClass& package = ModPackageMgrClass::Get_Current_Package();
  416. fileCRC = package.Get_CRC();
  417. modMapIndex = package.Get_Map_Index(mMapName);
  418. }
  419. else
  420. {
  421. fileCRC = ::CRC_Stringi(mMapName);
  422. }
  423. // Put the map index into the printable ASCII range
  424. modMapIndex += 32;
  425. // WARNING: The channels ExInfo field has a maximum size of 40 bytes.
  426. char exInfo[41];
  427. sprintf(exInfo, "%08lX%08lX%08lX%08lX%c%c%c%c", mVersion, fileCRC,
  428. mClanID1, mClanID2, (0x30 + mGameType), gameFlags1, gameFlags2, modMapIndex);
  429. channel->SetExtraInfo(exInfo);
  430. //-------------------------------------------------------------------------
  431. // Encode topic
  432. //-------------------------------------------------------------------------
  433. unsigned int titleLength = min<unsigned int>(strlen(mTitle), 32);
  434. titleLength += 0x20;
  435. // WARNING: The channels topic field has a maximum size of 80 bytes.
  436. // Ping profile and quickmatch settings are encoded in the topic in
  437. // addition to the the game title. The combined maximum of ALL these
  438. // entries MUST NEVER exceed 80 bytes.
  439. char topic[81];
  440. sprintf(topic, "%c%.32s", titleLength, mTitle);
  441. //
  442. // Only using 61 max right now. Room for a map name maybe? ST - 10/31/2002 2:55PM
  443. //
  444. unsigned int mapLength = min<unsigned int>(strlen(mMapName), 16);
  445. mapLength += 0x20;
  446. // WARNING: The channels topic field has a maximum size of 80 bytes.
  447. // Ping profile and quickmatch settings are encoded in the topic in
  448. // addition to the the game title. The combined maximum of ALL these
  449. // entries MUST NEVER exceed 80 bytes.
  450. char mapinfo[81];
  451. sprintf(mapinfo, "%c%.16s", mapLength, mMapName);
  452. strcat(topic, mapinfo);
  453. // Add our ping profile
  454. const PingProfile& localPings = GetLocalPingProfile();
  455. EncodePingProfile(localPings, topic);
  456. channel->SetTopic(topic);
  457. }
  458. }
  459. /******************************************************************************
  460. *
  461. * NAME
  462. * WOLGameInfo::
  463. *
  464. * DESCRIPTION
  465. *
  466. * INPUTS
  467. *
  468. * RESULT
  469. *
  470. ******************************************************************************/
  471. bool WOLGameInfo::IsValidGameChannel(const RefPtr<ChannelData>& channel)
  472. {
  473. WOLGameInfo gameInfo(channel);
  474. return (gameInfo.IsDataValid() && (gameInfo.mVersion == (unsigned long)cNetwork::Get_Exe_Key()));
  475. }
  476. /******************************************************************************
  477. *
  478. * NAME
  479. * WOLGameInfo::IsClanCompeting
  480. *
  481. * DESCRIPTION
  482. * Check if the specified clan is competing in the game.
  483. *
  484. * INPUTS
  485. * Clan - ID of clan to check.
  486. *
  487. * RESULT
  488. * True if clan is competing.
  489. *
  490. ******************************************************************************/
  491. bool WOLGameInfo::IsClanCompeting(unsigned long clanID) const
  492. {
  493. return (mIsClanGame && (clanID != 0) && ((clanID == mClanID1) || (clanID == mClanID2)));
  494. }
  495. /******************************************************************************
  496. *
  497. * NAME
  498. * WOLGameInfo::IsClanGameOpen
  499. *
  500. * DESCRIPTION
  501. * Check if the clan game is open for new clans to join.
  502. *
  503. * INPUTS
  504. * NONE
  505. *
  506. * RESULT
  507. * True if the game is open to clans.
  508. *
  509. ******************************************************************************/
  510. bool WOLGameInfo::IsClanGameOpen(void) const
  511. {
  512. return (mIsClanGame && ((0 == mClanID1) || (0 == mClanID2)));
  513. }
  514. /******************************************************************************
  515. *
  516. * NAME
  517. * WOLGameInfo::CanUserJoin
  518. *
  519. * DESCRIPTION
  520. * Check if the user is able to join this game.
  521. *
  522. * INPUTS
  523. * User
  524. *
  525. * RESULT
  526. * True if user can join this game.
  527. *
  528. ******************************************************************************/
  529. bool WOLGameInfo::CanUserJoin(const RefPtr<UserData>& user)
  530. {
  531. if (!user.IsValid() || !mIsDataValid || !mIsMapValid)
  532. {
  533. return false;
  534. }
  535. if (mVersion != (unsigned long)cNetwork::Get_Exe_Key())
  536. {
  537. return false;
  538. }
  539. if (mIsClanGame)
  540. {
  541. unsigned long userClanID = user->GetSquadID();
  542. return ((0 != userClanID) && (IsClanGameOpen() || IsClanCompeting(userClanID)));
  543. }
  544. return true;
  545. }