diff --git a/Core/GameEngine/Include/GameNetwork/NetCommandMsg.h b/Core/GameEngine/Include/GameNetwork/NetCommandMsg.h index caf2302bc9b..611d9b5287a 100644 --- a/Core/GameEngine/Include/GameNetwork/NetCommandMsg.h +++ b/Core/GameEngine/Include/GameNetwork/NetCommandMsg.h @@ -33,6 +33,7 @@ #include "GameNetwork/NetPacketStructs.h" #include "Common/UnicodeString.h" +class GameMessageArgument; class NetCommandRef; //----------------------------------------------------------------------------- @@ -117,10 +118,9 @@ class NetGameCommandMsg : public NetCommandMsgT m_argList; }; //----------------------------------------------------------------------------- diff --git a/Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp b/Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp index dd652a6cba3..b7ab720ef46 100644 --- a/Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp +++ b/Core/GameEngine/Source/GameNetwork/NetCommandMsg.cpp @@ -88,12 +88,8 @@ Int NetCommandMsg::getSortNumber() const { * Constructor with no argument, sets everything to default values. */ NetGameCommandMsg::NetGameCommandMsg() { - m_argSize = 0; - m_numArgs = 0; m_type = (GameMessage::Type)0; m_commandType = NETCOMMANDTYPE_GAMECOMMAND; - m_argList = nullptr; - m_argTail = nullptr; } /** @@ -102,11 +98,14 @@ NetGameCommandMsg::NetGameCommandMsg() { */ NetGameCommandMsg::NetGameCommandMsg(GameMessage *msg) { m_commandType = NETCOMMANDTYPE_GAMECOMMAND; - m_type = msg->getType(); - Int count = msg->getArgumentCount(); - for (Int i = 0; i < count; ++i) { - addArgument(msg->getArgumentDataType(i), *(msg->getArgument(i))); + + const std::vector& args = msg->getArguments(); + m_argList.reserve(args.size()); + + for (size_t i = 0; i < args.size(); ++i) { + const GameMessageArgument* arg = args[i]; + addArgument(arg->m_type, arg->m_data); } } @@ -114,11 +113,8 @@ NetGameCommandMsg::NetGameCommandMsg(GameMessage *msg) { * Destructor */ NetGameCommandMsg::~NetGameCommandMsg() { - GameMessageArgument *arg = m_argList; - while (arg != nullptr) { - m_argList = m_argList->m_next; - deleteInstance(arg); - arg = m_argList; + for (size_t i = 0; i < m_argList.size(); ++i) { + deleteInstance(const_cast(m_argList[i])); } } @@ -127,21 +123,10 @@ NetGameCommandMsg::~NetGameCommandMsg() { */ void NetGameCommandMsg::addArgument(const GameMessageArgumentDataType type, GameMessageArgumentType arg) { - if (m_argTail == nullptr) { - m_argList = newInstance(GameMessageArgument); - m_argTail = m_argList; - m_argList->m_data = arg; - m_argList->m_type = type; - m_argList->m_next = nullptr; - return; - } - GameMessageArgument *newArg = newInstance(GameMessageArgument); newArg->m_data = arg; newArg->m_type = type; - newArg->m_next = nullptr; - m_argTail->m_next = newArg; - m_argTail = newArg; + m_argList.push_back(newArg); } // here's where we figure out which slot corresponds to which player @@ -171,9 +156,8 @@ GameMessage *NetGameCommandMsg::constructGameMessage() const name.format("player%d", getPlayerID()); retval->friend_setPlayerIndex( ThePlayerList->findPlayerWithNameKey(TheNameKeyGenerator->nameToKey(name))->getPlayerIndex()); - GameMessageArgument *arg = m_argList; - while (arg != nullptr) { - + for (size_t i = 0; i < m_argList.size(); ++i) { + const GameMessageArgument* arg = m_argList[i]; switch (arg->m_type) { case ARGUMENTDATATYPE_INTEGER: @@ -211,8 +195,6 @@ GameMessage *NetGameCommandMsg::constructGameMessage() const break; } - - arg = arg->m_next; } return retval; } diff --git a/Generals/Code/GameEngine/Include/Common/MessageStream.h b/Generals/Code/GameEngine/Include/Common/MessageStream.h index 2b04f40be2e..e32173a4a33 100644 --- a/Generals/Code/GameEngine/Include/Common/MessageStream.h +++ b/Generals/Code/GameEngine/Include/Common/MessageStream.h @@ -82,7 +82,6 @@ class GameMessageArgument : public MemoryPoolObject { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageArgument, "GameMessageArgument") public: - GameMessageArgument* m_next; ///< The next argument GameMessageArgumentType m_data; ///< The data storage of an argument GameMessageArgumentDataType m_type; ///< The type of the argument. }; @@ -605,7 +604,16 @@ class GameMessage : public MemoryPoolObject GameMessage *prev() { return m_prev; } ///< Return prev message in the stream Type getType() const { return m_type; } ///< Return the message type - UnsignedByte getArgumentCount() const { return m_argCount; } ///< Return the number of arguments for this msg + // TheSuperHackers @refactor RiQQ 12/05/2026 Return argument count from vector size + /// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's. + UnsignedByte getArgumentCount() const { + DEBUG_ASSERTCRASH( + m_argList.size() <= 255, + ("GameMessage has more than 255 arguments") + ); + return static_cast(m_argList.size()); + } + const std::vector& getArguments() const { return m_argList ; } const char *getCommandAsString() const; ///< returns a string representation of the command type. static const char *getCommandTypeAsString(GameMessage::Type t); @@ -628,7 +636,6 @@ class GameMessage : public MemoryPoolObject /** * Return the given argument union. - * @todo This should be a more list-like interface. Very inefficient. */ const GameMessageArgumentType *getArgument( Int argIndex ) const; GameMessageArgumentDataType getArgumentDataType( Int argIndex ) const; @@ -649,10 +656,8 @@ class GameMessage : public MemoryPoolObject Int m_playerIndex; ///< The Player who issued the command - /// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's. - UnsignedByte m_argCount; ///< The number of arguments of this message - - GameMessageArgument *m_argList, *m_argTail; ///< This message's arguments + // TheSuperHackers @refactor RiQQ 12/05/2026 Replaced linked list with std::vector for argument storage + std::vector m_argList; ///< This message's arguments /// allocate a new argument, add it to list, return pointer to its data GameMessageArgument *allocArg(); diff --git a/Generals/Code/GameEngine/Source/Common/MessageStream.cpp b/Generals/Code/GameEngine/Source/Common/MessageStream.cpp index b970e457bf0..a1c7b80af6b 100644 --- a/Generals/Code/GameEngine/Source/Common/MessageStream.cpp +++ b/Generals/Code/GameEngine/Source/Common/MessageStream.cpp @@ -56,9 +56,6 @@ GameMessage::GameMessage( GameMessage::Type type ) { m_playerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex(); m_type = type; - m_argList = nullptr; - m_argTail = nullptr; - m_argCount = 0; m_list = nullptr; } @@ -69,12 +66,8 @@ GameMessage::GameMessage( GameMessage::Type type ) GameMessage::~GameMessage() { // free all arguments - GameMessageArgument *arg, *nextArg; - - for( arg = m_argList; arg; arg=nextArg ) - { - nextArg = arg->m_next; - deleteInstance(arg); + for( size_t i = 0; i < m_argList.size(); ++i ) { + deleteInstance(const_cast(m_argList[i])); } // detach message from list @@ -84,14 +77,11 @@ GameMessage::~GameMessage() /** * Return the given argument union. - * @todo This should be a more list-like interface. Very inefficient. */ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const { - int i=0; - for( GameMessageArgument *a = m_argList; a; a=a->m_next, i++ ) - if (i == argIndex) - return &a->m_data; + if (static_cast(argIndex) < m_argList.size()) + return &m_argList[argIndex]->m_data; DEBUG_CRASH(("argument not found")); static const GameMessageArgumentType zero = { 0 }; @@ -103,17 +93,9 @@ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const */ GameMessageArgumentDataType GameMessage::getArgumentDataType( Int argIndex ) const { - if (argIndex >= m_argCount) { - return ARGUMENTDATATYPE_UNKNOWN; - } - int i=0; - GameMessageArgument *a = m_argList; - for (; a && (i < argIndex); a=a->m_next, ++i ); + if (static_cast(argIndex) < m_argList.size()) + return m_argList[argIndex]->m_type; - if (a != nullptr) - { - return a->m_type; - } return ARGUMENTDATATYPE_UNKNOWN; } @@ -124,21 +106,7 @@ GameMessageArgument *GameMessage::allocArg() { // allocate a new argument GameMessageArgument *arg = newInstance(GameMessageArgument); - - // add to end of argument list - if (m_argTail) - m_argTail->m_next = arg; - else - { - m_argList = arg; - m_argTail = arg; - } - - arg->m_next = nullptr; - m_argTail = arg; - - m_argCount++; - + m_argList.push_back(arg); return arg; } diff --git a/Generals/Code/GameEngine/Source/Common/Recorder.cpp b/Generals/Code/GameEngine/Source/Common/Recorder.cpp index 1e4fdd83238..359685bef48 100644 --- a/Generals/Code/GameEngine/Source/Common/Recorder.cpp +++ b/Generals/Code/GameEngine/Source/Common/Recorder.cpp @@ -741,15 +741,10 @@ void RecorderClass::writeToFile(GameMessage * msg) { argType = argType->getNext(); } -// UnsignedByte lasttype = (UnsignedByte)ARGUMENTDATATYPE_UNKNOWN; - Int numArgs = msg->getArgumentCount(); - for (Int i = 0; i < numArgs; ++i) { -// UnsignedByte type = (UnsignedByte)(msg->getArgumentDataType(i)); -// if (lasttype != type) { -// fwrite(&type, sizeof(type), 1, m_file); -// lasttype = type; -// } - writeArgument(msg->getArgumentDataType(i), *(msg->getArgument(i))); + const std::vector& args = msg->getArguments(); + for ( size_t i = 0; i < args.size(); ++i ) { + const GameMessageArgument *arg = args[i]; + writeArgument(arg->m_type, arg->m_data); } deleteInstance(parser); diff --git a/GeneralsMD/Code/GameEngine/Include/Common/MessageStream.h b/GeneralsMD/Code/GameEngine/Include/Common/MessageStream.h index 0a08d98486d..629848de8ba 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/MessageStream.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/MessageStream.h @@ -82,7 +82,6 @@ class GameMessageArgument : public MemoryPoolObject { MEMORY_POOL_GLUE_WITH_USERLOOKUP_CREATE(GameMessageArgument, "GameMessageArgument") public: - GameMessageArgument* m_next; ///< The next argument GameMessageArgumentType m_data; ///< The data storage of an argument GameMessageArgumentDataType m_type; ///< The type of the argument. }; @@ -639,7 +638,16 @@ class GameMessage : public MemoryPoolObject GameMessage *prev() { return m_prev; } ///< Return prev message in the stream Type getType() const { return m_type; } ///< Return the message type - UnsignedByte getArgumentCount() const { return m_argCount; } ///< Return the number of arguments for this msg + // TheSuperHackers @refactor RiQQ 11/05/2026 Return argument count from vector size + /// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's. + UnsignedByte getArgumentCount() const { + DEBUG_ASSERTCRASH( + m_argList.size() <= 255, + ("GameMessage has more than 255 arguments") + ); + return static_cast(m_argList.size()); + } + const std::vector& getArguments() const { return m_argList ; } const char *getCommandAsString() const; ///< returns a string representation of the command type. static const char *getCommandTypeAsString(GameMessage::Type t); @@ -662,7 +670,6 @@ class GameMessage : public MemoryPoolObject /** * Return the given argument union. - * @todo This should be a more list-like interface. Very inefficient. */ const GameMessageArgumentType *getArgument( Int argIndex ) const; GameMessageArgumentDataType getArgumentDataType( Int argIndex ) const; @@ -683,10 +690,8 @@ class GameMessage : public MemoryPoolObject Int m_playerIndex; ///< The Player who issued the command - /// @todo If a GameMessage needs more than 255 arguments, it needs to be split up into multiple GameMessage's. - UnsignedByte m_argCount; ///< The number of arguments of this message - - GameMessageArgument *m_argList, *m_argTail; ///< This message's arguments + // TheSuperHackers @refactor RiQQ 11/05/2026 Replaced linked list with std::vector for argument storage + std::vector m_argList; ///< This message's arguments /// allocate a new argument, add it to list, return pointer to its data GameMessageArgument *allocArg(); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/MessageStream.cpp b/GeneralsMD/Code/GameEngine/Source/Common/MessageStream.cpp index 0addbe79dac..66c4337aa9c 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/MessageStream.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/MessageStream.cpp @@ -56,9 +56,6 @@ GameMessage::GameMessage( GameMessage::Type type ) { m_playerIndex = ThePlayerList->getLocalPlayer()->getPlayerIndex(); m_type = type; - m_argList = nullptr; - m_argTail = nullptr; - m_argCount = 0; m_list = nullptr; } @@ -69,12 +66,8 @@ GameMessage::GameMessage( GameMessage::Type type ) GameMessage::~GameMessage() { // free all arguments - GameMessageArgument *arg, *nextArg; - - for( arg = m_argList; arg; arg=nextArg ) - { - nextArg = arg->m_next; - deleteInstance(arg); + for( size_t i = 0; i < m_argList.size(); ++i ) { + deleteInstance(const_cast(m_argList[i])); } // detach message from list @@ -84,14 +77,11 @@ GameMessage::~GameMessage() /** * Return the given argument union. - * @todo This should be a more list-like interface. Very inefficient. */ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const { - int i=0; - for( GameMessageArgument *a = m_argList; a; a=a->m_next, i++ ) - if (i == argIndex) - return &a->m_data; + if (static_cast(argIndex) < m_argList.size()) + return &m_argList[argIndex]->m_data; DEBUG_CRASH(("argument not found")); static const GameMessageArgumentType zero = { 0 }; @@ -103,17 +93,9 @@ const GameMessageArgumentType *GameMessage::getArgument( Int argIndex ) const */ GameMessageArgumentDataType GameMessage::getArgumentDataType( Int argIndex ) const { - if (argIndex >= m_argCount) { - return ARGUMENTDATATYPE_UNKNOWN; - } - int i=0; - GameMessageArgument *a = m_argList; - for (; a && (i < argIndex); a=a->m_next, ++i ); + if (static_cast(argIndex) < m_argList.size()) + return m_argList[argIndex]->m_type; - if (a != nullptr) - { - return a->m_type; - } return ARGUMENTDATATYPE_UNKNOWN; } @@ -124,21 +106,7 @@ GameMessageArgument *GameMessage::allocArg() { // allocate a new argument GameMessageArgument *arg = newInstance(GameMessageArgument); - - // add to end of argument list - if (m_argTail) - m_argTail->m_next = arg; - else - { - m_argList = arg; - m_argTail = arg; - } - - arg->m_next = nullptr; - m_argTail = arg; - - m_argCount++; - + m_argList.push_back(arg); return arg; } diff --git a/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp b/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp index 7e38c456b89..d32b71fca8d 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/Recorder.cpp @@ -743,15 +743,10 @@ void RecorderClass::writeToFile(GameMessage * msg) { argType = argType->getNext(); } -// UnsignedByte lasttype = (UnsignedByte)ARGUMENTDATATYPE_UNKNOWN; - Int numArgs = msg->getArgumentCount(); - for (Int i = 0; i < numArgs; ++i) { -// UnsignedByte type = (UnsignedByte)(msg->getArgumentDataType(i)); -// if (lasttype != type) { -// fwrite(&type, sizeof(type), 1, m_file); -// lasttype = type; -// } - writeArgument(msg->getArgumentDataType(i), *(msg->getArgument(i))); + const std::vector& args = msg->getArguments(); + for ( size_t i = 0; i < args.size(); ++i ) { + const GameMessageArgument *arg = args[i]; + writeArgument(arg->m_type, arg->m_data); } deleteInstance(parser);