An NPC is driving toward a destination. The player takes over, drives around a roadblock, stops farther along the road, and hands the car back. That takeover has changed both the vehicle’s position and who is allowed to submit driving commands.
The NPC still needs to reach the original destination, but its old route progress can no longer be used directly. The runtime must read the car’s current position and heading and determine whether it can rejoin a directed road. If it cannot, it retains the destination and waits. If the journey has been cancelled, it must reject attempts to resume the old task.
The previous article, Player Driving, Wheel Forces, and Physics Feedback, explained how inputs pass through the transmission, wheel contacts, and Chaos to produce actual motion. The earlier seat reservation and driver handoff article covered character relationships and command eligibility. This article adds journey management: retaining a destination, replacing a road plan, and separating suspension, failed road admission, cancellation, and arrival. The existing city traffic implementation keeps its own execution flow; this continuation prototype has not been integrated into citywide traffic scheduling.
The current implementation handles journey continuation for one ordinary sedan. Journey state lives in the UE host for the duration of the current session. It does not provide task save/load, transfer across worlds, or reconnection recovery. The clips were recorded in the existing city scene. Each preserves one logical vehicle and one Chaos body internally, but the clips are independent PIE sessions rather than one long-running mission in a shared world.
The player moves the car; the destination stays
Start with a temporary takeover. The NPC drives along its lane, receives a takeover request, and brakes to a stop. The player drives around the orange roadblock, stops again, and hands control back. The car has passed its earlier position, while the blue GOAL remains the same destination.
Video 1 | Continue to the original destination after a temporary takeover, approximately 31.93 seconds. Watch the change in car position before handback and the NPC continuing from that new position. The roadblock remains. The detour uses replayed raw player input; it does not demonstrate autonomous NPC obstacle detection or detour planning.
The car receives the takeover request at roughly 6.1 seconds, brakes, and enters player driving at about 6.7 seconds. After the detour, control returns to the NPC at about 21.4 seconds. The native task reports arrival at about 29.4 seconds, followed by footage of the parked car. These are approximate clip times converted from event records; on-screen captions may differ by a few frames.
In the same run, the upper intent remains Intent=1, while the road plan changes from Plan=1 to Plan=2. The initial plan has seven points; the replacement has three. It is shorter because the car has physically moved farther along the road, not because playback time removed the first half of a route.
After the player leaves the old route, its cursor may still point to a node behind the car. Continuing to chase that point could make the vehicle turn around, reverse course, or cross back toward the previous route. Resetting the car’s position directly would instead interrupt wheel contact and collision state. This implementation retains the destination and queries the roads again from the measured pose.
That determines what suspension must freeze. While the player drives, the NPC road task produces no cruise control, does not advance its cursor, and does not complete itself based on the player reaching some location. The player can follow the old road, leave it, or stop near the goal. The physical body continues to supply actual motion; the decision to resume is made at handback.
Contents
- The player moves the car; the destination stays
- Separate destination, road plan, and driving eligibility
- Stop before takeover; check the road after handback
- Match directed roads from the measured pose
- A connected graph does not guarantee physical access
- A sideways car needs valid entry conditions first
- Route progress must follow the actual body
- Handing control back cannot revive a cancelled task
- Mapping reference mechanisms into UE
- How parameters affect admission, progress, and completion
- What videos, automation, and scene records establish
- AI collaboration retrospective
Continuation within the current session
The journey object is a member of the single-car host. It stores destination, cruise speed, phase, and version numbers during the current session. When the host ends, those states do not automatically transfer to a save file or another world, and the object does not preserve all of a character’s other tasks.
The car is still the same car, and its task is still valid. Only the road plan no longer fits its position. Replanning that route lets the task continue without issuing the destination again.
Separate destination, road plan, and driving eligibility
After handback, the NPC may already be eligible to issue commands but still have no executable route. The implementation gives these facts separate state and update points:
| Information | Current owner | When it changes |
|---|---|---|
| Destination, cruise speed, intent serial | Journey object in the single-car host | Established when a destination request is accepted; retained through suspension and retry; invalidated by cancellation |
| Road entries, lane points, cursor, plan serial | Road plan within the journey object | Replaced when a graph plan is successfully formed; entries cleared when the plan cannot execute |
| Occupants, actual driver, command ownership | Logical characters, logical vehicle, relationship interfaces | Updated during a stopped handoff; eligibility checked again for subsequent commands |
| Position, orientation, linear velocity, contacts | Chaos body | Produced continuously by physical motion and collision, then read back to the logical vehicle |
| Compiled nodes, links, lane information | Road runtime | Used for queries; this work does not regenerate or rewrite the road network |
| Temporary obstacles, captions, camera, takeover timing | Demonstration script | Arranges scene conditions without owning road search or body position |
The destination and road plan live in one C++ object but have different lifetimes. One intent can undergo several plan rebuilds. A failed plan can be discarded while its destination remains valid. Physical state exists independently and does not return to an old position when the route is rebuilt.
Intent and plan serials identify different changes
IntentSerial increases when a new valid destination request is accepted. Temporary takeover, handback, and retry do not create a new intent. PlanSerial increases when a new graph plan is accepted. Even if the later physical admission check rejects that plan, the plan version has already changed. Cursor describes progress inside the current plan and is reset to that plan’s starting progress when the plan is rebuilt.
Thus, Intent=1 / Plan=3 can describe one destination after several road-plan rebuilds; it does not mean a third gameplay task. Two clips reporting Plan=2 do not share a route either. Version numbers are meaningful only within their respective runtime instances.
An intent serial records an accepted task request; matching destination coordinates do not make two requests the same. Every accepted Start increases IntentSerial, even when the new coordinates equal the previous ones. Retry explicitly retains the original intent. Callers should choose between retrying an existing task and issuing a new one based on gameplay meaning, not solely on whether the target coordinates changed.
These serials currently record changes to intents and plans. They are not general network-session tokens. Rejection of the old driver’s commands depends on vehicle relationships and the command-acceptance interface; the journey serial alone does not solve every authority problem.
Point-target control and a journey cannot issue commands together
The host could already drive an NPC toward a point. The new journey does not introduce another transmission or wheel-force model. It passes a road look-ahead target to the existing target controller, then follows the same command-acceptance and physics path.
Point-target control and a road journey cannot act as concurrent NPC command producers. Accepting a new journey disables the existing point target. Cancelling a journey also disables that entry point, preventing an old point target from taking over after the journey becomes invalid. This leaves one clear source of NPC commands on each step.
There is no project-wide central task arbitrator here. The current exclusion policy covers the producers already present in this single-car entry point. Additional sources must still pass the relationship and command checks.
Stop before takeover; check the road after handback
A takeover request first changes the road task’s phase. RequestRoadJourneyTakeover() can enter StoppingForPlayer only while the task is joining a road or driving its plan. Cruise output stops, and physical braking slows the car. The request does not immediately exchange drivers.
Once the car has stopped, the driving-mode switch can be called. The host must be ready, have no submitted physics frame awaiting readback, and have an actual velocity magnitude no greater than 0.3 m/s. Using the full magnitude avoids allowing a handoff merely because forward speed is small while the car still has substantial sideways or vertical motion.
Seat exchange reuses the previous article’s relationship interfaces: remove the old seat relationships, assign the driver and passenger seats, update the actual driver, and reset player-input interpretation and NPC steering history. The gear, wheel state, and Chaos body remain. Normal exchanges have been validated, but intermediate failures do not have a complete rollback covering every partial write. This is not an atomic exchange guaranteed to recover losslessly from arbitrary failure.
When the player takes control, a valid, unfinished journey enters SuspendedForPlayer. On handback, the host first exchanges driver relationships and then attempts to rebuild the road plan from the measured pose. A successful driver handoff can therefore be followed by failed road admission.
What does a successful return value mean?
StartRoadJourney() returning true means a new destination request was accepted. The host first checks NPC mode, readiness, physics readback, and low speed. The journey object then validates the target, cruise speed, and pose. An accepted request updates destination and intent serial before attempting road admission. If admission later fails, that accepted intent remains.
For a call that actually switches from player driving to NPC driving, SetPlayerDriving(false) returning true means the driver handoff completed. The internal road-rebuild result does not replace that return value. The caller must also read the journey phase and failure reason.
The interface also has a same-mode success branch. After the readiness, readback, and low-speed checks, it returns true immediately if the requested mode is already active. It exchanges no characters and does not rejoin the road. Consequently, setting NPC mode again while the NPC is in WaitingForRoad cannot replace Retry. Success must be interpreted alongside the mode before and after the call, rather than treated as another completed road-recovery attempt.
RetryRoadJourney() asks whether the existing intent can now be rebuilt and pass the admission check. It requires NPC mode, readiness, no unread submission, and a strict speed condition of <0.3 m/s. Lower-level Resume and the driving-mode switch reject speeds >0.3 m/s, so the interfaces differ exactly at the threshold.
| Call | What a successful return establishes | What still needs checking |
|---|---|---|
| Start a journey | A new destination intent was accepted | Whether a plan formed and passed the short admission check |
| Request player takeover | The task accepted a request to stop first | Whether the car actually stopped and the driver exchange completed |
| Request NPC driving mode | The requested mode is satisfied; relationships are transferred only when a mode change actually occurs | Whether a switch occurred and what happened to road admission; a same-mode call does not retry |
| Retry the existing journey | This resume attempt and short admission check passed | Subsequent driving, route validity, and actual arrival |
The caller needs to know which step succeeded. A single success misses the situation shown in the waiting scene: the NPC is already the driver, but road admission has not passed, so the car must stay stopped.
How the upper layer handles handback results
After requesting handback, the upper layer must keep reading state to determine whether driving has resumed. A takeover request only starts braking. Scene logic then waits for measured low speed before attempting the exchange. At handback, the caller checks whether the mode request succeeded and reads the journey report. If relationship writes fail partway through, it must inspect the relationships and host fault rather than assume both sides retain the complete old state. After a normal successful exchange, road admission determines the next action.
After this host has actually completed handback and its road-resume call, a new JoiningRoad report means the graph plan was accepted and the short admission check passed. The measured body still needs to align with the lane. Reading JoiningRoad immediately after lower-level Resume alone establishes only that a graph plan formed; the host performs its physical sweep afterward. A WaitingForRoad report retains task context and passes the reason to whichever layer decides how conditions should be restored. In the second clip, the script removes a barrier and calls Retry. In the third, the player adjusts the physical pose and hands control back. These are explicit choices in the current scenes, not fallback tasks generated automatically inside the journey object.
The upper layer therefore distinguishes a takeover request, a driver handoff, road recovery, and arrival. The demonstration organizes these through script state; it does not implement a general event-subscription or gameplay-scheduling framework. The script also triggers takeover based on measured position. That must not be recast as the NPC seeing a roadblock and deciding to ask the player for help.
The previous driver’s request must actually be rejected
After each driver change, the validation script submits a full-throttle candidate using the previous driver. It checks that the request is rejected and that neither the current source tag nor ownership serial is overwritten. The checks use the actual rejection result and identity fields. The on-screen PLAYER or NPC label only indicates the current mode.
A car remaining still would not prove that old authority was revoked. The old request might simply not have executed, or braking might have overridden it later. Checking rejection together with command identity establishes that the relationship layer blocks the now-ineligible source. These checks do not simulate out-of-order networking or late packets.
Match directed roads from the measured pose
At handback, Resume reads the body’s actual position, forward direction, and velocity. It does not substitute the old plan’s start for the car’s position or read a prerecorded trajectory from the demonstration script. Queries use the existing compiled roads: nodes, directed links, and lane offsets.
The road entry point is read-only. The journey query now has access to compiled roads without regenerating the network, changing road art, or making UE NavMesh the authority for vehicle roads.
Find a lane segment the vehicle can join
Candidate collection first excludes unsuitable nodes marked as non-navigable, switched off, water, or off-road. Links must permit travel toward the other node, provide lanes in that direction, and not prohibit navigation. The query constructs lane segments for each remaining directed link using its lane offsets.
Let the lane endpoints be A and B, and the actual vehicle position be P. Positions below have been converted to centimeters; XY denotes horizontal components:
D = B − A
alpha = clamp(dot(Pxy − Axy, Dxy) / dot(Dxy, Dxy), 0, 1)
Q = A + alpha × D
lateralSquared = lengthSquaredXY(P − Q)
alignment = dot(normalizeXY(bodyForward), normalizeXY(D))
Q is the projection onto the candidate lane. The projection parameter is clamped to [0,1], and height is interpolated from the lane endpoints. Roads are not flattened onto a world-horizontal plane. A horizontally nearby road on a different elevation still has to pass the separate height check.
The current policy requires horizontal distance no greater than 8 m, height difference no greater than 2.5 m, and forward alignment of at least 0.5. A dot product of 0.5 corresponds to a horizontal angle of 60°, filtering candidates that disagree substantially with the direction of travel. It is a project admission threshold, not a guarantee that the car can instantly make a 60° turn.
Candidates with alpha>0.98 are also rejected to avoid unsuitable entry near a segment’s end. This is not complete junction planning. Although projection itself clamps to an endpoint, admission still depends on distance, direction, height, and the segment-end condition together.
Candidate score is not total route cost
Candidates that pass filtering are sorted by this project score:
score = lateralSquared + (1 − alignment) × 40000
lateralSquared is in square centimeters, so 40000 must be interpreted at that same position scale. The alignment term affects ordering at this scale; changing the distance calculation to meters requires converting its weight accordingly.
For example, candidate A is 2 m away and fully aligned, giving 40000. Candidate B is 1 m away with alignment 0.5, giving 10000+20000=30000. The current rule tries B first. That is query priority, not proof that B gives a shorter complete driving route or a collision-free joining arc.
Score ties are broken using the source node’s combined address, without comparing every lane and link field. Tied candidates therefore have no guaranteed fixed lane order.
At most 24 candidates are tried after sorting. This limits subsequent road-search attempts, not the entire query to twenty-four links. Candidate collection still traverses nodes and links in the topology. A bounded number of search attempts is not a fixed query cost independent of network size.
Carry the entry direction into route search
For a candidate directed link From→To, search starts at To and heads toward the destination node, with From supplied as the previous node. This preserves the direction of entry at the search boundary. Once the remaining path is found, the candidate’s starting node and link are prepended, and road entries are built using the measured starting position and candidate lane.
The destination node is matched separately. The implementation searches usable nodes around the target, choosing a closer node with horizontal distance strictly below 30 m and height difference strictly below 2.5 m. That node is for graph search. Final completion still checks the original destination coordinates; reaching a nearby road node alone is not arrival at the requested goal.
Collection is capped at 256 road entries. There must be at least two, and the last must be the destination node. A candidate that reaches the collection cap without reaching the destination is not accepted as complete merely because it produced some route points.
Candidates are tried in local-score order, and the first graph plan meeting the construction conditions is accepted. Total journey costs are not compared across every candidate. This does not establish a globally shortest or optimal re-entry plan.
Local construction does not make Resume reversible
Candidate search builds a route, entries, and lane points locally before replacing the current plan. That avoids writing a half-built candidate incrementally into the active arrays. Local construction protects candidate writes, but does not give the whole Resume operation transactional rollback.
If every candidate fails, waiting logic clears the old entries and lane points. Execution does not fall back to the old plan. After player takeover, those entries may still be structurally complete but refer to a different car position; continuing them would defeat rebuilding from measured state.
Resume can also reject before querying roads when there is no valid intent, the journey is complete, the pose is invalid, or speed is too high. These upfront refusals do not all run the same cleanup. Callers must consider the prior phase rather than interpret every false return as an emptied plan and entry into waiting.
A connected graph does not guarantee physical access
The second clip retains the complete takeover and detour, but adds a transverse barrier before handback. It blocks the short corridor between the car’s position and its original lane. The NPC can regain driving authority and graph search can form a plan, yet the car must wait.
Video 2 | A blocked road-admission corridor, followed by clearance and continuation, approximately 34.40 seconds. After handback, the NPC is eligible to drive but the car does not immediately move toward the lane. The removed object is the added joining barrier. The roadblock passed during the original detour remains.
In the same-run events, handback around 21.4 seconds forms Plan=2, followed by WaitingForRoad / JoinObstructed. The barrier is removed around 23.5 seconds; explicit retry at about 23.9 seconds produces Plan=3. The car arrives at the original destination around 31.8 seconds. The intent serial remains 1 throughout.
Accept the graph plan, then check the physical corridor
Only after the query obtains a constructible node and lane sequence does it replace Entries and LanePoints, reset Cursor to 1, record the joining projection and direction, and increment the plan serial. The host then sweeps the scene along the short corridor from the actual car position to that projection.
The sweep uses 95% of the body’s box extents and retains the body’s current quaternion orientation. Its endpoint is 85 cm above the joining point, matching this host’s body-placement convention. It queries the scene’s Visibility channel and ignores the host itself. The box does not rotate through a future turning arc, and the query does not cover the whole remaining route.
If the sweep hits an obstruction, the host rejects admission, enters waiting, and clears the road entries and lane points. PlanSerial does not roll back: the graph plan really was accepted. This explains why the second clip can report plan serial 2 while the number of executable points has returned to zero.
Recording these steps separately locates the failure: the graph connects, but the physical corridor between the car and the route is blocked. Conversely, passing the sweep does not prove a clear journey ahead. The route may later become invalid, another vehicle may enter, or actual motion may leave the allowed corridor.
What waiting preserves and what it stops
WaitingForRoad retains destination, cruise speed, and intent serial, but clears plan entries and lane points and resets the cursor. It produces no cruise look-ahead target. The NPC command branch applies braking, and while an intent exists with measured speed below 0.25 m/s, the host also requests the handbrake.
While waiting, the body remains in the physics simulation and braking holds the car stopped. In the second clip, the pre-clearance wait is roughly two seconds. Including the short delay for the scene to update after clearance, the recorded waiting interval is about 2.4 s.
A fixed countdown does not substitute for restored conditions. The demonstration script explicitly removes the barrier and then requests retry. If the barrier remained after two seconds, elapsed time alone would not make the corridor usable.
Rejection concerns one short corridor
The chosen joining corridor was rejected; other possible entry locations were not checked. The implementation selects an admission candidate and waits when its short corridor is blocked. It does not invoke a complete fallback chain, resample turning curves at other joining positions, or coordinate neighboring-vehicle occupancy and junction rights.
The clearance-and-retry scene checks whether the original intent survives one admission failure and continues after conditions recover. Automatically selecting another entry position and autonomous recovery remain future work.
A sideways car needs valid entry conditions first
The third clip moves failure earlier, before a graph plan is formed. The player turns the car nearly across the road, to a heading of about −83°, stops, and hands it back. Roads are nearby, but the heading does not satisfy the current forward-entry policy.
Video 3 | Failed admission while sideways, followed by player-driven reversing and continuation, approximately 45.20 seconds. Neither the first handback nor the next retry makes the NPC depart. The player takes over again, physically reverses to correct the pose, and hands back once more. The footage is not played backward, and the body is not moved or rotated directly into a valid pose.
After the first handback at about 13.6 seconds, the report is WaitingForRoad / NoJoin. Retry still fails at about 15.7 seconds, after which the player takes control again. Reversing continues until roughly 21 seconds; valid-heading handback at about 21.8 seconds finally creates Plan=2. An event for displaying arrival is recorded around 42.6 seconds. It also waits for speed below 0.05 m/s, so it is not the instant the task first enters Completed.
The failure reason determines what must change
In the second clip, JoinObstructed means a graph plan formed but its chosen short entry corridor was blocked by a scene object. In the third, NoJoin means no candidate passed the current admission conditions, so no new graph plan formed. Both enter waiting, but the recovery conditions differ.
| Condition | Blocked-corridor clip | Sideways-car clip |
|---|---|---|
| Nearby roads | Present | Present |
| Valid graph plan | Formed, then its short corridor is blocked | No valid admission candidate at the current heading |
| Failure reason | JoinObstructed |
NoJoin |
| Plan serial after failure | Already increased to 2 |
Still 1 |
| Demonstrated recovery | Remove the entry barrier and explicitly retry | Player physically reverses to adjust the pose, then hands back |
| Upper intent | Original destination retained | Original destination retained |
With the sideways condition unchanged, another query still finds no candidate and does not increment the plan serial. The records retain that failed retry before the player restores heading and completes a successful handback.
The player restores conditions; the journey rebuilds the plan
In the third clip, the player changes the body’s actual position and heading. The journey object does not correct the physical pose directly. Once the player takes over again, raw reverse input, steering, transmission, and wheel forces remain responsible for moving the car into a better admission pose.
The upper destination and intent serial remain unchanged at 1. Handback matches roads again, builds a new six-point plan, and passes it to NPC target control. Player actions change the body pose, the stopped handoff transfers driving eligibility, and the journey object rebuilds the plan. Each step checks its own conditions before passing its result to the next.
The car remains near the road in this clip. It demonstrates an incompatible heading, not return from an arbitrary off-road location. NavMesh, straight-line driving, and wandering fallback schemes are outside this prototype.
Route progress must follow the actual body
A plan specifies where to go next, not where the car already is. Each journey evaluation reads actual pose and velocity, then outputs a target position and desired speed. The existing target controller produces throttle, brake, and steering, followed by eligibility checks, wheel forces, and Chaos.
Advance the cursor by measured approach or passage
For the current target node B, the implementation allows advancement in two cases: actual horizontal distance is below 1.8 m; or the car has passed the point longitudinally and remains within 5 m horizontally. The second condition prevents a car that passes a node between samples from continually turning back toward it.
passed = dot(actualPosition − B, normalizeXY(B − A)) >= 0
advance = distanceXY(actualPosition, B) < 1.8 m
or (passed and distanceXY(actualPosition, B) < 5 m)
One evaluation can advance at most thirty-two times without going beyond the final segment. It does not integrate cruise speed over time into virtual distance. Repeated evaluations at the same stationary pose do not create progress merely because the task has been running longer.
Passage uses the horizontal segment direction, while distance remains an independent condition. passed=true alone cannot make a car far from the road skip all subsequent nodes. Before producing a target for the current segment, the code also checks that the nodes, link, link destination, and lane index remain usable.
Invalid nodes or links produce RouteUnavailable. Horizontal distance above 12 m from the current segment projection, or a height difference above 2.5 m, produces LeftRoute. These describe different failures: lost plan dependencies versus an actual body outside its allowed corridor. LeftRoute is implemented, but this delivery has no separate dedicated driving video or targeted test record for it.
Look-ahead follows measured progress
After projecting the actual car position onto the current road segment, the code chooses a target ahead on that segment. Look-ahead uses current horizontal speed and produces centimeters:
lookAheadCm = clamp(400 + speedXY_mps × 120, 500, 1000)
targetAlong = min(segmentLengthCm, projectedAlongCm + lookAheadCm)
At a measured horizontal speed of 3 m/s, the result is 760 cm, or 7.6 m. Near rest, the lower bound is 5 m; the upper bound is 10 m. Configuring the video’s cruise target to 3 m/s does not make measured speed equal to 3 on every step, so look-ahead still changes with actual motion. It selects a control target, not a per-step displacement budget or arrival tolerance.
The target is clamped to the current segment. The next segment and its lane relationships take over after the cursor advances. Changing a route point still requires actual steering and wheel forces to move the car; the plan does not update body position directly along a spline.
From joining the road to driving along it
JoiningRoad does not mean that the vehicle is already aligned with its lane. The journey enters Driving only when lateral error is strictly below 0.75 m and the horizontal dot product between heading and current segment direction is strictly above 0.85. Both depend on the measured body.
The joining point recorded at graph-plan acceptance primarily supports the short-corridor check. Subsequent control targets continue to use the current segment and actual position, rather than interpolating the body directly to that recorded joining point. Entering Driving does not remove route-validity checks.
Arrival requires the original goal and measured low speed
The final segment reduces desired speed with distance to the original destination:
desiredSpeedMps = min(cruiseSpeedMps,
max(0, (distanceXY_to_destination_m − 0.8) × 0.8))
Within 12 m of the final road node, the target changes to the original destination. Completion requires the final plan segment, actual horizontal distance strictly below 1.8 m, height difference strictly below 2.5 m, and actual velocity magnitude strictly below 0.2 m/s. Passing through the goal coordinates too fast cannot complete the task.
After completion, the host stops cruise output and maintains braking. In the third and fourth clips, the arrival caption also waits for measured speed below 0.05 m/s, followed by roughly 2.5 s of parked footage. That stricter display condition does not change the native Completed threshold. Caption appearance must not be treated as the exact frame of kernel completion.
These distances and speeds serve the current continuation prototype. Without complete checks for precise parking pose, space detection, and path planning, stopping near the blue box does not establish production-quality precision parking.
Handing control back cannot revive a cancelled task
Suspension keeps the intent valid while preventing the road task from executing. Cancellation invalidates the intent. The fourth clip makes the distinction visible with different destinations: the original journey goes to A, the player takes over and cancels A, then hands control back. The car stays stopped until it receives a new destination B.
Video 4 | Cancel the old journey and execute a new destination, approximately 31.53 seconds. Watch the rejected retry and the car departing only after a new request arrives. It stops at B, while A’s target box remains empty farther ahead. This is not suspension and resumption of the original task.
The original target is cancelled around 7.5 seconds, control returns to the NPC around 8.5 seconds, retry of the old task is actually called and rejected around 10.6 seconds, and B is accepted around 12.1 seconds. An arrival event is written around 29 seconds, after the task is complete and speed meets the caption condition, followed by parked footage. That timestamp is not the first instant of kernel completion.
A and B use centimeter coordinates, approximately (11435.29, −1500, 0) and (10258.82, −1500, 0). They are about 11.76 m apart, with B before A. Distinct targets make the new task observable, rather than merely changing a report serial while following the same route to the same position.
Cancellation need not erase every diagnostic value
Cancel sets Cancelled, clears the failure reason, road entries, and lane points, and resets the cursor. The destination and old intent serial can remain in the report. They describe the previous task without authorizing it to continue.
HasIntent() returns false for Inactive and Cancelled, preventing the resume entry point from reviving a cancelled task through retry. A zero versus nonzero target coordinate is not a test for task existence, and a readable old target does not mean the task is still running in the background.
The interface name needs care: Completed still makes HasIntent() return true, but Suspend and Resume separately reject the completed phase, and Evaluate no longer produces cruise output. An intent record existing is therefore different from being resumable or executable. After reading HasIntent=true, the caller must also check the phase to determine whether the task can still execute.
This also affects the old point-target interface. It uses HasIntent() to reject targets that coexist with a journey, so a completed journey still cannot be directly overwritten with a point target. A new valid destination can start another journey. Explicit cancellation is required to release the journey’s exclusion of point-target control. Arrival does not automatically return to Inactive and restore every previous control source.
A new destination goes through a new acceptance step
Retry after cancellation creates no new intent. Successfully accepting B through Start increments the intent serial to 2, then forms Plan=2. The fourth clip’s final Intent=2 / Plan=2 differs from the third clip’s Intent=1 / Plan=2: the former changes the gameplay goal; the latter rebuilds the road plan for an unchanged goal.
Parameters are validated before the new target is written or the intent serial increments. An invalid target, non-finite cruise speed, out-of-range speed, or invalid pose cannot first replace the destination and then fail. Automation also checks that an invalid replacement does not increment the intent serial. These checks reject invalid new requests before writes. If an accepted new request later fails road admission, its new intent remains in waiting rather than reverting to the previous destination. Upfront rejection and failure after acceptance are separate paths.
Check waiting against physical results
Over the fourth clip’s approximately 4.57 s cancellation interval, the displacement between the body’s recorded endpoints is about 0.0515 cm. This records how well the car stayed stopped after cancellation in this scene. It compares only the interval endpoints, not cumulative distance traveled, and cannot predict drift under other slopes, collisions, or tire conditions.
The behavioral sequence matters more: retry of the old task really fails, and driving resumes only after a new target is accepted. Footage, return values, and events establish cancellation together. A nearly stationary image alone cannot prove that the old intent is invalid.
Mapping reference mechanisms into UE
This implementation draws on mechanisms from vehicle tasks in an established open-world engine. Upper destinations and lower driving tasks hold state separately. When a lower route needs rebuilding, it is matched again from the current vehicle state rather than requiring the body to return to the task’s old starting point.
In the reference source, the task base can propagate a soft-reset request to a lower vehicle subtask. A long-range destination task returns to its target-finding phase on reset. Road cruising reorganizes route queries using position, direction, velocity, and target. The node-list joining entry clears old nodes and lanes, then matches a directed node pair, link, and lane from the current position and orientation.
Those code paths support the separation of target and route responsibilities and the use of actual state for admission. They do not establish that every NPC task automatically persists forever after player takeover. Nor is a soft reset identical to this project’s explicit Journey interfaces.
Preserve responsibilities without assuming identical coordinates or interfaces
The reference road-search helper stores a start position, target, starting orientation, velocity, search flags, and an optional preferred target route. A new search resets its internal search state, then works through finding starting roads and the remaining path. Some vehicle tasks can also choose NavMesh, straight-line, or wandering branches instead of immediately searching the road graph.
This prototype does not reproduce that complete search state machine. It obtains compiled roads from the host, collects candidates, and attempts graph searches within one Resume call, then waits for explicit external retry on failure. The reference vehicle task can use a following reference point near the front of the vehicle as its search origin. This adapter uses the physical body component’s actual position. Both query from actual vehicle state, but their sampled positions are not numerically identical.
That difference also explains the separate short-corridor sweep. A lane projection found in the graph solves road matching; UE scene queries must still check the space between the body origin and the lane. This is the current bridging policy, not a claim that every reference road-entry path uses the same box sweep.
Preserve responsibilities without copying the entire task system
| Layer | Current mapping | Scope to retain |
|---|---|---|
| Reference mechanisms | Separate upper goal, lower route, directed admission, and measured arrival | Not every task type or fallback entry branch is reconstructed |
| UE-native implementation | C++ state objects, FVector, arrays, read-only world road entry |
Queries retain the existing compiled vehicle-road network |
| Physics and scene services | Chaos body, contacts, box sweeps, post-physics pose readback | Scene services do not own destination validity or task versions |
| Project policy | Single-car host owns a journey; explicit suspension and handback; finite candidate selection | Distances, directions, capacities, and retry behavior belong to this adapter |
| Demonstration orchestration | Request stopping, replay raw input, add/remove a temporary barrier, show markers | Script requests are not autonomous NPC decisions |
The code is split among the journey object, vehicle host, and existing road runtime. The journey owns intent and plan, the host coordinates driving modes and physics phases, and the road runtime supplies queries. Those responsibilities are connected, but the complete character intelligence tree has not been migrated.
Route output reaches the same physical car
During physics submission, the host reads body pose and metric velocity. Player mode reads raw input. In NPC mode, an existing journey is evaluated for the current target and desired speed. The existing target controller then uses actual orientation, speed, and previous steering to produce a vehicle command.
After the logical vehicle’s driver-acceptance interface accepts the command, the host also checks consistency between the actual driver and ownership. It then passes the command to the existing ordinary-car executor for transmission, contacts, and wheel-force preparation. The previous article’s implementation continues to handle wheel forces and body collision. Journey does not introduce a second vehicle physics model.
Post-physics code reads actual pose and velocity from that same body, publishes them to the same logical vehicle, and updates character and wheel presentation. The next road evaluation again reads measured results. This permits replacing a road plan without destroying and recreating the car.
If road evaluation stops supplying cruise targets because the journey is waiting, suspended, or completed, the NPC branch applies braking. Host faults such as lost driving eligibility or invalid kernel input follow separate fault handling. Gameplay waiting is not a host fault, and not all failures mean stop and automatically retry.
The host’s cleanup policy covers the designated tags for player driving, point-target driving, and road journeys, then uses neutral fallback while continuing support forces and readback. It still compares source tags rather than complete task-session identity. Journey versions do not automatically turn it into a general late-cleanup protocol.
End the host together with the relationships it owns
Keeping a journey during the session does not leave it waiting after its host is destroyed. EndPlay first removes the physics callback, clears readiness, disables simulation, and destroys the auxiliary camera. It then cancels the journey, handles road registration, removes character seat relationships, and closes native entity bindings. Subsequent physics callbacks cannot continue referring to the ended vehicle relationships.
Road data also needs registration ownership. At startup, a host uses the required region if it is already loaded. Only if the host actually registers it does it record ownership of that registration and unregister it on shutdown. Using a road network does not authorize unconditional unloading of roads loaded by another entry point.
This cleanup is different from temporary player takeover. Takeover preserves host, body, and intent; ending the host closes the whole instance. Moving the journey into a longer-lived character task would require explicit ownership of that lifetime. A member of the current host does not establish save/load or cross-scene migration.
How parameters affect admission, progress, and completion
Parameters enter candidate filtering, plan construction, physical admission, measured progress, and completion. The table gathers each stage’s comparison operators and units for reference alongside the implementation above.
| Parameter or check | Current value and comparison | Where it is used |
|---|---|---|
| Cruise-speed input | 0 < speed <= 8 m/s; clips use 3 m/s |
New journey acceptance |
| Stopped handoff and lower Resume | Actual velocity magnitude <=0.3 m/s |
Low-speed handoff and resume checks |
| Explicit host retry | Actual velocity magnitude <0.3 m/s |
Additional Retry entry condition |
| Horizontal distance to candidate lane | <=8 m |
Directed admission filtering |
| Candidate lane height difference | <=2.5 m |
Reject unsuitable elevations |
| Candidate heading and segment-end projection | Dot product >=0.5, alpha<=0.98 |
Entry direction and segment-end policy |
| Destination-node match | XY distance <30 m, height difference <2.5 m |
Graph-search destination selection |
| Candidate attempts and entry capacity | At most 24 candidates, collection cap 256 entries |
Search and plan construction |
| Enter road driving | Lateral error <0.75 m, heading dot product >0.85 |
JoiningRoad→Driving |
| Measured departure from corridor | Lateral error >12 m or height difference >2.5 m |
LeftRoute |
| Native completion | Final segment, XY distance <1.8 m, height difference <2.5 m, speed <0.2 m/s |
Completed |
Presentation interfaces and the body use centimeters; compiled road-core nodes use meters. Lane geometry is converted to centimeters, while the measured starting point passed to road construction is converted back to meters. Velocity uses meters per second. Squared distances in candidate scoring, centimeters in look-ahead, and meter-based completion thresholds each require the appropriate boundary conversions. Conversions need to follow the units expected by each consuming interface.
One waiting phase retains distinct failure reasons
| Failure reason | Meaning in this implementation | Available evidence |
|---|---|---|
NoLoadedRoad |
Native road queries have no navigable nodes | Empty-network automation; the host can return false earlier if it cannot obtain the road entry point |
NoJoin |
No admissible entry candidate at the current pose and heading | Direction, distance, and height automation; video 3 demonstrates incompatible heading |
NoDirectedRoute |
Destination-node matching fails or the limited candidate set cannot form a complete directed plan | Disconnected-graph automation; not an exhaustive search of every citywide alternative |
RouteUnavailable |
Required current nodes, links, lanes, or plan state are unavailable | Automation covering road-region unload |
LeftRoute |
The measured body leaves the current segment’s allowed corridor | Implemented; no dedicated driving-video or targeted-test coverage claim |
JoinObstructed |
A sweep hits an obstacle in the chosen short joining corridor | The physical scene in video 2 |
Before retrying, the caller needs to check whether the condition behind the failure has changed. A cancelled task cannot resume, and a car still parked sideways may fail again. Waiting retains the task; obstacles, heading, and road loading must be handled externally.
Lower Resume can also reject an invalid pose, excessive speed, missing intent, or completed state before setting a new road-failure reason. The host may reject earlier if it cannot obtain the road entry point. Diagnosis needs the entry point, return value, phase, and failure reason together; not every false means NoJoin.
What videos, automation, and scene records establish
The recorded delivery includes a successful build and 220 related Runtime regression passes, with zero failures or unrun tests. Those already include the three journey mechanism tests. When the third and fourth clips were added, native code and DLL remained unchanged. The three journey tests were rerun and new scene checks were added; the full set of two hundred and twenty was not rerun. Rerunning those three tests does not add three distinct tests to the total.
The mechanism tests cover intent lifecycle, road admission, and measured progress. Lifecycle checks include no progress during suspension, no completion credited to NPC driving when the player reaches the goal, rejection of moving Resume, rebuilding from a new pose, cancellation that cannot resume, and invalid replacement that does not increment the serial. Admission checks cover direction, height, off-road positions, disconnected graphs, and missing roads. Progress checks cover no invented movement while stationary, advancement after passing a node, no high-speed completion, stopped arrival, and invalidation when roads unload.
The tests check branches that are difficult to distinguish in footage. Scene records check integration with physics, including vehicle identity within a clip, submission/readback correspondence, agreement between logical and physical position, no host Fault, no body collisions, and an unchanged cursor within each continuous suspended interval.
What the footage shows and the records add
| Clip | Continuous footage | Same-run records add | Conclusions it does not establish |
|---|---|---|---|
| Continuation after takeover | Player detour, stopped handback, NPC reaches the old goal | Retained intent, seven-point plan replaced by three points, old-driver commands rejected | Automatic permanent preservation of arbitrary character tasks or autonomous NPC avoidance |
| Retry after a blocked join | NPC waits after handback and continues after barrier removal | Graph plan formed before sweep rejection, then another plan accepted | Exhaustive citywide alternatives or complete autonomous recovery |
| Recovery from a sideways pose | No departure on two attempts; player reverses and the NPC resumes | NoJoin, no plan increment on failed retry, unchanged intent |
Automatic return from arbitrary off-road positions |
| New task after cancellation | Car stays stopped after handback, then departs for B on acceptance | Old retry rejected, cancellation endpoint drift, new intent serial | Complete taxi, ambulance, or network-cancellation protocols |
Old-driver rejection, plan serials, and precise drift come from same-run records, not direct measurement from the video. The main clips do not separately show rejection of an attempted moving driver exchange. That belongs to interface conditions and test scope rather than a process already shown on screen.
Phase entry, recorded events, and captions have different timestamps
In the third and fourth recording scripts, the event named native_arrival also requires speed below 0.05 m/s. Rechecking frame reports places the first observed Completed in the third clip at about 42.27 s, with the arrival event at 42.60 s. The fourth clip gives about 28.63 s and 28.97 s. That roughly one-third-second gap runs from task completion to the stricter caption condition in these recordings. It is not a fixed response time of the task kernel.
Journey evaluation uses pose and velocity read during physics submission; the recording script reads a later report. Its speed value in the first report showing Completed cannot be used to reconstruct the earlier evaluation inputs. Step-level validation of the completion gate would require logging at that decision point. Existing records distinguish the two times but do not provide that same-instant input snapshot.
Recording format and build relationships
The main clips are approximately 31.93, 34.40, 45.20, and 31.53 s, totaling about 143.07 s. They were recorded separately in city PIE with fixed 30 Hz simulation, retaining every second frame for 15 fps output at the original duration. A short initialization section is trimmed from the start. There are no internal cuts, reverse playback, or speed changes. Player driving replays raw inputs; NPC driving uses the native road task and target controller.
The demonstration script arranges cameras and captions, but does not complete vehicle motion by writing position, rotation, or velocity during driving. Encoded frame rate does not measure UE performance, and input replay is not a human keyboard or gamepad playtest. The local frame player uses actual final-frame images and canvas for playback compatibility checks. The public article embeds MP4 files.
Native source, DLL, original city map, and the first two video files were fingerprinted before and after the additional material. Temporary barriers, markers, and cameras were not saved into the map. Writing uses frozen source and same-run records; it did not modify the project, record new footage, or rerun engine acceptance.
Extending continuation beyond one car
This implementation handles temporary takeover, road rebuilding from measured pose, explicit admission failure, restored conditions, and new tasks after cancellation within one car’s session. It does not yet cover a complete character task tree, cross-world task persistence, the full admission fallback chain, citywide junction rights and dynamic occupancy, or network validation.
Seat exchange remains a simplified logical operation without entering, exiting, or in-car seat-change animations. A gameplay or demonstration script explicitly requests takeover; the NPC does not detect the roadblock and autonomously ask the player to drive. Collision-free runs in these scenes do not validate every road shape, dynamic traffic situation, or difficult terrain.
For taxis, companions, or service vehicles, the gameplay layer still decides whether the task continues. The journey layer manages road plans, relationships manage driving eligibility, and physics reports actual results. A taxi order, for example, ends according to its business conditions. Neither the current occupant of the driver seat nor a connected road plan can replace the checks for arrival and order completion.
AI collaboration retrospective
Writing began with watching the complete task scenarios, then checking the journey object, host calls, and same-run events. AI helped organize state ownership, express candidate matching and measured progress as traceable formulas, arrange video explanations, and draw mechanism diagrams. Implementation and validation come from the existing delivery; writing did not add task capabilities.
Two questions needed particular care during writing: whether a route is executable after handback, and whether retaining the destination also preserves a usable old cursor. The second and third clips provide counterexamples: one accepts a graph plan, while the other rejects all entry candidates, yet both preserve the intent. Cancellation also shows why retaining old diagnostic coordinates does not make a task resumable.
Technical review retained the differences between interfaces: Retry and Resume use different low-speed boundaries; a same-mode request does not rejoin roads; plan serial increments before the physical sweep; and Completed retains an intent record without permitting resumption. Text and diagrams follow that order. Atomic submission, automatic retry, and general version protocols remain unimplemented.
Reviewing the recording scripts also corrected arrival-time wording: an event used for a caption is not always the first moment the kernel enters Completed. Comparing script conditions with frame records separated those two moments. The footage explains the continuous driving behavior; precise timing still needs to be checked against the corresponding records.









