276 lines
8.3 KiB
C++
276 lines
8.3 KiB
C++
|
/*
|
||
|
** 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 <http://www.gnu.org/licenses/>.
|
||
|
*/
|
||
|
|
||
|
/***********************************************************************************************
|
||
|
*** Confidential - Westwood Studios ***
|
||
|
***********************************************************************************************
|
||
|
* *
|
||
|
* Project Name : Commando *
|
||
|
* *
|
||
|
* $Archive:: /Commando/Code/Commando/comnetrcvinst.cpp $*
|
||
|
* *
|
||
|
* $Author:: Steve_t $*
|
||
|
* *
|
||
|
* $Modtime:: 2/22/02 7:00p $*
|
||
|
* *
|
||
|
* $Revision:: 118 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "comnetrcvinst.h"
|
||
|
|
||
|
#include "gameobjmanager.h"
|
||
|
#include "playermanager.h"
|
||
|
#include "cnetwork.h"
|
||
|
#include "WWAudio.H"
|
||
|
#include "ccamera.h"
|
||
|
#include "gametype.h"
|
||
|
#include "textdisplay.h"
|
||
|
#include "wwprofile.h"
|
||
|
#include "serverfps.h"
|
||
|
#include "useroptions.h"
|
||
|
#include "serversettings.h"
|
||
|
#include "consolemode.h"
|
||
|
#include "demosupport.h"
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CombatNetworkReceiverInstanceClass::Print( const char *format, ... )
|
||
|
{
|
||
|
va_list arg_list;
|
||
|
va_start (arg_list, format);
|
||
|
StringClass string;
|
||
|
string.Format_Args( format, arg_list );
|
||
|
|
||
|
ConsoleBox.Print_Maybe(string);
|
||
|
if (!ConsoleBox.Is_Exclusive()) {
|
||
|
WWASSERT( Get_Text_Display() );
|
||
|
Get_Text_Display()->Print_System( string );
|
||
|
}
|
||
|
va_end (arg_list);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CombatNetworkReceiverInstanceClass::Print( const Vector3 & color, const char *format, ... )
|
||
|
{
|
||
|
WWASSERT( Get_Text_Display() );
|
||
|
va_list arg_list;
|
||
|
va_start (arg_list, format);
|
||
|
StringClass string;
|
||
|
string.Format_Args( format, arg_list );
|
||
|
WideStringClass ws(string, true);
|
||
|
ConsoleBox.Add_Message(&ws, (Vector3*)&color);
|
||
|
if (!ConsoleBox.Is_Exclusive()) {
|
||
|
WWASSERT( Get_Text_Display() );
|
||
|
Get_Text_Display()->Print( string, color );
|
||
|
}
|
||
|
va_end (arg_list);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
void CombatNetworkReceiverInstanceClass::Server_Send_Delete_Notifications(void)
|
||
|
{
|
||
|
WWASSERT(cNetwork::I_Am_Server());
|
||
|
|
||
|
if (IS_SOLOPLAY) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Figure out what data to send to each player (client)
|
||
|
//
|
||
|
for (
|
||
|
SLNode<cPlayer> * player_node = cPlayerManager::Get_Player_Object_List()->Head();
|
||
|
player_node;
|
||
|
player_node = player_node->Next()) {
|
||
|
|
||
|
cPlayer * p_player = player_node->Data();
|
||
|
WWASSERT(p_player != NULL);
|
||
|
|
||
|
int client_id = p_player->Get_Id();
|
||
|
|
||
|
if (client_id < 0) {
|
||
|
//
|
||
|
// AI... no sends
|
||
|
//
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (p_player->Get_Is_Active().Is_False()) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (p_player->Get_Is_In_Game().Is_False()) {
|
||
|
//
|
||
|
// Loading... delay send
|
||
|
//
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
cNetwork::Tell_Client_About_Delete_Notifications(client_id);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CombatNetworkReceiverInstanceClass::Server_Update_Dynamic_Objects(bool is_urgent)
|
||
|
{
|
||
|
WWASSERT(cNetwork::I_Am_Server());
|
||
|
|
||
|
if (IS_SOLOPLAY) {
|
||
|
return(false);
|
||
|
}
|
||
|
|
||
|
DEMO_SECURITY_CHECK;
|
||
|
|
||
|
//
|
||
|
// Limit the maximum rate at which the server sends updates.
|
||
|
// This code will result in updates at a little less than NetUpdateRate.
|
||
|
// This saves bandwidth at the cost of added latency.
|
||
|
//
|
||
|
static DWORD last_update_time = 0;
|
||
|
DWORD time_now = TIMEGETTIME();
|
||
|
if (!is_urgent && (time_now - last_update_time < 1000 / (float) cUserOptions::NetUpdateRate.Get())) {
|
||
|
return(false);
|
||
|
}
|
||
|
last_update_time = time_now;
|
||
|
|
||
|
//
|
||
|
// cRemoteHost figures out when to update priorities based on this so keep it in sync with the NetUpdateRate.
|
||
|
//
|
||
|
cRemoteHost::Set_Priority_Update_Rate(cUserOptions::NetUpdateRate.Get());
|
||
|
|
||
|
//
|
||
|
// TSS - bug
|
||
|
// Must handle sniper... also, should use camera position
|
||
|
// rather than commando position
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// Figure out what data to send to each player (client)
|
||
|
//
|
||
|
for (
|
||
|
SLNode<cPlayer> * player_node = cPlayerManager::Get_Player_Object_List()->Head();
|
||
|
player_node;
|
||
|
player_node = player_node->Next()) {
|
||
|
|
||
|
cPlayer * p_player = player_node->Data();
|
||
|
WWASSERT(p_player != NULL);
|
||
|
|
||
|
int client_id = p_player->Get_Id();
|
||
|
|
||
|
if (client_id < 0) {
|
||
|
//
|
||
|
// AI... no sends
|
||
|
//
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (p_player->Get_Is_Active().Is_False()) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
if (!is_urgent && p_player->Get_Is_In_Game().Is_False()) {
|
||
|
//
|
||
|
// Loading... delay sends
|
||
|
//
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
//is_urgent = true;//XXX
|
||
|
|
||
|
if (!is_urgent) {
|
||
|
//
|
||
|
// Do not send to the client at a rate much higher than his framerate
|
||
|
// This code will only impact if his framerate is below NetUpdateRate.
|
||
|
// This code should help prevent players whose framerate bogs from
|
||
|
// getting packet-swamped.
|
||
|
//
|
||
|
int min_delay_ms = 0;
|
||
|
if (p_player->Get_Fps() > 0) {
|
||
|
const float arbitrary_scale_factor = 1.0;
|
||
|
min_delay_ms = (int)(arbitrary_scale_factor * 1000 / (float) p_player->Get_Fps());
|
||
|
}
|
||
|
int time_elapsed_ms = time_now - p_player->Get_Last_Update_Time_Ms();
|
||
|
if (time_elapsed_ms < min_delay_ms) {
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
p_player->Set_Last_Update_Time_Ms(time_now);
|
||
|
|
||
|
SmartGameObj * p_soldier = GameObjManager::Find_Soldier_Of_Client_ID(client_id);
|
||
|
|
||
|
Vector3 dest_pos;
|
||
|
if (p_soldier == NULL) {
|
||
|
//
|
||
|
// Act like the guy is far, far away.
|
||
|
// He'll only receive priority 1 messages.
|
||
|
//
|
||
|
dest_pos.Set(Vector3(0, 0, -10000));
|
||
|
} else {
|
||
|
p_soldier->Get_Position(&dest_pos);
|
||
|
|
||
|
//
|
||
|
// His eyes are say 1.5 m above his feet
|
||
|
//
|
||
|
dest_pos.Z += 1.5;
|
||
|
}
|
||
|
|
||
|
cNetwork::Tell_Client_About_Dynamic_Objects(client_id, dest_pos);
|
||
|
}
|
||
|
return(true);
|
||
|
}
|
||
|
|
||
|
//-----------------------------------------------------------------------------
|
||
|
bool CombatNetworkReceiverInstanceClass::Client_Update_Dynamic_Objects(bool is_urgent)
|
||
|
{
|
||
|
//
|
||
|
// TSS092001
|
||
|
// Do not send updates to the server at a rate higher than NetUpdateRate.
|
||
|
// If the server framerate is below this, match the client send rate to it.
|
||
|
//
|
||
|
|
||
|
/*TSS092101*/
|
||
|
WWASSERT(cNetwork::I_Am_Client());
|
||
|
|
||
|
static DWORD last_update_time_ms = 0;
|
||
|
DWORD time_now_ms = TIMEGETTIME();
|
||
|
DWORD time_elapsed_ms = time_now_ms - last_update_time_ms;
|
||
|
|
||
|
int max_updates_per_second = cUserOptions::NetUpdateRate.Get();
|
||
|
WWASSERT(cServerFps::Get_Instance() != NULL);
|
||
|
int server_fps = cServerFps::Get_Instance()->Get_Fps();
|
||
|
if (server_fps > 0 && server_fps < cUserOptions::NetUpdateRate.Get()) {
|
||
|
max_updates_per_second = server_fps;
|
||
|
}
|
||
|
|
||
|
DWORD min_delay_ms = (DWORD)(1000 / (float) max_updates_per_second);
|
||
|
|
||
|
//is_urgent = true;//XXX
|
||
|
|
||
|
if (is_urgent || (time_elapsed_ms >= min_delay_ms)) {
|
||
|
last_update_time_ms = time_now_ms;
|
||
|
cNetwork::Tell_Server_About_Dynamic_Objects();
|
||
|
return(true);
|
||
|
}
|
||
|
return(false);
|
||
|
/**/
|
||
|
}
|