Provide ScriptInterface CreateObject and CreateArray functions to replace Eval calls following 7c2e9027c2, 1c0536bf08 and later.

Differential Revision: https://code.wildfiregames.com/D2080
Previous version reviewed By: Krinkle
Comments By: historic_bruno, wraitii
This was SVN commit r22528.
This commit is contained in:
elexis 2019-07-22 19:35:14 +00:00
parent 6643613b54
commit b4626359f5
23 changed files with 316 additions and 192 deletions

View file

@ -398,10 +398,13 @@ JS::Value CMapGeneratorWorker::LoadMapTerrain(ScriptInterface::CxPrivate* pCxPri
}
}
JS::RootedValue returnValue(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
self->m_ScriptInterface->SetProperty(returnValue, "height", heightmap);
self->m_ScriptInterface->SetProperty(returnValue, "textureNames", textureNames);
self->m_ScriptInterface->SetProperty(returnValue, "textureIDs", textureIDs);
JS::RootedValue returnValue(cx);
self->m_ScriptInterface->CreateObject(
&returnValue,
"height", heightmap,
"textureNames", textureNames,
"textureIDs", textureIDs);
return returnValue;
}

View file

@ -372,7 +372,8 @@ void CMapSummaryReader::GetMapSettings(const ScriptInterface& scriptInterface, J
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("({})", ret);
scriptInterface.CreateObject(ret);
if (m_ScriptSettings.empty())
return;

View file

@ -459,10 +459,12 @@ void IGUIObject::ScriptEvent(const CStr& Action)
// Set up the 'mouse' parameter
JS::RootedValue mouse(cx);
m_pGUI->GetScriptInterface()->Eval("({})", &mouse);
m_pGUI->GetScriptInterface()->SetProperty(mouse, "x", m_pGUI->m_MousePos.x, false);
m_pGUI->GetScriptInterface()->SetProperty(mouse, "y", m_pGUI->m_MousePos.y, false);
m_pGUI->GetScriptInterface()->SetProperty(mouse, "buttons", m_pGUI->m_MouseButtons, false);
m_pGUI->GetScriptInterface()->CreateObject(
&mouse,
"x", m_pGUI->m_MousePos.x,
"y", m_pGUI->m_MousePos.y,
"buttons", m_pGUI->m_MouseButtons);
JS::AutoValueVector paramData(cx);
paramData.append(mouse);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -243,9 +243,7 @@ void CMiniMap::FireWorldClickEvent(int UNUSED(button), int UNUSED(clicks))
GetMouseWorldCoordinates(x, z);
JS::RootedValue coords(cx);
g_GUI->GetActiveGUI()->GetScriptInterface()->Eval("({})", &coords);
g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(coords, "x", x, false);
g_GUI->GetActiveGUI()->GetScriptInterface()->SetProperty(coords, "z", z, false);
g_GUI->GetActiveGUI()->GetScriptInterface()->CreateObject(&coords, "x", x, "z", z);
JS::AutoValueVector paramData(cx);
paramData.append(coords);

View file

@ -107,21 +107,16 @@ bool JSI_IGUIObject::getProperty(JSContext* cx, JS::HandleObject obj, JS::Handle
}
else if (propName == "children")
{
JS::RootedObject obj(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty()));
vp.setObject(*obj);
pScriptInterface->CreateArray(vp);
for (size_t i = 0; i < e->m_Children.size(); ++i)
{
JS::RootedValue val(cx);
ScriptInterface::ToJSVal(cx, &val, e->m_Children[i]);
JS_SetElement(cx, obj, i, val);
}
pScriptInterface->SetPropertyInt(vp, i, e->m_Children[i]);
return true;
}
else if (propName == "name")
{
vp.set(JS::StringValue(JS_NewStringCopyZ(cx, e->GetName().c_str())));
ScriptInterface::ToJSVal(cx, vp, e->GetName());
return true;
}
else
@ -741,12 +736,13 @@ bool JSI_IGUIObject::getTextSize(JSContext* cx, uint argc, JS::Value* vp)
GUI<float>::GetSetting(obj, "buffer_zone", buffer_zone);
SGUIText text = obj->GetGUI()->GenerateText(caption, font, width, buffer_zone, obj);
JS::RootedValue objVal(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
JS::RootedValue objVal(cx);
try
{
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
pScriptInterface->SetProperty(objVal, "width", text.m_Size.cx, false, true);
pScriptInterface->SetProperty(objVal, "height", text.m_Size.cy, false, true);
ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject(
&objVal,
"width", text.m_Size.cx,
"height", text.m_Size.cy);
}
catch (PSERROR_Scripting_ConversionFailed&)
{
@ -772,14 +768,15 @@ bool JSI_IGUIObject::getComputedSize(JSContext* cx, uint UNUSED(argc), JS::Value
e->UpdateCachedSize();
CRect size = e->m_CachedActualSize;
JS::RootedValue objVal(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
JS::RootedValue objVal(cx);
try
{
ScriptInterface* pScriptInterface = ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface;
pScriptInterface->SetProperty(objVal, "left", size.left, false, true);
pScriptInterface->SetProperty(objVal, "right", size.right, false, true);
pScriptInterface->SetProperty(objVal, "top", size.top, false, true);
pScriptInterface->SetProperty(objVal, "bottom", size.bottom, false, true);
ScriptInterface::GetScriptInterfaceAndCBData(cx)->pScriptInterface->CreateObject(
&objVal,
"left", size.left,
"right", size.right,
"top", size.top,
"bottom", size.bottom);
}
catch (PSERROR_Scripting_ConversionFailed&)
{

View file

@ -503,18 +503,21 @@ void XmppClient::GUIGetPlayerList(const ScriptInterface& scriptInterface, JS::Mu
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("([])", ret);
scriptInterface.CreateArray(ret);
int j = 0;
// Convert the internal data structure to a Javascript object.
for (const std::pair<std::string, std::vector<std::string> >& p : m_PlayerMap)
{
JS::RootedValue player(cx);
scriptInterface.Eval("({})", &player);
scriptInterface.SetProperty(player, "name", wstring_from_utf8(p.first));
scriptInterface.SetProperty(player, "presence", wstring_from_utf8(p.second[0]));
scriptInterface.SetProperty(player, "rating", wstring_from_utf8(p.second[1]));
scriptInterface.SetProperty(player, "role", wstring_from_utf8(p.second[2]));
scriptInterface.CallFunctionVoid(ret, "push", player);
scriptInterface.CreateObject(
&player,
"name", wstring_from_utf8(p.first),
"presence", wstring_from_utf8(p.second[0]),
"rating", wstring_from_utf8(p.second[1]),
"role", wstring_from_utf8(p.second[2]));
scriptInterface.SetPropertyInt(ret, j++, player);
}
}
@ -528,19 +531,22 @@ void XmppClient::GUIGetGameList(const ScriptInterface& scriptInterface, JS::Muta
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("([])", ret);
scriptInterface.CreateArray(ret);
int j = 0;
const char* stats[] = { "name", "ip", "port", "stunIP", "stunPort", "hostUsername", "state",
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType",
"victoryCondition", "startTime", "mods" };
for(const glooxwrapper::Tag* const& t : m_GameList)
{
JS::RootedValue game(cx);
scriptInterface.Eval("({})", &game);
scriptInterface.CreateObject(&game);
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
scriptInterface.SetProperty(game, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string()));
scriptInterface.CallFunctionVoid(ret, "push", game);
scriptInterface.SetPropertyInt(ret, j++, game);
}
}
@ -554,17 +560,20 @@ void XmppClient::GUIGetBoardList(const ScriptInterface& scriptInterface, JS::Mut
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("([])", ret);
scriptInterface.CreateArray(ret);
int j = 0;
const char* attributes[] = { "name", "rank", "rating" };
for(const glooxwrapper::Tag* const& t : m_BoardList)
{
JS::RootedValue board(cx);
scriptInterface.Eval("({})", &board);
scriptInterface.CreateObject(&board);
for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i)
scriptInterface.SetProperty(board, attributes[i], wstring_from_utf8(t->findAttribute(attributes[i]).to_string()));
scriptInterface.CallFunctionVoid(ret, "push", board);
scriptInterface.SetPropertyInt(ret, j++, board);
}
}
@ -578,17 +587,20 @@ void XmppClient::GUIGetProfile(const ScriptInterface& scriptInterface, JS::Mutab
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("([])", ret);
scriptInterface.CreateArray(ret);
int j = 0;
const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" };
for (const glooxwrapper::Tag* const& t : m_Profile)
{
JS::RootedValue profile(cx);
scriptInterface.Eval("({})", &profile);
scriptInterface.CreateObject(&profile);
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
scriptInterface.SetProperty(profile, stats[i], wstring_from_utf8(t->findAttribute(stats[i]).to_string()));
scriptInterface.CallFunctionVoid(ret, "push", profile);
scriptInterface.SetPropertyInt(ret, j++, profile);
}
}
@ -621,16 +633,22 @@ JS::Value XmppClient::GuiMessageToJSVal(const ScriptInterface& scriptInterface,
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue ret(cx);
scriptInterface.Eval("({})", &ret);
scriptInterface.SetProperty(ret, "type", wstring_from_utf8(message.type));
scriptInterface.CreateObject(
&ret,
"type", wstring_from_utf8(message.type),
"time", static_cast<double>(message.time),
"historic", historic);
if (!message.level.empty())
scriptInterface.SetProperty(ret, "level", wstring_from_utf8(message.level));
if (!message.property1_name.empty())
scriptInterface.SetProperty(ret, message.property1_name.c_str(), wstring_from_utf8(message.property1_value));
if (!message.property2_name.empty())
scriptInterface.SetProperty(ret, message.property2_name.c_str(), wstring_from_utf8(message.property2_value));
scriptInterface.SetProperty(ret, "time", (double)message.time);
scriptInterface.SetProperty(ret, "historic", historic);
return ret;
}
@ -653,15 +671,17 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& scriptInter
{
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedObject ret(cx, JS_NewArrayObject(cx, 0));
uint32_t i = 0;
JS::RootedValue ret(cx);
scriptInterface.CreateArray(&ret);
int j = 0;
for (const GUIMessage& message : m_HistoricGuiMessages)
{
JS::RootedValue msg(cx, GuiMessageToJSVal(scriptInterface, message, true));
JS_SetElement(cx, ret, i++, msg);
scriptInterface.SetPropertyInt(ret, j++, msg);
}
return JS::ObjectValue(*ret);
return ret;
}
/**

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -295,11 +295,14 @@ void CNetClient::PostPlayerAssignmentsToScript()
for (const std::pair<CStr, PlayerAssignment>& p : m_PlayerAssignments)
{
JS::RootedValue assignment(cx);
GetScriptInterface().Eval("({})", &assignment);
GetScriptInterface().SetProperty(assignment, "name", CStrW(p.second.m_Name), false);
GetScriptInterface().SetProperty(assignment, "player", p.second.m_PlayerID, false);
GetScriptInterface().SetProperty(assignment, "status", p.second.m_Status, false);
GetScriptInterface().SetProperty(newAssignments, p.first.c_str(), assignment, false);
GetScriptInterface().CreateObject(
&assignment,
"name", CStrW(p.second.m_Name),
"player", p.second.m_PlayerID,
"status", p.second.m_Status);
GetScriptInterface().SetProperty(newAssignments, p.first.c_str(), assignment);
}
PushGuiMessage(msg);
@ -760,10 +763,12 @@ bool CNetClient::OnKicked(void *context, CFsmEvent* event)
CKickedMessage* message = (CKickedMessage*)event->GetParamRef();
JS::RootedValue msg(cx);
client->GetScriptInterface().Eval("({})", &msg);
client->GetScriptInterface().SetProperty(msg, "username", message->m_Name);
client->GetScriptInterface().SetProperty(msg, "type", CStr("kicked"));
client->GetScriptInterface().SetProperty(msg, "banned", message->m_Ban != 0);
client->GetScriptInterface().CreateObject(
&msg,
"username", message->m_Name,
"type", CStr("kicked"),
"banned", message->m_Ban != 0);
client->PushGuiMessage(msg);
return true;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -147,12 +147,16 @@ void CNetClientTurnManager::OnSyncError(u32 turn, const CStr& expectedHash, cons
JSAutoRequest rq(cx);
JS::RootedValue msg(cx);
scriptInterface.Eval("({ 'type':'out-of-sync' })", &msg);
scriptInterface.SetProperty(msg, "turn", turn);
scriptInterface.SetProperty(msg, "players", playerNamesStrings);
scriptInterface.SetProperty(msg, "expectedHash", expectedHashHex);
scriptInterface.SetProperty(msg, "hash", Hexify(hash));
scriptInterface.SetProperty(msg, "path_oos_dump", wstring_from_utf8(oosdumpPath.string8()));
scriptInterface.SetProperty(msg, "path_replay", wstring_from_utf8(m_Replay.GetDirectory().string8()));
scriptInterface.CreateObject(
&msg,
"type", std::wstring(L"out-of-sync"),
"turn", turn,
"players", playerNamesStrings,
"expectedHash", expectedHashHex,
"hash", Hexify(hash),
"path_oos_dump", wstring_from_utf8(oosdumpPath.string8()),
"path_replay", wstring_from_utf8(m_Replay.GetDirectory().string8()));
m_NetClient.PushGuiMessage(msg);
}

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* Copyright (C) 2013-2016 SuperTuxKart-Team.
* This file is part of 0 A.D.
*
@ -392,9 +392,7 @@ JS::Value StunClient::FindStunEndpointHost(const ScriptInterface& scriptInterfac
JSAutoRequest rq(cx);
JS::RootedValue stunEndpoint(cx);
scriptInterface.Eval("({})", &stunEndpoint);
scriptInterface.SetProperty(stunEndpoint, "ip", CStr(ipStr));
scriptInterface.SetProperty(stunEndpoint, "port", m_Port);
scriptInterface.CreateObject(&stunEndpoint, "ip", CStr(ipStr), "port", m_Port);
return stunEndpoint;
}

View file

@ -524,20 +524,21 @@ void InitPsAutostart(bool networked, JS::HandleValue attrs)
JSAutoRequest rq(cx);
JS::RootedValue playerAssignments(cx);
scriptInterface.Eval("({})", &playerAssignments);
scriptInterface.CreateObject(&playerAssignments);
if (!networked)
{
JS::RootedValue localPlayer(cx);
scriptInterface.Eval("({})", &localPlayer);
scriptInterface.SetProperty(localPlayer, "player", g_Game->GetPlayerID());
scriptInterface.CreateObject(&localPlayer, "player", g_Game->GetPlayerID());
scriptInterface.SetProperty(playerAssignments, "local", localPlayer);
}
JS::RootedValue sessionInitData(cx);
scriptInterface.Eval("({})", &sessionInitData);
scriptInterface.SetProperty(sessionInitData, "attribs", attrs);
scriptInterface.SetProperty(sessionInitData, "playerAssignments", playerAssignments);
scriptInterface.CreateObject(
&sessionInitData,
"attribs", attrs,
"playerAssignments", playerAssignments);
InitPs(true, L"page_loading.xml", &scriptInterface, sessionInitData);
}
@ -1107,7 +1108,7 @@ void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& i
JS::RootedValue data(cx);
if (g_GUI)
{
scriptInterface->Eval("({})", &data);
scriptInterface->CreateObject(&data);
scriptInterface->SetProperty(data, "isStartup", true);
if (!installedMods.empty())
scriptInterface->SetProperty(data, "installedMods", installedMods);
@ -1268,11 +1269,12 @@ bool Autostart(const CmdLineArgs& args)
JSAutoRequest rq(cx);
JS::RootedValue attrs(cx);
scriptInterface.Eval("({})", &attrs);
JS::RootedValue settings(cx);
scriptInterface.Eval("({})", &settings);
JS::RootedValue playerData(cx);
scriptInterface.Eval("([])", &playerData);
scriptInterface.CreateObject(&attrs);
scriptInterface.CreateObject(&settings);
scriptInterface.CreateArray(&playerData);
// The directory in front of the actual map name indicates which type
// of map is being loaded. Drawback of this approach is the association
@ -1325,11 +1327,11 @@ bool Autostart(const CmdLineArgs& args)
for (size_t i = 0; i < numPlayers; ++i)
{
JS::RootedValue player(cx);
scriptInterface.Eval("({})", &player);
// We could load player_defaults.json here, but that would complicate the logic
// even more and autostart is only intended for developers anyway
scriptInterface.SetProperty(player, "Civ", std::string("athen"));
scriptInterface.CreateObject(&player, "Civ", std::string("athen"));
scriptInterface.SetPropertyInt(playerData, i, player);
}
mapType = "random";
@ -1412,7 +1414,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-team option", playerID);
continue;
}
scriptInterface.Eval("({})", &player);
scriptInterface.CreateObject(&player);
}
int teamID = civArgs[i].AfterFirst(":").ToInt() - 1;
@ -1443,7 +1445,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-ai option", playerID);
continue;
}
scriptInterface.Eval("({})", &player);
scriptInterface.CreateObject(&player);
}
CStr name = aiArgs[i].AfterFirst(":");
@ -1471,7 +1473,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-aidiff option", playerID);
continue;
}
scriptInterface.Eval("({})", &player);
scriptInterface.CreateObject(&player);
}
int difficulty = civArgs[i].AfterFirst(":").ToInt();
@ -1499,7 +1501,7 @@ bool Autostart(const CmdLineArgs& args)
LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID);
continue;
}
scriptInterface.Eval("({})", &player);
scriptInterface.CreateObject(&player);
}
CStr name = civArgs[i].AfterFirst(":");

View file

@ -75,20 +75,25 @@ void ConvertCaches(const ScriptInterface& scriptInterface, x86_x64::IdxCache idx
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("[]", ret);
scriptInterface.CreateArray(ret);
for (size_t idxLevel = 0; idxLevel < x86_x64::Cache::maxLevels; ++idxLevel)
{
const x86_x64::Cache* pcache = x86_x64::Caches(idxCache+idxLevel);
if (pcache->m_Type == x86_x64::Cache::kNull || pcache->m_NumEntries == 0)
continue;
JS::RootedValue cache(cx);
scriptInterface.Eval("({})", &cache);
scriptInterface.SetProperty(cache, "type", static_cast<u32>(pcache->m_Type));
scriptInterface.SetProperty(cache, "level", static_cast<u32>(pcache->m_Level));
scriptInterface.SetProperty(cache, "associativity", static_cast<u32>(pcache->m_Associativity));
scriptInterface.SetProperty(cache, "linesize", static_cast<u32>(pcache->m_EntrySize));
scriptInterface.SetProperty(cache, "sharedby", static_cast<u32>(pcache->m_SharedBy));
scriptInterface.SetProperty(cache, "totalsize",static_cast<u32>(pcache->TotalSize()));
scriptInterface.CreateObject(
&cache,
"type", static_cast<u32>(pcache->m_Type),
"level", static_cast<u32>(pcache->m_Level),
"associativity", static_cast<u32>(pcache->m_Associativity),
"linesize", static_cast<u32>(pcache->m_EntrySize),
"sharedby", static_cast<u32>(pcache->m_SharedBy),
"totalsize", static_cast<u32>(pcache->TotalSize()));
scriptInterface.SetPropertyInt(ret, idxLevel, cache);
}
}
@ -98,19 +103,24 @@ void ConvertTLBs(const ScriptInterface& scriptInterface, JS::MutableHandleValue
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
scriptInterface.Eval("[]", ret);
scriptInterface.CreateArray(ret);
for(size_t i = 0; ; i++)
{
const x86_x64::Cache* ptlb = x86_x64::Caches(x86_x64::TLB+i);
if (!ptlb)
break;
JS::RootedValue tlb(cx);
scriptInterface.Eval("({})", &tlb);
scriptInterface.SetProperty(tlb, "type", static_cast<u32>(ptlb->m_Type));
scriptInterface.SetProperty(tlb, "level", static_cast<u32>(ptlb->m_Level));
scriptInterface.SetProperty(tlb, "associativity", static_cast<u32>(ptlb->m_Associativity));
scriptInterface.SetProperty(tlb, "pagesize", static_cast<u32>(ptlb->m_EntrySize));
scriptInterface.SetProperty(tlb, "entries", static_cast<u32>(ptlb->m_NumEntries));
scriptInterface.CreateObject(
&tlb,
"type", static_cast<u32>(ptlb->m_Type),
"level", static_cast<u32>(ptlb->m_Level),
"associativity", static_cast<u32>(ptlb->m_Associativity),
"pagesize", static_cast<u32>(ptlb->m_EntrySize),
"entries", static_cast<u32>(ptlb->m_NumEntries));
scriptInterface.SetPropertyInt(ret, i, tlb);
}
}
@ -234,7 +244,7 @@ void RunHardwareDetection()
// includes some fields that aren't directly useful for the hwdetect script)
JS::RootedValue settings(cx);
scriptInterface.Eval("({})", &settings);
scriptInterface.CreateObject(&settings);
scriptInterface.SetProperty(settings, "os_unix", OS_UNIX);
scriptInterface.SetProperty(settings, "os_bsd", OS_BSD);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -143,11 +143,13 @@ JS::Value Mod::GetEngineInfo(const ScriptInterface& scriptInterface)
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue metainfo(cx);
JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(scriptInterface));
scriptInterface.Eval("({})", &metainfo);
scriptInterface.SetProperty(metainfo, "engine_version", std::string(engine_version));
scriptInterface.SetProperty(metainfo, "mods", mods);
JS::RootedValue metainfo(cx);
scriptInterface.CreateObject(
&metainfo,
"engine_version", std::string(engine_version),
"mods", mods);
scriptInterface.FreezeObject(metainfo, true);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -531,14 +531,15 @@ namespace
JSAutoRequest rq(cx);
JS::RootedValue data(cx);
m_ScriptInterface.Eval("({})", &data);
m_ScriptInterface.CreateObject(&data);
const std::vector<ProfileColumn>& columns = table->GetColumns();
for (size_t r = 0; r < table->GetNumberRows(); ++r)
{
JS::RootedValue row(cx);
m_ScriptInterface.Eval("([])", &row);
m_ScriptInterface.CreateArray(&row);
m_ScriptInterface.SetProperty(data, table->GetCellText(r, 0).c_str(), row);
if (table->GetChild(r))

View file

@ -79,33 +79,40 @@ Status SavedGames::Save(const CStrW& name, const CStrW& description, CSimulation
if (!simulation.SerializeState(simStateStream))
WARN_RETURN(ERR::FAIL);
JS::RootedValue metadata(cx);
JS::RootedValue initAttributes(cx, simulation.GetInitAttributes());
JS::RootedValue mods(cx, Mod::GetLoadedModsWithVersions(simulation.GetScriptInterface()));
simulation.GetScriptInterface().Eval("({})", &metadata);
simulation.GetScriptInterface().SetProperty(metadata, "engine_version", std::string(engine_version));
simulation.GetScriptInterface().SetProperty(metadata, "mods", mods);
simulation.GetScriptInterface().SetProperty(metadata, "time", (double)now);
simulation.GetScriptInterface().SetProperty(metadata, "playerID", g_Game->GetPlayerID());
simulation.GetScriptInterface().SetProperty(metadata, "initAttributes", initAttributes);
JS::RootedValue metadata(cx);
simulation.GetScriptInterface().CreateObject(
&metadata,
"engine_version", std::string(engine_version),
"time", static_cast<double>(now),
"playerID", g_Game->GetPlayerID(),
"mods", mods,
"initAttributes", initAttributes);
JS::RootedValue guiMetadata(cx);
simulation.GetScriptInterface().ReadStructuredClone(guiMetadataClone, &guiMetadata);
// get some camera data
JS::RootedValue cameraMetadata(cx);
simulation.GetScriptInterface().Eval("({})", &cameraMetadata);
const CVector3D cameraPosition = g_Game->GetView()->GetCameraPosition();
simulation.GetScriptInterface().SetProperty(cameraMetadata, "PosX", cameraPosition.X);
simulation.GetScriptInterface().SetProperty(cameraMetadata, "PosY", cameraPosition.Y);
simulation.GetScriptInterface().SetProperty(cameraMetadata, "PosZ", cameraPosition.Z);
const CVector3D cameraRotation = g_Game->GetView()->GetCameraRotation();
simulation.GetScriptInterface().SetProperty(cameraMetadata, "RotX", cameraRotation.X);
simulation.GetScriptInterface().SetProperty(cameraMetadata, "RotY", cameraRotation.Y);
simulation.GetScriptInterface().SetProperty(cameraMetadata, "Zoom", g_Game->GetView()->GetCameraZoom());
simulation.GetScriptInterface().SetProperty(guiMetadata, "camera", cameraMetadata);
simulation.GetScriptInterface().SetProperty(metadata, "gui", guiMetadata);
JS::RootedValue cameraMetadata(cx);
simulation.GetScriptInterface().CreateObject(
&cameraMetadata,
"PosX", cameraPosition.X,
"PosY", cameraPosition.Y,
"PosZ", cameraPosition.Z,
"RotX", cameraRotation.X,
"RotY", cameraRotation.Y,
"Zoom", g_Game->GetView()->GetCameraZoom());
simulation.GetScriptInterface().SetProperty(guiMetadata, "camera", cameraMetadata);
simulation.GetScriptInterface().SetProperty(metadata, "gui", guiMetadata);
simulation.GetScriptInterface().SetProperty(metadata, "description", description);
std::string metadataString = simulation.GetScriptInterface().StringifyJSON(&metadata, true);
@ -225,7 +232,8 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedObject games(cx, JS_NewArrayObject(cx, 0));
JS::RootedValue games(cx);
scriptInterface.CreateArray(&games);
Status err;
@ -261,13 +269,15 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
JS::RootedValue metadata(cx, loader.GetMetadata());
JS::RootedValue game(cx);
scriptInterface.Eval("({})", &game);
scriptInterface.SetProperty(game, "id", pathnames[i].Basename());
scriptInterface.SetProperty(game, "metadata", metadata);
JS_SetElement(cx, games, i, game);
scriptInterface.CreateObject(
&game,
"id", pathnames[i].Basename(),
"metadata", metadata);
scriptInterface.SetPropertyInt(games, i, game);
}
return JS::ObjectValue(*games);
return games;
}
bool SavedGames::DeleteSavedGame(const std::wstring& name)

View file

@ -189,9 +189,11 @@ JS::HandleObject VisualReplay::ReloadReplayCache(const ScriptInterface& scriptIn
continue;
CFileInfo fileInfo;
GetFileInfo(replayFile, &fileInfo);
scriptInterface.Eval("({})", &replayData);
scriptInterface.SetProperty(replayData, "directory", directory.string());
scriptInterface.SetProperty(replayData, "fileSize", (double)fileInfo.Size());
scriptInterface.CreateObject(
&replayData,
"directory", directory.string(),
"fileSize", static_cast<double>(fileInfo.Size()));
}
JS_SetElement(cx, replays, i++, replayData);
newReplays = true;
@ -232,7 +234,9 @@ JS::Value VisualReplay::GetReplays(const ScriptInterface& scriptInterface, bool
JSAutoRequest rq(cx);
JS::RootedObject replays(cx, ReloadReplayCache(scriptInterface, compareFiles));
// Only take entries with data
JS::RootedObject replaysWithoutNullEntries(cx, JS_NewArrayObject(cx, 0));
JS::RootedValue replaysWithoutNullEntries(cx);
scriptInterface.CreateArray(&replaysWithoutNullEntries);
u32 replaysLength = 0;
JS_GetArrayLength(cx, replays, &replaysLength);
for (u32 j = 0, i = 0; j < replaysLength; ++j)
@ -240,9 +244,9 @@ JS::Value VisualReplay::GetReplays(const ScriptInterface& scriptInterface, bool
JS::RootedValue replay(cx);
JS_GetElement(cx, replays, j, &replay);
if (scriptInterface.HasProperty(replay, "attribs"))
JS_SetElement(cx, replaysWithoutNullEntries, i++, replay);
scriptInterface.SetPropertyInt(replaysWithoutNullEntries, i++, replay);
}
return JS::ObjectValue(*replaysWithoutNullEntries);
return replaysWithoutNullEntries;
}
/**
@ -400,11 +404,15 @@ JS::Value VisualReplay::LoadReplayData(const ScriptInterface& scriptInterface, c
// Return the actual data
JS::RootedValue replayData(cx);
scriptInterface.Eval("({})", &replayData);
scriptInterface.SetProperty(replayData, "directory", directory.string());
scriptInterface.SetProperty(replayData, "fileSize", (double)fileSize);
scriptInterface.CreateObject(
&replayData,
"directory", directory.string(),
"fileSize", static_cast<double>(fileSize),
"duration", static_cast<u32>(duration));
scriptInterface.SetProperty(replayData, "attribs", attribs);
scriptInterface.SetProperty(replayData, "duration", duration);
return replayData;
}
@ -423,7 +431,7 @@ JS::Value VisualReplay::GetReplayAttributes(ScriptInterface::CxPrivate* pCxPriva
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue attribs(cx);
pCxPrivate->pScriptInterface->Eval("({})", &attribs);
pCxPrivate->pScriptInterface->CreateObject(&attribs);
// Return empty object if file doesn't exist
const OsPath replayFile = GetDirectoryPath() / directoryName / L"commands.txt";

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -91,23 +91,23 @@ JS::Value JSI_ModIo::GetMods(ScriptInterface::CxPrivate* pCxPrivate)
const std::vector<ModIoModData>& availableMods = g_ModIo->GetMods();
JS::RootedObject mods(cx, JS_NewArrayObject(cx, availableMods.size()));
if (!mods)
return JS::NullValue();
JS::RootedValue mods(cx);
scriptInterface->CreateArray(&mods, availableMods.size());
u32 i = 0;
for (const ModIoModData& mod : availableMods)
{
JS::RootedValue m(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
JS::RootedValue m(cx);
scriptInterface->CreateObject(&m);
for (const std::pair<std::string, std::string>& prop : mod.properties)
scriptInterface->SetProperty(m, prop.first.c_str(), prop.second, true);
scriptInterface->SetProperty(m, "dependencies", mod.dependencies, true);
JS_SetElement(cx, mods, i++, m);
scriptInterface->SetPropertyInt(mods, i++, m);
}
return JS::ObjectValue(*mods);
return mods;
}
const std::map<DownloadProgressStatus, std::string> statusStrings = {
@ -136,9 +136,10 @@ JS::Value JSI_ModIo::GetDownloadProgress(ScriptInterface::CxPrivate* pCxPrivate)
JSContext* cx = scriptInterface->GetContext();
JSAutoRequest rq(cx);
JS::RootedValue progressData(cx, JS::ObjectValue(*JS_NewPlainObject(cx)));
const DownloadProgressData& progress = g_ModIo->GetDownloadProgress();
JS::RootedValue progressData(cx);
scriptInterface->CreateObject(&progressData);
scriptInterface->SetProperty(progressData, "status", statusStrings.at(progress.status), true);
scriptInterface->SetProperty(progressData, "progress", progress.progress, true);
scriptInterface->SetProperty(progressData, "error", progress.error, true);

View file

@ -152,7 +152,8 @@ JS::Value JSI_VFS::ReadFile(ScriptInterface::CxPrivate* pCxPrivate, const std::w
// Return file contents as an array of lines. Assume file is UTF-8 encoded text.
JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const std::wstring& filename)
{
JSContext* cx = pCxPrivate->pScriptInterface->GetContext();
const ScriptInterface& scriptInterface = *pCxPrivate->pScriptInterface;
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
CVFSFile file;
@ -166,7 +167,10 @@ JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const s
// split into array of strings (one per line)
std::stringstream ss(contents);
JS::RootedObject line_array(cx, JS_NewArrayObject(cx, JS::HandleValueArray::empty()));
JS::RootedValue line_array(cx);
scriptInterface.CreateArray(&line_array);
std::string line;
int cur_line = 0;
@ -175,10 +179,10 @@ JS::Value JSI_VFS::ReadFileLines(ScriptInterface::CxPrivate* pCxPrivate, const s
// Decode each line as UTF-8
JS::RootedValue val(cx);
ScriptInterface::ToJSVal(cx, &val, CStr(line).FromUTF8());
JS_SetElement(cx, line_array, cur_line++, val);
scriptInterface.SetPropertyInt(line_array, cur_line++, val);
}
return JS::ObjectValue(*line_array);
return line_array;
}
JS::Value JSI_VFS::ReadJSONFile(ScriptInterface::CxPrivate* pCxPrivate, const std::vector<CStrW>& validPaths, const CStrW& filePath)

View file

@ -579,6 +579,28 @@ bool ScriptInterface::CallFunction_(JS::HandleValue val, const char* name, JS::H
return ok;
}
bool ScriptInterface::CreateObject(JS::MutableHandleValue objectValue) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
objectValue.setObjectOrNull(JS_NewPlainObject(cx));
if (!objectValue.isObject())
throw PSERROR_Scripting_CreateObjectFailed();
return true;
}
void ScriptInterface::CreateArray(JS::MutableHandleValue objectValue, size_t length) const
{
JSContext* cx = GetContext();
JSAutoRequest rq(cx);
objectValue.setObjectOrNull(JS_NewArrayObject(cx, length));
if (!objectValue.isObject())
throw PSERROR_Scripting_CreateObjectFailed();
}
JS::Value ScriptInterface::GetGlobalObject() const
{
JSAutoRequest rq(m->m_cx);

View file

@ -131,6 +131,32 @@ public:
JSObject* CreateCustomObject(const std::string & typeName) const;
void DefineCustomObjectType(JSClass *clasp, JSNative constructor, uint minArgs, JSPropertySpec *ps, JSFunctionSpec *fs, JSPropertySpec *static_ps, JSFunctionSpec *static_fs);
/**
* Sets the given value to a new plain JS::Object. Can throw an exception in case of running out of memory.
*/
bool CreateObject(JS::MutableHandleValue objectValue) const;
/**
* Sets the given value to a new plain JS::Object, converts the arguments to JS::Values and sets them as properties.
* Can throw an exception.
*/
template<typename T, typename... Args>
bool CreateObject(JS::MutableHandleValue objectValue, const char* propertyName, const T& propertyValue, Args const&... args) const
{
return CreateObject(objectValue, args...) && SetProperty(objectValue, propertyName, propertyValue);
}
template<typename T, typename... Args>
bool CreateObject(JS::MutableHandleValue objectValue, const wchar_t* propertyName, const T& propertyValue, Args const&... args) const
{
return CreateObject(objectValue, args...) && SetProperty(objectValue, propertyName, propertyValue);
}
/**
* Sets the given value to a new JS object or Null Value in case of out-of-memory.
*/
void CreateArray(JS::MutableHandleValue objectValue, size_t length = 0) const;
JS::Value GetGlobalObject() const;
/**

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -982,7 +982,8 @@ std::string CSimulation2::GetAIData()
// Build single JSON string with array of AI data
JS::RootedValue ais(cx);
if (!scriptInterface.Eval("({})", &ais) || !scriptInterface.SetProperty(ais, "AIData", aiData))
if (!scriptInterface.CreateObject(&ais, "AIData", aiData))
return std::string();
return scriptInterface.StringifyJSON(&ais);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -630,7 +630,7 @@ public:
m_HasLoadedEntityTemplates = true;
m_ScriptInterface->Eval("({})", &m_EntityTemplates);
m_ScriptInterface->CreateObject(&m_EntityTemplates);
JS::RootedValue val(cx);
for (size_t i = 0; i < templates.size(); ++i)
@ -1183,7 +1183,7 @@ private:
JSAutoRequest rq(cx);
JS::RootedValue classesVal(cx);
scriptInterface.Eval("({})", &classesVal);
scriptInterface.CreateObject(&classesVal);
std::map<std::string, pass_class_t> classes;
cmpPathfinder->GetPassabilityClasses(classes);

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2017 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -64,9 +64,10 @@ public:
std::wstring dirname = GetWstringFromWpath(*it);
JS::RootedValue ai(cx);
self->m_ScriptInterface.CreateObject(&ai);
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", data, true);
u32 length;

View file

@ -1,4 +1,4 @@
/* Copyright (C) 2018 Wildfire Games.
/* Copyright (C) 2019 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -99,10 +99,11 @@ QUERYHANDLER(GenerateMap)
scriptInterface.SetProperty(settings, "mapType", std::string("random"));
JS::RootedValue attrs(cx);
scriptInterface.Eval("({})", &attrs);
scriptInterface.SetProperty(attrs, "mapType", std::string("random"));
scriptInterface.SetProperty(attrs, "script", std::wstring(*msg->filename));
scriptInterface.SetProperty(attrs, "settings", settings);
scriptInterface.CreateObject(
&attrs,
"mapType", std::string("random"),
"script", std::wstring(*msg->filename),
"settings", settings);
StartGame(&attrs);
@ -121,26 +122,31 @@ QUERYHANDLER(GenerateMap)
JSContext* cx = scriptInterface.GetContext();
JSAutoRequest rq(cx);
JS::RootedValue settings(cx);
scriptInterface.Eval("({})", &settings);
// Set up 8-element array of empty objects to satisfy init
JS::RootedValue playerData(cx);
scriptInterface.Eval("([])", &playerData);
scriptInterface.CreateArray(&playerData);
for (int i = 0; i < 8; ++i)
{
JS::RootedValue player(cx);
scriptInterface.Eval("({})", &player);
scriptInterface.CreateObject(&player);
scriptInterface.SetPropertyInt(playerData, i, player);
}
scriptInterface.SetProperty(settings, "mapType", std::string("scenario"));
scriptInterface.SetProperty(settings, "PlayerData", playerData);
JS::RootedValue atts(cx);
scriptInterface.Eval("({})", &atts);
scriptInterface.SetProperty(atts, "mapType", std::string("scenario"));
scriptInterface.SetProperty(atts, "map", std::wstring(L"maps/scenarios/_default"));
scriptInterface.SetProperty(atts, "settings", settings);
StartGame(&atts);
JS::RootedValue settings(cx);
scriptInterface.CreateObject(
&settings,
"mapType", std::string("scenario"),
"PlayerData", playerData);
JS::RootedValue attrs(cx);
scriptInterface.CreateObject(
&attrs,
"mapType", std::string("scenario"),
"map", std::wstring(L"maps/scenarios/_default"),
"settings", settings);
StartGame(&attrs);
msg->status = -1;
}
@ -159,9 +165,11 @@ MESSAGEHANDLER(LoadMap)
CStrW mapBase = map.BeforeLast(L".pmp"); // strip the file extension, if any
JS::RootedValue attrs(cx);
scriptInterface.Eval("({})", &attrs);
scriptInterface.SetProperty(attrs, "mapType", std::string("scenario"));
scriptInterface.SetProperty(attrs, "map", std::wstring(mapBase));
scriptInterface.CreateObject(
&attrs,
"mapType", std::string("scenario"),
"map", std::wstring(mapBase));
StartGame(&attrs);
}