private SegmentsStruct() : base("PathmapSegment")
        {
            this.Kind = "struct";

            Node_A = new InternalVar("Node_A", CompletionItemKind.Property)
            {
                Documentation = "The primary node of this segment. This returns a number which is the index of the node in the pathmap."
            };
            Node_B = new InternalVar("Node_B", CompletionItemKind.Property)
            {
                Documentation = "The secondary node of this segment. This returns a number which is the index of the node in the pathmap."
            };
            Attribute_AB = new InternalVar("Attribute_AB", CompletionItemKind.Property)
            {
                Documentation = "The attribute of this segment when traveling from node A to B."
            };
            Attribute_BA = new InternalVar("Attribute_BA", CompletionItemKind.Property)
            {
                Documentation = "The attribute of this segment when traveling from node B to A."
            };

            _scope.AddNativeVariable(Node_A);
            _scope.AddNativeVariable(Node_B);
            _scope.AddNativeVariable(Attribute_AB);
            _scope.AddNativeVariable(Attribute_BA);
        }
 public JsonProperty(JProperty property)
 {
     Name = property.Name;
     Var  = new InternalVar(property.Name, Value.Type);
     // Var.IsSettable = false;
     Value             = IJsonValue.GetValue(property.Value);
     Var.Documentation = Value.Documentation;
 }
        public override void ResolveElements()
        {
            if (elementsResolved)
            {
                return;
            }
            base.ResolveElements();

            serveObjectScope.AddNativeMethod(Pathfind);
            serveObjectScope.AddNativeMethod(PathfindAll);
            serveObjectScope.AddNativeMethod(GetPath);
            serveObjectScope.AddNativeMethod(PathfindEither);
            serveObjectScope.AddNativeMethod(GetResolve(DeltinScript));
            serveObjectScope.AddNativeMethod(GetResolveTo(DeltinScript));
            serveObjectScope.AddNativeMethod(AddNode);
            serveObjectScope.AddNativeMethod(DeleteNode);
            serveObjectScope.AddNativeMethod(AddSegment);
            serveObjectScope.AddNativeMethod(DeleteSegment);
            serveObjectScope.AddNativeMethod(SetSegmentAttributeAB);
            serveObjectScope.AddNativeMethod(SetSegmentAttributeBA);
            serveObjectScope.AddNativeMethod(SegmentFromNodes);

            staticScope.AddNativeMethod(StopPathfind);
            staticScope.AddNativeMethod(CurrentSegmentAttribute);
            staticScope.AddNativeMethod(IsPathfinding);
            staticScope.AddNativeMethod(IsPathfindStuck);
            staticScope.AddNativeMethod(FixPathfind);
            staticScope.AddNativeMethod(NextNode);
            staticScope.AddNativeMethod(ThrottleToNextNode);
            staticScope.AddNativeMethod(Recalibrate);
            staticScope.AddNativeMethod(IsPathfindingToNode);
            staticScope.AddNativeMethod(IsPathfindingToSegment);

            // Hooks

            // All 'userLambda' variables below should be LambdaAction.

            // Code to run when pathfinding starts.
            OnPathStartHook = new HookVar("OnPathStart", new BlockLambda(), userLambda => DeltinScript.ExecOnComponent <ResolveInfoComponent>(resolveInfo => resolveInfo.OnPathStart = (LambdaAction)userLambda));
            OnPathStartHook.Documentation = AddHookInfo(new MarkupBuilder()
                                                        .Add("The code that runs when a pathfind starts for a player. By default, it will start throttling to the player's current node. Hooking will override the thottle, so if you want to throttle you will need to call ").Code("Pathmap.ThrottleEventPlayerToNextNode").Add(".")
                                                        .NewLine().Add("Call ").Code("EventPlayer()").Add(" to get the player that is pathfinding."));
            // Code to run when node is reached.
            OnNodeReachedHook = new HookVar("OnNodeReached", new BlockLambda(), userLambda => DeltinScript.ExecOnComponent <ResolveInfoComponent>(resolveInfo => resolveInfo.OnNodeReached = (LambdaAction)userLambda));
            OnNodeReachedHook.Documentation = AddHookInfo(new MarkupBuilder().Add("The code that runs when a player reaches a node. Does nothing by default.")
                                                          .NewLine().Add("Call ").Code("EventPlayer()").Add(" to get the player that reached the node."));
            // Code to run when pathfind completes.
            OnPathCompleted = new HookVar("OnPathCompleted", new BlockLambda(), userLambda => DeltinScript.ExecOnComponent <ResolveInfoComponent>(resolveInfo => resolveInfo.OnPathCompleted = (LambdaAction)userLambda));
            OnPathCompleted.Documentation = AddHookInfo(new MarkupBuilder().Add("The code that runs when a player completes a pathfind. By default, it will stop throttling the player and call ").Code("StopPathfind(EventPlayer())").Add(", hooking will override this.")
                                                        .NewLine().Add("Call ").Code("EventPlayer()").Add(" to get the player that completed the path."));
            // The condition to use to determine if a node was reached.
            IsNodeReachedDeterminer = new HookVar("IsNodeReachedDeterminer", new MacroLambda(null, new CodeType[] { VectorType.Instance }), userLambda => DeltinScript.ExecOnComponent <ResolveInfoComponent>(resolveInfo => resolveInfo.IsNodeReachedDeterminer = (LambdaAction)userLambda));
            IsNodeReachedDeterminer.Documentation = AddHookInfo(new MarkupBuilder()
                                                                .Add("The condition that is used to determine if a player reached the current node. The given value is the position of the next node. The returned value should be a boolean determining if the player reached the node they are walking towards.")
                                                                .NewLine()
                                                                .Add("Modify the ").Code("Pathmap.OnNodeReached").Add(" hook to run code when the player reaches the node.")
                                                                .NewSection()
                                                                .Add("By default, it will return true when the player is less than or equal to " + ResolveInfoComponent.DefaultMoveToNext + " meters away from the next node."));
            // The condition to use to determine the closest node to a player.
            ApplicableNodeDeterminer = new HookVar("ApplicableNodeDeterminer", new ValueBlockLambda(null, new CodeType[] { new ArrayType(VectorType.Instance), VectorType.Instance }), userLambda => DeltinScript.ExecOnComponent <ResolveInfoComponent>(resolveInfo => resolveInfo.ApplicableNodeDeterminer = (LambdaAction)userLambda));
            ApplicableNodeDeterminer.Documentation = AddHookInfo(new MarkupBuilder()
                                                                 .Add("Gets a node that is relevent to the specified position. Hooking this will change how OSTW generated rules will get the node. By default, it will return the node that is closest to the specified position.")
                                                                 .NewLine()
                                                                 .Add("The returned value must be the index of the node in the ").Code("nodes").Add(" array.")
                                                                 .NewLine()
                                                                 .Add("The default implementation may cause problems if the closest node to a player is behind a wall or under the floor. Hooking this so line-of-sight is accounted for may be a good idea if accuracy is more important than server load, for example:")
                                                                 .NewSection()
                                                                 .StartCodeLine()
                                                                 .Add(@"Pathmap.ApplicableNodeDeterminer = (Vector[] nodes, Vector position) => {
    return IndexOfArrayValue(nodes, nodes.FilteredArray(Vector node => node.IsInLineOfSight(position)).SortedArray(Vector node => node.DistanceTo(position))[0]);
}")
                                                                 .EndCodeLine());

            staticScope.AddNativeVariable(OnPathStartHook);
            staticScope.AddNativeVariable(OnNodeReachedHook);
            staticScope.AddNativeVariable(OnPathCompleted);
            staticScope.AddNativeVariable(IsNodeReachedDeterminer);
            staticScope.AddNativeVariable(ApplicableNodeDeterminer);

            NodesVar = new InternalVar("Nodes", CompletionItemKind.Property)
            {
                Documentation = "The nodes of the pathmap.",
                CodeType      = new ArrayType(VectorType.Instance),
                IsSettable    = false
            };
            SegmentsVar = new InternalVar("Segments", CompletionItemKind.Property)
            {
                Documentation = "The segments of the pathmap. These segments connect the nodes together.",
                CodeType      = new ArrayType(SegmentsStruct.Instance),
                IsSettable    = false
            };
            serveObjectScope.AddNativeVariable(NodesVar);
            serveObjectScope.AddNativeVariable(SegmentsVar);
        }