Download this documentation page as a PDF.

Contents

Photon Unity Networking 2

While Pure Pool includes an integration script for Photon Unity Networking, it's currently designed for the original version of PUN (version 1). If you'd like to use Pure Pool with PUN2, you'll need a slightly different integration script.

Create a new script with the name "PrefabPool.cs", and paste the following code inside it:


using System;

using UnityEngine;

namespace Umbrace.Unity.PurePool.Photon {
	
	using PoolManagerBase = PoolManagerBase<GameObjectPoolManagerSettings,GameObjectPool,GameObjectPoolSettings,GameObject,GameObject>;

	/// <summary>
	/// A bridge class to allow object pooling to be used by Photon Unity Networking 2 (PUN2).
	/// </summary>
	/// <remarks>
	/// <para>
	/// To use this class for pooling with Photon, instantiate a new instance of it, set the <see cref="Manager"/> property, and assign the instance to <c>PhotonNetwork.PrefabPool</c>.
	/// </para>
	/// <para>
	/// Please note that pooled GameObjects don't get the usual Awake and Start calls. OnEnable will be called (by your pool) but the
	/// networking values are not updated yet when that happens. OnEnable will have outdated values for PhotonView (isMine, etc.).
	/// You might have to adjust scripts.
	/// </para>
	/// <para>
	/// PUN will call OnPhotonInstantiate (see IPunInstantiateMagicCallback). This should be used to setup the re-used object with regards to networking values / ownership. 
	/// </para>
	/// </remarks>
	public class PrefabPool : IPunPrefabPool {

		private NamedGameObjectPoolManager manager;
		private readonly Dictionary<string, GameObject> resourceCache = new Dictionary<string, GameObject>();

		/// <summary>
		/// Gets or sets the pool manager to be used by Photon.
		/// </summary>
		/// <remarks>
		/// The <see cref="NamedGameObjectPoolManager"/> assigned to this property must meet the following requirements:
		/// <list type="bullet">
		/// <item><description><see cref="NamedGameObjectPoolManager.UseResources"/> must be set to true.</description></item>
		/// <item><description>The <see cref="PoolManagerBase.AcquireMode"/> property of <see cref="NamedGameObjectPoolManager.Manager"/> must be set to <see cref="AcquireNoPoolMode.Instantiate"/> or <see cref="AcquireNoPoolMode.CreatePool"/>.</description></item>
		/// <item><description>In the case of <see cref="AcquireNoPoolMode.CreatePool"/>, the <see cref="SharedPoolSettings{TSource}.InstantiateWhenEmpty"/> property of <see cref="PoolManagerBase.DefaultPoolSettings"/> must be set to true.</description></item>
		/// </list>
		/// </remarks>
		public NamedGameObjectPoolManager Manager {
			get { return this.manager; }
			set {
				if (value == null) throw new ArgumentNullException();

				// Ensure Resources.Load is allowed. Unlikely all prefab names will have been set up in the manager.
				if (!value.UseResources) throw new ArgumentException("The manager must be set to load from Resources to use it with Photon. Set UseResources to true.");

				// Ensure an instance can always be acquired, even when no pool exists.
				if (value.Manager.AcquireMode == AcquireNoPoolMode.Error) throw new ArgumentException("The manager must be set to an AcquireMode that always allows instantiation. Set AcquireMode to CreatePool or Instantiate.");
				if (value.Manager.AcquireMode == AcquireNoPoolMode.CreatePool && !value.Manager.DefaultPoolSettings.InstantiateWhenEmpty) {
					throw new ArgumentException("The manager must be set to always allow instantiation." +
												"When using an AcquireMode of CreatePool, set DefaultPoolSettings.InstantiateWhenEmpty to true.");
				}

				this.manager = value;
			}
		}

		/// <inheritdoc />
		public void Destroy(GameObject gameObject) {
			this.manager.Release(gameObject);
		}

		/// <inheritdoc />
		public GameObject Instantiate(string prefabId, Vector3 position, Quaternion rotation) {
			GameObject instance;

			// Check the resourceCache for the prefab, to avoid calling Resources.Load unnecessarily.
			GameObject prefab;
			if (this.resourceCache.TryGetValue(prefabId, out prefab)) {
				if (this.manager.Manager.TryAcquire(prefab, position, rotation, out instance)) {
					return instance;
				}

				// This should never occur, as an instance should always be available.
				return null;
			}
			
			// Try to acquire by a pre-defined name.
			if (this.manager.HasName(prefabId)) {
				if (this.manager.TryAcquire(prefabId, position, rotation, out instance)) {
					return instance;
				}
				
				// This should never occur, as an instance should always be available.
				return null;
			}
			
			// Fallback to using Resources.Load, as there is no pre-defined name registered.
			prefab = Resources.Load<GameObject>(prefabId);
			if (prefab != null && this.manager.Manager.TryAcquire(prefab, position, rotation, out instance)) {
				this.resourceCache[prefabId] = prefab;
				return instance;
			}

			// No instance could be acquired. This should only occur if the prefab ID is not valid (no resource file with that name).
			return null;
		}

	}

}

With the new integration script added to your project, you can hook it up to PUN2 by following the Integration Script Usage section of the original PUN guide.

In a future version of Pure Pool, the PUN2 integration script will be included by default.