Update devlog and add ability to choose IP address to connect to

This commit is contained in:
Barra Ó Catháin 2023-07-12 23:56:48 +01:00
parent 09f5684d3e
commit b903be7aa9
2 changed files with 55 additions and 22 deletions

View File

@ -3,7 +3,7 @@ An example of client-side prediction for networked games, as research and
training for 'Spacewar!' training for 'Spacewar!'
** What is this repository for? ** 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 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 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 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 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 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. program, but that's another project for another day.
For now, circles moving around in an empty space that move smoothly over network 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 that. It probably should have been done that way from the start; but I didn't
really think about that. 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: * Notes On Techniques:
** Entry 00: Where I'm Learning All This From: ** Entry 00: Where I'm Learning All This From:
I'm using a series of articles from gabrielgambetta.com, which seem to be well I'm using a series of articles from gabrielgambetta.com, which seem to be well

View File

@ -18,6 +18,14 @@
#include "../cspt-state.h" #include "../cspt-state.h"
#include "../cspt-message.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) void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32_t radius)
{ {
const int32_t diameter = (radius * 2); const int32_t diameter = (radius * 2);
@ -56,22 +64,16 @@ void DrawCircle(SDL_Renderer * renderer, int32_t centreX, int32_t centreY, int32
} }
} }
struct threadParameters
{
struct gameState * state;
struct clientInput * message;
};
void * networkHandler(void * parameters) void * networkHandler(void * parameters)
{ {
// // Declare the needed variables for the thread:
struct threadParameters * arguments = parameters; struct threadParameters * arguments = parameters;
struct sockaddr_in serverAddress; struct sockaddr_in serverAddress;
int udpSocket = 0; int udpSocket = 0;
// Point at the server: // Point at the server:
serverAddress.sin_family = AF_INET; 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); serverAddress.sin_port = htons(5200);
// Create a UDP socket to send through: // Create a UDP socket to send through:
@ -82,6 +84,7 @@ void * networkHandler(void * parameters)
timeout.tv_sec = 0; timeout.tv_sec = 0;
timeout.tv_usec = 1000; timeout.tv_usec = 1000;
setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout)); setsockopt(udpSocket, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
struct gameState * updatedState = calloc(1, sizeof(struct gameState)); struct gameState * updatedState = calloc(1, sizeof(struct gameState));
while (true) while (true)
{ {
@ -196,13 +199,14 @@ void * graphicsThreadHandler(void * parameters)
} }
} }
} }
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
// Clear the screen, filling it with black: // Clear the screen, filling it with black:
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer); SDL_RenderClear(renderer);
// Set the colour to yellow:
SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255); SDL_SetRenderDrawColor(renderer, 255, 255, 0, 255);
// Draw all the connected clients:
for (int index = 0; index < 16; index++) for (int index = 0; index < 16; index++)
{ {
if (state->clients[index].registered == true) if (state->clients[index].registered == true)
@ -213,6 +217,9 @@ void * graphicsThreadHandler(void * parameters)
// Present the rendered graphics: // Present the rendered graphics:
SDL_RenderPresent(renderer); SDL_RenderPresent(renderer);
// Delay enough so that we only hit 144 frames:
SDL_Delay(1000/144);
} }
return NULL; return NULL;
@ -221,13 +228,15 @@ void * graphicsThreadHandler(void * parameters)
int main(int argc, char ** argv) int main(int argc, char ** argv)
{ {
int serverSocket = 0; int serverSocket = 0;
pthread_t graphicsThread, networkThread, gameThread;
struct CsptMessage currentMessage;
bool continueRunning = true; bool continueRunning = true;
struct gameState * currentState = calloc(1, sizeof(struct gameState));
struct clientInput * clientInput = calloc(1, sizeof(struct gameState));
uint8_t currentPlayerNumber = 0; uint8_t currentPlayerNumber = 0;
struct sockaddr_in serverAddress; 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"); printf("Client-Side Prediction Test - Client Starting.\n");
// Give me a socket, and make sure it's working: // Give me a socket, and make sure it's working:
@ -239,8 +248,19 @@ int main(int argc, char ** argv)
} }
// Set our IP address and port. Default to localhost for testing: // 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_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); serverAddress.sin_port = htons(5200);
// Connect to the server: // Connect to the server:
@ -263,14 +283,17 @@ int main(int argc, char ** argv)
} }
printf("Registered as: %u\n", currentPlayerNumber); printf("Registered as: %u\n", currentPlayerNumber);
printf("%-7s | %u\n", messageStrings[currentMessage.type], currentMessage.content);
// Configure the thread parameters:
struct threadParameters parameters; struct threadParameters parameters;
parameters.message = clientInput; parameters.message = clientInput;
parameters.state = currentState; parameters.state = currentState;
pthread_create(&graphicsThread, NULL, graphicsThreadHandler, &parameters); parameters.ipAddress = ipAddress;
// Create all of our threads:
pthread_create(&gameThread, NULL, gameThreadHandler, &parameters); pthread_create(&gameThread, NULL, gameThreadHandler, &parameters);
pthread_create(&networkThread, NULL, networkHandler, &parameters); pthread_create(&networkThread, NULL, networkHandler, &parameters);
pthread_create(&graphicsThread, NULL, graphicsThreadHandler, &parameters);
while (continueRunning) while (continueRunning)
{ {
@ -298,8 +321,11 @@ int main(int argc, char ** argv)
} }
else else
{ {
// Say goodbye to the server:
currentMessage.type = 1; currentMessage.type = 1;
currentMessage.content = 0; currentMessage.content = 0;
// Send the goodbye message and shutdown:
send(serverSocket, &currentMessage, sizeof(struct CsptMessage), 0); send(serverSocket, &currentMessage, sizeof(struct CsptMessage), 0);
shutdown(serverSocket, SHUT_RDWR); shutdown(serverSocket, SHUT_RDWR);
serverSocket = 0; serverSocket = 0;