1
0
forked from 0ad/0ad

Fix non-visual autostart, as well as client/host autostart.

Follows 8eecc39e71.

Piping the autostart through a GUI page is easy but requires using the
GUI in non-visual mode, which is problematic since it's not initialized.
The GUI is not needed, only its ability to load scripts, so this diff
fixes the problem by adding an 'entrypoint' script in the new
`autostart` folder that gets called with this unique ability, setting
things up properly. The mod mod gets a placeholder.

Other changes:
- Fix some issues with networked autostart:
  - Players were not assigned slots.
  - The host didn't actually wait for other players.
- Move gamesettings from `gui/gamesettings/` to `gamesettings/`. This
moves attributes as well.
- Move autostart files from `gui/autostart/` to ` autostart/`. Note that
`gui/autostart/` still exists as it's used in the tutorial button from
the main menu.
- Rename the JSI_VFS functions to be explicitly about their function:
the ability to write and the potential restricted folders.
- Don't require `autostart` when using `--autostart-client` in
non-visual mode.

Starting the autostart client/host has poor UX in some situations, but
improving that feature is beyond the scope of this diff.

Suggestions for future work:
- Some files in gui/common should probably be moved elsewhere
- Template loading code is duplicated
- The gamesetup code still needs work for proper UI/logic separation.

Help & comments by: smiley

Reported by: vladislav / Langbart
Fixes #6513

Differential Revision: https://code.wildfiregames.com/D4628
This was SVN commit r26879.
This commit is contained in:
wraitii 2022-05-15 06:34:17 +00:00
parent 967f9ea7a3
commit 557fa0312e
65 changed files with 381 additions and 196 deletions

View File

@ -0,0 +1,23 @@
/**
* This file is called from the visual & non-visual paths when autostarting.
* To avoid relying on the GUI, this script has access to a special 'LoadScript' function.
* See implementation in the public mod for more details.
*/
function autostartClient(initData)
{
throw new Error("Autostart is not implemented in the 'mod' mod");
}
function autostartHost(initData, networked = false)
{
throw new Error("Autostart is not implemented in the 'mod' mod");
}
/**
* @returns false if the loop should carry on.
*/
function onTick()
{
return true;
}

View File

@ -0,0 +1,29 @@
class AutoStart
{
constructor(initData)
{
this.settings = new GameSettings().init();
this.settings.fromInitAttributes(initData.attribs);
this.playerAssignments = initData.playerAssignments;
this.settings.launchGame(this.playerAssignments, initData.storeReplay);
this.onLaunch();
}
onTick()
{
}
/**
* In the visual autostart path, we need to show the loading screen.
*/
onLaunch()
{
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": this.settings.finalizedAttributes,
"playerAssignments": this.playerAssignments
});
}
}

View File

@ -0,0 +1,54 @@
class AutoStartClient
{
constructor(initData)
{
this.playerAssignments = {};
try
{
Engine.StartNetworkJoin(initData.playerName, initData.ip, initData.port, initData.storeReplay);
}
catch (e)
{
const message = sprintf(translate("Cannot join game: %(message)s."), { "message": e.message });
messageBox(400, 200, message, translate("Error"));
}
}
onTick()
{
while (true)
{
const message = Engine.PollNetworkClient();
if (!message)
break;
switch (message.type)
{
case "players":
this.playerAssignments = message.newAssignments;
Engine.SendNetworkReady(2);
break;
case "start":
this.onLaunch(message);
// Process further pending netmessages in the session page.
return true;
default:
}
}
return false;
}
/**
* In the visual autostart path, we need to show the loading screen.
* Overload this as appropriate, the default implementation works for the public mod.
*/
onLaunch(message)
{
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": message.initAttributes,
"isRejoining": true,
"playerAssignments": this.playerAssignments
});
}
}

View File

@ -0,0 +1,85 @@
class AutoStartHost
{
constructor(initData)
{
this.launched = false;
this.maxPlayers = initData.maxPlayers;
this.storeReplay = initData.storeReplay;
this.playerAssignments = {};
this.initAttribs = initData.attribs;
try
{
// Stun and password not implemented for autostart.
Engine.StartNetworkHost(initData.playerName, initData.port, false, "", initData.storeReplay);
}
catch (e)
{
const message = sprintf(translate("Cannot host game: %(message)s."), { "message": e.message });
messageBox(400, 200, message, translate("Error"));
}
}
/**
* Handles a simple implementation of player assignments.
* Should not need be overloaded in mods unless you want to change that logic.
*/
onTick()
{
while (true)
{
const message = Engine.PollNetworkClient();
if (!message)
break;
switch (message.type)
{
case "players":
this.playerAssignments = message.newAssignments;
Engine.SendNetworkReady(2);
let max = 0;
for (const uid in this.playerAssignments)
{
max = Math.max(this.playerAssignments[uid].player, max);
if (this.playerAssignments[uid].player == -1)
Engine.AssignNetworkPlayer(++max, uid);
}
break;
case "ready":
this.playerAssignments[message.guid].status = message.status;
break;
case "start":
return true;
default:
}
}
if (!this.launched && Object.keys(this.playerAssignments).length == this.maxPlayers)
{
for (const uid in this.playerAssignments)
if (this.playerAssignments[uid].player == -1 || this.playerAssignments[uid].status == 0)
return false;
this.onLaunch();
}
return false;
}
/**
* In the visual autostart path, we need to show the loading screen.
* Overload this as appropriate.
*/
onLaunch()
{
this.launched = true;
this.settings = new GameSettings().init();
this.settings.fromInitAttributes(this.initAttribs);
this.settings.playerCount.setNb(Object.keys(this.playerAssignments).length);
this.settings.launchGame(this.playerAssignments, this.storeReplay);
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": this.initAttribs,
"playerAssignments": this.playerAssignments
});
}
}

View File

@ -0,0 +1,58 @@
/**
* Implement autostart for the public mod.
* We want to avoid relying on too many specific files, so we'll mock a few engine functions.
* Depending on the path, these may get overwritten with the real function.
*/
Engine.HasXmppClient = () => false;
Engine.SetRankedGame = () => {};
Engine.TextureExists = () => false;
Engine.PushGuiPage = () => {};
Engine.SwitchGuiPage = () => {};
var translateObjectKeys = () => {}
var translate = x => x;
var translateWithContext = x => x;
// Required for functions such as sprintf.
Engine.LoadScript("globalscripts/");
// MsgBox is used in the failure path.
// TODO: clean this up and show errors better in the non-visual path.
Engine.LoadScript("gui/common/functions_msgbox.js");
var autostartInstance;
function autostartClient(initData)
{
autostartInstance = new AutoStartClient(initData);
}
/**
* This path depends on files currently stored under gui/, which should be moved.
* The best place would probably be a new 'engine' mod, independent from the 'mod' mod and the public mod.
*/
function autostartHost(initData, networked = false)
{
Engine.LoadScript("gui/common/color.js");
Engine.LoadScript("gui/common/functions_utility.js");
Engine.LoadScript("gui/common/Observable.js");
Engine.LoadScript("gui/common/settings.js");
Engine.LoadScript("gui/maps/MapCache.js")
Engine.LoadScript("gamesettings/");
Engine.LoadScript("gamesettings/attributes/");
if (networked)
autostartInstance = new AutoStartHost(initData);
else
autostartInstance = new AutoStart(initData);
}
/**
* @returns false if the loop should carry on.
*/
function onTick()
{
return autostartInstance.onTick();
}

View File

@ -1,12 +0,0 @@
function init(initData)
{
let settings = new GameSettings().init();
settings.fromInitAttributes(initData.attribs);
settings.launchGame(initData.playerAssignments, initData.storeReplay);
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": settings.finalizedAttributes,
"playerAssignments": initData.playerAssignments
});
}

View File

@ -2,7 +2,8 @@
<objects>
<script file="gui/maps/MapCache.js"/>
<script directory="gui/common/"/>
<script directory="gui/gamesettings/"/>
<script directory="gui/gamesettings/attributes/"/>
<script directory="gamesettings/"/>
<script directory="gamesettings/attributes/"/>
<script file="autostart/autostart.js"/>
<script file="gui/autostart/autostart.js"/>
</objects>

View File

@ -1,54 +0,0 @@
class AutoStartClient
{
constructor(initData)
{
Engine.GetGUIObjectByName("ticker").onTick = this.onTick.bind(this);
this.playerAssignments = {};
try
{
Engine.StartNetworkJoin(initData.playerName, initData.ip, initData.port, initData.storeReplay);
}
catch (e)
{
messageBox(
400, 200,
sprintf(translate("Cannot join game: %(message)s."), { "message": e.message }),
translate("Error")
);
}
}
onTick()
{
while (true)
{
const message = Engine.PollNetworkClient();
if (!message)
break;
switch (message.type)
{
case "players":
this.playerAssignments = message.newAssignments;
break;
case "start":
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": message.initAttributes,
"isRejoining": true,
"playerAssignments": this.playerAssignments
});
// Process further pending netmessages in the session page.
return;
default:
}
}
}
}
function init(initData)
{
new AutoStartClient(initData);
}

View File

@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script directory="gui/common/"/>
<script file="gui/autostart/autostart_client.js"/>
<object name="ticker"/>
</objects>

View File

@ -1,61 +0,0 @@
class AutoStartHost
{
constructor(initData)
{
this.maxPlayers = initData.maxPlayers;
this.storeReplay = initData.storeReplay;
this.playerAssignments = {};
Engine.GetGUIObjectByName("ticker").onTick = this.onTick.bind(this);
try
{
// Stun and password not implemented for autostart.
Engine.StartNetworkHost(initData.playerName, initData.port, false, "", initData.storeReplay);
}
catch (e)
{
messageBox(
400, 200,
sprintf(translate("Cannot host game: %(message)s."), { "message": e.message }),
translate("Error")
);
}
this.settings = new GameSettings().init();
this.settings.fromInitAttributes(initData.attribs);
}
onTick()
{
while (true)
{
const message = Engine.PollNetworkClient();
if (!message)
break;
switch (message.type)
{
case "players":
this.playerAssignments = message.newAssignments;
break;
default:
}
}
if (Object.keys(this.playerAssignments).length == this.maxPlayers)
{
this.settings.launchGame(this.playerAssignments, this.storeReplay);
Engine.SwitchGuiPage("page_loading.xml", {
"attribs": this.settings.finalizedAttributes,
"playerAssignments": this.playerAssignments
});
}
}
}
function init(initData)
{
new AutoStartHost(initData);
}

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script file="gui/maps/MapCache.js"/>
<script directory="gui/common/"/>
<script directory="gui/gamesettings/"/>
<script directory="gui/gamesettings/attributes/"/>
<script file="gui/autostart/autostart_host.js"/>
<object name="ticker"/>
</objects>

View File

@ -3,8 +3,8 @@
<objects>
<script file="gui/maps/MapCache.js"/>
<script directory="gui/common/"/>
<script directory="gui/gamesettings/"/>
<script directory="gui/gamesettings/attributes/"/>
<script directory="gamesettings/"/>
<script directory="gamesettings/attributes/"/>
<script directory="gui/campaigns/default_menu/"/>
<object type="image" style="ModernWindow" size="0 0 100% 100%" name="campaignMenuWindow">

View File

@ -3,8 +3,8 @@
<script directory="gui/common/"/>
<script directory="gui/maps/"/>
<script directory="gui/gamesettings/"/>
<script directory="gui/gamesettings/attributes/"/>
<script directory="gamesettings/"/>
<script directory="gamesettings/attributes/"/>
<script directory="gui/gamesetup/"/>
<script directory="gui/gamesetup/Controllers/"/>
<script directory="gui/gamesetup/NetMessages/"/>

View File

@ -2,7 +2,7 @@
<page>
<!--
This is simply a convenience forwarder to avoid loading
the gameSettings from the main menu or command line.
the gameSettings from the main menu.
-->
<include>autostart/autostart.xml</include>
</page>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<!--
This is simply a convenience forwarder to avoid loading
the gamesetup_mp when autostarting from command line.
-->
<include>common/modern/styles.xml</include>
<include>autostart/autostart_client.xml</include>
</page>

View File

@ -1,10 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<!--
This is simply a convenience forwarder to avoid loading
the gamesetup_mp when autostarting from command line.
-->
<include>common/modern/styles.xml</include>
<include>autostart/autostart_host.xml</include>
</page>

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -170,7 +170,7 @@ void CMapGeneratorWorker::InitScriptInterface(const u32 seed)
m_MapGenRNG.seed(seed);
// VFS
JSI_VFS::RegisterScriptFunctions_Maps(*m_ScriptInterface);
JSI_VFS::RegisterScriptFunctions_ReadOnlySimulationMaps(*m_ScriptInterface);
// Globalscripts may use VFS script functions
m_ScriptInterface->LoadGlobalScripts();

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -71,6 +71,6 @@ void GuiScriptingInit(ScriptInterface& scriptInterface)
JSI_Simulation::RegisterScriptFunctions(rq);
JSI_Sound::RegisterScriptFunctions(rq);
JSI_UserReport::RegisterScriptFunctions(rq);
JSI_VFS::RegisterScriptFunctions_GUI(rq);
JSI_VFS::RegisterScriptFunctions_ReadWriteAnywhere(rq);
JSI_VisualReplay::RegisterScriptFunctions(rq);
}

View File

@ -455,10 +455,13 @@ static void NonVisualFrame()
g_Profiler2.IncrementFrameNumber();
PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber());
static u32 turn = 0;
debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH);
if (g_NetClient)
g_NetClient->Poll();
g_Game->GetSimulation2()->Update(DEFAULT_TURN_LENGTH);
static u32 turn = 0;
if (g_Game && g_Game->IsGameStarted() && g_Game->GetTurnManager())
if (g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1))
debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH);
g_Profiler.Frame();
@ -505,7 +508,7 @@ static void RunGameOrAtlas(int argc, const char* argv[])
return;
}
if (args.Has("autostart-nonvisual") && args.Get("autostart").empty() && !args.Has("rl-interface"))
if (args.Has("autostart-nonvisual") && args.Get("autostart").empty() && !args.Has("rl-interface") && !args.Has("autostart-client"))
{
LOGERROR("-autostart-nonvisual cant be used alone. A map with -autostart=\"TYPEDIR/MAPNAME\" is needed.");
return;
@ -661,8 +664,9 @@ static void RunGameOrAtlas(int argc, const char* argv[])
if (isNonVisual)
{
InitNonVisual(args);
if (isUsingRLInterface)
if (!InitNonVisual(args))
g_Shutdown = ShutdownType::Quit;
else if (isUsingRLInterface)
StartRLInterface(args);
while (g_Shutdown == ShutdownType::None)

View File

@ -24,6 +24,7 @@
#include "graphics/TerrainTextureManager.h"
#include "gui/CGUI.h"
#include "gui/GUIManager.h"
#include "gui/Scripting/JSInterface_GUIManager.h"
#include "i18n/L10n.h"
#include "lib/app_hooks.h"
#include "lib/config2.h"
@ -36,6 +37,7 @@
#include "network/NetClient.h"
#include "network/NetMessage.h"
#include "network/NetMessages.h"
#include "network/scripting/JSInterface_Network.h"
#include "ps/CConsole.h"
#include "ps/CLogger.h"
#include "ps/ConfigDB.h"
@ -58,6 +60,9 @@
#include "ps/Profiler2.h"
#include "ps/Pyrogenesis.h" // psSetLogDir
#include "ps/scripting/JSInterface_Console.h"
#include "ps/scripting/JSInterface_Game.h"
#include "ps/scripting/JSInterface_Main.h"
#include "ps/scripting/JSInterface_VFS.h"
#include "ps/TouchInput.h"
#include "ps/UserReport.h"
#include "ps/Util.h"
@ -74,6 +79,7 @@
#include "scriptinterface/ScriptContext.h"
#include "scriptinterface/ScriptConversions.h"
#include "simulation2/Simulation2.h"
#include "simulation2/scripting/JSInterface_Simulation.h"
#include "soundmanager/scripting/JSInterface_Sound.h"
#include "soundmanager/ISoundManager.h"
#include "tools/atlas/GameInterface/GameLoop.h"
@ -710,9 +716,9 @@ void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& i
}
}
void InitNonVisual(const CmdLineArgs& args)
bool InitNonVisual(const CmdLineArgs& args)
{
Autostart(args);
return Autostart(args);
}
/**
@ -760,6 +766,34 @@ CStr8 LoadSettingsOfScenarioMap(const VfsPath &mapPath)
return mapElement.GetText();
}
// TODO: this essentially duplicates the CGUI logic to load directory or scripts.
// NB: this won't make sure to not double-load scripts, unlike the GUI.
void AutostartLoadScript(const ScriptInterface& scriptInterface, const VfsPath& path)
{
if (path.IsDirectory())
{
VfsPaths pathnames;
vfs::GetPathnames(g_VFS, path, L"*.js", pathnames);
for (const VfsPath& file : pathnames)
scriptInterface.LoadGlobalScriptFile(file);
}
else
scriptInterface.LoadGlobalScriptFile(path);
}
// TODO: this essentially duplicates the CGUI function
CParamNode GetTemplate(const std::string& templateName)
{
// This is very cheap to create so let's just do it every time.
CTemplateLoader templateLoader;
const CParamNode& templateRoot = templateLoader.GetTemplateFileData(templateName).GetChild("Entity");
if (!templateRoot.IsOk())
LOGERROR("Invalid template found for '%s'", templateName.c_str());
return templateRoot;
}
/*
* Command line options for autostart
* (keep synchronized with binaries/system/readme.txt):
@ -818,6 +852,9 @@ CStr8 LoadSettingsOfScenarioMap(const VfsPath &mapPath)
*/
bool Autostart(const CmdLineArgs& args)
{
if (!args.Has("autostart-client") && !args.Has("autostart"))
return false;
// Get optional playername.
CStrW userName = L"anonymous";
if (args.Has("autostart-playername"))
@ -827,6 +864,30 @@ bool Autostart(const CmdLineArgs& args)
ScriptInterface scriptInterface("Engine", "Game Setup", g_ScriptContext);
ScriptRequest rq(scriptInterface);
// We use the javascript gameSettings to handle options, but that requires running JS.
// Since we don't want to use the full Gui manager, we load an entrypoint script
// that can run the priviledged "LoadScript" function, and then call the appropriate function.
ScriptFunction::Register<&AutostartLoadScript>(rq, "LoadScript");
// Load the entire folder to allow mods to extend the entrypoint without copying the whole file.
AutostartLoadScript(scriptInterface, VfsPath(L"autostart/"));
// Provide some required functions to the script.
if (args.Has("autostart-nonvisual"))
ScriptFunction::Register<&GetTemplate>(rq, "GetTemplate");
else
{
JSI_GUIManager::RegisterScriptFunctions(rq);
// TODO: this loads pregame, which is hardcoded to exist by various code paths. That ought be changed.
InitPs(false, L"page_pregame.xml", g_GUI->GetScriptInterface().get(), JS::UndefinedHandleValue);
}
JSI_Game::RegisterScriptFunctions(rq);
JSI_Main::RegisterScriptFunctions(rq);
JSI_Simulation::RegisterScriptFunctions(rq);
JSI_VFS::RegisterScriptFunctions_ReadWriteAnywhere(rq);
JSI_Network::RegisterScriptFunctions(rq);
JS::RootedValue sessionInitData(rq.cx);
if (args.Has("autostart-client"))
@ -843,8 +904,23 @@ bool Autostart(const CmdLineArgs& args)
"port", PS_DEFAULT_PORT,
"storeReplay", !args.Has("autostart-disable-replay"));
InitPs(true, L"page_autostart_client.xml", &scriptInterface, sessionInitData);
JS::RootedValue global(rq.cx, rq.globalValue());
if (!ScriptFunction::CallVoid(rq, global, "autostartClient", sessionInitData, true))
return false;
bool shouldQuit = false;
while (!shouldQuit)
{
g_NetClient->Poll();
ScriptFunction::Call(rq, global, "onTick", shouldQuit);
std::this_thread::sleep_for(std::chrono::microseconds(200));
}
if (args.Has("autostart-nonvisual"))
{
LDR_NonprogressiveLoad();
g_Game->ReallyStartGame();
}
return true;
}
@ -1096,7 +1172,18 @@ bool Autostart(const CmdLineArgs& args)
"maxPlayers", maxPlayers,
"storeReplay", !args.Has("autostart-disable-replay"));
InitPs(true, L"page_autostart_host.xml", &scriptInterface, sessionInitData);
JS::RootedValue global(rq.cx, rq.globalValue());
if (!ScriptFunction::CallVoid(rq, global, "autostartHost", sessionInitData, true))
return false;
// In MP host mode, we need to wait until clients have loaded.
bool shouldQuit = false;
while (!shouldQuit)
{
g_NetClient->Poll();
ScriptFunction::Call(rq, global, "onTick", shouldQuit);
std::this_thread::sleep_for(std::chrono::microseconds(200));
}
}
else
{
@ -1118,7 +1205,15 @@ bool Autostart(const CmdLineArgs& args)
"playerAssignments", playerAssignments,
"storeReplay", !args.Has("autostart-disable-replay"));
InitPs(true, L"page_autostart.xml", &scriptInterface, sessionInitData);
JS::RootedValue global(rq.cx, rq.globalValue());
if (!ScriptFunction::CallVoid(rq, global, "autostartHost", sessionInitData, false))
return false;
}
if (args.Has("autostart-nonvisual"))
{
LDR_NonprogressiveLoad();
g_Game->ReallyStartGame();
}
return true;

View File

@ -79,7 +79,7 @@ extern void MountMods(const Paths& paths, const std::vector<CStr>& mods);
extern bool Init(const CmdLineArgs& args, int flags);
extern void InitInput();
extern void InitGraphics(const CmdLineArgs& args, int flags, const std::vector<CStr>& installedMods = std::vector<CStr>());
extern void InitNonVisual(const CmdLineArgs& args);
extern bool InitNonVisual(const CmdLineArgs& args);
extern void Shutdown(int flags);
extern void CancelLoad(const CStrW& message);

View File

@ -265,7 +265,7 @@ VFS_ScriptFunctions(Simulation);
VFS_ScriptFunctions(Maps);
#undef VFS_ScriptFunctions
void RegisterScriptFunctions_GUI(const ScriptRequest& rq)
void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq)
{
ScriptFunction::Register<&Script_ListDirectoryFiles_GUI>(rq, "ListDirectoryFiles");
ScriptFunction::Register<&Script_FileExists_GUI>(rq, "FileExists");
@ -278,14 +278,14 @@ void RegisterScriptFunctions_GUI(const ScriptRequest& rq)
ScriptFunction::Register<&DeleteCampaignSave>(rq, "DeleteCampaignSave");
}
void RegisterScriptFunctions_Simulation(const ScriptRequest& rq)
void RegisterScriptFunctions_ReadOnlySimulation(const ScriptRequest& rq)
{
ScriptFunction::Register<&Script_ListDirectoryFiles_Simulation>(rq, "ListDirectoryFiles");
ScriptFunction::Register<&Script_FileExists_Simulation>(rq, "FileExists");
ScriptFunction::Register<&Script_ReadJSONFile_Simulation>(rq, "ReadJSONFile");
}
void RegisterScriptFunctions_Maps(const ScriptRequest& rq)
void RegisterScriptFunctions_ReadOnlySimulationMaps(const ScriptRequest& rq)
{
ScriptFunction::Register<&Script_ListDirectoryFiles_Maps>(rq, "ListDirectoryFiles");
ScriptFunction::Register<&Script_FileExists_Maps>(rq, "FileExists");

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2021 Wildfire Games.
/* Copyright (C) 2022 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -22,9 +22,9 @@ class ScriptRequest;
namespace JSI_VFS
{
void RegisterScriptFunctions_GUI(const ScriptRequest& rq);
void RegisterScriptFunctions_Simulation(const ScriptRequest& rq);
void RegisterScriptFunctions_Maps(const ScriptRequest& rq);
void RegisterScriptFunctions_ReadWriteAnywhere(const ScriptRequest& rq);
void RegisterScriptFunctions_ReadOnlySimulation(const ScriptRequest& rq);
void RegisterScriptFunctions_ReadOnlySimulationMaps(const ScriptRequest& rq);
}
#endif // INCLUDED_JSI_VFS

View File

@ -270,7 +270,7 @@ public:
#undef REGISTER_FUNC_NAME
JSI_VFS::RegisterScriptFunctions_Simulation(rq);
JSI_VFS::RegisterScriptFunctions_ReadOnlySimulation(rq);
// Globalscripts may use VFS script functions
m_ScriptInterface->LoadGlobalScripts();

View File

@ -68,7 +68,7 @@ CComponentManager::CComponentManager(CSimContext& context, std::shared_ptr<Scrip
// these functions, so we skip registering them here in those cases
if (!skipScriptFunctions)
{
JSI_VFS::RegisterScriptFunctions_Simulation(m_ScriptInterface);
JSI_VFS::RegisterScriptFunctions_ReadOnlySimulation(m_ScriptInterface);
ScriptRequest rq(m_ScriptInterface);
constexpr ScriptFunction::ObjectGetter<CComponentManager> Getter = &ScriptInterface::ObjectFromCBData<CComponentManager>;
ScriptFunction::Register<&CComponentManager::Script_RegisterComponentType, Getter>(rq, "RegisterComponentType");