protected override void OnNeutronFixedUpdate() { base.OnNeutronFixedUpdate(); { if (HasAuthority) { if (LocalTime >= (_lastSyncedTime + (1d / _packetsPerSecond))) { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var writer = Begin_iRPC(1, stream, out var option); writer.Write(_rb.position); writer.Write(_rb.velocity); writer.Write(_rb.angularVelocity); writer.Write(LocalTime); writer.Write(); End_iRPC(1, stream); } _lastSyncedTime = LocalTime; } } else { if (_sync) { _rb.position = _position; _rb.velocity = _velocity; _rb.angularVelocity = _angularVelocity; } } } }
private void Update() { if (Input.GetKeyDown(KeyCode.Return)) { if (_inputField.text.Length > 0) { if (_autoChat) { Main.SendMessage(_inputField.text, MatchmakingTo.Auto); //* Send the message to all clients. } else { //* Send the message to all clients. using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var writer = Begin_gRPC(stream, Main); writer.Write(_inputField.text); writer.Write(); End_gRPC(CHAT_ID, stream, Protocol.Tcp, Main); } } //* Reset inputfields. _inputField.text = ""; _inputField.ActivateInputField(); } else { LogHelper.Error("Input field is empty!"); } } }
protected async void HandshakeHandler(NeutronPlayer player, double clientTime, Authentication authentication) { if (authentication.Pass.Decrypt(out string phrase)) { authentication = new Authentication(authentication.User, phrase, false); try { if (await OnAuthentication.Invoke(player, authentication)) //* First packet { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) //* Second First packet { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Handshake); writer.Write(LocalTime); writer.Write(clientTime); writer.Write(player.StateObject.UdpLocalEndPoint.Port); writer.WriteWithInteger(player); player.Write(writer); } OnPlayerConnected?.Invoke(player); //* Three packet } } catch (Exception ex) // Tasks manual catch exception. { LogHelper.Stacktrace(ex); } } else if (!LogHelper.Error("Auth decrypt failed!")) { DisconnectHandler(player); } }
protected void ChatHandler(NeutronPlayer player, ChatMode packet, MatchmakingTo matchmakingTo, int viewId, string message) { if (OnMessageReceived.Invoke(player, message)) { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Chat); writer.Write(message); if (packet == ChatMode.Global) { player.Write(writer, TargetTo.All, matchmakingTo, Protocol.Tcp); } else if (packet == ChatMode.Private) { if (MatchmakingHelper.Server.GetPlayer(viewId, out NeutronPlayer playerFound)) { playerFound.Write(player, writer, TargetTo.Me, MatchmakingTo.Me, Protocol.Tcp); } else { player.Error(Packet.Chat, "Player not found!", ErrorMessage.PLAYER_NOT_FOUND); } } } } }
public static void Disconnect(NeutronPlayer player, string reason) { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Disconnection); writer.Write(player.Id); writer.Write(reason); player.Write(writer, Helper.GetHandlers().OnPlayerDisconnected); } }
/// <summary> ///* Envia uma mensagem para o jogador.<br/> ///* (Server-Side). /// </summary> /// <param name="player"></param> /// <param name="packet"></param> /// <param name="message"></param> public static void Error(this NeutronPlayer player, Packet packet, string message, int errorCode = 0) { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Error); writer.WritePacket((byte)packet); writer.Write(message); writer.Write(errorCode); player.Write(writer); } }
//* Client->Server //* Server->Client protected void Send(NeutronStream stream, NeutronPlayer player, bool isServerSide, Protocol protocol) { NeutronStream.IWriter writer = stream.Writer; if (!isServerSide) { Send(stream, protocol); } else { var packet = Helper.PollPacket(writer.ToArray(), player, player, protocol); Neutron.Server.AddPacket(packet); } }
#pragma warning disable IDE1006 protected void iRPCHandler(NeutronPlayer owner, NeutronPlayer sender, short viewId, byte rpcId, byte instanceId, byte[] buffer, RegisterMode registerType, TargetTo targetTo, CacheMode cache, Protocol protocol) #pragma warning restore IDE1006 { void Run((int, int, RegisterMode) key) { bool Send() { MatchmakingTo matchmakingTo = MatchmakingTo.Auto; if (targetTo == TargetTo.Me) { matchmakingTo = MatchmakingTo.Me; } using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.iRPC); writer.WritePacket((byte)registerType); writer.Write(viewId); writer.Write(rpcId); writer.Write(instanceId); writer.WriteNext(buffer); MatchmakingHelper.Internal.AddCache(rpcId, viewId, writer, owner, cache, CachedPacket.iRPC); owner.Write(sender, writer, targetTo, matchmakingTo, protocol); } return(true); } if (MatchmakingHelper.Server.GetNetworkObject(key, owner, out NeutronView neutronView)) { if (neutronView.iRPCs.TryGetValue((rpcId, instanceId), out RPCInvoker remoteProceduralCall)) { try { iRPCAttribute iRPCAttribute = remoteProceduralCall.iRPC; if (ReflectionHelper.iRPC(buffer, remoteProceduralCall, owner)) { Send(); } } catch (Exception ex) { LogHelper.Stacktrace(ex); } } else { Send(); } }
protected void SetNicknameHandler(NeutronPlayer player, string nickname) { if (OnPlayerNicknameChanged.Invoke(player, nickname)) { player.Nickname = nickname; using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Nickname); writer.Write(nickname); player.Write(writer, Helper.GetHandlers().OnPlayerNicknameChanged); } } }
protected override void OnPlayerJoinedChannel(NeutronChannel channel, NeutronPlayer player, bool isMine, Neutron neutron) { base.OnPlayerJoinedChannel(channel, player, isMine, neutron); { if (isMine) { using (NeutronStream stream = new NeutronStream()) { var writer = neutron.BeginPlayer(stream, Vector3.zero, Quaternion.identity); writer.Write(); neutron.EndPlayer(stream, 10); } } } }
private IEnumerator WaitForNextFrame() { while (true) { //currentFrameTime += Time.deltaTime; //if (currentFrameTime >= (1f / _packetsPerSecond)) //{ packets++; using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var writer = Begin_iRPC(1, stream, out var option); if (_syncPosition) { writer.Write(transform.localPosition); } if (_syncRotation) { if (_compressQuaternion) { writer.WriteCompressed(transform.localRotation, _floatMultiplicationPrecision); } else { writer.Write(transform.localRotation); } } if (_syncScale) { writer.Write(transform.localScale); } writer.Write(LocalTime); //* timestamp writer.Write(); End_iRPC(1, stream); } currentFrameTime = 0; //} yield return(new WaitForSecondsRealtime(1f / _sendRate)); } }
protected override void Update() { base.Update(); { if (HasAuthority) { //if (Input.GetKeyDown(KeyCode.Return)) { for (int i = 0; i < 5; i++) { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var writer = Begin_iRPC(10, stream, out var options); writer.Write(i); writer.Write(); End_iRPC(10, stream); } } } } } }
protected void SynchronizeHandler(NeutronPlayer player, Protocol protocol) { //* Envia todos os jogadores conectados para mim. using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; NeutronPlayer[] players = MatchmakingHelper.Internal.GetPlayersByMatchmakingTo(player, MatchmakingTo.Auto); players = players.Where(x => x.Id != player.Id).ToArray(); writer.WritePacket((byte)Packet.Synchronize); writer.Write((byte)1); writer.WriteNext(players.Serialize().Compress(CompressionMode.Deflate)); player.Write(writer, TargetTo.Me, MatchmakingTo.Me, protocol); } //* Envia-me para todos os jogadores conectados. using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = stream.Writer; writer.WritePacket((byte)Packet.Synchronize); writer.Write((byte)2); writer.WriteNext(player.Serialize().Compress(CompressionMode.Deflate)); player.Write(writer, TargetTo.Others, MatchmakingTo.Auto, protocol); } }
private void RunPacket(NeutronPacket neutronPacket) { byte[] pBuffer = neutronPacket.Buffer; //* Get the packet buffer. bool isServer = neutronPacket.IsServerSide; //* Get the packet is server side. Protocol protocol = neutronPacket.Protocol; //* Get the packet protocol. NeutronPlayer owner = neutronPacket.Owner; //* Get the packet owner. NeutronPlayer sender = neutronPacket.Sender; //* Get the packet sender. using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IReader reader = stream.Reader; reader.SetBuffer(pBuffer); //* Set the buffer. Packet outPacket = (Packet)reader.ReadPacket(); //* Read the packet. if (OnReceivePacket(outPacket) || isServer) { switch (outPacket) { case Packet.TcpKeepAlive: { using (NeutronStream tcpStream = Neutron.PooledNetworkStreams.Pull()) { NeutronStream.IWriter writer = tcpStream.Writer; writer.WritePacket((byte)Packet.TcpKeepAlive); owner.Write(writer); } } break; case Packet.Handshake: { var appId = reader.ReadString(); //* Read the app id. var time = reader.ReadDouble(); //* Read the time. var authentication = reader.ReadWithInteger <Authentication>(); //* Read the authentication. if (appId.Decrypt(out appId)) { //* Decrypt the app id. if (Helper.GetSettings().GlobalSettings.AppId == appId) { HandshakeHandler(owner, time, authentication); //* Handshake the player. } else { owner.Error(Packet.Handshake, "Update your game version, it does not match the current server version."); Task.Run(async() => { await Task.Delay(150); //* Submit the disconnect after receiving the error message. DisconnectHandler(owner); //* Disconnect the player. }); } } else if (!LogHelper.Error("Failed to verify handshake!")) { DisconnectHandler(owner); //* Disconnect the player. } } break; case Packet.Nickname: { var nickname = reader.ReadString(); //* Read the nickname. SetNicknameHandler(owner, nickname); } break; case Packet.Chat: { var matchmakingTo = default(MatchmakingTo); //* Create the matchmaking to. var viewId = default(int); //* Read the view id. var chatPacket = (ChatMode)reader.ReadPacket(); //* Read the chat mode. switch (chatPacket) { case ChatMode.Global: matchmakingTo = (MatchmakingTo)reader.ReadPacket(); //* Read the matchmaking to. break; case ChatMode.Private: viewId = reader.ReadInt(); //* Read the view id. break; } string message = reader.ReadString(); ChatHandler(owner, chatPacket, matchmakingTo, viewId, message); } break; case Packet.iRPC: { var registerType = (RegisterMode)reader.ReadPacket(); //* Read the register mode. var targetTo = (TargetTo)reader.ReadPacket(); //* Read the target to. var cache = (CacheMode)reader.ReadPacket(); //* Read the cache mode. short viewId = reader.ReadShort(); //* Read the view id. var rpcId = reader.ReadByte(); //* Read the rpc id. var instanceId = reader.ReadByte(); //* Read the instance id. var buffer = reader.ReadNext(); //* Read the buffer. iRPCHandler(owner, sender, viewId, rpcId, instanceId, buffer, registerType, targetTo, cache, protocol); //* Handle the iRPC. } break; case Packet.gRPC: { var id = reader.ReadByte(); //* Read the id. var buffer = reader.ReadNext(); //* Read the buffer. gRPCHandler(owner, sender, id, buffer, protocol); //* Handle the gRPC. } break; case Packet.GetChannels: { GetChannelsHandler(owner); //* Handle the get channels. } break; case Packet.JoinChannel: { var channelId = reader.ReadInt(); //* Read the channel id. JoinChannelHandler(owner, channelId); //* Handle the join channel. } break; case Packet.GetCache: { var cachedPacket = (CachedPacket)reader.ReadPacket(); //* Read the cached packet. var Id = reader.ReadByte(); //* Read the id. var includeMe = reader.ReadBool(); //* Send packets to me? GetCacheHandler(owner, cachedPacket, Id, includeMe); //* Handle the get cache. } break; case Packet.CreateRoom: { var password = reader.ReadString(); //* Read the password. var room = reader.ReadWithInteger <NeutronRoom>(); //* Read the room. CreateRoomHandler(owner, room, password); //* Handle the create room. } break; case Packet.GetRooms: { GetRoomsHandler(owner); //* Handle the get rooms. } break; case Packet.JoinRoom: { var roomId = reader.ReadInt(); //* Read the room id. var password = reader.ReadString(); //* Read the password. JoinRoomHandler(owner, roomId, password); //* Handle the join room. } break; case Packet.Leave: { var packet = (MatchmakingMode)reader.ReadPacket(); //* Read the matchmaking mode. if (packet == MatchmakingMode.Room) { LeaveRoomHandler(owner); //* Handle the leave room. } else if (packet == MatchmakingMode.Channel) { LeaveChannelHandler(owner); //* Handle the leave channel. } } break; case Packet.Destroy: { DestroyPlayerHandler(owner); //* Handle the destroy player. } break; case Packet.SetPlayerProperties: { var properties = reader.ReadString(); //* Read the properties. SetPlayerPropertiesHandler(owner, properties); //* Handle the set player properties. } break; case Packet.SetRoomProperties: { var properties = reader.ReadString(); //* Read the properties. SetRoomPropertiesHandler(owner, properties); //* Handle the set room properties. } break; case Packet.UdpKeepAlive: { var time = reader.ReadDouble(); //* Read the time. PingHandler(owner, time); //* Handle the ping. } break; case Packet.CustomPacket: { // var isMine; // TargetTo targetTo = default(TargetTo); // MatchmakingTo matchmakingTo = default(MatchmakingTo); // int viewId = reader.ReadInt(); // byte packet = reader.ReadPacket(); // if ((isMine = PlayerHelper.IsMine(owner, viewId))) // { // targetTo = (TargetTo)reader.ReadPacket(); // matchmakingTo = (MatchmakingTo)reader.ReadPacket(); // } // byte[] buffer = reader.ReadWithInteger(); // CustomPacketHandler(owner, isMine, viewId, buffer, packet, targetTo, matchmakingTo, protocol); } break; case Packet.AutoSync: { var registerMode = (RegisterMode)reader.ReadPacket(); //* Read the register mode. var viewId = reader.ReadShort(); //* Read the view id. var instanceId = reader.ReadByte(); //* Read the instance id. var parameters = reader.ReadNext(); //* Read the parameters. OnAutoSyncHandler(neutronPacket, viewId, instanceId, parameters, registerMode); //* Handle the auto sync. } break; case Packet.Synchronize: { SynchronizeHandler(owner, protocol); //* Handle the synchronize. } break; } } else { LogHelper.Error("Client is not allowed to run this packet."); } } }
//* Aqui os dados são enviados aos seus clientes. public void OnSendingData(NeutronPlayer player, NeutronPacket neutronPacket) { try { using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var playerId = (short)neutronPacket.Sender.Id; //* Get the player id. byte[] pBuffer = neutronPacket.Buffer.Compress(); //* Compress the packet. switch (neutronPacket.Protocol) { case Protocol.Tcp: { NeutronStream.IWriter wHeader = stream.Writer; wHeader.WriteByteArrayWithAutoSize(pBuffer); //* Write the packet and its size. wHeader.Write(playerId); //* Write the player id in header. byte[] hBuffer = wHeader.ToArray(); //* Get the header buffer. wHeader.Write(); //* End the header. NetworkStream networkStream = player.TcpClient.GetStream(); //* Get the network stream. switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: networkStream.Write(hBuffer, 0, hBuffer.Length); //* Send the header. break; default: if (Helper.GetConstants().SendAsyncPattern == AsynchronousType.APM) { networkStream.Write(hBuffer, 0, hBuffer.Length); //* Send the header. } else { SocketHelper.SendTcpAsync(networkStream, hBuffer, player.TokenSource.Token); //* Send the header. } break; } NeutronStatistics.ServerTCP.AddOutgoing(hBuffer.Length); //* Add the outgoing bytes to the statistics. } break; case Protocol.Udp: { NeutronStream.IWriter wHeader = stream.Writer; wHeader.Write(playerId); //* Write the player id in header. wHeader.WriteNext(pBuffer); //* Write the packet and its size. byte[] hBuffer = wHeader.ToArray(); //* Get the header buffer. wHeader.Write(); //* End the header. player.StateObject.SendDatagram = hBuffer; //* Set the datagram to send. if (player.StateObject.UdpIsReady()) //* Check if the player is ready to send. { NonAllocEndPoint remoteEp = (NonAllocEndPoint)player.StateObject.NonAllocEndPoint; //* Get the remote end point, prevent GC pressure/allocations. switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: SocketHelper.SendBytes(player.UdpClient, hBuffer, remoteEp); //* Send the datagram. break; default: { switch (Helper.GetConstants().SendAsyncPattern) { case AsynchronousType.APM: { SocketHelper.BeginSendBytes(player.UdpClient, hBuffer, remoteEp, (ar) => { SocketHelper.EndSendBytes(player.UdpClient, ar); //* End the send. }); //* Begin the send. break; } default: SocketHelper.SendUdpAsync(player.UdpClient, player.StateObject, remoteEp); //* Send the datagram. break; } break; } } NeutronStatistics.ServerUDP.AddOutgoing(hBuffer.Length); //* Add the outgoing bytes to the statistics. } else { LogHelper.Error($"{player.StateObject.TcpRemoteEndPoint} Cannot receive UDP data. trying... if you are running on WSL2, change the ip from \"localhost\" to the IP address of WSL2 on the client."); } } break; } } } catch (ThreadAbortException) { } catch (SocketException) { } catch (ObjectDisposedException) { } catch (OperationCanceledException) { } catch (Exception) { } }
//* Usado para enviar os dados para o servidor. //* Client->Server protected void Send(NeutronStream stream, Protocol protocol = Protocol.Tcp) { try { if (IsServer) { throw new NeutronException("To use this packet on the server side it is necessary to assign the \"Player\" parameter."); } #if !UNITY_SERVER || UNITY_EDITOR if (This.IsConnected) { NeutronStream.IWriter wHeader = stream.hWriter; NeutronStream.IWriter wPacket = stream.Writer; byte[] pBuffer = wPacket.ToArray().Compress(); //! Otimizado para evitar alocações, bom isso depende de como você usa o Neutron :p switch (protocol) { //* ValueTask ainda não funciona na Unity, isso mesmo, em 2021 com .net 6 e standard 2.1, e a unity atrasada com essa merda de Mono, vê se pode? case Protocol.Tcp: { if (wHeader.GetPosition() == 0) { wHeader.WriteByteArrayWithAutoSize(pBuffer); //* Pre-fixa o tamanho da mensagem no cabeçalho, um inteiro/short/byte(4/2/1 bytes), e a mensagem. byte[] hBuffer = wHeader.ToArray(); wHeader.Write(); NetworkStream networkStream = TcpClient.GetStream(); switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: networkStream.Write(hBuffer, 0, hBuffer.Length); //* Envia os dados pro servidor de modo síncrono, esta opção é melhor, não aloca e tem performance de CPU. break; default: if (Helper.GetConstants().SendAsyncPattern == AsynchronousType.APM) { networkStream.Write(hBuffer, 0, hBuffer.Length); //* Envia os dados pro servidor de modo assíncrono, mentira, envia da mesma forma de "SendType.Synchronous", preguiça mesmo. :p, porque BeginReceive e Endreceive é chato de fazer pro TCP :D } else { SocketHelper.SendTcpAsync(networkStream, hBuffer, TokenSource.Token); //* Envia os dados pro servidor de forma assíncrona., faz alocações pra caralho, no tcp não tanto, mas no UDP..... é foda. e usa muita cpu, evite, se souber como resolver, sinta-se a vontade para contribuir. } break; } //* Adiciona no profiler a quantidade de dados de saída(Outgoing). NeutronStatistics.ClientTCP.AddOutgoing(hBuffer.Length); } else { throw new Exception($"Send(Tcp): Invalid position, is not zero! Pos -> {wHeader.GetPosition()} Capacity -> {wHeader.GetCapacity()}. You called Finish() ?"); } } break; case Protocol.Udp: { if (UdpEndPoint == null) { LogHelper.Error("Unauthenticated!"); } else { StateObject.SendDatagram = pBuffer; switch (Helper.GetConstants().SendModel) { case SendType.Synchronous: SocketHelper.SendBytes(UdpClient, pBuffer, UdpEndPoint); //* envia de modo síncrono, evita alocações e performance boa. break; default: { switch (Helper.GetConstants().SendAsyncPattern) { case AsynchronousType.APM: { //* aloca, mas não tanto, boa performance. SocketHelper.BeginSendBytes(UdpClient, pBuffer, UdpEndPoint, (ar) => { SocketHelper.EndSendBytes(UdpClient, ar); }); break; } default: SocketHelper.SendUdpAsync(UdpClient, StateObject, UdpEndPoint); //* se foder, aloca pra caralho e usa cpu como a unreal engine, ValueTask poderia resolver, mas...... break; } break; } } //* Adiciona no profiler a quantidade de dados de saída(Outgoing). NeutronStatistics.ClientUDP.AddOutgoing(pBuffer.Length); } } break; } } else { LogHelper.Error("Non-connected socket, sending failed!"); } #else throw new Exception("To use this packet on the server side it is necessary to assign the \"Player\" parameter."); #endif } catch (ObjectDisposedException) { } catch (SocketException) { } catch (Exception ex) { LogHelper.Stacktrace(ex); } }
//* Sincroniza as variaveis. public override bool OnAutoSynchronization(NeutronStream stream, bool isMine) { var writer = stream.Writer; var reader = stream.Reader; for (int i = 0; i < m_Parameters.Length; i++) { var cParam = m_Parameters[i]; if (cParam.SyncMode == SyncOnOff.NonSync) { continue; } else { //* Percorre os parâmetros, escreve e ler os seus valores. switch (cParam.ParameterType) { case AnimatorControllerParameterType.Float: { if (isMine) { writer.Write(m_Animator.GetFloat(cParam.ParameterName)); } else if (DoNotPerformTheOperationOnTheServer) { m_Animator.SetFloat(cParam.ParameterName, reader.ReadFloat()); } } break; case AnimatorControllerParameterType.Int: { if (isMine) { writer.Write(m_Animator.GetInteger(cParam.ParameterName)); } else if (DoNotPerformTheOperationOnTheServer) { m_Animator.SetInteger(cParam.ParameterName, reader.ReadInt()); } } break; case AnimatorControllerParameterType.Bool: { if (isMine) { writer.Write(m_Animator.GetBool(cParam.ParameterName)); } else if (DoNotPerformTheOperationOnTheServer) { m_Animator.SetBool(cParam.ParameterName, reader.ReadBool()); } } break; case AnimatorControllerParameterType.Trigger: break; } writer.Write(); } } return(OnValidateAutoSynchronization(isMine)); }
protected override void OnNeutronUpdate() { base.OnNeutronUpdate(); { //if (HasAuthority) //{ // t += 1f * Time.deltaTime; // if (t >= 1f) // { // LogHelper.Error(packets); // packets = 0; // t = 0; // } //} delayt += 1f * Time.deltaTime; LogHelper.Error(1f / (60 - _sendRate)); if (delayt > 1f / (60 - _sendRate)) { packets++; using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) { var writer = Begin_iRPC(1, stream, out var option); if (_syncPosition) { writer.Write(transform.localPosition); } if (_syncRotation) { if (_compressQuaternion) { writer.WriteCompressed(transform.localRotation, _floatMultiplicationPrecision); } else { writer.Write(transform.localRotation); } } if (_syncScale) { writer.Write(transform.localScale); } writer.Write(LocalTime); //* timestamp writer.Write(); End_iRPC(1, stream); } delayt = 0; } //frames++; //if (!_syncPosition && !_syncRotation && !_syncScale) // return; //t += Time.deltaTime; //if (t > 1f) //{ // LogHelper.Error(Mathf.Round(frames / t)); // frames = 0; // t = 0; //} ////if (LocalTime >= (_lastSyncedTime + (1d / _packetsPerSecond))) //double d = (double)frames / (double)_packetsPerSecond; //if (d == 0) //{ // using (NeutronStream stream = Neutron.PooledNetworkStreams.Pull()) // { // var writer = Begin_iRPC(1, stream, out var option); // if (_syncPosition) // writer.Write(transform.localPosition); // if (_syncRotation) // { // if (_compressQuaternion) // writer.WriteCompressed(transform.localRotation, _floatMultiplicationPrecision); // else // writer.Write(transform.localRotation); // } // if (_syncScale) // writer.Write(transform.localScale); // writer.Write(LocalTime); //* timestamp // writer.Write(); // End_iRPC(1, stream); // } // _lastSyncedTime = LocalTime; //} //} //else //{ // lock (_bufferLock) // { // //* Corrige a posi��o, se o buffer estiver grande, logo o processamento est� atrasado, limpa e continua.... // if (_buffer.Count > _bufferMaxSize) // Clear(); // if (SnapshotInterpolation.Compute(LocalTime, Time.deltaTime, ref _interpolationTime, _bufferTime, _buffer, _catchupThreshold, _catchupMultiplier, _interpolate, out NetworkTransformSnapshot computed)) // Interpolate(computed); // } //} } }