From 0ae5fa1b54439658bf2dd89cdbce74e95b0bae14 Mon Sep 17 00:00:00 2001 From: Jeremy Rand Date: Wed, 7 Jun 2023 19:53:14 -0400 Subject: [PATCH] More global high score rework towards making it generic. --- BUGS.md | 1 + .../xcschemes/xcschememanagement.plist | 4 +- BuGS/globalScores.c | 717 ++++++++++-------- BuGS/globalScores.h | 4 + 4 files changed, 396 insertions(+), 330 deletions(-) diff --git a/BUGS.md b/BUGS.md index bbc258c..503bb3e 100644 --- a/BUGS.md +++ b/BUGS.md @@ -2,6 +2,7 @@ BUGS ======= This is a list of the software bugs (as opposed to the bugs in the game that you shoot) that still need attention: +* Should detect when running on system 5 or lower and quit gracefully. Today, the game crashes. FIXED diff --git a/BuGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist b/BuGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist index 1e269a5..f9d6b69 100644 --- a/BuGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist +++ b/BuGS.xcodeproj/xcuserdata/jrand.xcuserdatad/xcschemes/xcschememanagement.plist @@ -12,7 +12,7 @@ Binary.xcscheme_^#shared#^_ orderHint - 4 + 1 BuGS.xcscheme_^#shared#^_ @@ -22,7 +22,7 @@ DiskImage.xcscheme_^#shared#^_ orderHint - 1 + 4 doNotBuild.xcscheme_^#shared#^_ diff --git a/BuGS/globalScores.c b/BuGS/globalScores.c index 835d1ad..ec43e68 100644 --- a/BuGS/globalScores.c +++ b/BuGS/globalScores.c @@ -76,7 +76,7 @@ typedef struct tHelloResponse { typedef struct tScoresResponse { uint16_t responseType; - tHighScore highScores[10]; + tHighScores highScores; } tScoresResponse; @@ -135,8 +135,11 @@ typedef enum tGameNetworkState { GAME_NETWORK_WAITING_FOR_SCORE_ACK, GAME_NETWORK_CLOSING_TCP, + + NUM_GAME_NETWORK_STATES } tGameNetworkState; +typedef void (*tGameNetworkStateHandler)(void); typedef struct tGameNetworkGlobals { Boolean networkStartedConnected; @@ -157,9 +160,52 @@ typedef struct tGameNetworkGlobals { uint16_t timeout; } tGameNetworkGlobals; +// Forward declarations + +static void handleConnectFailed(void); +static void handleUnconnected(void); +static void handleConnected(void); +static void handleResolvingName(void); +static void handleLookupFailed(void); +static void handleSocketError(void); +static void handleProtocolFailed(void); +static void handleFailure(void); +static void handleTcpUnconnected(void); +static void handleWaitingForTcp(void); +static void handleWaitingForHello(void); +static void handleRequestScores(void); +static void handleWaitingForScores(void); +static void handleSetHighScore(void); +static void handleWaitingForScoreAck(void); +static void handleClosingTcp(void); // Globals +static tGameNetworkStateHandler handlers[NUM_GAME_NETWORK_STATES] = { + handleConnectFailed, + handleUnconnected, + + handleConnected, + handleResolvingName, + + handleLookupFailed, + handleSocketError, + handleProtocolFailed, + handleFailure, + + handleTcpUnconnected, + + handleWaitingForTcp, + + handleWaitingForHello, + handleRequestScores, + handleWaitingForScores, + handleSetHighScore, + handleWaitingForScoreAck, + + handleClosingTcp +}; + // I am running out of space in the main segment so I am moving these globals into // a dynamically allocated struct. It is only allocated if network capabilities are // detected. @@ -299,7 +345,7 @@ static char hexDigitToAscii(Word digit) static void displayString(Word row, char * string) { - strcpy(&(highScoreResponse.highScores[row].scoreText[2]), string); + strcpy(&(highScoreResponse.highScores.score[row].scoreText[2]), string); } static void displayNetworkError(char * line1, char * line2) @@ -309,16 +355,16 @@ static void displayNetworkError(char * line1, char * line2) networkGlobals->gameNetworkState = GAME_NETWORK_FAILURE; - for (row = 0; row < sizeof(highScoreResponse.highScores) / sizeof(highScoreResponse.highScores[0]); row++) { + for (row = 0; row < sizeof(highScoreResponse.highScores) / sizeof(highScoreResponse.highScores.score[0]); row++) { for (column = 0; - column < sizeof(highScoreResponse.highScores[0].scoreText) / sizeof(highScoreResponse.highScores[0].scoreText[0]); + column < sizeof(highScoreResponse.highScores.score[0].scoreText) / sizeof(highScoreResponse.highScores.score[0].scoreText[0]); column++) { - highScoreResponse.highScores[row].scoreText[column] = ' '; + highScoreResponse.highScores.score[row].scoreText[column] = ' '; } for (column = 0; - column < sizeof(highScoreResponse.highScores[0].who) / sizeof(highScoreResponse.highScores[0].who[0]); + column < sizeof(highScoreResponse.highScores.score[0].who) / sizeof(highScoreResponse.highScores.score[0].who[0]); column++) { - highScoreResponse.highScores[row].who[column] = ' '; + highScoreResponse.highScores.score[row].who[column] = ' '; } } @@ -328,21 +374,346 @@ static void displayNetworkError(char * line1, char * line2) displayString(4, line1); displayString(5, line2); - highScoreResponse.highScores[7].scoreText[0] = 'C'; - highScoreResponse.highScores[7].scoreText[1] = 'O'; - highScoreResponse.highScores[7].scoreText[2] = 'D'; - highScoreResponse.highScores[7].scoreText[3] = 'E'; - highScoreResponse.highScores[7].scoreText[4] = ':'; - highScoreResponse.highScores[7].scoreText[5] = ' '; - highScoreResponse.highScores[7].scoreText[6] = hexDigitToAscii(networkGlobals->errorCode >> 12); - highScoreResponse.highScores[7].scoreText[7] = hexDigitToAscii(networkGlobals->errorCode >> 8); - highScoreResponse.highScores[7].scoreText[8] = hexDigitToAscii(networkGlobals->errorCode >> 4); - highScoreResponse.highScores[7].scoreText[9] = hexDigitToAscii(networkGlobals->errorCode); + highScoreResponse.highScores.score[7].scoreText[0] = 'C'; + highScoreResponse.highScores.score[7].scoreText[1] = 'O'; + highScoreResponse.highScores.score[7].scoreText[2] = 'D'; + highScoreResponse.highScores.score[7].scoreText[3] = 'E'; + highScoreResponse.highScores.score[7].scoreText[4] = ':'; + highScoreResponse.highScores.score[7].scoreText[5] = ' '; + highScoreResponse.highScores.score[7].scoreText[6] = hexDigitToAscii(networkGlobals->errorCode >> 12); + highScoreResponse.highScores.score[7].scoreText[7] = hexDigitToAscii(networkGlobals->errorCode >> 8); + highScoreResponse.highScores.score[7].scoreText[8] = hexDigitToAscii(networkGlobals->errorCode >> 4); + highScoreResponse.highScores.score[7].scoreText[9] = hexDigitToAscii(networkGlobals->errorCode); globalScoreAge = 0; hasGlobalHighScores = TRUE; } +static void handleConnectFailed(void) +{ + displayNetworkError("CONNECT", "FAILED"); +} + +static void handleUnconnected(void) +{ + if (networkGlobals->initParams.displayConnectionString != NULL) + networkGlobals->initParams.displayConnectionString(TRUE); + TCPIPConnect(NULL); + if ((!toolerror()) && + (TCPIPGetConnectStatus())) { + networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED; + } else { + networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED; + } + if (networkGlobals->initParams.displayConnectionString != NULL) + networkGlobals->initParams.displayConnectionString(FALSE); +} + +static void handleConnected(void) +{ + TCPIPDNRNameToIP(networkGlobals->initParams.scoreServer, &(networkGlobals->domainNameResolution)); + if (toolerror()) { + networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED; + networkGlobals->errorCode = toolerror(); + } else + networkGlobals->gameNetworkState = GAME_NETWORK_RESOLVING_NAME; +} + +static void handleResolvingName(void) +{ + if (networkGlobals->domainNameResolution.DNRstatus == DNR_Pending) + return; + + if (networkGlobals->domainNameResolution.DNRstatus != DNR_OK) { + networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED; + networkGlobals->errorCode = networkGlobals->domainNameResolution.DNRstatus; + return; + } + + networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; +} + +static void handleLookupFailed(void) +{ + displayNetworkError("LOOKUP", "FAILED"); +} + +static void handleSocketError(void) +{ + displayNetworkError("SOCKET", "ERROR"); + networkGlobals->timeout = NETWORK_RETRY_TIMEOUT; +} + +static void handleProtocolFailed(void) +{ + abortConnection(); + displayNetworkError("PROTOCOL", "FAILED"); + networkGlobals->timeout = NETWORK_RETRY_TIMEOUT; +} + +static void handleFailure(void) +{ + // All of the different failure modes except protocol failure above end up here ultimately. And the state + // machine stays here once it arrives here. + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + if (networkGlobals->timeout == 0) + networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; + } +} + +static void handleTcpUnconnected(void) +{ + if ((hasGlobalHighScores) && + (globalScoreAge > 0) && + (!networkGlobals->hasHighScoreToSend)) + return; + + networkGlobals->ipid = TCPIPLogin(networkGlobals->initParams.userId, networkGlobals->domainNameResolution.DNRIPaddress, networkGlobals->initParams.scorePort, 0, 64); + if (toolerror()) { + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + networkGlobals->errorCode = toolerror(); + return; + } + + networkGlobals->errorCode = TCPIPOpenTCP(networkGlobals->ipid); + if (networkGlobals->errorCode != tcperrOK) { + TCPIPLogout(networkGlobals->ipid); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_TCP; + networkGlobals->timeout = TCP_CONNECT_TIMEOUT; +} + +static void handleWaitingForTcp(void) +{ + networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus)); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + if ((networkGlobals->tcpStatus.srState == TCPSSYNSENT) || + (networkGlobals->tcpStatus.srState == TCPSSYNRCVD)) { + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + } else { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = TCP_CONNECT_TIMEOUT_ERROR; + } + return; + } + + if (networkGlobals->tcpStatus.srState != TCPSESTABLISHED) { + abortConnection(); + networkGlobals->errorCode = networkGlobals->tcpStatus.srState | 0x8000; + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_HELLO; + networkGlobals->timeout = READ_NETWORK_TIMEOUT; + networkGlobals->bytesRead = 0; +} + +static void handleWaitingForHello(void) +{ + networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, + ((uint32_t)(&(networkGlobals->helloResponse))) + networkGlobals->bytesRead, + sizeof(networkGlobals->helloResponse) - networkGlobals->bytesRead, + &(networkGlobals->readResponseBuf)); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; + if (networkGlobals->bytesRead < sizeof(networkGlobals->helloResponse)) { + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + } else { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HELLO_TIMEOUT_ERROR; + } + return; + } + + if (networkGlobals->bytesRead > sizeof(networkGlobals->helloResponse)) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HELLO_TOO_BIG_ERROR; + return; + } + + if (networkGlobals->helloResponse.responseType != RESPONSE_TYPE_HELLO) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HELLO_UNEXPECTED_RESPONSE_ERROR; + return; + } + + networkGlobals->secrets[2] = networkGlobals->helloResponse.nonce; + if (networkGlobals->hasHighScoreToSend) { + networkGlobals->gameNetworkState = GAME_NETWORK_SET_HIGH_SCORE; + } else if ((!hasGlobalHighScores) || + (globalScoreAge == 0)) { + networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES; + } else { + TCPIPCloseTCP(networkGlobals->ipid); + networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP; + networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT; + } +} + +static void handleRequestScores(void) +{ + networkGlobals->highScoreRequest.highScoreRequest.requestType = REQUEST_TYPE_GET_HIGH_SCORES; + + md5Init(&(networkGlobals->hashWorkBlock)); + md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets)); + md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->highScoreRequest.highScoreRequest), sizeof(networkGlobals->highScoreRequest.highScoreRequest)); + md5Finish(&(networkGlobals->hashWorkBlock), &(networkGlobals->highScoreRequest.md5Digest[0])); + + networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->highScoreRequest), sizeof(networkGlobals->highScoreRequest), FALSE, FALSE); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORES; + networkGlobals->timeout = READ_NETWORK_TIMEOUT; + networkGlobals->bytesRead = 0; +} + +static void handleWaitingForScores(void) +{ + networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, + ((uint32_t)(&highScoreResponse)) + networkGlobals->bytesRead, + sizeof(highScoreResponse) - networkGlobals->bytesRead, + &(networkGlobals->readResponseBuf)); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; + if (networkGlobals->bytesRead < sizeof(highScoreResponse)) { + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + } else { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HIGH_SCORE_TIMEOUT_ERROR; + } + return; + } + + if (networkGlobals->bytesRead > sizeof(highScoreResponse)) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HIGH_SCORE_TOO_BIG_ERROR; + return; + } + + if (highScoreResponse.responseType != RESPONSE_TYPE_SCORES) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR; + return; + } + + globalScoreAge = GLOBAL_SCORE_REFRESH_TIME; + hasGlobalHighScores = TRUE; + + TCPIPCloseTCP(networkGlobals->ipid); + networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP; + networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT; +} + +static void handleSetHighScore(void) +{ + setHighScoreRequest.setHighScoreRequest.requestType = REQUEST_TYPE_SET_SCORE; + setHighScoreRequest.setHighScoreRequest.who[3] = '\0'; + + md5Init(&(networkGlobals->hashWorkBlock)); + md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets)); + md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(setHighScoreRequest.setHighScoreRequest), sizeof(setHighScoreRequest.setHighScoreRequest)); + md5Finish(&(networkGlobals->hashWorkBlock), &(setHighScoreRequest.md5Digest[0])); + + networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&setHighScoreRequest, sizeof(setHighScoreRequest), FALSE, FALSE); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORE_ACK; + networkGlobals->timeout = READ_NETWORK_TIMEOUT; + networkGlobals->bytesRead = 0; +} + +static void handleWaitingForScoreAck(void) +{ + networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, + ((uint32_t)(&(networkGlobals->setHighScoreResponse))) + networkGlobals->bytesRead, + sizeof(networkGlobals->setHighScoreResponse) - networkGlobals->bytesRead, + &(networkGlobals->readResponseBuf)); + if (networkGlobals->errorCode != tcperrOK) { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; + return; + } + + networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; + if (networkGlobals->bytesRead < sizeof(networkGlobals->setHighScoreResponse)) { + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + } else { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = SET_SCORE_TIMEOUT_ERROR; + } + return; + } + + if (networkGlobals->bytesRead > sizeof(networkGlobals->setHighScoreResponse)) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = SET_SCORE_TOO_BIG_ERROR; + return; + } + + if (networkGlobals->setHighScoreResponse.responseType != RESPONSE_TYPE_STATUS) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = SET_SCORE_UNEXPECTED_RESPONSE_ERROR; + return; + } + + if (!networkGlobals->setHighScoreResponse.success) { + networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; + networkGlobals->errorCode = SET_SCORE_FAILED_ERROR; + return; + } + + networkGlobals->hasHighScoreToSend = FALSE; + globalScoreAge = 0; + networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES; +} + +static void handleClosingTcp(void) +{ + networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus)); + if ((networkGlobals->tcpStatus.srState != TCPSCLOSED) && + (networkGlobals->tcpStatus.srState != TCPSTIMEWAIT)) { + if (networkGlobals->timeout > 0) { + networkGlobals->timeout--; + } else { + abortConnection(); + networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; + } + return; + } + + TCPIPLogout(networkGlobals->ipid); + networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; +} void pollNetwork(void) { @@ -351,317 +722,7 @@ void pollNetwork(void) TCPIPPoll(); - switch (networkGlobals->gameNetworkState) { - case GAME_NETWORK_SOCKET_ERROR: - displayNetworkError("SOCKET", "ERROR"); - networkGlobals->timeout = NETWORK_RETRY_TIMEOUT; - break; - - case GAME_NETWORK_LOOKUP_FAILED: - displayNetworkError("LOOKUP", "FAILED"); - break; - - case GAME_NETWORK_CONNECT_FAILED: - displayNetworkError("CONNECT", "FAILED"); - break; - - case GAME_NETWORK_PROTOCOL_FAILED: - abortConnection(); - displayNetworkError("PROTOCOL", "FAILED"); - networkGlobals->timeout = NETWORK_RETRY_TIMEOUT; - break; - - case GAME_NETWORK_FAILURE: - // All of the different failure modes except protocol failure above end up here ultimately. And the state - // machine stays here once it arrives here. - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - if (networkGlobals->timeout == 0) - networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; - } - break; - - case GAME_NETWORK_UNCONNECTED: - if (networkGlobals->initParams.displayConnectionString != NULL) - networkGlobals->initParams.displayConnectionString(TRUE); - TCPIPConnect(NULL); - if ((!toolerror()) && - (TCPIPGetConnectStatus())) { - networkGlobals->gameNetworkState = GAME_NETWORK_CONNECTED; - } else { - networkGlobals->gameNetworkState = GAME_NETWORK_CONNECT_FAILED; - } - if (networkGlobals->initParams.displayConnectionString != NULL) - networkGlobals->initParams.displayConnectionString(FALSE); - break; - - case GAME_NETWORK_CONNECTED: - TCPIPDNRNameToIP(networkGlobals->initParams.scoreServer, &(networkGlobals->domainNameResolution)); - if (toolerror()) { - networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED; - networkGlobals->errorCode = toolerror(); - } else - networkGlobals->gameNetworkState = GAME_NETWORK_RESOLVING_NAME; - break; - - case GAME_NETWORK_RESOLVING_NAME: - if (networkGlobals->domainNameResolution.DNRstatus == DNR_Pending) - break; - - if (networkGlobals->domainNameResolution.DNRstatus != DNR_OK) { - networkGlobals->gameNetworkState = GAME_NETWORK_LOOKUP_FAILED; - networkGlobals->errorCode = networkGlobals->domainNameResolution.DNRstatus; - break; - } - - networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; - break; - - case GAME_NETWORK_TCP_UNCONNECTED: - if ((hasGlobalHighScores) && - (globalScoreAge > 0) && - (!networkGlobals->hasHighScoreToSend)) - break; - - networkGlobals->ipid = TCPIPLogin(networkGlobals->initParams.userId, networkGlobals->domainNameResolution.DNRIPaddress, networkGlobals->initParams.scorePort, 0, 64); - if (toolerror()) { - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - networkGlobals->errorCode = toolerror(); - break; - } - - networkGlobals->errorCode = TCPIPOpenTCP(networkGlobals->ipid); - if (networkGlobals->errorCode != tcperrOK) { - TCPIPLogout(networkGlobals->ipid); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_TCP; - networkGlobals->timeout = TCP_CONNECT_TIMEOUT; - break; - - case GAME_NETWORK_WAITING_FOR_TCP: - networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus)); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - if ((networkGlobals->tcpStatus.srState == TCPSSYNSENT) || - (networkGlobals->tcpStatus.srState == TCPSSYNRCVD)) { - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - } else { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = TCP_CONNECT_TIMEOUT_ERROR; - } - break; - } - - if (networkGlobals->tcpStatus.srState != TCPSESTABLISHED) { - abortConnection(); - networkGlobals->errorCode = networkGlobals->tcpStatus.srState | 0x8000; - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_HELLO; - networkGlobals->timeout = READ_NETWORK_TIMEOUT; - networkGlobals->bytesRead = 0; - break; - - case GAME_NETWORK_WAITING_FOR_HELLO: - networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, - ((uint32_t)(&(networkGlobals->helloResponse))) + networkGlobals->bytesRead, - sizeof(networkGlobals->helloResponse) - networkGlobals->bytesRead, - &(networkGlobals->readResponseBuf)); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; - if (networkGlobals->bytesRead < sizeof(networkGlobals->helloResponse)) { - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - } else { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HELLO_TIMEOUT_ERROR; - } - break; - } - - if (networkGlobals->bytesRead > sizeof(networkGlobals->helloResponse)) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HELLO_TOO_BIG_ERROR; - break; - } - - if (networkGlobals->helloResponse.responseType != RESPONSE_TYPE_HELLO) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HELLO_UNEXPECTED_RESPONSE_ERROR; - break; - } - - networkGlobals->secrets[2] = networkGlobals->helloResponse.nonce; - if (networkGlobals->hasHighScoreToSend) { - networkGlobals->gameNetworkState = GAME_NETWORK_SET_HIGH_SCORE; - } else if ((!hasGlobalHighScores) || - (globalScoreAge == 0)) { - networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES; - } else { - TCPIPCloseTCP(networkGlobals->ipid); - networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP; - networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT; - } - break; - - case GAME_NETWORK_REQUEST_SCORES: - networkGlobals->highScoreRequest.highScoreRequest.requestType = REQUEST_TYPE_GET_HIGH_SCORES; - - md5Init(&(networkGlobals->hashWorkBlock)); - md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets)); - md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->highScoreRequest.highScoreRequest), sizeof(networkGlobals->highScoreRequest.highScoreRequest)); - md5Finish(&(networkGlobals->hashWorkBlock), &(networkGlobals->highScoreRequest.md5Digest[0])); - - networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&(networkGlobals->highScoreRequest), sizeof(networkGlobals->highScoreRequest), FALSE, FALSE); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORES; - networkGlobals->timeout = READ_NETWORK_TIMEOUT; - networkGlobals->bytesRead = 0; - break; - - case GAME_NETWORK_WAITING_FOR_SCORES: - networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, - ((uint32_t)(&highScoreResponse)) + networkGlobals->bytesRead, - sizeof(highScoreResponse) - networkGlobals->bytesRead, - &(networkGlobals->readResponseBuf)); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; - if (networkGlobals->bytesRead < sizeof(highScoreResponse)) { - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - } else { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HIGH_SCORE_TIMEOUT_ERROR; - } - break; - } - - if (networkGlobals->bytesRead > sizeof(highScoreResponse)) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HIGH_SCORE_TOO_BIG_ERROR; - break; - } - - if (highScoreResponse.responseType != RESPONSE_TYPE_SCORES) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = HIGH_SCORE_UNEXPECTED_RESPONSE_ERROR; - break; - } - - globalScoreAge = GLOBAL_SCORE_REFRESH_TIME; - hasGlobalHighScores = TRUE; - - TCPIPCloseTCP(networkGlobals->ipid); - networkGlobals->gameNetworkState = GAME_NETWORK_CLOSING_TCP; - networkGlobals->timeout = SHUTDOWN_NETWORK_TIMEOUT; - break; - - case GAME_NETWORK_SET_HIGH_SCORE: - setHighScoreRequest.setHighScoreRequest.requestType = REQUEST_TYPE_SET_SCORE; - setHighScoreRequest.setHighScoreRequest.who[3] = '\0'; - - md5Init(&(networkGlobals->hashWorkBlock)); - md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(networkGlobals->secrets), sizeof(networkGlobals->secrets)); - md5Append(&(networkGlobals->hashWorkBlock), (Pointer)&(setHighScoreRequest.setHighScoreRequest), sizeof(setHighScoreRequest.setHighScoreRequest)); - md5Finish(&(networkGlobals->hashWorkBlock), &(setHighScoreRequest.md5Digest[0])); - - networkGlobals->errorCode = TCPIPWriteTCP(networkGlobals->ipid, (Pointer)&setHighScoreRequest, sizeof(setHighScoreRequest), FALSE, FALSE); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->gameNetworkState = GAME_NETWORK_WAITING_FOR_SCORE_ACK; - networkGlobals->timeout = READ_NETWORK_TIMEOUT; - networkGlobals->bytesRead = 0; - break; - - case GAME_NETWORK_WAITING_FOR_SCORE_ACK: - networkGlobals->errorCode = TCPIPReadTCP(networkGlobals->ipid, 0, - ((uint32_t)(&(networkGlobals->setHighScoreResponse))) + networkGlobals->bytesRead, - sizeof(networkGlobals->setHighScoreResponse) - networkGlobals->bytesRead, - &(networkGlobals->readResponseBuf)); - if (networkGlobals->errorCode != tcperrOK) { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_SOCKET_ERROR; - break; - } - - networkGlobals->bytesRead += networkGlobals->readResponseBuf.rrBuffCount; - if (networkGlobals->bytesRead < sizeof(networkGlobals->setHighScoreResponse)) { - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - } else { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = SET_SCORE_TIMEOUT_ERROR; - } - break; - } - - if (networkGlobals->bytesRead > sizeof(networkGlobals->setHighScoreResponse)) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = SET_SCORE_TOO_BIG_ERROR; - break; - } - - if (networkGlobals->setHighScoreResponse.responseType != RESPONSE_TYPE_STATUS) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = SET_SCORE_UNEXPECTED_RESPONSE_ERROR; - break; - } - - if (!networkGlobals->setHighScoreResponse.success) { - networkGlobals->gameNetworkState = GAME_NETWORK_PROTOCOL_FAILED; - networkGlobals->errorCode = SET_SCORE_FAILED_ERROR; - break; - } - - networkGlobals->hasHighScoreToSend = FALSE; - globalScoreAge = 0; - networkGlobals->gameNetworkState = GAME_NETWORK_REQUEST_SCORES; - break; - - case GAME_NETWORK_CLOSING_TCP: - networkGlobals->errorCode = TCPIPStatusTCP(networkGlobals->ipid, &(networkGlobals->tcpStatus)); - if ((networkGlobals->tcpStatus.srState != TCPSCLOSED) && - (networkGlobals->tcpStatus.srState != TCPSTIMEWAIT)) { - if (networkGlobals->timeout > 0) { - networkGlobals->timeout--; - } else { - abortConnection(); - networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; - } - break; - } - - TCPIPLogout(networkGlobals->ipid); - networkGlobals->gameNetworkState = GAME_NETWORK_TCP_UNCONNECTED; - break; - } + handlers[networkGlobals->gameNetworkState](); } diff --git a/BuGS/globalScores.h b/BuGS/globalScores.h index f7b2989..656268c 100644 --- a/BuGS/globalScores.h +++ b/BuGS/globalScores.h @@ -20,6 +20,10 @@ typedef struct tHighScore unsigned long score; } tHighScore; +typedef struct tHighScores +{ + tHighScore score[10]; +} tHighScores; typedef struct tHighScoreInitParams {