ryzom / ryzomcore

Ryzom Core is the open-source project related to the Ryzom game. This community repository is synchronized with the Ryzom Forge repository, based on the Core branch.
https://wiki.ryzom.dev
GNU Affero General Public License v3.0
336 stars 91 forks source link

Monster freezing after aggro drops on player #300

Closed ryzom-pipeline closed 7 years ago

ryzom-pipeline commented 7 years ago

Original report by Guillaume DUPUY (Bitbucket: [Guillaume DUPUY](https://bitbucket.org/Guillaume DUPUY), ).


If a monster is under a root / sleep (mezz) / stun effect at the moment he drops agro on the player, he will never come back to his original spawn (unless if attacked). In the case of an aggressive monster, he'll never attack anything ever again (and since nothing will attack him, he'll freeze there for eternity).

Steps to reproduce :

  1. aggro a monster (needs to be a fauna-spawned monster, monster spawned using AIS command like eventNpcCreateGroup aren't subject to this bug)
  2. Successfully cast a root / sleep / stun on him (or use an enchant)
  3. Do anything to delete the link (move, cast anything else, attack ...). The effect will stay on for a couple more ticks (intended behaviour)
  4. While the effect is still active, drop monster aggro, either by dying, natural aggro dropping (if he walked too far away from spawn point), or simply become unaggroable (with priviledge command /a Aggro 0)
  5. Watch as the poor monster is now unable to do anything.

What happens is fairly simple : after the aggro is dropped, the monster profile is switched to a CBotProfileReturnAfterFightFauna, who calls CMovementMagnet::update(waitTime = 0);

This function is responsible for finding a path to original spawn point and moving the bot back to the point. On first call, whether we are in state Movement_Anim / Movement_Wait_Anim, we immediately go to BeginMove, who sets _Speed to the current walkSpeed().

After that, the state is now Movement_Move, who calculates the distance the bot has been able to travel since last call, and move him accordingly. To calculate the distance, it simply does :

#!c++

float       dist=_Speed*ticksSinceLastUpdate;

The problem is simple : _Speed is only set during BeginMove, and when we drop aggro (so, at first call of this function), our current walkSpeed() is 0, because we are rooted, stunned, or sleeping. After the first call, we calculate a dist of 0, and try to move accordingly. Obviously, this doesn't do anything, so we are stuck in an infinite loop.

Note that there is a way to go back to BeginAnim (who will go to BeginMove, and reset the _Speed), but we need for that distToDest<=0, which is never true (assuming we aren't at dest the first time, since we don't move we will never be at dest), or lastPos.quickDistTo(_BotFauna.pos())<(dist*0.5f). The left operand will be 0 (since lastPos = _BotFauna.pos() because we don't move), and right operand will be 0 (since dist is 0), and it's a strict compare.

My fix is easy, simply update the _Speed at each call.

Note : if you want to test on a ryzomcore server, i've recreated a stun brick (well, modified the acid damage brick to be a stun brick because i'm lazy) thanks to trial and error (& looking at the parsing code), you can find it here : http://pastebin.com/WRGevn0B

Note 2 : This does not happens with spawned monster because they use a CBotProfileReturnAfterFightNpc (because they are an eventNpcGroup), which use a CBotProfileFollowPos instead of a CMagnetMovement, which does use the current walkSpeed() to calculate dist :

#!c++

    if (_Bot->getPersistent().getOwner()->getSpawnObj()->checkProfileParameter(runParameter))
        speed = std::min(_Bot->runSpeed(), _MaxRunSpeed);
    else
        speed = std::min(_Bot->walkSpeed(), _MaxWalkSpeed);

    dist = speed*ticksSinceLastUpdate;      
ryzom-pipeline commented 7 years ago

Original comment by Guillaume DUPUY (Bitbucket: [Guillaume DUPUY](https://bitbucket.org/Guillaume DUPUY), ).


https://bitbucket.org/ryzom/ryzomcore/pull-requests/143/fix-a-bug-where-a-monster-could-be-stuck/diff contains the fix

ryzom-pipeline commented 7 years ago

Original comment by Cédric Ochs (Bitbucket: [Cédric OCHS](https://bitbucket.org/Cédric OCHS), ).


Nice catch :p I proposed a little change for the pull request to avoid twice the same code :)

ryzom-pipeline commented 7 years ago

Original comment by Guillaume DUPUY (Bitbucket: [Guillaume DUPUY](https://bitbucket.org/Guillaume DUPUY), ).


Fixed by PR 143