Skip to content

Commit

Permalink
New pre-game ("waiting for players") screen
Browse files Browse the repository at this point in the history
  • Loading branch information
past-due committed Oct 11, 2023
1 parent a83a283 commit 46b51e1
Show file tree
Hide file tree
Showing 14 changed files with 901 additions and 125 deletions.
2 changes: 2 additions & 0 deletions lib/netplay/netplay.cpp
Expand Up @@ -604,6 +604,7 @@ static void initPlayerNetworkProps(int playerIndex)
ASSERT(false, "PLAYERS.wzFiles is uninitialized??");
}
ingame.JoiningInProgress[playerIndex] = false;
ingame.PendingDisconnect[playerIndex] = false;
}

void NET_InitPlayer(uint32_t i, bool initPosition, bool initTeams, bool initSpectator)
Expand Down Expand Up @@ -1930,6 +1931,7 @@ static bool swapPlayerIndexes(uint32_t playerIndexA, uint32_t playerIndexB)
std::swap(ingame.LagCounter[playerIndexA], ingame.LagCounter[playerIndexB]);
std::swap(ingame.VerifiedIdentity[playerIndexA], ingame.VerifiedIdentity[playerIndexB]);
std::swap(ingame.JoiningInProgress[playerIndexA], ingame.JoiningInProgress[playerIndexB]);
std::swap(ingame.PendingDisconnect[playerIndexA], ingame.PendingDisconnect[playerIndexB]);
std::swap(ingame.DataIntegrity[playerIndexA], ingame.DataIntegrity[playerIndexB]);
std::swap(ingame.lastSentPlayerDataCheck2[playerIndexA], ingame.lastSentPlayerDataCheck2[playerIndexB]);
std::swap(ingame.muteChat[playerIndexA], ingame.muteChat[playerIndexB]);
Expand Down
2 changes: 1 addition & 1 deletion src/console.cpp
Expand Up @@ -338,7 +338,7 @@ void flushConsoleMessages()
}

/** Sets console text color depending on message type */
static PIELIGHT getConsoleTextColor(int player)
PIELIGHT getConsoleTextColor(int player)
{
// System messages
if (player == SYSTEM_MESSAGE)
Expand Down
2 changes: 2 additions & 0 deletions src/console.h
Expand Up @@ -23,6 +23,7 @@

#include <functional>
#include <memory>
#include "lib/ivis_opengl/pietypes.h"

#define MAX_CONSOLE_MESSAGES (64)
#define MAX_CONSOLE_STRING_LENGTH (255)
Expand Down Expand Up @@ -91,6 +92,7 @@ void permitNewConsoleMessages(bool allow);
void toggleConsoleDrop();
void setHistoryMode(bool mode);
void clearInfoMessages();
PIELIGHT getConsoleTextColor(int player);

typedef std::function<void(ConsoleMessage const &)> CONSOLE_MESSAGE_LISTENER;
void consoleAddMessageListener(const std::shared_ptr<CONSOLE_MESSAGE_LISTENER>& listener);
Expand Down
3 changes: 3 additions & 0 deletions src/ingameop.cpp
Expand Up @@ -50,6 +50,7 @@
#include "radar.h"
#include "seqdisp.h"
#include "hci/groups.h"
#include "screens/netpregamescreen.h"

bool hostQuitConfirmation = true;

Expand Down Expand Up @@ -420,6 +421,8 @@ void intAddInGamePopup()

intMode = INT_POPUPMSG; // change interface mode.
isInGamePopupUp = true;

shutdownGameStartScreen();
}

// ////////////////////////////////////////////////////////////////////////////
Expand Down
4 changes: 4 additions & 0 deletions src/init.cpp
Expand Up @@ -1904,6 +1904,10 @@ bool stageThreeInitialise()
if (bMultiPlayer)
{
playerResponding(); // say howdy!
if (NetPlay.bComms)
{
multiStartScreenInit();
}
}

return true;
Expand Down
6 changes: 0 additions & 6 deletions src/loop.cpp
Expand Up @@ -329,12 +329,6 @@ static GAMECODE renderLoop()
/* Display the in game interface */
pie_SetFogStatus(false);

if (bMultiPlayer && bDisplayMultiJoiningStatus)
{
intDisplayMultiJoiningStatus(bDisplayMultiJoiningStatus);
setWidgetsStatus(false);
}

if (getWidgetsStatus())
{
intDisplayWidgets();
Expand Down
105 changes: 13 additions & 92 deletions src/multijoin.cpp
Expand Up @@ -77,98 +77,6 @@
// Local Functions

static void resetMultiVisibility(UDWORD player);

// ////////////////////////////////////////////////////////////////////////////
// Local Variables

struct DisplayMultiJoiningStatusCache {
WzText wzMainProgressText;
WzText wzPlayerCountText;
std::vector<WzText> wzPlayerNameAndStatus;
};

DisplayMultiJoiningStatusCache textCache;

// ////////////////////////////////////////////////////////////////////////////
// Clear Local Display Caches

void clearDisplayMultiJoiningStatusCache()
{
textCache = DisplayMultiJoiningStatusCache();
}

// ////////////////////////////////////////////////////////////////////////////
// Wait For Players

bool intDisplayMultiJoiningStatus(UBYTE joinCount)
{
UDWORD x, y, w, h;
char sTmp[6];

w = RET_FORMWIDTH;
h = RET_FORMHEIGHT;
x = RET_X;
y = RET_Y;

RenderWindowFrame(FRAME_NORMAL, x, y , w, h); // draw a wee blue box.

// display how far done..
textCache.wzMainProgressText.setText(_("Players Still Joining"), font_regular);
textCache.wzMainProgressText.render(x + (w / 2) - (textCache.wzMainProgressText.width() / 2),
y + (h / 2) - 8, WZCOL_TEXT_BRIGHT);

unsigned playerCount = 0; // Calculate what NetPlay.playercount should be, which is apparently only non-zero for the host.
unsigned numUsedPlayerSlots = 0;
for (unsigned player = 0; player < MAX_CONNECTED_PLAYERS; ++player)
{
if (isHumanPlayer(player))
{
++playerCount;
++numUsedPlayerSlots;
}
else if (NetPlay.players[player].ai >= 0)
{
++numUsedPlayerSlots;
}
}
if (!playerCount)
{
return true;
}
sprintf(sTmp, "%d%%", PERCENT(playerCount - joinCount, playerCount));
textCache.wzPlayerCountText.setText(sTmp, font_large);
textCache.wzPlayerCountText.render(x + (w / 2) - 10, y + (h / 2) + 10, WZCOL_TEXT_BRIGHT);

int yStep = iV_GetTextLineSize(font_small);
int yPos = RET_Y - yStep * numUsedPlayerSlots;

static const std::string statusStrings[3] = {"", "", ""};

for (unsigned player = 0; player < MAX_CONNECTED_PLAYERS; ++player)
{
int status = -1;
if (isHumanPlayer(player))
{
status = ingame.JoiningInProgress[player] ? 0 : 1; // Human player, still joining or joined.
}
else if (NetPlay.players[player].ai >= 0)
{
status = 2; // AI player (automatically joined).
}
if (status >= 0)
{
if (player >= textCache.wzPlayerNameAndStatus.size())
{
textCache.wzPlayerNameAndStatus.resize(player + 1);
}
textCache.wzPlayerNameAndStatus[player].setText((statusStrings[status] + getPlayerName(player)).c_str(), font_small);
textCache.wzPlayerNameAndStatus[player].render(x + 5, yPos + yStep * NetPlay.players[player].position, WZCOL_TEXT_BRIGHT);
}
}

return true;
}

void destroyPlayerResources(UDWORD player, bool quietly);

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -397,6 +305,7 @@ void handlePlayerLeftInGame(UDWORD player)

ingame.LagCounter[player] = 0;
ingame.JoiningInProgress[player] = false; // if they never joined, reset the flag
ingame.PendingDisconnect[player] = false;
ingame.DataIntegrity[player] = false;
ingame.lastSentPlayerDataCheck2[player].reset();

Expand Down Expand Up @@ -552,6 +461,17 @@ bool MultiPlayerLeave(UDWORD playerIndex)
else if (NetPlay.isHost) // If hosting, and game has started (not in pre-game lobby screen, that is).
{
sendPlayerLeft(playerIndex);

if (bDisplayMultiJoiningStatus) // if still waiting for players to load *or* waiting for game to start...
{
NETbeginEncode(NETbroadcastQueue(), NET_PLAYER_DROPPED);
NETuint32_t(&playerIndex);
NETend();
// only set ingame.JoiningInProgress[player_id] to false
// when the game starts, it will handle the GAME_PLAYER_LEFT message in their queue properly
ingame.JoiningInProgress[playerIndex] = false;
ingame.PendingDisconnect[playerIndex] = true; // used as a UI indicator that a disconnect will be processed in the future
}
}

if (NetPlay.players[playerIndex].wzFiles && NetPlay.players[playerIndex].fileSendInProgress())
Expand Down Expand Up @@ -720,6 +640,7 @@ void setupNewPlayer(UDWORD player)
ingame.LagCounter[player] = 0;
ingame.VerifiedIdentity[player] = false;
ingame.JoiningInProgress[player] = true; // Note that player is now joining
ingame.PendingDisconnect[player] = false;
ingame.DataIntegrity[player] = false;
ingame.lastSentPlayerDataCheck2[player].reset();
ingame.muteChat[player] = false;
Expand Down
2 changes: 0 additions & 2 deletions src/multijoin.h
Expand Up @@ -26,8 +26,6 @@

#include "droiddef.h"

void clearDisplayMultiJoiningStatusCache(); // Call when bDisplayMultiJoiningStatus is set to 0
bool intDisplayMultiJoiningStatus(UBYTE joinCount);
void recvPlayerLeft(NETQUEUE queue);
bool MultiPlayerLeave(UDWORD playerIndex); // A player has left the game.
bool MultiPlayerJoin(UDWORD playerIndex); // A Player has joined the game.
Expand Down
22 changes: 21 additions & 1 deletion src/multiopt.cpp
Expand Up @@ -65,6 +65,7 @@
#include "template.h"
#include "activity.h"
#include "warzoneconfig.h"
#include "screens/netpregamescreen.h"

#define MAX_STRUCTURE_LIMITS 4096 // Set a high (but explicit) maximum for the number of structure limits supported

Expand Down Expand Up @@ -518,6 +519,7 @@ bool hostCampaign(const char *SessionName, char *hostPlayerName, bool spectatorH

ingame.localJoiningInProgress = true;
ingame.JoiningInProgress[selectedPlayer] = true;
ingame.PendingDisconnect[selectedPlayer] = false;
bMultiPlayer = true;
bMultiMessages = true; // enable messages

Expand Down Expand Up @@ -561,7 +563,7 @@ bool multiShutdown()
debug(LOG_MAIN, "free game data (structure limits)");
ingame.structureLimits.clear();

clearDisplayMultiJoiningStatusCache();
shutdownGameStartScreen();

return true;
}
Expand Down Expand Up @@ -662,12 +664,30 @@ bool multiGameInit()
return true;
}

bool multiStartScreenInit()
{
bDisplayMultiJoiningStatus = 1; // always display this
gameTimeStop();
intHideInterface(true);
createGameStartScreen([] {
// on game start overlay screen close...
bDisplayMultiJoiningStatus = 0;
intShowInterface();
// restart gameTime
gameTimeStart();
});

return true;
}

////////////////////////////////
// at the end of every game.
bool multiGameShutdown()
{
debug(LOG_NET, "%s is shutting down.", getPlayerName(selectedPlayer));

shutdownGameStartScreen(); // make sure the start screen overlay is closed (in case the game shuts down before it fully starts)

sendLeavingMsg(); // say goodbye

if (selectedPlayer < MAX_CONNECTED_PLAYERS)
Expand Down
28 changes: 6 additions & 22 deletions src/multiplay.cpp
Expand Up @@ -311,28 +311,11 @@ bool multiPlayerLoop()
}
if (joinCount)
{
setWidgetsStatus(false);
bDisplayMultiJoiningStatus = joinCount; // someone is still joining! say So

// deselect anything selected.
selDroidDeselect(selectedPlayer);

if (keyPressed(KEY_ESC))// check for cancel
{
bDisplayMultiJoiningStatus = 0;
clearDisplayMultiJoiningStatusCache();
setWidgetsStatus(true);
setPlayerHasLost(true);
}
}
else //everyone is in the game now!
{
if (bDisplayMultiJoiningStatus)
{
bDisplayMultiJoiningStatus = 0;
clearDisplayMultiJoiningStatusCache();
setWidgetsStatus(true);
}
if (!ingame.TimeEveryoneIsInGame.has_value())
{
ingame.TimeEveryoneIsInGame = gameTime;
Expand Down Expand Up @@ -1272,19 +1255,20 @@ bool recvMessage()
break;
}

if (whosResponsible(player_id) != queue.index && queue.index != NetPlay.hostPlayer)
if (queue.index != NetPlay.hostPlayer) // only host should be sending this message
{
HandleBadParam("NET_PLAYER_DROPPED given incorrect params.", player_id, queue.index);
break;
}

debug(LOG_INFO, "** player %u has dropped!", player_id);

if (NetPlay.players[player_id].allocated)
if (NetPlay.players[player_id].allocated && ingame.JoiningInProgress[player_id])
{
MultiPlayerLeave(player_id); // get rid of their stuff
NET_InitPlayer(player_id, false);
ActivityManager::instance().updateMultiplayGameData(game, ingame, NETGameIsLocked());
// only set ingame.JoiningInProgress[player_id] to false
// when the game starts, it will handle the GAME_PLAYER_LEFT message in their queue properly
ingame.JoiningInProgress[player_id] = false;
ingame.PendingDisconnect[player_id] = true; // used as a UI indicator that a disconnect will be processed in the future
}
NETsetPlayerConnectionStatus(CONNECTIONSTATUS_PLAYER_DROPPED, player_id);
break;
Expand Down
2 changes: 2 additions & 0 deletions src/multiplay.h
Expand Up @@ -109,6 +109,7 @@ struct MULTIPLAYERINGAME
bool localOptionsReceived; // used to show if we have game options yet..
bool localJoiningInProgress; // used before we know our player number.
bool JoiningInProgress[MAX_CONNECTED_PLAYERS];
bool PendingDisconnect[MAX_CONNECTED_PLAYERS]; // used to mark players who have disconnected after the game has "fired up" but before it actually starts (i.e. pre-game / loading phase) - UI only
bool DataIntegrity[MAX_CONNECTED_PLAYERS];
InGameSide side;
optional<int32_t> TimeEveryoneIsInGame;
Expand Down Expand Up @@ -298,6 +299,7 @@ JoinGameResult joinGame(const std::vector<JoinConnectionDescription>& connection
void playerResponding();
bool multiGameInit();
bool multiGameShutdown();
bool multiStartScreenInit();

// syncing.
bool sendScoreCheck(); //score check only(frontend)
Expand Down

0 comments on commit 46b51e1

Please sign in to comment.