Harper
Harper7d ago

What's going on with offline mode?

I'm adding an offline mode to my application. It sounded simple enough to implement with Normcore's offline mode. So, I set the room connection options to offline, but now I'm running into some weird issues.
Exception: This view doesn't have a model yet. Wait until the model is present before interacting with the ownership.
Normal.Realtime.RealtimeView.get_isUnownedSelf () (at <83f033e5a6a04834bc436ae66ff481be>:0)
Normal.Realtime.RealtimeComponentEditor.GetComponentOwnerString (Normal.Realtime.IRealtimeComponent component) (at <55422fd9908c4c16a024190b9f5c4321>:0)
Normal.Realtime.RealtimeComponentEditor.DrawOwnershipSettings (Normal.Realtime.IRealtimeComponent component) (at <55422fd9908c4c16a024190b9f5c4321>:0)
Normal.Realtime.RealtimeViewEditor.OnInspectorGUI () (at <55422fd9908c4c16a024190b9f5c4321>:0)
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass72_0.<CreateInspectorElementUsingIMGUI>b__0 () (at <e79fb6b8b9ab474b8f0398fed96fa2af>:0)
UnityEditor.InspectorWindow:RedrawFromNative()
Exception: This view doesn't have a model yet. Wait until the model is present before interacting with the ownership.
Normal.Realtime.RealtimeView.get_isUnownedSelf () (at <83f033e5a6a04834bc436ae66ff481be>:0)
Normal.Realtime.RealtimeComponentEditor.GetComponentOwnerString (Normal.Realtime.IRealtimeComponent component) (at <55422fd9908c4c16a024190b9f5c4321>:0)
Normal.Realtime.RealtimeComponentEditor.DrawOwnershipSettings (Normal.Realtime.IRealtimeComponent component) (at <55422fd9908c4c16a024190b9f5c4321>:0)
Normal.Realtime.RealtimeViewEditor.OnInspectorGUI () (at <55422fd9908c4c16a024190b9f5c4321>:0)
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass72_0.<CreateInspectorElementUsingIMGUI>b__0 () (at <e79fb6b8b9ab474b8f0398fed96fa2af>:0)
UnityEditor.InspectorWindow:RedrawFromNative()
This error shows up from 0 to 4 times when I run my scene. When it doesn't show, elements of my project still fail. What's going on?
22 Replies
kapa.ai
kapa.ai7d 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: ---------------------- Based on the information provided in the knowledge sources, I can offer some insights into your offline mode issue with Normcore. The error message you're encountering suggests that there might be a timing issue with how the RealtimeView and its model are being initialized in offline mode. This error typically occurs when trying to access ownership information before the model is fully set up. Here are a few points to consider: 1. Offline Mode Setup: Make sure you're setting up offline mode correctly. According to the Room > Offline Mode documentation, you should use the ConnectOptions struct when calling Connect():
_realtime.Connect("My Room", new Room.ConnectOptions {
offlineMode = true
});

_realtime.Connect("My Room", new Room.ConnectOptions {
offlineMode = true
});

2. Timing of Access: The error suggests you're trying to access the RealtimeView's ownership information too early. In offline mode, some behaviors might be slightly different. As per the documentation, "For the most part, all features in Normcore operate the same way as online mode. However, there are a few details that are different." 3. Initialization Order: Make sure you're not trying to access RealtimeView properties in Awake() or too early in Start(). According to the Realtime > Common Questions documentation, for scene RealtimeViews, you need to wait until realtime.connected == true, or the didConnectToRoom event has fired. 4. Serialization Events: The documentation mentions that "The serialization and deserialization mechanisms are skipped in offline mode. Change events will still fire, but serialization events like RealtimeModelEvent.OnWillWrite will not be invoked." To resolve this issue: 1. Ensure you're setting up offline mode correctly. 2. Delay any access to RealtimeView properties until after the connection is established. 3. Consider using the didConnectToRoom event to trigger your initialization logic:
_realtime.didConnectToRoom += DidConnectToRoom;

private void DidConnectToRoom(Realtime realtime) {
if (realtime.room.offlineMode) {
// Initialize your offline mode logic here
}
}

_realtime.didConnectToRoom += DidConnectToRoom;

private void DidConnectToRoom(Realtime realtime) {
if (realtime.room.offlineMode) {
// Initialize your offline mode logic here
}
}

4. If you're still encountering issues, you might need to review how your custom RealtimeComponents are set up, especially if they rely on serialization events that don't fire in offline mode. If these suggestions don't resolve your issue, you may need to provide more details about your specific implementation, as the knowledge sources don't contain enough information to diagnose the exact cause of your problem. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7d ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Harper
HarperOP7d ago
@kapa.ai is it possible that this is happening because I often assume an empty model is fine before my client gets a real model? Maybe in offline mode there is no empty model provided before technically "connecting" to a real one.
kapa.ai
kapa.ai7d ago
Let me check the knowledge base for you again. One moment! :books: ---------------------- Your observation is quite insightful and likely correct. Based on the information provided in the knowledge sources, there are indeed differences in how models are initialized and handled in offline mode compared to online mode. According to the Realtime > RealtimeComponent documentation, the lifecycle of views and components differs between scene objects and prefabs, and between online and offline modes. In a typical online scenario, Realtime creates an empty model for every view and component before connecting to a room. However, in offline mode, this process might be different. The documentation states: "When using views and components in a scene, they follow this cycle: 1. Awake() + Start() both run. 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 an OnRealtimeModelReplaced() call." In offline mode, step 2 might be skipped or handled differently, which could explain why you're not getting an empty model before "connecting" to a real one. To address this, you should ensure that your code doesn't assume an empty model will always be available. Instead, you should wait for the OnRealtimeModelReplaced() call before interacting with the model. Here's a recommended approach:
protected override void OnRealtimeModelReplaced(ModelType previousModel, ModelType currentModel) {
if (currentModel != null) {
if (currentModel.isFreshModel) {
// Set initial values here
currentModel.someProperty = initialValue;
}

// Subscribe to events or initialize based on the model
}

if (previousModel != null) {
// Unsubscribe from events if necessary
}
}
protected override void OnRealtimeModelReplaced(ModelType previousModel, ModelType currentModel) {
if (currentModel != null) {
if (currentModel.isFreshModel) {
// Set initial values here
currentModel.someProperty = initialValue;
}

// Subscribe to events or initialize based on the model
}

if (previousModel != null) {
// Unsubscribe from events if necessary
}
}
This approach ensures that you're only working with the model when it's actually available, whether you're in online or offline mode. Additionally, the Room > Offline Mode documentation mentions some limitations and differences in offline mode, such as Realtime.clientID always returning 0 and Realtime.roomTime returning the device's system time. These differences might also contribute to the behavior you're observing. If you continue to face issues after implementing these changes, you might need to review how your specific RealtimeComponents are structured and ensure they're compatible with both online and offline modes. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai7d ago
<@276154194606424064> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mechabit
Mechabit7d ago
offline mode connects instantly so try adding a couple frames delay to what you're doing
Harper
HarperOP7d ago
I don't follow. If it connects instantly why would I need a few frames of delay?
Mechabit
Mechabit7d ago
if it worked in online mode then that delay might have masked another issue
Harper
HarperOP7d ago
I see Exception: This view doesn't have a model yet. Wait until the model is present before interacting with the ownership. suggests that shouldn't be the case though right? Unless the room connects in awake, and my scripts wait for connection in awake, and so it could be an execution order issue? But offline mode is set when we connect so I'm not sure if that makes since either. Just brainstorming. It's hard to diagnose where I should start first.
Mechabit
Mechabit7d ago
try onmodelreplaced instead of waiting in awake
NormalMark
NormalMark7d ago
Scene RealtimeViews only register with their Realtime in Start(). It's inside this registration process that they're assigned a model. There's 2 ways to approach this: 1. You could try using OnModelReplaced to access your models as Mechabit mentioned. These will be called in Start() when the views register. 2. Or you could connect/launch the offline mode after the 1st frame (or at least after or at the end of the 1st Start), by which point all views have registered. Although you still won't be able to access models inside components' Awake(). So 1 is probably the safest bet here. I do agree it's unintuitive, perhaps Realtime.Connect on offline mode should defer until after Start() I'll look into improving this but for now you should try those workarounds
Harper
HarperOP6d ago
Thanks the both of you! Looking into these fixes today. Alright so I'm going through my code and it looks like I never actually access the model in Awake. I do, on the other hand, subscribe to didConnectToRoom in Awake and then access the model in didConnectToRoom. So, I cleaned that up (assuming didConnectToRoom will be called before the model is registered) and I am still getting errors. Looking more closely at the error, I'm confused by all the mentions of UI. I suspect something else is going on here? Like DrawOwnershipSettings? Is this an issue with the inspector GUI for RealtimeViews?
NormalMark
NormalMark6d ago
Yeah it's starting to sound like a bug on our side. I'll test a scene in offline mode to see if I get the same UI error
Harper
HarperOP6d ago
It's noteworthy to mention again that the errors happen most of the time, but not all of the time. Though whatever is happening is not benign @NormalMark you haven't happened to have a chance to look a test scene yet have you? If it saves you some time I can take a crack at a test project That being said offline mode is not an immediately crucial feature for this project
NormalMark
NormalMark6d ago
I haven't looked yet. That would help me a lot actually 🙂
Harper
HarperOP6d ago
For sure I'll boot up a new project now Okay sooo I did have my realtime.Connect in Awake And that seems to have maybe been the issue (I should connect in Start?) Still testing... If true though I'm embaressed I didn't pick up on that earlier. This does seem to be the case. Offline mode seems to be working flawlessly now. Moral of the story: Room connection needs to happen in Start not Awake. I should have picked up this might have been the issue when it was pointed out that the model should not be accessed in Awake. Anyway, the time Normcore and its community puts into its users is really appreciated.
NormalMark
NormalMark6d ago
Glad it's sorted for now! I might add this to the docs or address this issue somehow. Because it's not unreasonable to want to call connect in Awake. Even Start might be too early because scene realtime views register themselves in Start. Depending on the execution order you might get lucky or unlucky 😓
Mechabit
Mechabit6d ago
you can add a 1 frame delay to offline mode connect to mimic the behaviour of a normal connect that would be the lazy way which I am very much lol
NormalMark
NormalMark5d ago
That is a good idea 🙂 I'll give it a shot
Harper
HarperOP5d ago
This would be useful! So you would recommend Mechabit's frame delay approach?
NormalMark
NormalMark5d ago
Yeah, I'm thinking of making that the built-in behavior somehow. I put it on my todo list.
Harper
HarperOP5d ago
Cool!

Did you find this page helpful?