-
Notifications
You must be signed in to change notification settings - Fork 481
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
Eventmanager cleanup #3818
Eventmanager cleanup #3818
Conversation
…esholds for combat skill effectiveness formulas to have a higher 100 cap (more descriptive about very strong warriors).
we, um, had it backwards
library/xml: master scripts: master
…oid potential iterator invalidation by an event callback, and did some tidying
library/modules/EventManager.cpp
Outdated
@@ -902,6 +935,26 @@ static void manageEquipmentEvent(color_ostream& out) { | |||
equipment.push_back(item); | |||
} | |||
} | |||
|
|||
// now handle events | |||
std::for_each(equipment_pickups.begin(), equipment_drops.end(), [&](InventoryChangeData& data) { |
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.
equipment_pickups != equipment_drops.
Is this intentional?
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.
no, it was not
library/modules/EventManager.cpp
Outdated
for (auto &[_,handle] : copy) { | ||
// the jobs must have a worker to start | ||
DEBUG(log,out).print("calling handler for job started event\n"); | ||
handle.eventHandler(out, job); |
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.
this still suffers from the problem that if a handler cancels the job (which deletes it and removes it from the list), it will crash (probably).
to improve safety, it might be better to move the handler calls back inline and check after each handler call that the previous link still points to this job
library/modules/EventManager.cpp
Outdated
for (df::job* job : new_jobs_completed_repeats) { | ||
for (auto &[_,handle] : copy) { | ||
DEBUG(log,out).print("calling handler for repeated job completed event\n"); | ||
handle.eventHandler(out, (void*) job); | ||
} |
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.
what does moving this logic gain us? the prevjobs
structure cannot be modified by the handlers (though the jobs could potentially be deleted, which would cause crashes both in the original code and in the proposed 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.
Yeah, there might be no way around that. Somehow I'm able to hold a job open in the gm-editor with auto-update long after its completion though, when it's no longer findable in the linked list? I might do some experiments later to determine the lifetime of a job.
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.
Actually, I think it's fine - the jobs in prevJobs
are actually cloned job structures (by Job::cloneJobStruct()
) and so won't be deleted by the game.
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.
oh that's good - I thought I remembered something like that, but I didn't see it when I was scanning the code for the review. So, this part can be refactored or not. You can refactor it for consistency with the other handlers or revert this section for fewer local variables. I'm ok with either way.
handle.eventHandler(out, (void*)intptr_t(building)); | ||
} | ||
}); | ||
|
||
//now alert people about destroyed buildings |
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.
could you take this opportunity to move the destroyed buildings events before the new building events? this would solve a longstanding bug in our building location cache where a new building is added in the spot a removed building just vacated.
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.
done!
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.
thanks! I keep on forgetting to do that. it's been bugging me for more than a year. It wasn't causing errors, just unnecessary O(N) lookups.
could you also make sure to test all these event code changes? you can use |
Interestingly in testing I've found a bug in the pre-existing code that fires unit death events when units leave the map - probably because the only check it does is whether the unit is active or not |
…evious in linked list in case it is removed. fix a bug with item change events and using invalidated stack pointer as item data. swapped order of destroyed and created building event calls, and a couple other improvements
As of the latest changes I have tested the events for the following events (using 2 forts, one with 300 pops and another newly embarked) All the other event types I didn't test as I didn't change them. |
Awesome! Thank you! Edit: just to check, did you test with more than one registered handler? Whenever we've found bugs in this code the past, it was with that use case. |
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.
please add changelog entries for:
- fixing the unit dead event (Fixes)
- changing the order of the events in the building handler (Misc Improvements)
- protecting against list/vector modification while sending events (Misc Improvements instead of Fixes since this wasn't actively causing reported crashes)
for (auto unit : df::global::world->units.all) { | ||
//if ( unit->counters.death_id == -1 ) { | ||
if ( Units::isActive(unit) ) { | ||
livingUnits.insert(unit->id); | ||
continue; | ||
} | ||
if (!Units::isDead(unit)) continue; // for units that have left the map but aren't dead |
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 had to check the difference between isDead()
and ! isAlive()
-- you chose the correct one.
Ah, I did not for everything, I'll go ahead and double check that. |
I have tested everything again with multiple listeners of each type and also mixed in different types together. Seems to work as expected, and I did stress-test certain conditions and not getting weird behaviour. |
fantastic! Thank you! |
Pulled out the event handler calls outside of the iterations over
df::global
structures so that if any of the calls tohandleEvent
change those structures those iterators aren't invalidated. Also made a few changes to tidy up some things here and there.Changed the way
manageConstructionEvent()
works so that - rather than doing a binary search for every one of the constructions in our memorised set to check if its been destroyed, instead does a linear pass over the game's construction vector (which had to be done regardless to check for new constructions) and moves those constructions which intersect to a new set, and whatever remains in the old set is our destroyed constructions.Range based for loops over map is now written as a structured binding for clarity. (no more ugly
.second
).In
manageUnitAttackEvent
replaced the weirdalreadyDone
(it was a map of maps to ints which represented bools?) with a simple hashset of pairs (hash function provided -hash_pair
) to check if that interaction was already done.