RoyNexus
RoyNexus3mo ago

How can I have a singleton custom Realtime Component in scene

I have an instance of a custom Realtime Component syncing data over the network. Here's what I want: 1- When first client connects, it instantiates the Component's model to an initial data state. 2 - When the second client connects, it should detect that the same Component's model's was already instantiated with a default state by the first client, so this second client only has to replicate the state on the scene. I've done experiments with the isFreshModel flag inside the OnRealtimeModelReplaced function but, for the second client it seems to be called twice, once when it first connects, and has a default valued currentModel. And then a second time, when it gets the actual data set by the first client. This behaviour seems odd, I would expect the currentModel have the data set up by the first client filled in on the first OnRealtimeModelReplaced call. Am I thinking of the sync model lifecycle wrong? How can I accomplish the desired behaviour described above?
4 Replies
kapa.ai
kapa.ai3mo ago
Hi @RoyNexus. 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, the OnRealtimeModelReplaced method is called when a RealtimeComponent is first created and it starts with no model. Normcore populates it once we have successfully connected to the server (or instantly, if we're already connected) and calls OnRealtimeModelReplaced() to provide us with a copy of it. If this RealtimeComponent was previously mapped to a different model (e.g., when switching rooms), it will provide a reference to the previous model in order to allow your component to unregister from events source (https://normcore.io/documentation/realtime/synchronizing-custom-data#creating-a-realtimecomponent-subclass). The isFreshModel flag is used to check if the model is a fresh one or an existing one. If it's fresh, you can populate it with the initial data state. If it's not fresh, it means the model already exists and you can just replicate the state on the scene source (https://normcore.io/documentation/realtime/realtimecomponent#using-a-model). As for the OnRealtimeModelReplaced being called twice for the second client, it might be due to the fact that when the second client connects, the RealtimeComponent starts with no model and then gets populated with the actual data set by the first client. This could explain why OnRealtimeModelReplaced is called twice. To accomplish the desired behavior, you could add a check in the OnRealtimeModelReplaced method to see if the currentModel is null or has default values. If it does, you can skip the rest of the method. This way, the method will only run once when the actual data set by the first client is received. Here's a simple example of how you could implement this:
protected override void OnRealtimeModelReplaced(ColorSyncModel previousModel, ColorSyncModel currentModel) {
if (currentModel == null || currentModel.HasDefaultValues()) {
// Skip the rest of the method
return;
}
// Rest of the method
}
protected override void OnRealtimeModelReplaced(ColorSyncModel previousModel, ColorSyncModel currentModel) {
if (currentModel == null || currentModel.HasDefaultValues()) {
// Skip the rest of the method
return;
}
// Rest of the method
}
Please note that HasDefaultValues is a hypothetical method and you would need to implement a way to check if the currentModel has default values or not. Remember to also unregister from events of the previous model to avoid memory leaks and unexpected behavior:
if (previousModel != null) {
// Unregister from events
previousModel.colorDidChange -= ColorDidChange;
}
if (previousModel != null) {
// Unregister from events
previousModel.colorDidChange -= ColorDidChange;
}
I hope this helps! Let me know if you have any other questions. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3mo ago
<@362795742198235136> kapa.ai is still learning and improving, please let us know how it did by reacting below
Mechabit
Mechabit3mo ago
the only way you'll get 2 isFreshModel flags is if 2 instances of the model exists in the scene the solution is to use a scene view model instead of instantiating it
maxweisel
maxweisel3mo ago
you’re going to get it twice for things in the scene if they’re not the first to join. A model is put in place before you connect, and if you’re the first to connect, your model is added to the datastore, but if you’re the second to connect, your model is replaced (this is the second call you’re seeing) with the one that’s already in the datastore. However that second one shouldn’t have isFreshModel set to true. If you’re seeing that, make sure you have at least one model property on the model.