Jump to content

Safley Release An Entity


Phodex Games
 Share

Go to solution Solved by Josh,

Recommended Posts

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

Link to comment
Share on other sites

10 hours ago, Josh said:

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.

Link to comment
Share on other sites

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

  • Thanks 1

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

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

Link to comment
Share on other sites

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

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

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. 

Link to comment
Share on other sites

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
	}
}

 

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

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 :(

Link to comment
Share on other sites

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 :D)

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

Link to comment
Share on other sites

  • Solution

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

 

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

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.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...