Added linear interpolation between states

This commit is contained in:
Barra Ó Catháin 2023-08-05 00:42:36 +01:00
parent 5e7bff96d0
commit d2ce7bc506
3 changed files with 40 additions and 38 deletions

View File

@ -20,7 +20,7 @@
#define ENABLE_CLIENT_SIDE_PREDICTION #define ENABLE_CLIENT_SIDE_PREDICTION
#define ENABLE_SERVER_RECONCILLIATION #define ENABLE_SERVER_RECONCILLIATION
uint8_t colours[16][3] = const uint8_t colours[16][3] =
{ {
{255, 255, 255}, {255, 255, 255},
{100, 176, 254}, {100, 176, 254},
@ -117,9 +117,11 @@ void * networkHandler(void * parameters)
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 ||
{ (updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec &&
memcpy(arguments->state, updatedState, sizeof(struct gameState)); updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec))
{
// memcpy(arguments->state, updatedState, sizeof(struct gameState));
#ifdef ENABLE_SERVER_RECONCILLIATION #ifdef ENABLE_SERVER_RECONCILLIATION
// Throw away any already acknowledged inputs: // Throw away any already acknowledged inputs:
while (arguments->inputBuffer->start != -1 && while (arguments->inputBuffer->start != -1 &&
@ -148,46 +150,16 @@ void * networkHandler(void * parameters)
} }
#endif #endif
} }
else if(updatedState->timestamp.tv_sec == arguments->state->timestamp.tv_sec && lerpStates(arguments->state, updatedState);
updatedState->timestamp.tv_usec > arguments->state->timestamp.tv_usec)
{
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
}
} }
} }
void * gameThreadHandler(void * parameters) void * gameThreadHandler(void * parameters)
{ {
struct threadParameters * arguments = parameters; struct threadParameters * arguments = parameters;
#ifdef ENABLE_CLIENT_SIDE_PREDICTION #ifdef ENABLE_CLIENT_SIDE_PREDICTION
struct gameState * nextStep = calloc(1, sizeof(struct gameState));
while (true) while (true)
{ {
updateInput(arguments->state, arguments->message); updateInput(arguments->state, arguments->message);
@ -204,7 +176,9 @@ void * gameThreadHandler(void * parameters)
arguments->inputBuffer->end = (arguments->inputBuffer->end + 1) % 256; arguments->inputBuffer->end = (arguments->inputBuffer->end + 1) % 256;
} }
#endif #endif
doGameTick(arguments->state); memcpy(nextStep, arguments->state, sizeof(struct gameState));
doGameTick(nextStep);
lerpStates(arguments->state, nextStep);
usleep(15625); usleep(15625);
} }
#endif #endif

View File

@ -1,5 +1,10 @@
#include <math.h>
#include <stdio.h> #include <stdio.h>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.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)
@ -11,7 +16,28 @@ void updateInput(struct gameState * state, struct clientInput * message)
state->clients[message->clientNumber].upAcceleration = message->up; state->clients[message->clientNumber].upAcceleration = message->up;
state->clients[message->clientNumber].downAcceleration = message->down; state->clients[message->clientNumber].downAcceleration = message->down;
} }
}
void lerpStates (struct gameState * state, struct gameState * endState)
{
// Create a copy of the initial state for interpolating to the final state:
struct gameState * startState = calloc(1, sizeof(struct gameState));
memcpy(startState, state, sizeof(struct gameState));
for (double progress = 0.0; progress < 1.0; progress += 0.01)
{
for (uint8_t index = 0; index < 16; index++)
{
// Movement:
state->clients[index].xPosition = startState->clients[index].xPosition +
(progress * (endState->clients[index].xPosition - startState->clients[index].xPosition));
state->clients[index].yPosition = startState->clients[index].yPosition +
(progress * (endState->clients[index].yPosition - startState->clients[index].yPosition));
}
usleep(100);
}
free(startState);
memcpy(state, endState, sizeof(struct gameState));
} }
void doGameTick(struct gameState * state) void doGameTick(struct gameState * state)

View File

@ -39,6 +39,8 @@ struct inputHistory
void updateInput(struct gameState * state, struct clientInput * message); void updateInput(struct gameState * state, struct clientInput * message);
void lerpStates (struct gameState * state, struct gameState * endState);
void doGameTick(struct gameState * state); void doGameTick(struct gameState * state);
#endif #endif