gubebra
gubebra2mo ago

How to use PrefabLoadDelegate to do object pooling?

I want to do an object pool, that when I call instantiate the code instead takes the object from the pool across all clients. How can I use PrefabLoadDelegate to achieve this?
15 Replies
kapa.ai
kapa.ai2mo ago
Hi @gubebra. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- To implement object pooling for realtime prefabs across all clients using PrefabLoadDelegate in NormalVR, you'll need to use the IRealtimePrefabInstantiateDelegate interface rather than IRealtimePrefabLoadDelegate. The IRealtimePrefabInstantiateDelegate is specifically designed for instantiating and destroying prefab instances, which is ideal for implementing object pooling. Here's a general approach to achieve this: 1. Create a class that implements IRealtimePrefabInstantiateDelegate. 2. In this class, implement the object pool logic. 3. Use the InstantiateRealtimePrefab method to return objects from the pool instead of creating new instances. 4. Use the DestroyRealtimePrefab method to return objects to the pool instead of destroying them. Here's a basic example of how you might structure this:
using UnityEngine;
using Normal.Realtime;
using System.Collections.Generic;

public class RealtimePrefabPool : IRealtimePrefabInstantiateDelegate
{
private Dictionary<string, Queue<GameObject>> pools = new Dictionary<string, Queue<GameObject>>();

public GameObject InstantiateRealtimePrefab(GameObject prefab)
{
string prefabName = prefab.name;
if (!pools.ContainsKey(prefabName))
{
pools[prefabName] = new Queue<GameObject>();
}

if (pools[prefabName].Count > 0)
{
GameObject instance = pools[prefabName].Dequeue();
instance.SetActive(true);
return instance;
}
else
{
return Object.Instantiate(prefab);
}
}

public void DestroyRealtimePrefab(GameObject prefabInstance)
{
string prefabName = prefabInstance.name.Replace("(Clone)", "");
prefabInstance.SetActive(false);
pools[prefabName].Enqueue(prefabInstance);
}
}
using UnityEngine;
using Normal.Realtime;
using System.Collections.Generic;

public class RealtimePrefabPool : IRealtimePrefabInstantiateDelegate
{
private Dictionary<string, Queue<GameObject>> pools = new Dictionary<string, Queue<GameObject>>();

public GameObject InstantiateRealtimePrefab(GameObject prefab)
{
string prefabName = prefab.name;
if (!pools.ContainsKey(prefabName))
{
pools[prefabName] = new Queue<GameObject>();
}

if (pools[prefabName].Count > 0)
{
GameObject instance = pools[prefabName].Dequeue();
instance.SetActive(true);
return instance;
}
else
{
return Object.Instantiate(prefab);
}
}

public void DestroyRealtimePrefab(GameObject prefabInstance)
{
string prefabName = prefabInstance.name.Replace("(Clone)", "");
prefabInstance.SetActive(false);
pools[prefabName].Enqueue(prefabInstance);
}
}
To use this pool, you would need to set it up with your Realtime instance:
RealtimePrefabPool pool = new RealtimePrefabPool();
realtime.prefabInstantiateDelegate = pool;
RealtimePrefabPool pool = new RealtimePrefabPool();
realtime.prefabInstantiateDelegate = pool;
This approach ensures that when Realtime.Instantiate() is called, it will use your custom pooling logic across all clients. The InstantiateRealtimePrefab method will either return an object from the pool or create a new one if the pool is empty. The DestroyRealtimePrefab method will return objects to the pool instead of destroying them. Remember that this is a basic implementation and you might need to adjust it based on your specific needs, such as pre-populating the pool, handling different prefab types, or managing pool sizes. For more details on the IRealtimePrefabInstantiateDelegate interface, you can refer to the NormalVR documentation on IRealtimePrefabInstantiateDelegate (https://normcore.io/documentation/reference/classes/Normal.Realtime.IRealtimePrefabInstantiateDelegate). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@599054560270483456> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
gubebra
gubebraOP2mo ago
@Normcore Assistant what is
realtime
realtime
in your example?
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- The realtime in the example refers to an instance of the Realtime component in NormalVR. The Realtime component is a crucial part of the NormalVR framework that manages connections to a room and handles synchronization of RealtimeViews across multiple clients. According to the NormalVR documentation on Realtime (https://normcore.io/documentation/realtime/realtime):
Realtime is the component that manages your connection to a room as well as any RealtimeViews that should be connected to the room's datastore. Use the Realtime component to connect to a room, instantiate realtime prefabs, and query any state about the room.
In the context of the object pooling example, realtime would be a reference to the Realtime component in your scene. You would typically get this reference in your script, often in the Awake() or Start() method, like this:
private Realtime _realtime;

private void Awake() {
// Get the Realtime component on this game object
_realtime = GetComponent<Realtime>();
}
private Realtime _realtime;

private void Awake() {
// Get the Realtime component on this game object
_realtime = GetComponent<Realtime>();
}
Then, you can use this _realtime reference to set up the prefab instantiate delegate for object pooling:
RealtimePrefabPool pool = new RealtimePrefabPool();
_realtime.prefabInstantiateDelegate = pool;
RealtimePrefabPool pool = new RealtimePrefabPool();
_realtime.prefabInstantiateDelegate = pool;
This setup ensures that when you use Realtime.Instantiate() to create objects in your multiplayer application, it will use your custom pooling logic across all connected clients. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@599054560270483456> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
gubebra
gubebraOP2mo ago
@Normcore Assistant I don't want every realtime.Instantiate() to call the pooling function, just when I call it from a specific place for a specific object for example
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- To achieve selective object pooling for specific instances of Realtime.Instantiate(), you can modify your approach to use InstantiateOptions when calling Realtime.Instantiate(). This allows you to specify a custom IRealtimePrefabInstantiateDelegate for individual instantiations. Here's how you can implement this: 1. First, create your object pool class as before, implementing IRealtimePrefabInstantiateDelegate. 2. Instead of setting this pool as the global delegate for your Realtime instance, you'll use it selectively when instantiating. Here's an example of how to use it:
// Your object pool implementation
RealtimePrefabPool pool = new RealtimePrefabPool();

// When you want to use the pool for a specific instantiation
GameObject pooledObject = Realtime.Instantiate(
"YourPrefabName",
new Realtime.InstantiateOptions {
prefabInstantiateDelegate = pool
}
);

// When you don't want to use the pool
GameObject normalObject = Realtime.Instantiate("YourPrefabName");
// Your object pool implementation
RealtimePrefabPool pool = new RealtimePrefabPool();

// When you want to use the pool for a specific instantiation
GameObject pooledObject = Realtime.Instantiate(
"YourPrefabName",
new Realtime.InstantiateOptions {
prefabInstantiateDelegate = pool
}
);

// When you don't want to use the pool
GameObject normalObject = Realtime.Instantiate("YourPrefabName");
This approach allows you to use the object pool only when you explicitly specify it, giving you fine-grained control over which objects are pooled. The Realtime.Instantiate() method accepts an InstantiateOptions parameter, which can include a custom prefabInstantiateDelegate. This delegate will be used for that specific instantiation only, overriding the default behavior for that call. You can find more information about the Realtime.Instantiate() method and its options in the NormalVR documentation on Realtime static methods (https://normcore.io/documentation/reference/classes/Normal.Realtime.Realtime). Remember, this approach requires you to explicitly specify the pool each time you want to use it, which gives you more control but also requires more careful management in your code. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@599054560270483456> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
gubebra
gubebraOP2mo ago
@Normcore Assistant I'm getting
'Realtime.InstantiateOptions' does not contain a definition for 'prefabInstantiateDelegate'
'Realtime.InstantiateOptions' does not contain a definition for 'prefabInstantiateDelegate'
kapa.ai
kapa.ai2mo ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- I apologize for the confusion in my previous response. It seems I made an error in describing the InstantiateOptions structure. Let me provide you with the correct information based on the available NormalVR documentation. The error you're encountering suggests that prefabInstantiateDelegate is not a property of Realtime.InstantiateOptions. After reviewing the documentation, I can confirm that this property indeed doesn't exist in the InstantiateOptions structure. Instead, the Realtime.Instantiate() method uses the prefabInstantiateDelegate that is set on the Realtime component itself. This means that to use a custom instantiate delegate for specific objects, you would need to temporarily change the delegate on the Realtime instance, instantiate your object, and then reset it. Here's how you could modify your approach:
// Your object pool implementation
RealtimePrefabPool pool = new RealtimePrefabPool();

// Store the original delegate
var originalDelegate = realtime.prefabInstantiateDelegate;

// Set the pool as the temporary delegate
realtime.prefabInstantiateDelegate = pool;

// Instantiate your object
GameObject pooledObject = Realtime.Instantiate("YourPrefabName");

// Reset to the original delegate
realtime.prefabInstantiateDelegate = originalDelegate;
// Your object pool implementation
RealtimePrefabPool pool = new RealtimePrefabPool();

// Store the original delegate
var originalDelegate = realtime.prefabInstantiateDelegate;

// Set the pool as the temporary delegate
realtime.prefabInstantiateDelegate = pool;

// Instantiate your object
GameObject pooledObject = Realtime.Instantiate("YourPrefabName");

// Reset to the original delegate
realtime.prefabInstantiateDelegate = originalDelegate;
This approach allows you to use the object pool for specific instantiations while keeping the default behavior for others. However, it's important to note that this method isn't thread-safe and could lead to issues in multi-threaded scenarios. For more information on the Realtime.Instantiate() method and its options, you can refer to the NormalVR documentation on Realtime static methods (https://normcore.io/documentation/reference/classes/Normal.Realtime.Realtime). I apologize again for the earlier misinformation. If you need a more robust solution for selective object pooling, you might need to implement a custom system or reach out to the NormalVR support for advanced customization options. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai2mo ago
<@599054560270483456> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mechabit
Mechabit2mo ago
if you don't want to use a pooled object just pass in a regular Instantiated one
gubebra
gubebraOP2mo ago
I actually want to do object pooling. I just don't know how to use IRealtimePrefabInstantiateDelegate to do this. I already have a pool in place and working locally
Mechabit
Mechabit2mo ago
the addessables doc has it laid out pretty clearly just swap in the pooled object instead of an addressable you also add this script to the same game object as the Realtime instance in the scene
gubebra
gubebraOP2mo ago
alright thanks