How do i use with pool manager

I recently got A* Pathfinding Project Pro and am trying to use it with Pathological Games Pool Manager.

And I have a question about using A* with PoolManger.

Now before I ask my question let me give you a little bit of a background as to what is going on so you can better understand my question.

I have a large number of enemies that I use the Pool Manager to manage.

These enemies among other things have a Wonder, Vision, Auditory, Damage, Attack, Seeker, Funnel Modifier and an and AI components.

The AI component extends AIPath and is where the magic happens.

The enemies use vision/auditory/damage components to control when they have a target.

We also have spawners which also use vision/auditory components to determine when a player comes into visual or auditory range of the spawner and if so prespawn enemies using a pool manager to spawn enemies as needed.

When an enemy is killed the target, some other player, by some ai logic or because it wonders out of range of the players the AI logic uses the pool manager to despawn it.

Instantiate() and Destroy() are never directly called by our code. The pool manager calls these as needed and we do not want to change any of that logic since it’s a 3rd party component.

So once we have an enemy if the vision/auditory system sees or hears a possible target it will call something like TargetInSite(Transform target) .

Likewise if the player attacks the enemy from outside it’s visual/auditory range the Damage system will call something like OnHit(Hit hit).

So it is TargetInSite() that will be calling A* system to get a path to target and the seeker will be used to take it to the target.

Likewise OnHit will use Wonder component to look in the direction the the hit came from and also if visual/auditory target could not be find.

Basically Wonder has the enemy looking around for a target for a little bit.

Regardless if all players go out of range the AI despawns them anyways.

Q. Now that I laid it out for you the question that I have is if the enemy is killed for any reason the pool manager is called to despawn the enemy then what do I have to clean up with respect to A*.

If the enemy was using A* to seek a target I’m guessing there is a path that the Seeker was using and perhaps some coroutine or native thread doing the movement of that enemy that was just killed.

Also what if its in the middle of finding a path. How do I tell A* forget about it there is no longer a need for you to find a path and there is no longer a need to cal OnPathComplete(). In fact its not good if it did called OnPathComplete(), since its no longer valid. But the thing is I’m not handling OnPathComplete() AIPath is.

The pool manager calls OnSpawned() and OnDespawned() which I have overridden in my AI so I can clean up stuff, like A*. So my AI extends AIPath and I have a Seeker component. How do I tell them the enemy is dead, give up seeking him. Release any stuff like path that you have. Likewise if the enemy has been spawned by the pool manage how do I tell AIPath and the Seeker the enemy is alive again.

My auditory/vision/hit systems will handle calling for a path and to kick off the seeking, but what, if anything, do I have to do.

I do have a bool called isAlive which I set as needed, but A* does not have the concept.

I do notice that A* Seeker does have OnDestory() and things like ReleaseClaimedPath() and DeregisterModifier(). But if I manually call any of tem in my OnDespawned() dont I sort of have to RegisterModifier() from my OnSpawned()

And then how do I determine if OnPathComplete() is spending and stop call to it. Basically the enemy could be killed before or after or even without there being any call to even SearchPath()/StartPath()

Also it looks like there is a PathPool what if anything do I have to do with regards to any such pool of paths?

There there could be any number of questions that I have not guessed yet. So it would be nice if someone could answer in detail or even have a tutorial or a section in the documentation of how to use A* with pool manager, any pool manager is ok, since they basically do the same thing and basically have their own OnSpawned() / OnDespawned() and the same setup/cleanup would have to happen so that the object being managed by the pool manager should properly work with A*

Thanks in advance!

one correction to my question (where is the edit button when you need it)

re: "If the enemy was using A* to seek a target I’m guessing there is a path that the Seeker was using and perhaps some coroutine or native thread doing the movement of that enemy that was just killed. "

actually the seeker does not use a coroutine / native thread, but i bet when my ai goes to AIPath that is calling into A* and that is using coroutine/native thread to get the path that will be returned to AIPath and that AIPath will give off to the Seeker to use.

Also I’m guessing when the Seeker arrives at the last node in the path it has to cleanup that path somehow…

Still If the enemy is dead I want to stop all these things, I dont want to have build path continue and I dont want the server to continue, etc.

And when the enemy is respawned I want be able to init things properly.

just noticed that Start() in AIPath.cs eventually calls SearchPath() which checks if target is null and if so logs an error. which is a problem cause if despawned target is null and if there is no target cause they are all out of site or if the target is dead there is no target as well
so im going to have to override a bit more of AIPath.cs :frowning:

since its part of the core it would be nice if it handled the case of not being a target easier, since when you Start() there may very well not be a target. There could be like Target = t property or like SetTarget(t) where it set things up. Also like Target=null or ClearTarget() which undoes things and does things like stop path building, and perhaps stops the seeker.

(ok finally found the well hidden edit button, too bad it does not have delete so i could clean up)

also I see OnDestroy() does a release path but it would be good to have like ReleasePath() which OnDestroy() called and I could call from OnDespawned() to release the path… and that something like ClearTarget() could call. Since I dont want to cal OnDestroy() myself since it’s improper use of that method and could in future cause problems like do some other things i would not want to happen in your black box.

Also, OnPathComplete in AIPath needs some check to see if there is even need to so anything. like if target is lost or target is dead or if the enemy which is using the has died or put in pool.

Also it does not look like there is easy way to disable/enable the Seeker. code commented out and not finished. Andit too has OnPathComplete that does not check at all if there is still a need to seek anything. Plus its OnDestroy() there is no undo and it calls OnDestory for startEndModifier…

it looks like a big job to put the round peg in the square peg. others must be using this with pool managers so im hoping someone will pitch in and have an easy enough solution so that i can use this framework.

Hi

Sorry for taking so long time to answer.

After reading this, I made some changes to the AIPath (and RichAI) scripts to make it easier for them to be used with pool managers.

Now if you disable them (so that the OnDisable method gets called), they will clean up all paths, cancel any currently calculating paths and reset all relevant variables. When enabling it again, it will restart the coroutine and start looking for paths, just as it would if it would have been instantiated instead of just enabled.
Try it out in the latest beta (3.3.6). If you do not have the pro version (and thus cannot download the beta), I can give you instructions for how to update the script.

Also, it no longer logs an error and exits the coroutine if the target is null. Instead it silently waits.

hi aron

np, i will try it it when i get a chance

also i had changed the code myself to work around it so i will do a diff and compare with your changes and let you know of anything different that may be important.

other than that thanks adding support for pool manager brings great value to this asset

best of luck

hi again,

here are the changes that i had made to the copy that i had to get it to work with pool manager

AIPath.cs

public virtual void SearchPath () 
{
		if (target == null) 
		{ 
// i had to comment the following out
			// Debug.LogError ("Target is null, aborting all search"); 
			canSearch = false; 
			return; 
		}

then to my code i did

AICharacterController.cs

using PathologicalGames;

[RequireComponent(typeof(CharacterSystem))]
[RequireComponent(typeof(Seeker))]
public class AICharacterController : AIPath 
{
	public bool isdead;	
	
// called to kill the enemy

	public void Kill()
	{
		if(!isdead)
		{
			isdead = true;
			
			StopPathing();
			
			PoolManager.Pools["Enemies"].Despawn(gameObject.transform);
		}
	}
	
// i had to do these things to start a* pathing

	void StartPathing(Transform target)
	{
		if(pathingStopped)
		{
			pathingStopped = false;

			ObjectTarget = target.gameObject;
			this.target = target;
			
			seeker.pathCallback += OnPathComplete;
			
			canSearch = true;
			canSearchAgain = true;
			canMove = true;
		}
	}

 // i had to do these things to stop a* pathing

	void StopPathing()
	{
		if(!pathingStopped)
		{
			pathingStopped = true;
			
			if (path != null)
			{
				path.Release (this);
				
				path = null;
			}
			
			seeker.pathCallback -= OnPathComplete;
			
			canSearch = false;
			canSearchAgain = false;
			canMove = false;
			
			ObjectTarget = null;
			target = null;
		}
	}

// i had to override this method in AIPath class

	void Start ()
	{
		StopPathing ();
		
		base.Start();
	}

// i had to replace this method in AIPath class

	protected new void Update ()
	{
		if(!isdead && !pathingStopped && canMove)
		{
			... my code went here ...
		}
	}

// called by vision system

	void TargetInSight(List<Transform> targets)
	{
		if(!isdead)
		{
			StartPathing(targets[0]);
		}
	}
	
	void TargetOutOfSight(List<Transform> targets)
	{
		if(!isdead)
		{
			StopPathing();
		}
	}

// called by pool manager

	void OnSpawned()
	{
		isdead = false;
	}
	
	void OnDespawned()
	{
		isdead = true;

		StopPathing();
	}