Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Did I setup ECS correctly?

Discussion in 'Entity Component System' started by FastTurtle222, Mar 23, 2018.

  1. FastTurtle222

    FastTurtle222

    Joined:
    Dec 24, 2017
    Posts:
    28
    Trying to convert an open soruce networking library to the new ecs system. Just finished up the first file and it is working as intended but the code just doesn't feel correct to me. I know its still a mess and needs some more final touches but before I do all that could someone take a look and tell me if this is how the ECS was supposed to be used?

    Here is the original script NetSocket.cs it can be found here
    https://github.com/jakevn/MassiveNet/blob/master/MassiveNet/NetSocket.cs

    I've split it into two files NetSocketComponent.cs and NetSocketSystem.cs. I created an entrypoint script as well that serves the same purpose as the TwostickBootstrapper file in the samples.

    @Joachim_Ante may be the one who has to answer this as the ecs is still fairily new. But I thank anyone in advance who can answer this for me.


    Code (csharp):
    1.  
    2. public class EntryPoint
    3. {
    4.     public static EntityManager entityManager;
    5.     public static EntityArchetype network;
    6.     public static ComponentType type;
    7.     public static MassiveNet.MassiveNetSettings settings;
    8.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
    9.     public static void Initialize()
    10.     {
    11.  
    12.  
    13.         entityManager = World.Active.GetOrCreateManager<EntityManager>();
    14.  
    15.         network = entityManager.CreateArchetype(typeof(NetSocketComponent));
    16.  
    17.     }
    18.  
    19.  
    20.     [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
    21.     public static void SceneLoaded()
    22.     {
    23.         var settingsGO = GameObject.Find("Settings");
    24.         settings = settingsGO.GetComponent<MassiveNet.MassiveNetSettings>();
    25.         StartGame();
    26.     }
    27.     public static void StartGame()
    28.     {
    29.         NetSocketSystem.SetupEntity();
    30.         settings.socketComponent.Events.OnSocketStart += Events_OnSocketStart;
    31.         settings.socketComponent.Events.OnClientConnected += Events_OnClientConnected;
    32.         NetSocketSystem.StartSocket(settings.socketComponent, "127.0.0.1:7777");
    33.        
    34.     }
    35.  
    36.     private static void Events_OnSocketStart()
    37.     {
    38.         Debug.Log("Server started");
    39.     }
    40.  
    41.     private static void Events_OnClientConnected(NetConnection connection)
    42.     {
    43.         Debug.Log("Client connected");
    44.     }
    45.  
    46.  
    47. }
    48.  
    NetSocketComponent.cs
    Code (csharp):
    1.  
    2. namespace MassiveNet
    3. {
    4.     /// <summary>
    5.     /// Commands are non-attribute, non-reflection/invoke based RPCs that must be
    6.     /// manually registered. They do not target specific NetViews.
    7.     /// The CommandID (enum ushort value) is used as the messageId.
    8.     /// Useable Range: 1801-2047
    9.     /// </summary>
    10.     internal enum Cmd : ushort
    11.     {
    12.         /// <summary> Sent by server to new connection with server's RPC names and the assigned RPC IDs. </summary>
    13.         RemoteAssignment = 2047,
    14.  
    15.         /// <summary> Sent by client to server upon connecting, requesting a numeric RPC ID for the supplied RPC method name. </summary>
    16.         AssignmentRequest = 2046,
    17.  
    18.         /// <summary> Sent by server to new client connection in response to an AssignmentRequest. The response contains the RPC ID assignment and the method name. </summary>
    19.         AssignmentResponse = 2045,
    20.  
    21.         /// <summary> Sends requirements for finishing connection setup. </summary>
    22.         ConnectionRequirements = 2044,
    23.  
    24.         /// <summary> Signals that requirements for finishing connection setup have been met. </summary>
    25.         RequirementsMet = 2043,
    26.  
    27.         /// <summary> Command containing the response to a request. </summary>
    28.         RequestResponse = 2042
    29.     }
    30.  
    31.     public class NetSocketComponent : MonoBehaviour
    32.     {
    33.         /// <summary> All active connections. Includes both client and server connections. </summary>
    34.         public readonly List<NetConnection> Connections = new List<NetConnection>();
    35.  
    36.         public readonly Dictionary<IPEndPoint, NetConnection> endpointToConnection =
    37.             new Dictionary<IPEndPoint, NetConnection>();
    38.  
    39.         public readonly List<IPEndPoint> connectingEndpoints = new List<IPEndPoint>();
    40.         public readonly List<NetStream> connectingData = new List<NetStream>();
    41.         public readonly List<uint> connectingTimes = new List<uint>();
    42.         public readonly List<int> connectingRetriesRemaining = new List<int>();
    43.  
    44.         /// <summary> Dummy NetConnection used to represent self for authority checks. </summary>
    45.         public NetConnection Self;
    46.  
    47.         public readonly CommandDispatcher Command = new CommandDispatcher();
    48.  
    49.         public RequestDispatcher Request;
    50.  
    51.         public RpcDispatcher Rpc;
    52.  
    53.         /// <summary> Contains all events related to this socket. </summary>
    54.         public readonly NetSocketEvents Events = new NetSocketEvents();
    55.  
    56.         /// <summary> Monobehaviour instances for viewless-RPC methods. The key is the method name and the value is the Monobehaviour instance. </summary>
    57.         public readonly Dictionary<string, object> rpcObjectInstances = new Dictionary<string, object>();
    58.  
    59.         /// <summary> If true, all incoming connections will have their RPC IDs generated by this socket. If false,
    60.         /// this socket will need to first connect to a protocol authority. </summary>
    61.         public bool ProtocolAuthority = false;
    62.  
    63.         /// <summary> Returns the port number for this socket. 0 if socket not yet initialized. </summary>
    64.         public int Port
    65.         {
    66.             get { return Self.Endpoint.Port; }
    67.         }
    68.  
    69.         /// <summary> Returns the IP address and port this socket is listening on. E.g., "192.168.1.1:17603" </summary>
    70.         public string Address
    71.         {
    72.             get { return Self.Endpoint.Address.ToString(); }
    73.         }
    74.  
    75.         /// <summary> The current number of total connections. Includes clients, servers, and peers.
    76.         /// Compared against MaxConnections to determine if incoming connections should be refused. </summary>
    77.         public int ConnectionCount { get { return Connections.Count; } }
    78.  
    79.         /// <summary> If ConnectionCount == MaxConnections, incoming connections will be refused. Outgoing connections
    80.         /// are counted in ConnectionCount, but are allowed to exceed MaxConnections. </summary>
    81.         public int MaxConnections { get; set; }
    82.  
    83.         /// <summary> Sets Unity's Application.targetFrameRate. It is recommended to set this to a resonable
    84.         /// number such as 60 so that timing-related functionality remains more consistent. </summary>
    85.         public int TargetFrameRate = 60;
    86.  
    87.         /// <summary> Handle to OS-level socket, created on successful StartSocket. </summary>
    88.         public Socket socket;
    89.  
    90.         /// <summary> All incoming connections are refused when set to false. Clients should be false. </summary>
    91.         public bool AcceptConnections { get; set; }
    92.     }
    93. }
    94.  
    NetSocketSystem.cs
    Code (csharp):
    1.  
    2. namespace MassiveNet
    3. {
    4.     public class NetSocketSystem : ComponentSystem
    5.     {
    6.  
    7.         public struct Data
    8.         {
    9.             public int Length;
    10.             public ComponentArray<NetSocketComponent> socket;
    11.         }
    12.         [Inject]
    13.         private Data m_Data;
    14.  
    15.         public static void SetupEntity()
    16.         {
    17.             Debug.Log("Called!");
    18.             Application.runInBackground = true;
    19.             Application.targetFrameRate = EntryPoint.settings.socketComponent.TargetFrameRate;
    20.  
    21.             EntryPoint.settings.socketComponent.Request = new RequestDispatcher(EntryPoint.settings.socketComponent);
    22.             EntryPoint.settings.socketComponent.Rpc = new RpcDispatcher(EntryPoint.settings.socketComponent);
    23.             EntryPoint.settings.socketComponent.AcceptConnections = true;
    24.             EntryPoint.settings.socketComponent.MaxConnections = 512;
    25.             RpcInfoCache.RpcMethods();
    26.  
    27.             RegisterCommandParams(EntryPoint.settings.socketComponent);
    28.         }
    29.  
    30.         /// <summary> Starts the socket using an automatically selected endpoint. </summary>
    31.         public void StartSocket(NetSocketComponent i)
    32.         {
    33.             StartSocket(i,new IPEndPoint(IPAddress.Any, 0));
    34.         }
    35.  
    36.         /// <summary>
    37.         /// Starts the socket using an address in the following format: "192.168.1.1:17010"
    38.         /// If the port is taken, the given port will be incremented to a free port.
    39.         /// </summary>
    40.         public static void StartSocket(NetSocketComponent i, string fullAddress)
    41.         {
    42.             StartSocket(i, StringToEndPoint(fullAddress));
    43.         }
    44.  
    45.         /// <summary>
    46.         /// Starts the socket using the supplied endpoint.
    47.         /// If the port is taken, the given port will be incremented to a free port.
    48.         /// </summary>
    49.         public static void StartSocket(NetSocketComponent i, IPEndPoint endpoint)
    50.         {
    51.  
    52.             i.Self = new NetConnection(false, false, i, endpoint);
    53.             i.socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
    54.  
    55.             try
    56.             {
    57.                 const uint IOC_IN = 0x80000000;
    58.                 const uint IOC_VENDOR = 0x18000000;
    59.                 uint SIO_UDP_CONNRESET = IOC_IN | IOC_VENDOR | 12;
    60.                 i.socket.IOControl((int)SIO_UDP_CONNRESET, new[] { Convert.ToByte(false) }, null);
    61.             }
    62.             catch
    63.             {
    64.                 NetLog.Warning("Failed to set control code for ignoring ICMP port unreachable.");
    65.             }
    66.  
    67.             i.socket.ReceiveBufferSize = 4194304;
    68.             if (i.socket.ReceiveBufferSize != 4194304) NetLog.Warning("ReceiveBufferSize restricted by OS.");
    69.             i.socket.SendBufferSize = 1048576;
    70.             i.socket.Blocking = false;
    71.  
    72.             try
    73.             {
    74.                 i.socket.Bind(endpoint);
    75.             }
    76.             catch (SocketException e)
    77.             {
    78.                 if (e.ErrorCode == 10048)
    79.                 {
    80.                     var newEp = new IPEndPoint(endpoint.Address, endpoint.Port + 1);
    81.                     NetLog.Warning("Port in use. Incrementing and retrying...");
    82.                     StartSocket(i,newEp);
    83.                 }
    84.                 else
    85.                 {
    86.                     NetLog.Error(e.Message);
    87.                 }
    88.                 return;
    89.             }
    90.  
    91.             NetLog.Info(NetTime.StartDateTime() + " | Socket Started. Bound to: " + endpoint);
    92.             NetTime.Milliseconds();
    93.  
    94.             if (i.ProtocolAuthority) i.Rpc.AssignLocalRpcs();
    95.             i.Events.SocketStart();
    96.         }
    97.  
    98.         /// <summary> Closes the socket and performs cleanup for active connections. </summary>
    99.         public void Shutdown(NetSocketComponent sock)
    100.         {
    101.             DisconnectAll(sock);
    102.             sock.socket.Close();
    103.             sock.socket = null;
    104.         }
    105.  
    106.         /// <summary> Byte values for connection control commands. </summary>
    107.         private enum ByteCmd : byte
    108.         {
    109.             Connect = 245,
    110.             ConnectToPeer = 244,
    111.             RefuseConnection = 243,
    112.             Disconnect = 240
    113.         }
    114.  
    115.         /// <summary> Attempts to connect to a server with address format: "192.168.1.1:17001" </summary>
    116.         public static void Connect(NetSocketComponent socket, string fullAddress)
    117.         {
    118.             Connect(socket, StringToEndPoint(fullAddress));
    119.         }
    120.  
    121.         /// <summary> Attempts to connect to a peer with address format: "192.168.1.1:17001" </summary>
    122.         public void ConnectToPeer(NetSocketComponent socket, string fullAddress)
    123.         {
    124.             ConnectToPeer(socket, StringToEndPoint(fullAddress));
    125.         }
    126.  
    127.         /// <summary> Attempts to connect to a server located at the supplied endpoint. </summary>
    128.         public static void Connect(NetSocketComponent socket, IPEndPoint endpoint)
    129.         {
    130.             if (EndpointConnected(socket,endpoint) || socket.connectingEndpoints.Contains(endpoint)) return;
    131.             NetStream approvalData = NetStream.Create();
    132.             approvalData.WriteByte((byte)ByteCmd.Connect);
    133.             socket.Events.WriteApproval(endpoint, approvalData);
    134.             Connect(socket,endpoint, approvalData);
    135.         }
    136.  
    137.         /// <summary> Attempts to connect to a peer located at the supplied endpoint. </summary>
    138.         public static void ConnectToPeer(NetSocketComponent socket, IPEndPoint endpoint)
    139.         {
    140.             if (EndpointConnected(socket,endpoint) || ConnectingTo(socket,endpoint)) return;
    141.             NetStream approvalData = NetStream.Create();
    142.             approvalData.WriteByte((byte)ByteCmd.ConnectToPeer);
    143.             socket.Events.WritePeerApproval(endpoint, approvalData);
    144.             Connect(socket, endpoint, approvalData);
    145.         }
    146.  
    147.         /// <summary> Returns true if socket is currently attempting a connection with supplied endpoint. </summary>
    148.         public static bool ConnectingTo(NetSocketComponent socket, IPEndPoint endpoint)
    149.         {
    150.             return socket.connectingEndpoints.Contains(endpoint);
    151.         }
    152.  
    153.         /// <summary> Handles connecting status. Tracks attempted connections and (re)sends connection data. </summary>
    154.         private static void Connect(NetSocketComponent socket, IPEndPoint ep, NetStream approvalData)
    155.         {
    156.             if (!socket.connectingEndpoints.Contains(ep))
    157.             {
    158.                 // We aren't currently trying to connect to this endpoint, add to lists:
    159.                 socket.connectingEndpoints.Add(ep);
    160.                 socket.connectingTimes.Add(NetTime.Milliseconds());
    161.                 socket.connectingData.Add(approvalData);
    162.                 socket.connectingRetriesRemaining.Add(4);
    163.                 NetLog.Info("Connecting to: " + ep);
    164.             }
    165.             else
    166.             {
    167.                 // We are already trying to connect, update attempt data:
    168.                 int index = socket.connectingEndpoints.IndexOf(ep);
    169.                 socket.connectingRetriesRemaining[index]--;
    170.                 if (socket.connectingRetriesRemaining[index] <= 0)
    171.                 {
    172.                     // Retried max amount of times, notify failure:
    173.                     RemoveFromConnecting(socket, ep, false);
    174.                     return;
    175.                 }
    176.                 socket.connectingTimes[index] = NetTime.Milliseconds();
    177.                 NetLog.Info("Retrying connection to: " + ep);
    178.             }
    179.             // Send the connection request data to the endpoint:
    180.             SendStream(socket, ep, approvalData);
    181.         }
    182.  
    183.         /// <summary> Cleans up a connection attempt and returns true if it is a peer connection. </summary>
    184.         private static bool RemoveFromConnecting(NetSocketComponent socket, IPEndPoint ep, bool successful)
    185.         {
    186.             bool isPeer = false;
    187.             if (!successful)
    188.             {
    189.                 NetLog.Info("Failed to connect to: " + ep);
    190.                 socket.Events.FailedToConnect(ep);
    191.             }
    192.             int index = socket.connectingEndpoints.IndexOf(ep);
    193.             socket.connectingTimes.RemoveAt(index);
    194.             socket.connectingRetriesRemaining.RemoveAt(index);
    195.             socket.connectingEndpoints.Remove(ep);
    196.             if (socket.connectingData[index].Data[0] == (byte)ByteCmd.ConnectToPeer) isPeer = true;
    197.             socket.connectingData[index].Release();
    198.             socket.connectingData.RemoveAt(index);
    199.             return isPeer;
    200.         }
    201.  
    202.         /// <summary> Creates an IPEndPoint by parsing a string with format "192.168.1.1:17010" </summary>
    203.         static IPEndPoint StringToEndPoint(string address)
    204.         {
    205.             string[] split = address.Split(':');
    206.             string stringAddress = split[0];
    207.             string stringPort = split[1];
    208.             int port = int.Parse(stringPort);
    209.             var ipaddress = IPAddress.Parse(stringAddress);
    210.             var endpoint = new IPEndPoint(ipaddress, port);
    211.             if (endpoint == null) throw new Exception("Failed to parse address: " + address);
    212.             return endpoint;
    213.         }
    214.  
    215.         /// <summary> Closes all connections. </summary>
    216.         public void DisconnectAll(NetSocketComponent sock)
    217.         {
    218.             for (int i = sock.Connections.Count - 1; i >= 0; i--) Disconnect(sock, sock.Connections[i]);
    219.         }
    220.  
    221.         /// <summary> Closes the supplied connection. </summary>
    222.         public static void Disconnect(NetSocketComponent sock, NetConnection connection)
    223.         {
    224.             sock.Connections.Remove(connection);
    225.             sock.endpointToConnection.Remove(connection.Endpoint);
    226.  
    227.             if (connection.IsPeer) sock.Events.PeerDisconnected(connection);
    228.             else if (connection.IsServer) sock.Events.DisconnectedFromServer(connection);
    229.             else sock.Events.ClientDisconnected(connection);
    230.         }
    231.  
    232.         /// <summary> Returns true if OS socket has data available for read. </summary>
    233.         private bool CanReceive(NetSocketComponent socket)
    234.         {
    235.             return socket.socket.Poll(0, SelectMode.SelectRead);
    236.         }
    237.  
    238.  
    239.         /// <summary> The starting point for incoming data. Attempts to read from OS socket buffer. False = failed. </summary>
    240.         private bool TryReceive(NetSocketComponent socket, byte[] buffer, int size, ref int receiveCount, ref IPEndPoint remoteEndpoint)
    241.         {
    242.             EndPoint epCache = new IPEndPoint(IPAddress.Any, 0);
    243.             try
    244.             {
    245.                 receiveCount = socket.socket.ReceiveFrom(buffer, size, SocketFlags.None, ref epCache);
    246.                 remoteEndpoint = epCache as IPEndPoint;
    247.                 return (receiveCount > 0);
    248.             }
    249.             catch
    250.             {
    251.                 return false;
    252.             }
    253.         }
    254.  
    255.         /// <summary> Final frontier for outgoing data. Attempts to send data to endpoint via OS socket. False = failed. </summary>
    256.         private static bool TrySend(NetSocketComponent socket, byte[] buffer, int sendCount, IPEndPoint endpoint)
    257.         {
    258.             try
    259.             {
    260.                 int bytesSent = socket.socket.SendTo(buffer, sendCount, SocketFlags.None, endpoint);
    261.                 return bytesSent == sendCount;
    262.             }
    263.             catch
    264.             {
    265.                 return false;
    266.             }
    267.         }
    268.  
    269.  
    270.  
    271.         private IPEndPoint endPoint = default(IPEndPoint);
    272.  
    273.         /// <summary> Receives data until CanReceive is no longer true (receive buffer empty). </summary>
    274.         private void ReceiveAll(NetSocketComponent socket)
    275.         {
    276.             if (socket.socket == null) return;
    277.  
    278.             while (CanReceive(socket))
    279.             {
    280.                 var readStream = NetStream.Create();
    281.                 readStream.Socket = socket;
    282.                 int received = 0;
    283.                 if (!TryReceive(socket, readStream.Data, readStream.Data.Length, ref received, ref endPoint)) return;
    284.                 readStream.Length = received << 3;
    285.                 ProcessReceived(socket,endPoint, received, readStream);
    286.             }
    287.         }
    288.  
    289.         public static void SendStream(NetConnection connection, NetStream stream)
    290.         {
    291.             SendStream(connection.Socket, connection.Endpoint, stream);
    292.         }
    293.  
    294.         public static void SendStream(NetSocketComponent socket,IPEndPoint endpoint, NetStream stream)
    295.         {
    296.             TrySend(socket,stream.Data, stream.Pos + 7 >> 3, endpoint);
    297.         }
    298.  
    299.         private void ProcessReceived(NetSocketComponent socket,IPEndPoint endpoint, int bytesReceived, NetStream readStream)
    300.         {
    301.             if (EndpointConnected(socket, endpoint)) socket.endpointToConnection[endpoint].ReceiveStream(readStream);
    302.             else ProcessUnconnected(socket, endpoint, bytesReceived, readStream);
    303.         }
    304.  
    305.         private void ProcessUnconnected(NetSocketComponent socket, IPEndPoint endpoint, int bytesReceived, NetStream readStream)
    306.         {
    307.             if (socket.connectingEndpoints.Contains(endpoint)) ReceiveConnectionResponse(socket, endpoint, bytesReceived, readStream);
    308.             else if (bytesReceived > 0)
    309.             {
    310.                 byte cmd = readStream.ReadByte();
    311.                 if (cmd == (byte)ByteCmd.Connect) ReceiveConnectionRequest(socket, endPoint, readStream);
    312.                 else if (cmd == (byte)ByteCmd.ConnectToPeer) ReceivePeerConnectionRequest(socket, endPoint, readStream);
    313.             }
    314.         }
    315.  
    316.         private void ReceiveConnectionResponse(NetSocketComponent socket, IPEndPoint endpoint, int bytesReceived, NetStream readStream)
    317.         {
    318.             bool isPeer = RemoveFromConnecting(socket, endpoint, true);
    319.             if (bytesReceived == 1 && readStream.Data[0] == (byte)ByteCmd.RefuseConnection)
    320.             {
    321.                 NetLog.Info("Connection refused by: " + endpoint);
    322.                 return;
    323.             }
    324.             var connection = CreateConnection(socket, endpoint, true, isPeer);
    325.             if (bytesReceived > 1) connection.ReceiveStream(readStream);
    326.         }
    327.  
    328.         private void ReceiveConnectionRequest(NetSocketComponent socket, IPEndPoint endpoint, NetStream readStream)
    329.         {
    330.             if (!socket.AcceptConnections || socket.Connections.Count >= socket.MaxConnections || !socket.Events.ClientApproval(endpoint, readStream))
    331.             {
    332.                 NetLog.Info("Refused connection: " + endpoint);
    333.                 TrySend(socket, new[] { (byte)ByteCmd.RefuseConnection }, 1, endpoint);
    334.             }
    335.             else CreateConnection(socket, endpoint, false, false);
    336.         }
    337.  
    338.         private void ReceivePeerConnectionRequest(NetSocketComponent socket,IPEndPoint endpoint, NetStream readStream)
    339.         {
    340.             if (!socket.AcceptConnections || socket.Connections.Count >= socket.MaxConnections || !socket.Events.PeerApproval(endpoint, readStream))
    341.             {
    342.                 NetLog.Info("Refused peer connection: " + endpoint);
    343.                 TrySend(socket, new[] { (byte)ByteCmd.RefuseConnection }, 1, endpoint);
    344.             }
    345.             else CreateConnection(socket, endpoint, false, true);
    346.         }
    347.  
    348.         /// <summary> Iterates through pending connections and retries any timeouts. </summary>
    349.         private void CheckForTimeouts(NetSocketComponent socket)
    350.         {
    351.             if (socket.connectingEndpoints.Count == 0) return;
    352.             for (int x = socket.connectingEndpoints.Count - 1; x >= 0; x--)
    353.             {
    354.                 if (NetTime.Milliseconds() - socket.connectingTimes[x] > 2000) Connect(socket,socket.connectingEndpoints[x], socket.connectingData[x]);
    355.             }
    356.         }
    357.  
    358.         /// <summary> Timeouts, disconnects, heartbeats, forced-acks, etc. need to be performed at end of frame. </summary>
    359.         private void EndFrameTasks(NetSocketComponent socket)
    360.         {
    361.             uint currentTime = NetTime.Milliseconds();
    362.             for (int x = socket.Connections.Count - 1; x >= 0; x--) socket.Connections[x].EndOfFrame(currentTime);
    363.             CheckForTimeouts(socket);
    364.         }
    365.  
    366.         public static bool EndpointConnected(NetSocketComponent socket,IPEndPoint ep)
    367.         {
    368.             return socket.endpointToConnection.ContainsKey(ep);
    369.         }
    370.  
    371.         public static NetConnection EndpointToConnection(NetSocketComponent component, IPEndPoint ep)
    372.         {
    373.             return component.endpointToConnection[ep];
    374.         }
    375.  
    376.         /// <summary> Adds a new NetConnection to the connection list. </summary>
    377.         internal NetConnection CreateConnection(NetSocketComponent socket, IPEndPoint ep, bool isServer, bool isPeer)
    378.         {
    379.             bool wasServer = false;
    380.             // Connection cannot be both server and peer:
    381.             if (isPeer)
    382.             {
    383.                 isServer = false;
    384.                 wasServer = true;
    385.             }
    386.  
    387.             var connection = new NetConnection(isServer, isPeer, socket, ep);
    388.  
    389.             socket.Connections.Add(connection);
    390.             socket.endpointToConnection.Add(ep, connection);
    391.             if (isPeer) NetLog.Info("Peer connection created: " + ep);
    392.             else if (isServer) NetLog.Info("Server connection created: " + ep);
    393.             else NetLog.Info("Client connection created: " + ep);
    394.  
    395.             if (socket.ProtocolAuthority && !isServer && !wasServer)
    396.             {
    397.                 SendConnectionRequirements(socket, connection);
    398.                 socket.Rpc.SendLocalAssignments(connection);
    399.             }
    400.             else if (connection.IsPeer && socket.Rpc.IdCount == RpcInfoCache.Count) socket.Events.PeerConnected(connection);
    401.             else if (isServer && socket.Rpc.IdCount == RpcInfoCache.Count) socket.Events.ConnectedToServer(connection);
    402.             else if (!isServer && !isPeer) socket.Events.ClientConnected(connection);
    403.  
    404.             return connection;
    405.         }
    406.  
    407.         /// <summary> Sends a reliable RPC that does not target a specific view. </summary>
    408.         public static void Send(NetSocketComponent socket, string methodName, NetConnection target, params object[] parameters)
    409.         {
    410.             if (!socket.Rpc.HasId(methodName))
    411.             {
    412.                 NetLog.Error("Remote RPC does not have an assigned ID: " + methodName);
    413.                 return;
    414.             }
    415.             var message = NetMessage.Create(socket.Rpc.NameToId(methodName), 0, parameters, true);
    416.             target.Send(message);
    417.         }
    418.  
    419.         /// <summary> Sends a request to the target connection without an associated view. </summary>
    420.         public Request<T> SendRequest<T>(int i, string methodName, NetConnection target, params object[] parameters)
    421.         {
    422.             return m_Data.socket[i].Request.Send<T>(methodName, target, parameters);
    423.         }
    424.  
    425.         /// <summary> Dispatches received commands and RPCs based on the messageID. </summary>
    426.         public static void ReceiveMessage(NetConnection connection, NetMessage message)
    427.         {
    428.             if (message.MessageId > 1800) connection.Socket.Command.Dispatch(message, connection);
    429.             else if (message.ViewId == 0) DispatchRpc(connection.Socket, message, connection);
    430.             else connection.Socket.Events.MessageReceived(message, connection);
    431.  
    432.             message.Release();
    433.         }
    434.  
    435.         /// <summary>
    436.         /// Passes parameters from an incoming network message to the method associated with the RPC.
    437.         /// </summary>
    438.         public static void DispatchRpc(NetSocketComponent socket, NetMessage message, NetConnection connection)
    439.         {
    440.             string methodName = socket.Rpc.IdToName(message.MessageId);
    441.  
    442.             if (!socket.rpcObjectInstances.ContainsKey(methodName))
    443.             {
    444.                 NetLog.Error(string.Format("Can't find method \"{0}\" for Viewless RPC.", methodName));
    445.                 return;
    446.             }
    447.  
    448.             socket.Rpc.Invoke(socket.rpcObjectInstances[methodName], methodName, message, connection);
    449.         }
    450.  
    451.         /// <summary> Sends connection configuration requirements command to a new client connection. </summary>
    452.         private void SendConnectionRequirements(NetSocketComponent socket, NetConnection connection)
    453.         {
    454.             socket.Command.Send((int)Cmd.ConnectionRequirements, connection, socket.Rpc.IdCount);
    455.         }
    456.  
    457.         /// <summary> Handles connection configuration requirements sent by server upon connection. </summary>
    458.         private void ReceiveConnectionRequirements(int i, NetMessage message, NetConnection connection)
    459.         {
    460.             if (!connection.IsServer && !connection.IsPeer) return;
    461.             m_Data.socket[i].Rpc.WaitingForRpcs += (int)message.Parameters[0];
    462.         }
    463.  
    464.         /// <summary> Sends command to server to signal that connection requirements have been met. </summary>
    465.         public static void SendRequirementsMet(NetSocketComponent socket, NetConnection connection)
    466.         {
    467.             socket.Command.Send((int)Cmd.RequirementsMet, connection);
    468.             if (connection.IsPeer) socket.Events.PeerConnected(connection);
    469.             else socket.Events.ConnectedToServer(connection);
    470.         }
    471.  
    472.         /// <summary> Handles RequirementsMet command sent by client to signal the client is ready. </summary>
    473.         private void ReceiveRequirementsMet(NetSocketComponent socket, NetMessage message, NetConnection connection)
    474.         {
    475.             if (!connection.IsPeer && !connection.IsServer) socket.Events.ClientConnected(connection);
    476.             else if (connection.IsPeer) socket.Events.PeerConnected(connection);
    477.         }
    478.  
    479.         /// <summary> Populates CommandParameterTypes with the type data for each command.
    480.         ///  This is necessary to allow proper deserialization of incoming data for these commands. </summary>
    481.         private static void RegisterCommandParams(NetSocketComponent socket)
    482.         {
    483.             /*
    484.             socket.Command.Register((ushort)Cmd.RemoteAssignment, socket.Rpc.ReceiveRemoteAssignment,
    485.                 new List<Type> { typeof(ushort), typeof(string) });
    486.             socket.Command.Register((ushort)Cmd.AssignmentResponse, socket.Rpc.ReceiveAssignmentResponse,
    487.                 new List<Type> { typeof(ushort), typeof(string) });
    488.             socket.Command.Register((ushort)Cmd.AssignmentRequest, socket.Rpc.ReceiveAssignmentRequest,
    489.                 new List<Type> { typeof(string) });
    490.             socket.Command.Register((ushort)Cmd.ConnectionRequirements, ReceiveConnectionRequirements,
    491.                 new List<Type> { typeof(int) });
    492.             socket.Command.Register((ushort)Cmd.RequirementsMet, ReceiveRequirementsMet, new List<Type>());
    493.             socket.Command.Register((ushort)Cmd.RequestResponse, socket.Request.SetResponse, new List<Type>());
    494.             */
    495.         }
    496.  
    497.         /// <summary> Registers an instance of a MonoBehaviour to receive RPCs not associated with a NetView. </summary>
    498.         public static void RegisterRpcListener(NetSocketComponent socket,MonoBehaviour listener)
    499.         {
    500.             foreach (KeyValuePair<string, RpcMethodInfo> cachedRpc in RpcInfoCache.RpcMethods())
    501.             {
    502.                 if (!cachedRpc.Value.MethodInfoLookup.ContainsKey(listener.GetType())) continue;
    503.                 socket.rpcObjectInstances.Add(cachedRpc.Value.Name, listener);
    504.             }
    505.         }
    506.  
    507.         override protected void OnUpdate()
    508.         {
    509.             for(int i = 0; i < m_Data.socket.Length; i ++)
    510.             {
    511.                 ReceiveAll(m_Data.socket[i]);
    512.                 EndFrameTasks(m_Data.socket[i]);
    513.             }
    514.  
    515.  
    516.        
    517.         }
    518.     }
    519. }
    520.