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
[3.3.5] [NEEDS TESTING] Core/Movement: expand Movement Slot implementation #21888
Conversation
What exactly is your plan with this? |
having 3 slots each capable of containing different generators then motionmaster will "consume" from CONTROLLED to IDLE, like right now; but finishing all the generators before going to the next inferior slot. |
I still think having 3 slots is something actually desirable, see more pros than cons but then again, we can swift to something like u once suggested, priority_queue, and forget about slots |
I feel like having different slots makes it actually easier/more efficient in regards of accessing a group of generators, or even a single one.... a multimap can also do the trick I guess |
uint8 _cleanFlag; | ||
std::unordered_multimap<uint32, MovementGenerator*> _baseUnitStatesMap; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the idea is to have an exact control of the unitstates that the owner must have and must remove.
example:
- moment 1
SLOT 2 -> PointMovement -> ROAMING State
SLOT 3 -> Empty - moment 2
SLOT 2 -> PointMovement -> ROAMING State
SLOT 3 -> new Generator -> new Top -> PointMovement -> ROAMING State - moment 3
SLOT 2 -> want to erase -> PointMovement -> Finalize -> wants to remove ROAMING State
SLOT 3 -> still active, still Top -> PointMovement -> still wants ROAMING State
{ | ||
public: | ||
MovementSlot(uint8 type); | ||
~MovementSlot(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should MovementSlot
be renamed to MovementSlots
here too (+ class
, uint8 type
) ?
build error: https://travis-ci.org/TrinityCore/TrinityCore/builds/371823289#L1385-L1391
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
dont worry about build errors, yet
Similar to something I had in mind long time ago
Your deque should be std::priority_queue instead, with priorities something like root > point > chase > ... (order up for discussion really, havent thought about it that much). Notice I listed root as movement generator type - you should implement it as .Stop() on init, empty on update. Here is where CONTROLLED slot comes in - scripts could use it to "override" defult generator priority (for example forcing movement while stunned) Ref states - if you mean UNIT_STATE enum then I think you should not have any fancy maps for it, just always override it with highest priority generator from highest slot |
Sounds good, will keep new things out of this PR though (Root generator), I just want to set the structure for future changes About UnitStates, I still think a detailed control is desirable, think about a jump spline while feared, you still are feared, cannot perform any action that is not allowed while feared. Or the case I pointed before #21888 (comment). Example, while a creature is moving towards a point, long distance travel, it can charge for example another creature, long distance charge too, and while charging maybe the AI tells MotionMaster to clear/delete the point movement, erasing ROAMING when it should still be applied because of the charge. |
Yeah but you don't need to store it, just erase "all movement related states" when current movegen changes and compute (just take it off highest new generator) new state (basically how certain auras do it and phasing flags on master) |
maybe its just too obvious for me to notice, but sorry for being stubborn, cant see what you mean on phases there are a couple reference counters to know what to do https://github.com/TrinityCore/TrinityCore/blob/master/src/server/game/Phasing/PhaseShift.cpp#L148 I'm just talking about "Base" UnitStates such as "UNIT_STATE_ROAMING" or "UNIT_STATE_CONFUSED", "Move" UnitStates ("UNIT_STATE_ROAMING_MOVE", "UNIT_STATE_CONFUSED_MOVE" and so on) are always cleared indeed. |
why are unit states for movement needed in the first place? arent they the current way of trying to solve movement type priority issue? |
they signal the different movements that are active on the creature I guess, in the end the check is usually done against UNIT_STATE_MOVING |
I bet most of these could be replaced with a real moving check (active spline/movement flag) |
most likely, the only use is in bool IsStopped() const { return !(HasUnitState(UNIT_STATE_MOVING)); } |
movement unit states are a bitmask, keep that in mind. a lot of movegens use them to check whether another unit has a specific kind of movegen active (chase uses this to prevent infinite repositioning when two units try to be behind each other, for example...) |
eitherway, the removal or not of those unitstates is out of the scope of this PR |
Is there any reason to actually still have three slots? If this is transformed into a ED: If you keep them around, then just keep them around as part of the priority system on a single |
oook MotionMaster can be reviewed far more clearly now https://github.com/ccrs/TrinityCore/blob/movementinform/src/server/game/Movement/MotionMaster.cpp |
Yes, but why do we need three different "slot" instances per se, instead of just one big Everything @Shauren mentioned is still possible with a single queue. |
@Treeston making a lower priority movement type be on top for scripts? |
PS: Though I disagree with using |
Thing is, I don't see a need to have 4 slots then |
I see Treeston's point, actually I think its a good idea. Let me do the changes and we can talk about it with actual code |
well, now its review ready 💃 |
All test done on my part (ingame and ASan). I consider it merge ready. |
.travis.yml
Outdated
- libboost-regex1.58-dev | ||
- libboost-system1.58-dev | ||
- libboost-thread1.58-dev | ||
- libboost1.62-dev |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these changes still required or can they be reverted ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
up to you/all to decide, not required indeed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe save them somewhere in case we have to upgrade boost but remove these changes from the PR, ty
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -2230,16 +2232,16 @@ void SmartScript::ProcessAction(SmartScriptHolder& e, Unit* unit, uint32 var0, u | |||
target->ToUnit()->RemoveAllGameObjects(); | |||
break; | |||
} | |||
case SMART_ACTION_STOP_MOTION: | |||
case SMART_ACTION_REMOVE_MOVEMENT: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is the change to this action backwards compatible? If not then you need to update db data to keep behavior the same
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there is not, currently, any script using the action
backwards compatible?
I guess so... the old one made 0 sense and hardly ever worked
{ | ||
MovementGenerator::Mode = MOTION_MODE_DEFAULT; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pretty sure you are supposed to use this->
in this situation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that sounds right, it did never make too much sense to mee either, like it works, but thats how u declare a local variable? or call a static one? dunnow, will change 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because this (or base) class is a template its "dependent name lookup", by qualifying it with this->
you change when compiler resolves it (template two phase stuff)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
got it 👍
AddFlag(MOVEMENTGENERATOR_FLAG_FINALIZED); | ||
|
||
/* | ||
* TODO: ugh |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ugh
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aka will change with time and future work, something more descriptive would be better though xd
owner->ClearUnitState(UNIT_STATE_ROAMING_MOVE); | ||
owner->StopMoving(); | ||
|
||
// TODO: ??????????? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
???????????
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same, but dont tell me its not worth the meme
case MOTION_SLOT_ACTIVE: | ||
if (!_generators.empty()) | ||
{ | ||
MotionMasterContainer::const_iterator itr = std::find_if(_generators.begin(), _generators.end(), [filter](MovementGenerator const* a) -> bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto (its an iterator)
also you can rewrite it as simply auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
// ref is here to avoid copying the function into find_if
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the function is referenced, there was no copy there, right?
eitherway, much cleaner your way 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is a copy, default lambda capture mode is by value, it does not matter what the actual captured type is (you would need capture by ref, [&filter])
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reference the reference, the more you know 💃
case MOTION_SLOT_ACTIVE: | ||
if (!_generators.empty()) | ||
{ | ||
MotionMasterContainer::const_iterator itr = std::find_if(_generators.begin(), _generators.end(), [filter](MovementGenerator const* a) -> bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here, auto itr = std::find_if(_generators.begin(), _generators.end(), std::ref(filter));
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
DirectClean(slot); | ||
if (HasFlag(MOTIONMASTER_FLAG_UPDATE)) | ||
{ | ||
std::function<void()> action = [this, movement, slot]() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
codestyle, {
placement (applies to all std::function objects you added for _delayedActions)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tru tru
case MOTION_SLOT_ACTIVE: | ||
if (!_generators.empty()) | ||
{ | ||
MotionMasterContainer::iterator itr = _generators.find(movement); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto with iterators
case MOTION_SLOT_ACTIVE: | ||
if (!_generators.empty()) | ||
{ | ||
MotionMasterContainer::iterator itr = std::find_if(_generators.begin(), _generators.end(), [type](MovementGenerator const* a) -> bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto iterator
if (cache.empty()) | ||
return; | ||
|
||
for (MovementGenerator* movement : cache) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you can do this without a temporary container, just use iterator directly instead of this loop syntax
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess, since the container size wont ever be > 20 (and thats maybe too much to say), I thought this was """"""safer"""""" and the setback was minimal. Will change though 👍
} | ||
else | ||
{ | ||
MotionMasterContainer::iterator itr = std::find_if(_generators.begin(), _generators.end(), [movement](MovementGenerator const* a) -> bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto
|
||
while (!empty() && !top()) | ||
--_top; | ||
_baseUnitStatesMap.insert(std::make_pair(movement->BaseUnitState, movement)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emplace should work here without make_pair step
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
did I try that? I cant remember it was like 3-4 weeks ago, will try again 👍
plus the current one is a copy insert sooo 💃
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should work (would be a different story if you tried to construct pair elements using their own constructors passing even more args, std::piecewise_construct would be needed)
curr->Finalize(_owner); | ||
delete curr; | ||
} | ||
std::pair<MotionMasterUnitStatesContainer::iterator, MotionMasterUnitStatesContainer::iterator> bounds = _baseUnitStatesMap.equal_range(movement->BaseUnitState); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Trinity::Containers::MultimapErasePair is designed exactly for what you are doing here, after erasing follow with
if (_baseUnitStatesMap.count(movement->BaseUnitState)
_owner->ClearUnitState(movement->BaseUnitState);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ow, thats a nice one 👍
doing some last tests (ingame with ASan) after the last commit before merging 👍 |
@ccrs: This is causing problems with Harvest Soul of The Lich King, the characters die for fall damage.
|
Open a ticket @Gooyeth |
Is there an open ticket about what Gooyeth says or do I open one? |
Open one please and references this PR, easy way to track things |
Internal structure and handling changes, nothing behavioural (or thats the intention at least). (cherry picked from commit 982643c)
basic structure changes, nothing behavioural
future PRs will have the real juice