DC
DC4d ago

Using RealtimeArray for reliable, ordered messages

As previously suggested, I want to use a RealtimeArray as a ordered queue for sending reliable, ordered messages. Messages can sometimes quickly (less that 30ms), but it is important that every message is sent in order. I need some guidance on how to use RealtimeArray to solve this problem. I have looked at the multiplayer paint brush example, but it is not helping my understanding. Here are a couple of strategies I am pondering: (1) use the realtime array as a queue. One player can put a message on the queue, another can take it off the queue. I am unsure if this is possible of as non-owner can alter an array, and I also cannot find a Remove type method for RealTime Array. (2) One player sends a new array with messages each time a message is created. The other player processes the arrays as the come. Any suggestions or sample code is greatly appreciated. Thanks
4 Replies
kapa.ai
kapa.ai4d ago
Hi @DC. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the knowledge sources provided, I can offer some guidance on using RealtimeArray for reliable, ordered messages in NormalVR. Let's address your strategies and provide some suggestions: 1. Using RealtimeArray as a queue: RealtimeArray is indeed designed for ordered, reliable message passing. However, it has some limitations that make it unsuitable for a traditional queue implementation: - RealtimeArray only supports adding elements, not removing them. As stated in the Room > Collections documentation: "RealtimeArray is equivalent to a List<ModelType> that only supports adding elements. Because the contents are sorted by index, removing items by index is not supported." - Non-owners can read from the array but cannot modify it. The ownership is typically set when the object containing the RealtimeArray is instantiated. 2. Sending a new array with messages: This approach is closer to how RealtimeArray is intended to be used. Here's a suggested implementation based on the documentation: 1. Create a model for your message:
[RealtimeModel]
public partial class MessageModel
{
[RealtimeProperty(1, true)]
private string _content;

[RealtimeProperty(2, true)]
private int _senderID;
}
[RealtimeModel]
public partial class MessageModel
{
[RealtimeProperty(1, true)]
private string _content;

[RealtimeProperty(2, true)]
private int _senderID;
}
2. Create a component that uses RealtimeArray to store and synchronize messages:
public class MessageSync : RealtimeComponent<MessageSyncModel>
{
protected override void OnRealtimeModelReplaced(MessageSyncModel previousModel, MessageSyncModel currentModel)
{
if (previousModel != null)
{
// Unregister from events
previousModel.messages.modelAdded -= MessageAdded;
}

if (currentModel != null)
{
// Register for events
currentModel.messages.modelAdded += MessageAdded;
}
}

private void MessageAdded(RealtimeArray<MessageModel> messages, MessageModel message, bool remote)
{
// Process the new message
Debug.Log($"New message from {message.senderID}: {message.content}");
}

public void SendMessage(string content, int senderID)
{
MessageModel newMessage = new MessageModel();
newMessage.content = content;
newMessage.senderID = senderID;
model.messages.Add(newMessage);
}
}
public class MessageSync : RealtimeComponent<MessageSyncModel>
{
protected override void OnRealtimeModelReplaced(MessageSyncModel previousModel, MessageSyncModel currentModel)
{
if (previousModel != null)
{
// Unregister from events
previousModel.messages.modelAdded -= MessageAdded;
}

if (currentModel != null)
{
// Register for events
currentModel.messages.modelAdded += MessageAdded;
}
}

private void MessageAdded(RealtimeArray<MessageModel> messages, MessageModel message, bool remote)
{
// Process the new message
Debug.Log($"New message from {message.senderID}: {message.content}");
}

public void SendMessage(string content, int senderID)
{
MessageModel newMessage = new MessageModel();
newMessage.content = content;
newMessage.senderID = senderID;
model.messages.Add(newMessage);
}
}
3. Use the MessageSync component: Attach this component to a GameObject that has a RealtimeView component. The owner of this object can send messages using the SendMessage method, and all clients (including the sender) will receive the message through the MessageAdded event handler. This approach ensures that: - Messages are sent in order - All clients receive all messages - Messages are processed in the order they were sent The RealtimeArray will automatically handle synchronization and ensure that late-joining clients receive all messages. Remember that RealtimeArray is designed for operations where you need to add elements in order, such as drawing brush strokes. As mentioned in the Room > Collections documentation: "RealtimeArray is generally used for operations such as drawing brush strokes, where a series of models need to be added in order." For more complex messaging systems, you might want to consider using other Normcore collections like RealtimeSet or RealtimeDictionary, depending on your specific requirements. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai4d ago
<@1259730396577529917> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
DC
DCOP4d ago
Do you have a definition for MessageSyncModel?
Mechabit
Mechabit3d ago
the bot did a mistake, just rename MessageModel.cs

Did you find this page helpful?