Uniquely identify objects already placed in the scene

This is not about Unity’s network implementation, but an own implementation:

I need a way to identify objects that should be synchronized over the network, similar to the networkID in Network: If for example the server broadcasts that the object with a specific ID has been destroyed, the clients need to know which object is meant, so the ID for the same objects on the server need to be the same on the client.

Now, this is not a big problem to implement for objects which are dynamically spawned into the scene. The server will just tell the clients that there is a new object of type T at position XYZ with an id I.

The problem is how to assign an id to those objects already present in the scene that should be synchronized over the network (e.g. can be destroyed). The scene is known to both the server and the clients, so there is no necessity for the server to announce the existance and id of the synchronizable objects. Rather, the id should already be defined in the scene or derived from the scene.
One solution would be to make the level designer have to manually assign each synchronizable object in the scene a unique id which he will have to keep track of himself in an excel file or something. This is of course stupid. Any proper solution must assign the ids to synchronizable objects in the scene automatically like it is also done with Unity’s Network. This can be done by assigning a network ID on initialization of each, lets call it, Synchronizable component by counting up a static ID counter (atomic integer, or guid).

But to do this seems to be a big problem in Unity:

  • The execution order is undefined, so there is not guarantee that f.e. Awake() in a Synchronizable component will be called in the same order on all clients like on the server
  • According to some Q&A the [Object.GetInstanceID](http://docs.unity3d.com/Documentation/ScriptReference/Object.GetInstanceID.html?from=GameObject) is not guaranteed to be the same across all instances of the same scene. This is not 100% clear, it would be nice to have a definite statement of a unity dev on this
  • FindGameObjectsWithTag does also not guarantee an order in which the objects are returned.
  • Ordering objects in the scene by their position is not a good solution as a position may not be unique - there may be several objects at the exact same position, especially objects which do not have a direct mesh representation somewhere in the scene but do something more abstract like e.g. show a statistics screen

So at this point I really wonder how it is done in Unity’s network and how or if this can be done at all using the Unity API.

  • Unity network does not work with Flash export

If it is really not at all possible to clearly identify objects across different platforms/instances of the scene, the only solution that comes to my mind now would be:

  • all objects in the scene with the Synchronizable component will be destroyed immediately on all clients
  • the server sends out all those objects to all clients as if they were created dynamically on each client connect

You need to setup your own system to identify these objects, there are a myriad of ways to do this, the most obvious being a custom monobehaviour with a counter/id that is set during edit time inside unity.

If you mean with “edit time inside unity” the level editing in the scene: That is the “manual” solution I mentioned in my initial post and which I dismissed. The reason for this is that the level designer would have to keep track himself which ids are already allocated and which aren’t which is a lot of effort and error-prone (allocating the same id twice).

Take a tech demo like bootcamp - most objects lying around there are destructible and thus must be synchronized over network. One would have to set a unique id for every can, garbage bag, barrel and piece of furniture lying around in the scene. It’d be even worse if the trees were also destructible. Allocating unique ids manually would quickly become an unmanagable mess.

Well, it can be done automatically by stepping through all objects in the scene or something.

How would you do that that the order of the objects you step through is always the same on all instances of the scene? As I mentioned in my first post: I didn’t find any possibility in the Unity API that guarantees the same order of the objects returned.

I am not sure if this relates directly to your requirements or not but I’ll post it anyway in the hope it may spark an idea.

I chose a method to uniquely identify my objects by using transform.name and a buffered RPC call.

For example, when I create an object on my server I network instantiate a prefab and append it’s instance ID to the name. I then call a buffered RPC.Others and send the name as a parameter. All client versions of the object are then updated with the server objects unique name.

For already created objects that exist in a scene you could attach a script to them that sends an RPC to the server to get the name of the server object sent back to it and then have it rename itself to match.

Just a thought.

The problem is the “bootstrapping” with this idea: The objective of the whole ID-giving procedure is that both the clients and the server can identify one object as the same over the network. If the client actively requests the server to give him an ID for some specific object, how would the server know which object the client means? After all, the object does not have an ID yet (= cannot be identified as the same by both the server and the clients).

This idea relates to another one I had but which is also not optimal: For the ID-giving procedure, rely on the transform+name as the identifier, following the statement “An object that exist at the exact same position on the server and on the client and has the same name on level load must be the same object”. This statement is not always correct, and that is the problem with this approach.

When you create a scene and place your objects with an attached Networkview in the scene the same object is then loaded by the Server and then the Client. So in effect there is one object and it has two or more instances (server + clients). If you have a script attached to that object and have the Client request an ID from the Server using a RPC then you know that it is being sent to the correct object as that is how Networkviews work (Unity manages the networkview relationships).

Hope that helps.

Nope, it does not because I am not using Unity’s network. See the first and last sentence in my original post

You will need to provide more details on how you have implemented your own networking because I believe that is where the solution lies rather than focusing mainly on the Unity API. As fholm has said, there are myriad ways to solve this problem. If we can better understand the specifics of your particular implementation then it would put us in a better position to assist.

What details do you mean exactly? Anyway, I will give a rough outline of (that part of) the networking here:

The server is an authorative server, meaning that the world it simulates is the truth. The clients only have a view on this world which may not always be 100% correct due to latency etc. The controls (WASD, mouse buttons etc.) issued on the clients are not executed on the client’s simulated world but are sent to the server instead and when the controls arrive on the server, they are executed there. This is the only thing that is sent from client to server. The server then sends to the clients the status of all objects in his simulated world that changed their properties: objects that moved, changed their velocity, got damaged, destroyed or got in any other way changed.
While the client may simulate the objects in his world further by himself (keyword: predicition), for example a ball rolling down a hill will probably just roll further in the next frame, any status update from the server overwrites the object status of the locally simulated world as this is just a view on the “true” world simulated on the server. One can talk about that the objects on the server are replicated onto the client.

The network implementation itself just ensures that these controls sent from client to server and these status updates sent from server to client are packed into and unpacked from messages and sent over network.

For this replication to work, the clients and the server need to agree that objects that should by replicated in their simulated worlds are “the same”. This happens with IDs. For example that ball rolling down a hill will have to have the same ID on the server and on the clients so that the server can tell the clients “That ball with ID 34 just got damaged by 34hp.” and every client will know exactly which object is meant.

I know this is a little late but after having just been through this myself and finding virtually no information on how to do it, I thought my findings might be useful.

I made an empty game object in the scene. Every destructible object in the scene gets added to the empty object by dragging it in as a child. Each destructible object has a script attached with health and object ID variables (these objects come from prefabs so only necessary to set up each type of object once). The ID variable is null until run-time when it is assigned a unique ID by iterating through GetChild of the empty object and assigning the matching ID. There are many ways you could assign an ID at this point so choose your own as required.

As the items are damaged or destroyed you can simply access the object ID and process the damage however you wish. When they are destoyed there is a little catch because Destroy() does not happen immediately, so I call Destroy() then remove the object from the child list by unparenting it. Naturally, you will need to send RPCs to advise clients when damage or destruction has occurred. I worked this out through discussions with whydoidoit and nastasache here how-to-properly-destroy-non-instantiated-objects-o.html. Hope this helps.