1
1
forked from 0ad/0ad

Display which clients are still in the loading screen

Reviewed by: elexis
Differential Revision: https://code.wildfiregames.com/D120
Fixes #4375

This was SVN commit r19320.
This commit is contained in:
Imarok 2017-03-21 18:50:29 +00:00
parent a3ea45509b
commit fdda57565b
9 changed files with 90 additions and 18 deletions

View File

@ -50,6 +50,9 @@ var g_NetMessageTypes = {
"paused": msg => {
setClientPauseState(msg.guid, msg.pause);
},
"clients-loading": msg => {
handleClientsLoadingMessage(msg.guids);
},
"rejoined": msg => {
addChatMessage({
"type": "rejoined",
@ -139,7 +142,7 @@ var g_StatusMessageTypes = {
sprintf(translate("Reason: %(reason)s."), {
"reason": getDisconnectReason(msg.reason, true)
}),
"waiting_for_players": msg => translate("Waiting for other players to connect..."),
"waiting_for_players": msg => translate("Waiting for players to connect:"),
"join_syncing": msg => translate("Synchronising gameplay with other players..."),
"active": msg => ""
};
@ -585,10 +588,13 @@ function handleNetStatusMessage(message)
g_IsNetworkedActive = message.status == "active";
let label = Engine.GetGUIObjectByName("netStatus");
let netStatus = Engine.GetGUIObjectByName("netStatus");
let statusMessage = g_StatusMessageTypes[message.status](message);
label.caption = statusMessage;
label.hidden = !statusMessage;
netStatus.caption = statusMessage;
netStatus.hidden = !statusMessage;
let loadingClientsText = Engine.GetGUIObjectByName("loadingClientsText");
loadingClientsText.hidden = message.status != "waiting_for_players";
if (message.status == "disconnected")
{
@ -601,6 +607,12 @@ function handleNetStatusMessage(message)
}
}
function handleClientsLoadingMessage(guids)
{
let loadingClientsText = Engine.GetGUIObjectByName("loadingClientsText");
loadingClientsText.caption = guids.map(guid => colorizePlayernameByGUID(guid)).join(translate(", "));
}
function handlePlayerAssignmentsMessage(message)
{
for (let guid in g_PlayerAssignments)

View File

@ -60,7 +60,7 @@
<object name="resumeMessage" size="50%-128 40%+20 50%+128 40%+40" type="text" style="ResumeMessageText" ghost="true" z="0">
<translatableAttribute id="caption">Click to Resume Game</translatableAttribute>
</object>
<object name="pausedByText" size="30% 40%+50 70% 100%" type="text" style="PausedByText" ghost="true" hidden="true" z="0"/>
<object name="pausedByText" size="30% 40%+50 70% 100%" type="text" style="netStatusPlayersText" ghost="true" hidden="true" z="0"/>
<action on="Press">togglePause();</action>
</object>
@ -159,6 +159,7 @@
</object>
<action on="Press">leaveGame();</action>
</object>
<object name="loadingClientsText" size="50%-300 50%+60 50%+300 50%+110" type="text" style="netStatusPlayersText" hidden="true" z="0"/>
</object>
</objects>

View File

@ -27,7 +27,7 @@
text_valign="center"
/>
<style name="PausedByText"
<style name="netStatusPlayersText"
font="sans-bold-16"
textcolor="white"
text_align="center"

View File

@ -119,12 +119,14 @@ CNetClient::CNetClient(CGame* game, bool isLocalClient) :
AddTransition(NCS_LOADING, (uint)NMT_KICKED, NCS_LOADING, (void*)&OnKicked, context);
AddTransition(NCS_LOADING, (uint)NMT_CLIENT_TIMEOUT, NCS_LOADING, (void*)&OnClientTimeout, context);
AddTransition(NCS_LOADING, (uint)NMT_CLIENT_PERFORMANCE, NCS_LOADING, (void*)&OnClientPerformance, context);
AddTransition(NCS_LOADING, (uint)NMT_CLIENTS_LOADING, NCS_LOADING, (void*)&OnClientsLoading, context);
AddTransition(NCS_LOADING, (uint)NMT_LOADED_GAME, NCS_INGAME, (void*)&OnLoadedGame, context);
AddTransition(NCS_INGAME, (uint)NMT_REJOINED, NCS_INGAME, (void*)&OnRejoined, context);
AddTransition(NCS_INGAME, (uint)NMT_KICKED, NCS_INGAME, (void*)&OnKicked, context);
AddTransition(NCS_INGAME, (uint)NMT_CLIENT_TIMEOUT, NCS_INGAME, (void*)&OnClientTimeout, context);
AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PERFORMANCE, NCS_INGAME, (void*)&OnClientPerformance, context);
AddTransition(NCS_INGAME, (uint)NMT_CLIENTS_LOADING, NCS_INGAME, (void*)&OnClientsLoading, context);
AddTransition(NCS_INGAME, (uint)NMT_CLIENT_PAUSED, NCS_INGAME, (void*)&OnClientPaused, context);
AddTransition(NCS_INGAME, (uint)NMT_CHAT, NCS_INGAME, (void*)&OnChat, context);
AddTransition(NCS_INGAME, (uint)NMT_GAME_SETUP, NCS_INGAME, (void*)&OnGameSetup, context);
@ -778,6 +780,28 @@ bool CNetClient::OnClientPerformance(void *context, CFsmEvent* event)
return true;
}
bool CNetClient::OnClientsLoading(void *context, CFsmEvent *event)
{
ENSURE(event->GetType() == (uint)NMT_CLIENTS_LOADING);
CClientsLoadingMessage* message = (CClientsLoadingMessage*)event->GetParamRef();
std::vector<CStr> guids;
guids.reserve(message->m_Clients.size());
for (const CClientsLoadingMessage::S_m_Clients& client : message->m_Clients)
guids.push_back(client.m_GUID);
CNetClient* client = (CNetClient*)context;
JSContext* cx = client->GetScriptInterface().GetContext();
JSAutoRequest rq(cx);
JS::RootedValue msg(cx);
client->GetScriptInterface().Eval("({ 'type':'clients-loading' })", &msg);
client->GetScriptInterface().SetProperty(msg, "guids", guids);
client->PushGuiMessage(msg);
return true;
}
bool CNetClient::OnClientPaused(void *context, CFsmEvent *event)
{
ENSURE(event->GetType() == (uint)NMT_CLIENT_PAUSED);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -233,6 +233,7 @@ private:
static bool OnKicked(void* context, CFsmEvent* event);
static bool OnClientTimeout(void* context, CFsmEvent* event);
static bool OnClientPerformance(void* context, CFsmEvent* event);
static bool OnClientsLoading(void* context, CFsmEvent* event);
static bool OnClientPaused(void* context, CFsmEvent* event);
static bool OnLoadedGame(void* context, CFsmEvent* event);

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -147,6 +147,10 @@ CNetMessage* CNetMessageFactory::CreateMessage(const void* pData,
pNewMessage = new CClientPerformanceMessage;
break;
case NMT_CLIENTS_LOADING:
pNewMessage = new CClientsLoadingMessage;
break;
case NMT_CLIENT_PAUSED:
pNewMessage = new CClientPausedMessage;
break;

View File

@ -1,4 +1,4 @@
/* Copyright (C) 2016 Wildfire Games.
/* Copyright (C) 2017 Wildfire Games.
* This file is part of 0 A.D.
*
* 0 A.D. is free software: you can redistribute it and/or modify
@ -28,7 +28,7 @@
#define PS_PROTOCOL_MAGIC 0x5073013f // 'P', 's', 0x01, '?'
#define PS_PROTOCOL_MAGIC_RESPONSE 0x50630121 // 'P', 'c', 0x01, '!'
#define PS_PROTOCOL_VERSION 0x01010014 // Arbitrary protocol
#define PS_PROTOCOL_VERSION 0x01010015 // Arbitrary protocol
#define PS_DEFAULT_PORT 0x5073 // 'P', 's'
// Defines the list of message types. The order of the list must not change.
@ -67,6 +67,7 @@ enum NetMessageType
NMT_CLIENT_TIMEOUT,
NMT_CLIENT_PERFORMANCE,
NMT_CLIENTS_LOADING,
NMT_CLIENT_PAUSED,
NMT_LOADED_GAME,
@ -193,6 +194,12 @@ START_NMT_CLASS_(ClientPerformance, NMT_CLIENT_PERFORMANCE)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(ClientsLoading, NMT_CLIENTS_LOADING)
NMT_START_ARRAY(m_Clients)
NMT_FIELD(CStr, m_GUID)
NMT_END_ARRAY()
END_NMT_CLASS()
START_NMT_CLASS_(ClientPaused, NMT_CLIENT_PAUSED)
NMT_FIELD(CStr, m_GUID)
NMT_FIELD_INT(m_Pause, u8, 1)

View File

@ -1178,13 +1178,29 @@ bool CNetServerWorker::OnLoadedGame(void* context, CFsmEvent* event)
{
ENSURE(event->GetType() == (uint)NMT_LOADED_GAME);
CNetServerSession* session = (CNetServerSession*)context;
CNetServerWorker& server = session->GetServer();
CNetServerSession* loadedSession = (CNetServerSession*)context;
CNetServerWorker& server = loadedSession->GetServer();
// We're in the loading state, so wait until every player has loaded before
// starting the game
// We're in the loading state, so wait until every client has loaded
// before starting the game
ENSURE(server.m_State == SERVER_STATE_LOADING);
server.CheckGameLoadStatus(session);
if (server.CheckGameLoadStatus(loadedSession))
return true;
CClientsLoadingMessage message;
// We always send all GUIDs of clients in the loading state
// so that we don't have to bother about switching GUI pages
for (CNetServerSession* session : server.m_Sessions)
if (session->GetCurrState() != NSS_INGAME && loadedSession->GetGUID() != session->GetGUID())
{
CClientsLoadingMessage::S_m_Clients client;
client.m_GUID = session->GetGUID();
message.m_Clients.push_back(client);
}
// Send to the client who has loaded the game but did not reach the NSS_INGAME state yet
loadedSession->SendMessage(&message);
server.Broadcast(&message, { NSS_INGAME });
return true;
}
@ -1331,11 +1347,11 @@ bool CNetServerWorker::OnClientPaused(void* context, CFsmEvent* event)
return true;
}
void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession)
bool CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession)
{
for (const CNetServerSession* session : m_Sessions)
if (session != changedSession && session->GetCurrState() != NSS_INGAME)
return;
return false;
// Inform clients that everyone has loaded the map and that the game can start
CLoadedGameMessage loaded;
@ -1345,6 +1361,7 @@ void CNetServerWorker::CheckGameLoadStatus(CNetServerSession* changedSession)
Broadcast(&loaded, { NSS_PREGAME, NSS_INGAME });
m_State = SERVER_STATE_INGAME;
return true;
}
void CNetServerWorker::StartGame()

View File

@ -255,7 +255,13 @@ private:
static bool OnDisconnect(void* context, CFsmEvent* event);
static bool OnClientPaused(void* context, CFsmEvent* event);
void CheckGameLoadStatus(CNetServerSession* changedSession);
/**
* Checks if all clients have finished loading.
* If so informs the clients about that and change the server state.
*
* Returns if all clients finished loading.
*/
bool CheckGameLoadStatus(CNetServerSession* changedSession);
void ConstructPlayerAssignmentMessage(CPlayerAssignmentMessage& message);