Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix: Do not send vehicles towards incomplete PF nodes #9280

Merged
merged 1 commit into from May 29, 2021

Conversation

vituscze
Copy link
Contributor

@vituscze vituscze commented May 17, 2021

Motivation / Problem

When a path cannot be found, the pathfinder attempts to send the vehicle as close to its destination as possible. However, it is possible to set up a situation where the pathfinder ends up sending the vehicle away from the destination.

Here's a savegame which demonstrates this issue: overwrite_bug.zip. If you start the vehicle, it chooses the track going away from its destination. If you remove the waypoint or the signal after it, the train chooses the correct track.

Description

When the pathfinder is exploring a new graph node, it requests a fresh node from the underlying NodeList which can either produce a completely new node or reuse the last node (if that node was never added to the open list or was not marked as the destination).

It is possible to set up a situation where the NodeList reuses a node that's currently marked as the best intermediate node (m_pBestIntermediateNode). If the best node is then never updated, it will end up with whatever random data the next round of the pathfinder fills it with, which might be completely unrelated to the actual best node.

The attached savegame works by exploiting very long track segments (ESRB_SEGMENT_TOO_LONG). In particular, the are two ways of getting to the waypoint (key: m_tile=3055 m_td=TRACKDIR_X_NE) that end up having different m_last_tiles of their segments. When the pathfinder gets to the waypoint for the second time, it creates a new node, it sees that its last tile is closer to the destination and sets it as the best intermediate node. Then it finds out that the key is already present in the closed list and the new node is never added to the open list (and thus finalized).

The fix to this issue is simple: the best intermediate node is only updated once we're sure that the construction of the node is finalized (i.e. it is inserted into the open list).

Limitations

A case could be made for changing the best intermediate node to the openNode or closedNode, but the content of the open/closed node couldn't be changed to match the newly created node (in particular the distance to the destination would be wrong). This is very unlikely to matter, but I'm open to suggestions.

Another possibility is to use ItemList's FoundBestNode to ensure the node isn't reused, but that seems like a misuse of that function.

Checklist for review

Some things are not automated, and forgotten often. This list is a reminder for the reviewers.

  • The bug fix is important enough to be backported? (label: 'backport requested')
  • This PR affects the save game format? (label 'savegame upgrade')
  • This PR affects the GS/AI API? (label 'needs review: Script API')
    • ai_changelog.hpp, gs_changelog.hpp need updating.
    • The compatibility wrappers (compat_*.nut) need updating.
  • This PR affects the NewGRF API? (label 'needs review: NewGRF')

YAPF could end up in a situation where it sets the best intermediate node
to a node whose construction is never finalized (i.e. it is never added to
the open list). The content of the node would be overwritten in the next
round, potentially sending the vehicle to an unwanted location.
@rubidium42 rubidium42 merged commit 0125ba8 into OpenTTD:master May 29, 2021
@rubidium42 rubidium42 added the backport requested This PR should be backport to current release (RC / stable) label May 29, 2021
@vituscze vituscze deleted the overwrite-fix branch May 29, 2021 17:18
@TrueBrain TrueBrain removed the backport requested This PR should be backport to current release (RC / stable) label Oct 3, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants