Question about which is the best data structure collection to use for playing card deck sync
Question about which is the best data structure collection to use for this use case:
I have a deck of playing cards. I want players to insert/remove cards at any arbitrary index in realtime. Ideally the deck card order is the same for all clients at all times. I've been using
StringKeyDictionary
with the card index as the key for my current implementation. But I see on https://docs.normcore.io/room/collections there's a tip at the bottom that says:
Tip: If you need a sorted collection that supports random removal, we generally recommend using either RealtimeDictionary with the key as the item index, or a RealtimeSet of models that can be sorted deterministically on all clients when the contents change.Now I'm wondering if I should switch to use
RealtimeDictionary
or a RealtimeSet.
On the set case do some client side work to deterministically sort the cards.
Consistency of shared state is super important as I want every player/client to have the exact same deck of cards in the same order. What is your recommendation?
I can share more details if neededCollections | Normcore Documenation
Normcore provides several collections that can be used to synchronize data in real-time. These collections are designed to be atomic even with multiple clients making simultaneous changes to them, so they have restrictions you may not see in a typical C# collection.
4 Replies
Hi @RoyNexus. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
For your use case—synchronizing a deck of playing cards where cards can be inserted or removed at any arbitrary index and the order must be consistent across all clients—the best collection type in Normcore depends on your priorities for transactional safety, ordering, and ease of use.
Key Considerations from the Documentation
- RealtimeArray only supports adding elements and does not support removal by index, so it is not suitable for your use case.
- StringKeyDictionary is transactional and supports arbitrary keys, but the documentation tip suggests alternatives for sorted collections with random removal.
- RealtimeDictionary (with the card index as the key) is recommended for sorted collections that support random removal. It is non-transactional, so changes are reflected instantly and the server merges changes using a last-client-wins approach. This can be suitable if you can tolerate the rare case of simultaneous edits being resolved by the server.
- RealtimeSet is unordered, but you can sort it deterministically on all clients. However, this adds complexity and is only recommended if you have a strong reason to use sets over dictionaries.
Use RealtimeDictionary with the card index as the key for your deck. This matches the documentation's recommendation for sorted collections with random removal and will keep your deck order consistent across all clients, provided you manage the keys carefully when cards are inserted or removed. If you need strict transactional guarantees, consider StringKeyDictionary, but be aware of its rejection behavior on concurrent edits. If you have more specific requirements (e.g., very high contention on the deck), please share more details!
Room > Collections ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
Tip: If you need a sorted collection that supports random removal, we generally recommend using either RealtimeDictionary with the key as the item index, or a RealtimeSet of models that can be sorted deterministically on all clients when the contents change.Room > Collections Recommendation RealtimeDictionary is the most straightforward and recommended option for your use case. Use the card index as the key, and store each card as a model. This allows you to insert and remove cards at any index, and all clients will have the same order as long as you update the keys appropriately when cards are inserted or removed. - If you need transactional safety (i.e., you want to ensure that no two clients can modify the same index at the same time without conflict), StringKeyDictionary is safer, but it may reject changes if there are concurrent modifications. - If you use RealtimeDictionary, be aware that in the rare case of simultaneous edits, the server will resolve conflicts using a last-client-wins approach. RealtimeSet is less ideal because it is unordered by design, and you would need to implement your own deterministic sorting logic on all clients to maintain order, which adds unnecessary complexity for a deck of cards. Summary Table | Collection Type | Supports Random Removal | Maintains Order | Transactional | Recommended for Deck? | |------------------------|------------------------|-----------------|--------------|----------------------| | RealtimeArray | No | Yes | No | No | | StringKeyDictionary | Yes | Yes (by key) | Yes | Possible | | RealtimeDictionary | Yes | Yes (by key) | No | Yes | | RealtimeSet | Yes | No (must sort) | No | No | In summary:
Use RealtimeDictionary with the card index as the key for your deck. This matches the documentation's recommendation for sorted collections with random removal and will keep your deck order consistent across all clients, provided you manage the keys carefully when cards are inserted or removed. If you need strict transactional guarantees, consider StringKeyDictionary, but be aware of its rejection behavior on concurrent edits. If you have more specific requirements (e.g., very high contention on the deck), please share more details!
Room > Collections ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@362795742198235136> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
The docs are out of date StringKeyDictionary is better than RealtimeDictionary
StringKeyDictionary didn’t exist when I wrote that. I’ll fix it
Thanks 🙏