Exact stack rooting for JSON related ScriptInterface functions.

Refs #2415
Refs #2462

This was SVN commit r15603.
This commit is contained in:
Yves
2014-08-02 22:21:50 +00:00
parent 15fa9e2c2e
commit a2bd44b23a
25 changed files with 151 additions and 79 deletions
+2 -1
View File
@@ -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");
+8 -2
View File
@@ -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);
+4 -2
View File
@@ -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)
+6 -2
View File
@@ -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
View File
@@ -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);
+17 -6
View File
@@ -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);
+2 -2
View File
@@ -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.
+12 -6
View File
@@ -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
View File
@@ -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);
}
+6 -8
View File
@@ -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);
+1 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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);
+7 -2
View File
@@ -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)
{
+2 -1
View File
@@ -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))
+14 -10
View File
@@ -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");
+5 -5
View File
@@ -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})");
}
};
+12 -3
View File
@@ -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)
+1 -1
View File
@@ -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);