void ApprovalCheck(byte[] _compressedSerializedData, ulong _clientId, NetworkingManager.ConnectionApprovedDelegate _callback) { Debug.Log("Client " + _clientId + " is being approved."); bool approve = true; bool createPlayerObject = true; ConnectionApprovalData connectionData = _compressedSerializedData.GetDecompressedAndDeserialized <ConnectionApprovalData>(); // I don't actually know that this is going to do us much good, but it seems like if they hack their game this might catch it and I already coded it :p approve = true || (connectionData.playerPrefabHash == SpawnManager.GetPrefabHashFromGenerator("Player")); if (!connectionDataCache.ContainsKey(_clientId)) { connectionDataCache.Add(_clientId, connectionData); } //If approve is true, the connection gets added. If it's false. The client gets disconnected _callback(createPlayerObject, null, approve, null, null); Debug.Log("Client " + _clientId + " approved, spawning player object"); // set a reference to the NetworkedClient on the Player class for later networking CustomMessagingManager.SendNamedMessage("JoinConnectionAccepted", _clientId, Stream.Null); }
// this happens after approval (96% sure :p) private void ML_OnClientConnected(ulong _clientId) { if (!NetworkingManager.Singleton.IsHost && !NetworkingManager.Singleton.IsServer) { return; } Debug.Log("Client " + _clientId + " connected"); NetworkedClient client = NetworkingManager.Singleton.ConnectedClients[_clientId]; Player player = client.GetPlayer(); player.ClientId.Value = _clientId; player.Name.Value = connectionDataCache[_clientId].playerName; connectionDataCache.Remove(_clientId); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter w = PooledBitWriter.Get(stream)) { w.WriteUInt64(player.NetworkedObject.NetworkId); CustomMessagingManager.SendNamedMessage("ClientConnected", AllClientIDs(), stream); } } }
public void CustomMessageManagerAssigned() { var gameObject = new GameObject(nameof(CustomMessageManagerAssigned)); var networkManager = gameObject.AddComponent <NetworkManager>(); var transport = gameObject.AddComponent <DummyTransport>(); // MLAPI sets this in validate networkManager.NetworkConfig = new NetworkConfig() { // Set the current scene to prevent unexpected log messages which would trigger a failure RegisteredScenes = new List <string>() { SceneManager.GetActiveScene().name } }; // Set dummy transport that does nothing networkManager.NetworkConfig.NetworkTransport = transport; CustomMessagingManager preManager = networkManager.CustomMessagingManager; // Start server to cause init networkManager.StartServer(); Debug.Assert(preManager == null); Debug.Assert(networkManager.CustomMessagingManager != null); Object.DestroyImmediate(gameObject); }
public CustomMessages() { CustomMessagingManager.RegisterNamedMessageHandler(MessageName, (sender, payload) => { Debug.Log("MESSAGE HANDLER"); using (var reader = PooledBitReader.Get(payload)) { ChatReceived?.Invoke(this, reader.ReadString().ToString()); } }); }
public void SendChatMessage(ulong clientId, string message) { using (var messageStream = PooledBitStream.Get()) { using (var writer = PooledBitWriter.Get(messageStream)) { writer.WriteString(message); CustomMessagingManager.SendNamedMessage(MessageName, clientId, messageStream); } } }
private void OnDestroy() { if (Singleton == this) { CustomMessagingManager.UnregisterNamedMessageHandler("NetworkInput"); CustomMessagingManager.UnregisterNamedMessageHandler("NetworkState"); Singleton = null; } }
private void Start() { timer = Stopwatch.StartNew(); entities = new Dictionary <ulong, Entity>(); LastUpdate = CurrentTime; transport = NetworkingManager.Singleton.GetComponent <LiteNetLibTransport.LiteNetLibTransport>(); CustomMessagingManager.RegisterNamedMessageHandler("NetworkInput", ReceiveInput); CustomMessagingManager.RegisterNamedMessageHandler("NetworkState", ReceiveState); }
void Start() { Instance = this; NetworkingManager.Singleton.OnClientConnectedCallback += ML_OnClientConnected; NetworkingManager.Singleton.OnClientDisconnectCallback += ML_OnClientDisconnect; CustomMessagingManager.RegisterNamedMessageHandler("ClientConnected", ClientConnected); CustomMessagingManager.RegisterNamedMessageHandler("ClientDisconnected", ClientDisconnected); }
void StartListenForDownloadRequests() { Debug.Log("Listening for download requests"); if (!NetworkingManager.Singleton.IsServer) { Debug.LogWarning("Only run ListenForDownloadRequests() on the server"); return; } CustomMessagingManager.RegisterNamedMessageHandler("DownloadFilesRequest", DownloadRequestReceived); }
protected override void RegisterClientMessageHandlers() { CustomMessagingManager.RegisterNamedMessageHandler(NetMessageName.s2c_ConnectResult, (ulSenderClientId, hStream) => { using (var hReader = PooledNetworkReader.Get(hStream)) { ConnectStatus eStatus = (ConnectStatus)hReader.ReadInt32(); m_hConnectFinishCallback?.Invoke(eStatus); } }); }
public override void Connect() { // Register receiving packets on the client from the server CustomMessagingManager.RegisterNamedMessageHandler("DissonanceToClient", (senderClientId, stream) => { Int32 length = stream.Length > Int32.MaxValue ? Int32.MaxValue : Convert.ToInt32(stream.Length); Byte[] buffer = new Byte[length]; stream.Read(buffer, 0, length); base.NetworkReceivedPacket(new ArraySegment <byte>(buffer)); }); Connected(); }
public void SendCommand <T>(T message) where T : ICommand, new() { using (var stream = PooledBitStream.Get()) { using (var writer = PooledBitWriter.Get(stream)) { writer.WriteInt32((int)message.CommandCode); message.Write(stream); } CustomMessagingManager.SendUnnamedMessage(null, stream); } }
void RequestDownloads() { ProgressUI.SetMessage("Downloading files", "Waiting for headers..."); ProgressUI.Show(); Debug.Log("Requesting downloads"); LargeRPC download = new LargeRPC("InitialGameDownload"); download.ListenForDownload(); download.OnDownloadComplete += FinishedDownloadingFromHost; download.OnProgressUpdated += UpdateProgressBar; CustomMessagingManager.SendNamedMessage("DownloadFilesRequest", NetworkingManager.Singleton.ServerClientId, Stream.Null); }
public void SendInputMessage(InputMessage msg) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteInt32(msg.messageID); writer.WriteInt32(msg.timeCreated); writer.WriteUInt32(msg.playerId); writer.WriteShortArray(msg.keycode.ToArray()); CustomMessagingManager.SendNamedMessage("Input", this.ServerClientId, stream, "customChannel"); } } }
private void ML_OnClientDisconnect(ulong _clientId) { if (!NetworkingManager.Singleton.IsHost && !NetworkingManager.Singleton.IsServer) { return; } Debug.Log("Client " + _clientId + " connected: "); using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { CustomMessagingManager.SendNamedMessage("ClientDisconnected", AllClientIDs(), stream); } } }
public void SendReplicationMessage(ReplicationMessage msg) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteInt32(msg.messageID); writer.WriteInt32(msg.timeCreated); writer.WriteUInt32(msg.entityId); writer.WriteInt16((byte)msg.shape); writer.WriteVector2(msg.pos); writer.WriteVector2(msg.speed); writer.WriteDouble(msg.size); CustomMessagingManager.SendNamedMessage("Replication", null, stream, "customChannel"); } } }
protected override void SendUnreliable(ArraySegment <byte> packet) { if (NetworkingManager.Singleton.IsHost) { // As we are the host in this scenario we should send the packet directly to the server rather than over the network and avoid loopback issues _network.server.NetworkReceivedPacket(new MlapiConn(), packet); } else { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { for (var i = 0; i < packet.Count; i++) { writer.WriteByte(packet.Array[i + packet.Offset]); } CustomMessagingManager.SendNamedMessage("DissonanceToServer", NetworkingManager.Singleton.ServerClientId, stream, "MLAPI_TIME_SYNC"); } } } }
void JoinServer(string _ip, int _port = 20202, string _password = "") { if (Transport == null) { Transport = NetworkingManager.Singleton.GetComponent <UnetTransport>(); } Transport.ConnectAddress = _ip; //takes string Transport.ConnectPort = _port; Debug.Log("Connecting to " + _ip + ":" + _port); ulong?hsh = SpawnManager.GetPrefabHashFromGenerator("Player"); Debug.Log(hsh); ConnectionApprovalData connectionData = new ConnectionApprovalData((ulong)hsh, playerNameField.text, _password); NetworkingManager.Singleton.NetworkConfig.ConnectionData = connectionData.GetSerializedAndCompressed(); NetworkingManager.Singleton.StartClient(); Debug.Log("registered JoinConnectionAccepted"); CustomMessagingManager.RegisterNamedMessageHandler("JoinConnectionAccepted", OnJoinConnectionAccepted); }
protected override void SendUnreliable(MlapiConn destination, ArraySegment <byte> packet) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { var count = packet.Count; var offset = packet.Offset; for (var i = 0; i < count; i++) { writer.WriteByte(packet.Array[i + offset]); } if (NetworkingManager.Singleton.LocalClientId == destination.clientId) { // As we are the host in this scenario we should send the packet directly to the client rather than over the network and avoid loopback issues _network.client.NetworkReceivedPacket(packet); } else { CustomMessagingManager.SendNamedMessage("DissonanceToClient", destination.clientId, stream, "MLAPI_TIME_SYNC"); } } } }
void StopListenForDownloadRequests() { CustomMessagingManager.UnregisterNamedMessageHandler("DownloadFilesRequest"); }
public void RegisterClientNetworkHandlers() { CustomMessagingManager.RegisterNamedMessageHandler("Replication", HandleReplicationMessage); }
public void StopListening() { CustomMessagingManager.UnregisterNamedMessageHandler(MessageName); Debug.Log("Stopped Listening"); }
void Awake() { CustomMessagingManager.RegisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_SERVER_PROCESS_DOWN_COMMAND, MessageHandler_Server_SendServerProcessDownCommand); CustomMessagingManager.RegisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_SYSTEM_USERID_TO_SERVER, MessageHandler_Server_SendSystemUserIdToServer); CustomMessagingManager.RegisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_PLAYER_EJECTION_COMMAND, MessageHandler_Server_SendPlayerEjectionCommand); }
public void ListenForDownload() { ChangeState(LargeRPCState.Receive_AwaitingFirstPacket); CustomMessagingManager.RegisterNamedMessageHandler(MessageName, ReceiveFilesDownloadPieceFromSender); Debug.Log("Started Listening"); }
// Essentially, when this is passed an empty list, the okay will be sent to the server IEnumerator SendNeededFilesListToSender(List <int> _fileIDs) { bool allFilesReceived = _fileIDs.Count == 0; Debug.Log("sending needed files, files: " + _fileIDs.Count); PooledBitStream bitStream = PooledBitStream.Get(); PooledBitWriter writer = PooledBitWriter.Get(bitStream); if (allFilesReceived) { writer.WriteBit(true); writer.WriteIntArray(_fileIDs.ToArray()); writer.WriteBit(true); CustomMessagingManager.SendNamedMessage(MessageName, SenderID, bitStream, "MLAPI_INTERNAL"); bitStream.Dispose(); writer.Dispose(); _fileIDs.Clear(); StopListening(); if (OnDownloadComplete != null) { OnDownloadComplete(SendOrReceiveFlag.Receive, SenderID); } ChangeState(LargeRPCState.Idle); } else { var i = 0; List <int> ids = _fileIDs; foreach (var id in ids) { i++; bool isFinalPacket = i >= _fileIDs.Count; if (i >= _fileIDs.Count) { writer.WriteBit(isFinalPacket); writer.WriteIntArray(_fileIDs.ToArray()); writer.WriteBit(false); CustomMessagingManager.SendNamedMessage(MessageName, SenderID, bitStream, "MLAPI_INTERNAL"); bitStream.Dispose(); writer.Dispose(); bitStream = PooledBitStream.Get(); writer = PooledBitWriter.Get(bitStream); _fileIDs.Clear(); yield return(new WaitForSeconds(1 / 8)); break; } } } yield break; }
public void ListenForFilesNeededListOrCompletion() { CustomMessagingManager.RegisterNamedMessageHandler(MessageName, ReceiveFilesNeededListFromReceiver); Debug.Log("Started Listening"); }
/// <summary> /// this function splits FILES into MEMORY SAFE sized chunks and safely sends one before starting another /// /// files receipient needs to receive the same number of headers with each header packet (packet 1 counts as a header packet) /// </summary> public IEnumerator SendFilesDownloadRoutine(string[] _paths, ulong _clientID) { Debug.Log("coroutine started"); if (State != LargeRPCState.Idle) { Debug.LogWarning("Cannot start sending files while files are being sent, waiting for Idle state to begin"); yield break; } ReceiverID = _clientID; ChangeState(LargeRPCState.Send_SendingHeaders); #region comment -- header sizes /* -- Header sizes -- * packet 1 * int fileCount 4b | long downloadSize 8b | <start headers> * * header packets * int fileID 4b | string filename varsize | byte[256] hash 32b | long fileLength 8b | bool isLastInPacket 1bit * * subsequent packets * int fileID 4b | int filedata_length 4b | byte[var] filedata <=netChunkSize | bool isLastInPacket 1byte */ #endregion #region Grab Download Information // grab info for headers foreach (var path in _paths) { if (File.Exists(path)) { using (FileStream fs = File.Open(path, FileMode.Open)) { Debug.Log(fs.Name); int id = Headers.Count; byte[] fileHash = fs.sha256(); yield return(new WaitForEndOfFrame()); FileHeader header = new FileHeader(id, Path.GetFileName(path), fileHash, fs.Length); Headers.Add(header); DownloadSize += header.fileSize; } // let it exit if it needs to, giving StopRoutine() a chance yield return(0); } else { Debug.LogWarning("File not found, skipping: " + path); } } #endregion #region send headers PooledBitStream bitStream = PooledBitStream.Get(); PooledBitWriter writer = PooledBitWriter.Get(bitStream); // fileCount writer.WriteInt32(Headers.Count); // downloadSize writer.WriteInt64(DownloadSize); var headersThisPacket = 0; var packetsSent = 0; Debug.Log("Sending headers"); foreach (var header in Headers) { // let it exit if it needs to, giving StopRoutine() a chance yield return(0); Debug.Log(headersThisPacket + " " + packetsSent); var path = header.path; var id = header.id; headersThisPacket++; // fileID writer.WriteInt32(header.id); // filename writer.WriteString(path); Debug.Log(Encoding.Unicode.GetString(header.hash)); // hash writer.WriteByteArray(header.hash, 32); // fileLength writer.WriteInt64(header.fileSize); bool isLastPacket = id >= Headers.Count - 1; // send it off if we've filled up a packet if (headersThisPacket >= headersPerPacket || isLastPacket) { Debug.Log("message going out"); // isLastInPacket writer.WriteBit(true); CustomMessagingManager.SendNamedMessage(MessageName, _clientID, bitStream, "MLAPI_INTERNAL"); /* headers are pretty small, they really don't need the receiver to check in here unless it becomes a problem * * // if we haven't sent any packets yet when we get here, wait for an okay from the receiver * if (packetsSent == 0) * { * ChangeState(LargeRPCState.Send_AwaitingOkayToSend); * * while (State == LargeRPCState.Send_AwaitingOkayToSend) * { * yield return new WaitForSeconds(0.5f); * } * }*/ packetsSent++; Debug.Log("headers: " + headersThisPacket + " packets: " + packetsSent); headersThisPacket = 0; writer.Dispose(); bitStream.Dispose(); bitStream = PooledBitStream.Get(); writer = PooledBitWriter.Get(bitStream); // don't wait on the last one if (!isLastPacket) { yield return(new WaitForSeconds(1 / 14)); } } else { writer.WriteBit(false); } } writer.Dispose(); bitStream.Dispose(); #endregion ChangeState(LargeRPCState.Send_AwaitingFilesNeededList); ListenForFilesNeededListOrCompletion(); // loop start while (State != LargeRPCState.Complete) { // let it exit if it needs to, giving StopRoutine() a chance yield return(0); Debug.Log("Not done, running not-complete loop"); #region wait for needed files list while (State == LargeRPCState.Send_AwaitingFilesNeededList || State == LargeRPCState.Send_EnsuringIntegrity) { Debug.Log("waiting for list"); yield return(new WaitForSeconds(0.5f)); } Debug.Log("No longer waiting for list"); #endregion // runs ReceiveFilesNeededListFromReceiver, changes state to either Send_SendingFiles or Complete if (filesToSend.Count > 0) { Debug.Log("client still needs more files, sending"); #region send files bitStream = PooledBitStream.Get(); writer = PooledBitWriter.Get(bitStream); foreach (var header in Headers) { // let it exit if it needs to, giving StopRoutine() a chance yield return(0); Debug.Log("processing header"); if (File.Exists(header.path) && filesToSend.Contains(header.id)) { Debug.Log("file is needed"); using (FileStream fs = File.Open(header.path, FileMode.Open)) { // while loop pulled from fs.Read docs from microsoft, a little confusing to the glance but works and will be fast int numBytesToRead = (int)fs.Length; int numBytesRead = 0; while (numBytesToRead > 0) { Debug.Log("still bytes left"); int thisFileChunkSize = fileChunkSize; thisFileChunkSize = Mathf.Min(thisFileChunkSize, numBytesToRead); byte[] fileChunk = new byte[thisFileChunkSize]; // Read may return anything from 0 to numBytesToRead. int n = fs.Read(fileChunk, numBytesRead, thisFileChunkSize); foreach (byte[] netChunk in fileChunk.Slices(netChunkSize, false)) { Debug.Log("processing next chunk"); // fileID writer.WriteInt32(header.id); //writer.WriteInt32(netChunk.Length); Debug.Log("netchunk len: " + netChunk.Length); // filedata writer.WriteByteArray(netChunk); // isLastInPacket, need to add in its own size bool isLastInPacket = bitStream.Length + 1 >= netChunkSize || netChunk.Length < netChunkSize; writer.WriteBit(isLastInPacket); if (isLastInPacket) { CustomMessagingManager.SendNamedMessage(MessageName, _clientID, bitStream, "MLAPI_INTERNAL"); Debug.Log("packet sent"); yield return(new WaitForSeconds(1 / 14)); writer.Dispose(); bitStream.Dispose(); bitStream = PooledBitStream.Get(); writer = PooledBitWriter.Get(bitStream); } } // Break when the end of the file is reached. if (n == 0) { Debug.Log("end of file reached, this is a failsafe"); break; } numBytesRead += n; numBytesToRead -= n; } } } } Debug.Log("all headers processed"); filesToSend.Clear(); // just failsafing these, should be disposed of already writer.Dispose(); bitStream.Dispose(); #endregion ChangeState(LargeRPCState.Send_EnsuringIntegrity); } Debug.Log("Waiting before checking completion again"); yield return(new WaitForSeconds(1f)); } StopListening(); Debug.Log("files sent"); if (OnDownloadComplete != null) { OnDownloadComplete(SendOrReceiveFlag.Send, ReceiverID); } ChangeState(LargeRPCState.Idle); yield break; }
void OnDestroy() { CustomMessagingManager.UnregisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_SERVER_PROCESS_DOWN_COMMAND); CustomMessagingManager.UnregisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_SYSTEM_USERID_TO_SERVER); CustomMessagingManager.UnregisterNamedMessageHandler(GameRoomMessagingHubConstants.SEND_PLAYER_EJECTION_COMMAND); }
public void RegisterServerNetworkHandlers() { CustomMessagingManager.RegisterNamedMessageHandler("Input", HandleInputMessage); }
internal void Tick(uint tick) { if (IsServer) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteUInt32(tick); Dictionary <ulong, IEntityState> states = new Dictionary <ulong, IEntityState>(entities.Count); foreach (Entity entity in entities.Values) { IEntityState state = entity.DoStateTick(tick); if (state != null) { states.Add(entity.NetworkId, state); } } writer.WriteInt32(states.Count); foreach (var state in states) { writer.WriteUInt64(state.Key); state.Value.Serialize(writer); } CustomMessagingManager.SendNamedMessage("NetworkState", null, stream); } } } else { foreach (Entity entity in entities.Values) { entity.DoStateTick(tick); } uint predictTicks = (uint)Math.Ceiling(RTT / FixedStep) + 2 * Deviation; for (uint i = 0; i < predictTicks; i++) { if (tick + i > LastPredictedTick) { using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { LastPredictedTick = tick + i; var authEntities = entities.Values.Where(e => e.IsOwner); int count = authEntities.Count(); Dictionary <ulong, IEntityInput> inputs = new Dictionary <ulong, IEntityInput>(count); foreach (Entity entity in authEntities) { IEntityInput input = entity.DoInputTick(tick + i); if (input != null) { inputs.Add(entity.NetworkId, input); } } writer.WriteUInt32(tick + i); writer.WriteInt32(inputs.Count); foreach (var input in inputs) { writer.WriteUInt64(input.Key); input.Value.Serialize(writer); } CustomMessagingManager.SendNamedMessage("NetworkInput", NetworkingManager.Singleton.ServerClientId, stream); } } } foreach (Entity entity in entities.Values.Where(e => e.extrapolate || e.IsOwner)) { entity.DoStateTick(tick + i); } } foreach (Entity entity in entities.Values) { entity.Present(); } } }