Phodex Games Posted January 29, 2018 Share Posted January 29, 2018 Hi Leadwerks fellows I think some of you may run into the same problem once in a while. The problem is the following. My AI wants to grab an item, but if, for whatever reason, this item gets released, while the AI is moving towards the item, the game just crashes, with no error. The same happens if I grab an item as a player and release the entity in my function, I fixed this by releasing the entity some time later in the loop. And yes I am testing my variables if they are nil, so I guess this could not be the problem... I think this has to do with the order how the loops are iterated through and I kind of understand the problem, but how to overcome this. Any safe solutions on how to release an entity, which is used somewhere else in the code? Thanks for reading so far and thanks for your help in advance! Markus from Phodex Games Quote Link to comment Share on other sites More sharing options...
Josh Posted January 29, 2018 Share Posted January 29, 2018 https://www.leadwerks.com/learn?page=API-Reference_Object_AddRef 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Phodex Games Posted January 30, 2018 Author Share Posted January 30, 2018 10 hours ago, Josh said: https://www.leadwerks.com/learn?page=API-Reference_Object_AddRef Thank you this is actually helpful :), but the problem is I want to release the entity. To give a more precice example. I have an item inside my gameworld, lets say its a bread model. And the script attached to it has the following code inside: function Script:Use(player) self.itemClass:Use(player) --adds item to player inventory self.entity:Release() end if I say self.entity:AddRef() before release it obviously is not releasing it, but I want to remove my item as the player grabs it. Or am I using Release totally wrong and should I come up with a system like: function Script:Use(player) self.itemClass:Use(player) self.entity:Hide() self.disabled = false end I thought as the item is not needed anymore I just release it. The problem is it may be used/be target of some other entity/script etc. Quote Link to comment Share on other sites More sharing options...
Josh Posted January 30, 2018 Share Posted January 30, 2018 That is what I am saying. If you create a new relationship that would cause a crash if the pointer became NULL, you should call AddRef() to add one to the ref count, then call Release() when that relationship can be let go of: https://en.wikipedia.org/wiki/Reference_counting 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Phodex Games Posted January 30, 2018 Author Share Posted January 30, 2018 2 minutes ago, Josh said: If you create a new relationship that would cause a crash if the pointer became NULL Hmm ok, this is going to be tricky as I don't exactly now what relatonship is causing the error and it just crashes. Have to learn some more about this topic I guess, but thank you for the information will read through it and hopefully get this fixed... Quote Link to comment Share on other sites More sharing options...
Josh Posted January 30, 2018 Share Posted January 30, 2018 That is why you need to do this with everything. It's a simple concept: If you want an extra handle that can't be deleted by code somewhere else, you increment the reference count. When you are done with it, you decrement the reference count with Release(). Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Rick Posted January 30, 2018 Share Posted January 30, 2018 Quote If you want an extra handle that can't be deleted by code somewhere else I think he's saying he really doesn't want an extra handle. He really just wants something to know if something else still exists in the world or not. From his perspective it's perfectly fine if 5 entities know about entity 'A' and 1 of those 5 entities releases entity 'A'. The other 4 just need to know entity 'A' no longer exists somehow. If all 5 entities called AddRef() when they assigned entity 'A' internally, then when the 1 entity that reached entity 'A' first got it and called Release() on it entity 'A' would still exist, which he doesn't want. He wants it gone, and to somehow tell the other 4 entities it's gone. Perhaps one way would be to have entity 'A' store a list of other entities that "have" it in their sights. I believe there is a script function called when Release is called. When that's called it can go through this list and inform the other entities it will no longer exist and they should set their internal pointer to it to null? Kind of looking at it from a reverse perspective where the object being released tells all other objects that have a reference to it that it's being deleted and they should handle that accordingly. https://gamedev.stackexchange.com/questions/115580/how-to-handle-gameobjects-that-have-been-destroyed-but-are-still-held-by-others Tower defense is probably the most common situation. 3 towers all pointing to 1 enemy and 1 tower kills that enemy. The other 2 need to know so they know not to use that pointer to the dead enemy. Quote Link to comment Share on other sites More sharing options...
Josh Posted January 30, 2018 Share Posted January 30, 2018 In that situation I would either keep the object in memory and add a value like "health" or "state" that indicates it is no longer valid/alive, or I would have a list associated with the object of all the towers that point to it, so that their values can be cleared in the object destructor: Enemy::~Enemy() { for (auto it=towers.begin(); it!= towers.end(); ++it) { (*it)->target = nullptr; } towers.clear(); } In Leadwerks 5 we can use weak pointers to handle this more easily, and you never have to worry about an invalid pointer: Tower::Update() { auto enemy = target.lock(); if (enemy) { //do something } } Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Phodex Games Posted January 30, 2018 Author Share Posted January 30, 2018 59 minutes ago, Rick said: He really just wants something to know if something else still exists in the world or not. Yes thats the point, or simpler I want my game not to crash when my player grabs an item, which is referenced somewhere else. However I was not aware of the "AddRef" function and I guess it helps me overcome some problems. I am pretty sure I can come up with a system that handels that problem, just did not know, releasing an entity can be such a complex thing. I will play around with the new knowledge doing some tests. It just some very awful work to find the error source now, as I get no error message and it just crashes Quote Link to comment Share on other sites More sharing options...
Phodex Games Posted January 30, 2018 Author Share Posted January 30, 2018 1 hour ago, Josh said: In that situation I would either keep the object in memory and add a value like "health" or "state" that indicates it is no longer valid/alive I just set up a simple scenario like this. Entity 1 with script: Script.target = nil --entity "Target" Script.name = "Test" function Script:Start() self.target.script:Insert(self.entity) end function Script:UpdateWorld() if keyHit.Z then self.entity:Release() end end And entity 2 with script: function Script:UpdateWorld() if self.target ~= nil then self.target:GetPosition(true) end end function Script:Insert(entity) self.target = entity end Entity 1 has Entity 2 as target, but if I press Z now, it crashes. So now I tried the "AddRef" function (most likely used it wrong though ) Entity 2 script now looks like this and gives me a object reference count error: function Script:UpdateWorld() if self.target ~= nil then self.target:AddRef() self.target:GetPosition(true) end if self.target ~= nil then self.target:Release() end --so the target can only be released from here end function Script:Insert(entity) self.target = entity end However the following code fixes the problem, for some reason without using AddRef: function Script:UpdateWorld() if self.target ~= nil and self.target.script ~= nil then self.target:GetPosition(true) end end function Script:Insert(entity) self.target = entity end Don't ask my how that came in my mind ^^ but why does it actually fix the crashing... Quote Link to comment Share on other sites More sharing options...
Solution Josh Posted January 30, 2018 Solution Share Posted January 30, 2018 Your second example is reading the script member of an invalid pointer, or the pointer may be reallocated for another object. You should be doing something like this: function Script:SetTarget(target) if target~=self.target then if self.target~=nil then self.target:Release() end self.target = target if self.target~=nil then self.target:AddRef() end end end function Script:Detach() self:SetTarget(nil) end Quote My job is to make tools you love, with the features you want, and performance you can't live without. Link to comment Share on other sites More sharing options...
Phodex Games Posted January 30, 2018 Author Share Posted January 30, 2018 9 minutes ago, Josh said: You should be doing something like this: Great this works, totally forgot about the Detach function. Thank you you saved me a lot of time Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.