Exemple #1
0
        public static InvalidCatchupException ApplyCatchupInfo(this SceneTree tree, Dictionary data)
        {
            const string errorPrefix = "Catchup info target entry is malformed and was ignored: ";

            Debug.Assert(_catchupPhase == CatchupApplicationPhase.NotCatchingUp);

            // Deliver catchup "RPCs"
            _catchupPhase = CatchupApplicationPhase.ApplyingInfo;
            foreach (var pathRaw in data.Keys)
            {
                // Parse path
                if (!(pathRaw is NodePath path))
                {
                    GD.PushWarning(errorPrefix + "key was not a node path.");
                    continue;
                }

                GD.Print($"Catching up node at \"{path}\"");

                var node = tree.Root.GetNodeOrNull <IRequiresCatchup>(path);
                if (node == null)
                {
                    GD.PushWarning(errorPrefix +
                                   $"specified node does not exist or does not implement {nameof(IRequiresCatchup)}.");
                    continue;
                }

                if (!((Node)node).IsInGroup(GroupRequiresCatchup))
                {
                    GD.PushWarning(errorPrefix + "specified node at is not flagged as currently requiring catchup.");
                    continue;
                }

                // Attempt to apply catchup
                try
                {
                    node.HandleCatchupState(data[pathRaw]);
                    ((Node)node).RemoveFromGroup(GroupRequiresCatchup);
                }
                catch (InvalidCatchupException e)
                {
                    e.Instigator  = (Node)node;
                    _catchupPhase = CatchupApplicationPhase.NotCatchingUp;
                    return(e);
                }
            }

            // Ensure that all nodes requiring catchup have been caught up
            if (tree.DoesAnythingRequireCatchup())
            {
                _catchupPhase = CatchupApplicationPhase.NotCatchingUp;
                var list  = new StringBuilder();
                var first = true;
                foreach (var node in tree.GetNodesInGroup(GroupRequiresCatchup).Cast <Node>())
                {
                    if (!first)
                    {
                        list.Append(",");
                    }
                    first = false;
                    list.Append(node.GetPath());
                }
                return(new InvalidCatchupException($"At least one node marked as currently requiring catchup has not been caught up.\nNodes: {list}"));
            }

            // Perform macro catchup validation
            _catchupPhase = CatchupApplicationPhase.SecondPass;
            foreach (var(node, validator) in tree.EnumerateGroupMembers <IMacroCatchupValidator>(GroupMacroCatchupValidator))
            {
                try
                {
                    validator.ValidateCatchupState();
                }
                catch (InvalidCatchupException e)
                {
                    e.Instigator  = node;
                    _catchupPhase = CatchupApplicationPhase.NotCatchingUp;
                    return(e);
                }

                node.RemoveFromGroup(GroupMacroCatchupValidator);
            }

            // Announce catchup finish
            foreach (var(node, awaiter) in tree.EnumerateGroupMembers <ICatchupAwaiter>(GroupCatchupAwaiter))
            {
                awaiter._CaughtUp();
                node.RemoveFromGroup(GroupCatchupAwaiter);
            }

            _catchupPhase = CatchupApplicationPhase.NotCatchingUp;
            return(null);
        }