Index: ps/trunk/source/graphics/MapGenerator.cpp =================================================================== --- ps/trunk/source/graphics/MapGenerator.cpp +++ ps/trunk/source/graphics/MapGenerator.cpp @@ -398,10 +398,13 @@ } } - 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; } Index: ps/trunk/source/graphics/MapReader.cpp =================================================================== --- ps/trunk/source/graphics/MapReader.cpp +++ ps/trunk/source/graphics/MapReader.cpp @@ -372,7 +372,8 @@ JSContext* cx = scriptInterface.GetContext(); JSAutoRequest rq(cx); - scriptInterface.Eval("({})", ret); + scriptInterface.CreateObject(ret); + if (m_ScriptSettings.empty()) return; Index: ps/trunk/source/gui/IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/IGUIObject.cpp +++ ps/trunk/source/gui/IGUIObject.cpp @@ -459,10 +459,12 @@ // 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); Index: ps/trunk/source/gui/MiniMap.cpp =================================================================== --- ps/trunk/source/gui/MiniMap.cpp +++ ps/trunk/source/gui/MiniMap.cpp @@ -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 @@ 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); Index: ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp =================================================================== --- ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp +++ ps/trunk/source/gui/scripting/JSInterface_IGUIObject.cpp @@ -107,21 +107,16 @@ } 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 @@ GUI::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 @@ 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&) { Index: ps/trunk/source/lobby/XmppClient.cpp =================================================================== --- ps/trunk/source/lobby/XmppClient.cpp +++ ps/trunk/source/lobby/XmppClient.cpp @@ -503,18 +503,21 @@ 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 >& 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 @@ 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 @@ 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 @@ 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 @@ 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(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 @@ { 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; } /** Index: ps/trunk/source/network/NetClient.cpp =================================================================== --- ps/trunk/source/network/NetClient.cpp +++ ps/trunk/source/network/NetClient.cpp @@ -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 @@ for (const std::pair& 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 @@ 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; Index: ps/trunk/source/network/NetClientTurnManager.cpp =================================================================== --- ps/trunk/source/network/NetClientTurnManager.cpp +++ ps/trunk/source/network/NetClientTurnManager.cpp @@ -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 @@ 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); } Index: ps/trunk/source/network/StunClient.cpp =================================================================== --- ps/trunk/source/network/StunClient.cpp +++ ps/trunk/source/network/StunClient.cpp @@ -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 @@ 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; } Index: ps/trunk/source/ps/GameSetup/GameSetup.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/GameSetup.cpp +++ ps/trunk/source/ps/GameSetup/GameSetup.cpp @@ -524,20 +524,21 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ LOGWARNING("Autostart: Invalid player %d in autostart-civ option", playerID); continue; } - scriptInterface.Eval("({})", &player); + scriptInterface.CreateObject(&player); } CStr name = civArgs[i].AfterFirst(":"); Index: ps/trunk/source/ps/GameSetup/HWDetect.cpp =================================================================== --- ps/trunk/source/ps/GameSetup/HWDetect.cpp +++ ps/trunk/source/ps/GameSetup/HWDetect.cpp @@ -75,20 +75,25 @@ 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(pcache->m_Type)); - scriptInterface.SetProperty(cache, "level", static_cast(pcache->m_Level)); - scriptInterface.SetProperty(cache, "associativity", static_cast(pcache->m_Associativity)); - scriptInterface.SetProperty(cache, "linesize", static_cast(pcache->m_EntrySize)); - scriptInterface.SetProperty(cache, "sharedby", static_cast(pcache->m_SharedBy)); - scriptInterface.SetProperty(cache, "totalsize",static_cast(pcache->TotalSize())); + + scriptInterface.CreateObject( + &cache, + "type", static_cast(pcache->m_Type), + "level", static_cast(pcache->m_Level), + "associativity", static_cast(pcache->m_Associativity), + "linesize", static_cast(pcache->m_EntrySize), + "sharedby", static_cast(pcache->m_SharedBy), + "totalsize", static_cast(pcache->TotalSize())); + scriptInterface.SetPropertyInt(ret, idxLevel, cache); } } @@ -98,19 +103,24 @@ 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(ptlb->m_Type)); - scriptInterface.SetProperty(tlb, "level", static_cast(ptlb->m_Level)); - scriptInterface.SetProperty(tlb, "associativity", static_cast(ptlb->m_Associativity)); - scriptInterface.SetProperty(tlb, "pagesize", static_cast(ptlb->m_EntrySize)); - scriptInterface.SetProperty(tlb, "entries", static_cast(ptlb->m_NumEntries)); + + scriptInterface.CreateObject( + &tlb, + "type", static_cast(ptlb->m_Type), + "level", static_cast(ptlb->m_Level), + "associativity", static_cast(ptlb->m_Associativity), + "pagesize", static_cast(ptlb->m_EntrySize), + "entries", static_cast(ptlb->m_NumEntries)); + scriptInterface.SetPropertyInt(ret, i, tlb); } } @@ -234,7 +244,7 @@ // 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); Index: ps/trunk/source/ps/Mod.cpp =================================================================== --- ps/trunk/source/ps/Mod.cpp +++ ps/trunk/source/ps/Mod.cpp @@ -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 @@ 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); Index: ps/trunk/source/ps/ProfileViewer.cpp =================================================================== --- ps/trunk/source/ps/ProfileViewer.cpp +++ ps/trunk/source/ps/ProfileViewer.cpp @@ -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 @@ JSAutoRequest rq(cx); JS::RootedValue data(cx); - m_ScriptInterface.Eval("({})", &data); + m_ScriptInterface.CreateObject(&data); const std::vector& 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)) Index: ps/trunk/source/ps/SavedGame.cpp =================================================================== --- ps/trunk/source/ps/SavedGame.cpp +++ ps/trunk/source/ps/SavedGame.cpp @@ -79,33 +79,40 @@ 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(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()); + + 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, "gui", guiMetadata); simulation.GetScriptInterface().SetProperty(metadata, "description", description); std::string metadataString = simulation.GetScriptInterface().StringifyJSON(&metadata, true); @@ -225,7 +232,8 @@ 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::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) Index: ps/trunk/source/ps/VisualReplay.cpp =================================================================== --- ps/trunk/source/ps/VisualReplay.cpp +++ ps/trunk/source/ps/VisualReplay.cpp @@ -189,9 +189,11 @@ 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(fileInfo.Size())); } JS_SetElement(cx, replays, i++, replayData); newReplays = true; @@ -232,7 +234,9 @@ 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::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 @@ // 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(fileSize), + "duration", static_cast(duration)); + scriptInterface.SetProperty(replayData, "attribs", attribs); - scriptInterface.SetProperty(replayData, "duration", duration); + return replayData; } @@ -423,7 +431,7 @@ 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"; Index: ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp +++ ps/trunk/source/ps/scripting/JSInterface_ModIo.cpp @@ -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 @@ const std::vector& 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& 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 statusStrings = { @@ -136,9 +136,10 @@ 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); Index: ps/trunk/source/ps/scripting/JSInterface_VFS.cpp =================================================================== --- ps/trunk/source/ps/scripting/JSInterface_VFS.cpp +++ ps/trunk/source/ps/scripting/JSInterface_VFS.cpp @@ -152,7 +152,8 @@ // 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 @@ // 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 @@ // 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& validPaths, const CStrW& filePath) Index: ps/trunk/source/scriptinterface/ScriptInterface.h =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.h +++ ps/trunk/source/scriptinterface/ScriptInterface.h @@ -131,6 +131,32 @@ 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 + bool CreateObject(JS::MutableHandleValue objectValue, const char* propertyName, const T& propertyValue, Args const&... args) const + { + return CreateObject(objectValue, args...) && SetProperty(objectValue, propertyName, propertyValue); + } + + template + 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; /** Index: ps/trunk/source/scriptinterface/ScriptInterface.cpp =================================================================== --- ps/trunk/source/scriptinterface/ScriptInterface.cpp +++ ps/trunk/source/scriptinterface/ScriptInterface.cpp @@ -579,6 +579,28 @@ 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); Index: ps/trunk/source/simulation2/Simulation2.cpp =================================================================== --- ps/trunk/source/simulation2/Simulation2.cpp +++ ps/trunk/source/simulation2/Simulation2.cpp @@ -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 @@ // 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); Index: ps/trunk/source/simulation2/components/CCmpAIManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/CCmpAIManager.cpp +++ ps/trunk/source/simulation2/components/CCmpAIManager.cpp @@ -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 @@ 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 @@ JSAutoRequest rq(cx); JS::RootedValue classesVal(cx); - scriptInterface.Eval("({})", &classesVal); + scriptInterface.CreateObject(&classesVal); std::map classes; cmpPathfinder->GetPassabilityClasses(classes); Index: ps/trunk/source/simulation2/components/ICmpAIManager.cpp =================================================================== --- ps/trunk/source/simulation2/components/ICmpAIManager.cpp +++ ps/trunk/source/simulation2/components/ICmpAIManager.cpp @@ -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 @@ 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; Index: ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp =================================================================== --- ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp +++ ps/trunk/source/tools/atlas/GameInterface/Handlers/MapHandlers.cpp @@ -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 @@ 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 @@ 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 @@ 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); }