INSTANTIATING NETWORK-AWARE OBJECTS
uLink.Network.Instantiate() lets you instantiate a prefab on the server and on all clients in a very convenient manner. The uLink instantiation functions follow the same pattern as UnityEngine.Object.Instantiate(). When a client or server calls uLink.Network.Instantiate(), a game object of the prefab will be created for every connected uLink.NetworkPlayer in the client-server network. Note that a uLink.NetworkPlayer can represent any client as well as the server. Instantiations will not be sent over a uLink peer-to-peer connection. See the Peer-To-Peer manual chapter for how to replicate network-aware objects between peers in a peer-to-peer network.Communication in uLink is based on network views. For two network view components on different Unity clients to be able to talk to each other, they must have the same uLink.NetworkViewID. Read more about this in the Network Views manual chapter.
Registration of prefabs
Before you can instantiate prefabs across the network they need to be registered with uLink. There are two ways to do this.- Store all prefabs directly under the Resources folder of the project. This makes them registered automatically. While convenient for smaller projects, the drawback of this approach is that as soon as the number of prefabs grows, managing them will become harder and it will not be possible to start using Unity asset bundles to reduce the memory footprint of the client. This will also make the memory footprint of the server unnecessary large, therefore this is not the recommended way.
- Store prefabs in any folder, and then add the utility component uLinkRegisterPrefabs to one of the game objects in the scene and list all prefabs that should be registered inside this component. This is recommended for all projects since it allows you to structure your prefabs into separate folders. The uLinkRegisterPrefabs component only registers the prefabs for the scene it is placed in, so if you have several scenes that need to instantiate prefabs you must add the component uLinkRegisterPrefabs to those scenes as well. Note that different scenes can have different lists of prefabs depending on what needs to be instantiated in that scene. This will make the memory footprint of each scene as small as possible.
How to register prefabs downloaded in asset bundles is documented further down in this chapter.
NetworkPlayer roles for a game object: Creator, Owner and Proxy
Instantiation determines what role each uLink.NetworkPlayer has for the game object. The Creator role is assigned to the one that calls uLink.Network.Instantiate(). The Owner role is assigned to the uLink.NetworkPlayer that is explicitly set as owner in the instantiation call. If no owner is given, the default is the calling player (which will then be both Creator and Owner). The Proxy role is assigned to everyone else that is neither Creator nor Owner. uLink makes it possible to use different prefabs for creator, owner and proxies. The owner is usually the player with authority to move or manipulate the game object. Commonly in multiplayer games, the owner's version of a game object has more functionality and perhaps a different visual representation. With uLink you can use a completely different prefab for the owner. This makes it possible to attach a different set of scripts with extended functionallity for movement and other character control code. uLink also facilitates writing security checks that ensure only the owner of an object can send RPCs like "move" and "fire" to an authoritative server. A recommended practice is to write the security checks in the authoritatve server and to log warnings in a server log file if the RPC is sent from another client due to cheating or gameplay bugs. The prefab for a proxy is usally the representation of one player's game object in all the other players' clients. It can also be the representations of server owned objects like NPCs. The prefab used for the proxy usually has very limited game logic (fewer scripts) when comparing to the owner.It is important to note that each uLink.NetworkPlayer has a separate role for each game object.
The role a uLink.NetworkPlayer has for a given game object affects how uLink synchronizes it and treats RPCs. It is important that you understand the role mechanism when designing your instantiation code.
When not in authoritative server mode, i.e. when uLink.Network.isAuthoritativeServer is false, the following rules apply:
- State synchronization for a game object is sent from the Owner to everyone else. If the Owner is a client the state-synch is relayed through the server.
- Any uLink.NetworkPlayer can execute RPCs on a game object on any other uLink.NetworkPlayer. If a client executes an RPC on a game object on another client, it will be relayed through the server.
- State synchronization for a game object is sent from the server, if the server has the Creator role. If the server is not the Creator, then state-synch will not be sent for the game object.
- The server may execute RPCs on any network-aware object on any uLink.NetworkPlayer. If a client tries to execute an RPC on a game object on another client, the server will block the call. Any client may execute RPCs on a game object on the server.
When a client attempts to execute an RPC on a game object on the server, the server can compare the uLink.NetworkView.owner to the uLink.NetworkMessageInfo.sender of the RPC. This is the recommended way to make sure that a client only manipulates the server objects that it is allowed to.
Instantiate() variations
When you want to instantiate a network-aware object, there are a number of variations of the uLink.Network.Instantiate() method to choose from. They are all based on the following argument list, but in the cases where an argument is omitted a predefined value is used instead. Prefabs can generally be given as GameObjects or as strings.- viewID (uLink.NetworkViewID)
This allows you to manually assign an allocated view ID to the network view of the new game object. Use uLink.Network.AllocateViewID() to allocate a unique uLink.NetworkViewID. If you omit this parameter, a unique view ID will be automatically assigned to the new game object. - owner (uLink.NetworkPlayer)
This allows you to set the uLink.NetworkPlayer that should have the Owner role for the new game object. If you omit this parameter, the caller becomes the Owner in addition to being the Creator. This is the same as giving uLink.Network.player as owner. - prefab/creatorPrefab (GameObject/string/object)
This is the prefab uLink should use when instantiating the object for the uLink.NetworkPlayer that has the Creator role, i.e. the calling player. The method version that uses the object type for this argument is only kept for backwards compatibility with Unity Network, and should not be used in new uLink projects. This argument must always be included. - ownerPrefab (GameObject/string)
This is the prefab uLink should use when instantiating the object for the uLink.NetworkPlayer that has the Owner role. If no explicit owner has been assigned, the Owner and Creator is the same player. If you omit this argument, the Creator prefab will be used for Owner as well. - proxyPrefab (GameObject/string)
This is the prefab uLink should use when instantiating the object for the uLink.NetworkPlayer that has the Proxy role. If you omit this argument, the Creator prefab will be used for Proxy as well. - position (Vector3)
This is the world position of the new game object. This argument must always be included. - rotation (Quaternion)
This is the rotation of the new game object. This argument must always be included. - group (int)
This allows you to set a group number for the game object. This can later be used to filter network messages that are sent to more than one game object. If you don't want to use groups you can set this to 0. This argument must always be included. - initialData (object[])
Any additional arguments to uLink.Network.Instantiate() will be serialized and sent to the new game object as initial data. You can implement uLink.Network.uLink_OnNetworkInstantiate() to read the data in the game object. Any serializable data type can be used, see the Serialization manual chapter for more info. If you don't give any extra arguments, no initial data will be sent.
Instantiation sequence
When a network-aware object is instantiated, there is a sequence of events that can be responded to through callbacks. First, when the object is created, the following events occur.- Awake() is called for each component of the game object when the it is first created on each machine.
- OnEnable() is called for each component when the local game object becomes enabled.
- The uLink.Network.uLink_OnNetworkInstantiate() callback is the first point where the object has become network-aware. You should use this callback to read, and respond to, any initial data that was sent as part of the instantiation call.
- Start() is called for each component when all initiation of the object is complete, and before the first frame update.
- FixedUpdate() may be called several times per frame or not at all, depending on the current frame rate in relation to the physics time step.
- Update() is called once per frame, and is the recommended place to update most game logic.
- The uLink.Network.uLink_OnSerializeNetworkView() callback is used to serialize and deserialize state-synch to and from the network. Read about this concept in the State Synchronization manual chapter.
- LateUpdate() is called once per frame, and after both Update() and uLink.Network.uLink_OnSerializeNetworkView() has finished.
Sending initial data
Many times, it is convenient to send some extra parameters, called initial data, when instantiating network-aware objects. For example, in a game, the team membership of a new player could be chosen by the server to be the team with the least players, and the color of the new player's avatar should be chosen to be unique. These two variables can then be sent as the last two arguments to the uLink.Network.Instantiate() method call. The code for reading these two variables should be placed in the callback uLink.Network.uLink_OnNetworkInstantiate(). There are code examples for sending and receiving initial data in the API documentation for the uLink.Network class, uLink.Network.Instantiate() method and uLink.Network.uLink_OnNetworkInstantiate() callback.Prefabs in asset bundles
Asset bundles in Unity make it possible to reduce the memory footprint of the client by streaming prefabs to the client at the point they are needed. You can read more about loading asset bundles in the Unity manual:http://unity3d.com/support/documentation/Manual/Loading Resources at Runtime.html
You can write code that downloads asset bundles containing prefabs and then registers them in uLink; see uLink.NetworkInstantiator.AddAssetBundle() and uLink.NetworkInstantiator.AddPrefab(). After registration, uLink.Network.Instantiate() will be aware of the prefabs and can instantiate them. Although uLink.Network.Instantiate() is often called on the authoritave server, the corresponding prefabs to be instantiated in the clients (usually a proxy prefab and sometimes also an owner prefab) must have been registered in the client prior to the call to uLink.Network.Instantiate() on the server. We recommend programming the client (or all clients when needed) to send an RPC with a signal to the server that the asset bundle has been downloaded and the call to uLink.NetworkInstantiator.AddAssetBundle() has been made. When the server knows that all clients are ready, it can do the call to uLink.Network.Instantiate().
Replacing Instantiate with low-level code
When you use uLink.Network.Instantiate() to instantiate network objects, uLink will automatically make sure that the new game object has the same uLink.NetworkViewID on all clients. This is recommended in almost all cases. If you for some reason are prevented to use this automatic network instantiation feature, you can accomplish all the steps yourself. But before going down this path and make a lot of low level code we recommend that you take a look at the utility script uLinkInstantiatePool.cs that is included since uLink 1.2. That script is a code exaple for a pool of pre-instantiated game objects that can be used to increase performance. You should try to use or build upon the utility script, before going down the low level code path as it will save you a lot of work. Sequence for low level coding:- Call one of Unity's instantiation methods on the local client to create an instance of the prefab.
- Allocate and assign a unique uLink.NetworkViewID to the new game object's network view by calling uLink.NetworkViewBase.AllocateViewID() on the local client. This will also return the allocated view ID.
- Send a custom instantiation RPC to all clients that should have a replica of the game object, including the returned view ID. When received, the RPC receiving code should instantiate a game object and use uLink.NetworkViewBase.SetViewID() to set the view ID. This makes sure that the IDs match up and that the network views can talk to each other. To be able to send the instantiation RPC you need to have a networked game object already to send the RPC through. Read more about this in the RPC Details manual chapter.
Destroying objects
When an network-aware object is destroyed, it should be removed on all connected machines. The method uLink.Network.Destroy() helps you do this. You can either give it a GameObject, a uLink.NetworkView or a uLink.NetworkViewID, depending on which is more convenient. Regardless, the game object will be destroyed for all players. It is important to use this method instead of UnityEngine.GameObject.Destroy() for network-aware objects. When you call uLink.Network.Destroy() uLink will send an internal RPC to all connected peers and on every peer the object will be destryed. If you need to do some kind of cleanup code, just implement the callback OnDestroy() on all the peers that needs to do the cleanup. http://unity3d.com/support/documentation/ScriptReference/MonoBehaviour.OnDestroy.htmlTo destroy all network-aware objects in a scene, use the uLink.Network.DestroyAll() method. To destroy all network-aware objects that are owned by a specific player, use uLink.Network.DestroyPlayerObjects().
If you used uLink.Network.Instantiate() to create a game object, you should use uLink.Network.Destroy(), uLink.Network.DestroyAll() or uLink.Network.DestroyPlayerObjects() to destroy it.
In addition, all new players that connect after
the object has been destroyed should never get an instance of the
object. A complete code example for achieving exactly this, when a
player disconnects, is included in the RPC Details chapter, in the RPC
buffer section.






