gubebra
gubebra7d ago

Best way to fire VFX events?

I want to do a system that can fire VFX across clients, something like
VFXSyncManager.FireVFXSynced(vfxList[vfxIndex]);
VFXSyncManager.FireVFXSynced(vfxList[vfxIndex]);
What is the best way to do this? Should I use a RealtimeDictionary?
11 Replies
kapa.ai
kapa.ai7d 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: ---------------------- Based on the information provided in the knowledge sources, I can suggest an approach for firing VFX events across clients in NormalVR. While using a RealtimeDictionary is possible, there's a more direct method that aligns with your requirement. The recommended approach is to use a custom RealtimeComponent with a RealtimeModel to create an RPC-like event system. Here's how you can implement this: 1. Create a custom RealtimeModel for your VFX event:
[RealtimeModel]
public partial class VFXEventModel {
[RealtimeProperty(1, true)] private int _trigger;
[RealtimeProperty(2, true)] private int _senderID;
[RealtimeProperty(3, true)] private int _vfxIndex;
// Add other properties as needed

public void FireEvent(int senderID, int vfxIndex) {
this.trigger++;
this.senderID = senderID;
this.vfxIndex = vfxIndex;
}

public delegate void EventHandler(int senderID, int vfxIndex);
public event EventHandler eventDidFire;

[RealtimeCallback(RealtimeModelEvent.OnDidRead)]
private void DidRead() {
if (eventDidFire != null && trigger != 0)
eventDidFire(senderID, vfxIndex);
}
}
[RealtimeModel]
public partial class VFXEventModel {
[RealtimeProperty(1, true)] private int _trigger;
[RealtimeProperty(2, true)] private int _senderID;
[RealtimeProperty(3, true)] private int _vfxIndex;
// Add other properties as needed

public void FireEvent(int senderID, int vfxIndex) {
this.trigger++;
this.senderID = senderID;
this.vfxIndex = vfxIndex;
}

public delegate void EventHandler(int senderID, int vfxIndex);
public event EventHandler eventDidFire;

[RealtimeCallback(RealtimeModelEvent.OnDidRead)]
private void DidRead() {
if (eventDidFire != null && trigger != 0)
eventDidFire(senderID, vfxIndex);
}
}
2. Create a RealtimeComponent to use this model:
public class VFXEvent : RealtimeComponent<VFXEventModel> {
[SerializeField]
private List<ParticleSystem> vfxList = new List<ParticleSystem>();

protected override void OnRealtimeModelReplaced(VFXEventModel previousModel, VFXEventModel currentModel) {
if (previousModel != null) {
previousModel.eventDidFire -= EventDidFire;
}
if (currentModel != null) {
currentModel.eventDidFire += EventDidFire;
}
}

public void FireVFXSynced(int vfxIndex) {
model.FireEvent(realtime.clientID, vfxIndex);
}
private void EventDidFire(int senderID, int vfxIndex) {
if (vfxIndex >= 0 && vfxIndex < vfxList.Count) {
vfxList[vfxIndex].Play();
}
}
}
public class VFXEvent : RealtimeComponent<VFXEventModel> {
[SerializeField]
private List<ParticleSystem> vfxList = new List<ParticleSystem>();

protected override void OnRealtimeModelReplaced(VFXEventModel previousModel, VFXEventModel currentModel) {
if (previousModel != null) {
previousModel.eventDidFire -= EventDidFire;
}
if (currentModel != null) {
currentModel.eventDidFire += EventDidFire;
}
}

public void FireVFXSynced(int vfxIndex) {
model.FireEvent(realtime.clientID, vfxIndex);
}
private void EventDidFire(int senderID, int vfxIndex) {
if (vfxIndex >= 0 && vfxIndex < vfxList.Count) {
vfxList[vfxIndex].Play();
}
}
}
This approach allows you to fire VFX events across clients in a way similar to your desired syntax:
GetComponent<VFXEvent>().FireVFXSynced(vfxIndex);
GetComponent<VFXEvent>().FireVFXSynced(vfxIndex);
This method is based on the RPC Events recipe provided in the NormalVR documentation Recipe: RPC Events (https://normcore.io/documentation/guides/recipes/rpc-events#recipe). It uses a RealtimeModel to synchronize the event data and a RealtimeComponent to handle the event firing and receiving. However, it's important to note that the documentation warns against overusing this RPC-like pattern: "I still recommend avoiding this pattern if you can. Any state that is modified in response to an event like this can easily diverge between clients." Recipe: RPC Events (https://normcore.io/documentation/guides/recipes/rpc-events#recipe) For simple VFX events that don't affect game state, this approach should work well. If you need more complex synchronization or state management, you might want to consider using other Normcore features like RealtimeSet or RealtimeDictionary Non-transactional collections (https://normcore.io/documentation/room/collections#non-transactional-collections). ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7d ago
<@599054560270483456> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mechabit
Mechabit7d ago
the easiest method is to instantiate a prefab with the VFX on it
gubebra
gubebraOP7d ago
One thing to note is that there's a possibility that multiple people will try to fire the same event, and I should fire all of them (same VFX other part of the map) And how would I fire the event? Using a RealtimeModel?
Mechabit
Mechabit7d ago
the prefab will play on start and then destroy itself when it's done for performance you use pooling
gubebra
gubebraOP7d ago
yeah but I still need to trigger the VFX event. I want to just call a function that instantiates/activate a VFX whenever I need it
Mechabit
Mechabit7d ago
if you don't want to instantiate a prefab you can use a realtime set players add models to the set and everyone listens for models being added the model would contain VFX index and position etc.
Mechabit
Mechabit7d ago
FYI you do networked pooling with PrefabLoadDelegate https://normcore.io/documentation/guides/recipes/using-addressables
Using Addressables | Normcore Documenation
By default, Normcore loads all realtime prefabs using Resources.Load(). For larger projects, this can cause performance issues when loading prefabs from disk. It can also be a pain run a large project with multiple Resources folders.
Mechabit
Mechabit7d ago
for when you need to spawn lots of effects or objects you just pass in one of the pooled objects when someone calls Realtime.Instantiate
gubebra
gubebraOP7d ago
thanks mecha, i'll take a look at it I'm still a bit lost in terms of the networked data structure choice. In a nutshell I need something simple like sending an event, possibly with just id and position, which can be triggered multiple times (the vfx idx can be called by a lot of users at the same time). You recommend me using a RealtimeSet?
Mechabit
Mechabit7d ago
I suggest Realtime.Instantiate a prefab, don't need any extra models or listeners or anything