diff options
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters | 6 | ||||
-rw-r--r-- | NorthstarDedicatedTest/dllmain.cpp | 3 | ||||
-rw-r--r-- | NorthstarDedicatedTest/scriptjson.cpp | 609 | ||||
-rw-r--r-- | NorthstarDedicatedTest/scriptjson.h | 2 | ||||
-rw-r--r-- | NorthstarDedicatedTest/squirrel.cpp | 65 | ||||
-rw-r--r-- | NorthstarDedicatedTest/squirrel.h | 481 |
7 files changed, 1168 insertions, 0 deletions
diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj index ff6ca2ea..0bb2fe02 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj @@ -122,6 +122,7 @@ <ClInclude Include="plugins.h" /> <ClInclude Include="plugin_abi.h" /> <ClInclude Include="scriptutility.h" /> + <ClInclude Include="scriptjson.h" /> <ClInclude Include="serverchathooks.h" /> <ClInclude Include="clientauthhooks.h" /> <ClInclude Include="color.h" /> @@ -613,6 +614,7 @@ <ClCompile Include="plugins.cpp" /> <ClCompile Include="rpakfilesystem.cpp" /> <ClCompile Include="scriptbrowserhooks.cpp" /> + <ClCompile Include="scriptjson.cpp" /> <ClCompile Include="scriptmainmenupromos.cpp" /> <ClCompile Include="scriptmodmenu.cpp" /> <ClCompile Include="scriptserverbrowser.cpp" /> diff --git a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters index 0e48f4a0..6496c796 100644 --- a/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters +++ b/NorthstarDedicatedTest/NorthstarDedicatedTest.vcxproj.filters @@ -1518,6 +1518,9 @@ <ClInclude Include="scriptutility.h"> <Filter>Header Files\Shared</Filter> </ClInclude> + <ClInclude Include="scriptjson.h"> + <Filter>Header Files\Shared</Filter> + </ClInclude> </ItemGroup> <ItemGroup> <ClCompile Include="dllmain.cpp"> @@ -1685,6 +1688,9 @@ <ClCompile Include="clientruihooks.cpp"> <Filter>Source Files\Client</Filter> </ClCompile> + <ClCompile Include="scriptjson.cpp"> + <Filter>Source Files\Shared</Filter> + </ClCompile> <ClCompile Include="scriptutility.cpp"> <Filter>Source Files\Shared</Filter> </ClCompile> diff --git a/NorthstarDedicatedTest/dllmain.cpp b/NorthstarDedicatedTest/dllmain.cpp index d64cc34f..41236506 100644 --- a/NorthstarDedicatedTest/dllmain.cpp +++ b/NorthstarDedicatedTest/dllmain.cpp @@ -52,6 +52,7 @@ #include "rapidjson/writer.h" #include "rapidjson/error/en.h" #include "ExploitFixes.h" +#include "scriptJson.h" typedef void (*initPluginFuncPtr)(void* getPluginObject); @@ -256,6 +257,7 @@ bool InitialiseNorthstar() AddDllLoadCallbackForClient("client.dll", InitialiseClientVideoOverrides); AddDllLoadCallbackForClient("engine.dll", InitialiseEngineClientRUIHooks); AddDllLoadCallbackForClient("engine.dll", InitialiseDebugOverlay); + AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrelJson); AddDllLoadCallbackForClient("client.dll", InitialiseClientSquirrelUtilityFunctions); // audio hooks AddDllLoadCallbackForClient("client.dll", InitialiseMilesAudioHooks); @@ -270,6 +272,7 @@ bool InitialiseNorthstar() AddDllLoadCallback("server.dll", InitialiseMiscServerFixes); AddDllLoadCallback("server.dll", InitialiseBuildAINFileHooks); AddDllLoadCallback("server.dll", InitialiseServerSquirrelUtilityFunctions); + AddDllLoadCallback("server.dll", InitialiseServerSquirrelJson); AddDllLoadCallback("engine.dll", InitialisePlaylistHooks); diff --git a/NorthstarDedicatedTest/scriptjson.cpp b/NorthstarDedicatedTest/scriptjson.cpp new file mode 100644 index 00000000..220f4968 --- /dev/null +++ b/NorthstarDedicatedTest/scriptjson.cpp @@ -0,0 +1,609 @@ +#include "pch.h" +#include "scriptJson.h" +#include "rapidjson/document.h" +#include "rapidjson/writer.h" +#include "rapidjson/stringbuffer.h" + +#include "squirrel.h" + +#ifdef _MSC_VER +#undef GetObject // fuck microsoft developers +#endif + +void SQ_EncodeJSON_Table( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQTable* sqTable, + rapidjson_document* allocatorDoc); +void SQ_EncodeJSON_Array( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQArray* sqArray, + rapidjson_document* allocatorDoc); +void ServerSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj); +void ServerSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr); +void ClientSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj); +void ClientSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr); + +SQRESULT ServerSq_DecodeJSON(void* sqvm) +{ + const char* json = ServerSq_getstring(sqvm, 1); + rapidjson_document doc; + doc.Parse(json); + if (doc.HasParseError()) + { + ServerSq_newTable(sqvm); + return SQRESULT_NOTNULL; + } + ServerSq_newTable(sqvm); + + for (int i = 0; i < doc.MemberCount(); i++) + { + + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = doc.MemberBegin()[i]; + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushstring(sqvm, itr.value.GetString(), -1); + + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + if ((long long)itr.name.GetString() == -1) + { + spdlog::info("Neagative String decoding True"); + continue; + } + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, true); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + if ((long long)itr.name.GetString() == -1) + { + + continue; + } + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, false); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushinteger(sqvm, itr.value.GetInt()); + } + ServerSq_newSlot(sqvm, -3, false); + break; + } + } + return SQRESULT_NOTNULL; +} + +void ServerSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj) +{ + ServerSq_newTable(sqvm); + + for (int i = 0; i < obj->MemberCount(); i++) + { + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = obj->MemberBegin()[i]; + if (!itr.name.IsString()) + { + spdlog::info("Decoding table with non-string key"); + continue; + } + const char* key = itr.name.GetString(); + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ServerSq_pushstring(sqvm, key, -1); + ServerSq_pushstring(sqvm, itr.value.GetString(), -1); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + + ServerSq_pushstring(sqvm, key, -1); + ServerSq_pushbool(sqvm, true); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushbool(sqvm, false); + ServerSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ServerSq_pushstring(sqvm, itr.name.GetString(), -1); + ServerSq_pushinteger(sqvm, itr.value.GetInt()); + } + ServerSq_newSlot(sqvm, -3, false); + break; + } + } +} + +void ServerSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr) +{ + int usedType = arr->GetArray().Begin()->GetType(); + bool isFloat = arr->GetArray().Begin()->IsDouble() || arr->GetArray().Begin()->IsFloat(); + ServerSq_newarray(sqvm, 0); + for (auto& itr : arr->GetArray()) + { + switch (itr.GetType()) + { + case rapidjson::kObjectType: + + if (usedType != itr.GetType()) + continue; + ServerSq_DecodeJSON_Table(sqvm, &itr); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kArrayType: + + if (usedType != itr.GetType()) + continue; + ServerSq_DecodeJSON_Array(sqvm, &itr); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kStringType: + if ((long long)itr.GetString() == -1) + { + + continue; + } + if (usedType != itr.GetType()) + continue; + ServerSq_pushstring(sqvm, itr.GetString(), -1); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kTrueType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ServerSq_pushbool(sqvm, true); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kFalseType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ServerSq_pushbool(sqvm, false); + ServerSq_arrayappend(sqvm, -2); + break; + case rapidjson::kNumberType: + if (usedType != itr.GetType()) + continue; + if (itr.IsDouble() || itr.IsFloat()) + { + + if (!isFloat) + continue; + ServerSq_pushfloat(sqvm, itr.GetFloat()); + } + else + { + if (isFloat) + continue; + ServerSq_pushinteger(sqvm, itr.GetInt()); + } + ServerSq_arrayappend(sqvm, -2); + break; + } + } +} + +SQRESULT ClientSq_DecodeJSON(void* sqvm) +{ + const char* json = ClientSq_getstring(sqvm, 1); + rapidjson_document doc; + doc.Parse(json); + if (doc.HasParseError()) + { + ClientSq_newTable(sqvm); + return SQRESULT_NOTNULL; + } + ServerSq_newTable(sqvm); + + for (int i = 0; i < doc.MemberCount(); i++) + { + + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = doc.MemberBegin()[i]; + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushstring(sqvm, itr.value.GetString(), -1); + + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + if ((long long)itr.name.GetString() == -1) + { + spdlog::info("Neagative String decoding True"); + continue; + } + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, true); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + if ((long long)itr.name.GetString() == -1) + { + + continue; + } + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, false); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushinteger(sqvm, itr.value.GetInt()); + } + ClientSq_newSlot(sqvm, -3, false); + break; + } + } + return SQRESULT_NOTNULL; +} + +void ClientSq_DecodeJSON_Table( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj) +{ + ClientSq_newTable(sqvm); + + for (int i = 0; i < obj->MemberCount(); i++) + { + rapidjson::GenericMember<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>& itr = obj->MemberBegin()[i]; + if (!itr.name.IsString()) + { + spdlog::info("Decoding table with non-string key"); + continue; + } + const char* key = itr.name.GetString(); + + switch (itr.value.GetType()) + { + case rapidjson::kObjectType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_DecodeJSON_Table( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kArrayType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_DecodeJSON_Array( + sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr.value); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kStringType: + ClientSq_pushstring(sqvm, key, -1); + ClientSq_pushstring(sqvm, itr.value.GetString(), -1); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kTrueType: + + ClientSq_pushstring(sqvm, key, -1); + ClientSq_pushbool(sqvm, true); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kFalseType: + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushbool(sqvm, false); + ClientSq_newSlot(sqvm, -3, false); + break; + case rapidjson::kNumberType: + if (itr.value.IsDouble() || itr.value.IsFloat()) + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushfloat(sqvm, itr.value.GetFloat()); + } + else + { + ClientSq_pushstring(sqvm, itr.name.GetString(), -1); + ClientSq_pushinteger(sqvm, itr.value.GetInt()); + } + ClientSq_newSlot(sqvm, -3, false); + break; + } + } +} + +void ClientSq_DecodeJSON_Array( + void* sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr) +{ + int usedType = arr->GetArray().Begin()->GetType(); + bool isFloat = arr->GetArray().Begin()->IsDouble() || arr->GetArray().Begin()->IsFloat(); + ClientSq_newarray(sqvm, 0); + for (auto& itr : arr->GetArray()) + { + switch (itr.GetType()) + { + case rapidjson::kObjectType: + + if (usedType != itr.GetType()) + continue; + ClientSq_DecodeJSON_Table(sqvm, &itr); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kArrayType: + + if (usedType != itr.GetType()) + continue; + ClientSq_DecodeJSON_Array(sqvm, &itr); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kStringType: + if ((long long)itr.GetString() == -1) + { + + continue; + } + if (usedType != itr.GetType()) + continue; + ClientSq_pushstring(sqvm, itr.GetString(), -1); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kTrueType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ClientSq_pushbool(sqvm, true); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kFalseType: + if (usedType != rapidjson::kTrueType && usedType != rapidjson::kFalseType) + continue; + ClientSq_pushbool(sqvm, false); + ClientSq_arrayappend(sqvm, -2); + break; + case rapidjson::kNumberType: + if (usedType != itr.GetType()) + continue; + if (itr.IsDouble() || itr.IsFloat()) + { + + if (!isFloat) + continue; + ClientSq_pushfloat(sqvm, itr.GetFloat()); + } + else + { + if (isFloat) + continue; + ClientSq_pushinteger(sqvm, itr.GetInt()); + } + ClientSq_arrayappend(sqvm, -2); + break; + } + } +} + +SQRESULT SQ_EncodeJSON(void* sqvm) +{ + rapidjson_document doc; + doc.SetObject(); + + HSquirrelVM* vm = (HSquirrelVM*)sqvm; + SQTable* table = vm->_stackOfCurrentFunction[1]._VAL.asTable; + SQ_EncodeJSON_Table(&doc, table, &doc); + rapidjson::StringBuffer buffer; + rapidjson::Writer<rapidjson::StringBuffer> writer(buffer); + doc.Accept(writer); + const char* json = buffer.GetString(); + + ServerSq_pushstring(sqvm, json, -1); + return SQRESULT_NOTNULL; +} + +void SQ_EncodeJSON_Table( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQTable* table, + rapidjson_document* allocatorDoc) +{ + for (int i = 0; i < table->_numOfNodes; i++) + { + tableNode* node = &table->_nodes[i]; + if (node->key._Type == OT_STRING) + { + + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); + + switch (node->val._Type) + { + case OT_STRING: + + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::StringRef(node->val._VAL.asString->_val), + allocatorDoc->GetAllocator()); + break; + case OT_INTEGER: + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>( + (int)node->val._VAL.asInteger), + allocatorDoc->GetAllocator()); + break; + case OT_FLOAT: + + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(node->val._VAL.asFloat), + allocatorDoc->GetAllocator()); + break; + case OT_BOOL: + if (node->val._VAL.asInteger) + { + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(true), + allocatorDoc->GetAllocator()); + } + else + { + obj->AddMember( + rapidjson::StringRef(node->key._VAL.asString->_val), + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(false), + allocatorDoc->GetAllocator()); + } + break; + case OT_TABLE: + + SQ_EncodeJSON_Table(&newObj, node->val._VAL.asTable, allocatorDoc); + obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newObj, allocatorDoc->GetAllocator()); + break; + case OT_ARRAY: + + SQ_EncodeJSON_Array(&newArray, node->val._VAL.asArray, allocatorDoc); + obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newArray, allocatorDoc->GetAllocator()); + break; + default: + spdlog::info("SQ encode Json type {} not supported", sq_getTypeName(node->val._Type)); + break; + } + } + } +} + +void SQ_EncodeJSON_Array( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj, + SQArray* sqArray, + rapidjson_document* allocatorDoc) +{ + int usedType = sqArray->_values->_Type; + for (int i = 0; i < sqArray->_usedSlots; i++) + { + SQObject* node = &sqArray->_values[i]; + if (node->_Type != usedType) + { + const char* typeName = sq_getTypeName(node->_Type); + const char* usedTypeName = sq_getTypeName(usedType); + spdlog::info("SQ encode Json array not same type got %s expected %s", typeName, usedTypeName); + continue; + } + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newObj(rapidjson::kObjectType); + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>> newArray(rapidjson::kArrayType); + switch (node->_Type) + { + case OT_STRING: + obj->PushBack(rapidjson::StringRef(node->_VAL.asString->_val), allocatorDoc->GetAllocator()); + break; + case OT_INTEGER: + obj->PushBack( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>((int)node->_VAL.asInteger), + allocatorDoc->GetAllocator()); + break; + case OT_FLOAT: + obj->PushBack( + rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>(node->_VAL.asFloat), + allocatorDoc->GetAllocator()); + break; + case OT_BOOL: + if (node->_VAL.asInteger) + { + obj->PushBack(rapidjson::StringRef("true"), allocatorDoc->GetAllocator()); + } + else + { + obj->PushBack(rapidjson::StringRef("false"), allocatorDoc->GetAllocator()); + } + break; + case OT_TABLE: + + SQ_EncodeJSON_Table(&newObj, node->_VAL.asTable, allocatorDoc); + obj->PushBack(newObj, allocatorDoc->GetAllocator()); + break; + case OT_ARRAY: + + SQ_EncodeJSON_Array(&newArray, node->_VAL.asArray, allocatorDoc); + obj->PushBack(newArray, allocatorDoc->GetAllocator()); + break; + default: + + spdlog::info("SQ encode Json type {} not supported", sq_getTypeName(node->_Type)); + } + } +} + +void InitialiseServerSquirrelJson(HMODULE baseAddress) +{ + + g_ServerSquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ServerSq_DecodeJSON); + g_ServerSquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); +} + +void InitialiseClientSquirrelJson(HMODULE baseAddress) +{ + g_ClientSquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ClientSq_DecodeJSON); + g_ClientSquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); + + g_UISquirrelManager->AddFuncRegistration("table", "DecodeJSON", "string json", "", ClientSq_DecodeJSON); + g_UISquirrelManager->AddFuncRegistration("string", "EncodeJSON", "table data", "", SQ_EncodeJSON); +}
\ No newline at end of file diff --git a/NorthstarDedicatedTest/scriptjson.h b/NorthstarDedicatedTest/scriptjson.h new file mode 100644 index 00000000..5dd66855 --- /dev/null +++ b/NorthstarDedicatedTest/scriptjson.h @@ -0,0 +1,2 @@ +void InitialiseServerSquirrelJson(HMODULE baseAddress); +void InitialiseClientSquirrelJson(HMODULE baseAddress);
\ No newline at end of file diff --git a/NorthstarDedicatedTest/squirrel.cpp b/NorthstarDedicatedTest/squirrel.cpp index a0680d9a..4d305ee2 100644 --- a/NorthstarDedicatedTest/squirrel.cpp +++ b/NorthstarDedicatedTest/squirrel.cpp @@ -94,6 +94,12 @@ sq_getboolType ServerSq_getbool; sq_getType ClientSq_sq_get; sq_getType ServerSq_sq_get; +sq_newSlotType ServerSq_newSlot; +sq_newSlotType ClientSq_newSlot; + +sq_newTableType ServerSq_newTable; +sq_newTableType ClientSq_newTable; + template <ScriptContext context> void ExecuteCodeCommand(const CCommand& args); // inits @@ -153,6 +159,10 @@ void InitialiseClientSquirrel(HMODULE baseAddress) ClientSq_defconst = (sq_defconst)((char*)baseAddress + 0x12120); + // Table functions + ClientSq_newTable = (sq_newTableType)((char*)baseAddress + 0x5940); + ClientSq_newSlot = (sq_newSlotType)((char*)baseAddress + 0x70B0); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x26130, @@ -210,6 +220,9 @@ void InitialiseServerSquirrel(HMODULE baseAddress) ServerSq_defconst = (sq_defconst)((char*)baseAddress + 0x1F550); + ServerSq_newSlot = (sq_newSlotType)((char*)baseAddress + 0x7080); + ServerSq_newTable = (sq_newTableType)((char*)baseAddress + 0x3960); + ENABLER_CREATEHOOK( hook, (char*)baseAddress + 0x1FE90, @@ -499,6 +512,58 @@ template <ScriptContext context> int64_t RegisterSquirrelFuncHook(void* sqvm, SQ return ClientRegisterSquirrelFunc(sqvm, funcReg, unknown); } +const char* sq_getTypeName(int type) +{ + switch (type) + { + case OT_ASSET: + return "asset"; + case OT_INTEGER: + return "int"; + case OT_BOOL: + return "bool"; + case SQOBJECT_NUMERIC: + return "float or int"; + case OT_NULL: + return "null"; + case OT_VECTOR: + return "vector"; + case 0: + return "var"; + case OT_USERDATA: + return "userdata"; + case OT_FLOAT: + return "float"; + case OT_STRING: + return "string"; + case 0x8000040: + return "array"; + case 0x8000200: + return "function"; + case 0x8100000: + return "structdef"; + case OT_THREAD: + return "thread"; + case OT_FUNCPROTO: + return "function"; + case OT_CLAAS: + return "class"; + case OT_WEAKREF: + return "weakref"; + case 0x8080000: + return "unimplemented function"; + case 0x8200000: + return "struct instance"; + case 0xA000020: + return "table"; + case 0xA008000: + return "instance"; + case 0xA400000: + return "entity"; + } + return ""; +} + SQReturnTypeEnum GetReturnTypeEnumFromString(const char* returnTypeString) { diff --git a/NorthstarDedicatedTest/squirrel.h b/NorthstarDedicatedTest/squirrel.h index 0e49c7f8..fd271dc2 100644 --- a/NorthstarDedicatedTest/squirrel.h +++ b/NorthstarDedicatedTest/squirrel.h @@ -13,6 +13,8 @@ typedef char SQChar; typedef SQUnsignedInteger SQBool; typedef SQInteger SQRESULT; +#define uint8 char + const SQRESULT SQRESULT_ERROR = -1; const SQRESULT SQRESULT_NULL = 0; const SQRESULT SQRESULT_NOTNULL = 1; @@ -33,6 +35,8 @@ enum SQReturnTypeEnum SqReturnTable = 0x26, }; +const char* sq_getTypeName(int type); + struct CompileBufferState { const SQChar* buffer; @@ -74,6 +78,474 @@ struct SQFuncRegistration SQReturnTypeEnum GetReturnTypeEnumFromString(const char* returnTypeString); +struct CallInfo; +struct SQTable; +struct SQString; +struct SQFunctionProto; +struct SQClosure; +struct SQSharedState; +struct StringTable; +struct SQStructInstance; +struct SQStructDef; +struct SQNativeClosure; +struct SQArray; +struct SQInstruction; + +/* 127 */ +enum SQObjectType : __int32 +{ + _RT_NULL = 0x1, + _RT_INTEGER = 0x2, + _RT_FLOAT = 0x4, + _RT_BOOL = 0x8, + _RT_STRING = 0x10, + _RT_TABLE = 0x20, + _RT_ARRAY = 0x40, + _RT_USERDATA = 0x80, + _RT_CLOSURE = 0x100, + _RT_NATIVECLOSURE = 0x200, + _RT_GENERATOR = 0x400, + OT_USERPOINTER = 0x800, + _RT_USERPOINTER = 0x800, + _RT_THREAD = 0x1000, + _RT_FUNCPROTO = 0x2000, + _RT_CLASS = 0x4000, + _RT_INSTANCE = 0x8000, + _RT_WEAKREF = 0x10000, + OT_VECTOR = 0x40000, + SQOBJECT_CANBEFALSE = 0x1000000, + OT_NULL = 0x1000001, + OT_BOOL = 0x1000008, + SQOBJECT_DELEGABLE = 0x2000000, + SQOBJECT_NUMERIC = 0x4000000, + OT_INTEGER = 0x5000002, + OT_FLOAT = 0x5000004, + SQOBJECT_REF_COUNTED = 0x8000000, + OT_STRING = 0x8000010, + OT_ARRAY = 0x8000040, + OT_CLOSURE = 0x8000100, + OT_NATIVECLOSURE = 0x8000200, + OT_ASSET = 0x8000400, + OT_THREAD = 0x8001000, + OT_FUNCPROTO = 0x8002000, + OT_CLAAS = 0x8004000, + OT_STRUCT = 0x8200000, + OT_WEAKREF = 0x8010000, + OT_TABLE = 0xA000020, + OT_USERDATA = 0xA000080, + OT_INSTANCE = 0xA008000, + OT_ENTITY = 0xA400000, +}; + +/* 156 */ +union __declspec(align(8)) SQObjectValue +{ + SQString* asString; + SQTable* asTable; + SQClosure* asClosure; + SQFunctionProto* asFuncProto; + SQStructDef* asStructDef; + __int64 asInteger; + SQStructInstance* asStructInstance; + float asFloat; + SQNativeClosure* asNativeClosure; + SQArray* asArray; +}; + +/* 128 */ +struct __declspec(align(8)) SQObject +{ + SQObjectType _Type; + __int32 _structOffset; + SQObjectValue _VAL; +}; + +struct tableNode +{ + SQObject val; + SQObject key; + tableNode* next; +}; + +/* 138 */ +struct __declspec(align(8)) SQString +{ + __int64* vftable; + __int32 uiRef; + __int32 uiRef1; + SQString* _next_maybe; + SQSharedState* sharedState; + __int32 length; + uint8 gap_24[4]; + char _hash[8]; + char _val[1]; +}; + +/* 137 */ +struct __declspec(align(8)) SQTable +{ + __int64* vftable; + uint8 gap_08[4]; + __int32 uiRef; + uint8 gap_10[8]; + void* pointer_18; + void* pointer_20; + void* _sharedState; + __int64 field_30; + tableNode* _nodes; + __int32 _numOfNodes; + __int32 size; + __int32 field_48; + __int32 _usedNodes; + uint8 _gap_50[20]; + __int32 field_64; + uint8 _gap_68[80]; +}; + +/* 140 */ +struct __declspec(align(8)) SQClosure +{ + void* vftable; + uint8 gap_08[4]; + __int32 uiRef; + void* pointer_10; + void* pointer_18; + void* pointer_20; + void* sharedState; + SQObject obj_30; + SQObject _function; + SQObject* _outervalues; + uint8 gap_58[8]; + uint8 gap_60[96]; + SQObject* objectPointer_C0; +}; + +/* 139 */ +struct __declspec(align(8)) SQFunctionProto +{ + void* vftable; + uint8 gap_08[4]; + __int32 uiRef; + uint8 gap_10[8]; + void* pointer_18; + void* pointer_20; + void* sharedState; + void* pointer_30; + SQObject fileName; + SQObject funcName; + SQObject obj_58; + uint8 gap_68[64]; + __int32 nParameters; + uint8 gap_AC[60]; + __int32 nDefaultParams; + uint8 gap_EC[200]; +}; + +/* 152 */ +struct SQStructDef +{ + uint8 gap_0[56]; + SQString* name; + uint8 gap_[300]; +}; + +/* 150 */ +struct SQStructInstance +{ + void* vftable; + uint8 gap_8[16]; + void* pointer_18; + uint8 gap_20[8]; + SQSharedState* _sharedState; + uint8 gap_30[8]; + SQObject data[1]; +}; + +/* 157 */ +struct __declspec(align(8)) SQNativeClosure +{ + void* vftable; + uint8 gap_08[4]; + __int32 uiRef; + uint8 gap_10[88]; + SQString* _name; + uint8 gap_0[300]; +}; + +/* 148 */ +struct SQSharedState +{ + uint8 gap_0[72]; + StringTable* _stringtable; + uint8 gap_50[30000]; +}; + +/* 149 */ +struct StringTable +{ + uint8 gap_0[12]; + int _numofslots; + uint8 gap_10[200]; +}; + +/* 129 */ +struct __declspec(align(8)) HSquirrelVM +{ + void* vftable; + __int32 uiRef; + uint8 gap_8[12]; + void* _toString; + void* _roottable_pointer; + void* pointer_28; + CallInfo* ci; + CallInfo* _callsstack; + __int32 _callsstacksize; + __int32 _stackbase; + SQObject* _stackOfCurrentFunction; + SQSharedState* sharedState; + void* pointer_58; + void* pointer_60; + __int32 _top; + SQObject* _stack; + uint8 gap_78[8]; + SQObject* _vargsstack; + uint8 gap_88[8]; + SQObject temp_reg; + uint8 gapA0[8]; + void* pointer_A8; + uint8 gap_B0[8]; + SQObject _roottable_object; + SQObject _lasterror; + SQObject _errorHandler; + __int64 field_E8; + __int32 traps; + uint8 gap_F4[12]; + __int32 _nnativecalls; + __int32 _suspended; + __int32 _suspended_root; + __int32 _callstacksize; + __int32 _suspended_target; + __int32 field_114; + __int32 _suspend_varargs; + SQObject* _object_pointer_120; +}; + +/* 136 */ +struct __declspec(align(8)) CallInfo +{ + SQInstruction* ip; + SQObject* _literals; + SQObject obj10; + SQObject closure; + __int32 _etraps[4]; + __int32 _root; + short _vargs_size; + short _vargs_base; +}; + +/* 135 */ +enum SQOpcode : int +{ + _OP_LOAD = 0x0, + _OP_LOADCOPY = 0x1, + _OP_LOADINT = 0x2, + _OP_LOADFLOAT = 0x3, + _OP_DLOAD = 0x4, + _OP_TAILCALL = 0x5, + _OP_CALL = 0x6, + _OP_PREPCALL = 0x7, + _OP_PREPCALLK = 0x8, + _OP_GETK = 0x9, + _OP_MOVE = 0xA, + _OP_NEWSLOT = 0xB, + _OP_DELETE = 0xC, + _OP_SET = 0xD, + _OP_GET = 0xE, + _OP_EQ = 0xF, + _OP_NE = 0x10, + _OP_ARITH = 0x11, + _OP_BITW = 0x12, + _OP_RETURN = 0x13, + _OP_LOADNULLS = 0x14, + _OP_LOADROOTTABLE = 0x15, + _OP_LOADBOOL = 0x16, + _OP_DMOVE = 0x17, + _OP_JMP = 0x18, + _OP_JNZ = 0x19, + _OP_JZ = 0x1A, + _OP_LOADFREEVAR = 0x1B, + _OP_VARGC = 0x1C, + _OP_GETVARGV = 0x1D, + _OP_NEWTABLE = 0x1E, + _OP_NEWARRAY = 0x1F, + _OP_APPENDARRAY = 0x20, + _OP_GETPARENT = 0x21, + _OP_COMPOUND_ARITH = 0x22, + _OP_COMPOUND_ARITH_LOCAL = 0x23, + _OP_INCREMENT_PREFIX = 0x24, + _OP_INCREMENT_PREFIX_LOCAL = 0x25, + _OP_INCREMENT_PREFIX_STRUCTFIELD = 0x26, + _OP_INCREMENT_POSTFIX = 0x27, + _OP_INCREMENT_POSTFIX_LOCAL = 0x28, + _OP_INCREMENT_POSTFIX_STRUCTFIELD = 0x29, + _OP_CMP = 0x2A, + _OP_EXISTS = 0x2B, + _OP_INSTANCEOF = 0x2C, + _OP_NEG = 0x2D, + _OP_NOT = 0x2E, + _OP_BWNOT = 0x2F, + _OP_CLOSURE = 0x30, + _OP_FOREACH = 0x31, + _OP_FOREACH_STATICARRAY_START = 0x32, + _OP_FOREACH_STATICARRAY_NEXT = 0x33, + _OP_FOREACH_STATICARRAY_NESTEDSTRUCT_START = 0x34, + _OP_FOREACH_STATICARRAY_NESTEDSTRUCT_NEXT = 0x35, + _OP_DELEGATE = 0x36, + _OP_CLONE = 0x37, + _OP_TYPEOF = 0x38, + _OP_PUSHTRAP = 0x39, + _OP_POPTRAP = 0x3A, + _OP_THROW = 0x3B, + _OP_CLASS = 0x3C, + _OP_NEWSLOTA = 0x3D, + _OP_EQ_LITERAL = 0x3E, + _OP_NE_LITERAL = 0x3F, + _OP_FOREACH_SETUP = 0x40, + _OP_ASSERT_FAILED = 0x41, + _OP_ADD = 0x42, + _OP_SUB = 0x43, + _OP_MUL = 0x44, + _OP_DIV = 0x45, + _OP_MOD = 0x46, + _OP_PREPCALLK_CALL = 0x47, + _OP_PREPCALLK_MOVE_CALL = 0x48, + _OP_PREPCALLK_LOADINT_CALL = 0x49, + _OP_CMP_JZ = 0x4A, + _OP_INCREMENT_LOCAL_DISCARD_JMP = 0x4B, + _OP_JZ_RETURN = 0x4C, + _OP_JZ_LOADBOOL_RETURN = 0x4D, + _OP_NEWVECTOR = 0x4E, + _OP_ZEROVECTOR = 0x4F, + _OP_GET_VECTOR_COMPONENT = 0x50, + _OP_SET_VECTOR_COMPONENT = 0x51, + _OP_VECTOR_COMPONENT_MINUSEQ = 0x52, + _OP_VECTOR_COMPONENT_PLUSEQ = 0x53, + _OP_VECTOR_COMPONENT_MULEQ = 0x54, + _OP_VECTOR_COMPONENT_DIVEQ = 0x55, + _OP_VECTOR_NORMALIZE = 0x56, + _OP_VECTOR_NORMALIZE_IN_PLACE = 0x57, + _OP_VECTOR_DOT_PRODUCT = 0x58, + _OP_VECTOR_DOT_PRODUCT2D = 0x59, + _OP_VECTOR_CROSS_PRODUCT = 0x5A, + _OP_VECTOR_CROSS_PRODUCT2D = 0x5B, + _OP_VECTOR_LENGTH = 0x5C, + _OP_VECTOR_LENGTHSQR = 0x5D, + _OP_VECTOR_LENGTH2D = 0x5E, + _OP_VECTOR_LENGTH2DSQR = 0x5F, + _OP_VECTOR_DISTANCE = 0x60, + _OP_VECTOR_DISTANCESQR = 0x61, + _OP_VECTOR_DISTANCE2D = 0x62, + _OP_VECTOR_DISTANCE2DSQR = 0x63, + _OP_INCREMENT_LOCAL_DISCARD = 0x64, + _OP_FASTCALL = 0x65, + _OP_FASTCALL_NATIVE = 0x66, + _OP_FASTCALL_NATIVE_ARGTYPECHECK = 0x67, + _OP_FASTCALL_ENV = 0x68, + _OP_FASTCALL_NATIVE_ENV = 0x69, + _OP_FASTCALL_NATIVE_ENV_ARGTYPECHECK = 0x6A, + _OP_LOADGLOBALARRAY = 0x6B, + _OP_GETGLOBAL = 0x6C, + _OP_SETGLOBAL = 0x6D, + _OP_COMPOUND_ARITH_GLOBAL = 0x6E, + _OP_GETSTRUCTFIELD = 0x6F, + _OP_SETSTRUCTFIELD = 0x70, + _OP_COMPOUND_ARITH_STRUCTFIELD = 0x71, + _OP_NEWSTRUCT = 0x72, + _OP_GETSUBSTRUCT = 0x73, + _OP_GETSUBSTRUCT_DYNAMIC = 0x74, + _OP_TYPECAST = 0x75, + _OP_TYPECHECK = 0x76, + _OP_TYPECHECK_ORNULL = 0x77, + _OP_TYPECHECK_NOTNULL = 0x78, + _OP_CHECK_ENTITY_CLASS = 0x79, + _OP_UNREACHABLE = 0x7A, + _OP_ARRAY_RESIZE = 0x7B, +}; + +/* 141 */ +struct __declspec(align(8)) SQStackInfos +{ + char* _name; + char* _sourceName; + __int32 _line; +}; + +/* 151 */ +struct __declspec(align(4)) SQInstruction +{ + int op; + int arg1; + int output; + __int16 arg2; + __int16 arg3; +}; + +/* 154 */ +struct SQLexer +{ + uint8 gap_0[112]; +}; + +/* 153 */ +struct SQCompiler +{ + uint8 gap_0[4]; + __int32 _token; + uint8 gap_8[8]; + SQObject object_10; + SQLexer lexer; + uint8 gap_1[768]; +}; + +/* 155 */ +struct CSquirrelVM +{ + uint8 gap_0[8]; + HSquirrelVM* sqvm; +}; + +struct SQVector +{ + SQObjectType _Type; + float x; + float y; + float z; +}; + +struct SQArray +{ + void* vftable; + __int32 uiRef; + uint8 gap_24[36]; + SQObject* _values; + __int32 _usedSlots; + __int32 _allocated; +}; + +#define INCREMENT_REFERENCECOUNT(val) \ + if ((val->_Type & SQOBJECT_REF_COUNTED) != 0) \ + ++val->_VAL.asString->uiRef; + +#define DECREMENT_REFERENCECOUNT(val) \ + if ((val->_Type & SQOBJECT_REF_COUNTED) != 0) \ + { \ + if (val->_VAL.asString->uiRef-- == 1) \ + { \ + spdlog::info("Deleted SQObject of type {} with address {:X}", sq_getTypeName(val->_Type), val->_VAL.asInteger); \ + (*(void(__fastcall**)(SQString*))(&val->_VAL.asString->vftable[1]))(val->_VAL.asString); \ + } \ + } + // core sqvm funcs typedef SQRESULT (*sq_compilebufferType)(void* sqvm, CompileBufferState* compileBuffer, const char* file, int a1, ScriptContext a2); extern sq_compilebufferType ClientSq_compilebuffer; @@ -151,6 +623,15 @@ typedef SQRESULT (*sq_getType)(void* sqvm, SQInteger idx); extern sq_getType ServerSq_sq_get; extern sq_getType ClientSq_sq_get; +// sq table functions +typedef SQRESULT (*sq_newTableType)(void* sqvm); +extern sq_newTableType ServerSq_newTable; +extern sq_newTableType ClientSq_newTable; + +typedef SQRESULT (*sq_newSlotType)(void* sqvm, int idx, bool bStatic); +extern sq_newSlotType ServerSq_newSlot; +extern sq_newSlotType ClientSq_newSlot; + template <ScriptContext context> class SquirrelManager { private: |