gubebra
gubebra4mo ago

Call DidChange event when value is the same

I basically want to trigger the ValueDidChange every time I assign model.value to something, even if that value is the same as before. For some context, I'm sending a string to all clients when a player scores and if he scores again the string is going to be the same, but I need the StringDidChange event to trigger on all clients to display who scored.
26 Replies
kapa.ai
kapa.ai4mo ago
Hi @gubebra. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- In NormalVR, the ValueDidChange event is triggered when a value changes. If you're setting the same value again, the event might not be triggered because the value hasn't technically changed. One workaround could be to slightly modify the value each time you set it, even if the meaningful content remains the same. For example, you could append a unique, but irrelevant, character or number to the string each time a player scores. This would ensure that the ValueDidChange event is triggered each time, as the value is technically different each time. Here's an example of how you might implement this in your code:
public void PlayerScored(string playerName) {
// Append a unique value to the player name each time they score
model.value = playerName + "_" + System.Guid.NewGuid().ToString();

// This will fire the valueChanged event on the model, which will update for all clients.
}
public void PlayerScored(string playerName) {
// Append a unique value to the player name each time they score
model.value = playerName + "_" + System.Guid.NewGuid().ToString();

// This will fire the valueChanged event on the model, which will update for all clients.
}
In this example, a new GUID is appended to the player name each time they score. This ensures that the value is unique each time, triggering the ValueDidChange event. You can then handle this event and strip the appended GUID before displaying the player name. Remember to handle the ValueDidChange event properly in your code. Here's an example of how you might do this:
private void ValueDidChange(MyModel model, string value) {
// Strip the appended GUID from the value
string playerName = value.Split('_')[0];

// Display the player name
DisplayPlayerScored(playerName);
}
private void ValueDidChange(MyModel model, string value) {
// Strip the appended GUID from the value
string playerName = value.Split('_')[0];

// Display the player name
DisplayPlayerScored(playerName);
}
In this example, the ValueDidChange method splits the value on the underscore character (_), and takes the first part as the player name. It then calls a hypothetical DisplayPlayerScored method to display the player name. Please note that this is a workaround and might not be the best solution depending on your specific use case. Always consider the implications of your design decisions and choose the best solution for your needs. For more information on how to use ValueDidChange and other events in NormalVR, you can refer to the official 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: ----------------------
kapa.ai
kapa.ai4mo ago
<@599054560270483456> kapa.ai is still learning and improving, please let us know how it did by reacting below
Mechabit
Mechabit4mo ago
the bot doesn't know but there's a better option set the equality check parameter to false when you make the model it's not in the docs but was added recently
gubebra
gubebra4mo ago
Interesting, when defining the RealtimeProperty?
Mechabit
Mechabit4mo ago
yeah, use intelisense in your IDE to get the property name RealtimePropertyAttribute(uint propertyID, bool reliable, bool createDidChangeEvent = false, bool includeEqualityCheck = true) set the last one to false
gubebra
gubebra4mo ago
[RealtimeProperty(1, true, true, false )] private string _text;
[RealtimeProperty(1, true, true, false )] private string _text;
Like this?
Mechabit
Mechabit4mo ago
yeah
gubebra
gubebra4mo ago
It's almost working, I get the event fired for the person that changed the string but not the other clients
Mechabit
Mechabit4mo ago
make sure they have registered to the event before you change it
gubebra
gubebra4mo ago
I don't know if I've done something wrong it's a really simple script:
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using Normal.Realtime;

public class TextEvent : RealtimeComponent<TextEventModel>
{
protected override void OnRealtimeModelReplaced(TextEventModel previousModel, TextEventModel currentModel)
{
if (previousModel != null)
{
previousModel.textDidChange -= TextDidChange;
}

if (currentModel != null)
{
currentModel.textDidChange += TextDidChange;
}
}

private void TextDidChange(TextEventModel model, string value)
{
Debug.Log("text: " + value); // this is not being called
UIManager.Instance.notificationFront(value, model.duration);
}

public void SetTextSynced(string text, float duration)
{
model.duration = duration;
model.text = text;
}
}
using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using Normal.Realtime;

public class TextEvent : RealtimeComponent<TextEventModel>
{
protected override void OnRealtimeModelReplaced(TextEventModel previousModel, TextEventModel currentModel)
{
if (previousModel != null)
{
previousModel.textDidChange -= TextDidChange;
}

if (currentModel != null)
{
currentModel.textDidChange += TextDidChange;
}
}

private void TextDidChange(TextEventModel model, string value)
{
Debug.Log("text: " + value); // this is not being called
UIManager.Instance.notificationFront(value, model.duration);
}

public void SetTextSynced(string text, float duration)
{
model.duration = duration;
model.text = text;
}
}
using UnityEngine;
using Normal.Realtime;
using Normal.Realtime.Serialization;

[RealtimeModel]
public partial class TextEventModel
{
[RealtimeProperty(1, true, true, false )] private string _text;
[RealtimeProperty(2, true )] private float _duration;
}
using UnityEngine;
using Normal.Realtime;
using Normal.Realtime.Serialization;

[RealtimeModel]
public partial class TextEventModel
{
[RealtimeProperty(1, true, true, false )] private string _text;
[RealtimeProperty(2, true )] private float _duration;
}
Mechabit
Mechabit4mo ago
you probably want to check the value on model replaced in case it's already set when you join
gubebra
gubebra4mo ago
Still not working. I'm changing the model value here a lot of times and no luck. Do you now which version of Nomcore has this feature?
Mechabit
Mechabit4mo ago
2.9.3
gubebra
gubebra4mo ago
Yeah I have version 2.10.4 Is that expected behaviour? Because the event is called for the person that changed the variable.
Mechabit
Mechabit4mo ago
no, it should call the event
gubebra
gubebra4mo ago
Should I file a bug then?
Mechabit
Mechabit4mo ago
could do, as an alternative you can add an int property that you increment when you want to fire an event
maxweisel
maxweisel4mo ago
did you make a new build for all clients after updating normcore and enabling this flag?
gubebra
gubebra4mo ago
Yes, I actually have 2 editors open with the project
maxweisel
maxweisel4mo ago
if you're able to make a repro in a blank project, I'd love to take a look
gubebra
gubebra4mo ago
I'll try @Max I managed to repro on a blank project, here's the video
gubebra
gubebra4mo ago
No description
gubebra
gubebra4mo ago
Here're the project files
maxweisel
maxweisel4mo ago
@NormalMark want to take a look at this when you get a sec?
NormalMark
NormalMark4mo ago
Hey, thanks for putting this test project together! We identified the issue and we're working on a fix 👍
gubebra
gubebra4mo ago
Great to hear thanks!