-
Notifications
You must be signed in to change notification settings - Fork 2k
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
ActiveObjectMgr fixes #13560
ActiveObjectMgr fixes #13560
Conversation
I like using unique_ptr. Looks good after a quick glance. I also agree that this is a holy mess! |
Should these all be unique_ptrs? It looks like the objects may be a shared resource and should use shared_ptr. |
Agree that unique_ptr is good. Nothing to indicate that any of the pointers returned from the object manager are owning. |
9c3ae04
to
6018fd7
Compare
Using
They aren't owning. They're owned by the aomgr. Addresses comments and added test instructions. Please review. |
`on_step` callbacks can modify `m_active_objects` and therefore invalidate iterators.
6018fd7
to
45eabc6
Compare
Rebased. |
auto it = m_active_objects.find(id); | ||
if (it == m_active_objects.end()) | ||
continue; // obj was removed | ||
f(it->second.get()); |
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.
from an efficiency POV this is quite bad
the loop goes from O(n)
to O(n * log n)
just for lookup (and this runs every step!)
if we set entries to nullptr
and postpone deletion wouldn't that solve the problem? IIRC it was just about iterator invalidation
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 currently iterated obj isn't necessarily deleted here, and neither in clearIf
.
if we set entries to
nullptr
and postpone deletion
Do you mean in removeObject
? That's an interesting idea.
f
can also insert new objects. Insertion doesn't invalidate iterators, but it means some of the new objects are immediately iterated through here and others aren't. So I'm not sure about the correctness.
IIRC, these functions are only called once per client or server step. So until this really turns out to be a performance bottleneck, I'd rather opt for the current more naive solution than to attempting premature optimization.
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.
Do you mean in removeObject? That's an interesting idea.
Yes.
f can also insert new objects. Insertion doesn't invalidate iterators, but it means some of the new objects are immediately iterated through here and others aren't. So I'm not sure about the correctness.
hmmm
IIRC, these functions are only called once per client or server step. So until this really turns out to be a performance bottleneck, I'd rather opt for the current more naive solution than to attempting premature optimization.
IMO we already have enough issues with entity performance and shouldn't be looking to make it worse.
Idea that's hopefully not too complicated: Edit: We should of course merge these fixes first to get the safety. |
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.
lgtm
f(ao_it.second); | ||
|
||
// Same as in server activeobjectmgr. | ||
std::vector<u16> ids = getAllIds(); |
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.
with many entites you will copy a huge memory block. Use ref as parameter to write result on
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.
Do you mean something like void getAllIds(std::vector<u16> &ret)
? That's not more efficient. Function calls are prvalue expressions (see value categories), and there's copy elision. So, there should only be move constructor calls, no copying.
{ | ||
auto obj = object.get(); |
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.
aren't we defeating the std::unique_ptr with this method, where we move the unique_ptr then we always have the pointer here and we are playing with it ?
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'm not sure if I understand the question correctly.
obj
is a non-owning ref/ptr. object
owns. After the registerObject
call, someone else owns the object, but references (i.e. obj
) are still valid (at least if registerObject
returns true).
(Before, there was just the raw ptr object
. It was an owning raw ptr when we got it, but after the registerObject
call it suddenly was no longer owning.)
The point of unique ptrs is not that you don't use other references on the object anymore.
@@ -404,12 +401,12 @@ void ClientEnvironment::addActiveObject(u16 id, u8 type, | |||
<<std::endl; | |||
} | |||
|
|||
u16 new_id = addActiveObject(obj); | |||
u16 new_id = addActiveObject(std::move(obj)); |
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 checked this function signature, i think we can diverge from ServerEnvironment, as there is no inheritance.
this will prevent the just next line getter. Can se return directly the CAO pointer instead (nullptr if register failed) ?
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.
by preventing that we will improve performance if there is huge amount of entities, removing one lookup
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.
Sure, that would be possible.
But I'd not like to stuff more changes into this PR.
This is a bugfix PR.
These are the ActiveObjectMgr related changes from #13275.
Fixes some iterator invalidation issues, as well as a memleak that you can get by adding an object in
on_destruct
.To do
This PR is a Ready for Review.
How to test
And spawn an ent1.
Note that there's a warning at shutdown, and no abort. This is expected.