Must all RealtimeViews be instantiated at runtime?
Is it not possible to have a RealtimeView in the scene? Do all RealtimeViews need to be instantiated at runtime? I'm getting this error for RealtimeViews that are already in the scene before runtime:
40 Replies
Hi @Harper. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
No, not all RealtimeViews must be instantiated at runtime. It is possible and common to have RealtimeViews in the scene before runtime. The error message you're seeing is not related to having RealtimeViews in the scene, but rather to how they are being initialized or accessed.
According to the Realtime > RealtimeView documentation, RealtimeViews can exist in the scene, and there's even a specific property called "Scene View UUID" for RealtimeViews that are in the scene:
"The Scene View UUID property will only appear on RealtimeViews that are in the scene. This is a globally unique identifier that is used to synchronize this view's model in the datastore."
The error you're seeing suggests that the RealtimeView's model is null when you're trying to access it. This can happen if you're trying to access the model too early in the lifecycle of the RealtimeView. For scene RealtimeViews, there's a specific initialization process:
1.
Awake()
and Start()
run, and RealtimeView registers with Realtime.
2. Realtime creates an empty model for every view and component.
3. When Realtime connects to a room, it either inserts the model into the datastore (if it's new) or populates it with existing state from the server.
4. Realtime.connected
becomes true and Realtime.didConnectToRoom
fires.
As mentioned in the Realtime > Common Questions documentation:
"If you're dealing with a RealtimeView that exists in a scene file, you'll need to wait until realtime.connected == true
, or the didConnectToRoom
event has fired."
To resolve your issue, make sure you're not trying to access the RealtimeView's model before Realtime has connected to the room. You can either check realtime.connected
or use the didConnectToRoom
event to ensure you're accessing the model at the right time.
Here's an example of how you might structure your code:
By following this approach, you should be able to use RealtimeViews that are already in your scene without encountering the null model error.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Understood, got it
that just means you're accessing the model before connection was complete or you're switching scenes in the middle of connection or similar
Yeah that makes since - I think this is happening in my update loop. So, I should wait for the connection to finish before proceeding with update.
A stack trace for this error would be really useful...
@kapa.ai I have updated my code and still receive the same errror.
Let me check the knowledge base for you again. One moment! :books:
----------------------
Thank you for providing your updated code. It seems you're on the right track, but there might still be an issue with how you're accessing the RealtimeView's model. Let's take a closer look at the problem and how to resolve it.
The error you're seeing suggests that the RealtimeView's model is still null when you're trying to access it. This can happen if you're interacting with the RealtimeView before it's fully initialized, even if you're waiting for the room connection.
According to the Realtime > Common Questions documentation, there's a specific order of operations for scene RealtimeViews:
1.
Awake()
and Start()
run, and RealtimeView registers with Realtime.
2. Realtime creates an empty model for every view and component and sets the model on each, triggering an OnRealtimeModelReplaced()
call.
3. When Realtime connects to a room, if an object in the scene doesn't exist, its model is inserted into the datastore. If the object already exists, Realtime creates a new RealtimeModel, populates it with the state from the server, and replaces the model again, triggering another OnRealtimeModelReplaced()
call.
4. Realtime.connected
becomes true and Realtime.didConnectToRoom
fires.
To ensure you're interacting with the RealtimeView only after its model is fully initialized, you should use the OnRealtimeModelReplaced()
method in your RealtimeComponent. Here's an example of how you might structure your code:
In this updated code:
1. We add an isModelReady
flag to ensure we only interact with the model after it's been properly initialized.
2. We implement the OnRealtimeModelReplaced()
method, which is called when the RealtimeModel is set or updated.
3. In the Update()
method, we check both isConnected
and isModelReady
before proceeding with any model interactions.
This approach ensures that you're only interacting with the RealtimeView's model after both the room connection is established and the model is properly initialized.
If you're still encountering issues after implementing these changes, it might be helpful to review the Realtime > RealtimeComponent documentation for more detailed information on the lifecycle and proper usage of RealtimeComponents.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai so the connection to realtime and the connection to the model happen at different times?
Let me check the knowledge base for you again. One moment! :books:
----------------------
Yes, you're correct. The connection to Realtime and the initialization of the RealtimeView's model happen at different times, and it's important to understand this sequence to properly work with Normcore.
According to the Realtime > Common Questions documentation, the process for scene RealtimeViews follows this order:
1. First,
Awake()
and Start()
methods run, and the RealtimeView registers with Realtime.
2. Then, Realtime creates an empty model for every view and component, and sets these models, triggering an initial OnRealtimeModelReplaced()
call.
3. When Realtime actually connects to a room, it either inserts new models into the datastore or populates existing ones with state from the server. This triggers another OnRealtimeModelReplaced()
call.
4. Finally, Realtime.connected
becomes true, and the Realtime.didConnectToRoom
event fires.
This sequence means that:
1. The connection to Realtime (step 4) happens after the initial model creation (step 2).
2. The model might be replaced or updated when the actual room connection is established (step 3).
That's why it's recommended to use both the didConnectToRoom
event and the OnRealtimeModelReplaced()
method to ensure you're working with a fully initialized and up-to-date model. The didConnectToRoom
event tells you when you're connected to the room, while OnRealtimeModelReplaced()
informs you when your model is ready or has been updated with the latest data from the server.
This separation allows Normcore to handle various scenarios, such as reconnecting to rooms or dealing with network interruptions, while ensuring that your components always have the most up-to-date data.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@kapa.ai So it can be assumed that when connected the model is loaded?
Let me check the knowledge base for you again. One moment! :books:
----------------------
While it might seem logical to assume that the model is loaded when the connection is established, it's not always safe to make that assumption. Let's clarify this based on the information from the Normcore documentation.
According to the Realtime > Common Questions documentation, the sequence of events for scene RealtimeViews is as follows:
1.
Awake()
and Start()
run, and RealtimeView registers with Realtime.
2. Realtime creates an empty model for every view and component and sets the model on each, triggering an OnRealtimeModelReplaced()
call.
3. When Realtime connects to a room, if an object in the scene doesn't exist, its model is inserted into the datastore. If the object already exists, Realtime creates a new RealtimeModel, populates it with the state from the server, and replaces the model again, triggering another OnRealtimeModelReplaced()
call.
4. Realtime.connected
becomes true and Realtime.didConnectToRoom
fires.
This sequence indicates that while the model is created before the connection is established, it might be replaced or updated with data from the server after the connection. Therefore, it's not entirely safe to assume that the model is fully loaded and up-to-date when didConnectToRoom
fires.
For the most reliable approach, it's recommended to use both the didConnectToRoom
event and the OnRealtimeModelReplaced()
method. This ensures that you're working with a fully initialized and up-to-date model.
Here's a safer way to structure your code:
This approach ensures that you're only interacting with the RealtimeView's model after both the room connection is established and the model is properly initialized and up-to-date.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
@Harper Scene RealtimeViews connect to Realtime in Start() (it's the earliest we can do it). They don't get a model until you connect to the room. You'll want to subscribe to Realtime.didConnectToRoom or check for Realtime.connected == true
more info here:
https://docs.normcore.io/realtime/realtimecomponent#using-views-and-components-in-a-scene
https://docs.normcore.io/realtime/common-questions#why-would-a-realtimecomponents-model-remain-null
@Max That's what I'm doing but still finding that I'm getting an error... I subscribe to a didChange function in OnRealtimeModelReplaced and then access the model in the subscribed function. Could the symptom be there?
hmm, that should work, although generally I recommend subscribing in Awake() on a component in the scene
this is inside of OnRealtimeModelReplaced within a component on the same game object for the view in the scene?
Yes
or are you waiting for a prefab to instantiate, then subscribing to Realtime.onDidConnect, and then using that to operate on a view in the scene?
ok that's really strange. I'd have to see the code then. afaik there's no way for didConnectToRoom to run before the model is set, and the model is being set because OnRealtimeModelReplaced is being called
@Max here's my file. I'm almost certain I'm just overlooking something so I apologize if the solution is obvious! For context this is a controller for a door that swings open and close.
P.S. I have no worries if my model is empty when it is first accessed. A few milliseconds of not being able to use doors is no problem.
Also, I'm on version 2.9.5
Have not updated in a while
My breakpoints don't seem to be triggering in OnRealtimeModelReplaced. I assume it's not on the main thread?
I can dive in a little later but all callbacks are on the main thread
Oh you know what
I think I've found the problem
what was it?
Scratch that never mind! Problem still ever-present.
Weird that OnRealtimeModelReplaced is never called though.
your class looks good at first glance
if you add a debug log instead of a breakpoint is it hit?
also how was your didConnectToRoom event firing if the method you subscribed in was never getting called?
something isn’t adding up
I think there may have been a miscommunication earlier regarding what I was doing with didConnectToRoom
It is not in the OnRealtimeModelReplaced method
It is in awake, and I have also tried putting it in start
Negative
Not sure if this tells you anything but this is what the inspector looks like
Okay. So, I had a suspicion. There are 3 doors, and they are all placed in the scene (not instantiated), but they are also prefabs. I thought: maybe if it's a prefab Normcore assumes it will be instantiated. So, I unpacked all 3 prefabs, and I see no error.
Is this the intended functionality?
Additionally the doors do not seem to be working over the network, so maybe there is something still wrong. But also, I need to be able to use prefabs so I can change all of the doors with ease.
hmm so we assign unique IDs in the scene
and they should show up as modifications on top of the prefab
but it looks like RealtimeView doesn’t recognize it’s in a scene here
there should be additional settings present
will you update to the latest Normcore?
I shall try!
let me see what the inspector looks like for one of the doors in the scene after you do
Should I be concerned about these?
Just noticing my remote client is saying this:
Server rejected add of scene view model, but we found it in the datastore!Not sure if it was there before.
-
On Normcore 2.13.1:
After migrating project settings though I think it might be working. Didn't see the migrate option before.
yeah this looks a lot better
and that error should only happen if two clients fight to initialize the datastore
do you have two Realtime instances connecting to the same room?
the warning is benign but can point to some code smell since it’s a race condition that’s pretty hard to hit
or possibly there are multiple scene views with the same scene view UUID
Error disappeared after migration
sweet
Seems to all be working now minus a bug which I believe is user error
Thanks for all your help!
I'll see if I can solve this bug on my own but otherwise leave this forum open until I do
sure thing! glad you got it working