Fix UI when connecting to a server fails

When the connection fails, it wasn't possible to close the progress
window.
Now `PollNetworkClient` also resolves the previous promise.
This commit is contained in:
phosit 2026-04-29 21:44:55 +02:00
parent 32e5520507
commit a95579a046
No known key found for this signature in database
GPG key ID: C9430B600671C268
8 changed files with 49 additions and 24 deletions

View file

@ -32,6 +32,8 @@ class NetMessages
while (true)
{
const message = await Engine.PollNetworkClient();
if (!message)
return;
log("Net message: " + uneval(message));

View file

@ -47,7 +47,11 @@ function init(initData, hotloadData)
return Promise.race([new Promise(closePageCallback =>
{
g_SetupWindow = new SetupWindow(initData, hotloadData, closePageCallback);
}), ...(g_IsNetworked ? [g_SetupWindow.controls.netMessages.pollPendingMessages()] : [])]);
}), new Promise((_, reject) =>
{
if (g_IsNetworked)
g_SetupWindow.controls.netMessages.pollPendingMessages().catch(reject);
})]);
}
function getHotloadData()

View file

@ -72,7 +72,9 @@ async function waitOnEvent(loadSavedGame, joinFromLobby)
}));
if (tickResult === cancelTag)
break;
const result = await onTick(loadSavedGame);
const result = await cancelOr(onTick(loadSavedGame));
if (result === cancelTag)
break;
if (typeof result === "object")
return result;
if (result)
@ -240,7 +242,7 @@ function getConnectionFailReason(reason)
function reportConnectionFail(reason)
{
messageBox(
return messageBox(
400, 200,
(translate("Failed to connect to the server.")
) + "\n\n" + getConnectionFailReason(reason),
@ -253,6 +255,8 @@ async function pollAndHandleNetworkClient(loadSavedGame)
while (true)
{
const message = await Engine.PollNetworkClient();
if (!message)
return true;
if (!g_IsConnecting)
continue;
@ -268,7 +272,7 @@ async function pollAndHandleNetworkClient(loadSavedGame)
switch (message.status)
{
case "failed":
reportConnectionFail(message.reason, false);
await reportConnectionFail(message.reason, false);
return true;
default:
@ -326,7 +330,7 @@ async function pollAndHandleNetworkClient(loadSavedGame)
switch (message.status)
{
case "failed":
reportConnectionFail(message.reason, false);
await reportConnectionFail(message.reason, false);
return true;
default:

View file

@ -425,6 +425,8 @@ async function handleNetMessages()
while (true)
{
const msg = await Engine.PollNetworkClient();
if (!msg)
return;
log("Net message: " + uneval(msg));

View file

@ -331,20 +331,23 @@ async function init(initData, hotloadData)
resumeGame();
});
const promise = Promise.race([g_IsNetworked ? handleNetMessages() : new Promise(() => {}),
new Promise(closePageCallback =>
{
g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates.bind(undefined,
closePageCallback));
g_Menu = new Menu(g_PauseControl, g_PlayerViewControl, g_Chat, closePageCallback);
g_NetworkStatusOverlay = new NetworkStatusOverlay(closePageCallback);
g_QuitConfirmationDefeat = new QuitConfirmationDefeat(closePageCallback);
g_QuitConfirmationReplay = new QuitConfirmationReplay(closePageCallback);
// TODO: use event instead
onSimulationUpdate(closePageCallback);
Engine.GetGUIObjectByName("session").onSimulationUpdate =
onSimulationUpdate.bind(undefined, closePageCallback);
})]);
const promise = Promise.race([new Promise((_, reject) =>
{
if (g_IsNetworked)
handleNetMessages().catch(reject);
}), new Promise(closePageCallback =>
{
g_PlayerViewControl.registerViewedPlayerChangeHandler(resetTemplates.bind(undefined,
closePageCallback));
g_Menu = new Menu(g_PauseControl, g_PlayerViewControl, g_Chat, closePageCallback);
g_NetworkStatusOverlay = new NetworkStatusOverlay(closePageCallback);
g_QuitConfirmationDefeat = new QuitConfirmationDefeat(closePageCallback);
g_QuitConfirmationReplay = new QuitConfirmationReplay(closePageCallback);
// TODO: use event instead
onSimulationUpdate(closePageCallback);
Engine.GetGUIObjectByName("session").onSimulationUpdate =
onSimulationUpdate.bind(undefined, closePageCallback);
})]);
for (const handler of g_PlayersInitHandlers)
handler();

View file

@ -108,7 +108,7 @@ CGUI::CGUI(ScriptContext& context)
CGUI::~CGUI()
{
if (g_NetClient)
g_NetClient->Unregister(*m_ScriptInterface);
g_NetClient->Unregister(m_ScriptInterface.get());
}
InReaction CGUI::HandleEvent(const SDL_Event_* ev)

View file

@ -159,6 +159,8 @@ CNetClient::CNetClient(CGame* game, const CStrW& username, const CStr& hostJID,
CNetClient::~CNetClient()
{
Unregister(nullptr);
// Try to flush messages before dying (probably fails).
if (m_ClientTurnManager)
m_ClientTurnManager->OnDestroyConnection();
@ -364,6 +366,7 @@ void CNetClient::CheckServerConnection()
JSObject* CNetClient::GetNextGUIMessage(const ScriptInterface& guiInterface)
{
Unregister(nullptr);
const ScriptRequest rq{guiInterface};
m_GuiMessagePoll.emplace(GuiPollData{guiInterface, {rq.cx, JS::NewPromiseObject(rq.cx, nullptr)}});
@ -371,10 +374,17 @@ JSObject* CNetClient::GetNextGUIMessage(const ScriptInterface& guiInterface)
return m_GuiMessagePoll.value().promise;
}
void CNetClient::Unregister(const ScriptInterface& guiInterface)
void CNetClient::Unregister(const ScriptInterface* guiInterface)
{
if (m_GuiMessagePoll.has_value() && &m_GuiMessagePoll.value().interface == &guiInterface)
m_GuiMessagePoll.reset();
if (!m_GuiMessagePoll.has_value() ||
(guiInterface && &m_GuiMessagePoll.value().interface != guiInterface))
{
return;
}
auto& [interface, promise] = m_GuiMessagePoll.value();
const ScriptRequest oldRq{interface};
JS::ResolvePromise(oldRq.cx, promise, JS::UndefinedHandleValue);
m_GuiMessagePoll.reset();
}
void CNetClient::FetchMessage()

View file

@ -147,7 +147,7 @@ public:
* Has to be called bevore the @c ScriptInterface gets destroied so that
* no future messages are sent to it.
*/
void Unregister(const ScriptInterface& guiInterface);
void Unregister(const ScriptInterface* guiInterface);
/**
* Add a message to the queue, to be read by GuiPoll.