From edfd43ce818f2718e96a01ec0c270b6f1b2d648e Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Mon, 3 Jul 2023 16:35:52 -0700 Subject: [PATCH 1/3] Use input steering (not camera steering) on skipped tics --- src/p_user.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index b6750eed8..d6166ec1e 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2380,7 +2380,20 @@ static void P_UpdatePlayerAngle(player_t *player) INT16 targetsteering = K_UpdateSteeringValue(player->steering, player->cmd.turning); angleChange = K_GetKartTurnValue(player, targetsteering) << TICCMD_REDUCE; - if (!K_PlayerUsesBotMovement(player)) + if (K_PlayerUsesBotMovement(player)) + { + // You're a bot. Go where you're supposed to go + player->steering = targetsteering; + } + else if (!(player->cmd.flags & TICCMD_RECEIVED)) + { + // This player missed a tic! This ticcmd is copied from our last received one, + // which means it will include the same angle. If we steer them towards this, + // it's very likely we will input the wrong direction and screw with easing state. + // Instead, assume the player keeps steering in the direction they were steering. + player->steering = targetsteering; + } + else { // With a full slam on the analog stick, how far could we steer in either direction? INT16 steeringRight = K_UpdateSteeringValue(player->steering, KART_FULLTURN); @@ -2431,11 +2444,6 @@ static void P_UpdatePlayerAngle(player_t *player) angleChange = targetDelta; } } - else - { - // You're a bot. Go where you're supposed to go - player->steering = targetsteering; - } if (p == UINT8_MAX) { From fe122291bc99516e585cc83ebf9c6edabb3f7cbc Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 6 Jul 2023 01:37:05 -0700 Subject: [PATCH 2/3] Buffer double-submitted ticcmds --- src/d_clisrv.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index e5dde4921..d5023265f 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -5170,8 +5170,14 @@ static void HandlePacketFromPlayer(SINT8 node) || netbuffer->packettype == PT_NODEKEEPALIVEMIS) break; + // If we already received a ticcmd for this tic, just submit it for the next one. + tic_t faketic = maketic; + + if (!!(netcmds[maketic % BACKUPTICS][netconsole].flags & TICCMD_RECEIVED)) + faketic++; + // Copy ticcmd - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][netconsole], &netbuffer->u.clientpak.cmd, 1); // Check ticcmd for "speed hacks" if (CheckForSpeedHacks((UINT8)netconsole)) @@ -5183,7 +5189,7 @@ static void HandlePacketFromPlayer(SINT8 node) || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) && (nodetoplayer2[node] >= 0)) { - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer2[node]], &netbuffer->u.client2pak.cmd2, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer2[node])) @@ -5194,7 +5200,7 @@ static void HandlePacketFromPlayer(SINT8 node) || (netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS)) && (nodetoplayer3[node] >= 0)) { - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer3[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer3[node]], &netbuffer->u.client3pak.cmd3, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer3[node])) @@ -5204,7 +5210,7 @@ static void HandlePacketFromPlayer(SINT8 node) if ((netbuffer->packettype == PT_CLIENT4CMD || netbuffer->packettype == PT_CLIENT4MIS) && (nodetoplayer4[node] >= 0)) { - G_MoveTiccmd(&netcmds[maketic%BACKUPTICS][(UINT8)nodetoplayer4[node]], + G_MoveTiccmd(&netcmds[faketic%BACKUPTICS][(UINT8)nodetoplayer4[node]], &netbuffer->u.client4pak.cmd4, 1); if (CheckForSpeedHacks((UINT8)nodetoplayer4[node])) From 9ebfc121677a32ba970fd6b4137e8a7694283618 Mon Sep 17 00:00:00 2001 From: AJ Martinez Date: Thu, 6 Jul 2023 16:04:28 -0700 Subject: [PATCH 3/3] Only use ticmiss input-steering if we didn't use it last tic --- src/p_user.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/p_user.c b/src/p_user.c index d6166ec1e..74b5d6231 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -2385,13 +2385,17 @@ static void P_UpdatePlayerAngle(player_t *player) // You're a bot. Go where you're supposed to go player->steering = targetsteering; } - else if (!(player->cmd.flags & TICCMD_RECEIVED)) + else if ((!(player->cmd.flags & TICCMD_RECEIVED)) && (!!(player->oldcmd.flags && TICCMD_RECEIVED))) { - // This player missed a tic! This ticcmd is copied from our last received one, - // which means it will include the same angle. If we steer them towards this, - // it's very likely we will input the wrong direction and screw with easing state. - // Instead, assume the player keeps steering in the direction they were steering. + // Missed a single tic. This ticcmd is copied from their previous one + // (less the TICCMD_RECEIVED flag), so it will include an old angle, and + // steering towards that will turn unambitiously. A better guess is to + // assume their inputs are the same, and turn based on those for 1 tic. player->steering = targetsteering; + // "Why not use this for multiple consecutive dropped tics?" Oversimplification: + // Clients have default netticbuffer 1, so missing more than 1 tic will freeze + // your client, and with it, your local camera. Our goal then becomes not to + // steer PAST the angle you can see, so the default turn solver behavior is best. } else {