Best way to sync data on a table?
I'm creating something similar to a bowling scoresheet: Each row is a different player and each column contains scores for each round.
Right now I'm thinking about using a couple realtime arrays much like you would use 2 lists to store the data. However, the model for the inner array only contains a single int (and the outer one contains only an realtime array).
I'm also not sure a RealtimeSet would work since the data isn't ordered?
I hope I'm over-complicating this. Is there a better way to sync this kind of data?
20 Replies
Hi @ReeseR. 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, a
RealtimeDictionary
might be a better fit. According to the documentation (https://normcore.io/documentation/room/collections#non-transactional-collections), a RealtimeDictionary
is commonly used to represent a model that can have fields that are dynamically added or removed at runtime.
You could create a ScoreModel
and store instances of it in a RealtimeDictionary
using each player's clientID as the key. The ScoreModel
could contain an array or list of integers representing the scores for each round. This way, you can easily add or remove scores for each player and keep everything in sync.
Here's a simplified example of what the ScoreModel
might look like:
And here's how you might use it with a RealtimeDictionary
:
Remember, the RealtimeDictionary
and ScoreModel
would need to be properly set up to work with Normcore's synchronization system. This is just a simplified example to illustrate the concept.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@806620207447146517> kapa.ai is still learning and improving, please let us know how it did by reacting below
RealtimeArray's can't be integers, only models? At least from what I'm reading in the docs: "RealtimeArray is a special model type that holds a sequential list of models that can be modified at runtime."
make a model with an int property and put that model into a realtime array
you can nest arrays this way
Ok, I've made a table using nested realtime models. Since I need to actively update each score, I used a RealtimeDictionary. How do I get the model to update? There is no "RowDidChange" with Realtime dictionaries, and I need to know the specific cell in order to update the right spot on the visible table.
Here's the structure:
add another property to the model that says what cell and row was changed
@Normcore Assistant I'm trying to auto-generate a table of scores. Currently, it doesn't work with RealtimeInstantiate. When making this table of scores, does every cell need a realtime sync component on it? Or is there a way to do it with only a sync on the parent object?
Let me check the knowledge base for you. One moment! :books:
----------------------
In Normcore, parent-child relationships are not automatically synchronized. As mentioned in the documentation (https://normcore.io/documentation/realtime/common-questions#can-i-reparent-a-game-object-with-a-realtimeview-or-realtimecomponent-on-it), Normcore does not synchronize parent relationships between objects. If the new parent gets destroyed, it will take the RealtimeView and its components with it, which can result in desyncs between your clients.
Therefore, if you want to synchronize each cell in your table of scores, you would need to add a RealtimeComponent to each cell. This could be a custom RealtimeComponent that you create to handle the specific data you need to sync for each cell.
However, if the data you're trying to sync is simply the scores for each player, you might not need to use RealtimeInstantiate or synchronize each cell individually. Instead, you could use a
RealtimeDictionary
or a StringKeyDictionary
to store and sync the scores, as suggested in the documentation (https://normcore.io/documentation/realtime/common-questions#im-trying-to-store-my-players-health-in-a-realtimecomponent-on-my-avatar-how-can-i-let-other-players-modify-this-values-or-others).
You could then update your table locally based on the data in the dictionary. This would avoid the need to manage a large number of RealtimeComponents and could make your implementation simpler and more efficient.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@806620207447146517> kapa.ai is still learning and improving, please let us know how it did by reacting below
@Normcore Assistant When you say "Update you table locally" do you mean update every frame? Because checking every cell on a table every single frame sounds like it takes a lot of performance. Is there a better way to do it?
Let me check the knowledge base for you. One moment! :books:
----------------------
When I say "update your table locally", I don't necessarily mean every frame. Instead, you can update it whenever there's a change in the data you're tracking.
In the context of Normcore, you can use event handlers to listen for changes in your
RealtimeDictionary
or StringKeyDictionary
. When a change event is triggered, you can then update the corresponding cell in your table. This way, you're not checking every cell every frame, but only updating when necessary.
Here's a simplified example of how you might set up an event handler for a RealtimeDictionary
:
In this example, HandleValueChanged
would be called whenever a value in scoreDictionary
changes. The key
parameter would be the player's clientID, and newValue
would be the new score. You could then use this information to update the corresponding cell in your table.
Remember, this is a simplified example and you would need to adapt it to fit your specific use case and to work with Normcore's synchronization system.
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@806620207447146517> kapa.ai is still learning and improving, please let us know how it did by reacting below
Sigh... Ok. Lets try a full context sentence...
@Normcore Assistant I'm making a table of scores using nested Realtime Dictionaries. Due to the way the table is currently set up, I do not want to add a Sync component to every cell. Since there is no "OnValueChanged" event for dictionaries, how can I change the text on any cell without looping through the whole table every frame?
Let me check the knowledge base for you. One moment! :books:
----------------------
You can use the
modelAdded
, modelReplaced
, and modelRemoved
events provided by the RealtimeDictionary
to listen for changes and update your table accordingly.
Here's a simplified example of how you might set up these event handlers:
In these examples, HandleModelAdded
, HandleModelReplaced
, and HandleModelRemoved
would be called whenever a model is added, replaced, or removed in scoreDictionary
. You could then use this information to update the corresponding cell in your table.
Remember, this is a simplified example and you would need to adapt it to fit your specific use case and to work with Normcore's synchronization system. You can find more information about these events in the RealtimeDictionary documentation (https://normcore.io/documentation/reference/classes/Normal.Realtime.Serialization.RealtimeDictionary%601).
----------------------
Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:
----------------------<@806620207447146517> kapa.ai is still learning and improving, please let us know how it did by reacting below
😮💨 Except, unless I did something wrong, "HandleModelReplaced" doesn't call within nested dictionaries...
Ok, fine. I've added a component to each cell that checks its data on the model every single frame.
I really don't like this solution. If someone knows a better way let me know.
I don't know if this fits your use case, but we did a thing where instead of storing/syncing player score totals, we sync a log of score events in an unordered RealtimeSet.
Everyone's local arrays only get updated on the ModelAdded event.
Then we calculate the local scores from the log as required:
(Our game is turn-based and has infrequent score updates.)
(Pseudo-code - our scoring system has more dimensions and data in the score "ledger", but hopefully you get the idea.)
...for i.e. a bowling score sheet your event could be
{ player, frame, delivery, pins }
Yeah, unfortunately mine isn't turn-based. The data syncs just fine, but I need to trigger an event on data sync that updates the scoreboard text. Still not sure there's a way to do that with realtime dictionaries. So, instead I have a component on every text object that checks a player's score every single frame and updates the text.
I think it would still work for you. In our model, we never update any of the list elements - we just add score events (net change).
RealtimeSet has an event for when a model is added, which the clients' local sim then uses to calculate/update the score locally.
Hmm... When I get a chance I'll play around with the model added event and see what happens. Might be a while, but I'll let you know how it goes.