diff --git a/sc2/doc/devel/netplay/todo b/sc2/doc/devel/netplay/todo index e452e1390..2600ba8f8 100644 --- a/sc2/doc/devel/netplay/todo +++ b/sc2/doc/devel/netplay/todo @@ -90,11 +90,14 @@ Bugs: to keep sync on games with a different resolution. - Both sides need identical battle frame rates. This value is not negotiated. -- When melee selection is aborted, the remote player will be stuck. - If there are packets in the packet queue when a connection is closed, the callback that clears the queue isn't called in time. -- When the player returns from the SuperMelee menu to the main menu, - all open connections should be closed. +- If one player closes the connection while the other player is selecting + a ship to put in his fleet, or loading a fleet, the "Network Control" + button won't be updated. +- Per state data (in NetConnection.stateData) is unnecessarilly complicated. + Putting all fields directly in NetConnection simplifies things a lot. + It's not as generic, but this code won't be used elsewhere anyhow. Final actions: diff --git a/sc2/src/sc2code/battle.c b/sc2/src/sc2code/battle.c index 40b8be7a7..ce67c0b31 100644 --- a/sc2/src/sc2code/battle.c +++ b/sc2/src/sc2code/battle.c @@ -240,13 +240,6 @@ FreeBattleSong (void) BattleRef = 0; } -typedef struct battlestate_struct { - BOOLEAN (*InputFunc) (struct battlestate_struct *pInputState); - COUNT MenuRepeatDelay; - BOOLEAN first_time; - DWORD NextTime; -} BATTLE_STATE; - static BOOLEAN DoBattle (BATTLE_STATE *bs) { @@ -459,6 +452,7 @@ Battle (void) #endif /* NETPLAY_CHECKSUM */ battleFrameCount = 0; currentDeadSide = (COUNT)~0; + setBattleStateConnections (&bs); #endif /* NETPLAY */ if (!selectAllShips (num_ships)) { @@ -492,12 +486,14 @@ AbortBattle: { // Do not return to the main menu when a game is aborted, // (just to the supermelee menu). +#ifdef NETPLAY UnlockMutex (GraphicsLock); waitResetConnections(NetState_inSetup); // A connection may already be in inSetup (set from // GetMeleeStarship). This is not a problem, although // it will generate a warning in debug mode. LockMutex (GraphicsLock); +#endif GLOBAL (CurrentActivity) &= ~CHECK_ABORT; } @@ -507,6 +503,7 @@ AbortBattle: #ifdef NETPLAY_CHECKSUM uninitChecksumBuffers (); #endif /* NETPLAY_CHECKSUM */ + setBattleStateConnections (NULL); #endif /* NETPLAY */ StopMusic (); diff --git a/sc2/src/sc2code/battle.h b/sc2/src/sc2code/battle.h index 236b273ed..39f33a4fd 100644 --- a/sc2/src/sc2code/battle.h +++ b/sc2/src/sc2code/battle.h @@ -19,6 +19,13 @@ #include "libs/compiler.h" #include "displist.h" +typedef struct battlestate_struct { + BOOLEAN (*InputFunc) (struct battlestate_struct *pInputState); + COUNT MenuRepeatDelay; + BOOLEAN first_time; + DWORD NextTime; +} BATTLE_STATE; + extern QUEUE disp_q; extern SIZE battle_counter; extern BOOLEAN instantVictory; diff --git a/sc2/src/sc2code/melee.c b/sc2/src/sc2code/melee.c index 64d86147e..4e7dc4d9b 100644 --- a/sc2/src/sc2code/melee.c +++ b/sc2/src/sc2code/melee.c @@ -3203,19 +3203,33 @@ confirmationCancelled(PMELEE_STATE pMS, COUNT side) pMS->InputFunc = DoMelee; } +static void +connectionFeedback (NetConnection *conn, const char *str) { + struct battlestate_struct *bs = NetMelee_getBattleState (conn); + + if (bs == NULL) + { + // bs == NULL means the game has started. + LockMutex (GraphicsLock); + DrawMeleeStatusMessage (str); + UnlockMutex (GraphicsLock); + } + else + { + DoPopupWindow (str); + } +} + void -connectedFeedback (PMELEE_STATE pMS, COUNT side) { - LockMutex (GraphicsLock); - if (side == 0) - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 8)); +connectedFeedback (NetConnection *conn) { + if (NetConnection_getPlayerNr(conn) == 0) + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 8)); // "Bottom player is connected." else - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 9)); + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 9)); // "Top player is connected." - UnlockMutex (GraphicsLock); PlayMenuSound (MENU_SOUND_INVOKED); - (void) pMS; } const char * @@ -3240,19 +3254,13 @@ abortReasonString (NetplayResetReason reason) } void -abortFeedback (COUNT side, NetplayAbortReason reason) +abortFeedback (NetConnection *conn, NetplayAbortReason reason) { const char *msg; msg = abortReasonString (reason); if (msg != NULL) - { - LockMutex (GraphicsLock); - DrawMeleeStatusMessage (msg); - UnlockMutex (GraphicsLock); - } - - (void) side; + connectionFeedback (conn, msg); } const char * @@ -3276,11 +3284,18 @@ resetReasonString (NetplayResetReason reason) } void -resetFeedback (COUNT side, NetplayResetReason reason, bool byRemote) +resetFeedback (NetConnection *conn, NetplayResetReason reason, + bool byRemote) { const char *msg; GLOBAL (CurrentActivity) |= CHECK_ABORT; + flushPacketQueues (); + // If the local side queued a reset packet as a result of a + // remote reset, that packet will not have been sent yet. + // We flush the queue now, so that the remote side won't be + // waiting for the reset packet while this side is waiting + // for an acknowledgement of the feedback message. if (reason == ResetReason_manualReset && !byRemote) { // No message needed, the player initiated the reset. @@ -3289,41 +3304,29 @@ resetFeedback (COUNT side, NetplayResetReason reason, bool byRemote) msg = resetReasonString (reason); if (msg != NULL) - { - LockMutex (GraphicsLock); - DrawMeleeStatusMessage (msg); - UnlockMutex (GraphicsLock); - } - - (void) side; + connectionFeedback (conn, msg); } void -errorFeedback (PMELEE_STATE pMS, COUNT side) +errorFeedback (NetConnection *conn) { - LockMutex (GraphicsLock); - if (side == 0) - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 10)); + if (NetConnection_getPlayerNr(conn) == 0) + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 10)); // "Bottom player: connection failed." else - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 11)); + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 11)); // "Top player: connection failed." - UnlockMutex (GraphicsLock); - (void) pMS; } void -closeFeedback (PMELEE_STATE pMS, COUNT side) +closeFeedback (NetConnection *conn) { - LockMutex (GraphicsLock); - if (side == 0) - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 12)); + if (NetConnection_getPlayerNr(conn) == 0) + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 12)); // "Bottom player: connection closed." else - DrawMeleeStatusMessage (GAME_STRING (NETMELEE_STRING_BASE + 13)); + connectionFeedback (conn, GAME_STRING (NETMELEE_STRING_BASE + 13)); // "Top player: connection closed." - UnlockMutex (GraphicsLock); - (void) pMS; } #endif /* NETPLAY */ diff --git a/sc2/src/sc2code/melee.h b/sc2/src/sc2code/melee.h index fb4c04062..58c38e613 100644 --- a/sc2/src/sc2code/melee.h +++ b/sc2/src/sc2code/melee.h @@ -124,11 +124,12 @@ void updateTeamName (PMELEE_STATE pMS, COUNT side, const char *name, bool updateFleetShip (PMELEE_STATE pMS, COUNT side, COUNT index, BYTE ship); void updateRandomSeed (PMELEE_STATE pMS, COUNT side, DWORD seed); void confirmationCancelled(PMELEE_STATE pMS, COUNT side); -void connectedFeedback (PMELEE_STATE pMS, COUNT side); -void abortFeedback (COUNT side, NetplayAbortReason reason); -void resetFeedback (COUNT side, NetplayResetReason reason, bool byRemote); -void errorFeedback (PMELEE_STATE pMS, COUNT side); -void closeFeedback (PMELEE_STATE pMS, COUNT side); +void connectedFeedback (NetConnection *conn); +void abortFeedback (NetConnection *conn, NetplayAbortReason reason); +void resetFeedback (NetConnection *conn, NetplayResetReason reason, + bool byRemote); +void errorFeedback (NetConnection *conn); +void closeFeedback (NetConnection *conn); #endif /* _MELEE_H */ diff --git a/sc2/src/sc2code/netplay/netmelee.c b/sc2/src/sc2code/netplay/netmelee.c index c94a1d649..196ea8df7 100644 --- a/sc2/src/sc2code/netplay/netmelee.c +++ b/sc2/src/sc2code/netplay/netmelee.c @@ -83,6 +83,31 @@ getNumNetConnections(void) { //////////////////////////////////////////////////////////////////////////// +struct melee_state * +NetMelee_getMeleeState(NetConnection *conn) { + if (NetConnection_getState(conn) > NetState_connecting) { + BattleStateData *battleStateData = + (BattleStateData *) NetConnection_getStateData(conn); + return battleStateData->meleeState; + } else { + return (struct melee_state *) NetConnection_getExtra(conn); + } +} + +struct battlestate_struct * +NetMelee_getBattleState(NetConnection *conn) { + if (NetConnection_getState(conn) > NetState_connecting) { + BattleStateData *battleStateData = + (BattleStateData *) NetConnection_getStateData(conn); + return battleStateData->battleState; + } else { + return NULL; + } +} + +//////////////////////////////////////////////////////////////////////////// + + // Check the network connections for input. void netInput(void) { @@ -260,6 +285,23 @@ initBattleStateDataConnections(void) { } } +void +setBattleStateConnections(struct battlestate_struct *bs) { + COUNT player; + + for (player = 0; player < NUM_PLAYERS; player++) + { + BattleStateData *battleStateData; + NetConnection *conn = netConnections[player]; + if (conn == NULL) + continue; + + battleStateData = + (BattleStateData *) NetConnection_getStateData(conn); + battleStateData->battleState = bs; + } +} + BATTLE_INPUT_STATE networkBattleInput(COUNT player, STARSHIPPTR StarShipPtr) { BattleInputBuffer *bib = getBattleInputBuffer(player); diff --git a/sc2/src/sc2code/netplay/netmelee.h b/sc2/src/sc2code/netplay/netmelee.h index f75d5bb20..c7ad2b10c 100644 --- a/sc2/src/sc2code/netplay/netmelee.h +++ b/sc2/src/sc2code/netplay/netmelee.h @@ -37,6 +37,9 @@ void closeAllConnections(void); void closeAllConnections(void); size_t getNumNetConnections(void); +struct melee_state *NetMelee_getMeleeState(NetConnection *conn); +struct battlestate_struct *NetMelee_getBattleState(NetConnection *conn); + void netInput(void); void netInputBlocking(uint32 timeoutMs); void flushPacketQueues(void); @@ -50,6 +53,7 @@ bool allConnected(void); void sendBattleInputConnections(BATTLE_INPUT_STATE input); void sendChecksumConnections(uint32 frameNr, uint32 checksum); void initBattleStateDataConnections(void); +void setBattleStateConnections(struct battlestate_struct *bs); BATTLE_INPUT_STATE networkBattleInput(COUNT player, STARSHIPPTR StarShipPtr); diff --git a/sc2/src/sc2code/netplay/netmisc.c b/sc2/src/sc2code/netplay/netmisc.c index 6827baf59..aeb207028 100644 --- a/sc2/src/sc2code/netplay/netmisc.c +++ b/sc2/src/sc2code/netplay/netmisc.c @@ -33,6 +33,7 @@ static BattleStateData *BattleStateData_alloc(void); static void BattleStateData_free(BattleStateData *battleStateData); static inline BattleStateData *BattleStateData_new( struct melee_state *meleeState, + struct battlestate_struct *battleState, struct getmelee_struct *getMeleeState); static void BattleStateData_delete(BattleStateData *battleStateData); @@ -49,11 +50,13 @@ BattleStateData_free(BattleStateData *battleStateData) { static inline BattleStateData * BattleStateData_new(struct melee_state *meleeState, + struct battlestate_struct *battleState, struct getmelee_struct *getMeleeState) { BattleStateData *battleStateData = BattleStateData_alloc(); battleStateData->releaseFunction = (NetConnectionStateData_ReleaseFunction) BattleStateData_delete; battleStateData->meleeState = meleeState; + battleStateData->battleState = battleState; battleStateData->getMeleeState = getMeleeState; return battleStateData; } @@ -72,14 +75,6 @@ static void NetMelee_enterState_inSetup(NetConnection *conn, void *arg); // Called when a connection has been established. void NetMelee_connectCallback(NetConnection *conn) { - BattleStateData *battleStateData; - struct melee_state *meleeState; - - meleeState = (struct melee_state *) NetConnection_getExtra(conn); - battleStateData = BattleStateData_new(meleeState, NULL); - NetConnection_setStateData(conn, (void *) battleStateData); - NetConnection_setExtra(conn, NULL); - sendInit(conn); Netplay_localReady (conn, NetMelee_enterState_inSetup, NULL, false); } @@ -87,28 +82,14 @@ NetMelee_connectCallback(NetConnection *conn) { // Called when a connection is closed. void NetMelee_closeCallback(NetConnection *conn) { - struct melee_state *meleeState; - - if (NetConnection_getState(conn) > NetState_connecting) { - BattleStateData *battleStateData = - (BattleStateData *) NetConnection_getStateData(conn); - meleeState = battleStateData->meleeState; - } else { - meleeState = (struct melee_state *) NetConnection_getExtra(conn); - } - - closeFeedback(meleeState, NetConnection_getPlayerNr(conn)); + closeFeedback(conn); } // Called when a network error occurs during connect. void NetMelee_errorCallback(NetConnection *conn, const NetConnectionError *error) { - void *meleeState; - - meleeState = NetConnection_getExtra(conn); - errorFeedback(meleeState, NetConnection_getPlayerNr(conn)); - + errorFeedback(conn); (void) error; } @@ -121,13 +102,15 @@ NetMelee_enterState_inSetup(NetConnection *conn, void *arg) { int player; NetConnection_setState(conn, NetState_inSetup); - - battleStateData = (BattleStateData *) NetConnection_getStateData(conn); - meleeState = battleStateData->meleeState; + + meleeState = (struct melee_state *) NetConnection_getExtra(conn); + battleStateData = BattleStateData_new(meleeState, NULL, NULL); + NetConnection_setStateData(conn, (void *) battleStateData); + NetConnection_setExtra(conn, NULL); player = NetConnection_getPlayerNr(conn); - connectedFeedback(meleeState, player); + connectedFeedback(conn); entireFleetChanged(meleeState, player); teamStringChanged(meleeState, player); diff --git a/sc2/src/sc2code/netplay/netmisc.h b/sc2/src/sc2code/netplay/netmisc.h index ad7d1da20..c5bf6a092 100644 --- a/sc2/src/sc2code/netplay/netmisc.h +++ b/sc2/src/sc2code/netplay/netmisc.h @@ -32,6 +32,7 @@ struct BattleStateData { NETCONNECTION_STATE_DATA_COMMON struct melee_state *meleeState; + struct battlestate_struct *battleState; struct getmelee_struct *getMeleeState; BattleFrameCounter endFrameCount; }; diff --git a/sc2/src/sc2code/netplay/netstate.h b/sc2/src/sc2code/netplay/netstate.h index c74273b5b..60bedf658 100644 --- a/sc2/src/sc2code/netplay/netstate.h +++ b/sc2/src/sc2code/netplay/netstate.h @@ -50,7 +50,7 @@ typedef void (*NetConnectionStateData_ReleaseFunction)( NetConnectionStateData *stateData); #define NETCONNECTION_STATE_DATA_COMMON \ - NetConnectionStateData_ReleaseFunction releaseFunction; + NetConnectionStateData_ReleaseFunction releaseFunction; struct NetConnectionStateData { diff --git a/sc2/src/sc2code/netplay/packethandlers.c b/sc2/src/sc2code/netplay/packethandlers.c index 857baf8e9..d93f5f35c 100644 --- a/sc2/src/sc2code/netplay/packethandlers.c +++ b/sc2/src/sc2code/netplay/packethandlers.c @@ -94,7 +94,7 @@ PacketHandler_Init(NetConnection *conn, const Packet_Init *packet) { if (packet->protoVersion.major != NETPLAY_PROTOCOL_VERSION_MAJOR || packet->protoVersion.minor != NETPLAY_PROTOCOL_VERSION_MINOR) { sendAbort (conn, AbortReason_versionMismatch); - abortFeedback(conn->player, AbortReason_versionMismatch); + abortFeedback(conn, AbortReason_versionMismatch); log_add(log_Error, "Protocol version %d.%d not supported.\n", packet->protoVersion.major, packet->protoVersion.minor); errno = ENOSYS; @@ -106,7 +106,7 @@ PacketHandler_Init(NetConnection *conn, const Packet_Init *packet) { NETPLAY_MIN_UQM_VERSION_MINOR, NETPLAY_MIN_UQM_VERSION_PATCH) < 0) { sendAbort (conn, AbortReason_versionMismatch); - abortFeedback(conn->player, AbortReason_versionMismatch); + abortFeedback(conn, AbortReason_versionMismatch); log_add(log_Error, "Remote side is running a version of UQM that " "is too old (%d.%d.%d; %d.%d.%d is required).\n", packet->uqmVersion.major, packet->uqmVersion.minor, @@ -662,7 +662,7 @@ PacketHandler_Checksum(NetConnection *conn, const Packet_Checksum *packet) { int PacketHandler_Abort(NetConnection *conn, const Packet_Abort *packet) { - abortFeedback(conn->player, packet->reason); + abortFeedback(conn, packet->reason); return -1; // Close connection. diff --git a/sc2/src/sc2code/netplay/proto/reset.c b/sc2/src/sc2code/netplay/proto/reset.c index 604438812..c74c43c18 100644 --- a/sc2/src/sc2code/netplay/proto/reset.c +++ b/sc2/src/sc2code/netplay/proto/reset.c @@ -83,7 +83,7 @@ Netplay_connectionReset(NetConnection *conn, NetplayResetReason reason, case NetState_endingBattle: case NetState_endingBattle2: case NetState_endMelee: - resetFeedback(conn->player, reason, byRemote); + resetFeedback(conn, reason, byRemote); break; } } @@ -147,9 +147,9 @@ Netplay_remoteReset(NetConnection *conn, NetplayResetReason reason) { conn->stateFlags.reset.remoteReset = true; if (!conn->stateFlags.reset.localReset) { - Netplay_connectionReset(conn, reason, true); sendReset(conn, reason); conn->stateFlags.reset.localReset = true; + Netplay_connectionReset(conn, reason, true); } Netplay_resetConditionTriggered(conn);