Taking the first player that triggers an action
Which would be a good approach for this case? I have some players in a table and I want to give a point for the one that press the button in the table first (when the lights turn on for example), Should I have a button owner that listen to the players trigger (ej a realtime property boolean for each player model or even an rpc call) or I can use a realtime collection in a model that has no owner to manage it? (since it is suppose that collections are prepared to avoid race conditions)
13 Replies
Hi @jos_valentin. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
For your scenario of determining which player presses a button first, I'd recommend using a RealtimeModel with ownership to manage this interaction. Here's how you could approach it:
Using a RealtimeModel with Ownership
You could create a custom RealtimeModel for your button that tracks which player pressed it first. The key is to use Normcore's ownership system to handle the race condition.
Then create a RealtimeComponent that uses this model:
This approach leverages Normcore's ownership system to handle the race condition. When multiple players try to press the button simultaneously, only one will successfully gain ownership and set the
firstPlayerID
property Requesting ownership of a RealtimeComponent.
Why This Approach Works Better Than Alternatives
1. Avoiding RPCs: Using RPCs for this would be problematic as mentioned in the documentation: "RPC messages in Normcore are available as a last resort. If you have players that can join a room late, RPC messages make consistent synchronization difficult" Room RPCs.
2. Race Condition Handling: The ownership system ensures that only one client can update the model at a time, preventing race conditions Ownership and Lifetime Flags.
3. Server Authority: This approach uses Normcore's server authority to determine which client's request is processed first, making it fair for all players.
The key insight is that by using RequestOwnership()
, you're letting Normcore's server decide which client gets to update the model first, which is exactly what you need for a "first to press" mechanic.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@391444583034257420> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
you can sync a list of server times which will be the same for all players regardless of ping time
you'd also want to turn on the light at a future server time so it appears at the same time for all players so the owner doesn't get a head start
You mean, using kind of this part of the docs? https://docs.normcore.io/guides/recipes/timers-and-synchronized-playback
Timers + Synchronized Playback | Normcore Documenation
A common need in Normcore is to synchronize a timeline across all clients for music playback or animation playback. A naive approach would be to choose a main client and have it send updates to all clients to update their timelines. This uses a lot of bandwidth, it can result in choppy playback for the other clients, and playback isn't guarantee...
that's a good start
and how could I handle which player touch the button first? any of the options I mencioned would be good or the one that the bot said maybe?
if you want to take ping out of the equation you need to store a list of server times when players hit their buttons
@kapa.ai how do I sync a list of server times when players press a button
Let me check the knowledge base for you again. One moment! :books:
----------------------
To sync a list of server times when players press a button in Normcore, you'll need to use a RealtimeModel with a collection to store the timestamps. Here's how you can implement this:
Using RealtimeSet to Store Timestamps
Normcore provides collections like StringKeyDictionary and RealtimeSet that are designed to handle concurrent updates properly. For your use case, you can create a model that stores timestamps when players press a button:
Then create a component to manage these button presses:
Why This Approach Works
1. Server Time Synchronization: Using
realtime.room.time
gives you access to the synchronized server clock, which ensures all timestamps are based on the same reference point Timers + Synchronized Playback.
2. Race Condition Handling: The RealtimeSet
collection is designed to handle concurrent updates from multiple clients, making it ideal for recording button presses that might happen simultaneously Room Common Questions.
3. Automatic Synchronization: Normcore's datastore automatically synchronizes all changes to the collection across all clients, so everyone will see the same list of button presses in the same order.
This approach gives you a chronologically ordered list of button presses with accurate server timestamps, allowing you to determine which player pressed the button first or analyze the timing of all button presses.
For more complex scenarios, you might want to add additional properties to the ButtonPressEvent model, such as the specific button that was pressed or other contextual information.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@162940911964258305> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
you also want the light to turn on at the same time regaurdless of ping
@kapa.ai how do I turn on a light at a future server time
Let me check the knowledge base for you again. One moment! :books:
----------------------
To turn on a light at a future server time in Normcore, you can use the synchronized room time to schedule events. Here's how you can implement this functionality:
Using Synchronized Server Time for Scheduled Events
You can create a RealtimeModel that stores the scheduled time for the light to turn on, and then check against the current server time in your Update method:
This approach leverages Normcore's synchronized room time, which is available via the
realtime.room.time
property. This time is synchronized across all clients to match the room server's clock exactly with no added latency, as mentioned in the Timers + Synchronized Playback documentation.
Why This Works Well
1. Synchronized Timing: All clients will turn on the light at the same server time, ensuring the action appears synchronized to all players.
2. No Continuous Updates Needed: Once the scheduled time is set, you don't need to send any additional network messages - each client independently checks against the server time.
3. Late-Join Support: If a player joins after the scheduling but before the light turns on, they'll still see the light turn on at the correct time because the scheduled time is stored in the model.
You can extend this concept to create more complex timed events by adding additional properties to your model, such as a duration for how long the light stays on, or by using collections to schedule multiple events.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@162940911964258305> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Thanks for the resources, I'll check it out 🙂