/* ** 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 . */ /*********************************************************************************************** *** Confidential - Westwood Studios *** *********************************************************************************************** * * * Project Name : Commando * * * * $Archive:: /Commando/Code/Commando/cnetwork.cpp $* * * * $Author:: Byon_g $* * * * $Modtime:: 3/29/02 5:02p $* * * * $Revision:: 152 $* * * *---------------------------------------------------------------------------------------------* * Functions: * * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ #include "cnetwork.h" #include #include #include "specialbuilds.h" #include "langmode.h" #include "wolgmode.h" #include "playermanager.h" #include "textdisplay.h" #include "gameobjmanager.h" #include "multihud.h" #include "WWAudio.H" #include "useroptions.h" #include "devoptions.h" #include "translatedb.h" #include "string_ids.h" #include "msgstatlistgroup.h" #include "wwprofile.h" #include "gametype.h" #include "crc.h" #include "render2d.h" #include "wwmemlog.h" #include "svrgoodbyeevent.h" #include "gameoptionsevent.h" #include "evictionevent.h" #include "changeteamevent.h" #include "clientcontrol.h" #include "serverfps.h" #include "sbbomanager.h" #include "clientgoodbyeevent.h" //#include "helptext.h" #include "natter.h" #include "vistable.h" #include "gameinitmgr.h" #include "dlgmessagebox.h" #include "apppacketstats.h" #include "clientfps.h" #include "gamechanlist.h" #include "packetmgr.h" #include "clientpingmanager.h" #include "bandwidthgraph.h" #include "buildnum.h" #include "messagewindow.h" #include "wwmemlog.h" #include "consolemode.h" #include "slavemaster.h" #include "gamedataupdateevent.h" #include "gamespyadmin.h" #include "demosupport.h" #include "serversettings.h" #include "dlgmpconnectionrefused.h" #include "Resource.h" #include #include "ffactory.h" #include "realcrc.h" extern bool g_is_loading; // // Networking cNetwork statics // char cNetwork::MessageToSend[]; char cNetwork::Command[]; int cNetwork::ExeKey = 0; int cNetwork::ExeCRC = 0; int cNetwork::StringsCRC = 0; char cNetwork::ClientString[]; char cNetwork::ClientEnumerationString[]; CombatNetworkReceiverInstanceClass * cNetwork::NetworkReceiver = NULL; GameCombatNetworkHandlerClass cNetwork::NetHandler; int cNetwork::Fps = 0; int cNetwork::ThinkCount = 0; cMsgStatList * cNetwork::PClientStatList = NULL; cMsgStatListGroup * cNetwork::PServerStatListGroup = NULL; cConnection * cNetwork::PClientConnection = NULL; cConnection * cNetwork::PServerConnection = NULL; CombatNetworkReceiver * cNetwork::Receiver = NULL; float cNetwork::GraphingY; float cNetwork::BandwidthBarLength = 0; //int cNetwork::BandwidthScaler = 28800; int cNetwork::BandwidthScaler = 50000; bool cNetwork::HaveDoneTeamChangeDialog = false; bool cNetwork::HaveDoneMotdDialog = false; VisTableClass * cNetwork::VisTable = NULL; bool cNetwork::LastServerConnectionStateBad = false; bool cNetwork::SensibleUpdates = true; //----------------------------------------------------------------------------- void cNetwork::Init_Client(unsigned short my_port) { WWMEMLOG(MEM_NETWORK); #ifndef FREEDEDICATEDSERVER WWDEBUG_SAY(("cNetwork::Init_Client\n")); if (PClientConnection != NULL) { Cleanup_Client(); } PClientStatList = new cMsgStatList; WWASSERT(PClientStatList != NULL); //PClientStatList->Init(MESSAGE_COUNT); PClientStatList->Init(1); for (int i = 0; i < PClientStatList->Get_Num_Stats(); i++) { //PClientStatList->Set_Name(i, Message_Type_Translation(i)); /* char message_trans[200]; strcpy(message_trans, Message_Type_Translation(i)); PClientStatList->Set_Name(i, &message_trans[8]); */ PClientStatList->Set_Name(i, "message"); } WWASSERT(PClientConnection == NULL); PClientConnection = new cConnection; WWASSERT(PClientConnection != NULL); CombatManager::Set_I_Am_Client(true); PClientConnection->Install_Accept_Handler(Accept_Handler); PClientConnection->Install_Refusal_Handler(Refusal_Handler); PClientConnection->Install_Client_Broken_Connection_Handler(Client_Broken_Connection_Handler); PClientConnection->Install_Client_Packet_Handler(Client_Packet_Handler); if (cGameSpyAdmin::Is_Gamespy_Game()) { WWASSERT(PTheGameData != NULL); The_Game()->Set_Password(cGameSpyAdmin::Get_Password_Attempt()); } ULONG bbo = 0; //if (IS_SOLOPLAY || GameModeManager::Find("LAN")->Is_Active()) { if (IS_SOLOPLAY || (GameModeManager::Find("LAN")->Is_Active() && !cGameSpyAdmin::Is_Gamespy_Game())) { bbo = cBandwidth::Get_Bandwidth_Bps_From_Type(BANDWIDTH_LANT1); WWASSERT(bbo > 0); cBandwidthGraph::Set_Scale(200000); HaveDoneTeamChangeDialog = false; } else { //WWASSERT(GameModeManager::Find("WOL")->Is_Active()); bbo = cBandwidth::Get_Bandwidth_Bps_From_Type((BANDWIDTH_TYPE_ENUM)cUserOptions::Get_Bandwidth_Type()); //bbo = cUserOptions::BandwidthBps.Get(); WWASSERT(bbo > 0); int bw_scale = (bbo * 2) / 10; bw_scale = (bw_scale / 1000) * 1000; cBandwidthGraph::Set_Scale(bw_scale); if (GameModeManager::Find("WOL")->Is_Active()) { HaveDoneTeamChangeDialog = true; } } PClientConnection->Set_Bandwidth_Budget_Out(bbo); BOOL is_flow_control_enabled = !IS_SOLOPLAY; PClientConnection->Enable_Flow_Control(is_flow_control_enabled); WWASSERT(PTheGameData != NULL); PClientConnection->Init_As_Client( The_Game()->Get_Ip_Address(), The_Game()->Get_Port(), my_port); // // This packet resurfaces on the server in Application_Acceptance_Handler // cPacket packet; packet.Add_Wide_Terminated_String(cNetInterface::Get_Nickname()); packet.Add_Wide_Terminated_String(The_Game()->Get_Password(), true); packet.Add(ExeKey); packet.Add(bbo); // note, this field is consumed by wwnet PClientConnection->Connect_Cs(packet); packet.Flush(); /* if (I_Am_Only_Client()) { ServerFps.Init(); } */ HaveDoneMotdDialog = false; if (I_Am_Only_Client()) { cAppPacketStats::Reset(); } LastServerConnectionStateBad = false; cClientPingManager::Init(); #endif // !FREEDEDICATEDSERVER } //----------------------------------------------------------------------------- void cNetwork::Cleanup_Client(void) { WWMEMLOG(MEM_NETWORK); #ifndef FREEDEDICATEDSERVER WWDEBUG_SAY(("cNetwork::Cleanup_Client\n")); if (I_Am_Client()) { if (PClientConnection->Is_Established()) { // i.e we did have a connection cClientGoodbyeEvent * p_event = new cClientGoodbyeEvent; p_event->Init(); Flush(); } delete PClientConnection; PClientConnection = NULL; } CombatManager::Set_I_Am_Client(false); delete PClientStatList; PClientStatList = NULL; delete PClientControl; PClientControl = NULL; delete PClientFps; PClientFps = NULL; #endif // !FREEDEDICATEDSERVER } //----------------------------------------------------------------------------- void cNetwork::Accept_Handler(void) { WWMEMLOG(MEM_NETWORK); #ifndef FREEDEDICATEDSERVER WWDEBUG_SAY(("cNetwork::Accept_Handler\n")); WWASSERT(I_Am_Client()); CombatManager::Set_My_Id(Get_My_Id()); NetworkObjectMgrClass::Init_New_Client_ID(Get_My_Id()); if (I_Am_Only_Client()) { // // Create C->S mirrored client control object // WWASSERT(PClientControl == NULL); PClientControl = new CClientControl; PClientControl->Init(); // // Create C->S mirrored client fps object // WWASSERT(PClientFps == NULL); PClientFps = new CClientFps; PClientFps->Init(); } if (!I_Am_Server()) { if (GameModeManager::Find("LAN")->Is_Active()) { PLC->Accept_Actions(); } else { GameModeClass* gameMode = GameModeManager::Find("WOL"); if (gameMode && gameMode->Is_Active()) { WolGameModeClass* wolGame = static_cast(gameMode); WWASSERT(wolGame); wolGame->Accept_Actions(); } } } #endif // !FREEDEDICATEDSERVER } //----------------------------------------------------------------------------- void cNetwork::Refusal_Handler(REFUSAL_CODE refusal_code) { #ifndef FREEDEDICATEDSERVER WWDEBUG_SAY(("cNetwork::Refusal_Handler\n")); // Close connecting dialog as neccessary. DialogBaseClass* dialog = DialogMgrClass::Find_Dialog(IDD_MULTIPLAY_CONNECTING); if (dialog != NULL) { // Sending 1 as the parameter tells the dialog that it is being closed // as a result of a refusal from the server. dialog->On_Command(IDCANCEL, 0, 1); } // Verify refusal code is within valid range WWASSERT(REFUSAL_CLIENT_ACCEPTED <= refusal_code && REFUSAL_BY_APPLICATION >= refusal_code); WWASSERT(I_Am_Client()); if (GameModeManager::Find("LAN")->Is_Active()) { PLC->Refusal_Actions(); } else { GameModeClass* gameMode = GameModeManager::Find("WOL"); if (gameMode && gameMode->Is_Active()) { WolGameModeClass* wolGame = static_cast(gameMode); WWASSERT(wolGame); wolGame->Refusal_Actions(); } } // // The server refused our connection request! At this stage this // is fatal. Later on we would have to re-init the connection etc. // static const unsigned long _refusalStrings[] = { IDS_MP_CONNECTION_REFUSED_GAME_FULL, // REFUSAL_GAME_FULL IDS_MP_PASSWORD_WRONG, // REFUSAL_BAD_PASSWORD IDS_MENU_VERSION_MISMATCH, // REFUSAL_VERSION_MISMATCH IDS_MP_CONNECTION_REFUSED_BY_APPLICATION, // REFUSAL_PLAYER_EXISTS IDS_MP_CONNECTION_REFUSED_BY_APPLICATION // REFUSAL_BY_APPLICATION }; const unsigned long refusalMsg = _refusalStrings[refusal_code - 1]; if (cGameSpyAdmin::Is_Gamespy_Game()) { if (refusal_code == REFUSAL_VERSION_MISMATCH) { WideStringClass tval; tval.Format(L"%s...%s", TRANSLATE(IDS_MP_CONNECTION_REFUSED_BY_APPLICATION), TRANSLATE(IDS_MENU_VERSION_MISMATCH)); DlgMPConnectionRefused::DoDialog(tval, false); } else { DlgMPConnectionRefused::DoDialog(TRANSLATE(refusalMsg), false); } } else { DlgMsgBox::DoDialog(TRANSLATE (IDS_MENU_SERVER_MESSAGE_TITLE), TRANSLATE(refusalMsg)); } // // N.B. We cannot destroy the connection from inside this callback. // #endif // !FREEDEDICATEDSERVER } //----------------------------------------------------------------------------- int cNetwork::Get_Data_Files_CRC(void) { #define UNINITIALLIZED_CRC 0x4592abf1 static int crc = UNINITIALLIZED_CRC; if ( crc == UNINITIALLIZED_CRC ) { char * filelist[] = { "jgo`fqv+aag", //"objects.ddb", "dwhjw+lkl", //"armor.ini", "gjk`v+lkl", //"bones.ini", "vpwcdf``cc`fqv+lkl", //"surfaceeffects.ini", "fdh`wdv+lkl", //"cameras.ini", "fZkjaZhbZi5+r6a", //"c_nod_mg_l0.w3d", "fZkjaZwnZi5+r6a", //"c_nod_rk_l0.w3d", "fZkjaZciZi5+r6a", //"c_nod_fl_l0.w3d", "fZkjaZ`kZi5+r6a", //"c_nod_en_l0.w3d", "fZkjaZhbjZi5+r6a", //"c_nod_mgo_l0.w3d", "fZkjaZwnjZi5+r6a", //"c_nod_rko_l0.w3d", "fZkjaZfm`hqZi5+r6a", //"c_nod_chemt_l0.w3d", "fZkjaZvklu`wZi5+r6a", //"c_nod_sniper_l0.w3d", "fZkjaZwvjiaZi5+r6a", //"c_nod_rsold_l0.w3d", "fZkjaZvqiqmZi5+r6a", //"c_nod_stlth_l0.w3d", "fZkjaZvdnpZi5+r6a", //"c_nod_saku_l0.w3d", "fZkjaZvdnp7Zi5+r6a", //"c_nod_saku2_l0.w3d", "fZkjaZwdsZi5+r6a", //"c_nod_rav_l0.w3d", "fZkjaZhwdsZi5+r6a", //"c_nod_mrav_l0.w3d", "fZkjaZhaZi5+r6a", //"c_nod_mdz_l0.w3d", "fZkjaZha7Zi5+r6a", //"c_nod_mdz2_l0.w3d", "fZkjaZqfZi5+r6a", //"c_nod_tc_l0.w3d", "fZkjaZhpqdkqZi5+r6a", //"c_nod_mutant_l0.w3d", "fZkjaZhviaZi5+r6a", //"c_nod_msld_l0.w3d", "fZkjaZvvjiaZi5+r6a", //"c_nod_ssold_l0.w3d", "fZkjaZu`qhZi5+r6a", //"c_nod_petm_l0.w3d", "fZkjaZndk`Zi5+r6a", //"c_nod_kane_l0.w3d", "fZbalZhbZi5+r6a", //"c_gdi_mg_l0.w3d", "fZbalZwnZi5+r6a", //"c_gdi_rk_l0.w3d", "fZbalZbwZi5+r6a", //"c_gdi_gr_l0.w3d", "fZbalZ`kZi5+r6a", //"c_gdi_en_l0.w3d", "fZbalZhbjZi5+r6a", //"c_gdi_mgo_l0.w3d", "fZbalZwnjZi5+r6a", //"c_gdi_rko_l0.w3d", "fZbalZv|aZi5+r6a", //"c_gdi_syd_l0.w3d", "fZbalZa`daZi5+r6a", //"c_gdi_dead_l0.w3d", "fZbalZbpkZi5+r6a", //"c_gdi_gun_l0.w3d", "fZbalZuqfmZi5+r6a", //"c_gdi_ptch_l0.w3d", "fZmdsjfZi5+r6a", //"c_havoc_l0.w3d", "fZmdsjfkZi5+r6a", //"c_havocn_l0.w3d", "fZmdsjfrZi5+r6a", //"c_havocw_l0.w3d", "fZmdsjfaZi5+r6a", //"c_havocd_l0.w3d", "fZbalZv|aZi5+r6a", //"c_gdi_syd_l0.w3d", "fZbalZv|a7Zi5+r6a", //"c_gdi_syd2_l0.w3d", "fZbalZhjglZi5+r6a", //"c_gdi_mobi_l0.w3d", "fZbalZmjqrZi5+r6a", //"c_gdi_hotw_l0.w3d", "fZbalZiqZi5+r6a", //"c_gdi_lt_l0.w3d", "fZkjaZu`qwZi5+r6a", //"c_nod_petr_l0.w3d", "fZijbdkZi5+r6a", //"c_logan_l0.w3d", "fZbalZijfn`Zi5+r6a", //"c_gdi_locke_l0.w3d", "sZkjaZgpbb|+r6a", //"v_nod_buggy.w3d", "sZkjaZdufZh+r6a", //"v_nod_apc_m.w3d", "sZkjaZdwqiw|+r6a", //"v_nod_artlry.w3d", "sZkjaZcidh`+r6a", //"v_nod_flame.w3d", "sZkjaZiqdkn+r6a", //"v_nod_ltank.w3d", "sZkjaZvqiqm+r6a", //"v_nod_stlth.w3d", "sZkjaZqwkvuqZh+r6a", //"v_nod_trnspt_m.w3d", "sZkjaZdudfm`Zh+r6a", //"v_nod_apache_m.w3d", "sZfmdh`i`jk+r6a", //"v_chameleon.w3d", "sZbalZmphs``+r6a", //"v_gdi_humvee.w3d", "sZbalZdufZh+r6a", //"v_gdi_apc_m.w3d", "sZbalZhwiv+r6a", //"v_gdi_mrls.w3d", "sZbalZh`aqkn+r6a", //"v_gdi_medtnk.w3d", "sZbalZhdhhqm+r6a", //"v_gdi_mammth.w3d", "sZulfnpu54+r6a", //"v_pickup01.w3d", "sZv`adk54+r6a", //"v_sedan01.w3d", "sZbalZjwfdZh+r6a", //"v_gdi_orca_m.w3d", "sZbalZqwkvuqZh+r6a", //"v_gdi_trnspt_m.w3d", }; #define NUM_CRC_FILES (sizeof( filelist ) / sizeof( filelist[0] ) ) crc = 0; for ( int i = 0; i < NUM_CRC_FILES; i++ ) { StringClass name = filelist[i]; // Obfuscate name char * n = &name[0]; while ( *n ) *n++ ^= 0x5; // Debug_Say(( " \"%s\",\n", name )); FileClass * file = _TheFileFactory->Get_File( name ); if ( file && file->Is_Available() ) { int size = file->Size(); file->Open(); while ( size > 0 ) { unsigned char buffer[ 4096 ]; int amount = min( (int)size, (int)sizeof(buffer) ); amount = file->Read( buffer, amount ); crc = CRC_Memory( buffer, amount, crc ); size -= amount; } file->Close(); } else { // Debug_Say(( "******%s not found\n", name )); } } } return crc; } //----------------------------------------------------------------------------- void cNetwork::Compute_Exe_Key(void) { WWDEBUG_SAY(("cNetwork::Compute_Exe_Key\n")); char exe_filename[500]; int succeeded = 0; succeeded = ::GetModuleFileName(NULL, exe_filename, sizeof(exe_filename)); WWASSERT(succeeded); StringClass key_string; StringClass string; StringClass build_string; // // 11/07/01 // We now match only on build number. // string.Format("RENEGADE %u", BuildInfoClass::Get_Build_Number()); WWDEBUG_SAY(("File id string: %s\n", string)); key_string += string; key_string += " "; ExeCRC = CRCEngine()(string, strlen(string)); // // TSS 09/07/01 // N.B. Do not require scripts to be in sync any more, since they do not run on the client. // Furthermore we would have to match the correct scripts target (d/p/r) and // also handle the registry flag that forces scriptsd.dll. // // // TSS102401 // We cannot match on exact strings.tdb because foreign language versions // are different files. Instead, match on filename and internal version number. // //cMiscUtil::Get_File_Id_String("Data\\strings.tdb", string); string.Format("strings.tdb %u", TranslateDBClass::Get_Version_Number()); WWDEBUG_SAY(("File id string: %s\n", string)); key_string += string; key_string += " "; StringsCRC = CRCEngine()(string, strlen(string)); // // TSS102401 - we can't match always.dbs either. // always.dbs will not match among foreign language version for numerous reasons. // // // Use the crc of the keystring as the key // ExeKey = CRCEngine()(key_string, strlen(key_string)); // // Include data file crc // int data_file_crc = Get_Data_Files_CRC(); ExeKey ^= data_file_crc; } //----------------------------------------------------------------------------- void cNetwork::Onetime_Init(void) { WWMEMLOG(MEM_NETWORK); WWDEBUG_SAY(("cNetwork::Onetime_Init\n")); Compute_Exe_Key(); NetworkReceiver = new CombatNetworkReceiverInstanceClass; Set_Receiver(NetworkReceiver); CombatManager::Set_Combat_Network_Handler(&NetHandler); //Clear_Help_Text(); } //----------------------------------------------------------------------------- void cNetwork::Onetime_Shutdown(void) { WWDEBUG_SAY(("cNetwork::Onetime_Shutdown\n")); Set_Receiver(NULL); delete NetworkReceiver; #if 0 UINT comp_bytes = cConnection::Get_Total_Compressed_Bytes_Sent(); UINT uncomp_bytes = cConnection::Get_Total_Uncompressed_Bytes_Sent(); Debug_Say(("\n")); Debug_Say(("TotalCompressedBytesSent = %d\n", comp_bytes)); Debug_Say(("Without compression = %d\n", uncomp_bytes)); if (uncomp_bytes > 0) { Debug_Say(("Compressed/Uncompressed = %-5.2f\n\n", comp_bytes / (float) uncomp_bytes)); } #endif // 0 #pragma message("(TSS) This packet ref count assert very occasionally fails.") //WWASSERT(cPacket::Get_Ref_Count() == 0); REF_PTR_RELEASE(VisTable); cGameChannelList::Remove_All();//TSS092201 added // // These are only printed once. So only run one game on a test run. // cAppPacketStats::Dump_Diagnostics(); } //----------------------------------------------------------------------------- void cNetwork::Init_Server(void) { WWMEMLOG(MEM_NETWORK); WWDEBUG_SAY(("cNetwork::Init_Server\n")); #ifndef BETACLIENT NetworkObjectClass::Set_Is_Server(true); PServerStatListGroup = new cMsgStatListGroup; WWASSERT(PServerStatListGroup != NULL); //PServerStatListGroup->Init(The_Game()->Get_Max_Players(), MESSAGE_COUNT); WWASSERT(PTheGameData != NULL); PServerStatListGroup->Init(The_Game()->Get_Max_Players(), 1); /* for (int message_type = 0; message_type < MESSAGE_COUNT; message_type++) { char message_trans[200]; strcpy(message_trans, Message_Type_Translation(message_type)); PServerStatListGroup->Set_Name(message_type, &message_trans[8]); } */ WWASSERT(PServerConnection == NULL); PServerConnection = new cConnection; WWASSERT(PServerConnection != NULL); CombatManager::Set_I_Am_Server(true); PServerConnection->Install_Server_Broken_Connection_Handler(Server_Broken_Connection_Handler); PServerConnection->Install_Eviction_Handler(Eviction_Handler); PServerConnection->Install_Conn_Handler(Connection_Handler); PServerConnection->Install_Application_Acceptance_Handler(Application_Acceptance_Handler); PServerConnection->Install_Server_Packet_Handler(Server_Packet_Handler); //if (IS_SOLOPLAY || GameModeManager::Find("LAN")->Is_Active()) { if (IS_SOLOPLAY || (GameModeManager::Find("LAN")->Is_Active() && !cGameSpyAdmin::Is_Gamespy_Game())) { ULONG bbo = cBandwidth::Get_Bandwidth_Bps_From_Type(BANDWIDTH_LANT1); WWASSERT(bbo > 0); PServerConnection->Set_Bandwidth_Budget_Out(bbo); cBandwidthGraph::Set_Scale(200000); } else { //WWASSERT(GameModeManager::Find("WOL")->Is_Active()); WWASSERT(cUserOptions::BandwidthBps.Get() > 0); unsigned long bw = cBandwidth::Get_Bandwidth_Bps_From_Type((BANDWIDTH_TYPE_ENUM)cUserOptions::Get_Bandwidth_Type()); /* ** Only use a portion of the bandwidth based on how many slave servers there are. */ if (The_Game()->IsDedicated.Get() && !SlaveMaster.Am_I_Slave()) { if (cUserOptions::Get_Bandwidth_Type() == BANDWIDTH_AUTO) { if (ServerSettingsClass::Get_Master_Bandwidth() == 0 || ServerSettingsClass::Get_Master_Bandwidth() == 0xffffffff) { int num_slaves = SlaveMaster.Get_Num_Enabled_Slaves(); if (num_slaves) { bw = bw / (num_slaves+1); } } } } PServerConnection->Set_Bandwidth_Budget_Out(bw); //PServerConnection->Set_Bandwidth_Budget_Out(cUserOptions::BandwidthBps.Get()); int bw_scale = (cUserOptions::BandwidthBps.Get() * 2) / 10; bw_scale = (bw_scale / 1000) * 1000; cBandwidthGraph::Set_Scale(bw_scale); } double max_acceptable_packetloss_pc = 10; PServerConnection->Set_Max_Acceptable_Packetloss_Pc(max_acceptable_packetloss_pc); BOOL is_flow_control_enabled = !IS_SOLOPLAY; PServerConnection->Enable_Flow_Control(is_flow_control_enabled); WWASSERT(PTheGameData != NULL); PServerConnection->Init_As_Server( The_Game()->Get_Port(), The_Game()->Get_Max_Players(), The_Game()->IsDedicated.Get(), ntohl(The_Game()->Get_Ip_Address())); // // Create teams // //if (The_Game()->Is_Team_Game()) { for (int team_num = 0; team_num < MAX_TEAMS; team_num++) { cTeam * p_team = new cTeam; p_team->Init(team_num); } //} cSbboManager::Reset(); cAppPacketStats::Reset(); #endif // not BETACLIENT } //----------------------------------------------------------------------------- void cNetwork::Cleanup_Server(void) { WWDEBUG_SAY(("cNetwork::Cleanup_Server\n")); if (I_Am_Server()) { delete PServerConnection; PServerConnection = NULL; } CombatManager::Set_I_Am_Server(false); delete PServerStatListGroup; PServerStatListGroup = NULL; NetworkObjectClass::Set_Is_Server(false); } //----------------------------------------------------------------------------- enum { CHUNKID_PLAYERMANAGER = 9876543, }; //----------------------------------------------------------------------------- bool cNetwork::Save(ChunkSaveClass & csave) { csave.Begin_Chunk(CHUNKID_PLAYERMANAGER); cPlayerManager::Save(csave); csave.End_Chunk(); return true; } //----------------------------------------------------------------------------- bool cNetwork::Load(ChunkLoadClass &cload) { while (cload.Open_Chunk()) { switch(cload.Cur_Chunk_ID()) { case CHUNKID_PLAYERMANAGER: //cPlayerManager::Remove_All(); cPlayerManager::Load(cload); break; default: Debug_Say(( "Unrecognized cNetwork chunkID\n" )); break; } cload.Close_Chunk(); } return true; } //----------------------------------------------------------------------------- void cNetwork::Update_Fps(void) { static DWORD last_time_ms = 0; static int frame_count = 0; DWORD time_now_ms = TIMEGETTIME(); // Handle timer resetting. if (time_now_ms < last_time_ms) { last_time_ms = time_now_ms; } frame_count++; DWORD time_interval = time_now_ms - last_time_ms; if (time_interval > 1000) { Fps = (int) (frame_count * 1000 / (float) time_interval + 0.5f); last_time_ms = time_now_ms; frame_count = 0; // Needed for release mode too. ST - 1/23/2002 11:02PM //#ifdef WWDEBUG if (I_Am_Server()) { WWASSERT(cServerFps::Get_Instance() != NULL); cServerFps::Get_Instance()->Set_Fps(Fps); } //#endif // WWDEBUG if (I_Am_Client() && PClientFps != NULL) { PClientFps->Set_Fps(Fps); } } } void cNetwork::Connection_Status_Change_Feedback(void) { static unsigned long _last_print = TIMEGETTIME(); static bool _last_print_bad = false; static unsigned long _print_good_soon = 0; unsigned long time = TIMEGETTIME(); const WCHAR *string = NULL; if (LastServerConnectionStateBad) { if (_last_print_bad && time - _last_print < 4000) { return; } string = TRANSLATE (IDS_MENU_CONNECTION_INTERRUPTED); _last_print_bad = true; } else { /* ** Wait 2 secs after connection restore before printing message. */ if (_last_print_bad && _print_good_soon == 0) { _print_good_soon = time; return; } if (!_last_print_bad) { return; } if (time - _print_good_soon < 2000) { return; } string = TRANSLATE (IDS_MENU_CONNECTION_RESTORED); _last_print_bad = false; } _last_print = time; WideStringClass widestring(string, true); if (CombatManager::Get_Message_Window() != NULL) { // // Display the message... // CombatManager::Get_Message_Window ()->Add_Message (widestring); } // // Write it to the logfile // StringClass temp_string; widestring.Convert_To(temp_string); WWDEBUG_SAY(("\n***%s\n", temp_string.Peek_Buffer())); } //----------------------------------------------------------------------------- void cNetwork::Update(void) { WWPROFILE( "cNetwork::Update" ); WWMEMLOG(MEM_GAMEDATA); bool flush_packets = false; ThinkCount++; // // Coding bugs may result in this function being called recursively. // Detect and assert! // static int recursion_level = 0; recursion_level++; WWASSERT(recursion_level == 1); Update_Fps(); #ifdef WWDEBUG // // Watch out for unexpected slow frames. They may interrupt networking. // static DWORD last_time_ms = TIMEGETTIME(); DWORD time_now_ms = TIMEGETTIME(); if (time_now_ms - last_time_ms > 2000) { Debug_Say(("\n***cNetwork::Update: warning, think # %d was slow (%u ms)\n\n", ThinkCount, time_now_ms - last_time_ms)); } last_time_ms = time_now_ms; #endif // WWDEBUG if (I_Am_Server()) { if (I_Am_Client()) { WWPROFILE( "Client Send" ); PClientConnection->Service_Send(); if (PClientConnection->Is_Bad_Connection() != LastServerConnectionStateBad) { LastServerConnectionStateBad = PClientConnection->Is_Bad_Connection(); //Connection_Status_Change_Feedback(); } Connection_Status_Change_Feedback(); } // { WWPROFILE("GameSpy_QnR"); // GameSpyQnR.Think(); // } WWPROFILE( "Server Read" ); PServerConnection->Service_Read(); if (!g_is_loading) { WWPROFILE( "Shared CS Think" ); Shared_Client_And_Server_Think(); } if (I_Am_Client() && !g_is_loading) { WWPROFILE( "Client_Think" ); if (Client_Think()) { flush_packets = true; } } if (!g_is_loading) { WWPROFILE( "Server_Think" ); if (Server_Think()) { flush_packets = true; } else { // Server only sends packets in response to server think, not client think. flush_packets = false; } } { WWPROFILE( "Server Send" ); PServerConnection->Service_Send(); } if (I_Am_Client()) { WWPROFILE( "Client Read" ); PClientConnection->Service_Read(); } } else if (I_Am_Client()) { { WWPROFILE( "Client Read" ); PClientConnection->Service_Read(); } if (PClientConnection->Is_Bad_Connection() != LastServerConnectionStateBad) { LastServerConnectionStateBad = PClientConnection->Is_Bad_Connection(); Connection_Status_Change_Feedback(); } if (!g_is_loading) { WWPROFILE( "Shared CS Think" ); Shared_Client_And_Server_Think(); } if (!g_is_loading) { WWPROFILE( "Client_Think" ); if (Client_Think()) { flush_packets = true; } } { WWPROFILE( "Client Send" ); if (PClientConnection != NULL) { PClientConnection->Service_Send(); } } } DEMO_SECURITY_CHECK; NetworkObjectMgrClass::Delete_Pending(); if (flush_packets) { PacketManager.Flush(true); } recursion_level--; WWASSERT(recursion_level == 0); } //----------------------------------------------------------------------------- void cNetwork::Client_Send_Packet(cPacket & packet, int mode) { #ifndef FREEDEDICATEDSERVER WWASSERT(I_Am_Client()); if (cNetwork::PClientConnection->Is_Established()) { PClientConnection->Send_Packet_To_Individual(packet, 0, mode); /* BYTE message_type = packet.Peek_Message_Type(); PClientStatList->Increment_Num_Msg_Sent(message_type); PClientStatList->Increment_Num_Byte_Sent(message_type, packet.Get_Compressed_Size_Bytes()); */ } else { WWDEBUG_SAY(("cNetwork::Client_Send_Packet: warning: Connection not yet established.\n")); //TSS2001 XXX DIE; } #endif // !FREEDEDICATEDSERVER } //----------------------------------------------------------------------------- void cNetwork::Server_Send_Packet(cPacket & packet, int mode, int recipient) { #ifndef BETACLIENT WWASSERT(I_Am_Server()); WWASSERT(PServerConnection->Is_Established()); if (recipient == ALL) { // // We cannot just send to all rhosts because that includes anyone // browsing the server settings, whereas here we wish to send to the // ingame players. // //PServerConnection->Send_Packet_To_All(*p_packet, mode); SLNode * objnode; for (objnode = cPlayerManager::Get_Player_Object_List()->Head(); objnode; objnode = objnode->Next()) { cPlayer * p_player = objnode->Data(); WWASSERT(p_player != NULL); //if (p_player->Is_Human()) { if (p_player->Get_Is_Active().Is_True() && p_player->Is_Human() && p_player->Get_Is_In_Game().Is_True()) { int client_id = p_player->Get_Id(); PServerConnection->Send_Packet_To_Individual( packet, client_id, mode); /* BYTE message_type = packet.Peek_Message_Type(); PServerStatListGroup->Increment_Num_Msg_Sent(client_id - 1, message_type); PServerStatListGroup->Increment_Num_Byte_Sent(client_id - 1, message_type, packet.Get_Compressed_Size_Bytes()); */ } } } else { PServerConnection->Send_Packet_To_Individual(packet, recipient, mode); /* BYTE message_type = packet.Peek_Message_Type(); PServerStatListGroup->Increment_Num_Msg_Sent(recipient - 1, message_type); PServerStatListGroup->Increment_Num_Byte_Sent(recipient - 1, message_type, packet.Get_Compressed_Size_Bytes()); */ } #endif // not BETACLIENT } //----------------------------------------------------------------------------- void cNetwork::Server_Send_Packet_To_All_Connected(cPacket & packet, int mode) { #ifndef BETACLIENT // // Traverse the rhost list here in the application level, so that // we can record message stats. // WWASSERT(I_Am_Server()); WWASSERT(PServerConnection->Is_Established()); //BYTE message_type = packet.Peek_Message_Type(); for (int rhost_id = PServerConnection->Get_Min_RHost(); rhost_id <= PServerConnection->Get_Max_RHost(); rhost_id++) { if (Get_Server_Rhost(rhost_id) != NULL) { PServerConnection->Send_Packet_To_Individual(packet, rhost_id, mode); /* PServerStatListGroup->Increment_Num_Msg_Sent(rhost_id - 1, message_type); PServerStatListGroup->Increment_Num_Byte_Sent(rhost_id - 1, message_type, packet.Get_Compressed_Size_Bytes()); */ } } #endif // not BETACLIENT } //----------------------------------------------------------------------------- LPCSTR cNetwork::Get_Client_Enumeration_String(void) { WWASSERT(I_Am_Server()); WWASSERT(PServerConnection->Is_Established()); char temp_str[10]; strcpy(ClientEnumerationString, ""); for (int rhost_id = PServerConnection->Get_Min_RHost(); rhost_id <= PServerConnection->Get_Max_RHost(); rhost_id++) { if (Get_Server_Rhost(rhost_id) != NULL) { strcat(ClientEnumerationString, itoa(rhost_id, temp_str, 10)); strcat(ClientEnumerationString, " "); } if (strlen(ClientEnumerationString) > 20) { strcpy(ClientEnumerationString, "many"); break; } } return ClientEnumerationString; } //----------------------------------------------------------------------------- cRemoteHost * cNetwork::Get_Server_Rhost(int client_id) { WWASSERT(I_Am_Server()); return PServerConnection->Get_Remote_Host(client_id); } //----------------------------------------------------------------------------- cRemoteHost * cNetwork::Get_Client_Rhost(void) { WWASSERT(I_Am_Client()); return PClientConnection->Get_Remote_Host(SERVER_RHOST_ID); } //----------------------------------------------------------------------------- float cNetwork::Get_Server_Rhost_Threshold_Priority(int client_id) { WWASSERT(I_Am_Server()); WWASSERT(Get_Server_Rhost(client_id) != NULL); return Get_Server_Rhost(client_id)->Get_Threshold_Priority(); } //----------------------------------------------------------------------------- float cNetwork::Get_Client_Rhost_Threshold_Priority(void) { WWASSERT(I_Am_Client()); WWASSERT(Get_Client_Rhost() != NULL); return Get_Client_Rhost()->Get_Threshold_Priority(); } //----------------------------------------------------------------------------- int cNetwork::Get_My_Id(void) { WWASSERT(I_Am_Client()); return PClientConnection->Get_Local_Id(); } //----------------------------------------------------------------------------- LPCSTR cNetwork::Get_Client_String(int recipient) { //WWASSERT(I_Am_Server()); if (recipient > 0) { WWASSERT(PServerConnection->Is_Established()); if (recipient == ALL) { sprintf(ClientString, "all %d clients (%s)", PServerConnection->Get_Num_RHosts(), Get_Client_Enumeration_String()); } else { sprintf(ClientString, "client %d", recipient); } } else { sprintf(ClientString, "server"); } // // Note: This WWASSERT would catch the overwrite AFTER it has happened... // WWASSERT(strlen(ClientString) < sizeof(ClientString)); return(ClientString); } //----------------------------------------------------------------------------- void cNetwork::Server_Broken_Connection_Handler(int broken_rhost_id) { WWASSERT(broken_rhost_id >= 0); // // The net lib calls this when a reliable packet fails after // many attempts. The connection data has already been destroyed. // WWDEBUG_SAY(("\n***Connection to client %d broken \n\n", broken_rhost_id)); WideStringClass widestring; widestring.Format( L"%s %d\n", TRANSLATION(IDS_MP_CONNECTION_TO_CLIENT_BROKEN), broken_rhost_id); WWASSERT(CombatManager::Get_Message_Window () != NULL); //Get_Text_Display()->Print_System(widestring); // // Display the message... // CombatManager::Get_Message_Window ()->Add_Message (widestring); Vector3 color(1.0f, 1.0f, 0.0f); ConsoleBox.Add_Message(&widestring, &color); WWAudioClass::Get_Instance()->Create_Instant_Sound("Broken_Connection", Matrix3D(1)); cNetwork::Cleanup_After_Client(broken_rhost_id); } //----------------------------------------------------------------------------- void cNetwork::Client_Broken_Connection_Handler(void) { // // The net lib calls this when a reliable packet fails after // many attempts. The connection data has already been destroyed. // WWASSERT(Get_Text_Display() != NULL); WWASSERT(PClientConnection != NULL); /**/ if (PClientConnection->Have_Id()) { //cHelpText::Set(TRANSLATION(IDS_MP_CONNECTION_TO_SERVER_BROKEN)); DlgMsgBox::DoDialog(L"", TRANSLATION(IDS_MP_CONNECTION_TO_SERVER_BROKEN)); } else { //cHelpText::Set(TRANSLATION(IDS_MP_UNABLE_CONNECT_TO_SERVER)); } //TSS090401 // // The client needs to quit back to the game list // extern bool g_client_quit; g_client_quit = true; //WWAudioClass::Get_Instance()->Create_Instant_Sound("Broken_Connection", Matrix3D(1)); /**/ /* WWDEBUG_SAY(("Connection to server broken.\n")); if (PClientConnection->Have_Id()) { DlgMPConnectionRefused::DoDialog(TRANSLATION(IDS_MP_CONNECTION_TO_SERVER_BROKEN), true); } else { extern bool g_client_quit; g_client_quit = true; } */ } //----------------------------------------------------------------------------- void cNetwork::Process_Eviction_Sc(cPacket & packet) { WWDEBUG_SAY(("cNetwork::Process_Eviction_Sc\n")); WWAudioClass::Get_Instance()->Create_Instant_Sound("Evicted_By_Server", Matrix3D(1)); WWASSERT(I_Am_Client()); UINT min_bps; packet.Get(min_bps);//naughty... type conversion float max_packetloss; packet.Get(max_packetloss); //UINT sustainable_bps = (UINT) packet.Get(); WWDEBUG_SAY(("\n* You were evicted from the server for inadequate bandwidth performance.\n" "* This server requires packetloss of less than %5.2f %%, and a minimum\n" "* sustainable bandwidth of %d bps.\n", max_packetloss, min_bps)); // // At this stage, just signal to close down. This is // a convenience during development // DIE; } //----------------------------------------------------------------------------- void cNetwork::Eviction_Handler(int evicted_rhost_id) { WWMEMLOG(MEM_NETWORK); WWDEBUG_SAY(("cNetwork::Eviction_Handler\n")); WWASSERT(evicted_rhost_id >= 0); WWASSERT(I_Am_Server()); //Send_Eviction_Sc(evicted_rhost_id); cEvictionEvent * p_event = new cEvictionEvent; p_event->Init(evicted_rhost_id, EVICTION_POOR_BANDWIDTH); cNetwork::Flush(); //WWAudioClass::Get_Instance()->Create_Instant_Sound("Broken_Connection", Matrix3D(1)); } //----------------------------------------------------------------------------- bool cNetwork::I_Am_God(void) { bool i_am_god = false; if (I_Am_Client()) { cPlayer * p_player = cPlayerManager::Find_Player(Get_My_Id()); if (p_player != NULL && p_player->Invulnerable.Is_True()) { i_am_god = true; } } return i_am_god; } //----------------------------------------------------------------------------- cPlayer * cNetwork::Get_My_Player_Object(void) { cPlayer * p_me = NULL; if (I_Am_Client()) { p_me = cPlayerManager::Find_Player(Get_My_Id()); } return p_me; } //----------------------------------------------------------------------------- int cNetwork::Get_My_Team_Number(void) { cPlayer * p_me = Get_My_Player_Object(); WWASSERT(p_me != NULL); return p_me->Get_Player_Type(); } //----------------------------------------------------------------------------- Vector3 cNetwork::Get_My_Color(void) { cPlayer * p_me = cPlayerManager::Find_Player(Get_My_Id()); WWASSERT(p_me != NULL); return p_me->Get_Color(); } //----------------------------------------------------------------------------- int cNetwork::Show_Welcome_Message(WideStringClass & name) { int show = false; if (!IS_MISSION && (name == cNetInterface::Get_Nickname())) { show = true; } return show; } //--------------------------------------------------------------------------- float cNetwork::Get_Distance_Priority(Vector3 & pos1, Vector3 & pos2) { Vector3 gap = pos2 - pos1; float d = gap.Length(); WWASSERT(PTheGameData != NULL); float max_distance = The_Game()->Get_Maximum_World_Distance(); WWASSERT(max_distance > 0); float range1 = max_distance / 25.0f; float range2 = max_distance / 5.0f; float range3 = max_distance + 1; float priority; if (d < range1) { priority = (float) ((range1 - d) / range1 * 0.499 + 0.50); } else if (d < range2) { priority = (float) ((range2 - d) / (range2 - range1) * 0.40 + 0.10); } else if (d < range3) { priority = (float) ((range3 - d) / (range3 - range2) * 0.10 + 0.00); } else { //WWASSERT(0); static bool already_warned = false; if (!already_warned) { Debug_Say(("Someone went outside the world box! (possibly numerous times)\n")); already_warned = true; } priority = 0; } WWASSERT(priority > -WWMATH_EPSILON && priority < 1 + WWMATH_EPSILON); return(priority); } //----------------------------------------------------------------------------- void cNetwork::Shell_Command(LPCSTR command) { WWASSERT(command != NULL); HINSTANCE hinst = ShellExecute(NULL, NULL, command, NULL, "", SW_SHOW); if ((int) hinst <= 32) { WWDEBUG_SAY(("Error: ShellExecute failed.\n")); } } //----------------------------------------------------------------------------- REFUSAL_CODE cNetwork::Application_Acceptance_Handler(cPacket & packet) { #ifndef BETACLIENT WWDEBUG_SAY(("cNetwork::Application_Acceptance_Handler\n")); WWASSERT(I_Am_Server()); // // Get player name // This is not supposed to be empty, but if for whatever reason it it, we should // just refuse, rather than crash. // WideStringClass player_name(0, true); //packet.Get_Wide_Terminated_String(player_name.Get_Buffer(256), 256); packet.Get_Wide_Terminated_String(player_name.Get_Buffer(256), 256, true); if (player_name.Get_Length() == 0) { return REFUSAL_VERSION_MISMATCH; } // Get the clients password WideStringClass password(0, true); packet.Get_Wide_Terminated_String(password.Get_Buffer(256), 256, true); // Get clients exe version int client_exe_key = packet.Get(client_exe_key); // Make sure the clients password matches the games password. WWASSERT(PTheGameData != NULL); if (The_Game()->IsPassworded.Is_True() && password.Compare(The_Game()->Get_Password()) != 0) { return REFUSAL_BAD_PASSWORD; } // Make sure the exe versions match if (client_exe_key != cNetwork::Get_Exe_Key()) { return REFUSAL_VERSION_MISMATCH; } // Make sure we haven't exceeded our max player limit if (cPlayerManager::Count() >= The_Game()->Get_Max_Players()) { return REFUSAL_GAME_FULL; } // // TSS100501 // // Make sure the player is not already in the game //GAMESPY //if (cPlayerManager::Find_Player(player_name)) { if (!cGameSpyAdmin::Is_Gamespy_Game() && cPlayerManager::Find_Player(player_name)) { return REFUSAL_PLAYER_EXISTS; } #endif // not BETACLIENT return REFUSAL_CLIENT_ACCEPTED; } //----------------------------------------------------------------------------- void cNetwork::Connection_Handler(int new_rhost_id) { WWMEMLOG(MEM_NETWORK); #ifndef BETACLIENT WWDEBUG_SAY(("cNetwork::Connection_Handler\n")); WWASSERT(new_rhost_id >= 0); WWASSERT(I_Am_Server()); WWASSERT(Receiver != NULL); /* // // Tell the new guy about all the teams. He needs this early in case he // needs to choose a team // SLNode * team_node; cTeam * p_team; for (team_node = cTeamManager::Get_Team_Object_List()->Head(); team_node; team_node = team_node->Next()) { p_team = team_node->Data(); WWASSERT(p_team != NULL); Send_Server_New_Team(p_team, new_rhost_id); } */ //TSS2001 - normal update mechanism won't catch this in time. // // Tell the new guy about all the teams. He needs this early in case he // needs to choose a team // if (!cNetwork::I_Am_Client() || new_rhost_id != cNetwork::Get_My_Id()) { for ( SLNode * team_node = cTeamManager::Get_Team_Object_List()->Head(); team_node; team_node = team_node->Next()) { cTeam * p_team = team_node->Data(); WWASSERT(p_team != NULL); Send_Object_Update(p_team, new_rhost_id); } } // // Next, send info about any remaining game options. This is only those // options that he doesn't pick up from the channel listing. // //Send_Server_Game_Options(new_rhost_id); cGameOptionsEvent * p_event = new cGameOptionsEvent; p_event->Init(new_rhost_id); Send_Object_Update(p_event, new_rhost_id); #endif // not BETACLIENT } //----------------------------------------------------------------------------- void cNetwork::Set_Desired_Frame_Sleep_Ms(int b) { WWASSERT(b >= 0); #ifdef WWDEBUG cDevOptions::DesiredFrameSleepMs.Set(b); #endif //WWDEBUG } //----------------------------------------------------------------------------- void cNetwork::Set_Simulated_Packet_Loss_Pc(int b) { WWASSERT(b >= 0); if (PClientConnection != NULL) { PClientConnection->Set_Packet_Loss(b); } if (PServerConnection != NULL) { PServerConnection->Set_Packet_Loss(b); } //SimulatedPacketLossPc = b; #ifdef WWDEBUG cDevOptions::SimulatedPacketLossPc.Set(b); #endif //WWDEBUG } //----------------------------------------------------------------------------- void cNetwork::Set_Simulated_Packet_Duplication_Pc(int b) { WWASSERT(b >= 0); if (PClientConnection != NULL) { PClientConnection->Set_Packet_Duplication(b); } if (PServerConnection != NULL) { PServerConnection->Set_Packet_Duplication(b); } //SimulatedPacketDuplicationPc = b; #ifdef WWDEBUG cDevOptions::SimulatedPacketDuplicationPc.Set(b); #endif } //----------------------------------------------------------------------------- void cNetwork::Set_Simulated_Latency_Range_Ms(int lower, int upper) { WWASSERT(lower >= 0); WWASSERT(upper >= 0); WWASSERT(lower <= upper); if (PClientConnection != NULL) { PClientConnection->Set_Packet_Latency_Range(lower, upper); } if (PServerConnection != NULL) { PServerConnection->Set_Packet_Latency_Range(lower, upper); } //SimulatedLatencyRangeMsLower = lower; //SimulatedLatencyRangeMsUpper = upper; #ifdef WWDEBUG cDevOptions::SimulatedLatencyRangeMsLower.Set(lower); cDevOptions::SimulatedLatencyRangeMsUpper.Set(upper); #endif } //----------------------------------------------------------------------------- void cNetwork::Set_Spam_Count(int spam_count) { WWASSERT(spam_count >= 0); //SpamCount = spam_count; #ifdef WWDEBUG cDevOptions::SpamCount.Set(spam_count); #endif } //----------------------------------------------------------------------------- void cNetwork::Get_Simulated_Latency_Range_Ms(int & lower, int & upper) { #ifdef WWDEBUG lower = cDevOptions::SimulatedLatencyRangeMsLower.Get(); upper = cDevOptions::SimulatedLatencyRangeMsUpper.Get(); #endif } //----------------------------------------------------------------------------- void cNetwork::Flush(void) { WWDEBUG_SAY(("cNetwork::Flush\n")); const bool is_urgent = true; //if (GameModeManager::Find ("Combat")->Is_Active() && Receiver != NULL) { if (Receiver != NULL) { if (I_Am_Server()) { Receiver->Server_Update_Dynamic_Objects(is_urgent); } if (I_Am_Client()) { Receiver->Client_Update_Dynamic_Objects(is_urgent); } } if (I_Am_Server()) { PServerConnection->Service_Send(is_urgent); } if (I_Am_Client()) { PClientConnection->Service_Send(is_urgent); } PacketManager.Flush(true); } void cNetwork::SwitchTeam(int newTeam) { cPlayer* player = cPlayerManager::Find_Player(Get_My_Id()); if (player) { int team = player->Get_Player_Type(); if (newTeam != team) { cChangeTeamEvent* event = new cChangeTeamEvent; event->Init(); } } } //----------------------------------------------------------------------------- void cNetwork::Enable_Waiting_Players(void) { SLNode * objnode; for (objnode = cPlayerManager::Get_Player_Object_List()->Head() ; objnode != NULL ; objnode = objnode->Next()) { cPlayer * p_player = objnode->Data(); WWASSERT(p_player != NULL); if (p_player->Is_Human() && p_player->Get_Is_Waiting_For_Intermission().Is_True()) { p_player->Set_Is_In_Game(true); p_player->Set_Is_Waiting_For_Intermission(false); if (cNetwork::PServerConnection) { cNetwork::PServerConnection->Set_Rhost_Is_In_Game(p_player->Get_Id(), true); } cGameDataUpdateEvent * p_event = new cGameDataUpdateEvent(); p_event->Init(p_player->Get_Id()); } } }