Added basic server reconcilliation

This commit is contained in:
Barra Ó Catháin 2023-08-03 00:15:44 +01:00
parent 9af376bcb1
commit 5e7bff96d0
3 changed files with 86 additions and 4 deletions

View File

@ -18,6 +18,7 @@
#include "../cspt-state.h" #include "../cspt-state.h"
#include "../cspt-message.h" #include "../cspt-message.h"
#define ENABLE_CLIENT_SIDE_PREDICTION #define ENABLE_CLIENT_SIDE_PREDICTION
#define ENABLE_SERVER_RECONCILLIATION
uint8_t colours[16][3] = uint8_t colours[16][3] =
{ {
@ -43,6 +44,7 @@ struct threadParameters
bool * keepRunning; bool * keepRunning;
struct gameState * state; struct gameState * state;
struct clientInput * message; struct clientInput * message;
struct inputHistory * inputBuffer;
}; };
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)
@ -110,18 +112,73 @@ void * networkHandler(void * parameters)
while (true) while (true)
{ {
// Send our input, recieve the state: // Send our input, recieve the state:
sendto(udpSocket, arguments->message, sizeof(struct clientInput), 0, (struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in)); sendto(udpSocket, arguments->message, sizeof(struct clientInput), 0,
(struct sockaddr *)&serverAddress, sizeof(struct sockaddr_in));
recvfrom(udpSocket, updatedState, sizeof(struct gameState), 0, NULL, NULL); recvfrom(udpSocket, updatedState, sizeof(struct gameState), 0, NULL, NULL);
// Only update the state if the given state is more recent than the current state: // Only update the state if the given state is more recent than the current state:
if(updatedState->timestamp.tv_sec > arguments->state->timestamp.tv_sec) if(updatedState->timestamp.tv_sec > arguments->state->timestamp.tv_sec)
{ {
memcpy(arguments->state, updatedState, sizeof(struct gameState)); memcpy(arguments->state, updatedState, sizeof(struct gameState));
#ifdef ENABLE_SERVER_RECONCILLIATION
// Throw away any already acknowledged inputs:
while (arguments->inputBuffer->start != -1 &&
arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber < arguments->state->tickNumber)
{
arguments->inputBuffer->start = (arguments->inputBuffer->start + 1) % 256;
if(arguments->inputBuffer->start == arguments->inputBuffer->end)
{
arguments->inputBuffer->start = -1;
}
}
uint8_t currentMessage = arguments->inputBuffer->start;
uint64_t lastTickNumber = arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber;
// Re-apply the currently unused messages:
while (currentMessage != 1 &&
currentMessage != arguments->inputBuffer->end)
{
updateInput(arguments->state, &arguments->inputBuffer->inputs[currentMessage]);
currentMessage = (currentMessage + 1) % 256;
if (arguments->inputBuffer->inputs[currentMessage].tickNumber != lastTickNumber)
{
doGameTick(arguments->state);
}
}
#endif
} }
else if(updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec && else if(updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec &&
updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec) updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec)
{ {
memcpy(arguments->state, updatedState, sizeof(struct gameState)); memcpy(arguments->state, updatedState, sizeof(struct gameState));
#ifdef ENABLE_SERVER_RECONCILLIATION
// Throw away any already acknowledged inputs:
while (arguments->inputBuffer->start != -1 &&
arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber < arguments->state->tickNumber)
{
arguments->inputBuffer->start = (arguments->inputBuffer->start + 1) % 256;
if(arguments->inputBuffer->start == arguments->inputBuffer->end)
{
arguments->inputBuffer->start = -1;
}
}
uint8_t currentMessage = arguments->inputBuffer->start;
uint64_t lastTickNumber = arguments->inputBuffer->inputs[arguments->inputBuffer->start].tickNumber;
// Re-apply the currently unused messages:
while (currentMessage != 1 &&
currentMessage != arguments->inputBuffer->end)
{
updateInput(arguments->state, &arguments->inputBuffer->inputs[currentMessage]);
currentMessage = (currentMessage + 1) % 256;
if (arguments->inputBuffer->inputs[currentMessage].tickNumber != lastTickNumber)
{
doGameTick(arguments->state);
}
}
#endif
} }
} }
} }
@ -134,11 +191,23 @@ void * gameThreadHandler(void * parameters)
while (true) while (true)
{ {
updateInput(arguments->state, arguments->message); updateInput(arguments->state, arguments->message);
#ifdef ENABLE_SERVER_RECONCILLIATION
if(arguments->inputBuffer->start = -1)
{
memcpy(&arguments->inputBuffer->inputs[0], arguments->message, sizeof(struct clientInput));
arguments->inputBuffer->start = 0;
arguments->inputBuffer->end = 1;
}
else
{
memcpy(&arguments->inputBuffer->inputs[arguments->inputBuffer->end], arguments->message, sizeof(struct clientInput));
arguments->inputBuffer->end = (arguments->inputBuffer->end + 1) % 256;
}
#endif
doGameTick(arguments->state); doGameTick(arguments->state);
usleep(15625); usleep(15625);
} }
#endif #endif
} }
void * graphicsThreadHandler(void * parameters) void * graphicsThreadHandler(void * parameters)
@ -329,6 +398,9 @@ int main(int argc, char ** argv)
parameters.message = clientInput; parameters.message = clientInput;
parameters.ipAddress = ipAddress; parameters.ipAddress = ipAddress;
parameters.keepRunning = &keepRunning; parameters.keepRunning = &keepRunning;
parameters.inputBuffer = calloc(1, sizeof(struct inputHistory));
parameters.inputBuffer->start = -1;
parameters.inputBuffer->end = -1;
// Create all of our threads: // Create all of our threads:
pthread_create(&gameThread, NULL, gameThreadHandler, &parameters); pthread_create(&gameThread, NULL, gameThreadHandler, &parameters);

View File

@ -1,5 +1,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include "cspt-state.h" #include "cspt-state.h"
void updateInput(struct gameState * state, struct clientInput * message) void updateInput(struct gameState * state, struct clientInput * message)
{ {
if(message->clientNumber < 16 && message->clientNumber >= 0) if(message->clientNumber < 16 && message->clientNumber >= 0)
@ -49,6 +51,7 @@ void doGameTick(struct gameState * state)
{ {
state->clients[index].yVelocity *= 0.9; state->clients[index].yVelocity *= 0.9;
} }
// Do movement: // Do movement:
state->clients[index].xPosition += state->clients[index].xVelocity; state->clients[index].xPosition += state->clients[index].xVelocity;
state->clients[index].yPosition += state->clients[index].yVelocity; state->clients[index].yPosition += state->clients[index].yVelocity;

View File

@ -4,6 +4,7 @@
#include <stdbool.h> #include <stdbool.h>
#include <sys/time.h> #include <sys/time.h>
#include <netinet/in.h> #include <netinet/in.h>
struct clientMovement struct clientMovement
{ {
double xPosition, yPosition, xVelocity, yVelocity; double xPosition, yPosition, xVelocity, yVelocity;
@ -30,6 +31,12 @@ struct networkThreadArguments
struct gameState * state; struct gameState * state;
}; };
struct inputHistory
{
uint8_t start, end;
struct clientInput inputs[256];
};
void updateInput(struct gameState * state, struct clientInput * message); void updateInput(struct gameState * state, struct clientInput * message);
void doGameTick(struct gameState * state); void doGameTick(struct gameState * state);