/// <summary> /// Called by UnityEditor. /// </summary> void OnValidate() { if (_serverOnly && _localPlayerAuthority) { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("Disabling Local Player Authority for " + gameObject + " because it is server-only."); } _localPlayerAuthority = false; } SetupIDs(); }
/// <summary> /// Sets the asset unique identifier during play. /// </summary> /// <param name="newAssetGUID">The new asset unique identifier.</param> public void SetDynamicAssetGUID(string newAssetGUID) { if (_assetGUID == null || _assetGUID == string.Empty || /*!IsValidAssetGUI(_assetGUID) || */ _assetGUID.Equals(newAssetGUID)) { _assetGUID = newAssetGUID; } else { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("SetDynamicAssetId object already has an assetId <" + _assetGUID + ">"); } } }
/// <summary> /// Calls TinyDeserialize in all Components that we received updates for. /// </summary> /// <param name="netMsg">A wrapper for a <see cref="TinyNetMsgType.StateUpdate"/> message.</param> void OnStateUpdateMessage(TinyNetMessageReader netMsg) { LastServerTick = netMsg.reader.GetUShort(); if (TinyNetLogLevel.logDev) { TinyLogger.Log("TinyNetClient::OnStateUpdateMessage frame: " + LastServerTick + " channel: " + netMsg.channelId); } while (netMsg.reader.AvailableBytes > 0) { int networkID = netMsg.reader.GetInt(); int rSize = netMsg.reader.GetInt(); _stateUpdateReader.Clear(); //Debug.Log("OnStateUpdate: RawDataSize: " + netMsg.reader.RawDataSize + ", Position: " + netMsg.reader.Position + ", rSize: " + rSize); _stateUpdateReader.SetSource(netMsg.reader.RawData, netMsg.reader.Position, rSize + netMsg.reader.Position); _stateUpdateReader.SetFrameTick(LastServerTick); //Debug.Log("OnStateUpdate: _stateUpdateReader " + _stateUpdateReader.RawDataSize + ", Position: " + _stateUpdateReader.Position); TinyNetIdentity localObject = GetTinyNetIdentityByNetworkID(networkID); if (localObject != null) { localObject.TinyDeserialize(_stateUpdateReader, false); } else { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("Did not find target for sync message for " + networkID); } } // We jump the reader position to the amount of data we read. //netMsg.reader.SetSource(netMsg.reader.RawData, netMsg.reader.Position + rSize, netMsg.reader.RawDataSize); netMsg.reader.SkipBytes(rSize); } foreach (TinyNetIdentity tinyNetId in LocalIdentityObjects.Values) { tinyNetId.OnStateUpdate(); } }
/// <summary> /// Always call this to hide an object from a client, or you will have sync issues. /// </summary> /// <param name="tni">The <see cref="TinyNetIdentity"/> of the object to hide.</param> public void HideObjectToConnection(TinyNetIdentity tni, bool isDestroyed) { if (!_observingNetObjects.Contains(tni)) { if (TinyNetLogLevel.logDev) { TinyLogger.LogWarning("RemoveFromVisList() called but object with networkdID: " + tni.NetworkID + " is not shown"); } return; } _observingNetObjects.Remove(tni); if (!isDestroyed) { // hide tni for this conn TinyNetServer.instance.HideForConnection(tni, this); } }
/// <summary> /// Called when an object is destroyed. /// </summary> /// <param name="netMsg">A wrapper for a <see cref="TinyNetObjectDestroyMessage"/>.</param> void OnObjectDestroy(TinyNetMessageReader netMsg) { netMsg.ReadMessage(s_TinyNetObjectDestroyMessage); if (TinyNetLogLevel.logDebug) { TinyLogger.Log("TinyNetClient::OnObjDestroy networkID:" + s_TinyNetObjectDestroyMessage.networkID); } TinyNetIdentity localObject = GetTinyNetIdentityByNetworkID(s_TinyNetObjectDestroyMessage.networkID); if (localObject != null) { RemoveTinyNetIdentityFromList(localObject); localObject.OnNetworkDestroy(); if (!TinyNetGameManager.instance.InvokeUnSpawnHandler(localObject.assetGUID, 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); _sceneIdentityObjectsToSpawn[localObject.sceneID] = localObject; } } } else { if (TinyNetLogLevel.logDebug) { TinyLogger.LogWarning("Did not find target for destroy message for " + s_TinyNetObjectDestroyMessage.networkID); } } }
/// <summary> /// By default it will deserialize the <see cref="TinyNetSyncVar"/> properties. /// </summary> /// <param name="netMsg">A wrapper for a <see cref="TinyNetObjectStateUpdate"/> message.</param> void OnStateUpdateMessage(TinyNetMessageReader netMsg) { int networkID = netMsg.reader.GetInt(); if (TinyNetLogLevel.logDev) { TinyLogger.Log("TinyNetClient::OnUpdateVarsMessage " + networkID + " channel:" + netMsg.channelId); } ITinyNetObject localObject = _localNetObjects[networkID]; if (localObject != null) { localObject.TinyDeserialize(netMsg.reader, false); } else { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("Did not find target for sync message for " + networkID); } } }
/// <summary> /// Called when an object is spawned. /// </summary> /// <param name="netMsg">A wrapper for a <see cref="TinyNetObjectSpawnMessage"/>.</param> void OnObjectSpawn(TinyNetMessageReader netMsg) { netMsg.ReadMessage(s_TinyNetObjectSpawnMessage); if (s_TinyNetObjectSpawnMessage.assetIndex < 0 || s_TinyNetObjectSpawnMessage.assetIndex > int.MaxValue || s_TinyNetObjectSpawnMessage.assetIndex > TinyNetGameManager.instance.GetAmountOfRegisteredAssets()) { if (TinyNetLogLevel.logError) { TinyLogger.LogError("OnObjSpawn networkID: " + s_TinyNetObjectSpawnMessage.networkID + " has invalid asset Id"); } return; } if (TinyNetLogLevel.logDev) { TinyLogger.Log("Client spawn handler instantiating [networkID:" + s_TinyNetObjectSpawnMessage.networkID + " asset ID:" + s_TinyNetObjectSpawnMessage.assetIndex + " pos:" + s_TinyNetObjectSpawnMessage.position + "]"); } TinyNetIdentity localTinyNetIdentity = GetTinyNetIdentityByNetworkID(s_TinyNetObjectSpawnMessage.networkID); // Check if this object was already registered in the scene: if (localTinyNetIdentity != null) { // this object already exists (was in the scene), just apply the update to existing object. ApplyInitialState(localTinyNetIdentity, s_TinyNetObjectSpawnMessage.position, s_TinyNetObjectSpawnMessage.initialState, s_TinyNetObjectSpawnMessage.networkID, null, s_TinyNetObjectSpawnMessage.frameTick); return; } GameObject prefab; SpawnDelegate handler; prefab = TinyNetGameManager.instance.GetPrefabFromAssetId(s_TinyNetObjectSpawnMessage.assetIndex); // Check if the prefab is registered in the list of spawnable prefabs. if (prefab != null) { var obj = (GameObject)Object.Instantiate(prefab, s_TinyNetObjectSpawnMessage.position, Quaternion.identity); localTinyNetIdentity = obj.GetComponent <TinyNetIdentity>(); if (localTinyNetIdentity == null) { if (TinyNetLogLevel.logError) { TinyLogger.LogError("Client object spawned for " + s_TinyNetObjectSpawnMessage.assetIndex + " does not have a TinyNetidentity"); } return; } ApplyInitialState(localTinyNetIdentity, s_TinyNetObjectSpawnMessage.position, s_TinyNetObjectSpawnMessage.initialState, s_TinyNetObjectSpawnMessage.networkID, obj, s_TinyNetObjectSpawnMessage.frameTick); // If not, check if the prefab have a spawn handler registered. } else if (TinyNetGameManager.instance.GetSpawnHandler(s_TinyNetObjectSpawnMessage.assetIndex, out handler)) { GameObject obj = handler(s_TinyNetObjectSpawnMessage.position, s_TinyNetObjectSpawnMessage.assetIndex); if (obj == null) { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("Client spawn handler for " + s_TinyNetObjectSpawnMessage.assetIndex + " returned null"); } return; } localTinyNetIdentity = obj.GetComponent <TinyNetIdentity>(); if (localTinyNetIdentity == null) { if (TinyNetLogLevel.logError) { TinyLogger.LogError("Client object spawned for " + s_TinyNetObjectSpawnMessage.assetIndex + " does not have a network identity"); } return; } localTinyNetIdentity.SetDynamicAssetGUID(TinyNetGameManager.instance.GetAssetGUIDFromAssetId(s_TinyNetObjectSpawnMessage.assetIndex)); ApplyInitialState(localTinyNetIdentity, s_TinyNetObjectSpawnMessage.position, s_TinyNetObjectSpawnMessage.initialState, s_TinyNetObjectSpawnMessage.networkID, obj, s_TinyNetObjectSpawnMessage.frameTick); // If also not, we literally cannot spawn this object and you should feel bad. } else { if (TinyNetLogLevel.logError) { TinyLogger.LogError("Failed to spawn server object, assetId=" + s_TinyNetObjectSpawnMessage.assetIndex + " networkID=" + s_TinyNetObjectSpawnMessage.networkID); } } }
/// <summary> /// Deserializes all <see cref="ITinyNetComponent"/> data. /// </summary> /// <param name="reader">The reader.</param> /// <param name="bInitialState">if set to <c>true</c> [b initial state].</param> public virtual void TinyDeserialize(TinyNetStateReader reader, bool firstStateUpdate) { if (firstStateUpdate && _tinyNetComponents == null) { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("TinyNetIdentity::TinyDeserialize called with firstStateUpdate true, but _tinyNetComponents is null."); } CacheTinyNetObjects(); } if (firstStateUpdate) { for (int i = 0; i < _tinyNetComponents.Length; i++) { _tinyNetComponents[i].ReceiveNetworkID(new TinyNetworkID(TinyInstanceID.NetworkID, (byte)(i + 1))); _recycleReader.Clear(); int rSize = reader.GetInt(); _recycleReader.SetSource(reader.RawData, reader.Position, rSize); _recycleReader.SetFrameTick(reader.FrameTick); _tinyNetComponents[i].TinyDeserialize(_recycleReader, firstStateUpdate); // We jump the reader position to the amount of data we read. reader.SkipBytes(rSize); } return; } switch (_dirtyFlag.Length) { case 8: TinyBitArrayUtil.U64ToBitArray(reader.GetByte(), _dirtyFlag); break; case 16: TinyBitArrayUtil.U64ToBitArray(reader.GetUShort(), _dirtyFlag); break; case 32: TinyBitArrayUtil.U64ToBitArray(reader.GetUInt(), _dirtyFlag); break; case 64: TinyBitArrayUtil.U64ToBitArray(reader.GetULong(), _dirtyFlag); break; } for (int i = 0; i < _tinyNetComponents.Length; i++) { if (_dirtyFlag[i] == true) { _recycleReader.Clear(); int rSize = reader.GetInt(); _recycleReader.SetSource(reader.RawData, reader.Position, rSize); _recycleReader.SetFrameTick(reader.FrameTick); //Debug.Log("[Deserialize] Size: " + rSize + ", DirtyFlag: " + TinyBitArrayUtil.Display(_recycleReader.PeekByte())); _tinyNetComponents[i].TinyDeserialize(_recycleReader, firstStateUpdate); // We jump the reader position to the amount of data we read. reader.SkipBytes(rSize); } } }
//============ Clients Functions ====================// /// <summary> /// Sets the client as ready. /// </summary> /// <param name="conn">The connection.</param> void SetClientReady(TinyNetConnection conn) { if (TinyNetLogLevel.logDebug) { TinyLogger.Log("SetClientReady for conn:" + conn.ConnectId); } if (conn.isReady) { if (TinyNetLogLevel.logDebug) { TinyLogger.Log("SetClientReady conn " + conn.ConnectId + " already ready"); } return; } if (conn.playerControllers.Count == 0) { if (TinyNetLogLevel.logDebug) { TinyLogger.LogWarning("Ready with no player object"); } } conn.isReady = true; // This is only in case this is a listen server. TinyNetLocalConnectionToClient localConnection = conn as TinyNetLocalConnectionToClient; if (localConnection != null) { if (TinyNetLogLevel.logDev) { TinyLogger.Log("NetworkServer Ready handling TinyNetLocalConnectionToClient"); } // Setup spawned objects for local player // Only handle the local objects for the first player (no need to redo it when doing more local players) // and don't handle player objects here, they were done above foreach (TinyNetIdentity tinyNetId in LocalIdentityObjects.Values) { // Need to call OnStartClient directly here, as it's already been added to the local object dictionary // in the above SetLocalPlayer call if (tinyNetId != null && tinyNetId.gameObject != null) { if (!tinyNetId.isClient) { localConnection.ShowObjectToConnection(tinyNetId); if (TinyNetLogLevel.logDev) { TinyLogger.Log("LocalClient.SetSpawnObject calling OnStartClient"); } tinyNetId.OnStartClient(); } } } return; } // Spawn/update all current server objects if (TinyNetLogLevel.logDebug) { TinyLogger.Log("Spawning " + LocalIdentityObjects.Count + " objects for conn " + conn.ConnectId); } TinyNetObjectSpawnFinishedMessage msg = new TinyNetObjectSpawnFinishedMessage(); msg.state = 0; //State 0 means we are starting the spawn messages 'spam'. SendMessageByChannelToTargetConnection(msg, DeliveryMethod.ReliableOrdered, conn); foreach (TinyNetIdentity tinyNetId in LocalIdentityObjects.Values) { if (tinyNetId == null) { if (TinyNetLogLevel.logWarn) { TinyLogger.LogWarning("Invalid object found in server local object list (null TinyNetIdentity)."); } continue; } if (!tinyNetId.gameObject.activeSelf) { continue; } if (TinyNetLogLevel.logDebug) { TinyLogger.Log("Sending spawn message for current server objects name='" + tinyNetId.gameObject.name + "' netId=" + tinyNetId.TinyInstanceID); } conn.ShowObjectToConnection(tinyNetId); } if (TinyNetLogLevel.logDebug) { TinyLogger.Log("Spawning objects for conn " + conn.ConnectId + " finished"); } msg.state = 1; //We finished spamming the spawn messages! SendMessageByChannelToTargetConnection(msg, DeliveryMethod.ReliableOrdered, conn); }