• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

Solved Weird monster behaviour in TFS 1.1?

Ahilphino

Excellent OT User
Joined
Jun 5, 2013
Messages
1,666
Solutions
1
Reaction score
723
The monster AI in tfs 1.1 (idk about 1.0) is EXTREMELY dumb. This has discouraged me from using TFS 1.1 even though i've spent so much time with it.

A couple of examples:

If you chase any ranged mob, let's take lizard legionaire, they will turn around every time they make an attack and this causes them to barely run away even if you set their speed to 2000.

If you're getting chased by a fast monster, let's say a grim reaper - he will stop at times. Especially when you're in melee range, then just decide to run away. It will take him like one second to react and start running after you.


There's youtube videos about it a couple of posts below
 
Last edited:
But does this have any negative affects on the performance? Else why is it not added on the offical tfs project :p?

Yes, it affects the performance significantly as the number of players online and number of monsters chasing players increases. It will recalculate the path for every step a player who is being chased is taking, for each monster chasing the player.

You probably won't notice the difference unless you have over 500 players running around at dense hunting grounds. When you apply the change I mentioned in this thread, Map::getPathMatching will be consuming more or less around the same CPU cycles as Map::getSpectatorsInternal, and Map::getSpectatorsInternal is a beast.
 
Yes, it affects the performance significantly as the number of players online and number of monsters chasing players increases. It will recalculate the path for every step a player who is being chased is taking, for each monster chasing the player.

You probably won't notice the difference unless you have over 500 players running around at dense hunting grounds. When you apply the change I mentioned in this thread, Map::getPathMatching will be consuming more or less around the same CPU cycles as Map::getSpectatorsInternal, and Map::getSpectatorsInternal is a beast.

There must be a better way to stop this, as of what CIP might be doing :p
 
@Mark

Sorry for opening thread again. I was thinking about running separate thread in TFS for pathfinding which could be used only in some occasions like this. The monster path would be always updated async. Do you think there may be some problems implementing this ?
 
@Mark

Sorry for opening thread again. I was thinking about running separate thread in TFS for pathfinding which could be used only in some occasions like this. The monster path would be always updated async. Do you think there may be some problems implementing this ?

Your problem will be communicating memory with the other thread in a way that is safe, but also more performant than just running pathfinding in the dispatcher thread.
 
Your problem will be communicating memory with the other thread in a way that is safe, but also more performant than just running pathfinding in the dispatcher thread.
You mean mainly problem with null pointers ?
I would use similiar principe that database tasks.
 
Last edited:
You mean mainly problem with null pointers ?
I would use similiar principe that database tasks.

No, the problem is that you'll be operating on shared memory that may be changed concurrently by a different thread which will result in hard to debug problems. You either need to do a lot of copying, or synchronization between the threads. Database tasks work fine because querying the database does not depend on non-thread safe code.
 
No, the problem is that you'll be operating on shared memory that may be changed concurrently by a different thread which will result in hard to debug problems. You either need to do a lot of copying, or synchronization between the threads. Database tasks work fine because querying the database does not depend on non-thread safe code.

I see TFS uses map cache for creatures. What about sending this map cache to separate thread and count the path without requirement of accesing memory in main thread ? The cache could be also improved (make ot bigger etc.)
 
I see TFS uses map cache for creatures. What about sending this map cache to separate thread and count the path without requirement of accesing memory in main thread ? The cache could be also improved (make ot bigger etc.)

The question is whether that is going to be faster than just running pathfinding in the dispatcher thread. Generating the cache on the fly may be worse than just running pathfinding on the dispatcher thread, and maintaining it is going to add performance overhead to changes on the map and increase the memory footprint. The latter may be the best option, but I don't think the added complexity is worth it unless this is a bottleneck on your server.
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
Sorry for beeing late to the party, also very new to all of this. But you say that I need to change the first text to the second text. I've done that but is there anything more I need to do before this will apply to the server? (im super new to this, please explain like you would explain to someone who has never started an OT before
Thanks in advance! :)
 
Sorry for beeing late to the party, also very new to all of this. But you say that I need to change the first text to the second text. I've done that but is there anything more I need to do before this will apply to the server? (im super new to this, please explain like you would explain to someone who has never started an OT before
Thanks in advance! :)
Recompile ur source.
 
If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }

If it bothers you so much, open up creature.cpp and change:
Code:
        if (hasFollowPath) {
            isUpdatingPath = true;
        }
to:
Code:
        if (hasFollowPath) {
            isUpdatingPath = false;
            g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
        }
Thanks bro, I was looking for this!!

My server is small and therefore I probably won't have much impact on performance.
 
Thanks bro, I was looking for this!!

My server is small and therefore I probably won't have much impact on performance.
As I posted here:
1 player fighting vs. 15 demons may consume 10% of CPU (Intel i9-9900K). On cheap VPS it would be 20% of CPU consumed just by 1 player.
Here are custom CPU optimized algorithms:
Fighting vs 15 demons (on [email protected]):
Algo nr 0 - current TFS. Super slow reaction. 0% CPU
Algo nr 1 - instant reaction - 5.88% CPU <<<<<<<-------- Mark's post from this thread
Algo nr 2 - fast first step - 1.1% CPU
Algo nr 3 - fast first step, faster next step - 1.6% CPU
Algo nr 4 - instant reaction, but with Scheduler for 'walkDelay' - 1.9% CPU
 
Yes, it affects the performance significantly as the number of players online and number of monsters chasing players increases. It will recalculate the path for every step a player who is being chased is taking, for each monster chasing the player.

You probably won't notice the difference unless you have over 500 players running around at dense hunting grounds. When you apply the change I mentioned in this thread, Map::getPathMatching will be consuming more or less around the same CPU cycles as Map::getSpectatorsInternal, and Map::getSpectatorsInternal is a beast.
Question tho, is the performance more CPU Intensive or will it impact Packets as well?
As I posted here:
1 player fighting vs. 15 demons may consume 10% of CPU (Intel i9-9900K). On cheap VPS it would be 20% of CPU consumed just by 1 player.
Here are custom CPU optimized algorithms:

wow that was a great read, thank you for taking the time to investigate this.

So, if I understood it correctly, the 3th Algorithm seems to have yielded the best result considering fast reaction/movement and performance right?
 
Question tho, is the performance more CPU Intensive or will it impact Packets as well?


wow that was a great read, thank you for taking the time to investigate this.

So, if I understood it correctly, the 3th Algorithm seems to have yielded the best result considering fast reaction/movement and performance right?
Yes. This code worked best:
Code:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
Monsters react pretty fast, but cheap VPS should still handle 150-200 online without lags.
 
Yes. This code worked best:
Code:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
Monsters react pretty fast, but cheap VPS should still handle 150-200 online without lags.
thanks bro!! I appreciate your time and effort
 
Yes. This code worked best:
Code:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
Monsters react pretty fast, but cheap VPS should still handle 150-200 online without lags.
should be like this right?, there is nothing else to add?
Post automatically merged:

Yes. This code worked best:
Code:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
Monsters react pretty fast, but cheap VPS should still handle 150-200 online without lags.
which one should add this or this Multithread pathfinding · gesior/forgottenserver@48cb292 (https://github.com/gesior/forgottenserver/commit/48cb292d56d36e87ab25e2bc00bcc5c61c4cc842?)
 
Last edited:
should be like this right?, there is nothing else to add?
Post automatically merged:


which one should add this or this Multithread pathfinding · gesior/forgottenserver@48cb292 (https://github.com/gesior/forgottenserver/commit/48cb292d56d36e87ab25e2bc00bcc5c61c4cc842?)
C++:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
This is tested version. Monster react fast and CPU usage is pretty low.
 
C++:
                if (getWalkDelay() <= 0) {
                    g_dispatcher.addTask(createTask(std::bind(&Game::updateCreatureWalk, &g_game, getID())));
                }
                isUpdatingPath = true;
This is tested version. Monster react fast and CPU usage is pretty low.
Hello @geisor, man I have noted that when monster are being chased by a player they run, turn around almost every step to look at player a, then begin to run and turn the look again,this occurs every step is there a fix for this?
 
Back
Top