Vain
Vain3w ago

Changing model data doesn't update the model for other client, am I missing something ?

Hello, I've started using the Realtime API around a week and a half ago with moderate success (players can move independently from others and the Realtime.Instantiate seems to work just fine), however I'm having issues when it comes to the fact of having a player interact with another. To break down the classes I have made and their links, I have : - Attributes, which stocks every variable needed by players, this uses [RealtimeModel] and has 37 [RealtimeProperty]'s - Entity that inherits from RealtimeComponent<Attributes>, methods that are worthy to note are "DealAutoDamage(Entity target)" and "ReceiveDamage(...)" (this method takes a bunch of parameters and I didn't want to list all of them (I'll post the code of those two at the end of the post) - Character that inherits from Entity and - among other stuff - offers a method that calls DealAutoDamage on a target (which is an Entity) I use Realtime.Instantiate in a different script that spawns players using the following line :
GameObject playerObject = Realtime.Instantiate(prefabName: "PlayerComponents", ownedByClient: true, preventOwnershipTakeover: true, useInstance: realtime);
GameObject playerObject = Realtime.Instantiate(prefabName: "PlayerComponents", ownedByClient: true, preventOwnershipTakeover: true, useInstance: realtime);
Now, characters also have a baseline health regen (which I set to 0 for the time being) that triggers every second. What I have remarked is that when one player (A) deals damage to another (B), the health of B goes down on his game and then is reset at its original value. On the player B game, the health of B never changed at all. I'm assuming that changes are made locally on player A game, but aren't actually updated on the datastore, then when the health regen happens, the update is sent by player B on the "new" (never actually changed) value on their game. I guess that might be related to the fact the player is owned by the client, but I tried removing that part and using realtime.clientID to know which character is owned by the player for the movement logic, changing [RealtimeModel] to [RealtimeModel(true)] and trying to both make RequestOwnership and model.RequestOwnership in the different methods that are concerned here, but nothing worked and the player's health kept not being in synch... My question is : how can I fix that so that when player A attacks player B, player B actually receives damage and the value is updated on all client ? Here is the different bits of code I'm using :
public bool ReceiveDamage(Entity hitter, float physDmg, float magDmg, float physPen, float magPen, float critChance, float critMult)
{
if (model.health <= 0) return false; // in case the entity receive damage after its death for whatever reason
// dégâts reçus = dégâts de base * (pen + (1-pen) * 100 / (def + 100))
float phys = physDmg * (physPen + (1 - physPen) * 100 / (model.physDef + 100));
model.health = Math.Max(0,
model.health - (critChance >= Random.Range(0, 1) ? phys * critMult : phys)
- magDmg * (magPen + (1 - magPen) * 100 / (model.magDef + 100))
);
if (hitter.GetType() == typeof(Character))
{
model.LastHitters.Push((Character) hitter);
}
return model.health <= 0;
}
public bool ReceiveDamage(Entity hitter, float physDmg, float magDmg, float physPen, float magPen, float critChance, float critMult)
{
if (model.health <= 0) return false; // in case the entity receive damage after its death for whatever reason
// dégâts reçus = dégâts de base * (pen + (1-pen) * 100 / (def + 100))
float phys = physDmg * (physPen + (1 - physPen) * 100 / (model.physDef + 100));
model.health = Math.Max(0,
model.health - (critChance >= Random.Range(0, 1) ? phys * critMult : phys)
- magDmg * (magPen + (1 - magPen) * 100 / (model.magDef + 100))
);
if (hitter.GetType() == typeof(Character))
{
model.LastHitters.Push((Character) hitter);
}
return model.health <= 0;
}
protected virtual bool DealAutoDamage(Entity target)
{
return target.ReceiveDamage(this, model.attack, 0, model.physPen, model.magPen, model.critChance, model.critMult);
}
protected virtual bool DealAutoDamage(Entity target)
{
return target.ReceiveDamage(this, model.attack, 0, model.physPen, model.magPen, model.critChance, model.critMult);
}
Any help provided would be greatly appreciated 😅
5 Replies
kapa.ai
kapa.ai3w ago
Hi @Vain. 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 information provided, it seems like you're experiencing issues with the synchronization of your RealtimeModel data across different clients. Here are a few things you might want to consider: 1. Ownership: In Normcore, the concept of ownership is crucial. Only the owner of a RealtimeModel can make changes to it that will be propagated to other clients. If a client that is not the owner tries to make changes, these changes will only be local and will not be reflected on other clients. You mentioned that you tried using RequestOwnership and model.RequestOwnership, but it's important to ensure that the client making the changes is indeed the owner. You can use SetOwnership(int clientID) to set the ownership to a specific client. source (https://normcore.io/documentation/reference/classes/Normal.Realtime.RealtimeComponent%601) 2. Update Rate: Normcore serializes all updates once per network frame (~20hz) and groups them into the same packet. If you change something and then change it back immediately, nothing will be sent to the server. Make sure that the changes you're making are not being overridden before they can be sent out. source (https://normcore.io/documentation/room/common-questions#sometimes-when-i-log-the-values-on-my-model-from-inside-of-valuedidchange-not-all-the-values-that-i-set-on-another-client-update-when-are-updates-sent-out-and-how-are-they-applied) 3. Change Events: Normcore provides a mechanism to listen for changes in the RealtimeModel data. When a property is changed, a change event is fired. You can use this to ensure that your scene is updated to match the model. source (https://normcore.io/documentation/room/realtimemodel#change-event) 4. Reliable vs Unreliable Properties: Normcore allows you to mark properties as reliable or unreliable. Reliable properties are good for things that you update once and that should be resent if the packet is dropped in transit. Unreliable updates are not resent if they’re dropped in transit because it’s expected that another update is following shortly after. Depending on your use case, you might want to consider marking your health property as reliable. source (https://normcore.io/documentation/realtime/synchronizing-custom-data#reliable--unreliable) If you're still having issues, it might be helpful to check for any compilation errors in your project. If your project has any errors, any changes you make to the model will not be visible to the model editor. source (https://normcore.io/documentation/room/common-questions#i-made-changes-to-my-properties-but-when-i-recompile-the-freshly-compiled-model-isnt-updated-why) I hope this helps! Let me know if you have any other questions. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.ai3w ago
<@601750546197774346> kapa.ai is still learning and improving, please let us know how it did by reacting below
Mechabit
Mechabit3w ago
You can't change models owned by other players (by design). You need to send a message to the other player to alter their own models using something like a RealtimeSet 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
Vain
Vain3w ago
Thanks a lot, I knew I couldn't change another person's model directly and I precisely tried the clear ownership method mentioned in the article, it didn't work either 😅 I'll try following this guide in around an hour, I'll send another message here while doing so if I either succeed or encountered an issue 👍 Well, using the RealtimeSet was indeed the solution to make it so the health is being update across all players, but I still have an issue with the health going up and down... I'll try looking for every instance where I update the health of characters in the code and try to understand where the issue comes from tomorrow Bug resolved, the health going up for no reason was due to me using Math.Max instead of Math.Min at some point ;-;
maxweisel
maxweisel2w ago
glad to hear you got it sorted 🙂