Start Atlas by closing the root page

Theere is now an  `Engine.startAtlas` property that will start Atlas
when it's returned from the root page. The `Engine.RestartInAtlas`
function is removed.
This commit is contained in:
phosit 2025-03-12 14:05:27 +01:00 committed by phosit
parent c2d3595777
commit 2d206708cd
9 changed files with 64 additions and 26 deletions

View file

@ -0,0 +1,4 @@
async function init(arg)
{
return arg ? Engine.startAtlas : undefined;
}

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<objects>
<script file="gui/Result/Result.js"/>
</objects>

View file

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<page>
<include>Result/Result.xml</include>
</page>

View file

@ -275,7 +275,7 @@ var g_MainMenuItems = [
{
"caption": translate("Scenario Editor"),
"tooltip": translate('Open the Atlas Scenario Editor in a new window. You can run this more reliably by starting the game with the command-line argument "-editor".'),
"onPress": async() => {
"onPress": async(closePageCallback) => {
if (!Engine.AtlasIsAvailable())
{
messageBox(
@ -292,7 +292,7 @@ var g_MainMenuItems = [
[translate("No"), translate("Yes")]);
if (buttonIndex === 1)
Engine.RestartInAtlas();
closePageCallback(Engine.startAtlas);
}
},
{

View file

@ -35,11 +35,14 @@
#include "scriptinterface/ScriptInterface.h"
#include "scriptinterface/StructuredClone.h"
#include "js/Equality.h"
namespace
{
const CStr EVENT_NAME_GAME_LOAD_PROGRESS = "GameLoadProgress";
const CStr EVENT_NAME_WINDOW_RESIZED = "WindowResized";
constexpr const char* START_ATLAS{"startAtlas"};
} // anonymous namespace
@ -165,6 +168,12 @@ void CGUIManager::SGUIPage::LoadPage(ScriptContext& scriptContext)
sendingPromise = std::make_shared<JS::PersistentRootedObject>(rq.cx,
JS::NewPromiseObject(rq.cx, nullptr));
{
JS::RootedString jsName{rq.cx, JS_NewStringCopyZ(rq.cx, START_ATLAS)};
JS::RootedValue symbol{rq.cx, JS::SymbolValue(JS::NewSymbol(rq.cx, jsName))};
JS::RootedValue nativeScope{rq.cx, JS::ObjectValue(*rq.nativeScope)};
Script::SetProperty(rq, nativeScope, START_ATLAS, symbol, true);
}
gui->AddObjectTypes();
VfsPath path = VfsPath("gui") / m_Name;
@ -257,7 +266,7 @@ JS::Value CGUIManager::SGUIPage::ReplacePromise(ScriptInterface& scriptInterface
return JS::ObjectValue(**receivingPromise);
}
std::optional<CGUIManager::SGUIPage::CloseResult> CGUIManager::SGUIPage::MaybeClose()
std::optional<CGUIManager::SGUIPage::CloseResult> CGUIManager::SGUIPage::MaybeClose(const bool topmostPage)
{
if (JS::GetPromiseState(*sendingPromise) == JS::PromiseState::Pending)
return std::nullopt;
@ -267,8 +276,20 @@ std::optional<CGUIManager::SGUIPage::CloseResult> CGUIManager::SGUIPage::MaybeCl
const ScriptRequest rq{gui->GetScriptInterface()};
JS::RootedValue arg{rq.cx, JS::GetPromiseResult(*sendingPromise)};
return CGUIManager::SGUIPage::CloseResult{Script::WriteStructuredClone(rq, arg),
JS::GetPromiseState(*sendingPromise) == JS::PromiseState::Rejected};
const bool rejected{JS::GetPromiseState(*sendingPromise) == JS::PromiseState::Rejected};
if (topmostPage)
{
JS::RootedValue nativeScope{rq.cx, JS::ObjectValue(*rq.nativeScope)};
JS::RootedValue symbol{rq.cx};
Script::GetProperty(rq, nativeScope, START_ATLAS, &symbol);
bool equals;
if (!JS::StrictlyEqual(rq.cx, arg, symbol, &equals))
throw std::runtime_error{"Error while comparing return value to a symbol."};
if (equals)
return CGUIManager::SGUIPage::CloseResult{nullptr, rejected};
}
return CGUIManager::SGUIPage::CloseResult{Script::WriteStructuredClone(rq, arg), rejected};
}
void CGUIManager::SGUIPage::Refocus(const CloseResult& result)
@ -375,7 +396,7 @@ void CGUIManager::SendEventToAll(const CStr& eventName, JS::HandleValueArray par
p.gui->SendEventToAll(eventName, paramData);
}
void CGUIManager::TickObjects()
std::optional<bool> CGUIManager::TickObjects()
{
PROFILE3("gui tick");
@ -394,16 +415,20 @@ void CGUIManager::TickObjects()
while (!m_PageStack.empty())
{
const size_t stackSize{m_PageStack.size()};
const std::optional<SGUIPage::CloseResult> result{m_PageStack.back().MaybeClose()};
const std::optional<SGUIPage::CloseResult> result{
m_PageStack.back().MaybeClose(stackSize == 1)};
if (!result.has_value())
break;
ENSURE(m_PageStack.size() == stackSize);
m_PageStack.pop_back();
if (!m_PageStack.empty())
if (m_PageStack.empty())
return !result.value().arg;
else
m_PageStack.back().Refocus(result.value());
m_ScriptContext.RunJobs();
}
return std::nullopt;
}
void CGUIManager::Draw(CCanvas2D& canvas) const

View file

@ -96,8 +96,10 @@ public:
/**
* See CGUI::TickObjects; applies to @em all loaded pages.
* When the root page is closed it's returned wheter Atlas should be
* started.
*/
void TickObjects();
std::optional<bool> TickObjects();
/**
* See CGUI::Draw; applies to @em all loaded pages.
@ -156,7 +158,7 @@ private:
* returns the result of the @c init function.
* If this page wasn't closed an empty optional is returned.
*/
std::optional<CloseResult> MaybeClose();
std::optional<CloseResult> MaybeClose(const bool topmostPage);
/**
* This function should be called when a child page got closed. The

View file

@ -284,4 +284,16 @@ public:
CloseTopmostPage();
TS_ASSERT_EQUALS(g_GUI->GetPageCount(), 0);
}
void test_Result()
{
const ScriptRequest rq{g_GUI->GetScriptInterface()};
g_GUI->OpenChildPage(L"Result/page_Result.xml",
Script::WriteStructuredClone(rq, JS::FalseHandleValue));
TS_ASSERT(!g_GUI->TickObjects().value());
g_GUI->OpenChildPage(L"Result/page_Result.xml",
Script::WriteStructuredClone(rq, JS::TrueHandleValue));
TS_ASSERT(g_GUI->TickObjects().value());
}
};

View file

@ -172,11 +172,6 @@ void RestartEngine()
g_Shutdown = ShutdownType::Restart;
}
void StartAtlas()
{
g_Shutdown = ShutdownType::RestartAsAtlas;
}
// main app message handler
static InReaction MainInputHandler(const SDL_Event_* ev)
{
@ -430,9 +425,9 @@ static void Frame(RL::Interface* rlInterface)
if (g_NetClient)
g_NetClient->Poll();
g_GUI->TickObjects();
if (g_GUI->GetPageCount() == 0)
QuitEngine();
std::optional<bool> completionCommand{g_GUI->TickObjects()};
if (completionCommand.has_value())
g_Shutdown = completionCommand.value() ? ShutdownType::RestartAsAtlas : ShutdownType::Quit;
if (rlInterface)
rlInterface->TryApplyMessage();

View file

@ -34,15 +34,8 @@
#include "scriptinterface/FunctionWrapper.h"
#include "tools/atlas/GameInterface/GameLoop.h"
extern void StartAtlas();
namespace JSI_Main
{
void StartAtlas()
{
::StartAtlas();
}
bool AtlasIsAvailable()
{
return ATLAS_IsAvailable();
@ -120,7 +113,6 @@ std::string CalculateMD5(const std::string& input)
void RegisterScriptFunctions(const ScriptRequest& rq)
{
ScriptFunction::Register<&StartAtlas>(rq, "RestartInAtlas");
ScriptFunction::Register<&AtlasIsAvailable>(rq, "AtlasIsAvailable");
ScriptFunction::Register<&IsAtlasRunning>(rq, "IsAtlasRunning");
ScriptFunction::Register<&OpenURL>(rq, "OpenURL");