-
Notifications
You must be signed in to change notification settings - Fork 167
feat(network): Send product information to distinguish clients #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
base: main
Are you sure you want to change the base?
Changes from all commits
296c768
7a7775e
f2651b9
765e5fa
8c71c3a
e834604
7a86f43
51636b6
fd39ae4
391bdf7
4302707
7feddc7
ae11852
1900b24
870bfd3
759efbc
d53d412
a8e1aa2
c4a34ce
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -173,6 +173,25 @@ struct LANMessage | |
| MSG_INACTIVE, ///< I've alt-tabbed out. Unaccept me cause I'm a poo-flinging monkey. | ||
|
|
||
| MSG_REQUEST_GAME_INFO, ///< For direct connect, get the game info from a specific IP Address | ||
|
|
||
| // TheSuperHackers @feature Caball009 05/02/2026 Product information is exchanged on demand and never broadcast. | ||
| // A client is considered 'patched' if it responds to a product info request (or, in pre-match, if it sends one). | ||
| // The implementation consists of three parts. | ||
| // 1. player - player in lobby: | ||
| // - When a player detects a new player in the lobby, it sends a product info request to that player. | ||
| // - If the other player responds with an acknowledgement, they are considered patched. | ||
| // 2. player - host in lobby: | ||
| // - When a player detects a new game host in the lobby, it sends a product info request to that host. | ||
| // - If the host responds with an acknowledgement, it is considered patched. | ||
| // 3. players in pre-match (game room): | ||
| // - When a player joins a match, it sends a product info request to all players in that match. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do the previous players also receive Product Info from the new joined player?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes. Does the comment suggest otherwise to you? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes it is not clear to me. It says:
This implies that existing player do not receive product info but just know that the requester is not a Retail guy. |
||
| // - Existing players treat this request as confirmation that the joining player is patched (no explicit acknowledgement required). | ||
| MSG_GAME_REQUEST_PRODUCT_INFO = 1000, | ||
| MSG_GAME_RESPONSE_PRODUCT_INFO, | ||
| MSG_LOBBY_REQUEST_PRODUCT_INFO, | ||
| MSG_LOBBY_RESPONSE_PRODUCT_INFO, | ||
| MSG_MATCH_REQUEST_PRODUCT_INFO, | ||
| MSG_MATCH_RESPONSE_PRODUCT_INFO, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned in the other file, perhaps a better terminology for these are: GAME to LOBBY_ROOM aka a Game Room in the Lobby |
||
| } messageType; | ||
|
|
||
| WideChar name[g_lanPlayerNameLength+1]; ///< My name, for convenience | ||
|
|
@@ -267,6 +286,16 @@ struct LANMessage | |
| char options[m_lanMaxOptionsLength+1]; | ||
| } GameOptions; | ||
|
|
||
| // ProductInfo is sent with REQUEST_PRODUCT_INFO and RESPONSE_PRODUCT_INFO | ||
xezon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| struct | ||
| { | ||
| UnsignedInt flags; | ||
| UnsignedInt upTime; | ||
| UnsignedInt exeCRC; | ||
| UnsignedInt iniCRC; | ||
| UnsignedInt fpMathCRC; | ||
| WideChar data[201]; | ||
xezon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } ProductInfo; | ||
xezon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| }; | ||
| }; | ||
| #pragma pack(pop) | ||
|
|
@@ -386,14 +415,22 @@ class LANAPI : public LANAPIInterface | |
|
|
||
| Bool m_isActive; ///< is the game currently active? | ||
|
|
||
| LANMessage m_productInfoMessage; ///< store product info message to avoid having to recreate it multiple times | ||
|
|
||
| protected: | ||
| void sendMessage(LANMessage *msg, UnsignedInt ip = 0); // Convenience function | ||
| void sendMessage(LANMessage *msg, UnsignedInt ip = 0, Bool broadcast = TRUE); // Convenience function | ||
| void removePlayer(LANPlayer *player); | ||
| void removeGame(LANGameInfo *game); | ||
| void addPlayer(LANPlayer *player); | ||
| void addGame(LANGameInfo *game); | ||
| AsciiString createSlotString(); | ||
|
|
||
| static UnsignedInt buildProductInfoFlags(); | ||
| static void setProductInfoFromLocalData(GameSlot &slot); | ||
| static void setProductInfoFromMessage(GameSlot &slot, LANMessage *msg); | ||
| static Bool setProductInfoStrings(const UnicodeString(&input)[4], WideChar(&output)[201]); | ||
| static Bool getProductInfoStrings(WideChar(&input)[201], UnicodeString*(&output)[4]); | ||
|
|
||
| // Functions to handle incoming messages ----------------------------------- | ||
| void handleRequestLocations( LANMessage *msg, UnsignedInt senderIP ); | ||
| void handleGameAnnounce( LANMessage *msg, UnsignedInt senderIP ); | ||
|
|
@@ -412,4 +449,12 @@ class LANAPI : public LANAPIInterface | |
| void handleGameOptions( LANMessage *msg, UnsignedInt senderIP ); | ||
| void handleInActive( LANMessage *msg, UnsignedInt senderIP ); | ||
|
|
||
| static LANMessage buildProductInfoMessage(); | ||
| void sendProductInfoMessage(LANMessage::Type messageType, UnsignedInt senderIP); | ||
| void handleGameProductInfoRequest(LANMessage *msg, UnsignedInt senderIP); | ||
| void handleGameProductInfoResponse(LANMessage *msg, UnsignedInt senderIP); | ||
| void handleLobbyProductInfoRequest(LANMessage *msg, UnsignedInt senderIP); | ||
| void handleLobbyProductInfoResponse(LANMessage *msg, UnsignedInt senderIP); | ||
| void handleMatchProductInfoRequest(LANMessage *msg, UnsignedInt senderIP); | ||
| void handleMatchProductInfoResponse(LANMessage *msg, UnsignedInt senderIP); | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -87,6 +87,7 @@ LANAPI::LANAPI() : m_transport(nullptr) | |
| m_lastUpdate = 0; | ||
| m_transport = new Transport; | ||
| m_isActive = TRUE; | ||
| m_productInfoMessage = buildProductInfoMessage(); | ||
| } | ||
|
|
||
| LANAPI::~LANAPI() | ||
|
|
@@ -179,13 +180,13 @@ void LANAPI::reset() | |
|
|
||
| } | ||
|
|
||
| void LANAPI::sendMessage(LANMessage *msg, UnsignedInt ip /* = 0 */) | ||
| void LANAPI::sendMessage(LANMessage *msg, UnsignedInt ip /* = 0 */, Bool broadcast /*= TRUE*/) | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The term Perhaps split this function into multiple to make its usage more explicit. For example have a
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is getting outside the scope of this PR imo. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be simple enough. Can write like so: void LANAPI::sendMessage(LANMessage *msg, UnsignedInt ip /* = 0 */)
{
if (ip != 0)
{
m_transport->queueSend(ip, lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */);
}
else if ((m_currentGame != nullptr) && (m_currentGame->getIsDirectConnect()))
{
sendMessageToGameRoomPlayers(msg);
}
else
{
m_transport->queueSend(m_broadcastAddr, lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */);
}
}
void LANAPI::sendMessageToGameRoomPlayers(LANMessage *msg)
{
if (!m_currentGame)
return;
Int localSlot = m_currentGame->getLocalSlotNum();
for (Int i = 0; i < MAX_SLOTS; ++i)
{
if (i != localSlot) {
GameSlot *slot = m_currentGame->getSlot(i);
if ((slot != nullptr) && (slot->isHuman())) {
m_transport->queueSend(slot->getIP(), lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */);
}
}
}
}This way you can simply call |
||
| { | ||
| if (ip != 0) | ||
| { | ||
| m_transport->queueSend(ip, lobbyPort, (unsigned char *)msg, sizeof(LANMessage) /*, 0, 0 */); | ||
| } | ||
| else if ((m_currentGame != nullptr) && (m_currentGame->getIsDirectConnect())) | ||
| else if (m_currentGame != nullptr && (m_currentGame->getIsDirectConnect() || !broadcast)) | ||
xezon marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| { | ||
| Int localSlot = m_currentGame->getLocalSlotNum(); | ||
| for (Int i = 0; i < MAX_SLOTS; ++i) | ||
|
|
@@ -425,6 +426,26 @@ void LANAPI::update() | |
| handleInActive( msg, senderIP ); | ||
| break; | ||
|
|
||
| // exchange product information with other players | ||
| case LANMessage::MSG_GAME_REQUEST_PRODUCT_INFO: | ||
| handleGameProductInfoRequest(msg, senderIP); | ||
| break; | ||
| case LANMessage::MSG_GAME_RESPONSE_PRODUCT_INFO: | ||
| handleGameProductInfoResponse(msg, senderIP); | ||
| break; | ||
| case LANMessage::MSG_LOBBY_REQUEST_PRODUCT_INFO: | ||
| handleLobbyProductInfoRequest(msg, senderIP); | ||
| break; | ||
| case LANMessage::MSG_LOBBY_RESPONSE_PRODUCT_INFO: | ||
| handleLobbyProductInfoResponse(msg, senderIP); | ||
| break; | ||
| case LANMessage::MSG_MATCH_REQUEST_PRODUCT_INFO: | ||
| handleMatchProductInfoRequest(msg, senderIP); | ||
| break; | ||
| case LANMessage::MSG_MATCH_RESPONSE_PRODUCT_INFO: | ||
| handleMatchProductInfoResponse(msg, senderIP); | ||
| break; | ||
|
|
||
| default: | ||
| DEBUG_LOG(("Unknown LAN message type %d", msg->messageType)); | ||
| } | ||
|
|
@@ -906,6 +927,9 @@ void LANAPI::RequestGameCreate( UnicodeString gameName, Bool isDirectConnect ) | |
| newSlot.setLogin(m_userName); | ||
| newSlot.setHost(m_hostName); | ||
|
|
||
| // set product information for local game slot | ||
| setProductInfoFromLocalData(newSlot); | ||
|
|
||
| myGame->setSlot(0,newSlot); | ||
| myGame->setNext(nullptr); | ||
| LANPreferences pref; | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.