Harper
Harper2w ago

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:
RealtimeView model is null. Was this view instantiated with GameObject.Instantiate instead of Realtime.Instantiate? Make sure you're passing a prefab name and not a prefab reference to avoid accidentally calling GameObject.Instantiate().
UnityEngine.Debug:LogError (object,UnityEngine.Object)
RealtimeView model is null. Was this view instantiated with GameObject.Instantiate instead of Realtime.Instantiate? Make sure you're passing a prefab name and not a prefab reference to avoid accidentally calling GameObject.Instantiate().
UnityEngine.Debug:LogError (object,UnityEngine.Object)
40 Replies
kapa.ai
kapa.ai2w ago
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:
private void Start()
{
// Find the Realtime instance in your scene
Realtime realtime = FindObjectOfType<Realtime>();

// Subscribe to the didConnectToRoom event
realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime)
{
// Now it's safe to access your RealtimeView's model
// Your code here...
}
private void Start()
{
// Find the Realtime instance in your scene
Realtime realtime = FindObjectOfType<Realtime>();

// Subscribe to the didConnectToRoom event
realtime.didConnectToRoom += DidConnectToRoom;
}

private void DidConnectToRoom(Realtime realtime)
{
// Now it's safe to access your RealtimeView's model
// Your code here...
}
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: ----------------------
kapa.ai
kapa.ai2w ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Harper
HarperOP2w ago
Understood, got it
Mechabit
Mechabit2w ago
that just means you're accessing the model before connection was complete or you're switching scenes in the middle of connection or similar
Harper
HarperOP2w ago
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.
c#
private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime realtime) => isConnected = true;
}

private void Update()
{
if (!isConnected) return;
// Rest of update code ...
}
c#
private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime realtime) => isConnected = true;
}

private void Update()
{
if (!isConnected) return;
// Rest of update code ...
}
kapa.ai
kapa.ai2w ago
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:
public class MyRealtimeComponent : RealtimeComponent<MyModelType>
{
private bool isModelReady = false;

private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime r) => isConnected = true;
}
protected override void OnRealtimeModelReplaced(MyModelType previousModel, MyModelType currentModel)
{
if (currentModel != null)
{
isModelReady = true;
// Initialize your component with the new model here
}
}

private void Update()
{
if (!isConnected || !isModelReady) return;
// Rest of update code ...
}
}
public class MyRealtimeComponent : RealtimeComponent<MyModelType>
{
private bool isModelReady = false;

private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime r) => isConnected = true;
}
protected override void OnRealtimeModelReplaced(MyModelType previousModel, MyModelType currentModel)
{
if (currentModel != null)
{
isModelReady = true;
// Initialize your component with the new model here
}
}

private void Update()
{
if (!isConnected || !isModelReady) return;
// Rest of update 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: ----------------------
kapa.ai
kapa.ai2w ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Harper
HarperOP2w ago
@kapa.ai so the connection to realtime and the connection to the model happen at different times?
kapa.ai
kapa.ai2w ago
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: ----------------------
kapa.ai
kapa.ai2w ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Harper
HarperOP2w ago
@kapa.ai So it can be assumed that when connected the model is loaded?
kapa.ai
kapa.ai2w ago
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:
public class MyRealtimeComponent : RealtimeComponent<MyModelType>
{
private bool isConnected = false;
private bool isModelReady = false;
private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime r) => isConnected = true;
}

protected override void OnRealtimeModelReplaced(MyModelType previousModel, MyModelType currentModel)
{
if (currentModel != null)
{
isModelReady = true;
// Initialize your component with the new model here
}
}

private void Update()
{
if (!isConnected || !isModelReady) return;
// Rest of update code ...
}
}
public class MyRealtimeComponent : RealtimeComponent<MyModelType>
{
private bool isConnected = false;
private bool isModelReady = false;
private void Start()
{
Realtime realtime = FindObjectOfType<Realtime>();
realtime.didConnectToRoom += (Realtime r) => isConnected = true;
}

protected override void OnRealtimeModelReplaced(MyModelType previousModel, MyModelType currentModel)
{
if (currentModel != null)
{
isModelReady = true;
// Initialize your component with the new model here
}
}

private void Update()
{
if (!isConnected || !isModelReady) return;
// Rest of update 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: ----------------------
kapa.ai
kapa.ai2w ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
maxweisel
maxweisel2w ago
@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
Harper
HarperOP2w ago
@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?
maxweisel
maxweisel2w ago
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?
Harper
HarperOP2w ago
Yes
maxweisel
maxweisel2w ago
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
Harper
HarperOP2w ago
@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.
Harper
HarperOP2w ago
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?
maxweisel
maxweisel2w ago
I can dive in a little later but all callbacks are on the main thread
Harper
HarperOP2w ago
Oh you know what I think I've found the problem
maxweisel
maxweisel2w ago
what was it?
Harper
HarperOP2w ago
Scratch that never mind! Problem still ever-present. Weird that OnRealtimeModelReplaced is never called though.
maxweisel
maxweisel2w ago
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
Harper
HarperOP2w ago
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
Harper
HarperOP2w ago
Not sure if this tells you anything but this is what the inspector looks like
No description
Harper
HarperOP2w ago
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.
maxweisel
maxweisel2w ago
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?
Harper
HarperOP2w ago
I shall try!
maxweisel
maxweisel2w ago
let me see what the inspector looks like for one of the doors in the scene after you do
Harper
HarperOP2w ago
Should I be concerned about these?
No description
Harper
HarperOP2w ago
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.
Harper
HarperOP2w ago
- On Normcore 2.13.1:
No description
Harper
HarperOP2w ago
After migrating project settings though I think it might be working. Didn't see the migrate option before.
maxweisel
maxweisel2w ago
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
Harper
HarperOP2w ago
Error disappeared after migration
maxweisel
maxweisel2w ago
sweet
Harper
HarperOP2w ago
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
maxweisel
maxweisel2w ago
sure thing! glad you got it working

Did you find this page helpful?