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

[Dev] WIP Catmullrom waypoint movement #13467

Open
Pitcrawler opened this issue Oct 27, 2014 · 40 comments · May be fixed by #29923
Open

[Dev] WIP Catmullrom waypoint movement #13467

Pitcrawler opened this issue Oct 27, 2014 · 40 comments · May be fixed by #29923

Comments

@Pitcrawler
Copy link
Contributor

I started to play around a little with the core and made the following change to WaypointMovementGenerator.cpp

diff --git a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
index 942996b..5b8dd8b 100755
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -153,6 +153,16 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
             trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
     }

+   if (creature->IsFlying())
+   {
+       for (uint32 i = 0; i < i_path->size() - i_currentNode; i++)
+       {
+           init.Path().push_back(G3D::Vector3(i_path->at(i_currentNode + i)->x, i_path->at(i_currentNode + i)->y, i_path->at(i_currentNode + i)->z));
+       }
+       init.SetSmooth();
+       init.Launch();
+       return true;
+   }
     //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
     //! but formationDest contains global coordinates
     init.MoveTo(node->x, node->y, node->z);

This made all the flying NPCs that have waypoint data use catmullrom movement. But there are some things that certainly need improvements which I can't take care of because I have really little knowledge when it gets to core programming:
At each WP the remaining path is rebuild which is unnecessary (memory consumption) and not blizzlike.
At the last WP there is no next WP so no path is build and point movement is used instead of catmullrom.
Flying creatures that have inhabitType!=4 (i.e. 5 or 7) don't use catmullrom movement. I guess the core doesn't handle them correctly so they don't get their movementflags.
Swimming creatures don't use catmullrom movement.

Want to back this issue? Post a bounty on it! We accept bounties via Bountysource.

@Pitcrawler Pitcrawler mentioned this issue Oct 27, 2014
10 tasks
@Pitcrawler Pitcrawler changed the title [Dev] Catmullrom waypoint movement [Dev] WIP Catmullrom waypoint movement Oct 27, 2014
@jackpoz
Copy link
Member

jackpoz commented Oct 27, 2014

C++ changes fit more in a pull request so they can be commented and discussed.

For example

i_currentNode + i < i_path->size()

is more clear, or you could even just initialize "i" to i_currentNode and avoid any other "+ i_currentNode"

Storing the value of

i_path->at(i_currentNode + i)

is better than writing the same code 3 times (otherwise if you need to change 1 place, you have to remember to do it 3 times)

@Subv
Copy link
Contributor

Subv commented Oct 28, 2014

About the issue with recalculating the path every time, you can just store the previously calculated path in the WayPointMovementGenerator class, you'll have to modify the code that calls MovementInform though, because as far as I remember it works by using _spline->Finished() which won't ever be true in this case except when the creature reaches the final waypoint.

@Pitcrawler
Copy link
Contributor Author

@joschiwald thanks for the tips. The reason why I don't create a PR is simple. I don't know how to and haven't got the time to learn it at the moment. I just want to share what I found out so far because someone else with more experience might bring this to an end meanwhile.

@Subv I investigated a little more and am now convinced that the path isn't recalculated at every WP. It is only calculated when the creature spawns and at end of path which is fine imo.

I modified my piece of code from above and got the following improvements

  • For smooth movement at the last WP I added the first WP after the loop. This might need a check for repeating flag though...
  • Flying creatures with inhabitType=5 or 7 now also use catmullrom movement.
  • Swimming creatures now use catmullrom movement, too.
--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -153,6 +153,17 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
             trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
     }

+   if (creature->IsFlying() || creature->HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED & MOVEMENTFLAG_CAN_FLY) || creature->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING))
+   {
+       for (uint32 i = i_currentNode; i < i_path->size(); i++)
+       {
+           init.Path().push_back(G3D::Vector3(i_path->at(i)->x, i_path->at(i)->y, i_path->at(i)->z));
+       }
+       init.Path().push_back(G3D::Vector3(i_path->at(0)->x, i_path->at(0)->y, i_path->at(0)->z));
+        init.SetSmooth();
+       init.Launch();
+       return true;
+   }
     //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
     //! but formationDest contains global coordinates
     init.MoveTo(node->x, node->y, node->z);

I got one new issue with flying creatures with inhabitType=5 or 7. They sort of fall and jump through the air. I think this is a core issue because they don't have movementflag MOVEMENTFLAG_FLYING | MOVEMENTFLAG_DISABLE_GRAVITY but MOVEMENTFLAG_SPLINE_ENABLED & MOVEMENTFLAG_CAN_FLY when they actually moving in the air. This needs further research.

@akrom23
Copy link
Contributor

akrom23 commented Oct 29, 2014

Use init.SetSmooth only for non-flying creatures - for flying you've got init.EnableFlying().

init.Path().push_back(G3D::Vector3(i_path->at(0)->x, i_path->at(0)->y, i_path->at(0)->z));
Use current creature position instead and add this point at the begin of the path.

To call Movement Inform, look at FlightPathGenerator::update and use this code in waypointgenerator code.

@MrSmite
Copy link
Contributor

MrSmite commented Oct 29, 2014

Nice work.

Would this type of path calculation be able to fix the taxi paths that fly inside Ironforge when they're supposed to go around it (eg: Stormwind to Menethil should not fly inside Ironforge).

I know taxipaths are loaded from the DBC but we should be able to recalculate them. I've tried in the past and only succeeded in either crashing the server or flying through the ground.

@Kittnz
Copy link
Member

Kittnz commented Oct 30, 2014

That's a grid problem @MrSmite if i recall correctly.
Ontopic: I guess this can be used for normal walking creatures too? Ill test tonight!

@MrSmite
Copy link
Contributor

MrSmite commented Oct 30, 2014

That's a grid problem @MrSmite if i recall correctly.

Nope, it's a waypoint problem. The taxipath that is loaded includes points that go inside IF to the flightmaster where you temporarily land and then take off again for the second half of the flight.

@Shauren
Copy link
Member

Shauren commented Oct 30, 2014

No, it would not be able to fix taxi paths, there is more going on there - i once wrote a hack for that (it sort of worked but was also crashing, never looked more at that)

@Aokromes
Copy link
Member

Yeah i remember that XD

@Pitcrawler
Copy link
Contributor Author

@akrom23 thanks for the suggestions. But I have some questions about them.

  • I think you are speaking about init.SetFly() because there is no init.EnableFlying() at least on my core.
  • I don't see the point in adding the current position at the beginning of the spline instead of adding the first WP of the path in the end to get a smooth movement at the end of the spline. Maybe you can explain that?
  • Why would I want to call movementInform?

By using SetFly I fixed the strange flying behavior of creatures with inhabitType=5 or 7. Btw creature's movementflags are blizzlike after that change. They were wrong before compared to sniff from 3.3.5.

Unfortunately I found some flying creatures that are not respecting smooth movement at the end of the path when they start to repeat it but others do it like a charm. I don't have any idea about that right now.

@akrom23
Copy link
Contributor

akrom23 commented Oct 30, 2014

@Pitcrawler:
I think you are speaking about init.SetFly() because there is no init.EnableFlying() at least on my core.
Yes, i meant SetFly

I don't see the point in adding the current position at the beginning of the spline instead of adding the first WP of the path in the end to get a smooth movement at the end of the spline. Maybe you can explain that?
Because in case of only 2 waypoint points creature's spline will have only 1 arg in path and you will have errors in console. Besides, without this, you will have some visual problems - spline always begins with current position. See, how init.Moveto is designed - first point is the current unit position -> the start from where spline is launched.

Why would I want to call movementInform?
See OnArrived code. In some nodes creature stops or do sth.

@MrSmite
Copy link
Contributor

MrSmite commented Oct 31, 2014

@Shauren Too bad. Maybe it will correct itself in 6.x :)

@Pitcrawler
Copy link
Contributor Author

I have checked a number of sniffs and haven't found any spline that contains current position of the creature. So I will leave this as it is until somebody can give a proof of this. I think WP scripts are handled via OnArrived() which is called when a WP is reached. So I left this as it is as well.

But I changed the build process of the spline. Now the spline is always build for the whole path and the first WP is then taken from the current WP+1.

I also added the cyclic movement flag when the spline is meant to be repeated which is correct for all the waypoint NPCs. Maybe this check is not necessary.

I had to set speed because when such an NPC is aggroed and it returns back to its homeposition and continues the spline it will use walking speed otherwise.

--- a/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
+++ b/src/server/game/Movement/MovementGenerators/WaypointMovementGenerator.cpp
@@ -153,6 +153,21 @@ bool WaypointMovementGenerator<Creature>::StartMove(Creature* creature)
             trans->CalculatePassengerPosition(formationDest.x, formationDest.y, formationDest.z, &formationDest.orientation);
     }

+    if (creature->IsFlying() || creature->HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED | MOVEMENTFLAG_CAN_FLY) || creature->HasUnitMovementFlag(MOVEMENTFLAG_SWIMMING))
+    {
+        for (uint32 i = 0; i < i_path->size(); i++)
+        {
+            init.Path().push_back(G3D::Vector3(i_path->at(i)->x, i_path->at(i)->y, i_path->at(i)->z));
+        }
+        init.SetFirstPointId(i_currentNode + 1);
+        if (repeating)
+            init.SetCyclic();
+        init.SetFly();
+        init.SetVelocity(creature->GetSpeed(MOVE_RUN));
+        init.Launch();
+        return true;
+    }
+
     //! Do not use formationDest here, MoveTo requires transport offsets due to DisableTransportPathTransformations() call
     //! but formationDest contains global coordinates
     init.MoveTo(node->x, node->y, node->z);

I couldn't get rid of two minor things:

  • When the creature reaches the last WP of the spline it sort of rotates about half a second or so and then starts a new round of the spline as suppossed. I can only describe the behavior in a very poor way. I'd be best to see it for yourself.
    I tracked this down to the function MoveSpline::UpdateResult MoveSpline::_updateState(int32& ms_time_diff). I think the handling of cyclic splines needs to be improved there. As far as I understand it the first WP of the spline is loaded when the last one is reached and at the next update the new cycle is started. Possibly this takes too long so the creature doesn't know where to go between two updates. But this can be completly wrong as I already said that I have only very poor core knowledge.
  • After returning to its homeposition the creature also rotates about half a second before continuing the spline.

It would be nice if @Shauren or @Subv had the time to say something about that or even fix it.

@Shauren
Copy link
Member

Shauren commented Nov 3, 2014

creature->HasUnitMovementFlag(MOVEMENTFLAG_SPLINE_ENABLED & MOVEMENTFLAG_CAN_FLY) this is always false. (MOVEMENTFLAG_SPLINE_ENABLED & MOVEMENTFLAG_CAN_FLY = 0, HasUnitMovementFlag(0)... go figure)

@Pitcrawler
Copy link
Contributor Author

Well, that is really embarrassing even for me...
But I added this check, which should have been with bitwise OR, because of those creatures with inhabitType=5 or 7. I changed it above.

The best solution to this would be when they get MOVEMENTFLAG_DISABLE_GRAVITY as soon as they are in the air. Currently they just get MOVEMENTFLAG_CAN_FLY. I think this not correct compared to sniffs.

@Shauren
Copy link
Member

Shauren commented Nov 3, 2014

MOVEMENTFLAG_DISABLE_GRAVITY and MOVEMENTFLAG_CAN_FLY are exclusive with each other, disable is set for inhabit = 4, fly for 4 | 1

@Kittnz
Copy link
Member

Kittnz commented Dec 27, 2014

Is anyone still into this?

@jackpoz
Copy link
Member

jackpoz commented Mar 7, 2015

any update on this ?

@Kittnz
Copy link
Member

Kittnz commented Mar 8, 2015

No one is working on it, hope someone picks it up.

@click
Copy link
Contributor

click commented Apr 1, 2015

Ok, let's continue on this one ...

Single pathing :
Example with 20 "real" waypoints:
1-2-3...18-19-20-[21]
[21] = 20 - describes that we're on the end of a single-run path.

Cyclic pathing :
Example with 20 "real" waypoints:
[1-2-3]-4-5-6-7....18-19-20-[21-22-23]
[21-22-23] = [1-2-3] - describes that we are on a cyclic path.

(Courtesy of Malcroms research on the issue).

@MrSmite
Copy link
Contributor

MrSmite commented Apr 1, 2015

Question: After a path is generated would it make sense to save it to the DB (since the path should technically never change)?

@malcrom
Copy link
Contributor

malcrom commented Apr 1, 2015

Isn't the client doing the smoothing? we have many catmullrom paths in waypoint_data the same as offi sends to client. We are just sending them a point at a time.

@click
Copy link
Contributor

click commented Apr 1, 2015

@MrSmite : no, the path is actually picked up FROM the database, core just need to know the criterias above.
Final point twice = Full endpoint
First three repeated as last three = cyclic
The client most probably also knows about this criteria, so it can interpolate correctly clientside.

@malcrom: The client does the smoothing based on standard Catmullrom definitions and us shipping the right info to it. Which we obviously don't per today.

@MrSmite
Copy link
Contributor

MrSmite commented Apr 2, 2015

@click Ah, ok. I thought the goal was to calculate a path for use with mmaps to replace the waypoints we already had.

@funjoker
Copy link
Member

DDuarte pushed a commit that referenced this issue Nov 24, 2016
Implement smooth movement for all waypoint pathing and escortai
@DDuarte DDuarte closed this as completed Nov 24, 2016
@Aokromes Aokromes reopened this Nov 25, 2016
@funjoker
Copy link
Member

Bountysource do something xD

@Aokromes
Copy link
Member

i mailed them, still waiting for answer.

jackpoz pushed a commit that referenced this issue Jan 20, 2017
…" (#18888)

This reverts commit 28050f3.

Conflicts:
	src/server/game/AI/SmartScripts/SmartAI.cpp
	src/server/game/AI/SmartScripts/SmartScriptMgr.cpp
@Keader
Copy link
Member

Keader commented Jan 20, 2017

Fix reverted in a3c6880 so... reopen this

@Keader Keader reopened this Jan 20, 2017
@Aokromes Aokromes removed the bounty label Jan 20, 2017
@Aokromes Aokromes changed the title [Dev] WIP Catmullrom waypoint movement (65$ bounty) [Dev] WIP Catmullrom waypoint movement Jan 20, 2017
@jackpoz
Copy link
Member

jackpoz commented Jan 20, 2017

lul the bounty was awarded

@robinsch
Copy link
Contributor

ez money

@funjoker
Copy link
Member

Well xD RIP my money, it was fun. :P

gerripeach added a commit to gerripeach/TrinityCore that referenced this issue Nov 12, 2017
fixes TrinityCore#13467

WIP? - don't know whats missing - need feedback
joschiwald pushed a commit that referenced this issue Feb 11, 2018
Implement smooth movement for all waypoint pathing and escortai

(cherry picked from commit 28050f3)
Aszune pushed a commit to Aszune/TrinityCoreRP that referenced this issue Apr 1, 2018
…nityCore#18020)

Implement smooth movement for all waypoint pathing and escortai

(cherry picked from commit 28050f3)
Shauren pushed a commit that referenced this issue Aug 17, 2019
@mdX7 mdX7 linked a pull request Apr 14, 2024 that will close this issue
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.