mirror of
https://gitea.wildfiregames.com/0ad/0ad
synced 2026-06-16 05:13:58 -07:00
Wait for autostart by promise
Since the completion is checked using the promise the `onTick` function can be removed. This replaces the `AutoStart` `AutoStartClient` and `AutoStartHost` by async functions. The functions can now return something to the engine. That is used to inform the engine which page to open. That was previously done in JavaScript. Which is ugly because it doesn't know whether it's in visual-mode.
This commit is contained in:
parent
6805efc08a
commit
46b27f22ca
5 changed files with 140 additions and 206 deletions
|
|
@ -1,36 +1,22 @@
|
|||
class AutoStart
|
||||
async function autoStart(cmdLineArgs)
|
||||
{
|
||||
constructor(cmdLineArgs)
|
||||
{
|
||||
this.playerAssignments = {
|
||||
"local": {
|
||||
"player": +(cmdLineArgs?.['autostart-player'] ?? 1),
|
||||
"name": "anonymous",
|
||||
},
|
||||
};
|
||||
this.settings = new GameSettings().init();
|
||||
const playerAssignments = {
|
||||
"local": {
|
||||
"player": +(cmdLineArgs?.['autostart-player'] ?? 1),
|
||||
"name": "anonymous",
|
||||
},
|
||||
};
|
||||
const settings = new GameSettings().init();
|
||||
|
||||
// Enable cheats in SP
|
||||
this.settings.cheats.setEnabled(true);
|
||||
// Enable cheats in SP
|
||||
settings.cheats.setEnabled(true);
|
||||
|
||||
parseCmdLineArgs(this.settings, cmdLineArgs);
|
||||
parseCmdLineArgs(settings, cmdLineArgs);
|
||||
|
||||
this.settings.launchGame(this.playerAssignments, !('autostart-disable-replay' in cmdLineArgs));
|
||||
this.onLaunch();
|
||||
}
|
||||
settings.launchGame(playerAssignments, !('autostart-disable-replay' in cmdLineArgs));
|
||||
|
||||
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
|
||||
});
|
||||
}
|
||||
return ["page_loading.xml", {
|
||||
"attribs": settings.finalizedAttributes,
|
||||
"playerAssignments": playerAssignments
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,61 +1,36 @@
|
|||
class AutoStartClient
|
||||
async function autoStartClient(cmdLineArgs)
|
||||
{
|
||||
done = false;
|
||||
constructor(cmdLineArgs)
|
||||
try
|
||||
{
|
||||
this.playerAssignments = {};
|
||||
|
||||
try
|
||||
{
|
||||
const playerName = cmdLineArgs['autostart-playername'] || "anonymous";
|
||||
const ip = cmdLineArgs['autostart-client'] ?? "127.0.0.1";
|
||||
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
|
||||
Engine.StartNetworkJoin(playerName, ip, port, !('autostart-disable-replay' in cmdLineArgs));
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
const message = sprintf(translate("Cannot join game: %(message)s."), { "message": e.message });
|
||||
messageBox(400, 200, message, translate("Error"));
|
||||
}
|
||||
|
||||
(async() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const message = await Engine.PollNetworkClient();
|
||||
|
||||
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.
|
||||
this.done = true;
|
||||
return;
|
||||
default:
|
||||
}
|
||||
}
|
||||
})();
|
||||
const playerName = cmdLineArgs['autostart-playername'] || "anonymous";
|
||||
const ip = cmdLineArgs['autostart-client'] ?? "127.0.0.1";
|
||||
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
|
||||
Engine.StartNetworkJoin(playerName, ip, port, !('autostart-disable-replay' in cmdLineArgs));
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
const message = sprintf(translate("Cannot join game: %(message)s."), { "message": e.message });
|
||||
messageBox(400, 200, message, translate("Error"));
|
||||
}
|
||||
|
||||
onTick()
|
||||
let playerAssignments = {};
|
||||
while (true)
|
||||
{
|
||||
return this.done;
|
||||
}
|
||||
const message = await Engine.PollNetworkClient();
|
||||
|
||||
/**
|
||||
* 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
|
||||
});
|
||||
switch (message.type)
|
||||
{
|
||||
case "players":
|
||||
playerAssignments = message.newAssignments;
|
||||
Engine.SendNetworkReady(2);
|
||||
break;
|
||||
case "start":
|
||||
return ["page_loading.xml", {
|
||||
"attribs": message.initAttributes,
|
||||
"isRejoining": true,
|
||||
"playerAssignments": playerAssignments
|
||||
}];
|
||||
default:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,97 +1,74 @@
|
|||
class AutoStartHost
|
||||
async function autoStartHost(cmdLineArgs)
|
||||
{
|
||||
done = false;
|
||||
constructor(cmdLineArgs)
|
||||
const maxPlayers = +(cmdLineArgs['autostart-host-players'] ?? 2);
|
||||
|
||||
try
|
||||
{
|
||||
this.launched = false;
|
||||
this.playerAssignments = {};
|
||||
const playerName = cmdLineArgs['autostart-playername'] || "anonymous";
|
||||
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
|
||||
|
||||
this.maxPlayers = +(cmdLineArgs['autostart-host-players'] ?? 2);
|
||||
this.cmdLineArgs = cmdLineArgs;
|
||||
|
||||
try
|
||||
{
|
||||
const playerName = cmdLineArgs['autostart-playername'] || "anonymous";
|
||||
const port = +(cmdLineArgs['autostart-port'] ?? 5073);
|
||||
|
||||
// Password not implemented for autostart.
|
||||
Engine.StartNetworkHost(playerName, port, "", false, !('autostart-disable-replay' in cmdLineArgs));
|
||||
}
|
||||
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.
|
||||
*/
|
||||
(async() =>
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
const message = await Engine.PollNetworkClient();
|
||||
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":
|
||||
this.done = true;
|
||||
return;
|
||||
default:
|
||||
}
|
||||
|
||||
if (!this.launched)
|
||||
{
|
||||
const assignementArray = Object.values(this.playerAssignments);
|
||||
if (assignementArray.length === this.maxPlayers &&
|
||||
assignementArray.every(assignement =>
|
||||
assignement.player !== -1 || assignement.status !== 0))
|
||||
{
|
||||
this.onLaunch();
|
||||
}
|
||||
}
|
||||
}
|
||||
})();
|
||||
// Password not implemented for autostart.
|
||||
Engine.StartNetworkHost(playerName, port, "", false, !('autostart-disable-replay' in cmdLineArgs));
|
||||
}
|
||||
|
||||
onTick()
|
||||
catch(e)
|
||||
{
|
||||
return this.done;
|
||||
const message = sprintf(translate("Cannot host game: %(message)s."), { "message": e.message });
|
||||
messageBox(400, 200, message, translate("Error"));
|
||||
}
|
||||
|
||||
/**
|
||||
* In the visual autostart path, we need to show the loading screen.
|
||||
* Overload this as appropriate.
|
||||
* Handles a simple implementation of player assignments.
|
||||
* Should not need be overloaded in mods unless you want to change that logic.
|
||||
*/
|
||||
onLaunch()
|
||||
|
||||
let playerAssignments = {};
|
||||
while (true)
|
||||
{
|
||||
this.launched = true;
|
||||
const message = await Engine.PollNetworkClient();
|
||||
switch (message.type)
|
||||
{
|
||||
case "players":
|
||||
{
|
||||
playerAssignments = message.newAssignments;
|
||||
Engine.SendNetworkReady(2);
|
||||
let max = 0;
|
||||
for (const uid in playerAssignments)
|
||||
{
|
||||
max = Math.max(playerAssignments[uid].player, max);
|
||||
if (playerAssignments[uid].player == -1)
|
||||
Engine.AssignNetworkPlayer(++max, uid);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "ready":
|
||||
playerAssignments[message.guid].status = message.status;
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
this.settings = new GameSettings().init();
|
||||
|
||||
parseCmdLineArgs(this.settings, this.cmdLineArgs);
|
||||
|
||||
this.settings.playerCount.setNb(Object.keys(this.playerAssignments).length);
|
||||
this.settings.launchGame(this.playerAssignments, this.storeReplay);
|
||||
Engine.SwitchGuiPage("page_loading.xml", {
|
||||
"attribs": this.settings.finalizedAttributes,
|
||||
"playerAssignments": this.playerAssignments
|
||||
});
|
||||
const assignementArray = Object.values(playerAssignments);
|
||||
if (assignementArray.length === maxPlayers &&
|
||||
assignementArray.every(assignement =>
|
||||
assignement.player !== -1 || assignement.status !== 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const settings = new GameSettings().init();
|
||||
|
||||
parseCmdLineArgs(settings, cmdLineArgs);
|
||||
|
||||
settings.playerCount.setNb(Object.keys(playerAssignments).length);
|
||||
settings.launchGame(playerAssignments, false);
|
||||
|
||||
while ((await Engine.PollNetworkClient()).type !== "start")
|
||||
{
|
||||
// Just wait for condition
|
||||
}
|
||||
|
||||
return ["page_loading.xml", {
|
||||
"attribs": settings.finalizedAttributes,
|
||||
"playerAssignments": playerAssignments
|
||||
}];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,6 @@
|
|||
Engine.HasXmppClient = () => false;
|
||||
Engine.SetRankedGame = () => {};
|
||||
Engine.TextureExists = () => false;
|
||||
Engine.OpenChildPage = () => {};
|
||||
Engine.SwitchGuiPage = () => {};
|
||||
|
||||
var translateObjectKeys = () => {};
|
||||
var translate = x => x;
|
||||
|
|
@ -20,11 +18,9 @@ Engine.LoadScript("globalscripts/");
|
|||
// TODO: clean this up and show errors better in the non-visual path.
|
||||
Engine.LoadScript("gui/common/functions_msgbox.js");
|
||||
|
||||
var autostartInstance;
|
||||
|
||||
function autostartClient(cmdLineArgs)
|
||||
{
|
||||
autostartInstance = new AutoStartClient(cmdLineArgs);
|
||||
return autoStartClient(cmdLineArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -44,15 +40,6 @@ function autostartHost(cmdLineArgs, networked = false)
|
|||
Engine.LoadScript("gamesettings/attributes/");
|
||||
|
||||
if (networked)
|
||||
autostartInstance = new AutoStartHost(cmdLineArgs);
|
||||
else
|
||||
autostartInstance = new AutoStart(cmdLineArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns false if the loop should carry on.
|
||||
*/
|
||||
function onTick()
|
||||
{
|
||||
return autostartInstance.onTick();
|
||||
return autoStartHost(cmdLineArgs);
|
||||
return autoStart(cmdLineArgs);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@
|
|||
#include <fmt/format.h>
|
||||
#include <fstream>
|
||||
#include <js/CallArgs.h>
|
||||
#include <js/Promise.h>
|
||||
#include <js/RootingAPI.h>
|
||||
#include <js/TypeDecls.h>
|
||||
#include <js/Value.h>
|
||||
|
|
@ -841,39 +842,47 @@ bool Autostart(const CmdLineArgs& args)
|
|||
JS::RootedValue cmdLineArgs(rq.cx);
|
||||
Script::ToJSVal(rq, &cmdLineArgs, args);
|
||||
|
||||
if (args.Has("autostart-client") || args.Has("autostart-host"))
|
||||
{
|
||||
// Pass the default port if undefined, to avoid duplicating it in JS.
|
||||
if (!Script::HasProperty(rq, cmdLineArgs, "autostart-port"))
|
||||
Script::SetProperty(rq, cmdLineArgs, "autostart-port", PS_DEFAULT_PORT);
|
||||
// Pass the default port if undefined, to avoid duplicating it in JS.
|
||||
if (!Script::HasProperty(rq, cmdLineArgs, "autostart-port"))
|
||||
Script::SetProperty(rq, cmdLineArgs, "autostart-port", PS_DEFAULT_PORT);
|
||||
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (!ScriptFunction::CallVoid(rq, global, args.Has("autostart-client") ? "autostartClient" : "autostartHost", cmdLineArgs, true))
|
||||
return false;
|
||||
|
||||
bool shouldQuit = false;
|
||||
while (!shouldQuit)
|
||||
{
|
||||
g_NetClient->Poll();
|
||||
g_ScriptContext->RunJobs();
|
||||
if (!ScriptFunction::Call(rq, global, "onTick", shouldQuit))
|
||||
return false;
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||
}
|
||||
}
|
||||
else
|
||||
JS::RootedValue resultValue{rq.cx};
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (!ScriptFunction::Call(rq, global,
|
||||
args.Has("autostart-client") ? "autostartClient" : "autostartHost", &resultValue,
|
||||
cmdLineArgs, args.Has("autostart-host")) && !resultValue.isObject())
|
||||
{
|
||||
JS::RootedValue global(rq.cx, rq.globalValue());
|
||||
if (!ScriptFunction::CallVoid(rq, global, "autostartHost", cmdLineArgs, false))
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
|
||||
JS::RootedObject result{rq.cx, &resultValue.toObject()};
|
||||
while (JS::IsPromiseObject(result) && JS::GetPromiseState(result) == JS::PromiseState::Pending)
|
||||
{
|
||||
g_ScriptContext->RunJobs();
|
||||
g_NetClient->Poll();
|
||||
std::this_thread::sleep_for(std::chrono::microseconds(200));
|
||||
}
|
||||
if (JS::IsPromiseObject(result) && JS::GetPromiseState(result) == JS::PromiseState::Rejected)
|
||||
return false;
|
||||
|
||||
JS::RootedValue pageData{rq.cx, JS::IsPromiseObject(result) ? JS::GetPromiseResult(result) :
|
||||
resultValue};
|
||||
|
||||
if (args.Has("autostart-nonvisual"))
|
||||
{
|
||||
PS::Loader::NonprogressiveLoad();
|
||||
g_Game->ReallyStartGame();
|
||||
return true;
|
||||
}
|
||||
|
||||
std::wstring pageName;
|
||||
Script::GetPropertyInt(rq, pageData, 0, pageName);
|
||||
JS::RootedValue pageArgs{rq.cx};
|
||||
Script::GetPropertyInt(rq, pageData, 1, &pageArgs);
|
||||
Script::StructuredClone clonedpageArgs{Script::WriteStructuredClone(rq, pageArgs)};
|
||||
|
||||
g_GUI->OpenChildPage(pageName, std::move(clonedpageArgs));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue