/// <summary> /// Signal that the client connection is ready to enter the game. /// <para>This could be for example when a client enters an ongoing game and has finished loading the current scene. The server should respond to the SYSTEM_READY event with an appropriate handler which instantiates the players object for example.</para> /// </summary> /// <param name="conn">The client connection which is ready.</param> /// <returns>True if succcessful</returns> public static bool Ready(NetworkConnection conn) { if (ready) { Debug.LogError("A connection has already been set as ready. There can only be one."); return(false); } if (LogFilter.Debug) { Debug.Log("ClientScene.Ready() called with connection [" + conn + "]"); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(ReadyMessage), null, 1); #endif if (conn != null) { conn.Send(new ReadyMessage()); ready = true; readyConnection = conn; readyConnection.isReady = true; return(true); } Debug.LogError("Ready() called with invalid connection object: conn=null"); return(false); }
protected void SendRPCInternal(Type invokeClass, string rpcName, NetworkWriter writer, int channelId) { // this was in Weaver before if (!NetworkServer.active) { Debug.LogError("RPC Function " + rpcName + " called on Client."); return; } // This cannot use NetworkServer.active, as that is not specific to this object. if (!isServer) { Debug.LogWarning("ClientRpc " + rpcName + " called on un-spawned object: " + name); return; } // construct the message RpcMessage message = new RpcMessage { netId = netId, componentIndex = ComponentIndex, functionHash = GetMethodHash(invokeClass, rpcName), // type+func so Inventory.RpcUse != Equipment.RpcUse payload = writer.ToArraySegment() // segment to avoid reader allocations }; NetworkServer.SendToReady(netIdentity, message, channelId); #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(RpcMessage), $"{invokeClass.GetType()}.{rpcName}", 1); #endif }
internal static void OnLocalClientObjectDestroy(NetworkConnection _, ObjectDestroyMessage msg) { if (LogFilter.Debug) { Debug.Log("ClientScene.OnLocalObjectObjDestroy netId:" + msg.netId); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ObjectDestroyMessage), msg.netId.ToString(), 1); #endif NetworkIdentity.spawned.Remove(msg.netId); }
internal static void OnObjectSpawnStarted(NetworkConnection _, ObjectSpawnStartedMessage msg) { if (LogFilter.Debug) { Debug.Log("SpawnStarted"); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ObjectSpawnStartedMessage), null, 1); #endif PrepareToSpawnSceneObjects(); isSpawnFinished = false; }
internal static void OnSpawnSceneObject(NetworkConnection _, SpawnSceneObjectMessage msg) { if (LogFilter.Debug) { Debug.Log("Client spawn scene handler instantiating [netId:" + msg.netId + " sceneId:" + msg.sceneId + " pos:" + msg.position); } // owner? if (msg.owner) { OnSpawnMessageForOwner(msg.netId); } if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) { // this object already exists (was in the scene) localObject.Reset(); ApplySpawnPayload(localObject, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId); #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(SpawnSceneObjectMessage), localObject.gameObject.name, 1); #endif return; } NetworkIdentity spawnedId = SpawnSceneObject(msg.sceneId); if (spawnedId == null) { Debug.LogError("Spawn scene object not found for " + msg.sceneId.ToString("X") + " SpawnableObjects.Count=" + spawnableObjects.Count); // dump the whole spawnable objects dict for easier debugging if (LogFilter.Debug) { foreach (KeyValuePair <ulong, NetworkIdentity> kvp in spawnableObjects) { Debug.Log("Spawnable: SceneId=" + kvp.Key + " name=" + kvp.Value.name); } } return; } if (LogFilter.Debug) { Debug.Log("Client spawn for [netId:" + msg.netId + "] [sceneId:" + msg.sceneId + "] obj:" + spawnedId.gameObject.name); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(SpawnSceneObjectMessage), spawnedId.gameObject.name, 1); #endif spawnedId.Reset(); spawnedId.pendingOwner = msg.owner; ApplySpawnPayload(spawnedId, msg.position, msg.rotation, msg.scale, msg.payload, msg.netId); }
internal static void OnLocalClientObjectHide(NetworkConnection _, ObjectHideMessage msg) { if (LogFilter.Debug) { Debug.Log("ClientScene::OnLocalObjectObjHide netId:" + msg.netId); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ObjectHideMessage), msg.netId.ToString(), 1); #endif if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity localObject) && localObject != null) { localObject.OnSetLocalVisibility(false); } }
internal static void OnClientAuthority(NetworkConnection _, ClientAuthorityMessage msg) { if (LogFilter.Debug) { Debug.Log("ClientScene.OnClientAuthority for netId: " + msg.netId); } if (NetworkIdentity.spawned.TryGetValue(msg.netId, out NetworkIdentity identity)) { #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ClientAuthorityMessage), identity.gameObject.name, 1); #endif identity.HandleClientAuthority(msg.authority); } }
ulong DirtyObjectBits() { ulong dirtyObjects = 0; for (int i = 0; i < syncObjects.Count; i++) { SyncObject syncObject = syncObjects[i]; if (syncObject.IsDirty) { dirtyObjects |= 1UL << i; #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(UpdateVarsMessage), syncObject.GetType().Name, 1); #endif } } return(dirtyObjects); }
internal static void OnObjectSpawnFinished(NetworkConnection _, ObjectSpawnFinishedMessage msg) { if (LogFilter.Debug) { Debug.Log("SpawnFinished"); } NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ObjectSpawnFinishedMessage), null, 1); // paul: Initialize the objects in the same order as they were initialized // in the server. This is important if spawned objects // use data from scene objects foreach (NetworkIdentity identity in NetworkIdentity.spawned.Values.OrderBy(uv => uv.netId)) { if (!identity.isClient) { identity.OnStartClient(); CheckForOwner(identity); } } isSpawnFinished = true; }
protected void SendEventInternal(Type invokeClass, string eventName, NetworkWriter writer, int channelId) { if (!NetworkServer.active) { Debug.LogWarning("SendEvent no server?"); return; } // construct the message SyncEventMessage message = new SyncEventMessage { netId = netId, componentIndex = ComponentIndex, functionHash = GetMethodHash(invokeClass, eventName), // type+func so Inventory.RpcUse != Equipment.RpcUse payload = writer.ToArraySegment() // segment to avoid reader allocations }; NetworkServer.SendToReady(netIdentity, message, channelId); #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(SyncEventMessage), $"{invokeClass.GetType()}.{eventName}", 1); #endif }
static void DestroyObject(uint netId) { if (LogFilter.Debug) { Debug.Log("ClientScene.OnObjDestroy netId:" + netId); } if (NetworkIdentity.spawned.TryGetValue(netId, out NetworkIdentity localObject) && localObject != null) { NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(ObjectDestroyMessage), netId.ToString(), 1); localObject.OnNetworkDestroy(); if (!InvokeUnSpawnHandler(localObject.assetId, localObject.gameObject)) { // default handling if (localObject.sceneId == 0) { Object.Destroy(localObject.gameObject); } else { // scene object.. disable it in scene instead of destroying localObject.gameObject.SetActive(false); spawnableObjects[localObject.sceneId] = localObject; } } NetworkIdentity.spawned.Remove(netId); localObject.MarkForReset(); } else { if (LogFilter.Debug) { Debug.LogWarning("Did not find target for destroy message for " + netId); } } }
// this is called from message handler for Owner message internal static void InternalAddPlayer(NetworkIdentity identity) { if (LogFilter.Debug) { Debug.LogWarning("ClientScene.InternalAddPlayer"); } #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(AddPlayerMessage), identity.gameObject.name, 1); #endif // NOTE: It can be "normal" when changing scenes for the player to be destroyed and recreated. // But, the player structures are not cleaned up, we'll just replace the old player localPlayer = identity; if (readyConnection != null) { readyConnection.playerController = identity; } else { Debug.LogWarning("No ready connection found for setting player controller during InternalAddPlayer"); } }
/// <summary> /// Removes the player from the game. /// </summary> /// <returns>True if succcessful</returns> public static bool RemovePlayer() { if (LogFilter.Debug) { Debug.Log("ClientScene.RemovePlayer() called with connection [" + readyConnection + "]"); } if (readyConnection.playerController != null) { readyConnection.Send(new RemovePlayerMessage()); #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Incoming, typeof(RemovePlayerMessage), readyConnection.playerController.gameObject.name, 1); #endif Object.Destroy(readyConnection.playerController.gameObject); readyConnection.playerController = null; localPlayer = null; return(true); } return(false); }
protected void SendCommandInternal(Type invokeClass, string cmdName, NetworkWriter writer, int channelId) { // this was in Weaver before // NOTE: we could remove this later to allow calling Cmds on Server // to avoid Wrapper functions. a lot of people requested this. if (!NetworkClient.active) { Debug.LogError("Command Function " + cmdName + " called on server without an active client."); return; } // local players can always send commands, regardless of authority, other objects must have authority. if (!(isLocalPlayer || hasAuthority)) { Debug.LogWarning("Trying to send command for object without authority."); return; } if (ClientScene.readyConnection == null) { Debug.LogError("Send command attempted with no client running [client=" + connectionToServer + "]."); return; } // construct the message CommandMessage message = new CommandMessage { netId = netId, componentIndex = ComponentIndex, functionHash = GetMethodHash(invokeClass, cmdName), // type+func so Inventory.RpcUse != Equipment.RpcUse payload = writer.ToArraySegment() // segment to avoid reader allocations }; ClientScene.readyConnection.Send(message, channelId); #if MIRROR_PROFILING NetworkProfiler.RecordMessage(NetworkDirection.Outgoing, typeof(CommandMessage), $"{invokeClass.GetType()}.{cmdName}", 1); #endif }