public void SyncVarIsBitPacked([ValueSource(nameof(cases))] TestCase TestCase) { MyEnumByte value = TestCase.value; int expectedBitCount = TestCase.expectedBits; serverComponent.myValue = value; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { serverComponent.SerializeSyncVars(writer, true); Assert.That(writer.BitPosition, Is.EqualTo(expectedBitCount)); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment(), null)) { clientComponent.DeserializeSyncVars(reader, true); Assert.That(reader.BitPosition, Is.EqualTo(expectedBitCount)); Assert.That(clientComponent.myValue, Is.EqualTo(value)); } } }
public void SendLargerMaxBatchSizedMessageBatch() { int maxBatch = transport.GetMaxBatchSize(Channels.Reliable); int maxPacket = transport.GetMaxPacketSize(Channels.Reliable); // we can only tested if transport max batch < max message Assert.That(maxBatch < maxPacket, Is.True); // create a message > batch size byte[] message = new byte[maxPacket]; // add to batch queue PooledNetworkWriter writer = NetworkWriterPool.GetWriter(); writer.WriteBytes(message, 0, message.Length); batch.messages.Enqueue(writer); // send batch - client should receive that exact message connection.SendBatch(Channels.Reliable, batch); Assert.That(transport.clientIncoming.Count, Is.EqualTo(1)); Assert.That(transport.clientIncoming.Dequeue().data.Length, Is.EqualTo(message.Length)); }
public void BufferReturnsMutliplePacketsInTheOrderTheyWereWriten() { const string expectedMessage1 = "first Message"; const string expectedMessage2 = "second Message"; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteString(expectedMessage1); buffer.Write(writer.ToArraySegment()); } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteString(expectedMessage2); buffer.Write(writer.ToArraySegment()); } string message1; string message2; ArraySegment <byte> package1 = buffer.GetNextPacket(); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(package1)) { message1 = reader.ReadString(); } Assert.IsTrue(buffer.HasPackets()); ArraySegment <byte> package2 = buffer.GetNextPacket(); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(package2)) { message2 = reader.ReadString(); } Assert.That(message1, Is.EqualTo(expectedMessage1)); Assert.That(message2, Is.EqualTo(expectedMessage2)); }
public IEnumerator SendMany() { Task <RunNode.Result> task = RunNode.RunAsync("ReceiveManyMessages.js", 5_000); yield return(server.WaitForConnection); const int messageCount = 100; for (int i = 0; i < messageCount; i++) { using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { writer.WriteByte((byte)i); writer.WriteInt32(100); ArraySegment <byte> segment = writer.ToArraySegment(); server.ServerSend(new List <int> { 1 }, Channels.DefaultReliable, segment); } } yield return(new WaitForSeconds(1)); server.ServerDisconnect(1); yield return(new WaitUntil(() => task.IsCompleted)); RunNode.Result result = task.Result; string expectedFormat = "length: 5 msg: {0:X2} 64 00 00 00"; IEnumerable <string> expected = Enumerable.Range(0, messageCount).Select(i => string.Format(expectedFormat, i)); result.AssetTimeout(false); result.AssetOutput(expected.ToArray()); result.AssetErrors(); }
public void MessageIsBitPacked() { var inStruct = new BitPackStruct { myValue = value, }; using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { // generic write, uses generated function that should include bitPacking writer.Write(inStruct); Assert.That(writer.BitPosition, Is.EqualTo(32)); using (PooledNetworkReader reader = NetworkReaderPool.GetReader(writer.ToArraySegment(), null)) { var outStruct = reader.Read <BitPackStruct>(); Assert.That(reader.BitPosition, Is.EqualTo(32)); Assert.That(outStruct, Is.EqualTo(inStruct)); } } }
public void PoolReUsesWritersUpToSizeLimit() { NetworkWriterPool.Capacity = 1; // get 2 writers PooledNetworkWriter a = NetworkWriterPool.GetWriter(); PooledNetworkWriter b = NetworkWriterPool.GetWriter(); // recycle all NetworkWriterPool.Recycle(a); NetworkWriterPool.Recycle(b); // get 2 new ones PooledNetworkWriter c = NetworkWriterPool.GetWriter(); PooledNetworkWriter d = NetworkWriterPool.GetWriter(); // exactly one should be reused, one should be new bool cReused = c == a || c == b; bool dReused = d == a || d == b; Assert.That((cReused && !dReused) || (!cReused && dReused)); }
protected virtual void Update() { if (!hasAuthority) { return; } if (NetworkTime.localTime >= _lastSendTime + SendInterval) { _lastSendTime = NetworkTime.localTime; if (!HasChanged()) { return; } using var writer = NetworkWriterPool.GetWriter(); Serialize(writer); UpdatePrevData(); var data = writer.ToArraySegment(); if (UseReliableRpc) { CmdSendDataReliable(data); } else { CmdSendDataUnreliable(data); } if (QSBCore.IsHost) { _lastKnownData ??= new byte[data.Count]; Array.Copy(data.Array !, data.Offset, _lastKnownData, 0, data.Count); } } }
/// <summary> /// Send custom values to client's SyncObject. /// </summary> /// <param name="target">Target to send.</param> /// <param name="behaviorOwner"><see cref="Mirror.NetworkIdentity"/> of object that owns <see cref="Mirror.NetworkBehaviour"/>.</param> /// <param name="targetType"><see cref="Mirror.NetworkBehaviour"/>'s type.</param> /// <param name="customAction">Custom writing action.</param> public static void SendCustomSyncObject(this Player target, NetworkIdentity behaviorOwner, Type targetType, Action <NetworkWriter> customAction) { /* * Cant be use if you dont understand(ill make more use easily soonTM) * Example(SyncList) [EffectOnlySCP207]: * player.SendCustomSync(player.ReferenceHub.networkIdentity, typeof(PlayerEffectsController), (writer) => { * writer.WritePackedUInt64(1ul); // DirtyObjectsBit * writer.WritePackedUInt32((uint)1); // DirtyIndexCount * writer.WriteByte((byte)SyncList<byte>.Operation.OP_SET); // Operations * writer.WritePackedUInt32((uint)0); // EditIndex * writer.WriteByte((byte)1); // Item * }); */ NetworkWriter writer = NetworkWriterPool.GetWriter(); NetworkWriter writer2 = NetworkWriterPool.GetWriter(); MakeCustomSyncWriter(behaviorOwner, targetType, customAction, null, writer, writer2); NetworkServer.SendToClientOfPlayer(target.ReferenceHub.networkIdentity, new UpdateVarsMessage() { netId = behaviorOwner.netId, payload = writer.ToArraySegment() }); NetworkWriterPool.Recycle(writer); NetworkWriterPool.Recycle(writer2); }
/// <summary> /// Reply to the client to inform it of this server /// </summary> /// <remarks> /// Override if you wish to ignore server requests based on /// custom criteria such as language, full server game mode or difficulty /// </remarks> /// <param name="request">Request comming from client</param> /// <param name="endpoint">Address of the client that sent the request</param> protected virtual void ProcessClientRequest(Request request, IPEndPoint endpoint) { Response info = ProcessRequest(request, endpoint); if (info == null) { return; } using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter()) { try { writer.WriteInt64(secretHandshake); writer.Write(info); ArraySegment <byte> data = writer.ToArraySegment(); // signature matches // send response serverUdpClient.Send(data.Array, data.Count, endpoint); } catch (Exception ex) { Debug.LogException(ex, this); } } }
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: /// <code> /// public void MyServerRpc(float thrusting, int spin) /// { /// NetworkWriter networkWriter = new NetworkWriter(); /// networkWriter.Write(thrusting); /// networkWriter.WritePackedUInt32((uint) spin); /// base.SendServerRpcInternal(cmdName, networkWriter, cmdName); /// } /// /// public void UserCode_MyServerRpc(float thrusting, int spin) /// { /// // whatever the user was doing before /// /// } /// </code> /// </remarks> MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute serverRpcAttr) { MethodDefinition cmd = SubstituteMethod(md); ILProcessor worker = md.Body.GetILProcessor(); // if (IsServer) // { // call the body // return; // } CallBody(worker, cmd); // NetworkWriter writer = NetworkWriterPool.GetWriter() VariableDefinition writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, md.Module.ImportReference(() => NetworkWriterPool.GetWriter()))); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Cmd call if (!WriteArguments(worker, md, writer, RemoteCallType.ServerRpc)) { return(cmd); } string cmdName = md.Name; int channel = serverRpcAttr.GetField("channel", 0); bool requireAuthority = serverRpcAttr.GetField("requireAuthority", true); // invoke internal send and return // load 'base.' to call the SendServerRpc function with worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldtoken, md.DeclaringType.ConvertToGenericIfNeeded())); // invokerClass worker.Append(worker.Create(OpCodes.Call, () => Type.GetTypeFromHandle(default)));
/// <summary> /// Replaces the user code with a stub. /// Moves the original code to a new method /// </summary> /// <param name="td">The class containing the method </param> /// <param name="md">The method to be stubbed </param> /// <param name="ServerRpcAttr">The attribute that made this an RPC</param> /// <returns>The method containing the original code</returns> /// <remarks> /// Generates code like this: /// <code> /// public void MyServerRpc(float thrusting, int spin) /// { /// NetworkWriter networkWriter = new NetworkWriter(); /// networkWriter.Write(thrusting); /// networkWriter.WritePackedUInt32((uint) spin); /// base.SendServerRpcInternal(cmdName, networkWriter, cmdName); /// } /// /// public void UserCode_MyServerRpc(float thrusting, int spin) /// { /// // whatever the user was doing before /// /// } /// </code> /// </remarks> private MethodDefinition GenerateStub(MethodDefinition md, CustomAttribute serverRpcAttr, int rpcIndex, ValueSerializer[] paramSerializers) { var cmd = SubstituteMethod(md); var worker = md.Body.GetILProcessor(); // if (IsServer) // { // call the body // return; // } CallBody(worker, cmd); // NetworkWriter writer = NetworkWriterPool.GetWriter() var writer = md.AddLocal <PooledNetworkWriter>(); worker.Append(worker.Create(OpCodes.Call, md.Module.ImportReference(() => NetworkWriterPool.GetWriter()))); worker.Append(worker.Create(OpCodes.Stloc, writer)); // write all the arguments that the user passed to the Cmd call WriteArguments(worker, md, writer, paramSerializers, RemoteCallType.ServerRpc); var cmdName = md.FullName; var channel = serverRpcAttr.GetField(nameof(ServerRpcAttribute.channel), 0); var requireAuthority = serverRpcAttr.GetField(nameof(ServerRpcAttribute.requireAuthority), true); var sendMethod = GetSendMethod(md, worker); // ServerRpcSender.Send(this, 12345, writer, channel, requireAuthority) worker.Append(worker.Create(OpCodes.Ldarg_0)); worker.Append(worker.Create(OpCodes.Ldc_I4, rpcIndex)); worker.Append(worker.Create(OpCodes.Ldloc, writer)); worker.Append(worker.Create(OpCodes.Ldc_I4, channel)); worker.Append(worker.Create(requireAuthority ? OpCodes.Ldc_I4_1 : OpCodes.Ldc_I4_0)); worker.Append(worker.Create(OpCodes.Call, sendMethod)); NetworkWriterHelper.CallRelease(module, worker, writer); worker.Append(worker.Create(OpCodes.Ret)); return(cmd); }