private void OnTriggerEnter2D(Collider2D col) { switch (col.name) { case "LeftWall": right++; break; case "RightWall": left++; break; } using (PooledBitStream stream = PooledBitStream.Get()) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteInt32(left); writer.WriteInt32(right); InvokeClientRpcOnEveryonePerformance(WinRPC, stream); } } Spawn(); }
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"); } } }
public void Write(Stream stream) { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteInt32(stacks.Count); foreach (KeyValuePair <string, InventoryItem> kvp in stacks) { InventoryItem curInvItem = kvp.Value; if (curInvItem.Value.name != kvp.Key) { Debug.LogWarning("NetworkSharedItem name did not match " + kvp.Key + " != " + curInvItem.Value.name); } writer.WriteString(kvp.Key); writer.WriteInt32(curInvItem.Count); } } }
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"); } } }
public static void RegisterSerialization() { SerializationManager.RegisterSerializationHandlers <ItemSlotNetworkedData>((Stream stream, ItemSlotNetworkedData instance) => { using (PooledBitWriter writer = PooledBitWriter.Get(stream)) { writer.WriteStringPacked(instance.itemId); writer.WriteInt32(instance.itemAmount); } }, (Stream stream) => { using (PooledBitReader reader = PooledBitReader.Get(stream)) { return(new ItemSlotNetworkedData(reader.ReadStringPacked().ToString(), reader.ReadInt32())); } }); }
/// <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; }
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(); } } }