123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- using System;
- using System.Collections.Generic;
- using UnityEngine;
- namespace Mirror
- {
- // a server's connection TO a LocalClient.
- // sending messages on this connection causes the client's handler function to be invoked directly
- public class LocalConnectionToClient : NetworkConnectionToClient
- {
- internal LocalConnectionToServer connectionToServer;
- public LocalConnectionToClient() : base(LocalConnectionId) {}
- public override string address => "localhost";
- // Send stage two: serialized NetworkMessage as ArraySegment<byte>
- internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
- {
- // get a writer to copy the message into since the segment is only
- // valid until returning.
- // => pooled writer will be returned to pool when dequeuing.
- // => WriteBytes instead of WriteArraySegment because the latter
- // includes a 4 bytes header. we just want to write raw.
- //Debug.Log("Enqueue " + BitConverter.ToString(segment.Array, segment.Offset, segment.Count));
- PooledNetworkWriter writer = NetworkWriterPool.GetWriter();
- writer.WriteBytes(segment.Array, segment.Offset, segment.Count);
- connectionToServer.queue.Enqueue(writer);
- }
- // true because local connections never timeout
- internal override bool IsAlive(float timeout) => true;
- internal void DisconnectInternal()
- {
- // set not ready and handle clientscene disconnect in any case
- // (might be client or host mode here)
- isReady = false;
- RemoveFromObservingsObservers();
- }
- /// <summary>Disconnects this connection.</summary>
- public override void Disconnect()
- {
- DisconnectInternal();
- connectionToServer.DisconnectInternal();
- }
- }
- // a localClient's connection TO a server.
- // send messages on this connection causes the server's handler function to be invoked directly.
- public class LocalConnectionToServer : NetworkConnectionToServer
- {
- internal LocalConnectionToClient connectionToClient;
- // packet queue
- internal readonly Queue<PooledNetworkWriter> queue = new Queue<PooledNetworkWriter>();
- public override string address => "localhost";
- // see caller for comments on why we need this
- bool connectedEventPending;
- bool disconnectedEventPending;
- internal void QueueConnectedEvent() => connectedEventPending = true;
- internal void QueueDisconnectedEvent() => disconnectedEventPending = true;
- // Send stage two: serialized NetworkMessage as ArraySegment<byte>
- internal override void Send(ArraySegment<byte> segment, int channelId = Channels.Reliable)
- {
- if (segment.Count == 0)
- {
- Debug.LogError("LocalConnection.SendBytes cannot send zero bytes");
- return;
- }
- // OnTransportData assumes batching.
- // so let's make a batch with proper timestamp prefix.
- Batcher batcher = GetBatchForChannelId(channelId);
- batcher.AddMessage(segment);
- // flush it to the server's OnTransportData immediately.
- // local connection to server always invokes immediately.
- using (PooledNetworkWriter writer = NetworkWriterPool.GetWriter())
- {
- // make a batch with our local time (double precision)
- if (batcher.MakeNextBatch(writer, NetworkTime.localTime))
- {
- NetworkServer.OnTransportData(connectionId, writer.ToArraySegment(), channelId);
- }
- else Debug.LogError("Local connection failed to make batch. This should never happen.");
- }
- }
- internal override void Update()
- {
- base.Update();
- // should we still process a connected event?
- if (connectedEventPending)
- {
- connectedEventPending = false;
- NetworkClient.OnConnectedEvent?.Invoke();
- }
- // process internal messages so they are applied at the correct time
- while (queue.Count > 0)
- {
- // call receive on queued writer's content, return to pool
- PooledNetworkWriter writer = queue.Dequeue();
- ArraySegment<byte> message = writer.ToArraySegment();
- // OnTransportData assumes a proper batch with timestamp etc.
- // let's make a proper batch and pass it to OnTransportData.
- Batcher batcher = GetBatchForChannelId(Channels.Reliable);
- batcher.AddMessage(message);
- using (PooledNetworkWriter batchWriter = NetworkWriterPool.GetWriter())
- {
- // make a batch with our local time (double precision)
- if (batcher.MakeNextBatch(batchWriter, NetworkTime.localTime))
- {
- NetworkClient.OnTransportData(batchWriter.ToArraySegment(), Channels.Reliable);
- }
- }
- NetworkWriterPool.Recycle(writer);
- }
- // should we still process a disconnected event?
- if (disconnectedEventPending)
- {
- disconnectedEventPending = false;
- NetworkClient.OnDisconnectedEvent?.Invoke();
- }
- }
- /// <summary>Disconnects this connection.</summary>
- internal void DisconnectInternal()
- {
- // set not ready and handle clientscene disconnect in any case
- // (might be client or host mode here)
- // TODO remove redundant state. have one source of truth for .ready!
- isReady = false;
- NetworkClient.ready = false;
- }
- /// <summary>Disconnects this connection.</summary>
- public override void Disconnect()
- {
- connectionToClient.DisconnectInternal();
- DisconnectInternal();
- // simulate what a true remote connection would do:
- // first, the server should remove it:
- // TODO should probably be in connectionToClient.DisconnectInternal
- // because that's the NetworkServer's connection!
- NetworkServer.RemoveLocalConnection();
- // then call OnTransportDisconnected for proper disconnect handling,
- // callbacks & cleanups.
- // => otherwise OnClientDisconnected() is never called!
- // => see NetworkClientTests.DisconnectCallsOnClientDisconnect_HostMode()
- NetworkClient.OnTransportDisconnected();
- }
- // true because local connections never timeout
- internal override bool IsAlive(float timeout) => true;
- }
- }
|