示例#1
0
        private void DoCall(Node Target)
        {
            switch (Type)
            {
            case TypeOfCall.RPC:
                MethodInfo methodInfo = MDStatics.GetMethodInfo(Target, Convert.ToInt32(Name));
                if (methodInfo == null)
                {
                    MDLog.Fatal(LOG_CAT, $"Could not find method {Target.GetType().ToString()}#{Name}");
                    return;
                }
                object[] convertedParams = MDStatics.ConvertParametersBackToObject(methodInfo, Parameters);
                MDStatics.GetReplicator().RpcSenderId = SenderPeerId;
                methodInfo.Invoke(Target, convertedParams);
                MDStatics.GetReplicator().RpcSenderId = -1;
                break;

            case TypeOfCall.RSET:
                MemberInfo       memberInfo = MDStatics.GetMemberInfo(Target, Name);
                IMDDataConverter Converter  = MDStatics.GetConverterForType(memberInfo.GetUnderlyingType());
                object           value      = Converter.ConvertBackToObject(memberInfo.GetValue(Target), Parameters);
                MDLog.Trace(LOG_CAT, $"Setting {Name} on {Target.Name} to value {value}");
                memberInfo.SetValue(Target, value);
                break;
            }
        }
示例#2
0
        /// <summary>
        /// Clients receive this from the server as a way to attempt to keep them in synch in case they freeze for any reason
        /// </summary>
        /// <param name="EstimateTime">The estimated time for the tick</param>
        /// <param name="EstimatedTick">The estimated tick for the time</param>
        public void CheckSynch(long EstimateTime, long EstimatedTick)
        {
            long currentTime = OS.GetTicksMsec();

            if (EstimateTime < currentTime)
            {
                // This packet was delayed and is already in the past, ignore
                MDLog.Trace(LOG_CAT,
                            $"[{currentTime}] Ignoring tick packet as it was in the past {EstimatedTick} at {EstimateTime}");
                return;
            }

            // Figure out what tick we would be at when the estimated time is hit
            long localTickAtTime = GetTickAtTimeOffset(EstimateTime - currentTime);
            long tickOffset      = EstimatedTick - localTickAtTime;

            if (Math.Abs(tickOffset) > MaxTickDesynch)
            {
                MDLog.Trace(LOG_CAT,
                            $"[{currentTime}] We are out of synch, we should be at tick {EstimatedTick} at {EstimateTime}");
                MDLog.Trace(LOG_CAT,
                            $"[{currentTime}] We will be at tick {localTickAtTime} which is off by {tickOffset}");
                // We are too far out of synch
                TickSynchAdjustment = (int)tickOffset;
            }
        }
示例#3
0
 private void SendClockedCall(int PeerId, ClockedRemoteCall.TypeOfCall Type, MDReliability Reliability,
                              string NodePath, string Method, MDRemoteMode Mode, params object[] Parameters)
 {
     MDLog.Trace(LOG_CAT, $"Sending clocked call {Method} on {NodePath} with parameters ({MDStatics.GetParametersAsString(Parameters)})");
     if (Reliability == MDReliability.Reliable)
     {
         if (PeerId != -1)
         {
             RpcId(PeerId, nameof(ClockedCall), GameClock.GetTick(), Type, NodePath, Method, Mode, Parameters);
         }
         else
         {
             Rpc(nameof(ClockedCall), GameClock.GetTick(), Type, NodePath, Method, Mode, Parameters);
         }
     }
     else
     {
         if (PeerId != -1)
         {
             RpcUnreliableId(PeerId, nameof(ClockedCall), GameClock.GetTick(), Type, NodePath, Method, Mode,
                             Parameters);
         }
         else
         {
             RpcUnreliable(nameof(ClockedCall), GameClock.GetTick(), Type, NodePath, Method, Mode, Parameters);
         }
     }
 }
示例#4
0
        public object ConvertBackToObject(object CurrentObject, object[] Parameters)
        {
            MDLog.Trace(LOG_CAT, $"MDCommandReplicator converting back ({MDStatics.GetParametersAsString(Parameters)})");

            if (Parameters.Length == 1 && Parameters[0] == null)
            {
                return(null);
            }

            T obj;

            if (CurrentObject != null)
            {
                // Replace values in existing object
                obj = (T)CurrentObject;
            }
            else
            {
                // Return a new object
                obj = (T)Activator.CreateInstance(typeof(T));
            }

            for (int i = 0; i < Parameters.Length; i++)
            {
                // Get the length of the data
                int length = Convert.ToInt32(Parameters[i].ToString());

                // Extract parameters and apply to the command replicator
                object[] converterParams = Parameters.SubArray(i + 1, i + length);
                obj.MDProcessCommand(converterParams);
                i += length;
            }

            return((T)obj);
        }
示例#5
0
        public bool ShouldObjectBeReplicated(object LastValue, object CurrentValue)
        {
            ExtractMembers();
            if (LastValues.Count == 0 && CurrentValue != null)
            {
                return(true);
            }
            else if (CurrentValue != LastValue)
            {
                return(true);
            }
            else if (LastValue == null && CurrentValue == null)
            {
                return(false);
            }

            for (int i = 0; i < Members.Count; i++)
            {
                object value = Members[i].GetValue(CurrentValue);
                if (DataConverters[i].ShouldObjectBeReplicated(LastValues[i], value))
                {
                    MDLog.Trace(LOG_CAT, "We should be replicated");
                    return(true);
                }
            }

            return(false);
        }
 private void RequestTicksMsec(int RequestNumber, uint ServerTimeOfRequest)
 {
     // Respond
     RpcId(GameSession.GetNetworkMaster(), nameof(ResponseTicksMsec), OS.GetTicksMsec(), ServerTimeOfRequest,
           RequestNumber);
     MDLog.Trace(LOG_CAT,
                 $"Responded to server request number {RequestNumber} for OS.GetTicksMsec with [{OS.GetTicksMsec()}]");
 }
 private void NotifyAllNodesSynched()
 {
     // Called from client the first time they complete their node synch
     MDLog.Trace(LOG_CAT, $"Peer [{Multiplayer.GetRpcSenderId()}] has completed node synchronization");
     if (!PeerSynchInfo.ContainsKey(Multiplayer.GetRpcSenderId()))
     {
         PeerSynchInfo[Multiplayer.GetRpcSenderId()].CompletedNodeSynch = true;
     }
 }
示例#8
0
 /// <summary>
 /// Remove the uint id from our map
 /// </summary>
 /// <param name="id">The id</param>
 public void RemoveValue(uint id)
 {
     if (NetworkIDToKeyMap.ContainsKey(id))
     {
         MDLog.Trace(LOG_CAT, $"Removing id [{id}]");
         KeyToNetworkIdMap.Remove(NetworkIDToKeyMap[id]);
         RemoveBufferId(id);
         NetworkIDToKeyMap.Remove(id);
     }
 }
示例#9
0
 /// <summary>
 /// Remove the string key value from our map
 /// </summary>
 /// <param name="key">The string key</param>
 public void RemoveValue(string key)
 {
     if (KeyToNetworkIdMap.ContainsKey(key))
     {
         MDLog.Trace(LOG_CAT, $"Removing key [{key}]");
         NetworkIDToKeyMap.Remove(KeyToNetworkIdMap[key]);
         RemoveBufferId(KeyToNetworkIdMap[key]);
         KeyToNetworkIdMap.Remove(key);
     }
 }
        /// <summary>
        /// Check if we got enough of a confidence value in the Msec value of the client to resume the game
        /// </summary>
        /// <returns>True if we are ready to resume, false if not</returns>
        public bool IsClientMSecConfident()
        {
            if (TicksList.Count >= GameSynchronizer.GetMinimumMeasurementCountBeforeResume())
            {
                return(true);
            }

            MDLog.Trace(LOG_CAT, $"Still waiting for peer [{PeerId}] to get a more secure TickMsec value");
            return(false);
        }
        /// <summary>
        /// Adds the ping to the players ping list and removes any overflow
        /// </summary>
        /// <param name="Ping">The ping</param>
        public void PushPlayerPingToQueue(int Ping)
        {
            PingList.Enqueue(Ping);
            MDLog.Trace(LOG_CAT, $"Peer [{PeerId}] recorded a ping of {Ping}");
            if (PingList.Count > SettingAveragePingToKeep)
            {
                PingList.Dequeue();
            }

            CalculatePlayerAveragePing();
        }
示例#12
0
        /// /// <summary>
        /// Invoke the method with the given number on the node
        /// </summary>
        /// <param name="MethodNumber">The method number to invoke</param>
        /// <param name="Parameters">Parameters</param>
        /// <returns>True if invoked, false if not found</returns>
        public static bool Invoke(this Node Instance, int MethodNumber, params object[] Parameters)
        {
            MethodInfo Info = MDStatics.GetMethodInfo(Instance, MethodNumber);

            if (Info != null)
            {
                MDLog.Trace(LOG_CAT, $"Invoking {Info.Name} with parameters {MDStatics.GetParametersAsString(Parameters)}");
                Info.Invoke(Instance, Parameters);
                return(true);
            }

            MDLog.Trace(LOG_CAT, $"Failed to invoke method number {MethodNumber} with parameters {MDStatics.GetParametersAsString(Parameters)}");
            return(false);
        }
        private void UnpauseAtTickMsec(uint UnpauseTime, uint GameTickToUnpauseAt)
        {
            float waitTime = (UnpauseTime - OS.GetTicksMsec()) / 1000f;

            MDLog.Trace(LOG_CAT, $"Unpausing game in {waitTime}");
            Timer timer = this.CreateUnpausableTimer(RESUME_TIMER_NAME, true, waitTime, true, this,
                                                     nameof(OnUnpauseTimerTimeout));

            timer.Start();
            OnSynchCompleteEvent(waitTime);
            if (GameClock != null && MDStatics.IsClient())
            {
                GameClock.SetCurrentTick(GameTickToUnpauseAt);
            }
        }
示例#14
0
        /// <summary>Attempts to calculate what the remote offset should be based on the current ping</summary>
        private void CalculateRemoteOffset()
        {
            // Check if we got a fixed offset
            if (RemoteTickOffset > 0)
            {
                MDLog.Trace(LOG_CAT, $"Ping offset is set to be static at {RemoteTickOffset}");
                CurrentRemoteTickOffsetTarget = RemoteTickOffset + OffsetBuffer;
                return;
            }

            // Check if we got any ping
            int HighestPing = (int)Mathf.Ceil(GameSynchronizer.GetMaxPlayerPing() * RemoteTickPingModifier);

            if (HighestPing == 0)
            {
                CurrentRemoteTickOffsetTarget = MinimumOffset + OffsetBuffer;
                MDLog.Trace(LOG_CAT, $"We got no ping setting offset to minimum offset of {MinimumOffset}");
                return;
            }

            // Calculate offset based on ping
            int newOffset = (int)Mathf.Ceil(HighestPing / TICK_INTERVAL_MILLISECONDS);

            // If it is less than minimum set our target to minimum
            if (newOffset <= MinimumOffset)
            {
                CurrentRemoteTickOffsetTarget = MinimumOffset + OffsetBuffer;
                MDLog.Trace(LOG_CAT, $"Ping offset of {newOffset} is less than our minimum offset of {MinimumOffset}");
                return;
            }

            // Calculate the difference between new and old
            float difference = (float)(newOffset - CurrentRemoteTickOffset) / newOffset;

            difference = Mathf.Abs(difference);

            // Is the difference larger than our allowed tolerance?
            if (Mathf.Abs(difference) >= RemoteTickPingTolerance)
            {
                MDLog.Trace(LOG_CAT,
                            $"Ping difference is too large adjust remote tick offset target from {CurrentRemoteTickOffsetTarget} to {newOffset}");
                // We need to adjust the remote tick offset
                CurrentRemoteTickOffsetTarget = newOffset + OffsetBuffer;
            }
        }
示例#15
0
 private void UpdateNetworkIdMap(params object[] updates)
 {
     for (int i = 0; i < updates.Length; i += 2)
     {
         string key = (string)updates[i + 1];
         uint   id  = (uint)long.Parse(updates[i].ToString());
         MDLog.Debug(LOG_CAT, $"Received Network Map Update with id {id} and key [{key}]");
         NetworkIdKeyMap.AddNetworkKeyIdPair(id, key);
         if (KeyToMemberMap.ContainsKey(key))
         {
             NetworkIdKeyMap.CheckBuffer(id, KeyToMemberMap[key]);
         }
         else
         {
             MDLog.Trace(LOG_CAT, $"KeyToMemberMap does not contain key {key}");
         }
     }
 }
示例#16
0
        public override void _Process(float delta)
        {
            if (GetTree().Paused)
            {
                return;
            }

            // Adjust ourselves in synch with server at most once per tick
            if (TickSynchAdjustment > 0)
            {
                MDLog.Trace(LOG_CAT, $"Tick {CurrentTick}, was skipped because adjustment was {TickSynchAdjustment}");
                OnLocalSkippedTick(CurrentTick);
                CurrentTick++;
                TickSynchAdjustment--;
            }
            else if (TickSynchAdjustment < 0)
            {
                MDLog.Trace(LOG_CAT, $"Tick {CurrentTick}, was repeated because adjustment was {TickSynchAdjustment}");
                LastTickDuplicated = true;
                CurrentTick--;
                TickSynchAdjustment++;
            }

            DeltaTickCounter += delta;
            if (DeltaTickCounter >= TICK_INTERVAL_DELTA)
            {
                // Increase tick counter
                DeltaTickCounter -= TICK_INTERVAL_DELTA;
                CurrentTick++;

                // Allow skipping a single tick per update to catch up
                if (DeltaTickCounter >= TICK_INTERVAL_DELTA)
                {
                    MDLog.Trace(LOG_CAT, $"Tick {CurrentTick}, was skipped because delta was {delta}");
                    OnLocalSkippedTick(CurrentTick);
                    DeltaTickCounter -= TICK_INTERVAL_DELTA;
                    CurrentTick++;
                }
            }

            AdjustRemoteTickOffset();
            OnGameTick(CurrentTick);
        }
示例#17
0
        /// <summary>
        /// Apply the buffer to a member if it exists
        /// </summary>
        /// <param name="ID">The ID to check the buffer for</param>
        /// <param name="Member">The member to apply this buffer to</param>
        public void CheckBuffer(uint ID, MDReplicatedMember Member)
        {
            if (!ClockedValueBuffer.ContainsKey(ID))
            {
                return;
            }

            Dictionary <uint, object[]> buffer = GetBufferForId(ID);

            foreach (uint tick in buffer.Keys)
            {
                object[] value = buffer[tick];
                MDLog.Trace(LOG_CAT, $"Updating value to {MDStatics.GetParametersAsString(value)} for {ID} on tick {tick}");
                Member.SetValues(tick, value);
            }

            buffer.Clear();
            ClockedValueBuffer.Remove(ID);
        }
        /// <summary>
        /// Sets the value of this member
        /// </summary>
        /// <param name="member">The member</param>
        /// <param name="Instance">The instance to set the value for</param>
        /// <param name="Value">The value</param>
        public static void SetValue(this MemberInfo member, object Instance, object Value)
        {
            MDLog.Trace(LOG_CAT, $"Setting {member.Name}");
            switch (member.MemberType)
            {
            case MemberTypes.Field:
                ((FieldInfo)member).SetValue(Instance, Value);
                break;

            case MemberTypes.Property:
                ((PropertyInfo)member).SetValue(Instance, Value);
                break;

            default:
                MDLog.Error(LOG_CAT,
                            $"Input MemberInfo was of type {member.MemberType.ToString()}, it should be of type FieldInfo or PropertyInfo");
                break;
            }
        }
示例#19
0
        private void ClockedCall(uint Tick, ClockedRemoteCall.TypeOfCall Type, string NodePath, string Method,
                                 MDRemoteMode Mode, params object[] Parameters)
        {
            Node Target = GetNodeOrNull(NodePath);

            if (Target == null)
            {
                MDLog.Warn(LOG_CAT, $"Could not find target [{NodePath}] for ClockedRpcCall.");
                return;
            }
            MDLog.Trace(LOG_CAT, $"Got clocked call {Method} on {NodePath} with parameters ({MDStatics.GetParametersAsString(Parameters)})");
            ClockedRemoteCall RemoteCall = new ClockedRemoteCall(Tick, Type, WeakRef(Target), Method, Mode, Multiplayer.GetRpcSenderId(), Parameters);

            // Check if we should already invoke this (if the time has already passed)
            if (!RemoteCall.Invoke(GameClock.GetRemoteTick()))
            {
                ClockedRemoteCallList.Add(RemoteCall);
            }
        }
示例#20
0
        public bool ShouldObjectBeReplicated(object LastValue, object CurrentValue)
        {
            if (LastValue == null && CurrentValue == null)
            {
                return(false);
            }
            else if (LastValue == null || CurrentValue == null)
            {
                MDLog.Trace(LOG_CAT, "We should be replicated because something is null");
                return(true);
            }
            else if (((T)CurrentValue).MDShouldBeReplicated())
            {
                MDLog.Trace(LOG_CAT, "We should be replicated because we have updates");
                return(true);
            }

            return(false);
        }
示例#21
0
        public object ConvertBackToObject(object CurrentObject, object[] Parameters)
        {
            ExtractMembers();
            MDLog.Trace(LOG_CAT, $"MDCustomClass converting back ({MDStatics.GetParametersAsString(Parameters)})");

            if (Parameters.Length == 1 && Parameters[0] == null)
            {
                return(null);
            }

            T obj;

            if (CurrentObject != null)
            {
                // Replace values in existing object
                obj = (T)CurrentObject;
            }
            else
            {
                // Return a new object
                obj = (T)Activator.CreateInstance(typeof(T));
            }

            for (int i = 0; i < Parameters.Length; i++)
            {
                // key0 = index, key1 = length
                object[] keys   = Parameters[i].ToString().Split(SEPARATOR);
                int      index  = Convert.ToInt32(keys[0].ToString());
                int      length = Convert.ToInt32(keys[1].ToString());

                // Extract parameters and use data converter
                object[] converterParams = Parameters.SubArray(i + 1, i + length);
                object   currentValue    = Members[index].GetValue(obj);
                object   convertedValue  = DataConverters[index].ConvertBackToObject(currentValue, converterParams);

                // Set the value and increase i based on length of data
                Members[index].SetValue(obj, convertedValue);
                i += length;
            }
            return(obj);
        }
示例#22
0
        /// <summary>
        /// Finds and loads the file with the given name.
        /// This will overwrite any existing section+keys with the same value already in our configuration.
        /// </summary>
        /// <param name="name">The name of the file to load</param>
        /// <returns>True if it could be found and loaded, false if not</returns>
        public bool LoadConfiguration(string name)
        {
            string path = FindFile(name);

            if (path == "")
            {
                return(false);
            }

            MDLog.Trace(LOG_CAT, $"Loading config file {path}");
            ConfigFile conFile = new ConfigFile();

            conFile.Load(path);
            foreach (string section in conFile.GetSections())
            {
                foreach (string key in conFile.GetSectionKeys(section))
                {
                    if (!Configuration.ContainsKey(section))
                    {
                        MDLog.Trace(LOG_CAT, $"Adding section {section}");
                        // Add a new section
                        Configuration.Add(section, new Dictionary <string, object>());
                    }

                    if (!Configuration[section].ContainsKey(key))
                    {
                        MDLog.Trace(LOG_CAT, $"Adding section {section} key {key}");
                        // Add a new key
                        Configuration[section].Add(key, conFile.GetValue(section, key));
                    }
                    else
                    {
                        MDLog.Trace(LOG_CAT, $"Overwriting section {section} key {key}");
                        // Overwrite existing key
                        Configuration[section][key] = conFile.GetValue(section, key);
                    }
                }
            }
            return(true);
        }
        /// <summary>
        /// Called when the ping timer times out, sends a ping request to the given client.
        /// </summary>
        public void OnPingTimerTimeout()
        {
            // Check if network is still active
            if (!MDStatics.IsNetworkActive())
            {
                MDLog.Trace(LOG_CAT, $"Network is no longer active");
                return;
            }

            // Send ping request
            if (GameSynchronizer.GameClock == null)
            {
                GameSynchronizer.RpcId(PeerId, MDGameSynchronizer.METHOD_REQUEST_PING, OS.GetTicksMsec());
            }
            else
            {
                int  maxPlayerPing = GameSynchronizer.GetMaxPlayerPing() + (int)Ping;
                uint estimate      = GameSynchronizer.GetPlayerTicksMsec(PeerId) + (uint)Ping;
                GameSynchronizer.RpcId(PeerId, MDGameSynchronizer.METHOD_REQUEST_PING, OS.GetTicksMsec(), estimate,
                                       GameSynchronizer.GameClock.GetTickAtTimeOffset(Ping), maxPlayerPing);
            }
        }
示例#24
0
        public object[] ConvertForSending(object Item, bool Complete)
        {
            ExtractMembers();
            if (Item == null)
            {
                return(new object[] { null });
            }

            List <object> ObjectArray   = new List <object>();
            List <object> newLastValues = new List <object>();

            for (int i = 0; i < Members.Count; i++)
            {
                object           value     = Members[i].GetValue(Item);
                IMDDataConverter Converter = DataConverters[i];
                if (Complete || LastValues.Count == 0 || Converter.ShouldObjectBeReplicated(LastValues[i], value))
                {
                    object[] dataArray = Converter.ConvertForSending(value, Complete);
                    if (dataArray != null)
                    {
                        ObjectArray.Add($"{i}{SEPARATOR}{dataArray.Length}");
                        ObjectArray.AddRange(dataArray);
                    }
                    else
                    {
                        ObjectArray.Add($"{i}{SEPARATOR}{1}");
                        ObjectArray.Add(null);
                    }
                }
                newLastValues.Add(value);
            }

            MDLog.Trace(LOG_CAT, $"MDCustomClass converting for sending ({MDStatics.GetParametersAsString(ObjectArray.ToArray())})");

            LastValues = newLastValues;
            return(ObjectArray.ToArray());
        }
示例#25
0
        public object[] ConvertForSending(object Item, bool Complete)
        {
            if (Item == null)
            {
                return(new object[] { null });
            }

            // Get commands
            T CReplicator            = (T)Item;
            List <object[]> commands = Complete ? CReplicator.MDGetCommandsForNewPlayer() : CReplicator.MDGetCommands();

            List <object> ReturnList = new List <object>();

            foreach (object[] command in commands)
            {
                // Add length
                ReturnList.Add(command.Length);
                ReturnList.AddRange(command);
            }

            MDLog.Trace(LOG_CAT, $"MDCommandReplicator converting for sending ({MDStatics.GetParametersAsString(ReturnList.ToArray())})");

            return(ReturnList.ToArray());
        }
 private void RequestPing(uint ServerTimeOfRequest)
 {
     // Respond
     RpcId(Multiplayer.GetRpcSenderId(), nameof(PingResponse), ServerTimeOfRequest);
     MDLog.Trace(LOG_CAT, "Responded to server request for ping");
 }
 private void OnNetworkNodeRemoved(Node node)
 {
     MDLog.Trace(LOG_CAT, $"Node removed: {node.GetPath()}");
     NodeList.Remove(node);
 }
        private void CheckSynchStatus(Timer timer)
        {
            // Only do this on clients
            if (!this.IsClient())
            {
                timer.RemoveAndFree();
                return;
            }

            if (NodeCount < 0)
            {
                MDLog.Debug(LOG_CAT, "We got no node count");
                // We don't know how many nodes we got yet
                return;
            }

            int SynchedNodes = NodeCount;

            if (NodeList.Count < NodeCount)
            {
                MDLog.Debug(LOG_CAT, "We still don't have all nodes");
                // We still don't have all nodes
                SynchedNodes = NodeList.Count;
            }
            else if (!NodeSynchCompleted)
            {
                // This is the first time we synched all nodes, notify the server
                MDLog.Debug(LOG_CAT, "Node synch complete, notifying server");
                NodeSynchCompleted = true;
                RpcId(GameSession.GetNetworkMaster(), nameof(NotifyAllNodesSynched));
            }

            int NotSynchedNodes = 0;

            // Check node custom logic to see if synch is done
            foreach (Node node in NodeList)
            {
                if (!(node is IMDSynchronizedNode) || ((IMDSynchronizedNode)node).IsSynchronizationComplete())
                {
                    continue;
                }

                // We are not synched
                MDLog.Trace(LOG_CAT, $"A node is still synching: {node.GetPath()}");
                SynchedNodes--;
                NotSynchedNodes++;
            }

            if (SynchedNodes == NodeCount)
            {
                // We are done synching
                SynchronizationState = SynchronizationStates.SYNCRHONIZED;
                RpcId(MDStatics.GetServerId(), nameof(ClientSynchDone));
                MDLog.Debug(LOG_CAT, "We are done synching notifying server");
                // Set ourselves to done
                OnPlayerSynchStatusUpdateEvent(MDStatics.GetPeerId(), 1f);
                timer.RemoveAndFree();
            }
            else
            {
                float percentage = (float)SynchedNodes / NodeCount;
                MDLog.Debug(LOG_CAT,
                            $"We have {NotSynchedNodes} nodes that are still synching. Current status: {percentage * 100}%");
                // Notify the server of how many nodes we got synched
                RpcId(GameSession.GetNetworkMaster(), nameof(ClientSynchStatus), SynchedNodes);

                // Update our own UI
                OnPlayerSynchStatusUpdateEvent(MDStatics.GetPeerId(), percentage);
            }
        }
示例#29
0
        /// <summary>
        /// Registers the given instance's fields marked with [MDReplicated()]
        /// </summary>
        /// <param name="Instance">The node to register</param>
        public void RegisterReplication(Node Instance)
        {
            List <MemberInfo>         Members     = MDStatics.GetTypeMemberInfos(Instance);
            List <MDReplicatedMember> NodeMembers = new List <MDReplicatedMember>();

            foreach (MemberInfo Member in Members)
            {
                MDReplicated RepAttribute = Member.GetCustomAttribute(typeof(MDReplicated)) as MDReplicated;
                if (RepAttribute == null)
                {
                    continue;
                }

                MDReplicatedSetting[] Settings   = GetSettings(Member);
                MDReplicatedMember    NodeMember = CreateReplicatedMember(Member, RepAttribute, Instance, Settings);

                NodeMembers.Add(NodeMember);

                ProcessSettingsForMember(NodeMember, ParseParameters(typeof(Settings), Settings));

                GroupManager.AddReplicatedMember(NodeMember);

                MDLog.Debug(LOG_CAT, $"Adding Replicated Node {Instance.Name} Member {Member.Name}");

                if (HasRPCModeSet(Member) == false)
                {
                    Instance.RsetConfig(Member.Name, MultiplayerAPI.RPCMode.Puppet);
                }
            }

            if (NodeMembers.Count > 0)
            {
                NodeList.Add(new ReplicatedNode(Instance, NodeMembers));
                List <object> networkIdUpdates = new List <object>();
                foreach (MDReplicatedMember member in NodeMembers)
                {
                    string MemberUniqueKey = member.GetUniqueKey();
                    KeyToMemberMap.Add(MemberUniqueKey, member);

                    // Check if we have a buffer waiting for this member
                    if (NetworkIdKeyMap.ContainsKey(MemberUniqueKey))
                    {
                        NetworkIdKeyMap.CheckBuffer(NetworkIdKeyMap.GetValue(MemberUniqueKey), member);
                    }

                    if (MDStatics.IsServer())
                    {
                        if (!NetworkIdKeyMap.ContainsKey(member.GetUniqueKey()))
                        {
                            uint networkid = GetReplicationId();
                            MDLog.Trace(LOG_CAT, $"Adding NetworkIdKeyMap key [{member.GetUniqueKey()}] with id [{networkid}]");
                            NetworkIdKeyMap.AddNetworkKeyIdPair(networkid, member.GetUniqueKey());
                            NetworkIdKeyMap.CheckBuffer(networkid, member);
                            networkIdUpdates.Add(networkid);
                            networkIdUpdates.Add(member.GetUniqueKey());
                        }
                    }
                }

                if (MDStatics.IsNetworkActive() && networkIdUpdates.Count > 0)
                {
                    Rpc(nameof(UpdateNetworkIdMap), networkIdUpdates);
                }
            }
        }
 private void OnUnpauseTimerTimeout(Timer timer)
 {
     MDLog.Trace(LOG_CAT, "Unpausing game");
     timer.RemoveAndFree();
     GetTree().Paused = false;
 }