Hello,
I have a gameobject set up like this: the parent object called “enemy2” is set to sync with coherence.
The parent object has four child objects called “protection point”. When a player shoots the protection point, it is destroyed. The hit is communicated via the “SendCommand” function to the authority. This has worked for me previously for destroying other (non-child) objects.
However, when a non-authority shoots the protection point, nothing happens. Seemingly, the message is not sent (yes the function is enabled in the methods tab).
I suspect that this is because the SendMessage function can’t resolve which “ProtectionPoint” to send the message to, since there are multiple. But how would I go about making this work?
Hey Nicolaj, I think this paragraph on the Commands’ page in the documentation specifically should cover your case!
Sending a command to a specific MonoBehaviour instance
If you have the same command bound more than once in the same Prefab hierarchy, you can target a specific MonoBehaviour when sending a message, you can do so via the SendCommand(Action action) method in CoherenceSync.
I changed my code as shown in the screenshot. This somewhat works, the method is sent to the authority.
However, the destruction of the ProtectionPoint object is not synced back to the non-authority, so it only disappears on the authority end. In other cases where I destroy a gameobject with a CoherenceSync script on it, the destruction worked without any problem. But in this case the CoherenceSync is on the parent, I don’t know if this is what’s causing the problem. The same happens if I destroy the ProtectionPoint from the authority.
Also, if i set Coherence to track the location of the ProtectionPoint, I get the following error in the console after destroying it: “MissingReferenceException: The object of type ‘Transform’ has been destroyed but you are still trying to access it.” Probably Coherence trying to sync an object that does not exist anymore.
Yes, that’s the intended behaviour. If you were destroying a GO that had a CoherenceSync, you would be removing the network entity from the Replication Server and as such, that same GO would be removed on all clients by coherence.
But if you remove one of its children… we don’t sync it, because there can be many use cases for adding/removing children only on one client, and not wanting that change to propagate on the network.
So in conclusion you might have to use a command or some other way to ensure the removal of that object on all clients. Personally, I would maybe have a master script on the root of the GO that does it - on authority but also on other clients. So they all stay in sync.
…
Give me a second to check on your second question, I’m testing something…
Ah I think I understood. You set coherence to sync the position of the Transform? Yeah I guess if you are deleting the object from its own network entity, but without deleting the network entity itself (its parent), then of course the parent will still try to sync that property every frame but it will not be able to find it.
Ah, I see. I got it to work by sending a message to all clients that the ProtectionPoint should be destroyed.
I couldn’t find a solution to the second problem mentioned in your last comment. Is there any way to “unregister” the child from the parent before destroying it so that it does not keep trying to sync it?
No. When you establish what gets synced and what not, it’s per what we call “archetypes”. Once an archetype is established, it’s a bit like a contract between all Clients and Simulators that defines what data/precision/frequency to use to pass data around. Unregistering would mean modifying the contract, so to speak.
What I would suggest, if you can’t think of another solution, could be to make these protection points their own prefabs, with their own sync configuration (I presume only the Transform>Position?).
I have to mention though that we don’t fully support at the moment the editing of a synced prefab inside a synced prefab, but we will, soon®*. This means that you can only have synced prefabs as children of each other if you instantiate them at runtime. So for your particular case, if it’s not too much effort, you could have some kind of “placeholder” sub-object (let’s call it “protectionPointPlacement”) that indicates where a PP will be at runtime. In Start, you instantiate all these PP (the “protectionPointPlacement” objects could be in an array? and the parent script does it all).
The good news is, since these are now proper network entities, both their instantiation and also their destruction will be kept in sync.
And when you destroy one, that position will stop syncing - not because you changed the archetype - but because the entity is gone altogether.
Ok
Sounds awesome with sync inside sync, looking forward to that.
Until then, I’ll have to think some more about it and refactor my current solution, now that I understand how things work.
I’ll mark your first comment as the solution since it solved my original problem.