1
0
forked from mirrors/0ad

Remove Script::CreateArray

It's better to construct a js-array from a `JS::RootedValueVector`.
Because it is more strongly typed and the index doesn't has to be
specified when appending an element.
Some usages are replaced with `JS::RootedValueArray`.

Fixes: #8702
This commit is contained in:
phosit
2026-02-02 18:24:57 +01:00
parent fe9c0f6c2f
commit df18e22277
14 changed files with 146 additions and 136 deletions
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -244,11 +244,16 @@ bool JSI_GUIProxy<T>::get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue
} }
else if (propName == "children") else if (propName == "children")
{ {
Script::CreateArray(rq, vp); JS::RootedValueVector children{rq.cx};
for (size_t i = 0; i < e->m_Children.size(); ++i)
Script::SetPropertyInt(rq, vp, i, e->m_Children[i]);
for (const auto& child : e->m_Children)
{
JS::RootedValue rootedChild{rq.cx};
Script::ToJSVal(rq, &rootedChild, child);
if (!children.append(rootedChild))
throw std::runtime_error{"Append failed"};
}
vp.set(JS::ObjectValue(*JS::NewArrayObject(rq.cx, children)));
return true; return true;
} }
else if (propName == "name") else if (propName == "name")
+28 -31
View File
@@ -573,9 +573,7 @@ void XmppClient::handleOOB(const gloox::JID&, const gloox::OOB&)
*/ */
JS::Value XmppClient::GUIGetPlayerList(const ScriptRequest& rq) JS::Value XmppClient::GUIGetPlayerList(const ScriptRequest& rq)
{ {
JS::RootedValue ret(rq.cx); JS::RootedValueVector players{rq.cx};
Script::CreateArray(rq, &ret);
int j = 0;
for (const std::pair<const std::string, SPlayer>& p : m_PlayerMap) for (const std::pair<const std::string, SPlayer>& p : m_PlayerMap)
{ {
@@ -589,9 +587,10 @@ JS::Value XmppClient::GUIGetPlayerList(const ScriptRequest& rq)
"rating", p.second.m_Rating, "rating", p.second.m_Rating,
"role", p.second.m_Role); "role", p.second.m_Role);
Script::SetPropertyInt(rq, ret, j++, player); if (!players.append(player))
throw std::runtime_error{"Append failed"};
} }
return ret; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, players));
} }
/** /**
@@ -601,9 +600,7 @@ JS::Value XmppClient::GUIGetPlayerList(const ScriptRequest& rq)
*/ */
JS::Value XmppClient::GUIGetGameList(const ScriptRequest& rq) JS::Value XmppClient::GUIGetGameList(const ScriptRequest& rq)
{ {
JS::RootedValue ret(rq.cx); JS::RootedValueVector games{rq.cx};
Script::CreateArray(rq, &ret);
int j = 0;
const char* stats[] = { "name", "hostUsername", "hostJID", "state", "hasPassword", const char* stats[] = { "name", "hostUsername", "hostJID", "state", "hasPassword",
"nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType", "nbp", "maxnbp", "players", "mapName", "niceMapName", "mapSize", "mapType",
@@ -617,9 +614,10 @@ JS::Value XmppClient::GUIGetGameList(const ScriptRequest& rq)
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
Script::SetProperty(rq, game, stats[i], t->findAttribute(stats[i])); Script::SetProperty(rq, game, stats[i], t->findAttribute(stats[i]));
Script::SetPropertyInt(rq, ret, j++, game); if (!games.append(game))
throw std::runtime_error{"Append failed"};
} }
return ret; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, games));
} }
/** /**
@@ -629,9 +627,7 @@ JS::Value XmppClient::GUIGetGameList(const ScriptRequest& rq)
*/ */
JS::Value XmppClient::GUIGetBoardList(const ScriptRequest& rq) JS::Value XmppClient::GUIGetBoardList(const ScriptRequest& rq)
{ {
JS::RootedValue ret(rq.cx); JS::RootedValueVector boardList{rq.cx};
Script::CreateArray(rq, &ret);
int j = 0;
const char* attributes[] = { "name", "rank", "rating" }; const char* attributes[] = { "name", "rank", "rating" };
@@ -643,9 +639,10 @@ JS::Value XmppClient::GUIGetBoardList(const ScriptRequest& rq)
for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i) for (size_t i = 0; i < ARRAY_SIZE(attributes); ++i)
Script::SetProperty(rq, board, attributes[i], t->findAttribute(attributes[i])); Script::SetProperty(rq, board, attributes[i], t->findAttribute(attributes[i]));
Script::SetPropertyInt(rq, ret, j++, board); if (!boardList.append(board))
throw std::runtime_error{"Append failed"};
} }
return ret; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, boardList));
} }
/** /**
@@ -655,9 +652,7 @@ JS::Value XmppClient::GUIGetBoardList(const ScriptRequest& rq)
*/ */
JS::Value XmppClient::GUIGetProfile(const ScriptRequest& rq) JS::Value XmppClient::GUIGetProfile(const ScriptRequest& rq)
{ {
JS::RootedValue ret(rq.cx); JS::RootedValueVector profileData{rq.cx};
Script::CreateArray(rq, &ret);
int j = 0;
const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" }; const char* stats[] = { "player", "rating", "totalGamesPlayed", "highestRating", "wins", "losses", "rank" };
@@ -669,9 +664,10 @@ JS::Value XmppClient::GUIGetProfile(const ScriptRequest& rq)
for (size_t i = 0; i < ARRAY_SIZE(stats); ++i) for (size_t i = 0; i < ARRAY_SIZE(stats); ++i)
Script::SetProperty(rq, profile, stats[i], t->findAttribute(stats[i])); Script::SetProperty(rq, profile, stats[i], t->findAttribute(stats[i]));
Script::SetPropertyInt(rq, ret, j++, profile); if (!profileData.append(profile))
throw std::runtime_error{"Append failed"};
} }
return ret; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, profileData));
} }
/***************************************************** /*****************************************************
@@ -735,14 +731,12 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& guiInterface)
// Optimize for batch message processing that is more // Optimize for batch message processing that is more
// performance demanding than processing a lone message. // performance demanding than processing a lone message.
JS::RootedValue messages(rq.cx); JS::RootedValueVector messages{rq.cx};
Script::CreateArray(rq, &messages);
int j = 0;
for (const JS::Heap<JS::Value>& message : m_GuiMessageQueue) for (const JS::Heap<JS::Value>& message : m_GuiMessageQueue)
{ {
Script::SetPropertyInt(rq, messages, j++, message); if (!messages.append(message))
throw std::runtime_error{"Append failed"};
// Store historic chat messages. // Store historic chat messages.
// Only store relevant messages to minimize memory footprint. // Only store relevant messages to minimize memory footprint.
@@ -770,7 +764,8 @@ JS::Value XmppClient::GuiPollNewMessages(const ScriptInterface& guiInterface)
m_GuiMessageQueue.clear(); m_GuiMessageQueue.clear();
// Copy the messages over to the caller script interface. // Copy the messages over to the caller script interface.
return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface, messages); return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface,
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, messages))});
} }
JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& guiInterface) JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& guiInterface)
@@ -780,15 +775,17 @@ JS::Value XmppClient::GuiPollHistoricMessages(const ScriptInterface& guiInterfac
ScriptRequest rq(m_ScriptInterface); ScriptRequest rq(m_ScriptInterface);
JS::RootedValue messages(rq.cx); JS::RootedValueVector messages{rq.cx};
Script::CreateArray(rq, &messages);
int j = 0;
for (const JS::Heap<JS::Value>& message : m_HistoricGuiMessages) for (const JS::Heap<JS::Value>& message : m_HistoricGuiMessages)
Script::SetPropertyInt(rq, messages, j++, message); {
if (!messages.append(message))
throw std::runtime_error{"Append failed"};
}
// Copy the messages over to the caller script interface. // Copy the messages over to the caller script interface.
return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface, messages); return Script::CloneValueFromOtherCompartment(guiInterface, *m_ScriptInterface,
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, messages))});
} }
/** /**
+4 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -37,11 +37,9 @@ public:
ScriptInterface script("Test", "Test", g_ScriptContext); ScriptInterface script("Test", "Test", g_ScriptContext);
ScriptRequest rq(script); ScriptRequest rq(script);
JS::RootedValue val(rq.cx); JS::RootedValueArray<1> val{rq.cx, JS::ValueArray<1>{JS::NumberValue(4)}};
Script::CreateArray(rq, &val); CSimulationMessage msg(script, 1, 2, 3,
Script::SetPropertyInt(rq, val, 0, 4); JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, val))});
CSimulationMessage msg(script, 1, 2, 3, val);
TS_ASSERT_STR_EQUALS(msg.ToString(), "CSimulationMessage { m_Client: 1, m_Player: 2, m_Turn: 3, m_Data: [4] }"); TS_ASSERT_STR_EQUALS(msg.ToString(), "CSimulationMessage { m_Client: 1, m_Player: 2, m_Turn: 3, m_Data: [4] }");
size_t len = msg.GetSerializedLength(); size_t len = msg.GetSerializedLength();
+7 -7
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -193,14 +193,13 @@ JS::Value MakeFreeTypeReport(const ScriptRequest& rq)
void ReportLibraries(const ScriptRequest& rq, JS::HandleValue settings) void ReportLibraries(const ScriptRequest& rq, JS::HandleValue settings)
{ {
JS::RootedValue librariesSettings(rq.cx); JS::RootedValueVector librariesSettings{rq.cx};
Script::CreateArray(rq, &librariesSettings);
int libraryCount = 0;
auto appendLibrary = [&rq, &librariesSettings, &libraryCount](const JS::Value& librarySettings) auto appendLibrary = [&rq, &librariesSettings](const JS::Value& librarySettings)
{ {
JS::RootedValue value(rq.cx, librarySettings); JS::RootedValue value(rq.cx, librarySettings);
Script::SetPropertyInt(rq, librariesSettings, libraryCount++, value); if (!librariesSettings.append(value))
throw std::runtime_error{"Append failed"};
}; };
appendLibrary(MakeSDLReport(rq)); appendLibrary(MakeSDLReport(rq));
@@ -230,7 +229,8 @@ void ReportLibraries(const ScriptRequest& rq, JS::HandleValue settings)
.MakeReport()); .MakeReport());
#endif #endif
Script::SetProperty(rq, settings, "libraries", librariesSettings); Script::SetProperty(rq, settings, "libraries",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, librariesSettings))});
} }
void WriteSystemInfo(Renderer::Backend::IDevice* device, const utsname& un) void WriteSystemInfo(Renderer::Backend::IDevice* device, const utsname& un)
+9 -5
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -494,19 +494,23 @@ namespace
for (size_t r = 0; r < table->GetNumberRows(); ++r) for (size_t r = 0; r < table->GetNumberRows(); ++r)
{ {
JS::RootedValue row(rq.cx); JS::RootedValueVector row{rq.cx};
Script::CreateArray(rq, &row); if (!row.resize(columns.size() + 1))
throw std::runtime_error{"Resize failed"};
Script::SetProperty(rq, data, table->GetCellText(r, 0).c_str(), row); Script::SetProperty(rq, data, table->GetCellText(r, 0).c_str(), row);
if (table->GetChild(r)) if (table->GetChild(r))
{ {
JS::RootedValue childRows(rq.cx, DumpRows(table->GetChild(r))); JS::RootedValue childRows(rq.cx, DumpRows(table->GetChild(r)));
Script::SetPropertyInt(rq, row, 0, childRows); row[0].set(childRows);
} }
for (size_t c = 1; c < columns.size(); ++c) for (size_t c = 1; c < columns.size(); ++c)
Script::SetPropertyInt(rq, row, c, table->GetCellText(r, c)); {
row[c].set(JS::StringValue(
JS_NewStringCopyZ(rq.cx, table->GetCellText(r, c).c_str())));
}
} }
return data; return data;
+8 -8
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -279,8 +279,7 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
PROFILE2("GetSavedGames"); PROFILE2("GetSavedGames");
ScriptRequest rq(scriptInterface); ScriptRequest rq(scriptInterface);
JS::RootedValue games(rq.cx); JS::RootedValueVector games{rq.cx};
Script::CreateArray(rq, &games);
Status err; Status err;
@@ -288,10 +287,10 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
err = vfs::GetPathnames(g_VFS, "saves/", L"*.0adsave", pathnames); err = vfs::GetPathnames(g_VFS, "saves/", L"*.0adsave", pathnames);
WARN_IF_ERR(err); WARN_IF_ERR(err);
for (size_t i = 0; i < pathnames.size(); ++i) for (const VfsPath& pathname : pathnames)
{ {
OsPath realPath; OsPath realPath;
err = g_VFS->GetRealPath(pathnames[i], realPath); err = g_VFS->GetRealPath(pathname, realPath);
if (err < 0) if (err < 0)
{ {
DEBUG_WARN_ERR(err); DEBUG_WARN_ERR(err);
@@ -319,13 +318,14 @@ JS::Value SavedGames::GetSavedGames(const ScriptInterface& scriptInterface)
Script::CreateObject( Script::CreateObject(
rq, rq,
&game, &game,
"id", pathnames[i].Basename(), "id", pathname.Basename(),
"metadata", metadata); "metadata", metadata);
Script::SetPropertyInt(rq, games, i, game); if (!games.append(game))
throw std::runtime_error{"Append failed"};
} }
return games; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, games));
} }
bool SavedGames::DeleteSavedGame(const std::wstring& name) bool SavedGames::DeleteSavedGame(const std::wstring& name)
+8 -7
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -255,19 +255,20 @@ JS::Value VisualReplay::GetReplays(const ScriptInterface& scriptInterface, bool
ScriptRequest rq(scriptInterface); ScriptRequest rq(scriptInterface);
JS::RootedObject replays(rq.cx, ReloadReplayCache(scriptInterface, compareFiles)); JS::RootedObject replays(rq.cx, ReloadReplayCache(scriptInterface, compareFiles));
// Only take entries with data // Only take entries with data
JS::RootedValue replaysWithoutNullEntries(rq.cx); JS::RootedValueVector replaysWithoutNullEntries{rq.cx};
Script::CreateArray(rq, &replaysWithoutNullEntries);
u32 replaysLength = 0; u32 replaysLength = 0;
JS::GetArrayLength(rq.cx, replays, &replaysLength); JS::GetArrayLength(rq.cx, replays, &replaysLength);
for (u32 j = 0, i = 0; j < replaysLength; ++j) for (u32 j = 0; j < replaysLength; ++j)
{ {
JS::RootedValue replay(rq.cx); JS::RootedValue replay(rq.cx);
JS_GetElement(rq.cx, replays, j, &replay); JS_GetElement(rq.cx, replays, j, &replay);
if (Script::HasProperty(rq, replay, "attribs")) if (!Script::HasProperty(rq, replay, "attribs"))
Script::SetPropertyInt(rq, replaysWithoutNullEntries, i++, replay); continue;
if (!replaysWithoutNullEntries.append(replay))
throw std::runtime_error{"Append failed"};
} }
return replaysWithoutNullEntries; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, replaysWithoutNullEntries));
} }
/** /**
+7 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -70,10 +70,10 @@ JS::Value GetMods(const ScriptRequest& rq)
const std::vector<ModIoModData>& availableMods = g_ModIo->GetMods(); const std::vector<ModIoModData>& availableMods = g_ModIo->GetMods();
JS::RootedValue mods(rq.cx); JS::RootedValueVector mods{rq.cx};
Script::CreateArray(rq, &mods, availableMods.size()); if (!mods.reserve(availableMods.size()))
throw std::runtime_error{"Reserve failed"};
u32 i = 0;
for (const ModIoModData& mod : availableMods) for (const ModIoModData& mod : availableMods)
{ {
JS::RootedValue m(rq.cx); JS::RootedValue m(rq.cx);
@@ -83,10 +83,11 @@ JS::Value GetMods(const ScriptRequest& rq)
Script::SetProperty(rq, m, prop.first.c_str(), prop.second, true); Script::SetProperty(rq, m, prop.first.c_str(), prop.second, true);
Script::SetProperty(rq, m, "dependencies", mod.dependencies, true); Script::SetProperty(rq, m, "dependencies", mod.dependencies, true);
Script::SetPropertyInt(rq, mods, i++, m); if (!mods.append(m))
throw std::runtime_error{"Append failed"};
} }
return mods; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, mods));
} }
const std::map<DownloadProgressStatus, std::string> statusStrings = { const std::map<DownloadProgressStatus, std::string> statusStrings = {
+5 -6
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -227,21 +227,20 @@ JS::Value ReadFileLines(const ScriptRequest& rq, const std::wstring& filename)
// split into array of strings (one per line) // split into array of strings (one per line)
std::stringstream ss(contents); std::stringstream ss(contents);
JS::RootedValue line_array(rq.cx); JS::RootedValueVector lineArray{rq.cx};
Script::CreateArray(rq, &line_array);
std::string line; std::string line;
int cur_line = 0;
while (std::getline(ss, line)) while (std::getline(ss, line))
{ {
// Decode each line as UTF-8 // Decode each line as UTF-8
JS::RootedValue val(rq.cx); JS::RootedValue val(rq.cx);
Script::ToJSVal(rq, &val, CStr(line).FromUTF8()); Script::ToJSVal(rq, &val, CStr(line).FromUTF8());
Script::SetPropertyInt(rq, line_array, cur_line++, val); if (!lineArray.append(val))
throw std::runtime_error{"Append failed"};
} }
return line_array; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, lineArray));
} }
// Return file contents parsed as a JS Object // Return file contents parsed as a JS Object
+10 -7
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -726,16 +726,19 @@ void CDevice::Report(const ScriptRequest& rq, JS::HandleValue settings)
ReportAvailablePhysicalDevice(m_ChoosenDevice, rq, device); ReportAvailablePhysicalDevice(m_ChoosenDevice, rq, device);
Script::SetProperty(rq, settings, "choosen_device", device); Script::SetProperty(rq, settings, "choosen_device", device);
JS::RootedValue availableDevices(rq.cx); JS::RootedValueVector availableDevices{rq.cx};
Script::CreateArray(rq, &availableDevices, m_AvailablePhysicalDevices.size()); if (!availableDevices.reserve(m_AvailablePhysicalDevices.size()))
for (size_t index = 0; index < m_AvailablePhysicalDevices.size(); ++index) throw std::runtime_error{"Reserve failed"};
for (const SAvailablePhysicalDevice& d : m_AvailablePhysicalDevices)
{ {
JS::RootedValue device(rq.cx); JS::RootedValue device(rq.cx);
Script::CreateObject(rq, &device); Script::CreateObject(rq, &device);
ReportAvailablePhysicalDevice(m_AvailablePhysicalDevices[index], rq, device); ReportAvailablePhysicalDevice(d, rq, device);
Script::SetPropertyInt(rq, availableDevices, index, device); if (!availableDevices.append(device))
throw std::runtime_error{"Append failed"};
} }
Script::SetProperty(rq, settings, "available_devices", availableDevices); Script::SetProperty(rq, settings, "available_devices",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, availableDevices))});
Script::SetProperty(rq, settings, "instance_extensions", m_InstanceExtensions); Script::SetProperty(rq, settings, "instance_extensions", m_InstanceExtensions);
Script::SetProperty(rq, settings, "validation_layers", m_ValidationLayers); Script::SetProperty(rq, settings, "validation_layers", m_ValidationLayers);
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -29,6 +29,7 @@
#include <js/RootingAPI.h> #include <js/RootingAPI.h>
#include <js/Value.h> #include <js/Value.h>
#include <limits> #include <limits>
#include <span>
#include <string> #include <string>
#include <type_traits> #include <type_traits>
#include <vector> #include <vector>
@@ -353,32 +354,38 @@ void ReportAvailablePhysicalDevice(const SAvailablePhysicalDevice& device,
JS::RootedValue memory(rq.cx); JS::RootedValue memory(rq.cx);
Script::CreateObject(rq, &memory); Script::CreateObject(rq, &memory);
JS::RootedValue memoryTypes(rq.cx); JS::RootedValueVector memoryTypes{rq.cx};
Script::CreateArray(rq, &memoryTypes, device.memoryProperties.memoryTypeCount); if (!memoryTypes.reserve(device.memoryProperties.memoryTypeCount))
for (uint32_t memoryTypeIndex = 0; memoryTypeIndex < device.memoryProperties.memoryTypeCount; ++memoryTypeIndex) throw std::runtime_error{"Reserve failed"};
for (const VkMemoryType& type : std::span{device.memoryProperties.memoryTypes,
device.memoryProperties.memoryTypeCount})
{ {
const VkMemoryType& type = device.memoryProperties.memoryTypes[memoryTypeIndex];
JS::RootedValue memoryType(rq.cx); JS::RootedValue memoryType(rq.cx);
Script::CreateObject(rq, &memoryType); Script::CreateObject(rq, &memoryType);
Script::SetProperty(rq, memoryType, "propertyFlags", static_cast<uint32_t>(type.propertyFlags)); Script::SetProperty(rq, memoryType, "propertyFlags", static_cast<uint32_t>(type.propertyFlags));
Script::SetProperty(rq, memoryType, "heapIndex", type.heapIndex); Script::SetProperty(rq, memoryType, "heapIndex", type.heapIndex);
Script::SetPropertyInt(rq, memoryTypes, memoryTypeIndex, memoryType); if (!memoryTypes.append(memoryType))
throw std::runtime_error{"Append failed"};
} }
JS::RootedValue memoryHeaps(rq.cx); JS::RootedValueVector memoryHeaps{rq.cx};
Script::CreateArray(rq, &memoryHeaps, device.memoryProperties.memoryHeapCount); if (!memoryHeaps.reserve(device.memoryProperties.memoryHeapCount))
for (uint32_t memoryHeapIndex = 0; memoryHeapIndex < device.memoryProperties.memoryHeapCount; ++memoryHeapIndex) throw std::runtime_error{"Reserve failed"};
for (const VkMemoryHeap& heap : std::span{device.memoryProperties.memoryHeaps,
device.memoryProperties.memoryHeapCount})
{ {
const VkMemoryHeap& heap = device.memoryProperties.memoryHeaps[memoryHeapIndex];
JS::RootedValue memoryHeap(rq.cx); JS::RootedValue memoryHeap(rq.cx);
Script::CreateObject(rq, &memoryHeap); Script::CreateObject(rq, &memoryHeap);
// We can't serialize uint64_t in JS, so put data in KiB. // We can't serialize uint64_t in JS, so put data in KiB.
Script::SetProperty(rq, memoryHeap, "size", static_cast<uint32_t>(heap.size / 1024)); Script::SetProperty(rq, memoryHeap, "size", static_cast<uint32_t>(heap.size / 1024));
Script::SetProperty(rq, memoryHeap, "flags", static_cast<uint32_t>(heap.flags)); Script::SetProperty(rq, memoryHeap, "flags", static_cast<uint32_t>(heap.flags));
Script::SetPropertyInt(rq, memoryHeaps, memoryHeapIndex, memoryHeap); if (!memoryHeaps.append(memoryHeap))
throw std::runtime_error{"Append failed"};
} }
Script::SetProperty(rq, memory, "types", memoryTypes); Script::SetProperty(rq, memory, "types",
Script::SetProperty(rq, memory, "heaps", memoryHeaps); JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, memoryTypes))});
Script::SetProperty(rq, memory, "heaps",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, memoryHeaps))});
Script::SetProperty(rq, settings, "memory", memory); Script::SetProperty(rq, settings, "memory", memory);
JS::RootedValue constants(rq.cx); JS::RootedValue constants(rq.cx);
@@ -513,28 +520,33 @@ void ReportAvailablePhysicalDevice(const SAvailablePhysicalDevice& device,
Script::SetProperty(rq, settings, "features", features); Script::SetProperty(rq, settings, "features", features);
JS::RootedValue presentModes(rq.cx); JS::RootedValueVector presentModes{rq.cx};
Script::CreateArray(rq, &presentModes, device.presentModes.size()); if (!presentModes.reserve(device.presentModes.size()))
for (size_t index = 0; index < device.presentModes.size(); ++index) throw std::runtime_error{"Reserve failed"};
for (const VkPresentModeKHR& mode : device.presentModes)
{ {
Script::SetPropertyInt( if (!presentModes.append(JS::NumberValue(static_cast<uint32_t>(mode))))
rq, presentModes, index, static_cast<uint32_t>(device.presentModes[index])); throw std::runtime_error{"Append failed"};
} }
Script::SetProperty(rq, settings, "present_modes", presentModes); Script::SetProperty(rq, settings, "present_modes",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, presentModes))});
JS::RootedValue surfaceFormats(rq.cx); JS::RootedValueVector surfaceFormats{rq.cx};
Script::CreateArray(rq, &surfaceFormats, device.surfaceFormats.size()); if (!surfaceFormats.reserve(device.surfaceFormats.size()))
for (size_t index = 0; index < device.surfaceFormats.size(); ++index) throw std::runtime_error{"Reserve failed"};
for (const VkSurfaceFormatKHR& format : device.surfaceFormats)
{ {
JS::RootedValue surfaceFormat(rq.cx); JS::RootedValue surfaceFormat(rq.cx);
Script::CreateObject(rq, &surfaceFormat); Script::CreateObject(rq, &surfaceFormat);
Script::SetProperty( Script::SetProperty(
rq, surfaceFormat, "format", static_cast<uint32_t>(device.surfaceFormats[index].format)); rq, surfaceFormat, "format", static_cast<uint32_t>(format.format));
Script::SetProperty( Script::SetProperty(
rq, surfaceFormat, "color_space", static_cast<uint32_t>(device.surfaceFormats[index].colorSpace)); rq, surfaceFormat, "color_space", static_cast<uint32_t>(format.colorSpace));
Script::SetPropertyInt(rq, surfaceFormats, index, surfaceFormat); if (!surfaceFormats.append(surfaceFormat))
throw std::runtime_error{"Append failed"};
} }
Script::SetProperty(rq, settings, "surface_formats", surfaceFormats); Script::SetProperty(rq, settings, "surface_formats",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, surfaceFormats))});
JS::RootedValue surfaceCapabilities(rq.cx); JS::RootedValue surfaceCapabilities(rq.cx);
Script::CreateObject(rq, &surfaceCapabilities); Script::CreateObject(rq, &surfaceCapabilities);
+1 -10
View File
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -271,15 +271,6 @@ inline bool CreateObject(const ScriptRequest& rq, JS::MutableHandleValue objectV
return CreateObject(rq, objectValue, args...) && SetProperty(rq, objectValue, propertyName, val, false, true); return CreateObject(rq, objectValue, args...) && SetProperty(rq, objectValue, propertyName, val, false, true);
} }
/**
* Sets the given value to a new JS object or Null Value in case of out-of-memory.
*/
inline bool CreateArray(const ScriptRequest& rq, JS::MutableHandleValue objectValue, size_t length = 0)
{
objectValue.setObjectOrNull(JS::NewArrayObject(rq.cx, length));
return !objectValue.isNullOrUndefined();
}
} // namespace Script } // namespace Script
#endif // INCLUDED_SCRIPTINTERFACE_Object #endif // INCLUDED_SCRIPTINTERFACE_Object
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -148,9 +148,7 @@ JS::Value GetEdgesOfStaticObstructionsOnScreenNearTo(const ScriptInterface& scri
ENSURE(sim); ENSURE(sim);
ScriptRequest rq(scriptInterface); ScriptRequest rq(scriptInterface);
JS::RootedValue edgeList(rq.cx); JS::RootedValueVector edgeList{rq.cx};
Script::CreateArray(rq, &edgeList);
int edgeListIndex = 0;
const float distanceThreshold{g_ConfigDB.Get("gui.session.snaptoedgesdistancethreshold", 10.0f)}; const float distanceThreshold{g_ConfigDB.Get("gui.session.snaptoedgesdistancethreshold", 10.0f)};
CFixedVector2D entityPos(x, z); CFixedVector2D entityPos(x, z);
@@ -202,10 +200,11 @@ JS::Value GetEdgesOfStaticObstructionsOnScreenNearTo(const ScriptInterface& scri
"normal", normal, "normal", normal,
"order", "cw"); "order", "cw");
Script::SetPropertyInt(rq, edgeList, edgeListIndex++, edge); if (!edgeList.append(edge))
throw std::runtime_error{"Append failed"};
} }
} }
return edgeList; return JS::ObjectValue(*JS::NewArrayObject(rq.cx, edgeList));
} }
std::vector<entity_id_t> PickSimilarPlayerEntities(const std::string& templateName, bool includeOffScreen, bool matchRank, bool allowFoundations) std::vector<entity_id_t> PickSimilarPlayerEntities(const std::string& templateName, bool includeOffScreen, bool matchRank, bool allowFoundations)
@@ -1,4 +1,4 @@
/* Copyright (C) 2025 Wildfire Games. /* Copyright (C) 2026 Wildfire Games.
* This file is part of 0 A.D. * This file is part of 0 A.D.
* *
* 0 A.D. is free software: you can redistribute it and/or modify * 0 A.D. is free software: you can redistribute it and/or modify
@@ -163,14 +163,13 @@ QUERYHANDLER(GenerateMap)
ScriptRequest rq(scriptInterface); ScriptRequest rq(scriptInterface);
// Set up 8-element array of empty objects to satisfy init // Set up 8-element array of empty objects to satisfy init
JS::RootedValue playerData(rq.cx); JS::RootedValueArray<8> playerData{rq.cx};
Script::CreateArray(rq, &playerData);
for (int i = 0; i < 8; ++i) for (JS::Value& p : playerData.get().elements)
{ {
JS::RootedValue player(rq.cx); JS::RootedValue player(rq.cx);
Script::CreateObject(rq, &player); Script::CreateObject(rq, &player);
Script::SetPropertyInt(rq, playerData, i, player); p = player;
} }
JS::RootedValue settings(rq.cx); JS::RootedValue settings(rq.cx);
@@ -178,7 +177,8 @@ QUERYHANDLER(GenerateMap)
rq, rq,
&settings, &settings,
"mapType", "scenario", "mapType", "scenario",
"PlayerData", playerData); "PlayerData",
JS::RootedValue{rq.cx, JS::ObjectValue(*JS::NewArrayObject(rq.cx, playerData))});
JS::RootedValue attrs(rq.cx); JS::RootedValue attrs(rq.cx);
Script::CreateObject( Script::CreateObject(