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

[3.3.5] [NEEDS TESTING] Core/Movement: expand Movement Slot implementation #21888

Merged
merged 14 commits into from Jun 3, 2018

Conversation

ccrs
Copy link
Member

@ccrs ccrs commented Apr 26, 2018

basic structure changes, nothing behavioural
future PRs will have the real juice

@ccrs ccrs changed the title [3.3.5] Core/Movement: expand Movement Slot implementation [WIP] [3.3.5] Core/Movement: expand Movement Slot implementation Apr 26, 2018
@Shauren
Copy link
Member

Shauren commented Apr 26, 2018

What exactly is your plan with this?

@ccrs
Copy link
Member Author

ccrs commented Apr 26, 2018

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.

@ccrs
Copy link
Member Author

ccrs commented Apr 26, 2018

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

@ccrs
Copy link
Member Author

ccrs commented Apr 26, 2018

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;
Copy link
Member Author

@ccrs ccrs Apr 27, 2018

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

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

the main structure can be seen now... more or less, thoughts @Shauren @Treeston @ariel- ?

image

{
public:
MovementSlot(uint8 type);
~MovementSlot();
Copy link

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

Copy link
Member Author

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

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

Similar to something I had in mind long time ago

  • IDLE slot remains without changes (idle or db waypoints)
  • ACTIVE - all core movement goes here
  • CONTROLLED - for special cases (more on special cases later)

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

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

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.

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

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)

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

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
and for auras usually a getter is used to know if there are any other auras using the same mechanic or w/e, like GetAuraEffectsByType or https://github.com/TrinityCore/TrinityCore/blob/3.3.5/src/server/game/Entities/Unit/Unit.cpp#L11133

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.

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

why are unit states for movement needed in the first place? arent they the current way of trying to solve movement type priority issue?

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

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

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

I bet most of these could be replaced with a real moving check (active spline/movement flag)

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

most likely, the only use is in

bool IsStopped() const { return !(HasUnitState(UNIT_STATE_MOVING)); }

@Treeston
Copy link
Member

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...)

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

eitherway, the removal or not of those unitstates is out of the scope of this PR

@Treeston
Copy link
Member

Treeston commented Apr 27, 2018

Is there any reason to actually still have three slots?

If this is transformed into a priority_queue as @Shauren suggests (and I concur), I don't see any reason to keep the slots around at all.

ED: If you keep them around, then just keep them around as part of the priority system on a single priority_queue...

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

@Treeston #21888 (comment)

@ccrs
Copy link
Member Author

ccrs commented Apr 27, 2018

oook MotionMaster can be reviewed far more clearly now https://github.com/ccrs/TrinityCore/blob/movementinform/src/server/game/Movement/MotionMaster.cpp

@Treeston
Copy link
Member

Yes, but why do we need three different "slot" instances per se, instead of just one big priority_queue on motionmaster?

Everything @Shauren mentioned is still possible with a single queue.

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

@Treeston making a lower priority movement type be on top for scripts?

@Treeston
Copy link
Member

{ PRIORITY_CONTROLLED, PRIORITY_CHASE_MOVE }?

PS: Though I disagree with using _CONTROLLED for this - fourth priority (_SCRIPT_OVERRIDE) or whatever should exist.

@Shauren
Copy link
Member

Shauren commented Apr 27, 2018

Thing is, I don't see a need to have 4 slots then

@ccrs
Copy link
Member Author

ccrs commented Apr 29, 2018

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

@ccrs
Copy link
Member Author

ccrs commented May 30, 2018

well, now its review ready 💃

@ccrs
Copy link
Member Author

ccrs commented May 31, 2018

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
Copy link
Member

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 ?

Copy link
Member Author

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

Copy link
Member

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

Copy link
Member Author

Choose a reason for hiding this comment

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

👍

Copy link
Member Author

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:
Copy link
Member

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

Copy link
Member Author

@ccrs ccrs Jun 1, 2018

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;
Copy link
Member

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

Copy link
Member Author

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 👍

Copy link
Member

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)

Copy link
Member Author

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
Copy link
Member

Choose a reason for hiding this comment

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

ugh

Copy link
Member Author

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: ???????????
Copy link
Member

@Shauren Shauren May 31, 2018

Choose a reason for hiding this comment

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

???????????

Copy link
Member Author

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
Copy link
Member

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

Copy link
Member Author

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 👍

Copy link
Member

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])

Copy link
Member Author

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
Copy link
Member

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));

Copy link
Member Author

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]() {
Copy link
Member

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)

Copy link
Member Author

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);
Copy link
Member

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
Copy link
Member

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)
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 do this without a temporary container, just use iterator directly instead of this loop syntax

Copy link
Member Author

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
Copy link
Member

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));
Copy link
Member

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

Copy link
Member Author

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 💃

Copy link
Member

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);
Copy link
Member

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);

Copy link
Member Author

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 👍

@ccrs
Copy link
Member Author

ccrs commented Jun 3, 2018

doing some last tests (ingame with ASan) after the last commit before merging 👍

@ccrs ccrs merged commit 982643c into TrinityCore:3.3.5 Jun 3, 2018
@Gooyeth
Copy link
Contributor

Gooyeth commented Aug 26, 2018

@ccrs: This is causing problems with Harvest Soul of The Lich King, the characters die for fall damage.

  1. .go xyz 529.302 -2124.49 840.857 631
  2. .npc add temp 36598

@Keader
Copy link
Member

Keader commented Aug 26, 2018

Open a ticket @Gooyeth

@TheWinchesters
Copy link
Contributor

TheWinchesters commented Dec 24, 2018

Is there an open ticket about what Gooyeth says or do I open one?

@jackpoz
Copy link
Member

jackpoz commented Dec 24, 2018

Open one please and references this PR, easy way to track things

Shauren pushed a commit that referenced this pull request Sep 28, 2021
Internal structure and handling changes, nothing behavioural (or thats the intention at least).

(cherry picked from commit 982643c)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

10 participants