How is StopWatch Recipe updating other clients?
I dont see a didchange event in this model so how is this starting the stop watch on clients other than the one who started the stopwatch model?
using Normal.Realtime;
using Normal.Realtime.Serialization;
[RealtimeModel]
public partial class StopWatchModel {
[RealtimeProperty(1, true)] private double _startTime;
}
/* ----- Begin Normal Autogenerated Code ----- */
public partial class StopWatchModel : RealtimeModel {
public double startTime {
get {
return _startTimeProperty.value;
}
set {
if (_startTimeProperty.value == value) return;
_startTimeProperty.value = value;
InvalidateReliableLength();
}
}
public enum PropertyID : uint { StartTime = 1, }
#region Properties
private ReliableProperty<double> _startTimeProperty;
#endregion
public StopWatchModel() : base(null) { _startTimeProperty = new ReliableProperty<double>(1, _startTime); }
protected override void OnParentReplaced(RealtimeModel previousParent, RealtimeModel currentParent) { _startTimeProperty.UnsubscribeCallback(); }
protected override int WriteLength(StreamContext context) { var length = 0; length += _startTimeProperty.WriteLength(context); return length; }
protected override void Write(WriteStream stream, StreamContext context) { var writes = false; writes |= _startTimeProperty.Write(stream, context); if (writes) InvalidateContextLength(context); }
protected override void Read(ReadStream stream, StreamContext context) { var anyPropertiesChanged = false; while (stream.ReadNextPropertyID(out uint propertyID)) { var changed = false; switch (propertyID) { case (uint) PropertyID.StartTime: { changed = _startTimeProperty.Read(stream, context); break; } default: { stream.SkipProperty(); break; } } anyPropertiesChanged |= changed; } if (anyPropertiesChanged) { UpdateBackingFields(); } }
private void UpdateBackingFields() { _startTime = startTime; }
}
public enum PropertyID : uint { StartTime = 1, }
#region Properties
private ReliableProperty<double> _startTimeProperty;
#endregion
public StopWatchModel() : base(null) { _startTimeProperty = new ReliableProperty<double>(1, _startTime); }
protected override void OnParentReplaced(RealtimeModel previousParent, RealtimeModel currentParent) { _startTimeProperty.UnsubscribeCallback(); }
protected override int WriteLength(StreamContext context) { var length = 0; length += _startTimeProperty.WriteLength(context); return length; }
protected override void Write(WriteStream stream, StreamContext context) { var writes = false; writes |= _startTimeProperty.Write(stream, context); if (writes) InvalidateContextLength(context); }
protected override void Read(ReadStream stream, StreamContext context) { var anyPropertiesChanged = false; while (stream.ReadNextPropertyID(out uint propertyID)) { var changed = false; switch (propertyID) { case (uint) PropertyID.StartTime: { changed = _startTimeProperty.Read(stream, context); break; } default: { stream.SkipProperty(); break; } } anyPropertiesChanged |= changed; } if (anyPropertiesChanged) { UpdateBackingFields(); } }
private void UpdateBackingFields() { _startTime = startTime; }
}
Solution:Jump to solution
you don't need an extra int, just add the udpate event parameter to this model
12 Replies
Hi @cryptomax. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
The
StopwatchModel
in the Normcore VR platform uses a property _startTime
to hold the room time when the stopwatch was started. This property is marked with the [RealtimeProperty]
attribute, which means it is automatically synchronized across all clients connected to the same room.
When the StartStopwatch()
method is called, it sets the _startTime
to the current room time. This change is then propagated to all other clients due to the [RealtimeProperty]
attribute.
Here is the relevant code:
In this case, there is no need for a didChange
event because the Normcore platform handles the synchronization of [RealtimeProperty]
attributes automatically. When _startTime
is updated, the new value is automatically sent to all other clients.
You can find more details in the Normcore Documentation (https://normcore.io/documentation/guides/recipes/timers-and-synchronized-playback).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@401986039964631060> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant so you can make realtime properties that will automatically sync with all clients whenever they change? How do you catch the changes though?
Let me check the knowledge base for you. One moment! :books:
----------------------
Yes, you can create Realtime properties in Normcore that will automatically synchronize with all clients whenever they change. This is done by marking the property with the
[RealtimeProperty]
attribute in your model class.
Here is an example:
In this example, _name
is a Realtime property that will be synchronized across all clients.
To catch the changes, you can subscribe to the didChange
event of the property. This event is fired whenever the property changes. You can then define a method that will be called when this event is fired.
Here is an example:
In this example, NameDidChange
is a method that will be called whenever the name
property changes. You can put any code you want in this method to respond to the change.
You can find more details in the Normcore Documentation (https://normcore.io/documentation/realtime/synchronizing-custom-data#creating-a-realtimecomponent-subclass).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@401986039964631060> kapa.ai is still learning and improving, please let us know how it did by reacting below
I think I just got exceptionally confused....XD
it updates on all clients but there's no event
instead it polls time every frame
so it is just updating constantly? but what would you use to initiate catching the fact that it started though?
OnInspectorGUI() updates so long as you're looking at the inspector
nothing, unless you want it to, then you add the event parameter
in this example it only updates when you look at the inspector
but importantly there's only 1 syncing variable, the start time, which makes this timing method better than say syncing a variable called current time
less data being sent
hmmm ok so you woudl sort of need a different way to know if it started like a different int and if that flips then you can start reading the timer because it will be running everywhere, or add an additional event to this
Solution
you don't need an extra int, just add the udpate event parameter to this model
thanks for explaining it a bit more