| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- /*
- ** 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/clienthintmanager.cpp $*
- * *
- * $Author:: Steve_t $*
- * *
- * $Modtime:: 12/09/01 6:40p $*
- * *
- * $Revision:: 6 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "clienthintmanager.h"
- #include "cshint.h"
- #include "cnetwork.h"
- #include "combat.h"
- #include "gameobjmanager.h"
- #include "pscene.h"
- #include "apppackettypes.h"
- #include "vistable.h"
- #include "useroptions.h"
- #include "priority.h"
- #include "apppacketstats.h"
- //
- // Class statics
- //
- //-----------------------------------------------------------------------------
- void
- cClientHintManager::Think
- (
- void
- )
- {
- if (cNetwork::I_Am_Server() ||
- COMBAT_SCENE == NULL ||
- cUserOptions::ClientHintFactor.Get() < 1)
- {
- //
- // Bail:
- // Only dedicated clients send hints.
- // Also, ClientHintFactor is disabled by using any value < 1.
- //
- return;
- }
- WWASSERT(cNetwork::I_Am_Only_Client());
- SoldierGameObj * p_my_soldier = GameObjManager::Find_Soldier_Of_Client_ID(cNetwork::Get_My_Id());
- if (p_my_soldier == NULL)
- {
- //
- // Bail...
- //
- return;
- }
- //
- // Do not allow hints to go out at too high a frequency.
- //
- static DWORD last_hint_time_ms = 0;
- DWORD time_now_ms = TIMEGETTIME();
- const DWORD MIN_HINT_DELAY_MS = 1000;
- if (time_now_ms - last_hint_time_ms < MIN_HINT_DELAY_MS)
- {
- //
- // Bail...
- //
- return;
- }
- //
- // Examine all the vis-visible soldiers and vehicles. If we find one that hasn't been
- // updated for a suspiciously long time, send a hint to the server, He'll follow
- // up with an update.
- //
- Vector3 my_position;
- p_my_soldier->Get_Position(&my_position);
- my_position.Z += 1.5;
- VisTableClass * pvs = COMBAT_SCENE->Get_Vis_Table(my_position);
- int num_objects = 0;
- //ULONG total_delay_ms = 0;
- //ULONG maximum_delay_ms = 0;
- //int longest_delayed_index = -1;
- int count = NetworkObjectMgrClass::Get_Object_Count();
- NetworkObjectClass **object_list = (NetworkObjectClass **) _alloca((count * sizeof(NetworkObjectClass*)) + 128);
- WWASSERT(object_list != NULL);
- SmartGameObj * player_ptr = GameObjManager::Find_Soldier_Of_Client_ID(cNetwork::Get_My_Id());
- WWASSERT(player_ptr != NULL);
- //
- // Traverse the vehicles and soldiers and gather data about update rates.
- //
- for (int index = 0; index < count; index ++)
- {
- NetworkObjectClass * p_object = NetworkObjectMgrClass::Get_Object(index);
- WWASSERT(p_object != NULL);
- BYTE type = p_object->Get_App_Packet_Type();
- if (type == APPPACKETTYPE_SOLDIER || type == APPPACKETTYPE_VEHICLE)
- {
- if (p_object->Get_Clientside_Update_Frequency()) {
- int vis_id = p_object->Get_Vis_ID();
- //
- // If there is no vis data, proceed.
- // If vis data does exist then only proceed with this object if it is vis-visible.
- //
- if (pvs == NULL || vis_id == -1 || pvs->Get_Bit(vis_id))
- {
- // Just add the object to the list on this pass.
- object_list[num_objects++] = p_object;
- // Work out the priority of this object from the clients perspective.
- if (player_ptr) {
- Vector3 position;
- player_ptr->Get_Position(&position);
- float priority = cPriority::Compute_Object_Priority(cNetwork::Get_My_Id(), position, p_object, true);
- p_object->Set_Cached_Priority(priority);
- }
- #if (0)
- ULONG delay_ms = time_now_ms - p_object->Get_Last_Clientside_Update_Time();
- total_delay_ms += delay_ms;
- num_objects++;
- if (delay_ms > maximum_delay_ms)
- {
- maximum_delay_ms = delay_ms;
- longest_delayed_index = index;
- }
- #endif //(0)
- }
- }
- }
- }
- if (num_objects < 2) {
- return;
- }
- //
- // Sort the object list. Lowest priority first.
- //
- qsort(object_list, num_objects, sizeof(unsigned long), (int (__cdecl *)(const void *,const void *)) &Priority_Compare);
- //
- // Look for an object that has a higher priority than it's neighbor but is getting updated much less frequently
- //
- // Ignore the worst priority object. This might have to change....?
- //
- int most_broken_object_index = -1;
- int worst_percentage = 0;
- unsigned long time = TIMEGETTIME();
- for (int i=1 ; i<num_objects ; i++) {
- int higher_priority_rate = object_list[i]->Get_Clientside_Update_Frequency();
- //
- // Don't hint for objects with a recent updates. This should prevent us from hinting about objects we just hinted about.
- //
- if (time - object_list[i]->Get_Last_Clientside_Update_Time() > 1500) {
- int lower_priority_rate = object_list[i-1]->Get_Clientside_Update_Frequency();
- if (lower_priority_rate && higher_priority_rate) {
- // Lower priority rate should be higher in terms of milliseconds.
- if (lower_priority_rate < higher_priority_rate) {
- // The higher priority object is being updated by the server less frequently. That doesn't seem right.
- int percentage = (higher_priority_rate * 100) / lower_priority_rate;
- if (percentage > worst_percentage) {
- worst_percentage = percentage;
- most_broken_object_index = i;
- }
- }
- }
- }
- }
- //
- // Calculate the average delay for this set of soldiers and vehicles
- //
- //float average_delay_ms = 0;
- //if (num_objects > 0)
- //{
- // average_delay_ms = total_delay_ms / (float) num_objects;
- //}
- //
- // If the most OOD object is much more OOD than the average object, then request an update.
- //
- //if ((longest_delayed_index != -1) &&
- // (maximum_delay_ms > cUserOptions::ClientHintFactor.Get() * average_delay_ms))
- //{
- float hint_factor = cUserOptions::ClientHintFactor.Get();
- if (most_broken_object_index != -1 && worst_percentage > 100 + (10.0f * hint_factor)) {
- //NetworkObjectClass * p_object = NetworkObjectMgrClass::Get_Object(longest_delayed_index);
- NetworkObjectClass * p_object = object_list[most_broken_object_index];
- WWASSERT(p_object != NULL);
- cCsHint * p_hint = new cCsHint;
- p_hint->Init(p_object->Get_Network_ID());
- last_hint_time_ms = time_now_ms;
- //WWDEBUG_SAY(("cClientHintManager::Think, requesting hint for object id %d, avg = %5.2f, max = %d\n",
- // p_object->Get_Network_ID(), average_delay_ms, maximum_delay_ms));
- WWDEBUG_SAY(("cClientHintManager::Think, requesting hint for object id %d (%s), priority = %5.2f, ave update rate = %dms\n",
- p_object->Get_Network_ID(),
- cAppPacketStats::Interpret_Type(p_object->Get_App_Packet_Type()),
- p_object->Get_Cached_Priority(),
- p_object->Get_Clientside_Update_Frequency()));
- WWDEBUG_SAY((" Compared to object id %d with priority %5.2f, avg update rate %dms\n",
- object_list[most_broken_object_index-1]->Get_Network_ID(),
- object_list[most_broken_object_index-1]->Get_Cached_Priority(),
- object_list[most_broken_object_index-1]->Get_Clientside_Update_Frequency()));
- WWDEBUG_SAY((" Client hint factor = %5.2f\n", hint_factor));
- }
- }
- //
- // Qsort compare function for array of object pointers.
- //
- int __cdecl cClientHintManager::Priority_Compare(const void **object1, const void **object2)
- {
- WWASSERT(object1 != NULL);
- WWASSERT(object2 != NULL);
- NetworkObjectClass *n1 = (NetworkObjectClass*) *object1;
- NetworkObjectClass *n2 = (NetworkObjectClass*) *object2;
- float p1 = n1->Get_Cached_Priority();
- float p2 = n2->Get_Cached_Priority();
- if (p1 == p2) {
- return(0);
- }
- if (p1 < p2) {
- return(-1);
- }
- return(1);
- }
|