mirror of
https://github.com/R2Northstar/NorthstarLauncher
synced 2026-08-23 20:26:04 -04:00
* Untemplate g_pSquirrel so intellisense and stuff actually works with it * Remove unnecessary bitwise operations * Don't use ScriptContext_COUNT and treat INVALID as a valid flag
254 lines
8.2 KiB
C++
254 lines
8.2 KiB
C++
#include "squirrel/squirrel.h"
|
|
|
|
#include "rapidjson/error/en.h"
|
|
#include "rapidjson/document.h"
|
|
#include "rapidjson/writer.h"
|
|
#include "rapidjson/stringbuffer.h"
|
|
|
|
#ifdef _MSC_VER
|
|
#undef GetObject // fuck microsoft developers
|
|
#endif
|
|
|
|
template <ScriptContext context>
|
|
void DecodeJsonArray(HSQUIRRELVM sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* arr)
|
|
{
|
|
g_pSquirrel[context]->newarray(sqvm, 0);
|
|
|
|
for (auto& itr : arr->GetArray())
|
|
{
|
|
switch (itr.GetType())
|
|
{
|
|
case rapidjson::kObjectType:
|
|
DecodeJsonTable<context>(sqvm, &itr);
|
|
g_pSquirrel[context]->arrayappend(sqvm, -2);
|
|
break;
|
|
case rapidjson::kArrayType:
|
|
DecodeJsonArray<context>(sqvm, &itr);
|
|
g_pSquirrel[context]->arrayappend(sqvm, -2);
|
|
break;
|
|
case rapidjson::kStringType:
|
|
g_pSquirrel[context]->pushstring(sqvm, itr.GetString(), -1);
|
|
g_pSquirrel[context]->arrayappend(sqvm, -2);
|
|
break;
|
|
case rapidjson::kTrueType:
|
|
case rapidjson::kFalseType:
|
|
g_pSquirrel[context]->pushbool(sqvm, itr.GetBool());
|
|
g_pSquirrel[context]->arrayappend(sqvm, -2);
|
|
break;
|
|
case rapidjson::kNumberType:
|
|
if (itr.IsDouble() || itr.IsFloat())
|
|
g_pSquirrel[context]->pushfloat(sqvm, itr.GetFloat());
|
|
else
|
|
g_pSquirrel[context]->pushinteger(sqvm, itr.GetInt());
|
|
g_pSquirrel[context]->arrayappend(sqvm, -2);
|
|
break;
|
|
case rapidjson::kNullType:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <ScriptContext context>
|
|
void DecodeJsonTable(HSQUIRRELVM sqvm, rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj)
|
|
{
|
|
g_pSquirrel[context]->newtable(sqvm);
|
|
|
|
for (auto itr = obj->MemberBegin(); itr != obj->MemberEnd(); itr++)
|
|
{
|
|
switch (itr->value.GetType())
|
|
{
|
|
case rapidjson::kObjectType:
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
DecodeJsonTable<context>(
|
|
sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr->value);
|
|
g_pSquirrel[context]->newslot(sqvm, -3, false);
|
|
break;
|
|
case rapidjson::kArrayType:
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
DecodeJsonArray<context>(
|
|
sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&itr->value);
|
|
g_pSquirrel[context]->newslot(sqvm, -3, false);
|
|
break;
|
|
case rapidjson::kStringType:
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->value.GetString(), -1);
|
|
|
|
g_pSquirrel[context]->newslot(sqvm, -3, false);
|
|
break;
|
|
case rapidjson::kTrueType:
|
|
case rapidjson::kFalseType:
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
g_pSquirrel[context]->pushbool(sqvm, itr->value.GetBool());
|
|
g_pSquirrel[context]->newslot(sqvm, -3, false);
|
|
break;
|
|
case rapidjson::kNumberType:
|
|
if (itr->value.IsDouble() || itr->value.IsFloat())
|
|
{
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
g_pSquirrel[context]->pushfloat(sqvm, itr->value.GetFloat());
|
|
}
|
|
else
|
|
{
|
|
g_pSquirrel[context]->pushstring(sqvm, itr->name.GetString(), -1);
|
|
g_pSquirrel[context]->pushinteger(sqvm, itr->value.GetInt());
|
|
}
|
|
g_pSquirrel[context]->newslot(sqvm, -3, false);
|
|
break;
|
|
case rapidjson::kNullType:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
template <ScriptContext context> void EncodeJSONTable(
|
|
SQTable* table,
|
|
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj,
|
|
rapidjson::MemoryPoolAllocator<SourceAllocator>& allocator)
|
|
{
|
|
for (int i = 0; i < table->_numOfNodes; i++)
|
|
{
|
|
SQTable::_HashNode* 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), allocator);
|
|
break;
|
|
case OT_INTEGER:
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), node->val._VAL.asInteger, allocator);
|
|
break;
|
|
case OT_FLOAT:
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), node->val._VAL.asFloat, allocator);
|
|
break;
|
|
case OT_BOOL:
|
|
if (node->val._VAL.asInteger)
|
|
{
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), true, allocator);
|
|
}
|
|
else
|
|
{
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), false, allocator);
|
|
}
|
|
break;
|
|
case OT_TABLE:
|
|
EncodeJSONTable<context>(node->val._VAL.asTable, &newObj, allocator);
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newObj, allocator);
|
|
break;
|
|
case OT_ARRAY:
|
|
EncodeJSONArray<context>(node->val._VAL.asArray, &newArray, allocator);
|
|
obj->AddMember(rapidjson::StringRef(node->key._VAL.asString->_val), newArray, allocator);
|
|
break;
|
|
default:
|
|
spdlog::warn("SQ_EncodeJSON: squirrel type {} not supported", SQTypeNameFromID(node->val._Type));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <ScriptContext context> void EncodeJSONArray(
|
|
SQArray* arr,
|
|
rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>* obj,
|
|
rapidjson::MemoryPoolAllocator<SourceAllocator>& allocator)
|
|
{
|
|
for (int i = 0; i < arr->_usedSlots; i++)
|
|
{
|
|
SQObject* node = &arr->_values[i];
|
|
|
|
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), allocator);
|
|
break;
|
|
case OT_INTEGER:
|
|
obj->PushBack(node->_VAL.asInteger, allocator);
|
|
break;
|
|
case OT_FLOAT:
|
|
obj->PushBack(node->_VAL.asFloat, allocator);
|
|
break;
|
|
case OT_BOOL:
|
|
if (node->_VAL.asInteger)
|
|
obj->PushBack(rapidjson::StringRef("true"), allocator);
|
|
else
|
|
obj->PushBack(rapidjson::StringRef("false"), allocator);
|
|
break;
|
|
case OT_TABLE:
|
|
EncodeJSONTable<context>(node->_VAL.asTable, &newObj, allocator);
|
|
obj->PushBack(newObj, allocator);
|
|
break;
|
|
case OT_ARRAY:
|
|
EncodeJSONArray<context>(node->_VAL.asArray, &newArray, allocator);
|
|
obj->PushBack(newArray, allocator);
|
|
break;
|
|
default:
|
|
spdlog::info("SQ encode Json type {} not supported", SQTypeNameFromID(node->_Type));
|
|
}
|
|
}
|
|
}
|
|
|
|
ADD_SQFUNC(
|
|
"table",
|
|
DecodeJSON,
|
|
"string json, bool fatalParseErrors = false",
|
|
"converts a json string to a squirrel table",
|
|
ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)
|
|
{
|
|
const char* pJson = g_pSquirrel[context]->getstring(sqvm, 1);
|
|
const bool bFatalParseErrors = g_pSquirrel[context]->getbool(sqvm, 2);
|
|
|
|
rapidjson_document doc;
|
|
doc.Parse(pJson);
|
|
if (doc.HasParseError())
|
|
{
|
|
g_pSquirrel[context]->newtable(sqvm);
|
|
|
|
std::string sErrorString = fmt::format(
|
|
"Failed parsing json file: encountered parse error \"{}\" at offset {}",
|
|
GetParseError_En(doc.GetParseError()),
|
|
doc.GetErrorOffset());
|
|
|
|
if (bFatalParseErrors)
|
|
{
|
|
g_pSquirrel[context]->raiseerror(sqvm, sErrorString.c_str());
|
|
return SQRESULT_ERROR;
|
|
}
|
|
|
|
spdlog::warn(sErrorString);
|
|
return SQRESULT_NOTNULL;
|
|
}
|
|
|
|
DecodeJsonTable<context>(sqvm, (rapidjson::GenericValue<rapidjson::UTF8<char>, rapidjson::MemoryPoolAllocator<SourceAllocator>>*)&doc);
|
|
return SQRESULT_NOTNULL;
|
|
}
|
|
|
|
ADD_SQFUNC(
|
|
"string",
|
|
EncodeJSON,
|
|
"table data",
|
|
"converts a squirrel table to a json string",
|
|
ScriptContext::UI | ScriptContext::CLIENT | ScriptContext::SERVER)
|
|
{
|
|
rapidjson_document doc;
|
|
doc.SetObject();
|
|
|
|
// temp until this is just the func parameter type
|
|
HSQUIRRELVM vm = (HSQUIRRELVM)sqvm;
|
|
SQTable* table = vm->_stackOfCurrentFunction[1]._VAL.asTable;
|
|
EncodeJSONTable<context>(table, &doc, doc.GetAllocator());
|
|
|
|
rapidjson::StringBuffer buffer;
|
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
|
doc.Accept(writer);
|
|
const char* pJsonString = buffer.GetString();
|
|
|
|
g_pSquirrel[context]->pushstring(sqvm, pJsonString, -1);
|
|
return SQRESULT_NOTNULL;
|
|
}
|