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

Optimize pathfinding #4637

Open
wants to merge 53 commits into
base: master
Choose a base branch
from
Open

Conversation

NRH-AA
Copy link
Contributor

@NRH-AA NRH-AA commented Mar 23, 2024

Pull Request Prelude

Changes Proposed

This is a overhaul of when and how pathfinding is done. I did attempt this before but I closed the pull request due to congestion. I believe all problems from the original pull request have been fixed.

This will change the pathfinding to work as A* algorithm rather than djikstra's.
It will also add more pathfinding calls as needed fixing monster moving around slowly due to 1 second pathfinding interval.
This PR also includes separation of when creatures will update their path from creatures onThink.
Lastly it includes some fixes for bugs which were not detectable until pathfinding was able to be called more often.

Issues addressed:
Might fix: #4617

@MillhioreBT
Copy link
Contributor

I did a quick test but this PR doesn't work, the monsters walk randomly and move away from the target slowly until they disappear from sight, and the summons don't have any type of movement.

@NRH-AA

This comment was marked as outdated.

src/map.cpp Fixed Show fixed Hide fixed
src/map.cpp Outdated Show resolved Hide resolved
@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 16, 2024

BUG: after changing the floor for the first time, guards guards monsters have a slow walk reaction. If the monsters had seen you before, they will have the correct walk reaction.

I am still looking into this but I seriously doubt this problem is created from this PR. The only reason you are noticing it more now is because monsters have faster reactions in 99% of cases compared to base repo

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 19, 2024

The new constexpr update seems to have destroyed this

edit: I think changing int_fast32_t, ect is the problem.

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 20, 2024

Can someone test the last commit. I think this should fix the pathfinding again. I also tried to fix the reaction speed when a monster first targets a player that has changed floors. @floki21uu

Keep in mind you will need to have updated to the new constexpr position methods.

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 20, 2024

std::sqrt is running almost 3x faster than std::hypot

@ranisalt
Copy link
Member

edit: I think changing int_fast32_t, ect is the problem.

FP math is orders of magnitude slower than integer math. I don't see why you changed the get*Cost functions to use doubles without changing how they work.

std::sqrt is running almost 3x faster than std::hypot

How did you measure it?

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 21, 2024

edit: I think changing int_fast32_t, ect is the problem.

FP math is orders of magnitude slower than integer math. I don't see why you changed the get*Cost functions to use doubles without changing how they work.

std::sqrt is running almost 3x faster than std::hypot

How did you measure it?

I used time measurements strictly around the sqrt operation. I checked 1sqm-100sqm paths. I also created a small project just as a frame of reference using only the sqrt and hypot so there wasn't any additional bloatware. All instances were 2-3x faster from what I saw. I also tried different data types with integers giving the best results with sqrt being 3-4x faster. With that being said, I am not aware of tools, ect that can be used so its just based on time measurements. Someone with more experience may be able to look into it more.

As for what I changed to double I can revert some of the code back to using integers. I didn't realize I should leave out the heuristic from the g (walk) cost and place it in its own variable. However, I do think leaving the heuristic as a double is best as from everything I read about path finding the more precise the better for the heuristic. In other words I am still learning and did some things that weren't needed. I also didn't know it was done using order of magnitude which I am assuming is referencing the extra cost for fields and destroying creatures

5 Iterations
image

100k iterations
image

Edit: I have tried moving back to integers for the walk cost function and the result is that because of how big of a difference the integers are compared to the result of our heuristic the algorithm can no longer find the path properly. So keeping the walk cost as a float or double seems to be the best option and we will have to modify the extra costs to work properly assuming they dont. I do think it works as expected though because I have just divided the values by 10.

We also may be able to just *10 the dx and dy before running sqrt on it as well.

@EPuncker EPuncker added the enhancement Increase or improvement in quality, value, or extent label Apr 21, 2024
@floki21uu
Copy link

The new constexpr update seems to have destroyed this

edit: I think changing int_fast32_t, ect is the problem.

destroyed what?

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 22, 2024

The new constexpr update seems to have destroyed this
edit: I think changing int_fast32_t, ect is the problem.

destroyed what?

The path finding stopped working with @ranisalt's constexpr position change. I did revert the datatype changes in this repo for pathmatching so I think it should be working properly again.

@NRH-AA
Copy link
Contributor Author

NRH-AA commented Apr 25, 2024

Lets get this added peeps

@Codinablack
Copy link
Contributor

When you made this using the constexpr positions you had problems. It seems there were problems with that commit that have since been fixed, have you tried using the current version of the constexpr positions?

@NRH-AA
Copy link
Contributor Author

NRH-AA commented May 28, 2024

When you made this using the constexpr positions you had problems. It seems there were problems with that commit that have since been fixed, have you tried using the current version of the constexpr positions?

Yes, and the fixes did solve the problem. The system works as it is so I will push updates to get it ready to merge with tfs master when people have tested it and say it can be merged once its updated to lastest commits. I can't keep doing micro updates.

@EvilHero90 EvilHero90 added this to the 1.8 milestone May 28, 2024
@EvilHero90
Copy link
Contributor

Feel free to update this, once 1.6 is released it'll be merged directly into 1.7 dev cycle

@EvilHero90 EvilHero90 added needs-triage Needs testing with screenshot/video confirmation priority: high labels May 28, 2024
return;
}

if (lastPathUpdate - OTSYS_TIME() > 0) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if (lastPathUpdate - OTSYS_TIME() > 0) {
if (lastPathUpdate > OTSYS_TIME()) {

Shouldn't this be called nextPathUpdate? It's always set to a date in the future.

}

std::list<Creature*> newList;
newList.resize(followedByCreatures.size());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please do not use std::list, and the way you use it doesn't make much sense, you resize it adding empty values, push to it and then clear it and never use any intermediate state, looks like it could be completely removed

creature->forceUpdatePath();
}
++it;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a range for here?

return nullptr;
std::sort(nodes.begin(), nodes.end(), [](AStarNode* left, AStarNode* right) { return left->f > right->f; });
AStarNode* retNode = nodes.back();
nodes.pop_back();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can use nth_element to partially sort, bubbling the best element to the end (using the same comparison function) so it only performs N operations rather than N log N

++closedNodes;
}
uint16_t dx = std::abs(p1.x - p2.x);
uint16_t dy = std::abs(p1.y - p2.y);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You must either use getX and getY or static cast both to a signed integer, otherwise they will overflow since both numbers are unsigned.


static int_fast32_t getMapWalkCost(AStarNode* node, const Position& neighborPos);
static int_fast32_t getTileWalkCost(const Creature& creature, const Tile* tile);
static double calculateHeuristic(const Position& p1, const Position& p2);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This function does not need to be member of AStarNode, it can be a free function within map.cpp

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement Increase or improvement in quality, value, or extent needs-triage Needs testing with screenshot/video confirmation priority: high
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Wrong interactions of monsters with pathfinding.
8 participants