Exemplo n.º 1
0
        public IEnumerable <Status> FindPath()
        {
            Vector3 target = Entity.Position;

            if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint)
            {
                target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint);
            }

            List <MoveAction> path = new List <MoveAction>();
            VoxelHandle       curr = Creature.Physics.CurrentVoxel;
            var storage            = new MoveActionTempStorage();

            for (int i = 0; i < PathLength; i++)
            {
                var actions = Creature.AI.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = curr
                }, new List <GameComponent>(), storage);

                MoveAction?bestAction = null;
                float      bestDist   = float.MinValue;
                foreach (MoveAction action in actions)
                {
                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared();

                    if (dist > bestDist)
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType &&
                              Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains))
                {
                    MoveAction action = bestAction.Value;
                    action.DestinationVoxel = curr;
                    path.Add(action);
                    curr = bestAction.Value.DestinationVoxel;
                }
                else
                {
                    break;
                }
            }
            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("FleePath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
Exemplo n.º 2
0
        public List <MoveAction> ComputeGreedyFallback(int maxsteps = 10, List <VoxelHandle> exploredVoxels = null)
        {
            var toReturn      = new List <MoveAction>();
            var goal          = GetGoal();
            var creatureVoxel = Agent.Physics.CurrentVoxel;

            if (goal.IsInGoalRegion(creatureVoxel))
            {
                return(toReturn);
            }

            var storage      = new MoveActionTempStorage();
            var bodies       = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();
            var currentVoxel = creatureVoxel;

            while (toReturn.Count < maxsteps)
            {
                var actions = Agent.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = currentVoxel
                }, bodies, storage);

                float minCost      = float.MaxValue;
                var   minAction    = new MoveAction();
                bool  hasMinAction = false;

                foreach (var action in actions)
                {
                    if (toReturn.Any(a => a.DestinationVoxel == action.DestinationVoxel && a.MoveType == action.MoveType))
                    {
                        continue;
                    }

                    var vox = action.DestinationVoxel;

                    float cost = goal.Heuristic(vox) * MathFunctions.Rand(1.0f, 1.1f) + Agent.Movement.Cost(action.MoveType);
                    if (exploredVoxels != null && exploredVoxels.Contains(action.DestinationVoxel))
                    {
                        cost *= 10;
                    }

                    if (cost < minCost)
                    {
                        minAction    = action;
                        minCost      = cost;
                        hasMinAction = true;
                    }
                }

                if (hasMinAction)
                {
                    MoveAction action = minAction;
                    action.DestinationVoxel = currentVoxel;
                    toReturn.Add(action);
                    currentVoxel = minAction.DestinationVoxel;
                    if (goal.IsInGoalRegion(minAction.DestinationVoxel))
                    {
                        return(toReturn);
                    }
                }
                else
                {
                    return(toReturn);
                }
            }
            return(toReturn);
        }
Exemplo n.º 3
0
        public IEnumerable <Status> FindGreedyPath()
        {
            Vector3 target = Target.Position;

            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }
            List <MoveAction> path = new List <MoveAction>();
            var curr    = Creature.Physics.CurrentVoxel;
            var bodies  = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();
            var storage = new MoveActionTempStorage();

            for (int i = 0; i < PathLength; i++)
            {
                IEnumerable <MoveAction> actions =
                    Creature.AI.Movement.GetMoveActions(new MoveState()
                {
                    Voxel = curr
                }, bodies, storage);

                MoveAction?bestAction = null;
                float      bestDist   = float.MaxValue;

                foreach (MoveAction action in actions)
                {
                    // Prevents a stack overflow due to "DestroyObject" task creating a FollowPathAct!
                    if (action.MoveType == MoveType.DestroyObject)
                    {
                        continue;
                    }
                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared();

                    if (dist < bestDist)
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                Vector3 half = Vector3.One * 0.5f;
                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType))
                {
                    path.Add(bestAction.Value);
                    MoveAction action = bestAction.Value;
                    action.DestinationVoxel = curr;
                    curr       = bestAction.Value.DestinationVoxel;
                    bestAction = action;

                    if (((bestAction.Value.DestinationVoxel.WorldPosition + half) - target).Length() < Threshold)
                    {
                        break;
                    }
                }
            }

            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
Exemplo n.º 4
0
        public IEnumerable <Act.Status> GreedyFallbackBehavior(Creature agent)
        {
            var edgeGoal = new EdgeGoalRegion();

            while (true)
            {
                DieTimer.Update(DwarfTime.LastTime);
                if (DieTimer.HasTriggered)
                {
                    foreach (var status in Die(agent))
                    {
                        continue;
                    }
                    yield break;
                }
                var creatureVoxel      = agent.Physics.CurrentVoxel;
                List <MoveAction> path = new List <MoveAction>();
                var storage            = new MoveActionTempStorage();
                for (int i = 0; i < 10; i++)
                {
                    if (edgeGoal.IsInGoalRegion(creatureVoxel))
                    {
                        foreach (var status in Die(agent))
                        {
                            continue;
                        }
                        yield return(Act.Status.Success);

                        yield break;
                    }

                    var actions = agent.AI.Movement.GetMoveActions(new MoveState {
                        Voxel = creatureVoxel
                    }, new List <GameComponent>(), storage);

                    float minCost      = float.MaxValue;
                    var   minAction    = new MoveAction();
                    bool  hasMinAction = false;
                    foreach (var action in actions)
                    {
                        var vox = action.DestinationVoxel;

                        float cost = edgeGoal.Heuristic(vox) * 10 + MathFunctions.Rand(0.0f, 0.1f) + agent.AI.Movement.Cost(action.MoveType);

                        if (cost < minCost)
                        {
                            minAction    = action;
                            minCost      = cost;
                            hasMinAction = true;
                        }
                    }

                    if (hasMinAction)
                    {
                        path.Add(minAction);
                        creatureVoxel = minAction.DestinationVoxel;
                    }
                    else
                    {
                        foreach (var status in Die(agent))
                        {
                            continue;
                        }
                        yield return(Act.Status.Success);

                        yield break;
                    }
                }
                if (path.Count == 0)
                {
                    foreach (var status in Die(agent))
                    {
                        continue;
                    }
                    yield return(Act.Status.Success);

                    yield break;
                }
                agent.AI.Blackboard.SetData("GreedyPath", path);
                var pathAct = new FollowPathAct(agent.AI, "GreedyPath");
                pathAct.Initialize();

                foreach (Act.Status status in pathAct.Run())
                {
                    yield return(Act.Status.Running);
                }
                yield return(Act.Status.Running);
            }
        }
Exemplo n.º 5
0
        // Inverts GetMoveActions. So, returns the list of move actions whose target is the current voxel.
        // Very, very slow.
        public IEnumerable <MoveAction> GetInverseMoveActions(MoveState currentstate, OctTreeNode OctTree, List <Body> teleportObjects)
        {
            if (Parent == null)
            {
                yield break;
            }

            if (Creature == null)
            {
                yield break;
            }

            var current = currentstate.Voxel;

            if (Can(MoveType.Teleport))
            {
                foreach (var obj in teleportObjects)
                {
                    if ((obj.Position - current.WorldPosition).LengthSquared() > 2)
                    {
                        continue;
                    }

                    for (int dx = -TeleportDistance; dx <= TeleportDistance; dx++)
                    {
                        for (int dz = -TeleportDistance; dz <= TeleportDistance; dz++)
                        {
                            for (int dy = -TeleportDistance; dy <= TeleportDistance; dy++)
                            {
                                if (dx * dx + dy * dy + dz * dz > TeleportDistanceSquared)
                                {
                                    continue;
                                }
                                VoxelHandle teleportNeighbor = new VoxelHandle(Parent.World.ChunkManager.ChunkData, current.Coordinate + new GlobalVoxelOffset(dx, dy, dz));

                                if (teleportNeighbor.IsValid && teleportNeighbor.IsEmpty && !VoxelHelpers.GetNeighbor(teleportNeighbor, new GlobalVoxelOffset(0, -1, 0)).IsEmpty)
                                {
                                    yield return(new MoveAction()
                                    {
                                        InteractObject = obj,
                                        Diff = new Vector3(dx, dx, dz),
                                        SourceVoxel = teleportNeighbor,
                                        DestinationState = currentstate,
                                        MoveType = MoveType.Teleport
                                    });
                                }
                            }
                        }
                    }
                }
            }

            var storage = new MoveActionTempStorage();

            foreach (var v in VoxelHelpers.EnumerateCube(current.Coordinate)
                     .Select(n => new VoxelHandle(current.Chunk.Manager.ChunkData, n))
                     .Where(h => h.IsValid))
            {
                foreach (var a in GetMoveActions(new MoveState()
                {
                    Voxel = v
                }, OctTree, teleportObjects, storage).Where(a => a.DestinationState == currentstate))
                {
                    yield return(a);
                }

                if (!Can(MoveType.RideVehicle))
                {
                    continue;
                }

                // Now that dwarfs can ride vehicles, the inverse of the move actions becomes extremely complicated. We must now
                // iterate through all rails intersecting every neighbor and see if we can find a connection from that rail to this one.
                // Further, we must iterate through the entire rail network and enumerate all possible directions in and out of that rail.
                // Yay!

                // Actually - why not just not bother with rails when inverse pathing, since it should only be invoked when forward pathing fails anyway?
                var bodies = new HashSet <Body>();
                OctTree.EnumerateItems(v.GetBoundingBox(), bodies);
                var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active);
                foreach (var rail in rails)
                {
                    if (rail.GetContainingVoxel() != v)
                    {
                        continue;
                    }

                    foreach (var neighborRail in rail.NeighborRails.Select(neighbor => Creature.Manager.FindComponent(neighbor.NeighborID) as Rail.RailEntity))
                    {
                        var actions = GetMoveActions(new MoveState()
                        {
                            Voxel = v, VehicleState = new VehicleState()
                            {
                                Rail = rail, PrevRail = neighborRail
                            }
                        }, OctTree, teleportObjects, storage);
                        foreach (var a in actions.Where(a => a.DestinationState == currentstate))
                        {
                            yield return(a);
                        }
                    }

                    foreach (var a in GetMoveActions(new MoveState()
                    {
                        Voxel = v, VehicleState = new VehicleState()
                        {
                            Rail = rail, PrevRail = null
                        }
                    }, OctTree, teleportObjects, storage).Where(a => a.DestinationState == currentstate))
                    {
                        yield return(a);
                    }
                }
            }
        }
Exemplo n.º 6
0
        private IEnumerable <MoveAction> EnumerateSuccessors(MoveState state, VoxelHandle voxel, MoveActionTempStorage Storage, bool inWater, bool standingOnGround, bool topCovered, bool hasNeighbors, bool isRiding)
        {
            bool isClimbing = false;

            if (CanClimb || Can(MoveType.RideVehicle))
            {
                //Climbing ladders.

                var bodies = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(voxel.GetBoundingBox()));

                if (!isRiding)
                {
                    var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable"));

                    // if the creature can climb objects and a ladder is in this voxel,
                    // then add a climb action.
                    if (ladder != null && CanClimb)
                    {
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(1, 2, 1),
                            MoveType = MoveType.Climb,
                            InteractObject = ladder
                        });

                        if (!standingOnGround)
                        {
                            yield return(new MoveAction
                            {
                                Diff = new Vector3(1, 0, 1),
                                MoveType = MoveType.Climb,
                                InteractObject = ladder
                            });
                        }
                        standingOnGround = true;
                    }
                }

                if (!isRiding)
                {
                    var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active);

                    if (rails.Count() > 0 && Can(MoveType.RideVehicle))
                    {
                        {
                            foreach (var rail in rails)
                            {
                                if (rail.GetContainingVoxel() != state.Voxel)
                                {
                                    continue;
                                }


                                yield return(new MoveAction()
                                {
                                    SourceState = state,
                                    DestinationState = new MoveState()
                                    {
                                        VehicleState = new VehicleState()
                                        {
                                            Rail = rail
                                        },
                                        Voxel = rail.GetContainingVoxel()
                                    },
                                    MoveType = MoveType.EnterVehicle,
                                    Diff = new Vector3(1, 1, 1)
                                });
                            }
                        }
                    }
                }

                if (Can(MoveType.ExitVehicle) && isRiding)
                {
                    yield return(new MoveAction()
                    {
                        SourceState = state,
                        DestinationState = new MoveState()
                        {
                            VehicleState = new VehicleState(),
                            Voxel = state.Voxel
                        },
                        MoveType = MoveType.ExitVehicle,
                        Diff = new Vector3(1, 1, 1)
                    });
                }

                if (Can(MoveType.RideVehicle) && isRiding)
                {
                    foreach (var neighbor in Rail.RailHelper.EnumerateForwardNetworkConnections(state.VehicleState.PrevRail, state.VehicleState.Rail))
                    {
                        var neighborRail = Creature.Manager.FindComponent(neighbor) as Rail.RailEntity;
                        if (neighborRail == null || !neighborRail.Active)
                        {
                            continue;
                        }

                        yield return(new MoveAction()
                        {
                            SourceState = state,
                            DestinationState = new MoveState()
                            {
                                Voxel = neighborRail.GetContainingVoxel(),
                                VehicleState = new VehicleState()
                                {
                                    Rail = neighborRail,
                                    PrevRail = state.VehicleState.Rail
                                }
                            },
                            MoveType = MoveType.RideVehicle,
                        });
                    }
                }
            }

            // If the creature can climb walls and is not blocked by a voxl above.
            if (!isRiding && CanClimbWalls && !topCovered)
            {
                // This monstrosity is unrolling an inner loop so that we don't have to allocate an array or
                // enumerators.
                var wall = VoxelHandle.InvalidHandle;
                var n211 = Storage.Neighborhood[2, 1, 1];
                if (n211.IsValid && !n211.IsEmpty)
                {
                    wall = n211;
                }
                else
                {
                    var n011 = Storage.Neighborhood[0, 1, 1];
                    if (n011.IsValid && !n011.IsEmpty)
                    {
                        wall = n011;
                    }
                    else
                    {
                        var n112 = Storage.Neighborhood[1, 1, 2];
                        if (n112.IsValid && !n112.IsEmpty)
                        {
                            wall = n112;
                        }
                        else
                        {
                            var n110 = Storage.Neighborhood[1, 1, 0];
                            if (n110.IsValid && !n110.IsEmpty)
                            {
                                wall = n110;
                            }
                        }
                    }
                }

                if (wall.IsValid)
                {
                    isClimbing = true;
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(1, 2, 1),
                        MoveType = MoveType.ClimbWalls,
                        ActionVoxel = wall
                    });

                    if (!standingOnGround)
                    {
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(1, 0, 1),
                            MoveType = MoveType.ClimbWalls,
                            ActionVoxel = wall
                        });
                    }
                }
            }

            // If the creature either can walk or is in water, add the
            // eight-connected free neighbors around the voxel.
            if (!isRiding && ((CanWalk && standingOnGround) || (CanSwim && inWater)))
            {
                // If the creature is in water, it can swim. Otherwise, it will walk.
                var moveType = inWater ? MoveType.Swim : MoveType.Walk;
                if (!Storage.Neighborhood[0, 1, 1].IsValid || Storage.Neighborhood[0, 1, 1].IsEmpty)
                {
                    // +- x
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(0, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!Storage.Neighborhood[2, 1, 1].IsValid || Storage.Neighborhood[2, 1, 1].IsEmpty)
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(2, 1, 1),
                        MoveType = moveType
                    });
                }

                if (!Storage.Neighborhood[1, 1, 0].IsValid || Storage.Neighborhood[1, 1, 0].IsEmpty)
                {
                    // +- z
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(1, 1, 0),
                        MoveType = moveType
                    });
                }

                if (!Storage.Neighborhood[1, 1, 2].IsValid || Storage.Neighborhood[1, 1, 2].IsEmpty)
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(1, 1, 2),
                        MoveType = moveType
                    });
                }

                // Only bother worrying about 8-connected movement if there are
                // no full neighbors around the voxel.
                if (!hasNeighbors)
                {
                    if (!Storage.Neighborhood[2, 1, 2].IsValid || Storage.Neighborhood[2, 1, 2].IsEmpty)
                    {
                        // +x + z
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(2, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!Storage.Neighborhood[2, 1, 0].IsValid || Storage.Neighborhood[2, 1, 0].IsEmpty)
                    {
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(2, 1, 0),
                            MoveType = moveType
                        });
                    }

                    if (!Storage.Neighborhood[0, 1, 2].IsValid || Storage.Neighborhood[0, 1, 2].IsEmpty)
                    {
                        // -x -z
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(0, 1, 2),
                            MoveType = moveType
                        });
                    }

                    if (!Storage.Neighborhood[0, 1, 0].IsValid || Storage.Neighborhood[0, 1, 0].IsEmpty)
                    {
                        yield return(new MoveAction
                        {
                            Diff = new Vector3(0, 1, 0),
                            MoveType = moveType
                        });
                    }
                }
            }

            // If the creature's head is free, and it is standing on ground,
            // or if it is in water, or if it is climbing, it can also jump
            // to voxels that are 1 cell away and 1 cell up.
            if (!isRiding && (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing)))
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        if (dx == 1 && dz == 1)
                        {
                            continue;
                        }

                        if (Storage.Neighborhood[dx, 1, dz].IsValid && !Storage.Neighborhood[dx, 1, dz].IsEmpty)
                        {
                            yield return(new MoveAction
                            {
                                Diff = new Vector3(dx, 2, dz),
                                MoveType = MoveType.Jump
                            });
                        }
                    }
                }
            }

            // If the creature is not in water and is not standing on ground,
            // it can fall one voxel downward in free space.
            if (!isRiding && !inWater && !standingOnGround)
            {
                yield return(new MoveAction
                {
                    Diff = new Vector3(1, 0, 1),
                    MoveType = MoveType.Fall
                });
            }

            // If the creature can fly and is not underwater, it can fly
            // to any adjacent empty cell.
            if (!isRiding && CanFly && !inWater)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        for (int dy = 0; dy <= 2; dy++)
                        {
                            if (dx == 1 && dz == 1 && dy == 1)
                            {
                                continue;
                            }

                            if (!Storage.Neighborhood[dx, 1, dz].IsValid || Storage.Neighborhood[dx, 1, dz].IsEmpty)
                            {
                                yield return(new MoveAction
                                {
                                    Diff = new Vector3(dx, dy, dz),
                                    MoveType = MoveType.Fly
                                });
                            }
                        }
                    }
                }
            }
            if (!isRiding && CanDig)
            {
                // This loop is unrolled for speed. It gets the manhattan neighbors and tells the creature that it can mine
                // the surrounding rock to get through.
                int         dx       = -1;
                int         dy       = 0;
                int         dz       = 0;
                VoxelHandle neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }

                dx       = 1;
                dy       = 0;
                dz       = 0;
                neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }

                dx       = 0;
                dy       = 0;
                dz       = 1;
                neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }

                dx       = 0;
                dy       = 0;
                dz       = -1;
                neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }

                dx       = 0;
                dy       = 1;
                dz       = 0;
                neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }

                dx       = 0;
                dy       = -1;
                dz       = 0;
                neighbor = Storage.Neighborhood[dx + 1, dy + 1, dz + 1];
                if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
                {
                    yield return(new MoveAction
                    {
                        Diff = new Vector3(dx + 1, dy + 1, dz + 1),
                        MoveType = MoveType.Dig,
                        DestinationVoxel = neighbor,
                    });
                }
            }
        }
Exemplo n.º 7
0
        /// <summary> gets the list of actions that the creature can take from a given voxel. </summary>
        public IEnumerable <MoveAction> GetMoveActions(MoveState state, OctTreeNode OctTree, List <Body> teleportObjects, MoveActionTempStorage Storage)
        {
            if (Parent == null)
            {
                yield break;
            }

            if (!state.Voxel.IsValid)
            {
                yield break;
            }

            if (Creature == null)
            {
                yield break;
            }

            if (Storage == null)
            {
                Storage = new MoveActionTempStorage();
            }

            GetNeighborhood(state.Voxel.Chunk.Manager.ChunkData, state.Voxel, Storage.Neighborhood);

            bool inWater          = (Storage.Neighborhood[1, 1, 1].IsValid && Storage.Neighborhood[1, 1, 1].LiquidLevel > WaterManager.inWaterThreshold);
            bool standingOnGround = (Storage.Neighborhood[1, 0, 1].IsValid && !Storage.Neighborhood[1, 0, 1].IsEmpty);
            bool topCovered       = (Storage.Neighborhood[1, 2, 1].IsValid && !Storage.Neighborhood[1, 2, 1].IsEmpty);
            bool hasNeighbors     = HasNeighbors(Storage.Neighborhood);
            bool isRiding         = state.VehicleState.IsRidingVehicle;

            var neighborHoodBounds = new BoundingBox(Storage.Neighborhood[0, 0, 0].GetBoundingBox().Min, Storage.Neighborhood[2, 2, 2].GetBoundingBox().Max);

            Storage.NeighborObjects.Clear();
            OctTree.EnumerateItems(neighborHoodBounds, Storage.NeighborObjects);

            if (Can(MoveType.Teleport))
            {
                foreach (var obj in teleportObjects)
                {
                    if ((obj.Position - state.Voxel.WorldPosition).LengthSquared() < TeleportDistanceSquared)
                    {
                        yield return new MoveAction()
                               {
                                   InteractObject   = obj,
                                   MoveType         = MoveType.Teleport,
                                   SourceVoxel      = state.Voxel,
                                   DestinationState = new MoveState()
                                   {
                                       Voxel = new VoxelHandle(state.Voxel.Chunk.Manager.ChunkData, GlobalVoxelCoordinate.FromVector3(obj.Position))
                                   }
                               }
                    }
                }
            }
            ;

            var successors = EnumerateSuccessors(state, state.Voxel, Storage, inWater, standingOnGround, topCovered, hasNeighbors, isRiding);

            // Now, validate each move action that the creature might take.
            foreach (MoveAction v in successors)
            {
                var n = v.DestinationVoxel.IsValid ? v.DestinationVoxel : Storage.Neighborhood[(int)v.Diff.X, (int)v.Diff.Y, (int)v.Diff.Z];
                if (n.IsValid && (v.MoveType == MoveType.Dig || isRiding || n.IsEmpty || n.LiquidLevel > 0))
                {
                    // Do one final check to see if there is an object blocking the motion.
                    bool blockedByObject = false;
                    if (!isRiding)
                    {
                        var objectsAtNeighbor = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(n.GetBoundingBox()));

                        // If there is an object blocking the motion, determine if it can be passed through.

                        foreach (var body in objectsAtNeighbor)
                        {
                            var door = body as Door;
                            // ** Doors are in the octtree, pretty sure this was always pointless -- var door = body.GetRoot().EnumerateAll().OfType<Door>().FirstOrDefault();
                            // If there is an enemy door blocking movement, we can destroy it to get through.
                            if (door != null)
                            {
                                if (
                                    Creature.World.Diplomacy.GetPolitics(door.TeamFaction, Creature.Faction)
                                    .GetCurrentRelationship() ==
                                    Relationship.Hateful)
                                {
                                    if (Can(MoveType.DestroyObject))
                                    {
                                        yield return(new MoveAction
                                        {
                                            Diff = v.Diff,
                                            MoveType = MoveType.DestroyObject,
                                            InteractObject = door,
                                            DestinationVoxel = n,
                                            SourceState = state
                                        });
                                    }
                                    blockedByObject = true;
                                }
                            }
                        }
                    }

                    // If no object blocked us, we can move freely as normal.
                    if (!blockedByObject && n.LiquidType != LiquidType.Lava)
                    {
                        MoveAction newAction = v;
                        newAction.SourceState      = state;
                        newAction.DestinationVoxel = n;
                        yield return(newAction);
                    }
                }
            }
        }
Exemplo n.º 8
0
        private IEnumerable <MoveAction> EnumerateSuccessors(
            MoveState state,
            VoxelHandle voxel,
            MoveActionTempStorage Storage,
            bool inWater,
            bool standingOnGround,
            bool topCovered,
            bool hasNeighbors)
        {
            bool isClimbing = false;

            if (state.VehicleType == VehicleTypes.Rail)
            {
                if (Can(MoveType.ExitVehicle)) // Possibly redundant... If they can ride they should be able to exit right?
                {
                    yield return(new MoveAction()
                    {
                        SourceState = state,
                        DestinationState = new MoveState()
                        {
                            VehicleType = VehicleTypes.None,
                            Voxel = state.Voxel
                        },
                        MoveType = MoveType.ExitVehicle,
                        Diff = new Vector3(1, 1, 1),
                        CostMultiplier = 1.0f
                    });
                }

                if (Can(MoveType.RideVehicle))
                {
                    foreach (var neighbor in Rail.RailHelper.EnumerateForwardNetworkConnections(state.PrevRail, state.Rail))
                    {
                        var neighborRail = Creature.Manager.FindComponent(neighbor) as Rail.RailEntity;
                        if (neighborRail == null || !neighborRail.Active)
                        {
                            continue;
                        }

                        yield return(new MoveAction()
                        {
                            SourceState = state,
                            DestinationState = new MoveState()
                            {
                                Voxel = neighborRail.GetContainingVoxel(),
                                Rail = neighborRail,
                                PrevRail = state.Rail,
                                VehicleType = VehicleTypes.Rail
                            },
                            MoveType = MoveType.RideVehicle,
                            CostMultiplier = 1.0f
                        });
                    }
                }

                yield break; // Nothing can be done without exiting the rails first.
            }

            if (CanClimb || Can(MoveType.RideVehicle))
            {
                //Climbing ladders and riding rails.

                var bodies = Storage.NeighborObjects.Where(o => o.GetBoundingBox().Intersects(voxel.GetBoundingBox()));

                // if the creature can climb objects and a ladder is in this voxel,
                // then add a climb action.
                if (CanClimb)
                {
                    var ladder = bodies.FirstOrDefault(component => component.Tags.Contains("Climbable"));

                    if (ladder != null)
                    {
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(1, 2, 1),
                            MoveType = MoveType.Climb,
                            InteractObject = ladder,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[1, 2, 1]
                        });

                        if (!standingOnGround)
                        {
                            yield return(new MoveAction
                            {
                                SourceState = state,
                                Diff = new Vector3(1, 0, 1),
                                MoveType = MoveType.Climb,
                                InteractObject = ladder,
                                CostMultiplier = 1.0f,
                                DestinationVoxel = Storage.Neighborhood[1, 2, 1]
                            });
                        }
                        standingOnGround = true;
                    }
                }

                if (Can(MoveType.RideVehicle))
                {
                    var rails = bodies.OfType <Rail.RailEntity>().Where(r => r.Active);

                    if (rails.Count() > 0 && Can(MoveType.RideVehicle))
                    {
                        {
                            foreach (var rail in rails)
                            {
                                if (rail.GetContainingVoxel() != state.Voxel)
                                {
                                    continue;
                                }


                                yield return(new MoveAction()
                                {
                                    SourceState = state,
                                    DestinationState = new MoveState()
                                    {
                                        VehicleType = VehicleTypes.Rail,
                                        Rail = rail,
                                        Voxel = rail.GetContainingVoxel()
                                    },
                                    MoveType = MoveType.EnterVehicle,
                                    Diff = new Vector3(1, 1, 1),
                                    CostMultiplier = 1.0f
                                });
                            }
                        }
                    }

                    var elevators = bodies.OfType <Elevators.ElevatorShaft>().Where(r => r.Active && System.Math.Abs(r.Position.Y - voxel.Center.Y) < 0.5f);

                    foreach (var elevator in elevators)
                    {
                        foreach (var elevatorExit in Elevators.Helper.EnumerateExits(elevator.Shaft))
                        {
                            if (object.ReferenceEquals(elevator, elevatorExit.ShaftSegment))
                            {
                                continue;                                                              // Ignore exits from the segment we are entering at.
                            }
                            yield return(new MoveAction()
                            {
                                SourceState = state,
                                DestinationState = new MoveState()
                                {
                                    Voxel = elevatorExit.OntoVoxel,
                                    VehicleType = VehicleTypes.None,
                                    Tag = new Elevators.ElevatorMoveState
                                    {
                                        Entrance = elevator,
                                        Exit = elevatorExit.ShaftSegment
                                    }
                                },
                                MoveType = MoveType.RideElevator,
                                CostMultiplier = elevator.GetQueueSize() + 1.0f
                            });
                        }
                    }
                }
            }

            // If the creature can fly and is not underwater, it can fly
            // to any adjacent empty cell.
            if (CanFly && !inWater)
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        for (int dy = 0; dy <= 2; dy++)
                        {
                            if (dx == 1 && dz == 1 && dy == 1)
                            {
                                continue;
                            }

                            if (Storage.Neighborhood[dx, dy, dz].IsValid && Storage.Neighborhood[dx, dy, dz].IsEmpty)
                            {
                                yield return(new MoveAction
                                {
                                    SourceState = state,
                                    Diff = new Vector3(dx, dy, dz),
                                    MoveType = MoveType.Fly,
                                    CostMultiplier = 1.0f,
                                    DestinationVoxel = Storage.Neighborhood[dx, dy, dz]
                                });
                            }
                        }
                    }
                }
            }

            // If the creature is not in water and is not standing on ground,
            // it can fall one voxel downward in free space.
            if (!inWater && !standingOnGround && Storage.Neighborhood[1, 0, 1].IsValid)
            {
                yield return(new MoveAction
                {
                    SourceState = state,
                    Diff = new Vector3(1, 0, 1),
                    MoveType = MoveType.Fall,
                    CostMultiplier = 1.0f,
                    DestinationVoxel = Storage.Neighborhood[1, 0, 1]
                });
            }

            // If the creature can climb walls and is not blocked by a voxl above.
            if (CanClimbWalls && !topCovered)
            {
                // This monstrosity is unrolling an inner loop so that we don't have to allocate an array or
                // enumerators.
                var wall = VoxelHandle.InvalidHandle;
                if (Storage.Neighborhood[2, 1, 1].IsValid && !Storage.Neighborhood[2, 1, 1].IsEmpty)
                {
                    wall = Storage.Neighborhood[2, 1, 1];
                }
                else if (Storage.Neighborhood[0, 1, 1].IsValid && !Storage.Neighborhood[0, 1, 1].IsEmpty)
                {
                    wall = Storage.Neighborhood[0, 1, 1];
                }
                else if (Storage.Neighborhood[1, 1, 2].IsValid && !Storage.Neighborhood[1, 1, 2].IsEmpty)
                {
                    wall = Storage.Neighborhood[1, 1, 2];
                }
                else if (Storage.Neighborhood[1, 1, 0].IsValid && !Storage.Neighborhood[1, 1, 0].IsEmpty)
                {
                    wall = Storage.Neighborhood[1, 1, 0];
                }

                if (wall.IsValid)
                {
                    isClimbing = true;

                    if (Storage.Neighborhood[1, 2, 1].IsValid)
                    {
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(1, 2, 1),
                            MoveType = MoveType.ClimbWalls,
                            ActionVoxel = wall,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[1, 2, 1]
                        });
                    }

                    if (!standingOnGround && Storage.Neighborhood[1, 0, 1].IsValid)
                    {
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(1, 0, 1),
                            MoveType = MoveType.ClimbWalls,
                            ActionVoxel = wall,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[1, 0, 1]
                        });
                    }
                }
            }

            // If the creature either can walk or is in water, add the
            // eight-connected free neighbors around the voxel.
            if ((CanWalk && standingOnGround) || (CanSwim && inWater))
            {
                // If the creature is in water, it can swim. Otherwise, it will walk.
                var moveType = inWater ? MoveType.Swim : MoveType.Walk;
                if (Storage.Neighborhood[0, 1, 1].IsValid && Storage.Neighborhood[0, 1, 1].IsEmpty)
                {
                    // +- x
                    yield return(new MoveAction
                    {
                        SourceState = state,
                        DestinationVoxel = Storage.Neighborhood[0, 1, 1],
                        Diff = new Vector3(0, 1, 1),
                        MoveType = moveType,
                        CostMultiplier = 1.0f
                    });
                }

                if (Storage.Neighborhood[2, 1, 1].IsValid && Storage.Neighborhood[2, 1, 1].IsEmpty)
                {
                    yield return(new MoveAction
                    {
                        SourceState = state,
                        Diff = new Vector3(2, 1, 1),
                        MoveType = moveType,
                        CostMultiplier = 1.0f,
                        DestinationVoxel = Storage.Neighborhood[2, 1, 1]
                    });
                }

                if (Storage.Neighborhood[1, 1, 0].IsValid && Storage.Neighborhood[1, 1, 0].IsEmpty)
                {
                    // +- z
                    yield return(new MoveAction
                    {
                        SourceState = state,
                        Diff = new Vector3(1, 1, 0),
                        MoveType = moveType,
                        CostMultiplier = 1.0f,
                        DestinationVoxel = Storage.Neighborhood[1, 1, 0]
                    });
                }

                if (Storage.Neighborhood[1, 1, 2].IsValid && Storage.Neighborhood[1, 1, 2].IsEmpty)
                {
                    yield return(new MoveAction
                    {
                        SourceState = state,
                        Diff = new Vector3(1, 1, 2),
                        MoveType = moveType,
                        CostMultiplier = 1.0f,
                        DestinationVoxel = Storage.Neighborhood[1, 1, 2]
                    });
                }

                // Only bother worrying about 8-connected movement if there are
                // no full neighbors around the voxel.
                if (!hasNeighbors)
                {
                    if (Storage.Neighborhood[2, 1, 2].IsValid && Storage.Neighborhood[2, 1, 2].IsEmpty)
                    {
                        // +x + z
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(2, 1, 2),
                            MoveType = moveType,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[2, 1, 2]
                        });
                    }

                    if (Storage.Neighborhood[2, 1, 0].IsValid && Storage.Neighborhood[2, 1, 0].IsEmpty)
                    {
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(2, 1, 0),
                            MoveType = moveType,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[2, 1, 0]
                        });
                    }

                    if (Storage.Neighborhood[0, 1, 2].IsValid && Storage.Neighborhood[0, 1, 2].IsEmpty)
                    {
                        // -x -z
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(0, 1, 2),
                            MoveType = moveType,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[0, 1, 2]
                        });
                    }

                    if (Storage.Neighborhood[0, 1, 0].IsValid && Storage.Neighborhood[0, 1, 0].IsEmpty)
                    {
                        yield return(new MoveAction
                        {
                            SourceState = state,
                            Diff = new Vector3(0, 1, 0),
                            MoveType = moveType,
                            CostMultiplier = 1.0f,
                            DestinationVoxel = Storage.Neighborhood[0, 1, 0]
                        });
                    }
                }
            }

            // If the creature's head is free, and it is standing on ground,
            // or if it is in water, or if it is climbing, it can also jump
            // to voxels that are 1 cell away and 1 cell up.
            if (!topCovered && (standingOnGround || (CanSwim && inWater) || isClimbing))
            {
                for (int dx = 0; dx <= 2; dx++)
                {
                    for (int dz = 0; dz <= 2; dz++)
                    {
                        if (dx == 1 && dz == 1)
                        {
                            continue;
                        }

                        if (Storage.Neighborhood[dx, 1, dz].IsValid && !Storage.Neighborhood[dx, 1, dz].IsEmpty)
                        {
                            // Check to see if there is headspace for a higher jump.

                            //var highAbove = state.Voxel.Chunk.Manager.CreateVoxelHandle(Storage.Neighborhood[dx, 1, dz].Coordinate + new GlobalVoxelOffset(0, 2, 0));
                            //if (highAbove.IsValid && highAbove.IsEmpty)
                            //    yield return new MoveAction
                            //    {
                            //        SourceState = state,
                            //        Diff = new Vector3(dx, 2, dz),
                            //        MoveType = MoveType.HighJump,
                            //        DestinationVoxel = Storage.Neighborhood[dx, 2, dz],
                            //        CostMultiplier = 1.0f
                            //    };
                            //else
                            yield return(new MoveAction
                            {
                                SourceState = state,
                                Diff = new Vector3(dx, 2, dz),
                                MoveType = MoveType.Jump,
                                DestinationVoxel = Storage.Neighborhood[dx, 2, dz],
                                CostMultiplier = 1.0f
                            });
                        }
                    }
                }
            }

            /*
             * if (CanDig)
             * {
             *  // This loop is unrolled for speed. It gets the manhattan neighbors and tells the creature that it can mine
             *  // the surrounding rock to get through.
             *  VoxelHandle neighbor = Storage.Neighborhood[0, 1, 1];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(0, 1, 1),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             *
             *  neighbor = Storage.Neighborhood[2, 1, 1];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(2, 1, 1),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             *
             *  neighbor = Storage.Neighborhood[1, 1, 2];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(1, 1, 2),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             *
             *  neighbor = Storage.Neighborhood[1, 1, 0];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(1, 1, 0),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             *
             *  neighbor = Storage.Neighborhood[1, 2, 1];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(1, 2, 1),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             *
             *  neighbor = Storage.Neighborhood[1, 0, 1];
             *  if (neighbor.IsValid && !neighbor.IsEmpty && (!IsDwarf || !neighbor.IsPlayerBuilt))
             *  {
             *      yield return (new MoveAction
             *      {
             *          SourceState = state,
             *          Diff = new Vector3(1, 0, 1),
             *          MoveType = MoveType.Dig,
             *          DestinationVoxel = neighbor,
             *          CostMultiplier = 1.0f
             *      });
             *  }
             * }
             */
        }
Exemplo n.º 9
0
        public IEnumerable <Status> FindRandomPath()
        {
            var target = MathFunctions.RandVector3Cube() * Radius + Creature.AI.Position;

            if (Creature.AI.PositionConstraint.Contains(target) == ContainmentType.Disjoint)
            {
                target = MathFunctions.RandVector3Box(Creature.AI.PositionConstraint);
            }
            if (Is2D)
            {
                target.Y = Creature.AI.Position.Y;
            }

            var path              = new List <MoveAction>();
            var curr              = Creature.Physics.CurrentVoxel;
            var bodies            = Agent.World.PlayerFaction.OwnedObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();
            var storage           = new MoveActionTempStorage();
            var previousMoveState = new MoveState {
                Voxel = curr
            };

            for (int i = 0; i < PathLength; i++)
            {
                var actions = Creature.AI.Movement.GetMoveActions(previousMoveState, bodies, storage);

                MoveAction?bestAction = null;
                var        bestDist   = float.MaxValue;

                foreach (MoveAction action in actions)
                {
                    if (Is2D && (action.MoveType == MoveType.Climb || action.MoveType == MoveType.ClimbWalls || action.MoveType == MoveType.Fall))
                    {
                        continue;
                    }

                    float dist = (action.DestinationVoxel.WorldPosition - target).LengthSquared() * Creature.AI.Movement.Cost(action.MoveType);

                    if (dist < bestDist && !path.Any(a => a.DestinationVoxel == action.DestinationVoxel))
                    {
                        bestDist   = dist;
                        bestAction = action;
                    }
                }

                if (bestAction.HasValue &&
                    !path.Any(p => p.DestinationVoxel.Equals(bestAction.Value.DestinationVoxel) && p.MoveType == bestAction.Value.MoveType &&
                              Creature.AI.PositionConstraint.Contains(bestAction.Value.DestinationVoxel.WorldPosition + Vector3.One * 0.5f) == ContainmentType.Contains))
                {
                    MoveAction action = bestAction.Value;
                    path.Add(action);
                    previousMoveState = action.DestinationState;
                }
                else
                {
                    break;
                }
            }

            if (path.Count > 0)
            {
                Creature.AI.Blackboard.SetData("RandomPath", path);
                yield return(Status.Success);
            }
            else
            {
                yield return(Status.Fail);
            }
        }
Exemplo n.º 10
0
        /// <summary>
        ///     Creates a path from the start voxel to some goal region, returning a list of movements that can
        ///     take a mover from the start voxel to the goal region.
        /// </summary>
        /// <param name="mover">The agent that we want to find a path for.</param>
        /// <param name="startVoxel"></param>
        /// <param name="goal">Goal conditions that the agent is trying to satisfy.</param>
        /// <param name="chunks">The voxels that the agent is moving through</param>
        /// <param name="maxExpansions">Maximum number of voxels to consider before giving up.</param>
        /// <param name="toReturn">The path of movements that the mover should take to reach the goal.</param>
        /// <param name="weight">
        ///     A heuristic weight to apply to the planner. If 1.0, the path is garunteed to be optimal. Higher values
        ///     usually result in faster plans that are suboptimal.
        /// </param>
        /// <param name="continueFunc"></param>
        /// <returns>True if a path could be found, or false otherwise.</returns>
        private static PlanResult Path(
            CreatureMovement mover,
            VoxelHandle startVoxel,
            GoalRegion goal,
            ChunkManager chunks,
            int maxExpansions,
            ref List <MoveAction> toReturn,
            float weight,
            Func <bool> continueFunc)
        {
            // Create a local clone of the octree, using only the objects belonging to the player.
            var octree = new OctTreeNode <GameComponent>(mover.Creature.World.ChunkManager.Bounds.Min, mover.Creature.World.ChunkManager.Bounds.Max);

            List <GameComponent> playerObjects   = new List <GameComponent>(mover.Creature.World.PlayerFaction.OwnedObjects);
            List <GameComponent> teleportObjects = playerObjects.Where(o => o.Tags.Contains("Teleporter")).ToList();

            foreach (var obj in playerObjects)
            {
                octree.Add(obj, obj.GetBoundingBox());
            }

            var storage = new MoveActionTempStorage();

            var start = new MoveState()
            {
                Voxel = startVoxel
            };

            var startTime = DwarfTime.Tick();

            if (mover.IsSessile)
            {
                return(new PlanResult()
                {
                    Expansions = 0,
                    Result = PlanResultCode.Invalid,
                    TimeSeconds = DwarfTime.Tock(startTime)
                });
            }

            // Sometimes a goal may not even be achievable a.priori. If this is true, we know there can't be a path
            // which satisifies that goal.
            if (!goal.IsPossible())
            {
                toReturn = null;
                return(new PlanResult()
                {
                    Expansions = 0,
                    Result = PlanResultCode.Invalid,
                    TimeSeconds = DwarfTime.Tock(startTime)
                });
            }

            // Voxels that have already been explored.
            var closedSet = new HashSet <MoveState>();

            // Voxels which should be explored.
            var openSet = new HashSet <MoveState>
            {
                start
            };

            // Dictionary of voxels to the optimal action that got the mover to that voxel.
            var cameFrom = new Dictionary <MoveState, MoveAction>();

            // Optimal score of a voxel based on the path it took to get there.
            var gScore = new Dictionary <MoveState, float>();

            // Expansion priority of voxels.
            var fScore = new PriorityQueue <MoveState>();

            // Starting conditions of the search.
            gScore[start] = 0.0f;
            fScore.Enqueue(start, gScore[start] + weight * goal.Heuristic(start.Voxel));

            // Keep count of the number of expansions we've taken to get to the goal.
            int numExpansions = 0;

            // Check the voxels adjacent to the current voxel as a quick test of adjacency to the goal.
            //var manhattanNeighbors = new List<VoxelHandle>(6);
            //for (int i = 0; i < 6; i++)
            //{
            //    manhattanNeighbors.Add(new VoxelHandle());
            //}

            // Loop until we've either checked every possible voxel, or we've exceeded the maximum number of
            // expansions.
            while (openSet.Count > 0 && numExpansions < maxExpansions)
            {
                if (numExpansions % 10 == 0 && !continueFunc())
                {
                    return new PlanResult
                           {
                               Result      = PlanResultCode.Cancelled,
                               Expansions  = numExpansions,
                               TimeSeconds = DwarfTime.Tock(startTime)
                           }
                }
                ;


                // Check the next voxel to explore.
                var current = GetStateWithMinimumFScore(fScore);
                if (!current.IsValid)
                {
                    // If there wasn't a voxel to explore, just try to expand from
                    // the start again.
                    numExpansions++;

                    continue;
                }

                numExpansions++;

                // If we've reached the goal already, reconstruct the path from the start to the
                // goal.


                if (goal.IsInGoalRegion(current.Voxel) && cameFrom.ContainsKey(current))
                {
                    toReturn = ReconstructPath(cameFrom, cameFrom[current], start);
                    return(new PlanResult()
                    {
                        Result = PlanResultCode.Success,
                        Expansions = numExpansions,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }

                // We've already considered the voxel, so add it to the closed set.
                openSet.Remove(current);
                closedSet.Add(current);

                // Get the voxels that can be moved to from the current voxel.
                var neighbors = mover.GetMoveActions(current, teleportObjects, storage).ToList();


                var foundGoalAdjacent = neighbors.FirstOrDefault(n => n.DestinationState.VehicleType == VehicleTypes.None && goal.IsInGoalRegion(n.DestinationState.Voxel));

                // A quick test to see if we're already adjacent to the goal. If we are, assume
                // that we can just walk to it.
                if (foundGoalAdjacent.DestinationState.IsValid && foundGoalAdjacent.SourceState.IsValid)
                {
                    if (cameFrom.ContainsKey(current))
                    {
                        toReturn = ReconstructPath(cameFrom, foundGoalAdjacent, start);
                        return(new PlanResult()
                        {
                            Result = PlanResultCode.Success,
                            Expansions = numExpansions,
                            TimeSeconds = DwarfTime.Tock(startTime)
                        });
                    }
                }

                // Otherwise, consider all of the neighbors of the current voxel that can be moved to,
                // and determine how to add them to the list of expansions.
                foreach (MoveAction n in neighbors)
                {
                    // If we've already explored that voxel, don't explore it again.
                    if (closedSet.Contains(n.DestinationState))
                    {
                        continue;
                    }

                    // Otherwise, consider the case of moving to that neighbor.
                    float tenativeGScore = gScore[current] + GetDistance(current.Voxel, n.DestinationState.Voxel, n.MoveType, mover) * n.CostMultiplier;

                    // IF the neighbor can already be reached more efficiently, ignore it.
                    if (openSet.Contains(n.DestinationState) && !(tenativeGScore < gScore[n.DestinationState]))
                    {
                        continue;
                    }

                    // Otherwise, add it to the list of voxels for consideration.
                    openSet.Add(n.DestinationState);

                    // Add an edge to the voxel from the current voxel.
                    var cameAction = n;
                    cameFrom[n.DestinationState] = cameAction;

                    // Update the expansion scores for the next voxel.
                    gScore[n.DestinationState] = tenativeGScore;
                    fScore.Enqueue(n.DestinationState, gScore[n.DestinationState] + weight * (goal.Heuristic(n.DestinationState.Voxel) + (n.DestinationState.VehicleType == VehicleTypes.None ? 100.0f : 0.0f)));
                }

                // If we've expanded too many voxels, just give up.
                if (numExpansions >= maxExpansions)
                {
                    return(new PlanResult()
                    {
                        Expansions = numExpansions,
                        Result = PlanResultCode.MaxExpansionsReached,
                        TimeSeconds = DwarfTime.Tock(startTime)
                    });
                }
            }

            // Somehow we've reached this code without having found a path. Return false.
            toReturn = null;
            return(new PlanResult()
            {
                Expansions = numExpansions,
                Result = PlanResultCode.NoSolution,
                TimeSeconds = DwarfTime.Tock(startTime)
            });
        }