mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-02-16 10:36:09 +00:00
Merge branch 'turn-predict' into 'master'
Bring back camera prediction See merge request KartKrew/Kart!592
This commit is contained in:
commit
d7591b0656
6 changed files with 132 additions and 19 deletions
|
|
@ -50,6 +50,9 @@ typedef enum
|
|||
// ticcmd turning bits
|
||||
#define TICCMD_REDUCE 16
|
||||
|
||||
// ticcmd latency mask
|
||||
#define TICCMD_LATENCYMASK 0xFF
|
||||
|
||||
// ticcmd flags
|
||||
#define TICCMD_RECEIVED 1
|
||||
#define TICCMD_TYPING 2/* chat window or console open */
|
||||
|
|
|
|||
80
src/g_game.c
80
src/g_game.c
|
|
@ -871,6 +871,78 @@ static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvect
|
|||
INT32 localaiming[MAXSPLITSCREENPLAYERS];
|
||||
angle_t localangle[MAXSPLITSCREENPLAYERS];
|
||||
|
||||
INT32 localsteering[MAXSPLITSCREENPLAYERS];
|
||||
INT32 localdelta[MAXSPLITSCREENPLAYERS];
|
||||
INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
|
||||
UINT8 localtic;
|
||||
|
||||
void G_ResetAnglePrediction(player_t *player)
|
||||
{
|
||||
UINT16 i, j;
|
||||
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
{
|
||||
if (&players[displayplayers[i]] == player)
|
||||
{
|
||||
localdelta[i] = 0;
|
||||
for (j = 0; j < TICCMD_LATENCYMASK; j++)
|
||||
{
|
||||
localstoredeltas[i][j] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Turning was removed from G_BuildTiccmd to prevent easy client hacking.
|
||||
// This brings back the camera prediction that was lost.
|
||||
static void G_DoAnglePrediction(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer, player_t *player)
|
||||
{
|
||||
angle_t angleChange = 0;
|
||||
angle_t destAngle = player->angleturn;
|
||||
angle_t diff = 0;
|
||||
|
||||
localtic = cmd->latency;
|
||||
|
||||
if (player->pflags & PF_DRIFTEND)
|
||||
{
|
||||
// Otherwise, your angle slingshots off to the side violently...
|
||||
G_ResetAnglePrediction(player);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (realtics > 0)
|
||||
{
|
||||
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
|
||||
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
|
||||
|
||||
// Store the angle we applied to this tic, so we can revert it later.
|
||||
// If we trust the camera to do all of the work, then it can get out of sync fast.
|
||||
localstoredeltas[ssplayer - 1][cmd->latency] += angleChange;
|
||||
localdelta[ssplayer - 1] += angleChange;
|
||||
|
||||
realtics--;
|
||||
}
|
||||
}
|
||||
|
||||
// We COULD set it to destAngle directly...
|
||||
// but this causes incredible jittering when the prediction turns out to be wrong. So we ease into it.
|
||||
// Slight increased camera lag in all scenarios > Mostly lagless camera but with jittering
|
||||
destAngle = player->angleturn + localdelta[ssplayer - 1];
|
||||
diff = destAngle - localangle[ssplayer - 1];
|
||||
|
||||
if (diff > ANGLE_180)
|
||||
{
|
||||
diff = InvAngle(InvAngle(diff) / 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
diff /= 2;
|
||||
}
|
||||
|
||||
localangle[ssplayer - 1] += diff;
|
||||
}
|
||||
|
||||
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
||||
{
|
||||
const UINT8 forplayer = ssplayer-1;
|
||||
|
|
@ -896,8 +968,6 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
boolean *rd = &resetdown[forplayer];
|
||||
const boolean mouseaiming = player->spectator;
|
||||
|
||||
(void)realtics;
|
||||
|
||||
if (demo.playback) return;
|
||||
|
||||
// Is there any reason this can't just be I_BaseTiccmd?
|
||||
|
|
@ -1153,7 +1223,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
|
||||
// Send leveltime when this tic was generated to the server for control lag calculations.
|
||||
// Only do this when in a level. Also do this after the hook, so that it can't overwrite this.
|
||||
cmd->latency = (leveltime & 0xFF);
|
||||
cmd->latency = (leveltime & TICCMD_LATENCYMASK);
|
||||
}
|
||||
|
||||
if (cmd->forwardmove > MAXPLMOVE)
|
||||
|
|
@ -1171,6 +1241,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
|
|||
else if (cmd->throwdir < -KART_FULLTURN)
|
||||
cmd->throwdir = -KART_FULLTURN;
|
||||
|
||||
G_DoAnglePrediction(cmd, realtics, ssplayer, player);
|
||||
|
||||
// Reset away view if a command is given.
|
||||
if ((cmd->forwardmove || cmd->buttons)
|
||||
&& !r_splitscreen && displayplayers[0] != consoleplayer && ssplayer == 1)
|
||||
|
|
@ -1936,7 +2008,7 @@ void G_Ticker(boolean run)
|
|||
else
|
||||
{
|
||||
//@TODO add a cvar to allow setting this max
|
||||
cmd->latency = min(((leveltime & 0xFF) - cmd->latency) & 0xFF, MAXPREDICTTICS-1);
|
||||
cmd->latency = min(((leveltime & TICCMD_LATENCYMASK) - cmd->latency) & TICCMD_LATENCYMASK, MAXPREDICTTICS-1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ extern consvar_t cv_resume;
|
|||
// build an internal map name MAPxx from map number
|
||||
const char *G_BuildMapName(INT32 map);
|
||||
|
||||
void G_ResetAnglePrediction(player_t *player);
|
||||
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer);
|
||||
|
||||
// copy ticcmd_t to and fro the normal way
|
||||
|
|
@ -117,6 +118,10 @@ INT32 PlayerJoyAxis(UINT8 player, axis_input_e axissel);
|
|||
|
||||
extern angle_t localangle[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localaiming[MAXSPLITSCREENPLAYERS]; // should be an angle_t but signed
|
||||
extern INT32 localsteering[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localdelta[MAXSPLITSCREENPLAYERS];
|
||||
extern INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
|
||||
extern UINT8 localtic;
|
||||
|
||||
//
|
||||
// GAME
|
||||
|
|
|
|||
13
src/k_kart.c
13
src/k_kart.c
|
|
@ -8233,31 +8233,34 @@ static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
|
|||
return basedrift + (FixedMul(driftadjust * FRACUNIT, countersteer) / FRACUNIT);
|
||||
}
|
||||
|
||||
void K_UpdateSteeringValue(player_t *player, INT16 destSteering)
|
||||
INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering)
|
||||
{
|
||||
// player->steering is the turning value, but with easing applied.
|
||||
// Keeps micro-turning from old easing, but isn't controller dependent.
|
||||
|
||||
const INT16 amount = KART_FULLTURN/4;
|
||||
INT16 diff = destSteering - player->steering;
|
||||
INT16 diff = destSteering - inputSteering;
|
||||
INT16 outputSteering = inputSteering;
|
||||
|
||||
if (abs(diff) <= amount)
|
||||
{
|
||||
// Reached the intended value, set instantly.
|
||||
player->steering = destSteering;
|
||||
outputSteering = destSteering;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Go linearly towards the value we wanted.
|
||||
if (diff < 0)
|
||||
{
|
||||
player->steering -= amount;
|
||||
outputSteering -= amount;
|
||||
}
|
||||
else
|
||||
{
|
||||
player->steering += amount;
|
||||
outputSteering += amount;
|
||||
}
|
||||
}
|
||||
|
||||
return outputSteering;
|
||||
}
|
||||
|
||||
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source);
|
|||
INT32 K_GetKartRingPower(player_t *player, boolean boosted);
|
||||
void K_UpdateDistanceFromFinishLine(player_t *const player);
|
||||
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y);
|
||||
void K_UpdateSteeringValue(player_t *player, INT16 destSteering);
|
||||
INT16 K_UpdateSteeringValue(INT16 inputSteering, INT16 destSteering);
|
||||
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue);
|
||||
INT32 K_GetUnderwaterTurnAdjust(player_t *player);
|
||||
INT32 K_GetKartDriftSparkValue(player_t *player);
|
||||
|
|
|
|||
48
src/p_user.c
48
src/p_user.c
|
|
@ -2003,13 +2003,46 @@ static void P_3dMovement(player_t *player)
|
|||
static void P_UpdatePlayerAngle(player_t *player)
|
||||
{
|
||||
angle_t angleChange = ANGLE_MAX;
|
||||
UINT8 p = UINT8_MAX;
|
||||
UINT8 i;
|
||||
|
||||
K_UpdateSteeringValue(player, player->cmd.turning);
|
||||
for (i = 0; i <= splitscreen; i++)
|
||||
{
|
||||
if (player == &players[g_localplayers[i]])
|
||||
{
|
||||
p = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
player->steering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
|
||||
angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE;
|
||||
|
||||
P_SetPlayerAngle(player, player->angleturn + angleChange);
|
||||
player->mo->angle = player->angleturn;
|
||||
if (p == UINT8_MAX)
|
||||
{
|
||||
// When F12ing players, set local angle directly.
|
||||
P_SetPlayerAngle(player, player->angleturn + angleChange);
|
||||
player->mo->angle = player->angleturn;
|
||||
}
|
||||
else
|
||||
{
|
||||
UINT8 lateTic = ((leveltime - player->cmd.latency) & TICCMD_LATENCYMASK);
|
||||
UINT8 clearTic = ((localtic + 1) & TICCMD_LATENCYMASK);
|
||||
|
||||
player->angleturn += angleChange;
|
||||
player->mo->angle = player->angleturn;
|
||||
|
||||
// Undo the ticcmd's old emulated angle,
|
||||
// now that we added the actual game logic angle.
|
||||
|
||||
while (lateTic != clearTic)
|
||||
{
|
||||
localdelta[p] -= localstoredeltas[p][lateTic];
|
||||
localstoredeltas[p][lateTic] = 0;
|
||||
|
||||
lateTic = (lateTic - 1) & TICCMD_LATENCYMASK;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cv_allowmlook.value || player->spectator == false)
|
||||
{
|
||||
|
|
@ -2021,13 +2054,9 @@ static void P_UpdatePlayerAngle(player_t *player)
|
|||
player->aiming = G_ClipAimingPitch((INT32 *)&player->aiming);
|
||||
}
|
||||
|
||||
for (i = 0; i <= r_splitscreen; i++)
|
||||
if (p != UINT8_MAX)
|
||||
{
|
||||
if (player == &players[displayplayers[i]])
|
||||
{
|
||||
localaiming[i] = player->aiming;
|
||||
break;
|
||||
}
|
||||
localaiming[p] = player->aiming;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4866,6 +4895,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
|
|||
if (player == &players[displayplayers[i]])
|
||||
{
|
||||
localangle[i] = angle;
|
||||
G_ResetAnglePrediction(player);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue