From dc493cca27cc0d214f4d3c4239081278d7ff2744 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:02:47 +0200 Subject: [PATCH 1/4] Minor clean up for the Generals code. --- Generals/Code/GameEngine/Source/GameClient/GameClient.cpp | 7 +++---- .../Code/GameEngine/Source/GameLogic/System/GameLogic.cpp | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index 9f7742976d4..ec9431607e6 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -433,7 +433,6 @@ void GameClient::init() /** Reset the game client for a new game */ void GameClient::reset() { - Drawable *draw, *nextDraw; m_drawableHash.clear(); #if USING_STLPORT m_drawableHash.resize(DRAWABLE_HASH_SIZE); @@ -445,7 +444,7 @@ void GameClient::reset() TheInGameUI->reset(); // destroy all Drawables - for( draw = m_drawableList; draw; draw = nextDraw ) + for( Drawable *draw = m_drawableList, *nextDraw = nullptr; draw; draw = nextDraw ) { nextDraw = draw->getNextDrawable(); destroyDrawable( draw ); @@ -860,7 +859,7 @@ void GameClient::addDrawableToLookupTable(Drawable *draw ) if( draw == nullptr ) return; - // add to lookup + // add to lookup table m_drawableHash[ draw->getID() ] = draw; } @@ -875,7 +874,7 @@ void GameClient::removeDrawableFromLookupTable( Drawable *draw ) if( draw == nullptr ) return; - // remove from table + // remove from lookup table m_drawableHash.erase( draw->getID() ); } diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 09048b600d6..68e5efad0fd 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -3444,7 +3444,7 @@ void GameLogic::addObjectToLookupTable( Object *obj ) if( obj == nullptr ) return; - // add to lookup + // add to lookup table m_objHash[ obj->getID() ] = obj; } From d72a2f8a6792d8f4b9e3c98634657200e30f1b18 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:09:42 +0200 Subject: [PATCH 2/4] Moved ZH GameClient::findDrawableByID from header to source file. --- .../Include/GameClient/GameClient.h | 24 ------------------- .../Source/GameClient/GameClient.cpp | 24 +++++++++++++++++++ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h index c4e6b7a7492..1b7802383ee 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h @@ -237,30 +237,6 @@ class GameClient : public SubsystemInterface, } \ } while (0); -/** ----------------------------------------------------------------------------------------------- - * Given an object id, return the associated object. - * This method is the primary interface for accessing objects, and should be used - * instead of pointers to "attach" objects to each other. - */ -inline Drawable* GameClient::findDrawableByID( const DrawableID id ) -{ - if( id == INVALID_DRAWABLE_ID ) - return nullptr; - -// DrawablePtrHashIt it = m_drawableHash.find(id); -// if (it == m_drawableHash.end()) { -// // no such drawable -// return nullptr; -// } -// -// return (*it).second; - - if( (size_t)id < m_drawableVector.size() ) - return m_drawableVector[(size_t)id]; - - return nullptr; -} - // the singleton extern GameClient *TheGameClient; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 983845c6e0d..08a17f6911b 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -849,6 +849,30 @@ void GameClient::updateFakeDrawables() } } +/** ----------------------------------------------------------------------------------------------- + * Given an object id, return the associated object. + * This method is the primary interface for accessing objects, and should be used + * instead of pointers to "attach" objects to each other. + */ +inline Drawable* GameClient::findDrawableByID( const DrawableID id ) +{ + if( id == INVALID_DRAWABLE_ID ) + return nullptr; + +// DrawablePtrHashIt it = m_drawableHash.find(id); +// if (it == m_drawableHash.end()) { +// // no such drawable +// return nullptr; +// } +// +// return (*it).second; + + if( (size_t)id < m_drawableVector.size() ) + return m_drawableVector[(size_t)id]; + + return nullptr; +} + /** ----------------------------------------------------------------------------------------------- * Destroy the drawable immediately. */ From 0405d026822e835df646e9f7bcd9ff6bebb5ef59 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:16:35 +0200 Subject: [PATCH 3/4] Refactored to hash table by porting GEN code to ZH. --- .../Include/GameClient/GameClient.h | 9 ++-- .../GameEngine/Include/GameLogic/GameLogic.h | 19 +++---- .../Source/GameClient/GameClient.cpp | 52 +++++++------------ .../Source/GameLogic/System/GameLogic.cpp | 25 ++++----- 4 files changed, 39 insertions(+), 66 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h index 1b7802383ee..bcc48e51b20 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h @@ -57,10 +57,8 @@ class SnowManager; /// Function pointers for use by GameClient callback functions. typedef void (*GameClientFuncPtr)( Drawable *draw, void *userData ); -//typedef std::hash_map, rts::equal_to > DrawablePtrHash; -//typedef DrawablePtrHash::iterator DrawablePtrHashIt; - -typedef std::vector DrawablePtrVector; +typedef std::hash_map, rts::equal_to/**/> DrawablePtrHash; +typedef DrawablePtrHash::iterator DrawablePtrHashIt; //----------------------------------------------------------------------------- /** The Client message dispatcher, this is the last "translator" on the message @@ -170,8 +168,7 @@ class GameClient : public SubsystemInterface, UnsignedInt m_frame; ///< Simulation frame number from server Drawable *m_drawableList; ///< All of the drawables in the world -// DrawablePtrHash m_drawableHash; ///< Used for DrawableID lookups - DrawablePtrVector m_drawableVector; + DrawablePtrHash m_drawableHash; ///< Used for DrawableID lookups DrawableID m_nextDrawableID; ///< For allocating drawable id's DrawableID allocDrawableID(); ///< Returns a new unique drawable id diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 15276811ccd..898f23b2cf8 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -78,8 +78,8 @@ enum /// Function pointers for use by GameLogic callback functions. typedef void (*GameLogicFuncPtr)( Object *obj, void *userData ); -//typedef std::hash_map, rts::equal_to > ObjectPtrHash; -//typedef ObjectPtrHash::const_iterator ObjectPtrIter; +typedef std::hash_map, rts::equal_to/**/> ObjectPtrHash; +typedef ObjectPtrHash::const_iterator ObjectPtrIter; typedef std::vector ObjectPtrVector; @@ -401,8 +401,7 @@ class GameLogic : public SubsystemInterface, public Snapshot WindowLayout *m_background; Object* m_objList; ///< All of the objects in the world. -// ObjectPtrHash m_objHash; ///< Used for ObjectID lookups - ObjectPtrVector m_objVector; + ObjectPtrHash m_objHash; ///< Used for ObjectID lookups // this is a vector, but is maintained as a priority queue. // never modify it directly; please use the proper access methods. @@ -503,15 +502,11 @@ inline Object* GameLogic::findObjectByID( ObjectID id ) if( id == INVALID_ID ) return nullptr; -// ObjectPtrHash::iterator it = m_objHash.find(id); -// if (it == m_objHash.end()) -// return nullptr; -// -// return (*it).second; - if( (size_t)id < m_objVector.size() ) - return m_objVector[(size_t)id]; + ObjectPtrHash::iterator it = m_objHash.find(id); + if (it == m_objHash.end()) + return nullptr; - return nullptr; + return (*it).second; } diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index 08a17f6911b..a33f7b07c6e 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -453,18 +453,18 @@ void GameClient::init() /** Reset the game client for a new game */ void GameClient::reset() { - Drawable *draw, *nextDraw; -// m_drawableHash.clear(); -// m_drawableHash.resize(DRAWABLE_HASH_SIZE); - - m_drawableVector.clear(); - m_drawableVector.resize(DRAWABLE_HASH_SIZE, nullptr); + m_drawableHash.clear(); +#if USING_STLPORT + m_drawableHash.resize(DRAWABLE_HASH_SIZE); +#else + m_drawableHash.reserve(DRAWABLE_HASH_SIZE); +#endif // need to reset the in game UI to clear drawables before they are destroyed TheInGameUI->reset(); // destroy all Drawables - for( draw = m_drawableList; draw; draw = nextDraw ) + for( Drawable *draw = m_drawableList, *nextDraw = nullptr; draw; draw = nextDraw ) { nextDraw = draw->getNextDrawable(); destroyDrawable( draw ); @@ -851,26 +851,19 @@ void GameClient::updateFakeDrawables() /** ----------------------------------------------------------------------------------------------- * Given an object id, return the associated object. + * For efficiency, a small Least Recently Used cache is incorporated. * This method is the primary interface for accessing objects, and should be used * instead of pointers to "attach" objects to each other. */ -inline Drawable* GameClient::findDrawableByID( const DrawableID id ) +Drawable* GameClient::findDrawableByID( const DrawableID id ) { - if( id == INVALID_DRAWABLE_ID ) + DrawablePtrHashIt it = m_drawableHash.find(id); + if (it == m_drawableHash.end()) { + // no such drawable return nullptr; + } -// DrawablePtrHashIt it = m_drawableHash.find(id); -// if (it == m_drawableHash.end()) { -// // no such drawable -// return nullptr; -// } -// -// return (*it).second; - - if( (size_t)id < m_drawableVector.size() ) - return m_drawableVector[(size_t)id]; - - return nullptr; + return (*it).second; } /** ----------------------------------------------------------------------------------------------- @@ -917,13 +910,8 @@ void GameClient::addDrawableToLookupTable(Drawable *draw ) if( draw == nullptr ) return; - // add to lookup -// m_drawableHash[ draw->getID() ] = draw; - DrawableID newID = draw->getID(); - while( newID >= m_drawableVector.size() ) // Fail case is hella rare, so faster to double up on size() call - m_drawableVector.resize(m_drawableVector.size() * 2, nullptr); - - m_drawableVector[ newID ] = draw; + // add to lookup table + m_drawableHash[ draw->getID() ] = draw; } @@ -934,13 +922,11 @@ void GameClient::removeDrawableFromLookupTable( Drawable *draw ) { // sanity - // TheSuperHackers @fix Mauller/Xezon 24/04/2025 Prevent out of range access to vector lookup table - if( draw == nullptr || static_cast(draw->getID()) >= m_drawableVector.size() ) + if( draw == nullptr ) return; - // remove from table -// m_drawableHash.erase( draw->getID() ); - m_drawableVector[ draw->getID() ] = nullptr; + // remove from lookup table + m_drawableHash.erase( draw->getID() ); } diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 0d8d4e64692..e9c5b1b9bab 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -311,8 +311,7 @@ void GameLogic::destroyAllObjectsImmediate() processDestroyList(); DEBUG_ASSERTCRASH( m_objList == nullptr, ("destroyAllObjectsImmediate: Object list not cleared") ); -// m_objHash.clear(); - m_objVector.clear(); + m_objHash.clear(); } @@ -422,8 +421,11 @@ void GameLogic::reset() destroyAllObjectsImmediate(); // set the hash to be rather large. We need to optimize this value later. -// m_objHash.resize(OBJ_HASH_SIZE); - m_objVector.resize(OBJ_HASH_SIZE, nullptr); +#if USING_STLPORT + m_objHash.resize(OBJ_HASH_SIZE); +#else + m_objHash.reserve(OBJ_HASH_SIZE); +#endif m_nextObjID = (ObjectID)1; @@ -3977,13 +3979,8 @@ void GameLogic::addObjectToLookupTable( Object *obj ) if( obj == nullptr ) return; - // add to lookup -// m_objHash[ obj->getID() ] = obj; - ObjectID newID = obj->getID(); - while( newID >= m_objVector.size() ) // Fail case is hella rare, so faster to double up on size() call - m_objVector.resize(m_objVector.size() * 2, nullptr); - - m_objVector[ newID ] = obj; + // add to lookup table + m_objHash[ obj->getID() ] = obj; } @@ -3994,13 +3991,11 @@ void GameLogic::removeObjectFromLookupTable( Object *obj ) { // sanity - // TheSuperHackers @fix Mauller/Xezon 24/04/2025 Prevent out of range access to vector lookup table - if( obj == nullptr || static_cast(obj->getID()) >= m_objVector.size() ) + if( obj == nullptr ) return; // remove from lookup table -// m_objHash.erase( obj->getID() ); - m_objVector[ obj->getID() ] = nullptr; + m_objHash.erase( obj->getID() ); } From 2fdfcbd5e1b89c781a1959ebee6d676ca864b9e0 Mon Sep 17 00:00:00 2001 From: Caball009 <82909616+Caball009@users.noreply.github.com> Date: Mon, 12 Oct 2026 21:39:11 +0200 Subject: [PATCH 4/4] Addressed feedback. --- Generals/Code/GameEngine/Source/GameClient/GameClient.cpp | 1 - GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp | 1 - 2 files changed, 2 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp index ec9431607e6..214fc9f7263 100644 --- a/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -800,7 +800,6 @@ void GameClient::updateFakeDrawables() /** ----------------------------------------------------------------------------------------------- * Given an object id, return the associated object. - * For efficiency, a small Least Recently Used cache is incorporated. * This method is the primary interface for accessing objects, and should be used * instead of pointers to "attach" objects to each other. */ diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp index a33f7b07c6e..9b6f5ebe70c 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp @@ -851,7 +851,6 @@ void GameClient::updateFakeDrawables() /** ----------------------------------------------------------------------------------------------- * Given an object id, return the associated object. - * For efficiency, a small Least Recently Used cache is incorporated. * This method is the primary interface for accessing objects, and should be used * instead of pointers to "attach" objects to each other. */