fix(racing): put racers going the wrong way back on the track

The client works out on its own when its racer goes the wrong way and
shows a 6 second countdown, but it only moves the car when the server
sends RacingSetPlayerResetInfo, which DLU never did for this.

The server now follows the reset planes the way the client's
LWORacingControlComponent does (1.10.64): each path waypoint is a plane
facing along its rotation; the racer starts between planes 0 and 1,
moves forward when in front of the upcoming plane and back when behind
the last one (CheckUpcomingResetPlane @ 0x00c7edf0, CheckLastResetPlane @
0x00c7f1a0, CrossResetPlaneBackward @ 0x00cba380). Driving back
through a second plane in a row starts the client's countdown
(UpdateWrongWayCount @ 0x00be5c10, 6 seconds); going forward through a plane ends it. When
it runs out, the racer gets the same reset as an unsmashed reset: reset
info for their furthest point and RacingResetPlayerToLastReset. Resets
sent for smashes keep the planes in step as well.

Fixes issue 764.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-09-27 09:04:31 -05:00
parent c759bd1a40
commit 6febb6d63c
4 changed files with 158 additions and 0 deletions

View File

@@ -99,11 +99,28 @@ struct RacingPlayerInfo {
* Unused
*/
std::chrono::milliseconds raceTime;
/**
* The reset planes (path waypoints) the player is between, and how many planes they have driven back through
* since they last went forward through one, tracked the way the client tracks them
* (LWORacingControlComponent::HandlePlayerAddedToRace @ 00cba0c0 starts them at 0 and 1).
*/
uint32_t lastPlane = 0;
uint32_t upcomingPlane = 1;
uint32_t wrongWayCount = 0;
/**
* Seconds left until a player going the wrong way is put back on the track, negative when not counting down
*/
float wrongWayTime = -1.0f;
};
/**
* Component that's attached to a manager entity in each race zone that loads player vehicles, keep scores, etc.
*/
struct Path;
struct PathWaypoint;
class RacingControlComponent final : public ActivityComponent {
public:
static constexpr eReplicaComponentType ComponentType = eReplicaComponentType::RACING_CONTROL;
@@ -119,6 +136,18 @@ public:
*/
void OnPlayerLoaded(Entity* player);
/**
* Moves the player's reset planes as they drive through them and puts them back on the track when they have been
* going the wrong way for as long as the client counts down.
*/
void UpdateWrongWay(RacingPlayerInfo& player, const Entity& vehicle, const Path& path, float deltaTime);
/**
* Moves the player's reset planes for the car being at position, like the client does each frame, and starts the
* wrong way countdown when they have driven back through a second plane.
*/
static void StepResetPlanes(RacingPlayerInfo& player, const std::vector<PathWaypoint>& waypoints, const NiPoint3& position);
/**
* Initalize the player's vehicle.
*