Is Object Pooling Possible?

I’m in the process of converting my Photon code to UNet and I’m stuck at the moment when it comes to object pooling. Does anyone know if pooling is possible with UNet or am I going to have to use regular create/destroy for now?

Yes! There are span handles you can override. Remove your Prefabs from the spawn registration in the editor, and override the on spawn and on despawn methods.

On the server, get an object from the pool and call NetworkServer.Spawn. On the client, get your object and return it from your spawn handler.

To return to pool, I recommend using custom messages as, while Network.Destroy will trigger the on despawn override on the client, it seems to also destroy the object on the server. Using custom messages you can handle returning to pool in your own way.

Check docs for method override names. :slight_smile:

Alright I kinda get it, but where do I find the OnSpawn/OnDespawn method? There doesn’t seem to be any in NetworkManager
http://docs.unity3d.com/ScriptReference/Networking.NetworkManager.html
And a quick search leads to no results.
Here’s my code btw (which is atm broken because I was in the mid process of experimenting with how to go about it).

using UnityEngine;
using UnityEngine.Networking;
using System;
using System.Collections;
using System.Collections.Generic;

public class GameObjectPoolManager : NetworkBehaviour {

    public static GameObjectPoolManager current;
    private List<GameObject> ObjectList = new List<GameObject>();
    private bool WillGrow = true;
    public List<GameObject> ObjectsToReadyUp = new List<GameObject>();
    public float AmountToReady = 2;

    public void Awake(){
        WillGrow = true;
        current = this;
        CmdCreateExtra();
    }

    [Command]
    public void CmdCreateExtra() {
        if (ObjectsToReadyUp != null) {
            for (int i = 0; i < ObjectsToReadyUp.Count; i++) {
                for (int w = 1; w < AmountToReady; w++) {
                    GameObject temp = null;
                    temp = (GameObject)Instantiate(ObjectsToReadyUp[i], new Vector3(0, 100, 0), Quaternion.identity);
                    ObjectList.Add(temp);
                    temp.SetActive(false);
                    NetworkServer.Spawn(temp);
                }
            }
        }
    }

    [Command]
    public GameObject CmdCreateObject(GameObject GO, Vector3 Position, Quaternion Rotation){

        for(int i=0; i < ObjectList.Count; i++){
            if(ObjectList[i].name == GO.name || ObjectList[i].name == GO.name + "(Clone)"){
                if(ObjectList[i].activeSelf == false){
                    ObjectList[i].SetActive(true);
                    ObjectList[i].transform.position = Position;
                    ObjectList[i].transform.rotation = Rotation;
                    return ObjectList[i];
                }
            }
        }

        if (WillGrow) {
            GameObject temp = null;
            temp = (GameObject)Instantiate(GO, Position, Rotation);
            ObjectList.Add (temp);
            NetworkServer.Spawn(temp);
            return temp;
        }

        return null;
    }

    [Command]
    public void CmdDestroyObject(GameObject GO){
        GO.SetActive (false);
    }

    [Command]
    public void CmdDestroyAfter(GameObject GO, float time){
        StartCoroutine (DisableObj (GO, time));
    }

    public IEnumerator DisableObj(GameObject GO, float time){
        yield return new WaitForSeconds (time);
        if (GO != null) {
            GO.SetActive (false);
        }
    }
}

Sorry my memory is a bit poor there. It isn’t an override. You register spawn and despawn handlers via ClientScene.RegisterSpawnHandler.

Have a read here:
http://docs.unity3d.com/Manual/UNetSpawning.html

I’m also implementing object pooling. The thing I don’t quite understand 100% yet myself is despawning. You would normally call NetworkServer.Destroy (i think) which would trigger the despawn handler on the client. I was having null reference exceptions on the server so I believe it is destroying the object on the server. That’s why I used messages instead. However I now wonder if NetworkServer.Destroy handles management of anything else… This is probably something we’ll both need to find out. Is it safe to despawn without using NetworkServer.Destroy?

1 Like

I’m having difficulty with this myself now. I think I need to use NetworkServer.Destroy to handle the removal of network observers or something, but at the same time I don’t want to destroy the object. If I can figure out more I’ll let you know.

If anyone else knows more about this, would love to hear about it.

1 Like

@Shinyclef I’m going to have a look at this myself later today as I will need to do pooling. But have you tried to just remove/add observers yourself manually along with your message that activates/deactivates(that’s what your doing right?) that gameobject? Observers is just a list of NetworkConnections. You can force a set of observers to be rebuilt when you want also. I don’t have the code in front of me but I feel there should be a way from what I’ve read to make this happen with messages… I am going to look at it later and see if I’m understanding the internals right

I would assume instead of trying to destroy the object, you’ll instead disable all the components on it so that it still exist. Then when respawning would have to find a way to change which localplayer owns the object.
For now I’ll default to every player using there own pool, but I would still like to know if it’s possible to have a pool handled by the server.

I’d assumed you would just pool everything on every client, and the server, and have syncvars and some kind of communication for enabling disabling them across all clients… I haven’t actually tried anything yet as I’m still wrapping my head around the API.

Yes you would pool on each client, but you still need to make sure that all active objects are connected via the network appropriately, and disconnected appropriately when returning to pool. Connecting occurs via NetworkServer.Spawn. Disconnecting would usually occur via NetworkServer.Destroy, but that destroys the object on server so is not suitable for pooling. The biggest problem is we don’t actually know very clearly what NetworkServer.Destroy actually does behind the scenes, so it’s difficult to replicate the network management.

I found this in the docs:

Hrmmm wonder if I can figure this out, haha

Yes, I mentioned that in my second post. The rest of the information in this thread still applies.

Doh - totally missed that post! Anyway I have spent days digging into multiplayer but I have been hitting so many roadblocks trying to figure out the basics I haven’t got around to messing with pooling yet. I’ll drop back by when I get there.

Did anyone figure this out yet? I’m currently having a play with the new networking feature and am trying to adapt my object pool to work with it.

Nope not yet. Still getting used to the API really. I think I know what to do though, but haven’t tried it, which is spawn across the network the whole pool on every client, and just pass around vars and changes, then destroy/instantiate more as necessary. No code sample here though haha

I’m not quite sure how to get the object back from client while the SpawnHandler delegate only give you a Vector3 and and assetID.

OnServer:

  • I spawn an object from the pool.
  • Call NetworkServer.Spawn(myobject);

OnClient:

  • The SpawnHandler delegate method get called but how to get my object back? There are only a Vector3 and an assetID and it looks like there is no method to get the prefab from its assetId.

After some minutes digging through all Unet classes in Visual Studio i just magically found out how to get prefab when you know its assetID. Simply call this:

ClientScene.prefabs[assetId]

and it will return the prefab associated with the assetId.
I also tried googling “Unity Unet ClientScene” and there is no relevant result :frowning:

1 Like

@Shinyclef I’m so happy that in the 5.1.2p1 there is a method called “Unspawn” which does excactly what you (and me :smile: ) want. There is no need to implement a custom message system anymore when you want to despawn an object but not destroying it.

Cheers!

1 Like

When I try to spawn on object that was previously unspawned, I get an error that says “Object has non-zero netId.” Is this a bug?

1 Like

hm. that sounds like a bug. I’ll look into it.

1 Like

Same here!
I’m getting crazy trying to reset the netId until i realize that i can’t :frowning:
NetworkInstanceId (netid) is read-only and it locks developers from modifying any of its properties.

At first i though this is by design so i tried a work-arround: When I fill the pool on server with actual clones of object I also NetworkServer.Spawn() it, so the pool is synced across network.

But soon when i need to completely destroy the object across network, NetworkServer.Destroy() also NOT reset the netId as well.

You could run a sample test by some code like this:

NetworkServer.Spawn(go);
NetworkServer.Destroy(go); // You can replace this with "NetworkServer.Unspawn(go)"
NetworkServer.Spawn(go); // Non-zero netId occurs