// Called when the node enters the scene tree for the first time.
 public override void _Ready()
 {
     MDLog.AddLogCategoryProperties(LOG_CAT, new MDLogProperties(MDLogLevel.Info));
     GameSession = GameInstance.GetGameSession();
     GameSession.OnPlayerJoinedEvent      += OnPlayerJoinedEvent;
     GameSession.OnPlayerInitializedEvent += OnPlayerInitializedEvent;
     GameSession.OnPlayerLeftEvent        += OnPlayerLeftEvent;
     GameSession.OnNetworkNodeAdded       += OnNetworkNodeAdded;
     GameSession.OnNetworkNodeRemoved     += OnNetworkNodeRemoved;
     GameSession.OnSessionStartedEvent    += OnSessionStartedEvent;
     SynchronizationState = SynchronizationStates.SYNCHRONIZING_IN_PROGRESS;
 }
        private void OnSessionStartedEvent()
        {
            if (this.IsClient())
            {
                // Add max ping information between this client and any other client
                // Roundtrip is: client 1 -> server -> client 2 -> server -> client 1.
                // TODO: Max ping should be not identical for each player we ping
                MDOnScreenDebug.AddOnScreenDebugInfo(DEBUG_CAT, "MaxRoundtripPing: ", () => MaxPing.ToString());
                PauseGame();
                SynchronizationState = SynchronizationStates.SYNCHRONIZING_IN_PROGRESS;
            }
            else
            {
                SynchronizationState = SynchronizationStates.SYNCRHONIZED;
            }

            // Reset to tick 0 at start of session
            GameClock?.SetCurrentTick(0);
        }
        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);
            }
        }