diff --git a/README.org b/README.org index 9cb5b32..ba13db2 100644 --- a/README.org +++ b/README.org @@ -3,7 +3,7 @@ An example of client-side prediction for networked games, as research and training for 'Spacewar!' ** What is this repository for? -I realized that the current netcode of Spacewar was fine for simply running two +I realized that the current net-code of Spacewar was fine for simply running two instances of the game on the same computer; but it would not hold up to latencies of actual networks nor would it be able to do any structured communication due to being entirely over UDP. I knew this when writing it, but I @@ -21,7 +21,7 @@ latency issues, and must be reasonably smooth. This will provide a simple enough simulation to learn the techniques, while also being similar enough to "Spacewar!" so that it's not too big of a stretch to -update that project's netcode. It may be cute to have this be some sort of chat +update that project's net-code. It may be cute to have this be some sort of chat program, but that's another project for another day. For now, circles moving around in an empty space that move smoothly over network @@ -56,6 +56,13 @@ packets that aren't tied to the game tick is causing it; I'm going to change that. It probably should have been done that way from the start; but I didn't really think about that. +** Entry 06: Fixed it! +Tying it to the game ticks made it much better. Packet spam was not the way to +go, and I should have realized that had I thought about it more. I'm now going +to work on improving the client and separating out the techniques so at the end +just by changing preprocessor statements you'll be able to see the effects of +each technique. + * Notes On Techniques: ** Entry 00: Where I'm Learning All This From: I'm using a series of articles from gabrielgambetta.com, which seem to be well diff --git a/src/client/cspt-client.c b/src/client/cspt-client.c index dd038bf..9332da9 100644 --- a/src/client/cspt-client.c +++ b/src/client/cspt-client.c @@ -18,6 +18,14 @@ #include "../cspt-state.h" #include "../cspt-message.h" +// A structure for binding together the shared state between threads: +struct threadParameters +{ + struct gameState * state; + struct clientInput * message; + char * ipAddress; +}; + void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius) { const int32_t diameter = (radius * 2); @@ -55,23 +63,17 @@ void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32 } } } - -struct threadParameters -{ - struct gameState * state; - struct clientInput * message; -}; void * networkHandler(void * parameters) { - // + // Declare the needed variables for the thread: struct threadParameters * arguments = parameters; struct sockaddr_in serverAddress; int udpSocket = 0; // Point at the server: serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = inet_addr("192.168.0.100"); + serverAddress.sin_addr.s_addr = inet_addr(arguments->ipAddress); serverAddress.sin_port = htons(5200); // Create a UDP socket to send through: @@ -82,6 +84,7 @@ void * networkHandler(void * parameters) timeout.tv_sec = 0; timeout.tv_usec = 1000; setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); + struct gameState * updatedState = calloc(1, sizeof(struct gameState)); while (true) { @@ -134,7 +137,7 @@ void * graphicsThreadHandler(void * parameters) { case SDL_KEYDOWN: { - switch( event.key.keysym.sym ) + switch (event.key.keysym.sym) { case SDLK_LEFT: { @@ -196,13 +199,14 @@ void * graphicsThreadHandler(void * parameters) } } } - + // Clear the screen, filling it with black: SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255); - // Clear the screen, filling it with black: SDL_RenderClear(renderer); - + + // Set the colour to yellow: SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); + // Draw all the connected clients: for (int index = 0; index < 16; index++) { if (state->clients[index].registered == true) @@ -213,6 +217,9 @@ void * graphicsThreadHandler(void * parameters) // Present the rendered graphics: SDL_RenderPresent(renderer); + + // Delay enough so that we only hit 144 frames: + SDL_Delay(1000/144); } return NULL; @@ -221,13 +228,15 @@ void * graphicsThreadHandler(void * parameters) int main(int argc, char ** argv) { int serverSocket = 0; - pthread_t graphicsThread, networkThread, gameThread; - struct CsptMessage currentMessage; bool continueRunning = true; - struct gameState * currentState = calloc(1, sizeof(struct gameState)); - struct clientInput * clientInput = calloc(1, sizeof(struct gameState)); uint8_t currentPlayerNumber = 0; struct sockaddr_in serverAddress; + struct CsptMessage currentMessage; + pthread_t graphicsThread, networkThread, gameThread; + struct gameState * currentState = calloc(1, sizeof(struct gameState)); + struct clientInput * clientInput = calloc(1, sizeof(struct gameState)); + + // Say hello: printf("Client-Side Prediction Test - Client Starting.\n"); // Give me a socket, and make sure it's working: @@ -237,10 +246,21 @@ int main(int argc, char ** argv) printf("Socket creation failed.\n"); exit(EXIT_FAILURE); } - + // Set our IP address and port. Default to localhost for testing: + char * ipAddress = calloc(46, sizeof(char)); + if (argc < 1) + { + strncpy(ipAddress,"127.0.0.1", 9); + } + else + { + strncpy(ipAddress, argv[1], strlen(argv[1])); + } + + // Create an address struct to point at the server: serverAddress.sin_family = AF_INET; - serverAddress.sin_addr.s_addr = inet_addr("192.168.0.100"); + serverAddress.sin_addr.s_addr = inet_addr(ipAddress); serverAddress.sin_port = htons(5200); // Connect to the server: @@ -263,14 +283,17 @@ int main(int argc, char ** argv) } printf("Registered as: %u\n", currentPlayerNumber); - printf("%-7s | %u\n", messageStrings[currentMessage.type], currentMessage.content); + // Configure the thread parameters: struct threadParameters parameters; parameters.message = clientInput; parameters.state = currentState; - pthread_create(&graphicsThread, NULL, graphicsThreadHandler, ¶meters); + parameters.ipAddress = ipAddress; + + // Create all of our threads: pthread_create(&gameThread, NULL, gameThreadHandler, ¶meters); pthread_create(&networkThread, NULL, networkHandler, ¶meters); + pthread_create(&graphicsThread, NULL, graphicsThreadHandler, ¶meters); while (continueRunning) { @@ -298,8 +321,11 @@ int main(int argc, char ** argv) } else { + // Say goodbye to the server: currentMessage.type = 1; currentMessage.content = 0; + + // Send the goodbye message and shutdown: send(serverSocket, ¤tMessage, sizeof(struct CsptMessage), 0); shutdown(serverSocket, SHUT_RDWR); serverSocket = 0;