Skip to content

feat(gui): Distinguish patch players from retail players by a colored name and different status #1404

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

Caball009
Copy link

@Caball009 Caball009 commented Aug 1, 2025

With this PR it'll become clear which clients are on a patched version with this feature and which are not:

  • the patched clients inform all other clients in the lobby and pre-match of their patch version.
  • the retail clients ignore the patch version data.
  • the patched clients show the player names of patched clients in a different color.
  • the patched clients show the player status of patched clients with a [SH] tag.

LAN Lobby:
image

Pre-match / Game Options:
image

Status in match:
image

TODO:

  • Add code comments.
  • Replicate in Generals.

@Caball009 Caball009 added Enhancement Is new feature or request GUI For graphical user interface Network Anything related to network, servers Gen Relates to Generals ZH Relates to Zero Hour labels Aug 1, 2025
@@ -461,6 +465,14 @@ void LANAPI::update( void )
}
}

if (m_inLobby || (m_currentGame && !m_currentGame->isGameInProgress())) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is broadcast every 200 ms to all other clients. It works perfectly, but it's a bit 'spammy'. Should try to find a more elegant solution for this.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should only be broadcasted when a new player joins the lobby. It is a fixed value that doesn't change.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eliminating the broadcast spam would good.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, the game periodically broadcasts other data that may or may not have changed. This happens with 10 second intervals, which I found to be a bit too slow for this feature.

It should only be broadcasted when a new player joins the lobby.

It's a bit more complicated than that, though. I also need data about the hosts of each game and about other players in the same match.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be redesigned with new message versions.

On RETAIL_COMPATIBLE_NETWORK versions, send the original messages

MSG_GAME_ANNOUNCE
MSG_LOBBY_ANNOUNCE
MSG_REQUEST_JOIN

and on top send new messages, give them a generous offset to avoid colliding with other community products.

MSG_COMMUNITY_GAME_ANNOUNCE = 1000
MSG_COMMUNITY_LOBBY_ANNOUNCE
MSG_COMMUNITY_REQUEST_JOIN

Then try to design the packets so that they cover all sorts of use cases we will have.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I assume MSG_COMMUNITY_GAME_ANNOUNCE equals MSG_GAME_ANNOUNCE + some patch information. Wouldn't it be better to do this when we break compatibility? Otherwise we'll be sending this data in duplicate. Also, redesigning these packets is absolutely outside the scope of this PR as far as I'm concerned.

I do agree that if we keep MSG_PATCH_VERSION or similar, it should be given a decent offset.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well ideally we build this feature here without the packet spam every 200 ms. Instead send 2 packets on the announcements, which is better than the spamming. The 2 packets will also only be sent on RETAIL_COMPATIBLE_NETWORK clients, so it is temporary. I did not think this fully through but my instict tells me this is the way to go?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if we understand well enough what our messages will look like after we break retail compatibility, so I propose we delay redesigning them until we have a better idea what that should look like.

I think it's possible to avoid spamming MSG_PATCH_VERSION by sending it whenever certain other messages are sent as well. This doesn't require newly designed messages.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes you can also send the product version message side by side with other messages. Try to anticipate future requirements for communications so that we do not need to touch it often.

@Caball009 Caball009 marked this pull request as ready for review August 10, 2025 19:34
@Caball009 Caball009 requested a review from a team August 11, 2025 15:24
@@ -423,6 +423,12 @@ void UpdateSlotList( GameInfo *myGame, GameWindow *comboPlayer[],
}
if(slot->isHuman())
{
if (i == myGame->getLocalSlotNum() || myGame->getSlot(i)->getPatchVersion() > 0)
{
GadgetComboBoxSetEnabledTextColors(comboPlayer[i], 0xFFFFFF00, 0xFF000000);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These colours should be put into variables, preferably configurable through INI.

@@ -642,7 +642,8 @@ void LANAPI::OnPlayerList( LANPlayer *playerList )
LANPlayer *player = m_lobbyPlayers;
while (player)
{
Int addedIndex = GadgetListBoxAddEntryText(listboxPlayers, player->getName(), playerColor, -1, -1);
const Color color = (player->getPatchVersion() > 0 || m_localIP == player->getIP()) ? 0xFFFFFF00 : playerColor;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic colour, create INI configurable variable

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put it by the others

const Color playerColor =  GameMakeColor(255,255,255,255);

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic colour, create INI configurable variable

The current white and grey colors are not configurable either, and I don't see that as an issue.

Put it by the others

Will do.

@@ -226,7 +226,10 @@ void LANDisplayGameList( GameWindow *gameListbox, LANGameInfo *gameList )
{
txtGName.concat(L"]");
}
Int addedIndex = GadgetListBoxAddEntryText(gameListbox, txtGName, (gameList->isGameInProgress())?gameInProgressColor:gameColor, -1, -1);
const Color color = (gameList->getSlot(0)->getPatchVersion() > 0)
? ((gameList->isGameInProgress()) ? 0xFF808000 : 0xFFFFFF00)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

magic colours

Copy link

@xezon xezon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good effort.

This work relates to #16

I think the packets need redesigning.

@@ -461,6 +465,14 @@ void LANAPI::update( void )
}
}

if (m_inLobby || (m_currentGame && !m_currentGame->isGameInProgress())) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eliminating the broadcast spam would good.

@@ -642,7 +642,8 @@ void LANAPI::OnPlayerList( LANPlayer *playerList )
LANPlayer *player = m_lobbyPlayers;
while (player)
{
Int addedIndex = GadgetListBoxAddEntryText(listboxPlayers, player->getName(), playerColor, -1, -1);
const Color color = (player->getPatchVersion() > 0 || m_localIP == player->getIP()) ? 0xFFFFFF00 : playerColor;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put it by the others

const Color playerColor =  GameMakeColor(255,255,255,255);

}
else if (m_currentGame && !m_currentGame->isGameInProgress())
{
for (int player = 0; player < MAX_SLOTS; ++player)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can split this into 2 functions:

handlePatchVersionInLobby(LANMessage* msg, UnsignedInt senderIP)
handlePatchVersionInGameRoom(LANMessage* msg, UnsignedInt senderIP)

@@ -146,6 +149,7 @@ class GameSlot
FirewallHelperClass::FirewallBehaviorType m_NATBehavior; ///< The NAT behavior for this slot's player.
UnsignedInt m_lastFrameInGame; // only valid for human players
Bool m_disconnected; // only valid for human players
UnsignedInt m_patchVersion; // TheSuperHackers patch version
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can label this as "Community made product version"

LANMessage msg;
fillInLANMessage(&msg);
msg.LANMessageType = LANMessage::MSG_PATCH_VERSION;
msg.PatchInfo.patchVersion = TheVersion->getVersionNumber();
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will only contain major 1 minor 4 for Zero Hour. This means the version will not change between builds.

I think this data can be extended with more version information.

The least we need is a product name and its version.

For reference, see

Version::getUnicodeProductTitle
Version::getUnicodeProductVersion
Version::getUnicodeProductAuthor

}
}

if (slot->isHuman() && (TheGameInfo->getLocalSlotNum() == slotNum || slot->getPatchVersion() > 0))
text.concat(L"[SH]");
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This string ideally is build from the product title and not hardcoded like this.

@@ -282,6 +282,7 @@ class LANAPI : public LANAPIInterface
void handleGameStartTimer( LANMessage *msg, UnsignedInt senderIP );
void handleGameOptions( LANMessage *msg, UnsignedInt senderIP );
void handleInActive( LANMessage *msg, UnsignedInt senderIP );
void handlePatchVersion( LANMessage *msg, UnsignedInt senderIP );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest use terminology

"ProductTitle"
"ProductVersion"
"ProductAuthor"

@@ -461,6 +465,14 @@ void LANAPI::update( void )
}
}

if (m_inLobby || (m_currentGame && !m_currentGame->isGameInProgress())) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this needs to be redesigned with new message versions.

On RETAIL_COMPATIBLE_NETWORK versions, send the original messages

MSG_GAME_ANNOUNCE
MSG_LOBBY_ANNOUNCE
MSG_REQUEST_JOIN

and on top send new messages, give them a generous offset to avoid colliding with other community products.

MSG_COMMUNITY_GAME_ANNOUNCE = 1000
MSG_COMMUNITY_LOBBY_ANNOUNCE
MSG_COMMUNITY_REQUEST_JOIN

Then try to design the packets so that they cover all sorts of use cases we will have.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Enhancement Is new feature or request Gen Relates to Generals GUI For graphical user interface Network Anything related to network, servers ZH Relates to Zero Hour
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants