WOLJoinGame.cpp 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609
  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/WOLJoinGame.cpp $
  22. *
  23. * DESCRIPTION
  24. *
  25. * PROGRAMMER
  26. * $Author: Denzil_l $
  27. *
  28. * VERSION INFO
  29. * $Revision: 18 $
  30. * $Modtime: 1/17/02 11:43a $
  31. *
  32. ******************************************************************************/
  33. #include "WOLJoinGame.h"
  34. #include "DlgWOLWait.h"
  35. #include "DlgMessageBox.h"
  36. #include "DlgMPConnect.h"
  37. #include "Nat.h"
  38. #include "Natter.h"
  39. #include "FirewallWait.h"
  40. #include "CNetwork.h"
  41. #include "WOLGameInfo.h"
  42. #include <WWOnline\WOLSession.h>
  43. #include <WWOnline\WOLProduct.h>
  44. #include <WWOnline\WOLChannel.h>
  45. #include "String_IDs.h"
  46. #include <WWTranslateDB\TranslateDB.h>
  47. #include <WWDebug\WWDebug.h>
  48. using namespace WWOnline;
  49. /******************************************************************************
  50. *
  51. * NAME
  52. * WOLJoinGame::JoinTheGame
  53. *
  54. * DESCRIPTION
  55. * Join the specified game.
  56. *
  57. * INPUTS
  58. * GameName - Name of the game to join
  59. * Password - Game password
  60. *
  61. * RESULT
  62. * NONE
  63. *
  64. ******************************************************************************/
  65. void WOLJoinGame::JoinTheGame(const wchar_t* gameName, const wchar_t* password, bool allowTeamSelect)
  66. {
  67. WWASSERT(gameName != NULL && "Invalid parameter");
  68. if (gameName)
  69. {
  70. // Create the object to handle the game joining process.
  71. WOLJoinGame* joinGame = new WOLJoinGame;
  72. WWASSERT(joinGame && "WOLJoinGame failed to instantiate");
  73. if (joinGame)
  74. {
  75. if (joinGame->FinalizeCreate())
  76. {
  77. // Start the join game process
  78. if (joinGame->Join(gameName, password, allowTeamSelect))
  79. {
  80. return;
  81. }
  82. }
  83. // This will delete the WOLJoinGame object
  84. joinGame->Release_Ref();
  85. }
  86. // If we got here then the join failed. Show a dialog telling the user
  87. // that we were unable to join the requested game.
  88. WideStringClass message(255, true);
  89. message.Format(TRANSLATE(IDS_GAME_JOINCHANNEL), gameName);
  90. DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_ERROR), message);
  91. }
  92. }
  93. /******************************************************************************
  94. *
  95. * NAME
  96. * WOLJoinGame::WOLJoinGame
  97. *
  98. * DESCRIPTION
  99. * Default constructor
  100. *
  101. * INPUTS
  102. * NONE
  103. *
  104. * RESULT
  105. * NONE
  106. *
  107. ******************************************************************************/
  108. WOLJoinGame::WOLJoinGame() :
  109. mJoinState(IDLE_STATE),
  110. mAllowTeamSelect(true),
  111. mTeamChoice(-1),
  112. mClanID(0)
  113. {
  114. WWDEBUG_SAY(("WOLJoinGame: Instantiated\n"));
  115. }
  116. /******************************************************************************
  117. *
  118. * NAME
  119. * WOLJoinGame::~WOLJoinGame
  120. *
  121. * DESCRIPTION
  122. * Destructor
  123. *
  124. * INPUTS
  125. * NONE
  126. *
  127. * RESULT
  128. * NONE
  129. *
  130. ******************************************************************************/
  131. WOLJoinGame::~WOLJoinGame()
  132. {
  133. WWDEBUG_SAY(("WOLJoinGame: Destroyed\n"));
  134. }
  135. /******************************************************************************
  136. *
  137. * NAME
  138. * WOLJoinGame::FinalizeCreate
  139. *
  140. * DESCRIPTION
  141. *
  142. * INPUTS
  143. * NONE
  144. *
  145. * RESULT
  146. * True if successful
  147. *
  148. ******************************************************************************/
  149. bool WOLJoinGame::FinalizeCreate(void)
  150. {
  151. mWOLSession = Session::GetInstance(false);
  152. return mWOLSession.IsValid();
  153. }
  154. /******************************************************************************
  155. *
  156. * NAME
  157. * WOLJoinGame::CreateGameFromChannel
  158. *
  159. * DESCRIPTION
  160. * Create a game data instance from a WWOnline game channel.
  161. *
  162. * INPUTS
  163. * Channel - Game channel to create game data instance from.
  164. *
  165. * RESULT
  166. * Game - Instance to game.
  167. *
  168. ******************************************************************************/
  169. cGameData* WOLJoinGame::CreateGameFromChannel(const RefPtr<ChannelData>& channel)
  170. {
  171. WWASSERT(channel.IsValid() && "Invalid paramter");
  172. WWDEBUG_SAY(("WOLJoinGame: Create game from channel '%S'\n", (const WCHAR*)channel->GetName()));
  173. // Extract game information from the channel
  174. WOLGameInfo gameInfo(channel);
  175. if (gameInfo.IsDataValid() == false)
  176. {
  177. return NULL;
  178. }
  179. // Create an instance of the correct type.
  180. cGameData* theGame = cGameData::Create_Game_Of_Type((cGameData::GameTypeEnum)gameInfo.GameType());
  181. if (theGame)
  182. {
  183. // The game owner is the name of the channel
  184. const WideStringClass& channelName = channel->GetName();
  185. theGame->Set_Owner(const_cast<WideStringClass&>(channelName));
  186. if (gameInfo.IsPassworded())
  187. {
  188. theGame->Set_Password(mPassword);
  189. }
  190. theGame->Import_Tier_1_Data(gameInfo);
  191. }
  192. return theGame;
  193. }
  194. /******************************************************************************
  195. *
  196. * NAME
  197. * WOLJoinGame::Join
  198. *
  199. * DESCRIPTION
  200. * The steps to join a game successfully are as follows:
  201. *
  202. * 1) Join the game channel.
  203. * 2) Allow user to select his team.
  204. * 3) Receive team selection choice.
  205. * 4) Create an instance of the game.
  206. * 5) Perform firewall negotiation
  207. * 6) Connect to the server.
  208. *
  209. * INPUTS
  210. * Name - Name of game channel (This is usually the same as the hosts name).
  211. * Password - Password to enter game; NULL if not passworded.
  212. * AllowSelect - True if user is allowed to select their team.
  213. *
  214. * RESULT
  215. * True if join request is successful.
  216. *
  217. ******************************************************************************/
  218. bool WOLJoinGame::Join(const wchar_t* gameName, const wchar_t* password, bool allowTeamSelect)
  219. {
  220. WWDEBUG_SAY(("WOLJoinGame: Joining game channel '%S' Password: '%S'\n", gameName, password));
  221. mAllowTeamSelect = allowTeamSelect;
  222. mGameName = gameName;
  223. mPassword = password;
  224. //---------------------------------------------------------------------------
  225. // First we need to join the channel
  226. //---------------------------------------------------------------------------
  227. RefPtr<Product> product = Product::Current();
  228. WWASSERT(product.IsValid());
  229. if (!product.IsValid())
  230. {
  231. WWDEBUG_SAY(("ERROR: WWOnline product not initialized.\n"));
  232. return false;
  233. }
  234. int gameType = product->GetGameCode();
  235. RefPtr<WaitCondition> wait = mWOLSession->JoinChannel(gameName, password, gameType);
  236. if (!wait.IsValid())
  237. {
  238. WWDEBUG_SAY(("ERROR: Couldn't create JoinChannellWait\n"));
  239. return false;
  240. }
  241. // Tell the firewall code that we are connecting as a client.
  242. WOLNATInterface.Set_Server(false);
  243. // Listen for channel events. We will use this to obtain the channel
  244. Observer<ChannelEvent>::NotifyMe(*mWOLSession);
  245. // Generate message for user to see while we are attempting to join the channel.
  246. WideStringClass message(255, true);
  247. message.Format(TRANSLATE(IDS_GAME_JOINCHANNEL), gameName);
  248. mJoinState = JOINING_STATE;
  249. return DlgWOLWait::DoDialog((const WCHAR*)message, wait, this);
  250. }
  251. /******************************************************************************
  252. *
  253. * NAME
  254. * WOLJoinGame::ProceedWithConnection
  255. *
  256. * DESCRIPTION
  257. *
  258. * INPUTS
  259. *
  260. * RESULT
  261. * NONE
  262. *
  263. ******************************************************************************/
  264. void WOLJoinGame::ProceedWithConnection(int teamChoice)
  265. {
  266. WWDEBUG_SAY(("WOLJoinGame: Proceeding with connection\n"));
  267. bool success = StartServerConnect();
  268. // If the connection is underway then wait for it to complete.
  269. if (success)
  270. {
  271. mTeamChoice = teamChoice;
  272. return;
  273. }
  274. // An error has occured while attempting to connect.
  275. DlgMsgBox::DoDialog(IDS_WOL_ERROR, IDS_MP_UNABLE_CONNECT_TO_SERVER);
  276. Leave();
  277. }
  278. /******************************************************************************
  279. *
  280. * NAME
  281. * WOLJoinGame::Leave
  282. *
  283. * DESCRIPTION
  284. *
  285. * INPUTS
  286. *
  287. * RESULT
  288. *
  289. ******************************************************************************/
  290. void WOLJoinGame::Leave(void)
  291. {
  292. WWDEBUG_SAY(("WOLJoinGame: Leaving channel\n"));
  293. // If the user elected to leave the game or we encountered an error starting
  294. // the connection then leave the channel.
  295. RefPtr<WaitCondition> wait = mWOLSession->LeaveChannel();
  296. DlgWOLWait::DoDialog(IDS_GAME_LEAVECHANNEL, wait);
  297. // This will delete the WOLJoinGame object
  298. Release_Ref();
  299. }
  300. /******************************************************************************
  301. *
  302. * NAME
  303. * WOLJoinGame::StartServerConnect
  304. *
  305. * DESCRIPTION
  306. * Start server connection negotiation
  307. *
  308. * INPUTS
  309. * NONE
  310. *
  311. * RESULT
  312. * True if negotiation successfully started.
  313. *
  314. ******************************************************************************/
  315. bool WOLJoinGame::StartServerConnect(void)
  316. {
  317. WWDEBUG_SAY(("WOLJoinGame: Start server connect\n"));
  318. // If the channel is NOT valid then bad things have happened.
  319. if (!mTheChannel.IsValid())
  320. {
  321. WWDEBUG_SAY(("WOLJoinGame: ERROR channel not valid when connecting to host\n"));
  322. WWASSERT(mTheChannel.IsValid() && "Bad channel connecting to host");
  323. return false;
  324. }
  325. // Verify that the user can join this game.
  326. WOLGameInfo gameInfo(mTheChannel);
  327. RefPtr<UserData> user = mWOLSession->GetCurrentUser();
  328. if (gameInfo.CanUserJoin(user) == false)
  329. {
  330. WWDEBUG_SAY(("WOLJoinGame: ERROR - User cannot join this game\n"));
  331. return false;
  332. }
  333. // If we are playing a clan game then we need the users clan ID in order to join.
  334. if (gameInfo.IsClanGame())
  335. {
  336. mClanID = user->GetSquadID();
  337. }
  338. // Delete any existing game.
  339. if (PTheGameData)
  340. {
  341. delete PTheGameData;
  342. PTheGameData = NULL;
  343. }
  344. // Create a new game from the channel
  345. cGameData* theGame = CreateGameFromChannel(mTheChannel);
  346. WWASSERT(theGame && "WOLJoinGame failed to create cGameData");
  347. if (theGame == NULL)
  348. {
  349. WWDEBUG_SAY(("WOLJoinGame: ERROR failed to create cGameData\n"));
  350. return false;
  351. }
  352. // Assign the new game instance
  353. PTheGameData = theGame;
  354. // We are done with the channel
  355. mTheChannel.Release();
  356. //---------------------------------------------------------------------------
  357. // Wait for the firewall negotiation. Will send DlgWOLWaitEvent when complete.
  358. //---------------------------------------------------------------------------
  359. RefPtr<WaitCondition> wait = FirewallConnectWait::Create();
  360. if (!wait.IsValid())
  361. {
  362. WWDEBUG_SAY(("WOLJoinGame: ERROR couldn't create FireWallWait\n"));
  363. return false;
  364. }
  365. mJoinState = FIREWALL_STATE;
  366. return DlgWOLWait::DoDialog(TRANSLATE (IDS_MENU_CONNECTING), wait, this);
  367. }
  368. /******************************************************************************
  369. *
  370. * NAME
  371. * WOLJoinGame::ConnectToServer
  372. *
  373. * DESCRIPTION
  374. * Establish connection to game server.
  375. *
  376. * INPUTS
  377. * NONE
  378. *
  379. * RESULT
  380. * NONE
  381. *
  382. ******************************************************************************/
  383. void WOLJoinGame::ConnectToServer(void)
  384. {
  385. WWDEBUG_SAY(("WOLJoinGame: Connect to server\n"));
  386. // Start the client
  387. unsigned short my_port = FirewallHelper.Get_Client_Bind_Port();
  388. cNetwork::Init_Client(my_port);
  389. // Display the "connecting" dialog.
  390. // Note: This dialog will close automatically when the connection has been
  391. // successfully completed.
  392. DlgMPConnect::DoDialog(mTeamChoice, mClanID);
  393. // Our job is done. (This will delete the WOLJoinGame object)
  394. Release_Ref();
  395. }
  396. /******************************************************************************
  397. *
  398. * NAME
  399. * WOLJoinGame::HandleNotification(ChannelEvent)
  400. *
  401. * DESCRIPTION
  402. * Handle channel events. Of particular interest during a join is the
  403. * channel data event. This event tells us that there is information
  404. * available from the channel encoded in the topic and exinfo fields that
  405. * we can use to create the game from.
  406. *
  407. * INPUTS
  408. * ChannelEvent
  409. *
  410. * RESULT
  411. * NONE
  412. *
  413. ******************************************************************************/
  414. void WOLJoinGame::HandleNotification(ChannelEvent& event)
  415. {
  416. // The channel data is always updated immediately after a channel is joined.
  417. // Therefore use this event to start the creation of the game we are joining.
  418. if (event.GetStatus() == ChannelNewData)
  419. {
  420. // Get the channel that is the subject of this event.
  421. const RefPtr<ChannelData>& channel = event.Subject();
  422. WWASSERT(channel.IsValid());
  423. // If the name of this channel is the name of the game we are joining
  424. // then create the game from this channel.
  425. const WideStringClass& channelName = channel->GetName();
  426. if (channelName.Compare_No_Case(mGameName) == 0)
  427. {
  428. WWDEBUG_SAY(("WOLJoinGame: Joined game channel '%S'\n", (const WCHAR*)channelName));
  429. // Keep a reference to the channel so we can create the game from it latter
  430. mTheChannel = channel;
  431. }
  432. }
  433. }
  434. /******************************************************************************
  435. *
  436. * NAME
  437. * WOLJoinGame::HandleNotification(DlgWOLWaitEvent)
  438. *
  439. * DESCRIPTION
  440. * Handle result of channel join and firewall negotiation. If everything
  441. * went okay then proceed with connecting to the game server. Otherwise
  442. * tell the user what went wrong.
  443. *
  444. * INPUTS
  445. * Event - Result event from joining WOL game wait condition.
  446. *
  447. * RESULT
  448. * NONE
  449. *
  450. ******************************************************************************/
  451. void WOLJoinGame::HandleNotification(DlgWOLWaitEvent& event)
  452. {
  453. // If the wait condition completed with success.
  454. if (event.Result() == WaitCondition::ConditionMet)
  455. {
  456. if (JOINING_STATE == mJoinState)
  457. {
  458. mJoinState = IDLE_STATE;
  459. // If we just joined the channel we need to present the user with
  460. // the team selection dialog. This dialog will allow them to view
  461. // the current teams and / or change their team.
  462. if (mAllowTeamSelect)
  463. {
  464. // DlgMPTeamSelect will send a signal indicating if the user has opted
  465. // to continue with the game or to back out. See ReceiveSignal()
  466. DlgMPTeamSelect::DoDialog(*this);
  467. }
  468. else
  469. {
  470. ProceedWithConnection(-1);
  471. }
  472. }
  473. else if (FIREWALL_STATE == mJoinState)
  474. {
  475. // If we have finished the firewall negotiation then proceed with
  476. // the server connection.
  477. mJoinState = IDLE_STATE;
  478. ConnectToServer();
  479. }
  480. }
  481. else
  482. {
  483. // If the wait condition failed then report the reason for the failure and
  484. // leave the channel.
  485. const WideStringClass& text = event.Subject()->GetResultText();
  486. WWDEBUG_SAY(("WOLJoinGame: Wait failed - %S\n", (const WCHAR*)text));
  487. DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_ERROR), text);
  488. Leave();
  489. }
  490. }
  491. /******************************************************************************
  492. *
  493. * NAME
  494. * WOLJoinGame::ReceiveSignal(MPChooseTeamSignal)
  495. *
  496. * DESCRIPTION
  497. * The team selection dialog will send a signal indicating the users choice
  498. * regarding his team preference.
  499. *
  500. * INPUTS
  501. * Signal
  502. *
  503. * RESULT
  504. * NONE
  505. *
  506. ******************************************************************************/
  507. void WOLJoinGame::ReceiveSignal(MPChooseTeamSignal& signal)
  508. {
  509. // If the user wants to proceed then connect to the server othewise leave
  510. // the game channel.
  511. if (signal.GetItemA() == true)
  512. {
  513. ProceedWithConnection(signal.GetItemB());
  514. }
  515. else
  516. {
  517. Leave();
  518. }
  519. }