/* ** Command & Conquer Renegade(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 . */ /****************************************************************************** * * FILE * $Archive: /Commando/Code/Commando/WOLJoinGame.cpp $ * * DESCRIPTION * * PROGRAMMER * $Author: Denzil_l $ * * VERSION INFO * $Revision: 18 $ * $Modtime: 1/17/02 11:43a $ * ******************************************************************************/ #include "WOLJoinGame.h" #include "DlgWOLWait.h" #include "DlgMessageBox.h" #include "DlgMPConnect.h" #include "Nat.h" #include "Natter.h" #include "FirewallWait.h" #include "CNetwork.h" #include "WOLGameInfo.h" #include #include #include #include "String_IDs.h" #include #include using namespace WWOnline; /****************************************************************************** * * NAME * WOLJoinGame::JoinTheGame * * DESCRIPTION * Join the specified game. * * INPUTS * GameName - Name of the game to join * Password - Game password * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::JoinTheGame(const wchar_t* gameName, const wchar_t* password, bool allowTeamSelect) { WWASSERT(gameName != NULL && "Invalid parameter"); if (gameName) { // Create the object to handle the game joining process. WOLJoinGame* joinGame = new WOLJoinGame; WWASSERT(joinGame && "WOLJoinGame failed to instantiate"); if (joinGame) { if (joinGame->FinalizeCreate()) { // Start the join game process if (joinGame->Join(gameName, password, allowTeamSelect)) { return; } } // This will delete the WOLJoinGame object joinGame->Release_Ref(); } // If we got here then the join failed. Show a dialog telling the user // that we were unable to join the requested game. WideStringClass message(255, true); message.Format(TRANSLATE(IDS_GAME_JOINCHANNEL), gameName); DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_ERROR), message); } } /****************************************************************************** * * NAME * WOLJoinGame::WOLJoinGame * * DESCRIPTION * Default constructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ WOLJoinGame::WOLJoinGame() : mJoinState(IDLE_STATE), mAllowTeamSelect(true), mTeamChoice(-1), mClanID(0) { WWDEBUG_SAY(("WOLJoinGame: Instantiated\n")); } /****************************************************************************** * * NAME * WOLJoinGame::~WOLJoinGame * * DESCRIPTION * Destructor * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ WOLJoinGame::~WOLJoinGame() { WWDEBUG_SAY(("WOLJoinGame: Destroyed\n")); } /****************************************************************************** * * NAME * WOLJoinGame::FinalizeCreate * * DESCRIPTION * * INPUTS * NONE * * RESULT * True if successful * ******************************************************************************/ bool WOLJoinGame::FinalizeCreate(void) { mWOLSession = Session::GetInstance(false); return mWOLSession.IsValid(); } /****************************************************************************** * * NAME * WOLJoinGame::CreateGameFromChannel * * DESCRIPTION * Create a game data instance from a WWOnline game channel. * * INPUTS * Channel - Game channel to create game data instance from. * * RESULT * Game - Instance to game. * ******************************************************************************/ cGameData* WOLJoinGame::CreateGameFromChannel(const RefPtr& channel) { WWASSERT(channel.IsValid() && "Invalid paramter"); WWDEBUG_SAY(("WOLJoinGame: Create game from channel '%S'\n", (const WCHAR*)channel->GetName())); // Extract game information from the channel WOLGameInfo gameInfo(channel); if (gameInfo.IsDataValid() == false) { return NULL; } // Create an instance of the correct type. cGameData* theGame = cGameData::Create_Game_Of_Type((cGameData::GameTypeEnum)gameInfo.GameType()); if (theGame) { // The game owner is the name of the channel const WideStringClass& channelName = channel->GetName(); theGame->Set_Owner(const_cast(channelName)); if (gameInfo.IsPassworded()) { theGame->Set_Password(mPassword); } theGame->Import_Tier_1_Data(gameInfo); } return theGame; } /****************************************************************************** * * NAME * WOLJoinGame::Join * * DESCRIPTION * The steps to join a game successfully are as follows: * * 1) Join the game channel. * 2) Allow user to select his team. * 3) Receive team selection choice. * 4) Create an instance of the game. * 5) Perform firewall negotiation * 6) Connect to the server. * * INPUTS * Name - Name of game channel (This is usually the same as the hosts name). * Password - Password to enter game; NULL if not passworded. * AllowSelect - True if user is allowed to select their team. * * RESULT * True if join request is successful. * ******************************************************************************/ bool WOLJoinGame::Join(const wchar_t* gameName, const wchar_t* password, bool allowTeamSelect) { WWDEBUG_SAY(("WOLJoinGame: Joining game channel '%S' Password: '%S'\n", gameName, password)); mAllowTeamSelect = allowTeamSelect; mGameName = gameName; mPassword = password; //--------------------------------------------------------------------------- // First we need to join the channel //--------------------------------------------------------------------------- RefPtr product = Product::Current(); WWASSERT(product.IsValid()); if (!product.IsValid()) { WWDEBUG_SAY(("ERROR: WWOnline product not initialized.\n")); return false; } int gameType = product->GetGameCode(); RefPtr wait = mWOLSession->JoinChannel(gameName, password, gameType); if (!wait.IsValid()) { WWDEBUG_SAY(("ERROR: Couldn't create JoinChannellWait\n")); return false; } // Tell the firewall code that we are connecting as a client. WOLNATInterface.Set_Server(false); // Listen for channel events. We will use this to obtain the channel Observer::NotifyMe(*mWOLSession); // Generate message for user to see while we are attempting to join the channel. WideStringClass message(255, true); message.Format(TRANSLATE(IDS_GAME_JOINCHANNEL), gameName); mJoinState = JOINING_STATE; return DlgWOLWait::DoDialog((const WCHAR*)message, wait, this); } /****************************************************************************** * * NAME * WOLJoinGame::ProceedWithConnection * * DESCRIPTION * * INPUTS * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::ProceedWithConnection(int teamChoice) { WWDEBUG_SAY(("WOLJoinGame: Proceeding with connection\n")); bool success = StartServerConnect(); // If the connection is underway then wait for it to complete. if (success) { mTeamChoice = teamChoice; return; } // An error has occured while attempting to connect. DlgMsgBox::DoDialog(IDS_WOL_ERROR, IDS_MP_UNABLE_CONNECT_TO_SERVER); Leave(); } /****************************************************************************** * * NAME * WOLJoinGame::Leave * * DESCRIPTION * * INPUTS * * RESULT * ******************************************************************************/ void WOLJoinGame::Leave(void) { WWDEBUG_SAY(("WOLJoinGame: Leaving channel\n")); // If the user elected to leave the game or we encountered an error starting // the connection then leave the channel. RefPtr wait = mWOLSession->LeaveChannel(); DlgWOLWait::DoDialog(IDS_GAME_LEAVECHANNEL, wait); // This will delete the WOLJoinGame object Release_Ref(); } /****************************************************************************** * * NAME * WOLJoinGame::StartServerConnect * * DESCRIPTION * Start server connection negotiation * * INPUTS * NONE * * RESULT * True if negotiation successfully started. * ******************************************************************************/ bool WOLJoinGame::StartServerConnect(void) { WWDEBUG_SAY(("WOLJoinGame: Start server connect\n")); // If the channel is NOT valid then bad things have happened. if (!mTheChannel.IsValid()) { WWDEBUG_SAY(("WOLJoinGame: ERROR channel not valid when connecting to host\n")); WWASSERT(mTheChannel.IsValid() && "Bad channel connecting to host"); return false; } // Verify that the user can join this game. WOLGameInfo gameInfo(mTheChannel); RefPtr user = mWOLSession->GetCurrentUser(); if (gameInfo.CanUserJoin(user) == false) { WWDEBUG_SAY(("WOLJoinGame: ERROR - User cannot join this game\n")); return false; } // If we are playing a clan game then we need the users clan ID in order to join. if (gameInfo.IsClanGame()) { mClanID = user->GetSquadID(); } // Delete any existing game. if (PTheGameData) { delete PTheGameData; PTheGameData = NULL; } // Create a new game from the channel cGameData* theGame = CreateGameFromChannel(mTheChannel); WWASSERT(theGame && "WOLJoinGame failed to create cGameData"); if (theGame == NULL) { WWDEBUG_SAY(("WOLJoinGame: ERROR failed to create cGameData\n")); return false; } // Assign the new game instance PTheGameData = theGame; // We are done with the channel mTheChannel.Release(); //--------------------------------------------------------------------------- // Wait for the firewall negotiation. Will send DlgWOLWaitEvent when complete. //--------------------------------------------------------------------------- RefPtr wait = FirewallConnectWait::Create(); if (!wait.IsValid()) { WWDEBUG_SAY(("WOLJoinGame: ERROR couldn't create FireWallWait\n")); return false; } mJoinState = FIREWALL_STATE; return DlgWOLWait::DoDialog(TRANSLATE (IDS_MENU_CONNECTING), wait, this); } /****************************************************************************** * * NAME * WOLJoinGame::ConnectToServer * * DESCRIPTION * Establish connection to game server. * * INPUTS * NONE * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::ConnectToServer(void) { WWDEBUG_SAY(("WOLJoinGame: Connect to server\n")); // Start the client unsigned short my_port = FirewallHelper.Get_Client_Bind_Port(); cNetwork::Init_Client(my_port); // Display the "connecting" dialog. // Note: This dialog will close automatically when the connection has been // successfully completed. DlgMPConnect::DoDialog(mTeamChoice, mClanID); // Our job is done. (This will delete the WOLJoinGame object) Release_Ref(); } /****************************************************************************** * * NAME * WOLJoinGame::HandleNotification(ChannelEvent) * * DESCRIPTION * Handle channel events. Of particular interest during a join is the * channel data event. This event tells us that there is information * available from the channel encoded in the topic and exinfo fields that * we can use to create the game from. * * INPUTS * ChannelEvent * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::HandleNotification(ChannelEvent& event) { // The channel data is always updated immediately after a channel is joined. // Therefore use this event to start the creation of the game we are joining. if (event.GetStatus() == ChannelNewData) { // Get the channel that is the subject of this event. const RefPtr& channel = event.Subject(); WWASSERT(channel.IsValid()); // If the name of this channel is the name of the game we are joining // then create the game from this channel. const WideStringClass& channelName = channel->GetName(); if (channelName.Compare_No_Case(mGameName) == 0) { WWDEBUG_SAY(("WOLJoinGame: Joined game channel '%S'\n", (const WCHAR*)channelName)); // Keep a reference to the channel so we can create the game from it latter mTheChannel = channel; } } } /****************************************************************************** * * NAME * WOLJoinGame::HandleNotification(DlgWOLWaitEvent) * * DESCRIPTION * Handle result of channel join and firewall negotiation. If everything * went okay then proceed with connecting to the game server. Otherwise * tell the user what went wrong. * * INPUTS * Event - Result event from joining WOL game wait condition. * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::HandleNotification(DlgWOLWaitEvent& event) { // If the wait condition completed with success. if (event.Result() == WaitCondition::ConditionMet) { if (JOINING_STATE == mJoinState) { mJoinState = IDLE_STATE; // If we just joined the channel we need to present the user with // the team selection dialog. This dialog will allow them to view // the current teams and / or change their team. if (mAllowTeamSelect) { // DlgMPTeamSelect will send a signal indicating if the user has opted // to continue with the game or to back out. See ReceiveSignal() DlgMPTeamSelect::DoDialog(*this); } else { ProceedWithConnection(-1); } } else if (FIREWALL_STATE == mJoinState) { // If we have finished the firewall negotiation then proceed with // the server connection. mJoinState = IDLE_STATE; ConnectToServer(); } } else { // If the wait condition failed then report the reason for the failure and // leave the channel. const WideStringClass& text = event.Subject()->GetResultText(); WWDEBUG_SAY(("WOLJoinGame: Wait failed - %S\n", (const WCHAR*)text)); DlgMsgBox::DoDialog(TRANSLATE(IDS_WOL_ERROR), text); Leave(); } } /****************************************************************************** * * NAME * WOLJoinGame::ReceiveSignal(MPChooseTeamSignal) * * DESCRIPTION * The team selection dialog will send a signal indicating the users choice * regarding his team preference. * * INPUTS * Signal * * RESULT * NONE * ******************************************************************************/ void WOLJoinGame::ReceiveSignal(MPChooseTeamSignal& signal) { // If the user wants to proceed then connect to the server othewise leave // the game channel. if (signal.GetItemA() == true) { ProceedWithConnection(signal.GetItemB()); } else { Leave(); } }