Merge branch 'local-camera-fudge' into 'master'

Turn towards your local camera

See merge request KartKrew/Kart!972
This commit is contained in:
toaster 2023-02-27 01:15:00 +00:00
commit a6d0edc5a0
7 changed files with 112 additions and 118 deletions

View file

@ -359,10 +359,10 @@ struct doomdata_t
UINT8 reserved; // Padding
union
{
clientcmd_pak clientpak; // 145 bytes
client2cmd_pak client2pak; // 202 bytes
client3cmd_pak client3pak; // 258 bytes(?)
client4cmd_pak client4pak; // 316 bytes(?)
clientcmd_pak clientpak; // 147 bytes
client2cmd_pak client2pak; // 206 bytes
client3cmd_pak client3pak; // 264 bytes(?)
client4cmd_pak client4pak; // 324 bytes(?)
servertics_pak serverpak; // 132495 bytes (more around 360, no?)
serverconfig_pak servercfg; // 773 bytes
UINT8 textcmd[MAXTEXTCMD+1]; // 66049 bytes (wut??? 64k??? More like 257 bytes...)

View file

@ -71,6 +71,7 @@ struct ticcmd_t
{
SINT8 forwardmove; // -MAXPLMOVE to MAXPLMOVE (50)
INT16 turning; // Turn speed
INT16 angle; // Predicted angle, use me if you can!
INT16 throwdir; // Aiming direction
INT16 aiming; // vertical aiming, see G_BuildTicCmd
UINT16 buttons;

View file

@ -136,15 +136,16 @@ demoghost *ghosts = NULL;
#define DEMO_BOT 0x08
// For demos
#define ZT_FWD 0x01
#define ZT_SIDE 0x02
#define ZT_TURNING 0x04
#define ZT_THROWDIR 0x08
#define ZT_BUTTONS 0x10
#define ZT_AIMING 0x20
#define ZT_LATENCY 0x40
#define ZT_FLAGS 0x80
// OUT OF ZIPTICS...
#define ZT_FWD 0x0001
#define ZT_SIDE 0x0002
#define ZT_TURNING 0x0004
#define ZT_ANGLE 0x0008
#define ZT_THROWDIR 0x0010
#define ZT_BUTTONS 0x0020
#define ZT_AIMING 0x0040
#define ZT_LATENCY 0x0080
#define ZT_FLAGS 0x0100
// Ziptics are UINT16 now, go nuts
#define DEMOMARKER 0x80 // demobuf.end
@ -530,17 +531,19 @@ void G_WriteDemoExtraData(void)
void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
{
UINT8 ziptic;
UINT16 ziptic;
if (!demobuf.p || !demo.deferstart)
return;
ziptic = READUINT8(demobuf.p);
ziptic = READUINT16(demobuf.p);
if (ziptic & ZT_FWD)
oldcmd[playernum].forwardmove = READSINT8(demobuf.p);
if (ziptic & ZT_TURNING)
oldcmd[playernum].turning = READINT16(demobuf.p);
if (ziptic & ZT_ANGLE)
oldcmd[playernum].angle = READINT16(demobuf.p);
if (ziptic & ZT_THROWDIR)
oldcmd[playernum].throwdir = READINT16(demobuf.p);
if (ziptic & ZT_BUTTONS)
@ -564,13 +567,14 @@ void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
{
char ziptic = 0;
UINT16 ziptic = 0;
UINT8 *ziptic_p;
(void)playernum;
if (!demobuf.p)
return;
ziptic_p = demobuf.p++; // the ziptic, written at the end of this function
ziptic_p = demobuf.p; // the ziptic, written at the end of this function
demobuf.p += 2;
if (cmd->forwardmove != oldcmd[playernum].forwardmove)
{
@ -586,6 +590,13 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
ziptic |= ZT_TURNING;
}
if (cmd->angle != oldcmd[playernum].angle)
{
WRITEINT16(demobuf.p,cmd->angle);
oldcmd[playernum].angle = cmd->angle;
ziptic |= ZT_ANGLE;
}
if (cmd->throwdir != oldcmd[playernum].throwdir)
{
WRITEINT16(demobuf.p,cmd->throwdir);
@ -621,7 +632,7 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum)
ziptic |= ZT_FLAGS;
}
*ziptic_p = ziptic;
WRITEUINT16(ziptic_p, ziptic);
// attention here for the ticcmd size!
// latest demos with mouse aiming byte in ticcmd

View file

@ -1080,80 +1080,32 @@ INT32 localaiming[MAXSPLITSCREENPLAYERS];
angle_t localangle[MAXSPLITSCREENPLAYERS];
INT32 localsteering[MAXSPLITSCREENPLAYERS];
INT32 localdelta[MAXSPLITSCREENPLAYERS];
INT32 localstoredeltas[MAXSPLITSCREENPLAYERS][TICCMD_LATENCYMASK + 1];
UINT8 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
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)
while (realtics > 0)
{
// Otherwise, your angle slingshots off to the side violently...
G_ResetAnglePrediction(player);
localsteering[ssplayer - 1] = K_UpdateSteeringValue(localsteering[ssplayer - 1], cmd->turning);
angleChange = K_GetKartTurnValue(player, localsteering[ssplayer - 1]) << TICCMD_REDUCE;
realtics--;
}
#if 0
// Left here in case it needs unsealing later. This tried to replicate an old localcam function, but this behavior was unpopular in tests.
//if (player->pflags & PF_DRIFTEND)
{
localangle[ssplayer - 1] = player->mo->angle;
}
else
#endif
{
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--;
}
localangle[ssplayer - 1] += angleChange;
}
// 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;
// In case of angle debugging, break glass
// localangle[ssplayer - 1] = destAngle;
}
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
@ -1189,6 +1141,8 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
break;
}
cmd->angle = localangle[forplayer] >> TICCMD_REDUCE;
// why build a ticcmd if we're paused?
// Or, for that matter, if we're being reborn.
if (paused || P_AutoPause() || (gamestate == GS_LEVEL && player->playerstate == PST_REBORN))
@ -1422,6 +1376,7 @@ ticcmd_t *G_MoveTiccmd(ticcmd_t* dest, const ticcmd_t* src, const size_t n)
{
dest[i].forwardmove = src[i].forwardmove;
dest[i].turning = (INT16)SHORT(src[i].turning);
dest[i].angle = (INT16)SHORT(src[i].angle);
dest[i].throwdir = (INT16)SHORT(src[i].throwdir);
dest[i].aiming = (INT16)SHORT(src[i].aiming);
dest[i].buttons = (UINT16)SHORT(src[i].buttons);

View file

@ -101,7 +101,6 @@ extern consvar_t cv_resume;
const char *G_BuildMapName(INT32 map);
INT32 G_MapNumber(const char *mapname);
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
@ -116,10 +115,6 @@ INT16 G_SoftwareClipAimingPitch(INT32 *aiming);
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 locallatency[MAXSPLITSCREENPLAYERS][TICRATE];
extern UINT8 localtic;
INT32 G_PlayerInputAnalog(UINT8 p, INT32 gc, UINT8 menuPlayers);
boolean G_PlayerInputDown(UINT8 p, INT32 gc, UINT8 menuPlayers);

View file

@ -9100,15 +9100,17 @@ void T_Pusher(pusher_t *p)
thing->player->carry = CR_SLIDING;
thing->angle = R_PointToAngle2(0, 0, xspeed, yspeed);
if (!demo.playback)
{
angle_t angle = thing->player->angleturn;
angle_t angle = thing->player->boostangle;
if (thing->angle - angle > ANGLE_180)
P_SetPlayerAngle(thing->player, angle - (angle - thing->angle) / 8);
thing->player->boostangle = angle - (angle - thing->angle) / 8;
else
P_SetPlayerAngle(thing->player, angle + (thing->angle - angle) / 8);
thing->player->boostangle = angle + (thing->angle - angle) / 8;
//P_SetPlayerAngle(thing->player, thing->angle);
}
}
if (p->exclusive)

View file

@ -2120,7 +2120,6 @@ static void P_3dMovement(player_t *player)
static void P_UpdatePlayerAngle(player_t *player)
{
angle_t angleChange = ANGLE_MAX;
UINT8 maxlatency;
UINT8 p = UINT8_MAX;
UINT8 i;
@ -2133,8 +2132,58 @@ static void P_UpdatePlayerAngle(player_t *player)
}
}
player->steering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
angleChange = K_GetKartTurnValue(player, player->steering) << TICCMD_REDUCE;
// Don't apply steering just yet. If we make a correction, we'll need to adjust it.
INT16 targetsteering = K_UpdateSteeringValue(player->steering, player->cmd.turning);
angleChange = K_GetKartTurnValue(player, targetsteering) << TICCMD_REDUCE;
if (!K_PlayerUsesBotMovement(player))
{
// With a full slam on the analog stick, how far could we steer in either direction?
INT16 steeringRight = K_UpdateSteeringValue(player->steering, KART_FULLTURN);
angle_t maxTurnRight = K_GetKartTurnValue(player, steeringRight) << TICCMD_REDUCE;
INT16 steeringLeft = K_UpdateSteeringValue(player->steering, -KART_FULLTURN);
angle_t maxTurnLeft = K_GetKartTurnValue(player, steeringLeft) << TICCMD_REDUCE;
// Grab local camera angle from ticcmd. Where do we actually want to go?
angle_t targetAngle = (player->cmd.angle) << TICCMD_REDUCE;
angle_t targetDelta = targetAngle - (player->mo->angle);
if (targetDelta == angleChange || player->pflags & PF_DRIFTEND || (maxTurnRight == 0 && maxTurnLeft == 0))
{
// We are where we need to be.
// ...Or we aren't, but shouldn't be able to steer.
player->steering = targetsteering;
// Alternatively, while in DRIFTEND we want to trust inputs for a bit, not camera.
// The game client doesn't know we're DRIFTEND until after a response gets back,
// so we momentarily ignore the camera angle and let the server trust our inputs instead.
// That way, even if you're steering blind, you get the intended "kick-out" effect.
}
else if (targetDelta >= ANGLE_180 && maxTurnLeft >= targetDelta) // Overshot, so just fudge it.
{
angleChange = targetDelta;
player->steering = targetsteering;
}
else if (targetDelta <= ANGLE_180 && maxTurnRight <= targetDelta) // Overshot, so just fudge it.
{
angleChange = targetDelta;
player->steering = targetsteering;
}
else if (targetDelta >= ANGLE_180 && maxTurnLeft < targetDelta) // Undershot, slam the stick.
{
angleChange = maxTurnLeft;
player->steering = steeringLeft;
}
else if (targetDelta <= ANGLE_180 && maxTurnRight > targetDelta) // Undershot, slam the stick.
{
angleChange = maxTurnRight;
player->steering = steeringRight;
}
}
else
{
// You're a bot. Go where you're supposed to go
player->steering = targetsteering;
}
if (p == UINT8_MAX)
{
@ -2144,33 +2193,8 @@ static void P_UpdatePlayerAngle(player_t *player)
}
else
{
// During standard play, our latency can vary by up to 1 tic in either direction, even on a stable connection.
// This probably comes from differences in ticcmd dispatch vs consumption rate. Probably.
// Uncorrected, this 2-tic "wobble" causes camera corrections to sometimes be skipped or batched.
// So just use the highest recent value for the furthest possible search.
// We unset the correction after applying, anyway.
locallatency[p][leveltime%TICRATE] = maxlatency = player->cmd.latency;
for (i = 0; i < TICRATE; i++)
{
maxlatency = max(locallatency[p][i], maxlatency);
}
UINT8 lateTic = ((leveltime - maxlatency) & 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)
@ -3162,7 +3186,13 @@ boolean P_MoveChaseCamera(player_t *player, camera_t *thiscam, boolean resetcall
if (demo.playback)
{
focusangle = mo->angle;
// Hack-adjacent.
// Sometimes stale ticcmds send a weird angle at the start of the race.
// P_UpdatePlayerAngle knows to ignore cmd angle when you literally can't turn, so we do the same here.
if (leveltime > introtime)
focusangle = player->cmd.angle << TICCMD_REDUCE;
else
focusangle = mo->angle; // Just use something known sane.
focusaiming = 0;
}
else
@ -4478,7 +4508,7 @@ void P_ForceLocalAngle(player_t *player, angle_t angle)
if (player == &players[displayplayers[i]])
{
localangle[i] = angle;
G_ResetAnglePrediction(player);
break;
}
}