示例#1
0
        protected override void ProcessStatusChanged(NetIncomingMessage msg, NetConnectionStatus status)
        {
            base.ProcessStatusChanged(msg, status);

            if (status == NetConnectionStatus.Connected)
            {
                Log("New client connected from {0}", msg.SenderConnection.RemoteEndPoint);

                // Send currently tracked objects, if not host.
                if (msg.SenderConnection != LocalClientConnection)
                {
                    SendAllObjects(msg.SenderConnection);
                }

                RemoteClient c = GetClient(msg);

                UponConnection?.Invoke(c);
            }

            if (status == NetConnectionStatus.Disconnected)
            {
                string reason = msg.ReadString();
                Log("Client has disconnected: {0}", reason);

                if (msg.SenderConnection == LocalClientConnection)
                {
                    Log("(Was local client)");
                    LocalClientConnection = null;
                }

                var client = GetClient(msg);
                if (client != null)
                {
                    // Remove net object from this client's ownership.
                    int loop = 0;
                    int max  = client.OwnedObjectsList.Count;
                    while (client.OwnedObjectsList.Count > 0)
                    {
                        JNet.SetOwner(client.OwnedObjectsList[0], null);

                        loop++;
                        if (loop > max)
                        {
                            JNet.Error($"Infinite loop?! Looped {loop}, expected {max}.");
                            break;
                        }
                    }

                    // Remove client.
                    this.Clients.Remove(client);
                    this.dictClients.Remove(client.ConnectionID);

                    UponDisconnection?.Invoke(client, reason);
                }
                else
                {
                    LogError("Client with Id {0} from {1} did not have a valid RemoteClient to remove.", msg.SenderConnection.RemoteUniqueIdentifier, msg.SenderConnection.RemoteEndPoint);
                }
            }
        }
        private void ProcessDespawn(NetIncomingMessage msg)
        {
            // Do not process if the server is active.
            if (JNet.IsServer)
            {
                return;
            }

            // Net ID.
            ushort netID = msg.ReadUInt16();

            if (netID == 0)
            {
                JNet.Error("Client was instructed to despawn object with netID 0, server error or corruption?");
                return;
            }

            NetObject obj = JNet.Tracker.TrackedObjects[netID];

            if (obj == null)
            {
                // Hmmm...
                JNet.Error(string.Format("Client was instructed to depsnaw object of NetID {0}, but that object was not found. Already destroyed?", netID));
                return;
            }

            // Destroy the object and unregister it.
            JNet.Tracker.Unregister(obj);

            // Destroy.
            GameObject.Destroy(obj.gameObject);
        }
示例#3
0
        private object[] MsgToArgs(MethodInfo f, NetIncomingMessage msg)
        {
            MethodArgs.Clear();
            var parameters = f.GetParameters();

            if (Parsers.Count == 0)
            {
                AddAllParsers();
            }

            for (int i = 0; i < parameters.Length; i++)
            {
                var  parameter = parameters[i];
                Type type      = parameter.ParameterType;

                if (!Parsers.ContainsKey(type))
                {
                    JNet.Error($"Failed to find parser for incoming data type: {type.FullName}. Method invocation will probably fail.");
                    continue;
                }

                ReadWrite rw  = Parsers[type];
                object    arg = rw(true, msg, null, null);
                MethodArgs.Add(arg);
            }

            return(MethodArgs.ToArray());
        }
示例#4
0
        private bool ArgsToMsg(MethodInfo f, object[] args, NetOutgoingMessage msg)
        {
            var parameters = f.GetParameters();

            if (parameters.Length != args.Length)
            {
                JNet.Error($"Expected {parameters.Length} parameters for remote invocation of {f.Name}, but only {args.Length} were supplied. Method will not be called.");
                return(false);
            }

            if (Parsers.Count == 0)
            {
                AddAllParsers();
            }

            for (int i = 0; i < parameters.Length; i++)
            {
                var param = parameters[i];

                Type type     = param.ParameterType;
                Type realType = args[i].GetType();

                if (!type.IsAssignableFrom(realType))
                {
                    JNet.Error($"Cannot automatically cast argument of type {realType.Name} to param {param.Name} of type {type.Name}.");
                    return(false);
                }

                ReadWrite rw = Parsers[type];

                rw(false, null, msg, args[i]);
            }

            return(true);
        }
示例#5
0
        private void Init()
        {
            if (doneInit)
            {
                return;
            }

            parameters = Animator.parameters;
            int count = parameters.Length;

            if (parameters.Length > 256)
            {
                count = 256;
                JNet.Error($"There are {parameters.Length} animator parameters on object {gameObject.name}, but only 256 can be networked. Some will not be syncronized. Why do you have that many anyway...");
            }

            paramDict = new Dictionary <string, byte>();
            for (int i = 0; i < count; i++)
            {
                var param = parameters[i];
                paramDict.Add(param.name.Trim(), (byte)i);
            }

            doneInit = true;
        }
示例#6
0
        private void LateUpdate()
        {
            if (!updateParent)
            {
                return;
            }

            updateParent = false;

            if (ParentNetID != 0 && ParentNodeID != 0)
            {
                // Try to find the object.
                NetObject obj = JNet.GetObject(ParentNetID);
                if (obj == null)
                {
                    JNet.Error($"Failed to find net object of id {ParentNetID} to sync the transform of this object.");
                    return;
                }

                var node = obj.GetParentNode(ParentNodeID);
                if (node == null)
                {
                    JNet.Error($"Failed to find net object of id {ParentNetID} parent node ({ParentNodeID}) to sync the transform of this object.");
                    return;
                }

                this.transform.SetParent(node.GetTransform(), true);
            }
            else
            {
                this.transform.SetParent(null, true);
            }
        }
示例#7
0
 private void CheckDeliveryMethod()
 {
     if (RMCDeliveryMethod == NetDeliveryMethod.ReliableSequenced || RMCDeliveryMethod == NetDeliveryMethod.UnreliableSequenced)
     {
         NetDeliveryMethod replacement = RMCDeliveryMethod == NetDeliveryMethod.ReliableSequenced ? NetDeliveryMethod.ReliableOrdered : NetDeliveryMethod.Unreliable;
         JNet.Error($"Remote Delivery Method {RMCDeliveryMethod} is not allowed because it is sequenced. Using {replacement} instead.");
         RMCDeliveryMethod = replacement;
     }
 }
示例#8
0
        /// <summary>
        /// Invokes the named method on the corresponding behaviour on the server.
        /// When called on the server, the target method will be instantly invoked.
        /// </summary>
        /// <param name="methodName">The name of the method to call. The method should have the [Cmd] attribute.</param>
        /// <param name="args">The arguments to pass to the method.</param>
        protected void InvokeCMD(string methodName, params object[] args)
        {
            if (!NetObject.HasNetID)
            {
                JNet.Error($"Cannot call Cmd {methodName} because the object that {GetType().FullName} is on is not net spawned.");
                return;
            }

            MethodInfo method = GetCmd(methodName);

            if (method == null)
            {
                JNet.Error($"Could not find valid method with Cmd tag {methodName}. Check tags, name spelling and regenerate netcode!");
                return;
            }

            if (!IsServer && !IsClient)
            {
                JNet.Error($"Not on client or server, can't invoke cmd {methodName}");
                return;
            }

            if (!HasAuthority)
            {
                JNet.Error($"There is currently no authority over this object {name}. Must call from on a client that has object ownership, or on the server. Current owner: {NetObject.OwnerID}");
                return;
            }

            methodName = methodName.Trim().ToLower();
            byte methodID = CustomGeneratedBehaviour.GetMethodID(methodName);

            if (!JNet.IsServer)
            {
                CheckDeliveryMethod();

                NetOutgoingMessage msg = JNet.GetClient().CreateMessage(Internal.JDataType.RMC);
                msg.Write(NetObject.NetID);
                msg.Write(this.BehaviourID);
                msg.Write(methodID);

                bool worked = ArgsToMsg(method, args, msg);
                if (!worked)
                {
                    JNet.Error("Did not invoke Cmd due to error.");
                    return;
                }

                var client = JNet.GetClient();
                client.Send(msg, RMCDeliveryMethod, 24);
            }
            else
            {
                // Invoke directly.
                var m = CustomGeneratedBehaviour.GetCmd(methodName);
                m.Invoke(this, args);
            }
        }
示例#9
0
        /// <summary>
        /// Invokes the named method on the behaviours of all connected clients.
        /// Therefore, this is only valid when called on the server.
        /// If the server is a host (client & server at the same time), then the method is also invoked
        /// locally.
        /// </summary>
        /// <param name="methodName">The name of the method to invoke.</param>
        /// <param name="args"></param>
        protected void InvokeRPC(string methodName, params object[] args)
        {
            if (!JNet.IsServer)
            {
                JNet.Error($"Cannot call Rpc {methodName} because server is not active!");
                return;
            }

            if (!NetObject.HasNetID)
            {
                JNet.Error($"Cannot call Rpc {methodName} because the object that {GetType().FullName} is on is not net spawned.");
                return;
            }

            MethodInfo method = GetRpc(methodName);

            if (method == null)
            {
                JNet.Error($"Could not find valid method with Rpc tag {methodName}. Check tags, name spelling and regenerate netcode!");
                return;
            }

            methodName = methodName.Trim().ToLower();
            byte methodID = CustomGeneratedBehaviour.GetMethodID(methodName);

            CheckDeliveryMethod();

            NetOutgoingMessage msg = JNet.GetServer().CreateMessage(Internal.JDataType.RMC);

            msg.Write(NetObject.NetID);
            msg.Write(this.BehaviourID);
            msg.Write(methodID);

            bool worked = ArgsToMsg(method, args, msg);

            if (!worked)
            {
                JNet.Error("Did not invoke Rpc due to error.");
                return;
            }

            var server = JNet.GetServer();

            server.SendToAllExcept(server.LocalClientConnection, msg, RMCDeliveryMethod, 24);

            // Call on local client, if we are a local client...
            if (JNet.IsClient)
            {
                method.Invoke(this, args);
            }
        }
示例#10
0
        private void ProcessSpawnAll(NetIncomingMessage msg)
        {
            int objectCount          = msg.ReadInt32();
            int expectedSceneObjects = JNet.EnableSceneObjectNetworking ? JNet.TrackedObjectCount : 0;

            JNet.Log($"Recieved {objectCount} objects from the server.");

            for (int i = 0; i < objectCount; i++)
            {
                ushort prefabID = msg.ReadUInt16();
                ushort netID    = msg.ReadUInt16();

                // Get the prefab for that ID...
                NetObject prefab = JNet.GetPrefab(prefabID);
                if (prefab == null && netID > expectedSceneObjects)
                {
                    JNet.Error("Failed to find prefab for ID " + prefabID + ", object not spawned on client. Desync incoming!");
                    return;
                }

                if (netID == 0)
                {
                    JNet.Error("Client got spawn message with instance net ID of zero, server error or corruption? Object not spawned, prefab id was " + prefabID + " (" + prefab + ").");
                    return;
                }

                // Instantiate the game object, if not scene object.
                NetObject no;
                if (prefab != null)
                {
                    no = GameObject.Instantiate(prefab);
                }
                else
                {
                    no = JNet.GetObject(netID);
                }

                // We need to register the object to the system, if not scene object.
                if (prefab != null)
                {
                    JNet.Tracker.Register(no, netID);
                }

                // Read all the behaviours.
                no.Deserialize(msg, true);
            }

            UponWorldRecieved?.Invoke();
        }
示例#11
0
        public JNetServer(string name, NetPeerConfiguration config) : base(config, true)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                JNet.Error(string.Format("Null name supplied to server, default name '{0}' will be used.", DEFAULT_NAME));
                name = DEFAULT_NAME;
            }

            Name        = name.Trim();
            Clients     = new List <RemoteClient>();
            dictClients = new Dictionary <long, RemoteClient>();

            SetProcessor(JDataType.PING, this.ProcessPing);
            SetProcessor(JDataType.RMC, this.ProcessRMC);
        }
示例#12
0
        public void Set(NetObject value)
        {
            if (!JNet.IsServer)
            {
                JNet.Error("Cannot set value of net reference when not on server.");
                return;
            }

            if (obj == value)
            {
                return;
            }

            obj   = value;
            objID = value?.NetID ?? 0;

            NetDirty = true;
        }
示例#13
0
        internal void NetAwake()
        {
            // This (derived) class should have a corresponding autogenerated netcode class. Let's find it!
            Type c = GetGeneratedType(this.GetType());

            if (c == null)
            {
                JNet.Error($"Failed to find network autogenerated class for {this.GetType().FullName}, perhaps network code needs to be regenerated?");
#if UNITY_EDITOR
                UnityEditor.EditorApplication.isPaused = true;
#endif
                return;
            }

            var constructor = c.GetConstructors()[0];
            var instance    = constructor.Invoke(null);

            CustomGeneratedBehaviour = instance as JNetGeneratedBehaviour;
        }
示例#14
0
        internal void HandleRMCMessage(NetIncomingMessage msg, byte methodID)
        {
            // TODO catch exceptions.

            bool   expectCmd  = JNet.IsServer;
            string methodName = CustomGeneratedBehaviour.GetMethodName(methodID);

            (var method, bool isCmd) = CustomGeneratedBehaviour.RemoteMethods[methodName];

            if (expectCmd != isCmd)
            {
                JNet.Error("Wrong remote type?? Invesitgate.");
                return;
            }

            if (isCmd)
            {
                // Check message sender for ownership of this object.
                long owner         = this.NetObject.OwnerID;
                long messageSender = msg.SenderConnection.RemoteUniqueIdentifier;

                if (owner != messageSender)
                {
                    JNet.Error($"Got CMD from a client for an object that they don't own. Serious bug or hacking attempt? owner ID: {owner}, message sender: {messageSender}.");
                    return;
                }
            }

            // Read arguments.
            object[] args = MsgToArgs(method, msg);

            try
            {
                method.Invoke(this, args);
            }
            catch (Exception e)
            {
                JNet.Error($"Exception invoking {(isCmd ? "CMD" : "RPC")} {method.Name} - {e.GetType().Name}: {e.Message}");
            }
        }
示例#15
0
        public void SerializeAll()
        {
            if (!JNet.IsServer)
            {
                JNet.Error("Not on server, cannot serialize all.");
                return;
            }

            for (int i = 0; i < ActiveObjects.Count; i++)
            {
                var obj = ActiveObjects[i];
                if(obj == null)
                {
                    JNet.Error("Null object in tracked objects list.");
                    ActiveObjects.RemoveAt(i);
                    i--;
                    continue;
                }

                if(obj.NetBehaviours != null)
                {
                    foreach (var b in obj.NetBehaviours)
                    {
                        if(b != null && b.NetDirty)
                        {
                            JNetServer server = JNet.GetServer();
                            NetOutgoingMessage msg = server.CreateMessage();
                            msg.Write((byte)JDataType.SERIALIZED);
                            msg.Write(obj.NetID);
                            msg.Write(b.BehaviourID);
                            b.NetSerialize(msg, false);

                            server.SendToAllExcept(server.LocalClientConnection, msg, b.SerializationDeliveryMethod, 1);

                            b.NetDirty = false;
                        }
                    }
                }
            }
        }
示例#16
0
        private void ProcessSpawn(NetIncomingMessage msg)
        {
            // Do not process if the server is active.
            if (JNet.IsServer)
            {
                return;
            }

            // Prefab ID.
            ushort prefabID = msg.ReadUInt16();

            // Net ID.
            ushort netID = msg.ReadUInt16();

            // Get the prefab for that ID...
            NetObject prefab = JNet.GetPrefab(prefabID);

            if (prefab == null)
            {
                JNet.Error("Failed to find prefab for ID " + prefabID + ", object not spawned on client. Desync incoming!");
                return;
            }

            if (netID == 0)
            {
                JNet.Error("Client got spawn message with instance net ID of zero, server error or corruption? Object not spawned, prefab id was " + prefabID + " (" + prefab + ").");
                return;
            }

            // Instantiate the game object.
            NetObject no = GameObject.Instantiate(prefab);

            // We need to register the object to the system.
            JNet.Tracker.Register(no, netID);

            // Read all the behaviours.
            no.Deserialize(msg, true);
        }
示例#17
0
        internal void UpdateBehaviourList()
        {
            var comps = this.GetComponents <NetBehaviour>();

            if (comps.Length <= 256)
            {
                NetBehaviours = comps;
            }
            else
            {
                NetBehaviours = new NetBehaviour[256];
                System.Array.Copy(comps, NetBehaviours, 256);
                JNet.Error(string.Format("NetObject {0} has {1} NetBehaviour components, but a max of 256 are supported. Some of them will not function properly, and errors will arise.", this.ToString(), comps.Length));
            }

            for (int i = 0; i < NetBehaviours.Length; i++)
            {
                NetBehaviours[i].BehaviourID = (byte)i;
                NetBehaviours[i].NetAwake();
            }

            RefreshParentNodes();
        }
示例#18
0
        public void Unregister(NetObject obj)
        {
            if (obj == null)
                return;

            if (!obj.HasNetID)
                return;

            ushort id = obj.NetID;

            NetObject current = TrackedObjects[id];
            if(current != obj)
            {
                JNet.Error("Current is not the object that is about to be unregistered.");
                return;
            }

            TrackedObjects[id] = null;
            obj.NetID = 0;
            ObjectCount--;

            ActiveObjects.Remove(obj);
        }
示例#19
0
        public void Register(NetObject obj, ushort overrideNetID = 0)
        {
            if (obj == null)
            {
                JNet.Error("Null object to register.");
                return;
            }

            if (obj.HasNetID)
            {
                JNet.Error("Object already registered!");
                return;
            }

            ushort id = 0;
            if(overrideNetID == 0)
            {
                int maxID = TrackedObjects.Length;

                for (int i = 0; i < maxID + 1; i++)
                {
                    id = CurrentTopID;

                    CurrentTopID++;
                    if (CurrentTopID >= maxID)
                    {
                        CurrentTopID = 1;
                    }

                    if (TrackedObjects[id] == null)
                    {
                        break;
                    }
                    else
                    {
                        id = 0;
                    }
                }
            }
            else
            {
                id = overrideNetID;
            }            

            if(id == 0)
            {
                JNet.Error("Cannot register new net object to be tracked, out of ID's! Too many objects are already tracked! Max object count: " + MAX_TRACKED_OBJECTS);
                return;
            }

            obj.NetID = id;
            obj.UpdateBehaviourList();

            if(TrackedObjects[id] != null)
            {
                JNet.Error("Overriding object in register, possibly from client. Override netID: " + overrideNetID);
            }

            TrackedObjects[id] = obj;
            ObjectCount++;

            ActiveObjects.Add(obj);
        }
示例#20
0
 protected void LogError(string s, params object[] args)
 {
     JNet.Error((IsServer ? "[S] " : "[C] ") + string.Format(s, args));
 }