From 813e4cc6fd14135258d4126ecbc59ec80fb6057a Mon Sep 17 00:00:00 2001 From: Wei Shuai Date: Thu, 14 Mar 2024 15:10:54 +0800 Subject: [PATCH] Avoid duplicated reading RPN code execution across multiple clients While multiple clients Add(MF.SimVars.Add.xxxxRPNcodexxx) the exact same SimVars to WASM, From MSFS2020 perspective, it is unnecessary to execute the same RPNcode several times in each frame. This is an enhancement change to reduce FPS impact WASM will smartly execute duplicated SimVars only once in each frame. introduce new data structure: //RPN code execution for reading values in every frame struct ReadRPNCode { std::string Code; int RetType; //RetType: 0:float 1:integer 2:string std::vector SimVars; std::vector StringSimVars; }; -- This patch is stable because we have 1000+ customers who have been using these changes over a year GitHub Copilot suggestions --- src/Sources/Code/Module.cpp | 189 ++++++++++++++++++++++++++---------- 1 file changed, 138 insertions(+), 51 deletions(-) diff --git a/src/Sources/Code/Module.cpp b/src/Sources/Code/Module.cpp index afe5a3e..0175203 100644 --- a/src/Sources/Code/Module.cpp +++ b/src/Sources/Code/Module.cpp @@ -44,19 +44,22 @@ uint16_t MOBIFLIGHT_MAX_VARS_PER_FRAME = 30; // due to the maximum client-data-array-size (SIMCONNECT_CLIENTDATA_MAX_SIZE) of 8kB! constexpr uint16_t MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN = 128; +//declare struct Client +struct Client; + // data struct for dynamically registered SimVars struct SimVar { int ID; int Offset; - std::string Name; float Value; + struct Client * client; }; struct StringSimVar { int ID; int Offset; - std::string Name; std::string Value; + struct Client * client; }; // data struct for client accessing SimVars @@ -81,12 +84,23 @@ struct Client { // This is an optimization to be able to re-use already defined data definition IDs & request IDs // after resetting registered SimVars uint16_t MaxClientDataDefinition = 0; - // Runtime Rolling CLient Data reading Index - //std::vector::iterator RollingClientDataReadIndex; - uint16_t RollingClientDataReadIndex; +}; + +// Runtime Rolling Client Data reading Index +uint16_t RollingDataReadIndex = 0; +//RPN code execution for reading values in every frame +struct ReadRPNCode { + std::string Code; + //RetType: 0:float 1:integer 2:string + int RetType; + std::vector SimVars; + std::vector StringSimVars; }; +std::vector RPNCodelist; + + // The list of currently registered clients std::vector RegisteredClients; @@ -111,6 +125,14 @@ enum eEvents EVENT_FRAME }; +// Enum for MSFS data types +enum eMSFSTypes +{ + RPN_TYPE_FLOAT = 0, + RPN_TYPE_INTEGER = 1, + RPN_TYPE_STRING = 2 +}; + void CALLBACK MyDispatchProc(SIMCONNECT_RECV* pData, DWORD cbData, void* pContext); // Helper method to split up the lines from config file @@ -255,10 +277,10 @@ void WriteSimVar(StringSimVar& simVar, Client* client) ); if (hr != S_OK) { - fprintf(stderr, "MobiFlight[%s]: Error on Setting String Client Data. %lu, SimVar: %s (String-ID: %ul)\n", client->Name.c_str(), hr, simVar.Name.c_str(), simVar.ID); + fprintf(stderr, "MobiFlight[%s]: Error on Setting String Client Data. %lu, SimVar: (String-ID: %ul)\n", client->Name.c_str(), hr, simVar.ID); } #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: Written String-SimVar " << simVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: Written String-SimVar"; std::cout << " with String-ID " << simVar.ID << " has value " << simVar.Value.c_str() << std::endl; #endif } @@ -276,27 +298,49 @@ void WriteSimVar(SimVar& simVar, Client* client) { ); if (hr != S_OK) { - fprintf(stderr, "MobiFlight[%s]: Error on Setting Client Data. %lu, SimVar: %s (ID: %u)", client->Name.c_str(), hr, simVar.Name.c_str(), simVar.ID); + fprintf(stderr, "MobiFlight[%s]: Error on Setting Client Data. %lu, SimVar: (ID: %u)", client->Name.c_str(), hr, simVar.ID); } #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: Written SimVar " << simVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: Written SimVar"; std::cout << " with ID " << simVar.ID << " has value " << simVar.Value << std::endl; #endif } +//check whether SimVar has already registered in SimVar list +ReadRPNCode* FindExistingRPNCode(const std::string code) { + for (auto &rpn : RPNCodelist) { + if (rpn.Code == code) { + return &rpn; + } + } + return nullptr; +} + // Register a single Float-SimVar and send the current value to SimConnect Clients void RegisterFloatSimVar(const std::string code, Client* client) { std::vector* SimVars = &(client->SimVars); std::vector* StringSimVars = &(client->StringSimVars); SimVar newSimVar; + ReadRPNCode* pdupRpn = FindExistingRPNCode(code); HRESULT hr; - newSimVar.Name = code; newSimVar.ID = SimVars->size() + client->DataDefinitionIdSimVarsStart; newSimVar.Offset = SimVars->size() * (sizeof(float)); newSimVar.Value = 0.0F; + newSimVar.client = client; SimVars->push_back(newSimVar); + //duplicated SimVar + if (pdupRpn) { + pdupRpn->SimVars.push_back(newSimVar); + } else { + ReadRPNCode rpnCode; + rpnCode.Code = code; + rpnCode.RetType = RPN_TYPE_FLOAT; + rpnCode.SimVars.push_back(newSimVar); + RPNCodelist.push_back(rpnCode); + } + if (client->MaxClientDataDefinition < (SimVars->size() + StringSimVars->size())) { hr = SimConnect_AddToClientDataDefinition( g_hSimConnect, @@ -307,11 +351,11 @@ void RegisterFloatSimVar(const std::string code, Client* client) { ); if (hr != S_OK) { - fprintf(stderr, "MobiFlight[%s]: Error on adding Client Data \"%s\" with ID: %u, Offset: %u and Size: %lu\n", client->Name.c_str(), newSimVar.Name.c_str(), newSimVar.ID, newSimVar.Offset, sizeof(float)); + fprintf(stderr, "MobiFlight[%s]: Error on adding Client Data \"%s\" with ID: %u, Offset: %u and Size: %lu\n", client->Name.c_str(), code.c_str(), newSimVar.ID, newSimVar.Offset, sizeof(float)); } #if _DEBUG else { - std::cout << "MobiFlight[" << client->Name.c_str() << "]: Added SimVar > " << newSimVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: Added SimVar > " << code.c_str(); std::cout << " with ID: " << newSimVar.ID << ", Offset: " << newSimVar.Offset << " and Size: " << sizeof(float) << std::endl; } std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterFloatSimVar SimVars Size: " << SimVars->size() << std::endl; @@ -324,7 +368,7 @@ void RegisterFloatSimVar(const std::string code, Client* client) { newSimVar.Value = floatVal; WriteSimVar(newSimVar, client); #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterFloatSimVar > " << newSimVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterFloatSimVar > " << code.c_str(); std::cout << " ID [" << newSimVar.ID << "] : Offset(" << newSimVar.Offset << ") : Value(" << newSimVar.Value << ")" << std::endl; #endif } @@ -334,14 +378,26 @@ void RegisterStringSimVar(const std::string code, Client* client) { std::vector* SimVars = &(client->SimVars); std::vector* StringSimVars = &(client->StringSimVars); StringSimVar newStringSimVar; + ReadRPNCode* pdupRpn = FindExistingRPNCode(code); HRESULT hr; - newStringSimVar.Name = code; newStringSimVar.ID = StringSimVars->size() + client->DataDefinitionIdStringVarsStart; newStringSimVar.Offset = StringSimVars->size() * MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN; newStringSimVar.Value.empty(); + newStringSimVar.client = client; StringSimVars->push_back(newStringSimVar); + //duplicated SimVar + if (pdupRpn) { + pdupRpn->StringSimVars.push_back(newStringSimVar); + } else { + ReadRPNCode rpnCode; + rpnCode.Code = code; + rpnCode.RetType = RPN_TYPE_STRING; + rpnCode.StringSimVars.push_back(newStringSimVar); + RPNCodelist.push_back(rpnCode); + } + if (client->MaxClientDataDefinition < (SimVars->size() + StringSimVars->size())) { hr = SimConnect_AddToClientDataDefinition( g_hSimConnect, @@ -352,11 +408,11 @@ void RegisterStringSimVar(const std::string code, Client* client) { ); if (hr != S_OK) { - fprintf(stderr, "MobiFlight[%s]: Error on adding Client Data \"%s\" with String-ID: %u, String-Offset: %u and Size: %u\n", client->Name.c_str(), newStringSimVar.Name.c_str(), newStringSimVar.ID, newStringSimVar.Offset, MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN); + fprintf(stderr, "MobiFlight[%s]: Error on adding Client Data \"%s\" with String-ID: %u, String-Offset: %u and Size: %u\n", client->Name.c_str(), code.c_str(), newStringSimVar.ID, newStringSimVar.Offset, MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN); } #if _DEBUG else { - std::cout << "MobiFlight[" << client->Name.c_str() << "]: Added String-SimVar > " << newStringSimVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: Added String-SimVar > " << code.c_str(); std::cout << " with String-ID: " << newStringSimVar.ID << ", String-Offset: " << newStringSimVar.Offset << " and Size: " << MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN << std::endl; } std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterStringSimVar StringSimVars Size: " << StringSimVars->size() << std::endl; @@ -369,7 +425,7 @@ void RegisterStringSimVar(const std::string code, Client* client) { newStringSimVar.Value = std::string(charVal, strnlen(charVal, MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN)); WriteSimVar(newStringSimVar, client); #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterStringSimVar > " << newStringSimVar.Name.c_str(); + std::cout << "MobiFlight[" << client->Name.c_str() << "]: RegisterStringSimVar > " << code.c_str(); std::cout << " ID [" << newStringSimVar.ID << "] : Offset(" << newStringSimVar.Offset << ") : Value(" << newStringSimVar.Value << ")" << std::endl; #endif } @@ -391,66 +447,98 @@ void ClearSimVars(Client* client) { WriteSimVar(simVar, client); } client->StringSimVars.clear(); + // clear RPN code list + for (std::vector::iterator rit = RPNCodelist.begin(); rit != RPNCodelist.end();) { + for (std::vector::iterator it = (*rit).StringSimVars.begin(); it != (*rit).StringSimVars.end();) { + if ((*it).client == client) { + it = (*rit).StringSimVars.erase(it); + } else { + ++it; + } + } + for (std::vector::iterator sit = (*rit).SimVars.begin(); sit != (*rit).SimVars.end();) { + if ((*sit).client == client) { + sit = (*rit).SimVars.erase(sit); + } else { + ++sit; + } + } + //remove empty RPN code + if ((*rit).StringSimVars.empty() && (*rit).SimVars.empty()) { + rit = RPNCodelist.erase(rit); + } else { + ++rit; + } + } std::cout << "MobiFlight[" << client->Name.c_str() << "]: Cleared SimVar tracking." << std::endl; - //client->RollingClientDataReadIndex = client->SimVars.begin(); - client->RollingClientDataReadIndex = 0; + //client->RollingDataReadIndex = client->SimVars.begin(); + RollingDataReadIndex = 0; } + // Read a single SimVar and send the current value to SimConnect Clients (overloaded for float SimVars) -void ReadSimVar(SimVar &simVar, Client* client) { +void ReadSimVarFloat(ReadRPNCode &rpn) { FLOAT64 floatVal = 0; - execute_calculator_code(std::string(simVar.Name).c_str(), &floatVal, nullptr, nullptr); + execute_calculator_code(std::string(rpn.Code).c_str(), &floatVal, nullptr, nullptr); - if (simVar.Value == floatVal) return; - simVar.Value = floatVal; + for (auto& simVar : rpn.SimVars) { + if (std::abs(simVar.Value - floatVal) < 0.00001F) + { + continue; + } + simVar.Value = floatVal; - WriteSimVar(simVar, client); + WriteSimVar(simVar, simVar.client); #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: SimVar " << simVar.Name.c_str(); - std::cout << " with ID " << simVar.ID << " has value " << simVar.Value << std::endl; + std::cout << "MobiFlight[" << simVar.client->Name.c_str() << "]: SimVar " << rpn.Code.c_str(); + std::cout << " with ID " << simVar.ID << " has value " << simVar.Value << std::endl; #endif + } } // Read a single SimVar and send the current value to SimConnect Clients (overloaded for string SimVars) -void ReadSimVar(StringSimVar &simVar, Client* client) { +void ReadSimVarString(ReadRPNCode &rpn) { PCSTRINGZ charVal = nullptr; - execute_calculator_code(std::string(simVar.Name).c_str(), nullptr, nullptr, &charVal); + execute_calculator_code(std::string(rpn.Code).c_str(), nullptr, nullptr, &charVal); std::string stringVal = std::string(charVal, strnlen(charVal, MOBIFLIGHT_STRING_SIMVAR_VALUE_MAX_LEN)); - if (simVar.Value == stringVal) return; - simVar.Value = stringVal; - WriteSimVar(simVar, client); + for (auto& simVar : rpn.StringSimVars) { + if (simVar.Value == stringVal) continue; + simVar.Value = stringVal; + + WriteSimVar(simVar, simVar.client); #if _DEBUG - std::cout << "MobiFlight[" << client->Name.c_str() << "]: StringSimVar " << simVar.Name.c_str(); - std::cout << " with ID " << simVar.ID << " has value " << simVar.Value << std::endl; + std::cout << "MobiFlight[" << simVar.client->Name.c_str() << "]: StringSimVar " << rpn.Code.c_str(); + std::cout << " with ID " << simVar.ID << " has value " << simVar.Value << std::endl; #endif + } +} + +// Read a single SimVar and send the current value to SimConnect Clients (overloaded for float SimVars) +void ReadSimVar(ReadRPNCode &rpn) { + if (rpn.RetType == 0) { + ReadSimVarFloat(rpn); + } else if (rpn.RetType == 2) { + ReadSimVarString(rpn); + } } // Read all dynamically registered SimVars void ReadSimVars() { - for (auto& client : RegisteredClients) { - std::vector* SimVars = &(client->SimVars); - std::vector* StringSimVars = &(client->StringSimVars); + int totalSimVars = RPNCodelist.size(); + int maxVarsPerFrame = (totalSimVars < MOBIFLIGHT_MAX_VARS_PER_FRAME) ? totalSimVars : MOBIFLIGHT_MAX_VARS_PER_FRAME; - int totalSimVars = SimVars->size() + StringSimVars->size(); - int maxVarsPerFrame = (totalSimVars < MOBIFLIGHT_MAX_VARS_PER_FRAME) ? totalSimVars : MOBIFLIGHT_MAX_VARS_PER_FRAME; + for (int i=0; i < maxVarsPerFrame; ++i) { + ReadSimVar(RPNCodelist.at(RollingDataReadIndex)); - for (int i=0; i < maxVarsPerFrame; ++i) { - if(client->RollingClientDataReadIndex < SimVars->size() ) { - ReadSimVar(SimVars->at(client->RollingClientDataReadIndex), client); - } - else { - ReadSimVar(StringSimVars->at(client->RollingClientDataReadIndex - SimVars->size()), client); - } - client->RollingClientDataReadIndex++; - if (client->RollingClientDataReadIndex >= totalSimVars) - client->RollingClientDataReadIndex = 0; - } + RollingDataReadIndex++; + if (RollingDataReadIndex >= totalSimVars) + RollingDataReadIndex = 0; } } @@ -544,8 +632,7 @@ Client* RegisterNewClient(const std::string clientName) { newClient->DataDefinitionIDStringCommand = newClient->DataDefinitionIDStringResponse + 1; newClient->SimVars = std::vector(); newClient->StringSimVars = std::vector(); - //newClient->RollingClientDataReadIndex = newClient->SimVars.begin(); - newClient->RollingClientDataReadIndex = 0; + RollingDataReadIndex = 0; newClient->DataDefinitionIdSimVarsStart = SIMVAR_OFFSET + (newClient->ID * (CLIENT_DATA_DEF_ID_SIMVAR_RANGE + CLIENT_DATA_DEF_ID_STRINGVAR_RANGE)); newClient->DataDefinitionIdStringVarsStart = newClient->DataDefinitionIdSimVarsStart + CLIENT_DATA_DEF_ID_SIMVAR_RANGE;