Button press on one client
What is the right way to sync a button press form one client to the rest, should I use an RPC event?
Solution:Jump to solution
you should give up on the rpc recipe, instead sync the the menu state as an int and use the model changed event to update the menu on clients
27 Replies
Hi @SoundGuy2. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
While RPC messages are available in Normcore, they are generally discouraged for use in most cases due to the difficulty they present in maintaining consistent synchronization across clients. Any state that is modified in response to an RPC message will need to be manually synchronized by your own code, which can lead to desyncs and bugs that are hard to reproduce and debug (source (https://normcore.io/documentation/guides/recipes/rpc-events#preface)).
Instead, Normcore recommends using the room's datastore for synchronizing state across clients. When you make a change to the datastore, it is automatically replicated to all connected clients. This means that if you need to sync a button press from one client to the rest, you should change its state in the datastore, and the datastore will automatically notify all clients connected to the room so they can update their world to match (source (https://normcore.io/documentation/architecture/client#datastore)).
However, if you absolutely need to use an RPC-like structure, Normcore provides a recipe for creating an RPC-like event message that can be fired by anyone in the room. This recipe involves creating a model that holds all the values you'd typically send in an RPC message and an integer that you can increment every time you want to trigger an event. You can then create a RealtimeComponent that uses this model to call a method on the button press whenever the event fires (source (https://normcore.io/documentation/guides/recipes/rpc-events#recipe)).
Here's an example of how you can create such a model and RealtimeComponent:
Please note that this is a simplified example and you may need to adjust it to fit your specific needs.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant
can you give me the following core -
I am pressing a button with an int number in one client
a function is called in another client with that number in the other clients
Let me check the knowledge base for you. One moment! :books:
----------------------
Sure, you can achieve this by using Normcore's RealtimeModel and RealtimeComponent. Here's an example of how you can create a model and a RealtimeComponent for a button press event that includes an integer value:
In this example, when a button is pressed on one client, the
Press
method is called with the button number as an argument. This fires an event on all clients, triggering the EventDidFire
method on each client with the sender's ID and the button number as arguments. You can replace the comment in the EventDidFire
method with the function you want to call on the other clients.
Please note that this is a simplified example and you may need to adjust it to fit your specific needs. You can find more information about creating a RealtimeModel and RealtimeComponent in the Normcore documentation (https://normcore.io/documentation/guides/recipes/rpc-events#recipe).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Tom why isn't this code nice like in the tickets you opened?
I was just looking at that myself
discord has character limits
and it seems the length spanned multiple messages
here you go
@Normcore Assistant does you last example use RPC or not?
Let me check the knowledge base for you. One moment! :books:
----------------------
The example provided does not use RPC in the traditional sense. Instead, it uses Normcore's RealtimeModel and RealtimeComponent to achieve a similar effect.
In this example, the button press event is represented as a change in the state of a RealtimeModel. When the button is pressed, the
FireEvent
method is called, which increments the _trigger
property and sets the _senderID
and _buttonNumber
properties. This change in the model's state is automatically synchronized across all clients connected to the room.
When a client receives the updated model from the server, it triggers the DidRead
method, which in turn fires the eventDidFire
event. This event is handled by the EventDidFire
method in the RealtimeComponent, which can then call any function you want with the sender's ID and the button number as arguments.
This approach provides a way to send messages between clients that is similar to RPC, but it avoids some of the synchronization issues that can occur with traditional RPC messages (source (https://normcore.io/documentation/guides/recipes/rpc-events#preface)).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
ok thanks @Normcore Assistant
Let me check the knowledge base for you. One moment! :books:
----------------------
You're welcome! If you have any more questions about Normcore or VR development, feel free to ask. Happy coding!
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant can the realtimeModel and component in the last example can be in the same Cs file or do i need to put the model in a separate cs file like in the other examples
Let me check the knowledge base for you. One moment! :books:
----------------------
Yes, the RealtimeModel and the RealtimeComponent can be in the same C# file. They are two separate classes and can coexist in the same file without any issues. However, for organizational purposes and to maintain clean code, it's often recommended to keep them in separate files, especially if they start to get large or complex. But this is not a requirement, just a suggestion for best practices.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------
<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant what about that .g file that is being auto regerated?
@Normcore Assistant what about that .g file that is being auto regerated?
Let me check the knowledge base for you. One moment! :books:
----------------------
The
.g
file you're referring to is likely the auto-generated code file that Normcore creates when you define a RealtimeModel. This file contains the code that Normcore uses to handle the synchronization of your model's state across all connected clients.
If you're using Unity 2021 or newer, Normcore will automatically generate this code for you. You won't see this code in your file; it exists as temporary C# code that is generated when your project compiles (source (https://normcore.io/documentation/realtime/synchronizing-custom-data#generating-model-code-in-unity-2021)).
If you're using an older version of Unity, you will need to manually compile the model in the Unity editor by highlighting the class and clicking "Compile Model." If any script in your project does not compile, Normcore's manual model compiler will be unable to load any of the state of your model (source (https://normcore.io/documentation/room/realtimemodel#compiling-a-model)).
In either case, you don't need to worry about the contents of the .g
file. Normcore handles all of the synchronization logic for you, so you can focus on defining the state you want to synchronize and how your application should respond to changes in that state.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant the code above is faulty. I'm getting an endless calls to the EventDidFire function after pressing the button once
Let me check the knowledge base for you. One moment! :books:
----------------------
The issue you're experiencing might be due to the
DidRead
method in the ButtonPressEventModel
class. This method is called whenever any values are read from the server, and it fires the eventDidFire
event if the trigger
property is not zero. This could result in the EventDidFire
method being called continuously if the trigger
property is not reset to zero after the event is fired.
To fix this, you can add a line of code to reset the trigger
property to zero in the DidRead
method after the eventDidFire
event is fired. Here's how you can modify the DidRead
method:
Please note that this is a simplified solution and you may need to adjust it to fit your specific needs. You can find more information about creating a RealtimeModel and RealtimeComponent in the Normcore documentation (https://normcore.io/documentation/guides/recipes/rpc-events#recipe).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant this is also not good. the event being only received in the remote client every once in a while . is it possible that the trigger changs to 0 in the local client before sendingg the button number ?
Let me check the knowledge base for you. One moment! :books:
----------------------
Yes, it's possible that the
trigger
property is being reset to zero before the change is sent to the remote clients. This could happen if the local client reads the updated model from the server before the remote clients do. When the local client reads the updated model, it resets the trigger
property to zero, which could prevent the remote clients from receiving the event.
To fix this, you could add a delay before resetting the trigger
property to zero. However, this might not be the best solution as it could lead to other synchronization issues.
A better solution would be to use a different property to indicate that the button has been pressed. For example, you could add a buttonPressed
property to the ButtonPressEventModel
class and set this property to true
when the button is pressed and to false
when the event has been fired. Here's how you can modify the ButtonPressEventModel
class:
This way, the buttonPressed
property will ensure that the event is fired on all clients when the button is pressed, and the trigger
property can still be used to keep track of how many times the button has been pressed.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@1081953198014734357> kapa.ai is still learning and improving, please let us know how it did by reacting below
Solution
you should give up on the rpc recipe, instead sync the the menu state as an int and use the model changed event to update the menu on clients
or if the button doesn't change any states you can just increment an int and you just listen to the update event