mirror of
https://gitea.wildfiregames.com/0ad/0ad.git
synced 2026-06-21 01:04:06 +00:00
Exact stack rooting for JSON related ScriptInterface functions.
Refs #2415 Refs #2462 This was SVN commit r15603.
This commit is contained in:
@@ -108,7 +108,8 @@ bool CMapGeneratorWorker::Run()
|
||||
m_ScriptInterface->RegisterFunction<std::vector<std::string>, std::string, bool, CMapGeneratorWorker::FindActorTemplates>("FindActorTemplates");
|
||||
|
||||
// Parse settings
|
||||
JS::RootedValue settingsVal(cx, m_ScriptInterface->ParseJSON(m_Settings).get());
|
||||
JS::RootedValue settingsVal(cx);
|
||||
m_ScriptInterface->ParseJSON(m_Settings, &settingsVal);
|
||||
if (settingsVal.isUndefined())
|
||||
{
|
||||
LOGERROR(L"CMapGeneratorWorker::Run: Failed to parse settings");
|
||||
|
||||
@@ -392,7 +392,11 @@ CScriptValRooted CMapSummaryReader::GetMapSettings(ScriptInterface& scriptInterf
|
||||
JS::RootedValue data(cx);
|
||||
scriptInterface.Eval("({})", &data);
|
||||
if (!m_ScriptSettings.empty())
|
||||
scriptInterface.SetProperty(data, "settings", scriptInterface.ParseJSON(m_ScriptSettings), false);
|
||||
{
|
||||
JS::RootedValue scriptSettingsVal(cx);
|
||||
scriptInterface.ParseJSON(m_ScriptSettings, &scriptSettingsVal);
|
||||
scriptInterface.SetProperty(data, "settings", scriptSettingsVal, false);
|
||||
}
|
||||
return CScriptValRooted(cx, data);
|
||||
}
|
||||
|
||||
@@ -1269,8 +1273,10 @@ int CMapReader::GenerateMap()
|
||||
if (m_ScriptFile.length())
|
||||
scriptPath = L"maps/random/"+m_ScriptFile;
|
||||
|
||||
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
JS::RootedValue tmpScriptSettings(cx, m_ScriptSettings.get());
|
||||
// Stringify settings to pass across threads
|
||||
std::string scriptSettings = pSimulation2->GetScriptInterface().StringifyJSON(m_ScriptSettings.get());
|
||||
std::string scriptSettings = pSimulation2->GetScriptInterface().StringifyJSON(&tmpScriptSettings);
|
||||
|
||||
// Try to generate map
|
||||
m_MapGen->GenerateMap(scriptPath, scriptSettings);
|
||||
|
||||
@@ -294,7 +294,7 @@ std::string CGUIManager::GetSavedGameData()
|
||||
JS::RootedValue data(cx);
|
||||
JS::RootedValue global(cx, top()->GetGlobalObject());
|
||||
scriptInterface->CallFunction(global, "getSavedGameData", &data);
|
||||
return scriptInterface->StringifyJSON(data, false);
|
||||
return scriptInterface->StringifyJSON(&data, false);
|
||||
}
|
||||
|
||||
void CGUIManager::RestoreSavedGameData(std::string jsonData)
|
||||
@@ -304,7 +304,9 @@ void CGUIManager::RestoreSavedGameData(std::string jsonData)
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
JS::RootedValue global(cx, top()->GetGlobalObject());
|
||||
scriptInterface->CallFunctionVoid(global, "restoreSavedGameData", scriptInterface->ParseJSON(jsonData));
|
||||
JS::RootedValue dataVal(cx);
|
||||
scriptInterface->ParseJSON(jsonData, &dataVal);
|
||||
scriptInterface->CallFunctionVoid(global, "restoreSavedGameData", dataVal);
|
||||
}
|
||||
|
||||
InReaction CGUIManager::HandleEvent(const SDL_Event_* ev)
|
||||
|
||||
@@ -298,11 +298,15 @@ void SaveGamePrefix(ScriptInterface::CxPrivate* pCxPrivate, std::wstring prefix,
|
||||
LOGERROR(L"Failed to save game");
|
||||
}
|
||||
|
||||
void SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs)
|
||||
void SetNetworkGameAttributes(ScriptInterface::CxPrivate* pCxPrivate, CScriptVal attribs1)
|
||||
{
|
||||
ENSURE(g_NetServer);
|
||||
// TODO: Get Handle parameter directly with SpiderMonkey 31
|
||||
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
JS::RootedValue attribs(cx, attribs1.get());
|
||||
|
||||
g_NetServer->UpdateGameAttributes(attribs, *(pCxPrivate->pScriptInterface));
|
||||
g_NetServer->UpdateGameAttributes(&attribs, *(pCxPrivate->pScriptInterface));
|
||||
}
|
||||
|
||||
void StartNetworkHost(ScriptInterface::CxPrivate* pCxPrivate, std::wstring playerName)
|
||||
|
||||
+1
-1
@@ -190,7 +190,7 @@ static void PumpEvents()
|
||||
{
|
||||
JS::RootedValue tmpVal(cx);
|
||||
ScriptInterface::ToJSVal(cx, &tmpVal, ev);
|
||||
std::string data = g_GUI->GetScriptInterface()->StringifyJSON(tmpVal);
|
||||
std::string data = g_GUI->GetScriptInterface()->StringifyJSON(&tmpVal);
|
||||
PROFILE2_ATTR("%s", data.c_str());
|
||||
}
|
||||
in_dispatch_event(&ev);
|
||||
|
||||
@@ -375,6 +375,9 @@ bool CNetServerWorker::RunStep()
|
||||
// Check for messages from the game thread.
|
||||
// (Do as little work as possible while the mutex is held open,
|
||||
// to avoid performance problems and deadlocks.)
|
||||
|
||||
JSContext* cx = m_ScriptInterface->GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
std::vector<std::pair<int, CStr> > newAssignPlayer;
|
||||
std::vector<bool> newStartGame;
|
||||
@@ -407,7 +410,11 @@ bool CNetServerWorker::RunStep()
|
||||
ClearAllPlayerReady();
|
||||
|
||||
if (!newGameAttributes.empty())
|
||||
UpdateGameAttributes(GetScriptInterface().ParseJSON(newGameAttributes.back()));
|
||||
{
|
||||
JS::RootedValue gameAttributesVal(cx);
|
||||
GetScriptInterface().ParseJSON(newGameAttributes.back(), &gameAttributesVal);
|
||||
UpdateGameAttributes(&gameAttributesVal);
|
||||
}
|
||||
|
||||
if (!newTurnLength.empty())
|
||||
SetTurnLength(newTurnLength.back());
|
||||
@@ -997,17 +1004,21 @@ void CNetServerWorker::StartGame()
|
||||
|
||||
m_State = SERVER_STATE_LOADING;
|
||||
|
||||
JSContext* cx = GetScriptInterface().GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
JS::RootedValue tmpGameAttributes(cx, m_GameAttributes.get());
|
||||
// Send the final setup state to all clients
|
||||
UpdateGameAttributes(m_GameAttributes);
|
||||
UpdateGameAttributes(&tmpGameAttributes);
|
||||
SendPlayerAssignments();
|
||||
|
||||
CGameStartMessage gameStart;
|
||||
Broadcast(&gameStart);
|
||||
}
|
||||
|
||||
void CNetServerWorker::UpdateGameAttributes(const CScriptValRooted& attrs)
|
||||
void CNetServerWorker::UpdateGameAttributes(JS::MutableHandleValue attrs)
|
||||
{
|
||||
m_GameAttributes = attrs;
|
||||
m_GameAttributes = CScriptValRooted(GetScriptInterface().GetContext(), attrs);
|
||||
|
||||
if (!m_Host)
|
||||
return;
|
||||
@@ -1106,11 +1117,11 @@ void CNetServer::StartGame()
|
||||
m_Worker->m_StartGameQueue.push_back(true);
|
||||
}
|
||||
|
||||
void CNetServer::UpdateGameAttributes(const CScriptVal& attrs, ScriptInterface& scriptInterface)
|
||||
void CNetServer::UpdateGameAttributes(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface)
|
||||
{
|
||||
// Pass the attributes as JSON, since that's the easiest safe
|
||||
// cross-thread way of passing script data
|
||||
std::string attrsJSON = scriptInterface.StringifyJSON(attrs.get(), false);
|
||||
std::string attrsJSON = scriptInterface.StringifyJSON(attrs, false);
|
||||
|
||||
CScopeLock lock(m_Worker->m_WorkerMutex);
|
||||
m_Worker->m_GameAttributesQueue.push_back(attrsJSON);
|
||||
|
||||
@@ -146,7 +146,7 @@ public:
|
||||
* The changes will be asynchronously propagated to all clients.
|
||||
* @param attrs game attributes, in the script context of scriptInterface
|
||||
*/
|
||||
void UpdateGameAttributes(const CScriptVal& attrs, ScriptInterface& scriptInterface);
|
||||
void UpdateGameAttributes(JS::MutableHandleValue attrs, ScriptInterface& scriptInterface);
|
||||
|
||||
/**
|
||||
* Set the turn length to a fixed value.
|
||||
@@ -220,7 +220,7 @@ private:
|
||||
* The changes will be propagated to all clients.
|
||||
* @param attrs game attributes, in the script context of GetScriptInterface()
|
||||
*/
|
||||
void UpdateGameAttributes(const CScriptValRooted& attrs);
|
||||
void UpdateGameAttributes(JS::MutableHandleValue attrs);
|
||||
|
||||
/**
|
||||
* Make a player name 'nicer' by limiting the length and removing forbidden characters etc.
|
||||
|
||||
@@ -135,6 +135,9 @@ public:
|
||||
// and prints a load of debug output so you can see if anything funny's going on
|
||||
|
||||
ScriptInterface scriptInterface("Engine", "Test", g_ScriptRuntime);
|
||||
JSContext* cx = scriptInterface.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
TestStdoutLogger logger;
|
||||
|
||||
std::vector<CNetClient*> clients;
|
||||
@@ -145,9 +148,9 @@ public:
|
||||
|
||||
CNetServer server;
|
||||
|
||||
CScriptValRooted attrs;
|
||||
scriptInterface.Eval("({mapType:'scenario',map:'_default',thing:'example'})", attrs);
|
||||
server.UpdateGameAttributes(attrs.get(), scriptInterface);
|
||||
JS::RootedValue attrs(cx);
|
||||
scriptInterface.Eval("({mapType:'scenario',map:'_default',thing:'example'})", &attrs);
|
||||
server.UpdateGameAttributes(&attrs, scriptInterface);
|
||||
|
||||
CNetClient client1(&client1Game);
|
||||
CNetClient client2(&client2Game);
|
||||
@@ -197,6 +200,9 @@ public:
|
||||
void test_rejoin_DISABLED()
|
||||
{
|
||||
ScriptInterface scriptInterface("Engine", "Test", g_ScriptRuntime);
|
||||
JSContext* cx = scriptInterface.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
TestStdoutLogger logger;
|
||||
|
||||
std::vector<CNetClient*> clients;
|
||||
@@ -207,9 +213,9 @@ public:
|
||||
|
||||
CNetServer server;
|
||||
|
||||
CScriptValRooted attrs;
|
||||
scriptInterface.Eval("({mapType:'scenario',map:'_default',thing:'example'})", attrs);
|
||||
server.UpdateGameAttributes(attrs.get(), scriptInterface);
|
||||
JS::RootedValue attrs(cx);
|
||||
scriptInterface.Eval("({mapType:'scenario',map:'_default',thing:'example'})", &attrs);
|
||||
server.UpdateGameAttributes(&attrs, scriptInterface);
|
||||
|
||||
CNetClient client1(&client1Game);
|
||||
CNetClient client2(&client2Game);
|
||||
|
||||
+1
-1
@@ -282,7 +282,7 @@ void CGame::StartGame(const CScriptValRooted& attribs1, const std::string& saved
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
JS::RootedValue attribs(cx, attribs1.get()); // TODO: Get Handle parameter directly with SpiderMonkey 31
|
||||
m_ReplayLogger->StartGame(attribs1);
|
||||
m_ReplayLogger->StartGame(&attribs);
|
||||
|
||||
RegisterInit(attribs, savedState);
|
||||
}
|
||||
|
||||
@@ -1184,7 +1184,8 @@ bool Autostart(const CmdLineArgs& args)
|
||||
|
||||
// Random map definition will be loaded from JSON file, so we need to parse it
|
||||
std::wstring scriptPath = L"maps/" + autoStartName.FromUTF8() + L".json";
|
||||
JS::RootedValue scriptData(cx, scriptInterface.ReadJSONFile(scriptPath).get());
|
||||
JS::RootedValue scriptData(cx);
|
||||
scriptInterface.ReadJSONFile(scriptPath, &scriptData);
|
||||
if (!scriptData.isUndefined() && scriptInterface.GetProperty(scriptData, "settings", &settings))
|
||||
{
|
||||
// JSON loaded ok - copy script name over to game attributes
|
||||
@@ -1239,9 +1240,7 @@ bool Autostart(const CmdLineArgs& args)
|
||||
// (Omitting this may cause the loading screen to display "Loading (undefined)",
|
||||
// for example...)
|
||||
CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml");
|
||||
CScriptValRooted mapSettings = scriptInterface.ParseJSON(mapSettingsJSON);
|
||||
|
||||
settings = mapSettings.get();
|
||||
scriptInterface.ParseJSON(mapSettingsJSON, &settings);
|
||||
mapType = "scenario";
|
||||
}
|
||||
else if (mapDirectory == L"skirmishes")
|
||||
@@ -1253,9 +1252,8 @@ bool Autostart(const CmdLineArgs& args)
|
||||
// To prevent this, we mimic the behavior of the game setup screen by
|
||||
// retrieving the map settings from the actual map xml...
|
||||
CStr8 mapSettingsJSON = LoadSettingsOfScenarioMap("maps/" + autoStartName + ".xml");
|
||||
CScriptValRooted mapSettings = scriptInterface.ParseJSON(mapSettingsJSON);
|
||||
|
||||
settings = mapSettings.get();
|
||||
scriptInterface.ParseJSON(mapSettingsJSON, &settings);
|
||||
|
||||
// ...and initialize the playerData array being edited by
|
||||
// autostart-civ et.al. with the real map data, so sensible values
|
||||
// are always present:
|
||||
@@ -1364,7 +1362,7 @@ bool Autostart(const CmdLineArgs& args)
|
||||
|
||||
g_NetServer = new CNetServer(maxPlayers);
|
||||
|
||||
g_NetServer->UpdateGameAttributes(attrs.get(), scriptInterface);
|
||||
g_NetServer->UpdateGameAttributes(&attrs, scriptInterface);
|
||||
|
||||
bool ok = g_NetServer->SetupConnection();
|
||||
ENSURE(ok);
|
||||
|
||||
@@ -320,7 +320,7 @@ void RunHardwareDetection()
|
||||
scriptInterface.SetProperty(settings, "timer_resolution", timer_Resolution());
|
||||
|
||||
// Send the same data to the reporting system
|
||||
g_UserReporter.SubmitReport("hwdetect", 11, scriptInterface.StringifyJSON(settings, false));
|
||||
g_UserReporter.SubmitReport("hwdetect", 11, scriptInterface.StringifyJSON(&settings, false));
|
||||
|
||||
// Run the detection script:
|
||||
JS::RootedValue global(cx, scriptInterface.GetGlobalObject());
|
||||
|
||||
+17
-7
@@ -75,17 +75,22 @@ CReplayLogger::~CReplayLogger()
|
||||
delete m_Stream;
|
||||
}
|
||||
|
||||
void CReplayLogger::StartGame(const CScriptValRooted& attribs)
|
||||
void CReplayLogger::StartGame(JS::MutableHandleValue attribs)
|
||||
{
|
||||
*m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs.get(), false) << "\n";
|
||||
*m_Stream << "start " << m_ScriptInterface.StringifyJSON(attribs, false) << "\n";
|
||||
}
|
||||
|
||||
void CReplayLogger::Turn(u32 n, u32 turnLength, const std::vector<SimulationCommand>& commands)
|
||||
{
|
||||
JSContext* cx = m_ScriptInterface.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
*m_Stream << "turn " << n << " " << turnLength << "\n";
|
||||
for (size_t i = 0; i < commands.size(); ++i)
|
||||
{
|
||||
*m_Stream << "cmd " << commands[i].player << " " << m_ScriptInterface.StringifyJSON(commands[i].data.get(), false) << "\n";
|
||||
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
JS::RootedValue tmpCommand(cx, commands[i].data.get());
|
||||
*m_Stream << "cmd " << commands[i].player << " " << m_ScriptInterface.StringifyJSON(&tmpCommand, false) << "\n";
|
||||
}
|
||||
*m_Stream << "end\n";
|
||||
m_Stream->flush();
|
||||
@@ -133,6 +138,9 @@ void CReplayPlayer::Replay(bool serializationtest)
|
||||
g_Game = &game;
|
||||
if (serializationtest)
|
||||
game.GetSimulation2()->EnableSerializationTest();
|
||||
|
||||
JSContext* cx = game.GetSimulation2()->GetScriptInterface().GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
// Need some stuff for terrain movement costs:
|
||||
// (TODO: this ought to be independent of any graphics code)
|
||||
@@ -155,9 +163,10 @@ void CReplayPlayer::Replay(bool serializationtest)
|
||||
{
|
||||
std::string line;
|
||||
std::getline(*m_Stream, line);
|
||||
CScriptValRooted attribs = game.GetSimulation2()->GetScriptInterface().ParseJSON(line);
|
||||
JS::RootedValue attribs(cx);
|
||||
game.GetSimulation2()->GetScriptInterface().ParseJSON(line, &attribs);
|
||||
|
||||
game.StartGame(attribs, "");
|
||||
game.StartGame(CScriptValRooted(cx, attribs), "");
|
||||
|
||||
// TODO: Non progressive load can fail - need a decent way to handle this
|
||||
LDR_NonprogressiveLoad();
|
||||
@@ -177,9 +186,10 @@ void CReplayPlayer::Replay(bool serializationtest)
|
||||
|
||||
std::string line;
|
||||
std::getline(*m_Stream, line);
|
||||
CScriptValRooted data = game.GetSimulation2()->GetScriptInterface().ParseJSON(line);
|
||||
JS::RootedValue data(cx);
|
||||
game.GetSimulation2()->GetScriptInterface().ParseJSON(line, &data);
|
||||
|
||||
SimulationCommand cmd = { player, data };
|
||||
SimulationCommand cmd = { player, CScriptValRooted(cx, data) };
|
||||
commands.push_back(cmd);
|
||||
}
|
||||
else if (type == "hash" || type == "hash-quick")
|
||||
|
||||
+4
-2
@@ -18,6 +18,8 @@
|
||||
#ifndef INCLUDED_REPLAY
|
||||
#define INCLUDED_REPLAY
|
||||
|
||||
#include "scriptinterface/ScriptTypes.h"
|
||||
|
||||
class CScriptValRooted;
|
||||
struct SimulationCommand;
|
||||
class ScriptInterface;
|
||||
@@ -35,7 +37,7 @@ public:
|
||||
/**
|
||||
* Started the game with the given game attributes.
|
||||
*/
|
||||
virtual void StartGame(const CScriptValRooted& attribs) = 0;
|
||||
virtual void StartGame(JS::MutableHandleValue attribs) = 0;
|
||||
|
||||
/**
|
||||
* Run the given turn with the given collection of player commands.
|
||||
@@ -69,7 +71,7 @@ public:
|
||||
CReplayLogger(ScriptInterface& scriptInterface);
|
||||
~CReplayLogger();
|
||||
|
||||
virtual void StartGame(const CScriptValRooted& attribs);
|
||||
virtual void StartGame(JS::MutableHandleValue attribs);
|
||||
virtual void Turn(u32 n, u32 turnLength, const std::vector<SimulationCommand>& commands);
|
||||
virtual void Hash(const std::string& hash, bool quick);
|
||||
|
||||
|
||||
@@ -106,7 +106,7 @@ Status SavedGames::Save(const std::wstring& name, const std::wstring& descriptio
|
||||
|
||||
simulation.GetScriptInterface().SetProperty(metadata, "description", description);
|
||||
|
||||
std::string metadataString = simulation.GetScriptInterface().StringifyJSON(metadata, true);
|
||||
std::string metadataString = simulation.GetScriptInterface().StringifyJSON(&metadata, true);
|
||||
|
||||
// Write the saved game as zip file containing the various components
|
||||
PIArchiveWriter archiveWriter = CreateArchiveWriter_Zip(tempSaveFileRealPath, false);
|
||||
@@ -161,12 +161,17 @@ public:
|
||||
|
||||
void ReadEntry(const VfsPath& pathname, const CFileInfo& fileInfo, PIArchiveFile archiveFile)
|
||||
{
|
||||
JSContext* cx = m_ScriptInterface.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
if (pathname == L"metadata.json")
|
||||
{
|
||||
std::string buffer;
|
||||
buffer.resize(fileInfo.Size());
|
||||
WARN_IF_ERR(archiveFile->Load("", DummySharedPtr((u8*)buffer.data()), buffer.size()));
|
||||
m_Metadata = m_ScriptInterface.ParseJSON(buffer);
|
||||
JS::RootedValue tmpMetadata(cx); // TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
m_ScriptInterface.ParseJSON(buffer, &tmpMetadata);
|
||||
m_Metadata = CScriptValRooted(cx, tmpMetadata);
|
||||
}
|
||||
else if (pathname == L"simulation.dat" && m_SavedState)
|
||||
{
|
||||
|
||||
@@ -203,7 +203,8 @@ std::vector<std::string> CTemplateLoader::FindPlaceableTemplates(const std::stri
|
||||
|
||||
if (templatesType == SIMULATION_TEMPLATES || templatesType == ALL_TEMPLATES)
|
||||
{
|
||||
JS::RootedValue placeablesFilter(cx, scriptInterface.ReadJSONFile("simulation/data/placeablesFilter.json").get());
|
||||
JS::RootedValue placeablesFilter(cx);
|
||||
scriptInterface.ReadJSONFile("simulation/data/placeablesFilter.json", &placeablesFilter);
|
||||
|
||||
std::vector<CScriptValRooted> folders;
|
||||
if (scriptInterface.GetProperty(placeablesFilter, "templates", folders))
|
||||
|
||||
@@ -1238,23 +1238,24 @@ bool ScriptInterface::Eval_(const wchar_t* code, JS::MutableHandleValue rval)
|
||||
return ok;
|
||||
}
|
||||
|
||||
CScriptValRooted ScriptInterface::ParseJSON(const std::string& string_utf8)
|
||||
void ScriptInterface::ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out)
|
||||
{
|
||||
JSAutoRequest rq(m->m_cx);
|
||||
std::wstring attrsW = wstring_from_utf8(string_utf8);
|
||||
utf16string string(attrsW.begin(), attrsW.end());
|
||||
JS::RootedValue vp(m->m_cx);
|
||||
if (!JS_ParseJSON(m->m_cx, reinterpret_cast<const jschar*>(string.c_str()), (u32)string.size(), &vp))
|
||||
if (!JS_ParseJSON(m->m_cx, reinterpret_cast<const jschar*>(string.c_str()), (u32)string.size(), out))
|
||||
{
|
||||
LOGERROR(L"JS_ParseJSON failed!");
|
||||
return CScriptValRooted(m->m_cx, vp);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path)
|
||||
void ScriptInterface::ReadJSONFile(const VfsPath& path, JS::MutableHandleValue out)
|
||||
{
|
||||
if (!VfsFileExists(path))
|
||||
{
|
||||
LOGERROR(L"File '%ls' does not exist", path.string().c_str());
|
||||
return CScriptValRooted();
|
||||
return;
|
||||
}
|
||||
|
||||
CVFSFile file;
|
||||
@@ -1264,12 +1265,12 @@ CScriptValRooted ScriptInterface::ReadJSONFile(const VfsPath& path)
|
||||
if (ret != PSRETURN_OK)
|
||||
{
|
||||
LOGERROR(L"Failed to load file '%ls': %hs", path.string().c_str(), GetErrorString(ret));
|
||||
return CScriptValRooted();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string content(file.DecodeUTF8()); // assume it's UTF-8
|
||||
|
||||
return ParseJSON(content);
|
||||
ParseJSON(content, out);
|
||||
}
|
||||
|
||||
struct Stringifier
|
||||
@@ -1299,11 +1300,14 @@ struct StringifierW
|
||||
std::wstringstream stream;
|
||||
};
|
||||
|
||||
std::string ScriptInterface::StringifyJSON(jsval obj, bool indent)
|
||||
// TODO: It's not quite clear why JS_Stringify needs JS::MutableHandleValue. |obj| should not get modified.
|
||||
// It probably has historical reasons and could be changed by SpiderMonkey in the future.
|
||||
std::string ScriptInterface::StringifyJSON(JS::MutableHandleValue obj, bool indent)
|
||||
{
|
||||
JSAutoRequest rq(m->m_cx);
|
||||
Stringifier str;
|
||||
if (!JS_Stringify(m->m_cx, &obj, NULL, indent ? INT_TO_JSVAL(2) : JSVAL_VOID, &Stringifier::callback, &str))
|
||||
JS::RootedValue indentVal(m->m_cx, indent ? JS::Int32Value(2) : JS::UndefinedValue());
|
||||
if (!JS_Stringify(m->m_cx, obj.address(), NULL, indentVal, &Stringifier::callback, &str))
|
||||
{
|
||||
JS_ClearPendingException(m->m_cx);
|
||||
LOGERROR(L"StringifyJSON failed");
|
||||
|
||||
@@ -268,19 +268,19 @@ public:
|
||||
std::wstring ToString(jsval obj, bool pretty = false);
|
||||
|
||||
/**
|
||||
* Parse a UTF-8-encoded JSON string. Returns the undefined value on error.
|
||||
* Parse a UTF-8-encoded JSON string. Returns the unmodified value on error and prints an error message.
|
||||
*/
|
||||
CScriptValRooted ParseJSON(const std::string& string_utf8);
|
||||
void ParseJSON(const std::string& string_utf8, JS::MutableHandleValue out);
|
||||
|
||||
/**
|
||||
* Read a JSON file. Returns the undefined value on error.
|
||||
* Read a JSON file. Returns the unmodified value on error and prints an error message.
|
||||
*/
|
||||
CScriptValRooted ReadJSONFile(const VfsPath& path);
|
||||
void ReadJSONFile(const VfsPath& path, JS::MutableHandleValue out);
|
||||
|
||||
/**
|
||||
* Stringify to a JSON string, UTF-8 encoded. Returns an empty string on error.
|
||||
*/
|
||||
std::string StringifyJSON(jsval obj, bool indent = true);
|
||||
std::string StringifyJSON(JS::MutableHandleValue obj, bool indent = true);
|
||||
|
||||
/**
|
||||
* Report the given error message through the JS error reporting mechanism,
|
||||
|
||||
@@ -241,15 +241,17 @@ public:
|
||||
void test_json()
|
||||
{
|
||||
ScriptInterface script("Test", "Test", g_ScriptRuntime);
|
||||
JSContext* cx = script.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
std::string input = "({'x':1,'z':[2,'3\\u263A\\ud800'],\"y\":true})";
|
||||
CScriptValRooted val;
|
||||
TS_ASSERT(script.Eval(input.c_str(), val));
|
||||
JS::RootedValue val(cx);
|
||||
TS_ASSERT(script.Eval(input.c_str(), &val));
|
||||
|
||||
std::string stringified = script.StringifyJSON(val.get());
|
||||
std::string stringified = script.StringifyJSON(&val);
|
||||
TS_ASSERT_STR_EQUALS(stringified, "{\n \"x\": 1,\n \"z\": [\n 2,\n \"3\xE2\x98\xBA\xEF\xBF\xBD\"\n ],\n \"y\": true\n}");
|
||||
|
||||
val = script.ParseJSON(stringified);
|
||||
script.ParseJSON(stringified, &val);
|
||||
TS_ASSERT_WSTR_EQUALS(script.ToString(val.get()), L"({x:1, z:[2, \"3\\u263A\\uFFFD\"], y:true})");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -724,7 +724,12 @@ CScriptValRooted CSimulation2::GetInitAttributes()
|
||||
|
||||
void CSimulation2::SetMapSettings(const std::string& settings)
|
||||
{
|
||||
m->m_MapSettings = m->m_ComponentManager.GetScriptInterface().ParseJSON(settings);
|
||||
JSContext* cx = m->m_ComponentManager.GetScriptInterface().GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
JS::RootedValue tmpMapSettings(cx);
|
||||
m->m_ComponentManager.GetScriptInterface().ParseJSON(settings, &tmpMapSettings);
|
||||
m->m_MapSettings = CScriptValRooted(cx, tmpMapSettings);
|
||||
}
|
||||
|
||||
void CSimulation2::SetMapSettings(const CScriptValRooted& settings)
|
||||
@@ -734,7 +739,11 @@ void CSimulation2::SetMapSettings(const CScriptValRooted& settings)
|
||||
|
||||
std::string CSimulation2::GetMapSettingsString()
|
||||
{
|
||||
return m->m_ComponentManager.GetScriptInterface().StringifyJSON(m->m_MapSettings.get());
|
||||
JSContext* cx = m->m_ComponentManager.GetScriptInterface().GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
// TODO: Check if this temporary root can be removed after SpiderMonkey 31 upgrade
|
||||
JS::RootedValue tmpMapSettings(cx, m->m_MapSettings.get());
|
||||
return m->m_ComponentManager.GetScriptInterface().StringifyJSON(&tmpMapSettings);
|
||||
}
|
||||
|
||||
CScriptVal CSimulation2::GetMapSettings()
|
||||
@@ -929,5 +938,5 @@ std::string CSimulation2::GetAIData()
|
||||
if (!scriptInterface.Eval("({})", &ais) || !scriptInterface.SetProperty(ais, "AIData", aiData))
|
||||
return std::string();
|
||||
|
||||
return scriptInterface.StringifyJSON(ais);
|
||||
return scriptInterface.StringifyJSON(&ais);
|
||||
}
|
||||
|
||||
@@ -100,7 +100,8 @@ private:
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
OsPath path = L"simulation/ai/" + m_AIName + L"/data.json";
|
||||
JS::RootedValue metadata(cx, m_Worker.LoadMetadata(path).get());
|
||||
JS::RootedValue metadata(cx);
|
||||
m_Worker.LoadMetadata(path, &metadata);
|
||||
if (metadata.isUndefined())
|
||||
{
|
||||
LOGERROR(L"Failed to create AI player: can't find %ls", path.string().c_str());
|
||||
@@ -741,15 +742,15 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
CScriptValRooted LoadMetadata(const VfsPath& path)
|
||||
void LoadMetadata(const VfsPath& path, JS::MutableHandleValue out)
|
||||
{
|
||||
if (m_PlayerMetadata.find(path) == m_PlayerMetadata.end())
|
||||
{
|
||||
// Load and cache the AI player metadata
|
||||
m_PlayerMetadata[path] = m_ScriptInterface->ReadJSONFile(path);
|
||||
m_ScriptInterface->ReadJSONFile(path, out);
|
||||
m_PlayerMetadata[path] = CScriptValRooted(m_ScriptInterface->GetContext(), out);
|
||||
}
|
||||
|
||||
return m_PlayerMetadata[path];
|
||||
out.set(m_PlayerMetadata[path].get());
|
||||
}
|
||||
|
||||
void PerformComputation()
|
||||
|
||||
@@ -89,12 +89,16 @@ public:
|
||||
m_LocalQueue.push_back(c);
|
||||
}
|
||||
|
||||
virtual void PostNetworkCommand(CScriptVal cmd)
|
||||
virtual void PostNetworkCommand(CScriptVal cmd1)
|
||||
{
|
||||
JSContext* cx = GetSimContext().GetScriptInterface().GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
// TODO: With ESR31 we should be able to take JS::HandleValue directly
|
||||
JS::RootedValue cmd(cx, cmd1.get());
|
||||
|
||||
PROFILE2_EVENT("post net command");
|
||||
PROFILE2_ATTR("command: %s", GetSimContext().GetScriptInterface().StringifyJSON(cmd.get(), false).c_str());
|
||||
PROFILE2_ATTR("command: %s", GetSimContext().GetScriptInterface().StringifyJSON(&cmd, false).c_str());
|
||||
|
||||
// TODO: would be nicer to not use globals
|
||||
if (g_Game && g_Game->GetTurnManager())
|
||||
|
||||
@@ -60,9 +60,11 @@ public:
|
||||
std::wstring dirname = GetWstringFromWpath(*it);
|
||||
|
||||
JS::RootedValue ai(cx);
|
||||
JS::RootedValue data(cx);
|
||||
self->m_ScriptInterface.ReadJSONFile(pathname, &data);
|
||||
self->m_ScriptInterface.Eval("({})", &ai);
|
||||
self->m_ScriptInterface.SetProperty(ai, "id", dirname, true);
|
||||
self->m_ScriptInterface.SetProperty(ai, "data", self->m_ScriptInterface.ReadJSONFile(pathname), true);
|
||||
self->m_ScriptInterface.SetProperty(ai, "data", data, true);
|
||||
self->m_AIs.push_back(CScriptValRooted(cx, ai));
|
||||
|
||||
return INFO::OK;
|
||||
|
||||
@@ -1147,13 +1147,16 @@ CScriptVal CComponentManager::Script_ReadCivJSONFile(ScriptInterface::CxPrivate*
|
||||
return ReadJSONFile(pCxPrivate, L"civs", fileName);
|
||||
}
|
||||
|
||||
CScriptVal CComponentManager::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring filePath, std::wstring fileName)
|
||||
JS::Value CComponentManager::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring filePath, std::wstring fileName)
|
||||
{
|
||||
CComponentManager* componentManager = static_cast<CComponentManager*> (pCxPrivate->pCBData);
|
||||
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
VfsPath path = VfsPath(filePath) / fileName;
|
||||
|
||||
return componentManager->GetScriptInterface().ReadJSONFile(path).get();
|
||||
JS::RootedValue out(cx);
|
||||
componentManager->GetScriptInterface().ReadJSONFile(path, &out);
|
||||
return out.get();
|
||||
}
|
||||
|
||||
Status CComponentManager::FindJSONFilesCallback(const VfsPath& pathname, const CFileInfo& UNUSED(fileInfo), const uintptr_t cbData)
|
||||
|
||||
@@ -286,7 +286,7 @@ private:
|
||||
static CScriptVal Script_ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring fileName);
|
||||
static CScriptVal Script_ReadCivJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring fileName);
|
||||
static std::vector<std::string> Script_FindJSONFiles(ScriptInterface::CxPrivate* pCxPrivate, std::wstring subPath, bool recursive);
|
||||
static CScriptVal ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring filePath, std::wstring fileName);
|
||||
static JS::Value ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, std::wstring filePath, std::wstring fileName);
|
||||
|
||||
// callback function to handle recursively finding files in a directory
|
||||
static Status FindJSONFilesCallback(const VfsPath&, const CFileInfo&, const uintptr_t);
|
||||
|
||||
@@ -91,7 +91,8 @@ QUERYHANDLER(GenerateMap)
|
||||
JSContext* cx = scriptInterface.GetContext();
|
||||
JSAutoRequest rq(cx);
|
||||
|
||||
JS::RootedValue settings(cx, scriptInterface.ParseJSON(*msg->settings).get());
|
||||
JS::RootedValue settings(cx);
|
||||
scriptInterface.ParseJSON(*msg->settings, &settings);
|
||||
|
||||
JS::RootedValue attrs(cx);
|
||||
scriptInterface.Eval("({})", &attrs);
|
||||
|
||||
Reference in New Issue
Block a user