| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661 |
- /*
- ** 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/wwnet/networkobject.cpp $*
- * *
- * $Author:: Tom_s $*
- * *
- * $Modtime:: 1/07/02 5:16p $*
- * *
- * $Revision:: 28 $*
- * *
- *---------------------------------------------------------------------------------------------*
- * Functions: *
- * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
- #include "networkobject.h"
- #include "networkobjectmgr.h"
- #include "wwmath.h"
- #include "vector3.h"
- #include "wwprofile.h"
- #include "systimer.h"
- #define CLIENT_SIDE_UPDATE_FREQUENCY_SAMPLE_PERIOD (1000 * 10)
- ////////////////////////////////////////////////////////////////
- // Static member initializtaion
- ////////////////////////////////////////////////////////////////
- bool NetworkObjectClass::IsServer = false;
- ////////////////////////////////////////////////////////////////
- //
- // NetworkObjectClass
- //
- ////////////////////////////////////////////////////////////////
- NetworkObjectClass::NetworkObjectClass (void) :
- ImportStateCount (0),
- LastClientsideUpdateTime (0),
- NetworkID (0),
- IsDeletePending (false),
- CachedPriority (0),
- UnreliableOverride (false),
- AppPacketType (0),
- FrequentExportPacketSize(0),
- ClientsideUpdateFrequencySampleStartTime(TIMEGETTIME()),
- ClientsideUpdateFrequencySampleCount(0),
- ClientsideUpdateRate(0),
- #ifdef WWDEBUG
- CreatedByPacketID(0),
- #endif //WWDEBUG
- LastObjectIdIDamaged(-1),
- LastObjectIdIGotDamagedBy(-1)
- {
- if (IsServer)
- {
- //
- // Assign the object a unique ID. This will happen on the client too during object
- // imports, but will be corrected immediately with an explicit Set_Network_ID call.
- //
- int new_id = NetworkObjectMgrClass::Get_New_Dynamic_ID();
- //WWDEBUG_SAY(("New network id = %d\n", new_id));//TSS2001
- Set_Network_ID(new_id);
- }
- //
- // By default, objects have the modifiction dirty bit set.
- // Static objects therefore don't need to remember to set this in their constructor.
- // Game objects will set BIT_CREATION.
- //
- Clear_Object_Dirty_Bits ();
- memset(CachedPriority_2, 0, sizeof(CachedPriority_2));
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // ~NetworkObjectClass
- //
- ////////////////////////////////////////////////////////////////
- NetworkObjectClass::~NetworkObjectClass (void)
- {
- //
- // Unregister this object from network updates
- //
- NetworkObjectMgrClass::Unregister_Object (this);
- return ;
- }
- extern bool SensibleUpdates;
- ////////////////////////////////////////////////////////////////
- //
- // Set_Network_ID
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Network_ID (int id)
- {
- WWASSERT(id > 0);
- //
- // Remove the object from the manager, change it's ID,
- // and re-insert it.
- //
- NetworkObjectMgrClass::Unregister_Object (this);
- NetworkID = id;
- NetworkObjectMgrClass::Register_Object (this);
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Object_Dirty_Bits
- //
- ////////////////////////////////////////////////////////////////
- BYTE
- NetworkObjectClass::Get_Object_Dirty_Bits (int client_id)
- {
- return ClientStatus[client_id];
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Object_Dirty_Bits
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Object_Dirty_Bits (int client_id, BYTE bits)
- {
- ClientStatus[client_id] = bits;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Object_Dirty_Bit
- //
- ////////////////////////////////////////////////////////////////
- bool
- NetworkObjectClass::Get_Object_Dirty_Bit (int client_id, DIRTY_BIT dirty_bit)
- {
- return ((ClientStatus[client_id] & dirty_bit) == dirty_bit);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Clear_Object_Dirty_Bits
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Clear_Object_Dirty_Bits (void)
- {
- //
- // Reset the status for each client
- //
- for (int index = 0; index < MAX_CLIENT_COUNT; index ++) {
- ClientStatus[index] = 0;
- UpdateInfo[index].LastUpdateTime = 0;
- UpdateInfo[index].UpdateRate = 50;
- UpdateInfo[index].ClientHintCount = 0;
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Object_Dirty_Bit
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Object_Dirty_Bit (int client_id, DIRTY_BIT dirty_bit, bool onoff)
- {
- if (onoff) {
- ClientStatus[client_id] |= dirty_bit;
- } else {
- ClientStatus[client_id] &= (~dirty_bit);
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Object_Dirty_Bit
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Object_Dirty_Bit (DIRTY_BIT dirty_bit, bool onoff)
- {
- if (!IsServer)
- {
- return;
- }
- //
- // Change the status for each client
- // N.B. Client 0 is actually the server.
- //
- for (int index = 1; index < MAX_CLIENT_COUNT; index ++) {//TSS2001
- if (onoff) {
- ClientStatus[index] |= dirty_bit;
- } else {
- ClientStatus[index] &= (~dirty_bit);
- }
- }
- return ;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Is_Client_Dirty
- //
- ////////////////////////////////////////////////////////////////
- bool
- NetworkObjectClass::Is_Client_Dirty (int client_id)
- {
- return ClientStatus[client_id] != 0;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Delete_Pending
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Delete_Pending (void)
- {
- IsDeletePending = true;
- NetworkObjectMgrClass::Register_Object_For_Deletion (this);
- return;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Reset_Client_Hint_Count
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Reset_Client_Hint_Count(int client_id)
- {
- WWASSERT(client_id >= 0 && client_id < MAX_CLIENT_COUNT);
- UpdateInfo[client_id].ClientHintCount = 0;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Increment_Client_Hint_Count
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Increment_Client_Hint_Count(int client_id)
- {
- WWASSERT(client_id >= 0 && client_id < MAX_CLIENT_COUNT);
- if (UpdateInfo[client_id].ClientHintCount < 255) {
- UpdateInfo[client_id].ClientHintCount++;
- }
- }
- ////////////////////////////////////////////////////////////////
- //
- // Hint_To_All_Clients
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Hint_To_All_Clients(void)
- {
- //
- // Hint that an update should be sent to all clients
- //
- for (int index = 0; index < MAX_CLIENT_COUNT; index ++) {
- Increment_Client_Hint_Count(index);
- }
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Client_Hint_Count
- //
- ////////////////////////////////////////////////////////////////
- BYTE
- NetworkObjectClass::Get_Client_Hint_Count(int client_id)
- {
- WWASSERT(client_id >= 0 && client_id < MAX_CLIENT_COUNT);
- return UpdateInfo[client_id].ClientHintCount;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Belongs_To_Client
- //
- ////////////////////////////////////////////////////////////////
- bool
- NetworkObjectClass::Belongs_To_Client (int client_id)
- {
- WWASSERT(client_id > 0);
- int id_min = NETID_CLIENT_OBJECT_MIN + (client_id - 1) * 100000;
- int id_max = id_min + 100000 - 1;
- return (NetworkID >= id_min) && (NetworkID <= id_max);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Last_Update_Time - Returns time that the client last received an update for this object.
- //
- // In: ID of client
- // Out: Last update time.
- //
- // 10/16/2001 2:45PM ST
- ////////////////////////////////////////////////////////////////
- unsigned long
- NetworkObjectClass::Get_Last_Update_Time(int client_id)
- {
- // Is this assert right? ST - 10/16/2001 2:44PM
- WWASSERT(client_id > 0 && client_id <= MAX_CLIENT_COUNT);
- return(UpdateInfo[client_id].LastUpdateTime);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Get_Update_Rate - Returns delay in ms between updates for this object to the given client
- //
- // In: ID of client
- // Out: Update delay in ms
- //
- // 10/16/2001 2:45PM ST
- ////////////////////////////////////////////////////////////////
- unsigned short
- NetworkObjectClass::Get_Update_Rate(int client_id)
- {
- // Is this assert right? ST - 10/16/2001 2:44PM
- WWASSERT(client_id > 0 && client_id <= MAX_CLIENT_COUNT);
- return(UpdateInfo[client_id].UpdateRate);
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Last_Update_Time - Sets time that the client last received an update for this object.
- //
- // In: ID of client, time this object was sent to the client.
- // Out: Nothing
- //
- // 10/16/2001 2:45PM ST
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Last_Update_Time(int client_id, unsigned long time)
- {
- // Is this assert right? ST - 10/16/2001 2:44PM
- WWASSERT(client_id > 0 && client_id <= MAX_CLIENT_COUNT);
- UpdateInfo[client_id].LastUpdateTime = time;
- }
- ////////////////////////////////////////////////////////////////
- //
- // Set_Update_Rate - Sets the ms delay between updates for this client
- //
- // In: ID of client, delay in ms between updates
- // Out: Nothing
- //
- // 10/16/2001 2:45PM ST
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Update_Rate(int client_id, unsigned short rate)
- {
- // Is this assert right? ST - 10/16/2001 2:44PM
- WWASSERT(client_id > 0 && client_id <= MAX_CLIENT_COUNT);
- UpdateInfo[client_id].UpdateRate = rate;
- }
- /*
- ////////////////////////////////////////////////////////////////
- //
- // Clear_Object_Dirty_Bits
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Clear_Object_Dirty_Bits (int client_id)
- {
- ClientStatus[client_id] = 0;
- return ;
- }
- */
- //float NetworkObjectClass::RandomFloat = 0.0F;
- //TSS2001d float perturbation = RandomFloat * 2 * distance - distance;
- /*
- ////////////////////////////////////////////////////////////////
- //
- // Set_Random_Float
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Random_Float (float random_float)
- {
- WWASSERT(random_float >= 0 && random_float <= 1);
- RandomFloat = random_float;
- }
- */
- //Set_Object_Dirty_Bit (BIT_RARE, true);
- //float NetworkObjectClass::MaxDistance = 300.0F;
- ////////////////////////////////////////////////////////////////
- //
- // Compute_Object_Priority
- //
- ////////////////////////////////////////////////////////////////
- /*
- float
- NetworkObjectClass::Compute_Object_Priority (int client_id, const Vector3 &client_pos)
- {
- //
- // Priority depends on physical distance. Objects with no physical location will
- // have a priority of 1.
- //
- CachedPriority = 0;
- if (Is_Client_Dirty(client_id)) {
- float distance = Get_Object_Distance (client_pos);
- if (distance < MaxDistance)
- {
- //
- // This object is visible to this client.
- // Add a random perturbation in the range [-distance, distance].
- //
- float rand_float = ::rand() / (float) RAND_MAX;
- float perturbation = rand_float * 2 * distance - distance;
- distance += perturbation;
- }
- //
- // Priority simply decreases linearly with distance and is zero at MaxDistance.
- //
- CachedPriority = 1 - distance / MaxDistance;
- CachedPriority = WWMath::Clamp (CachedPriority, 0.0F, 1.0F);
- }
- return CachedPriority;
- }
- */
- /*
- float
- NetworkObjectClass::Compute_Object_Priority (int client_id, const Vector3 &client_pos)
- {
- //
- // Compute the priority of this object to the given client at his given position.
- // Priority depends on physical distance. Objects with no physical location will
- // have a priority of 1.
- //
- CachedPriority = 0;
- if (Is_Client_Dirty(client_id)) {
- float distance = Get_Object_Distance (client_pos);
- //
- // Priority simply decreases linearly with distance and is zero at MaxDistance.
- //
- CachedPriority = 1 - distance / MaxDistance;
- CachedPriority = WWMath::Clamp (CachedPriority, 0.0F, 1.0F);
- }
- return CachedPriority;
- }
- */
- ////////////////////////////////////////////////////////////////
- //
- // Set_Cached_Priority
- //
- ////////////////////////////////////////////////////////////////
- void
- NetworkObjectClass::Set_Cached_Priority (float priority)
- {
- WWASSERT(priority >= 0 && priority <= 1);
- CachedPriority = priority;
- }
- /*
- ////////////////////////////////////////////////////////////////
- //
- // Get_Object_Distance
- //
- ////////////////////////////////////////////////////////////////
- float
- NetworkObjectClass::Get_Object_Distance (const Vector3 &client_pos)
- {
- //
- // Objects without a physical location will return a distance of zero.
- //
- float distance = 0;
- //
- // Get the object's world position (if it has one)
- //
- Vector3 position;
- if (Get_World_Position (position)) {
- //
- // Simple distance calculation based on the distance
- // between points.
- //
- distance = (position - client_pos).Length ();
- }
- return distance;
- }
- */
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Reset_Last_Clientside_Update_Time -- Reset the time this client object last got an update for the server
- //
- // In: Nothing.
- // Out: Nothing
- //
- // 10/19/2001 12:19PM ST
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void NetworkObjectClass::Reset_Last_Clientside_Update_Time(void)
- {
- LastClientsideUpdateTime = 0;
- ClientsideUpdateFrequencySampleStartTime = TIMEGETTIME();
- ClientsideUpdateFrequencySampleCount = 0;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Set_Last_Clientside_Update_Time -- Set the time this client object last got an update for the server
- //
- // In: Nothing.
- // Out: Nothing
- //
- // 10/19/2001 12:19PM ST
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- void NetworkObjectClass::Set_Last_Clientside_Update_Time (ULONG time)
- {
- LastClientsideUpdateTime = time;
- ClientsideUpdateFrequencySampleCount++;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- // Get_Clientside_Update_Frequency -- Get the updates rate from the server in ms
- //
- // In: Nothing.
- // Out: Average time between updates from the server in ms
- //
- // 10/19/2001 12:19PM ST
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////
- int NetworkObjectClass::Get_Clientside_Update_Frequency(void)
- {
- unsigned long time = TIMEGETTIME();
- if (time - ClientsideUpdateFrequencySampleStartTime > CLIENT_SIDE_UPDATE_FREQUENCY_SAMPLE_PERIOD) {
- // Say 10 seconds if we don't know.
- int rate = 10000;
- if (ClientsideUpdateFrequencySampleCount) {
- rate = (time - ClientsideUpdateFrequencySampleStartTime) / ClientsideUpdateFrequencySampleCount;
- ClientsideUpdateFrequencySampleStartTime = time;
- ClientsideUpdateFrequencySampleCount = 0;
- }
- ClientsideUpdateRate = rate;
- }
- return(ClientsideUpdateRate);
- }
- #ifdef WWDEBUG
- void NetworkObjectClass::Set_Created_By_Packet_ID (int id)
- {
- CreatedByPacketID = id;
- }
- #endif //WWDEBUG
|