public MyGuiScreenEditorWaypoint(MyWayPoint waypoint)
     : base(null, new Vector2(0.5f, 0.5f), MyGuiConstants.SCREEN_BACKGROUND_COLOR, null, MyTextsWrapperEnum.WayPoint)
 {
     m_waypoints = new List<MyWayPoint>();
     m_waypoints.Add(waypoint);
     Init();
 }
 public MyGuiScreenEditorWaypoint(MyWayPoint waypoint)
     : base(null, new Vector2(0.5f, 0.5f), MyGuiConstants.SCREEN_BACKGROUND_COLOR, null, MyTextsWrapperEnum.WayPoint)
 {
     m_waypoints = new List <MyWayPoint>();
     m_waypoints.Add(waypoint);
     Init();
 }
Example #3
0
 // Add a new vertex to the graph. Return true if the vertex was successfully added.
 // If you also want to add it into the world (MyEntities), use CreateWaypoint instead.
 public static bool AddVertex(MyWayPoint v)
 {
     MakeConnectedComponentsDirty();
     using (VerticesLock.AcquireExclusiveUsing())
     {
         System.Diagnostics.Debug.Assert(readingVertices == false);
         return m_vertices.Add(v);
     }
 }
        /// <summary>
        /// Create entities from action object builders
        /// </summary>
        void AddOrCreate()
        {
            MyEditorGizmo.ClearSelection();

            // Once entities has been created in this action, they remain and if needed, are only removed/added to scene
            if (ActionEntities != null && ActionEntities.Count > 0)
            {
                foreach (MyEntity actionEntity in ActionEntities)
                {
                    AddToScene(actionEntity);
                }
            }
            else
            {
                // If no ActionEntites are present, create them from provided object builders
                foreach (ObjectBuilderCreate crate in ActionObjectBuilders)
                {
                    CreateFromObjectBuilder(crate.ObjectBuilder, crate.Matrix, crate.ScreenPosition);
                }
            }

            // Link the new entities and clean up waypoint vertices
            foreach (var e in ActionEntities)
            {
                e.Link();
            }
            MyWayPointGraph.DeleteNullVerticesFromPaths();

            // When copying a single waypoint, connect it to its source
            if (this is MyEditorActionEntityCopy && ActionEntities.Count == 1 && ActionEntities[0] is MyWayPoint)
            {
                var source = (this as MyEditorActionEntityCopy).SourceEntities[0] as MyWayPoint;
                if (source != null)
                {
                    MyWayPoint.Connect(source, ActionEntities[0] as MyWayPoint);
                }
            }

            // When copying prefabs, connect snap points connections
            if (this is MyEditorActionEntityCopy)
            {
                MyEditor.Static.CopySnapPointLinks((this as MyEditorActionEntityCopy).SourceEntities, (this as MyEditorActionEntityCopy).RemapContext);
            }

            MyEditor.Static.IssueCheckAllCollidingObjects();
        }
Example #5
0
        // Remove a vertex and all of its edges. Return true if the vertex was successfully removed from the graph.
        // Note that this function doesn't remove the vertex from the world (MyEntities): use MyWayPoint.Close for that.
        public static bool RemoveVertex(MyWayPoint v)
        {
            MakeConnectedComponentsDirty();
            v.DisconnectFromAllNeighbors();

            // delete vertex from all paths
            foreach (var path in StoredPaths)
                if (path.WayPoints.Contains(v))
                    path.WayPoints.Remove(v);
            RemovePathsWithZeroVertices();

            using (VerticesLock.AcquireExclusiveUsing())
            {
                System.Diagnostics.Debug.Assert(readingVertices == false);
                return m_vertices.Remove(v);
            }
        }
        private void UpdateBlockedEdges()
        {
            if (IsWorking())
            {
                foreach (var edge in m_edges)
                {
                    MyWayPoint.RemoveBlockedEdgesForBots(edge);
                    MyWayPoint.RemoveBlockedEdgesForPlayer(edge);
                }
            }
            else
            {
                foreach (var edge in m_edges)
                {
                    MyWayPoint.AddBlockedEdgesForBots(edge);

                    if (!IsDestructible)
                    {
                        bool isDestructible = false;
                        foreach (var par in m_parts)
                        {
                            if (par != null && par.IsDestructible)
                            {
                                isDestructible = true;
                                break;
                            }
                        }

                        if (!isDestructible)
                        {
                            MyWayPoint.AddBlockedEdgesForPlayer(edge);
                        }
                    }
                }
            }
        }
Example #7
0
 public bool ContainsEdge(MyWayPoint v, MyWayPoint w)
 {
     using (MyEntities.EntityCloseLock.AcquireSharedUsing())
     {
         for (int i = 0; i < WayPoints.Count - 1; i++)
         {
             var subpath = WayPoints[i].GetShortestPathTo(WayPoints[i + 1]);
             for (int j = 0; j < subpath.Count - 1; j++)
                 if ((subpath[j] == v && subpath[j + 1] == w) || (subpath[j] == w && subpath[j + 1] == v))
                     return true;
         }
     }
     return false;
 }
Example #8
0
 public void SetWaypointPath(string name)
 {
     CurrentWaypoint = null;
     WaypointPath = MyWayPointGraph.GetPath(name);
     
     if (WaypointPath != null && WaypointPath.WayPoints.Count > 0)
     {
         CurrentWaypoint = WaypointPath.WayPoints[0];
     }
 }
Example #9
0
        private bool FindPathBetweenWaypoints(
            List<MyWayPoint> closestVisibleWaypoints,
            MyWayPoint goal,
            Dictionary<MyWayPoint, bool> visibleFromStartPosCache,
            HashSet<Tuple<MyWayPoint, MyWayPoint>> blockedEdges,
            HashSet<Tuple<MyWayPoint, MyWayPoint>> unblockedEdges
        )
        {
            // find the best path candidate
            float shortestPathLength = float.MaxValue;
            int retryCount = 0;

            for (int j = 0; j < closestVisibleWaypoints.Count && retryCount < 30; j++)  // max retry count is 30
            {
                var path = closestVisibleWaypoints[j].GetShortestPathTo(goal, blockedEdges, true, false);
                if (path.Count == 0) continue;

                // optimize the path: try to delete waypoints from the start of the path (if the next waypoints are visible)
                int farthestVisibleWaypointInPath = 0;

                for (int i = Math.Min(path.Count - 1, 20); i > 0; i--)  // path optimization: max 20 raycasts per path candidate, reuse previous results
                    if (path[i].IsVisibleFrom(m_startPos, m_goalEntity, visibleFromStartPosCache))
                    {
                        farthestVisibleWaypointInPath = i;
                        break;
                    }

                // compute the length of the path candidate
                float length = Vector3.Distance(m_startPos, path[farthestVisibleWaypointInPath].WorldMatrix.Translation) + Vector3.Distance(path[path.Count - 1].WorldMatrix.Translation, m_goalPos);
                for (int i = farthestVisibleWaypointInPath; i < path.Count - 1; i++)
                    length += Vector3.Distance(path[i].WorldMatrix.Translation, path[i + 1].WorldMatrix.Translation);

                // if it's the shortest path candidate yet, make it the new GPS path
                if (length < shortestPathLength)
                {
                    // but first check that the edges are free of any obstructions (and remember it)
                    bool pathBlocked = false;
                    for (int i = farthestVisibleWaypointInPath; i < path.Count - 2; i++)
                    {
                        // assume that edges between non-generated waypoints are always ok
                        if (path[i].Save && path[i + 1].Save)
                            continue;

                        var tuple = Tuple.Create(path[i], path[i + 1]);
                        if (unblockedEdges.Contains(tuple))  // already tested and it was ok
                        {
                        }
                        else if (path[i + 1].IsVisibleFrom(path[i].Position, m_goalEntity))
                        {
                            unblockedEdges.Add(tuple);
                            unblockedEdges.Add(Tuple.Create(path[i + 1], path[i]));
                        }
                        else
                        {
                            blockedEdges.Add(tuple);
                            blockedEdges.Add(Tuple.Create(path[i + 1], path[i]));
                            pathBlocked = true;
                            break;
                        }
                    }
                    if (pathBlocked)
                    {
                        j--;  // retry current waypoint with updated cache of blocked edges
                        retryCount++;
                        continue;
                    }

                    // seems legit
                    shortestPathLength = length;
                    Path = new List<Vector3>();
                    Path.Add(m_startPos);
                    for (int i = farthestVisibleWaypointInPath; i < path.Count; i++) Path.Add(path[i].WorldMatrix.Translation);
                    Path.Add(m_goalPos);
                }
            }

            if (Path.Count != 0)
            {
                Message = new StringBuilder().AppendFormat(MyTextsWrapper.Get(MyTextsWrapperEnum.GPSDistance).ToString(), shortestPathLength);
                return true;
            }
            else
            {
                return false;
            }
        }
        public static Matrix UpdateShapePosition()
        {
            if (DetachedVoxelHand != null)
            {
                VoxelHandShape.MoveAndRotate(DetachedVoxelHand.WorldMatrix.Translation, DetachedVoxelHand.WorldMatrix);
                return(DetachedVoxelHand.WorldMatrix);
            }

            Matrix world = Matrix.Identity;

            float   minDist = 2 * VoxelHandShape.LocalVolume.Radius;
            float   dist    = 2 * minDist;
            Vector3 from    = MyCamera.Position - MyCamera.UpVector * minDist * 0.5f;

            if (IsProjected)
            {
                if (!MyFakes.MWBUILDER)
                {
                    var line = new MyLine(from, from + MyCamera.ForwardVector * 10000, true);
                    var hit  = MyEntities.GetIntersectionWithLine_IgnoreOtherThanSpecifiedClass(ref line, new System.Type[] { typeof(MyVoxelMap) });
                    if (hit != null)
                    {
                        dist = Vector3.Distance(MyCamera.Position, hit.Value.IntersectionPointInWorldSpace);
                    }
                    else
                    {
                        dist = 5000;
                    }

                    m_conePosition = from + MyCamera.ForwardVector * minDist * 0.7f;
                    Vector3 shapePosition = from + MyCamera.ForwardVector * (dist + VoxelHandShape.LocalVolume.Radius * m_distance * 2);
                    Vector3 shapeForward  = Vector3.Normalize(MyCamera.UpVector * minDist * 0.5f + shapePosition - from);
                    Vector3 shapeUp       = shapeForward - MyCamera.ForwardVector + MyCamera.UpVector;
                    world = Matrix.CreateWorld(shapePosition, shapeForward, shapeUp);
                    VoxelHandShape.MoveAndRotate(shapePosition, world);
                    return(world);
                }
                else
                {
                    var     line   = new MyLine(from, from + MyCamera.ForwardVector * 10000, true);
                    var     hit    = MyEntities.GetIntersectionWithLine_IgnoreOtherThanSpecifiedClass(ref line, new System.Type[] { typeof(MyVoxelMap) });
                    Vector3 normal = Vector3.Up;
                    dist = 5000;
                    Vector3 shapePosition = from + MyCamera.ForwardVector * dist;
                    if (hit != null)
                    {
                        dist          = Vector3.Distance(MyCamera.Position, hit.Value.IntersectionPointInWorldSpace);
                        normal        = hit.Value.NormalInWorldSpace;
                        shapePosition = hit.Value.IntersectionPointInWorldSpace;
                    }


                    m_conePosition = from + MyCamera.ForwardVector * minDist * 0.7f;

                    Vector3 shapeUp      = normal;
                    Vector3 shapeForward = Vector3.Cross(-MyCamera.LeftVector, shapeUp);
                    float   dot          = Vector3.Dot(shapeUp, shapeForward);
                    if ((dot > 0.9f) || (dot < -0.9f))
                    {
                        shapeForward = Vector3.Forward;
                    }

                    shapePosition.X = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.X / MyEditorGrid.GetGridStepInMeters());
                    shapePosition.Y = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.Y / MyEditorGrid.GetGridStepInMeters());
                    shapePosition.Z = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.Z / MyEditorGrid.GetGridStepInMeters());


                    world = Matrix.CreateWorld(shapePosition, shapeForward, shapeUp);
                    VoxelHandShape.MoveAndRotate(shapePosition, world);
                    return(world);
                }
            }
            else if (IsProjectedToWaypoints)
            {
                //Lets find projection on closest collision with waypoint edge
                from           = MyCamera.Position - MyCamera.UpVector * 10.5f;
                m_conePosition = from + MyCamera.ForwardVector * 10.7f;
                Vector3 shapePosition = from + MyCamera.ForwardVector * m_distance;

                List <Tuple <MyWayPoint, MyWayPoint> > edges = MyWayPointGraph.GetAllEdgesInSphere(shapePosition, VoxelHandShape.LocalVolume.Radius * 2);

                Tuple <MyWayPoint, MyWayPoint> closestEdge = null;
                float   minDistance           = float.MaxValue;
                Vector3 closestPoint          = shapePosition;
                float   distFromFirstWaypoint = 0;

                foreach (Tuple <MyWayPoint, MyWayPoint> edge in edges)
                {
                    Vector3 linePos1 = edge.Item1.Position;
                    Vector3 linePos2 = edge.Item2.Position;

                    Vector3 point = MyUtils.GetClosestPointOnLine(ref linePos1, ref linePos2, ref shapePosition, out distFromFirstWaypoint);

                    float distance = Vector3.Distance(shapePosition, point);
                    if (distance < minDistance)
                    {
                        minDistance  = distance;
                        closestEdge  = edge;
                        closestPoint = point;
                    }
                }

                if (closestEdge != null)
                {
                    shapePosition = closestPoint;

                    Vector3 shapeForward = Vector3.Normalize(shapePosition - from);
                    Vector3 shapeUp      = MyCamera.UpVector;
                    world = Matrix.CreateWorld(shapePosition, shapeForward, shapeUp);
                    VoxelHandShape.MoveAndRotate(shapePosition, world);

                    MyWayPoint firstWaypoint  = null;
                    MyWayPoint secondWaypoint = null;
                    float      edgeDistance   = Vector3.Distance(closestEdge.Item1.Position, closestEdge.Item2.Position);

                    if (closestEdge.Item1.Position.Y < closestEdge.Item2.Position.Y)
                    {
                        firstWaypoint  = closestEdge.Item1;
                        secondWaypoint = closestEdge.Item2;
                    }
                    else
                    {
                        firstWaypoint         = closestEdge.Item2;
                        secondWaypoint        = closestEdge.Item1;
                        distFromFirstWaypoint = edgeDistance - distFromFirstWaypoint;
                    }

                    float edgeRatio = edgeDistance > 0 ? distFromFirstWaypoint / edgeDistance : 0;

                    Quaternion quaternion1 = Quaternion.CreateFromRotationMatrix(closestEdge.Item1.WorldMatrix);
                    Quaternion quaternion2 = Quaternion.CreateFromRotationMatrix(closestEdge.Item2.WorldMatrix);

                    Quaternion resultQuaternion = Quaternion.Lerp(quaternion1, quaternion2, edgeRatio);

                    Matrix resultMatrix = Matrix.CreateFromQuaternion(resultQuaternion);
                    resultMatrix.Translation = shapePosition;

                    VoxelHandShape.MoveAndRotate(shapePosition, resultMatrix);

                    return(resultMatrix);
                }
            }

            if (MyFakes.MWBUILDER)
            {
                from           = MyCamera.Position;
                m_conePosition = from + MyCamera.ForwardVector * 10.7f;

                /*
                 * //Vector3 planeNormal = new Vector3(MyCamera.ForwardVector.X, 0, MyCamera.ForwardVector.Z);
                 * Vector3 planeNormal = new Vector3(0, MyCamera.ForwardVector.Y, MyCamera.ForwardVector.Z);
                 *
                 *
                 * planeNormal.Normalize();
                 * Vector3 planePoint = planePoint = from + planeNormal * m_distance;
                 * planeNormal = -planeNormal;
                 *
                 * Plane plane = new Plane(planeNormal, -Vector3.Dot(planeNormal, planePoint));
                 *
                 * Ray r = new Ray(from, MyCamera.ForwardVector);
                 * float? intr = r.Intersects(plane); */
                // if (intr.HasValue)
                {
                    Vector3 shapePosition = from + MyCamera.ForwardVector * m_distance;
                    Vector3 shapeForward  = Vector3.Forward;
                    Vector3 shapeUp       = Vector3.Up;

                    shapePosition.X = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.X / MyEditorGrid.GetGridStepInMeters());
                    shapePosition.Y = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.Y / MyEditorGrid.GetGridStepInMeters());
                    shapePosition.Z = MyEditorGrid.GetGridStepInMeters() *
                                      (float)Math.Round(shapePosition.Z / MyEditorGrid.GetGridStepInMeters());

                    world = Matrix.CreateWorld(shapePosition, shapeForward, shapeUp);
                    VoxelHandShape.MoveAndRotate(shapePosition, world);
                }
            }
            else
            {
                from           = MyCamera.Position - MyCamera.UpVector * 10.5f;
                m_conePosition = from + MyCamera.ForwardVector * 10.7f;
                Vector3 shapePosition = from + MyCamera.ForwardVector * m_distance;
                Vector3 shapeForward  = Vector3.Normalize(/*MyCamera.UpVector * minDist * 0.5f*/ shapePosition - from);
                Vector3 shapeUp       = /*shapeForward - MyCamera.ForwardVector +*/ MyCamera.UpVector;
                world = Matrix.CreateWorld(shapePosition, shapeForward, shapeUp);
                VoxelHandShape.MoveAndRotate(shapePosition, world);
            }

            return(world);
        }
Example #11
0
        /// <summary>
        /// Create and connect waypoints to enable navigation outside prefab containers.
        /// Needs to be called from the main thread (because it uses MyEntities.GetSafeIterationHelperForAll).
        /// </summary>
        public static void RecreateWaypointsAroundMadelyn()
        {
            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("RecreateWaypointsAroundMadelyn");

            // counters for debugging
            int largeObjects = 0;
            int totalWaypointsOutside = 0;
            int bigSubdivisions = 0;
            int closed = 0;

            var envelopes = new List<MyWayPoint[, ,]>();
            var envelopeEntity = new List<MyEntity>();
            var envelopeBvh = new MyDynamicAABBTree(MyConstants.GAME_PRUNING_STRUCTURE_AABB_EXTENSION);

            var nonFree = new HashSet<MyWayPoint>();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("create envelope");

            int madelynsBox = -1;
            // create envelopes
            {
                var entity = MyEntities.GetEntityByName("Madelyn");

                entity.UpdateAABBHr();
                BoundingBox box = entity.WorldAABBHr;
                if (box.Max - box.Min == Vector3.Zero)
                    box = entity.WorldAABB;

                // enlarge by 1% and 15 meters on each side
                BoundingBox extrudedBox = new BoundingBox(box.Min - (box.Max - box.Min) * 0.01f - new Vector3(15, 15, 15), box.Max + (box.Max - box.Min) * 0.01f + new Vector3(15, 15, 15));

                var waypointsOutside = new HashSet<MyWayPoint>();

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("find crossing");
                // add all edges that cross the non-extruded box from inside to outside (remember out-vertices)
                foreach (var waypoint in MyGamePruningStructure.GetAllEntitiesInBox(ref extrudedBox, MyGamePruningStructure.QueryFlags.Waypoints))
                {
                    var v = waypoint as MyWayPoint;
                    if (!v.Save) continue;
                    nonFree.Add(v);
                    using (MyWayPoint.NeighborsLock.AcquireSharedUsing())
                    {
                        foreach (var n in v.Neighbors)
                            if (n.Save && extrudedBox.Contains(n.Position) != ContainmentType.Contains)
                            {
                                if (waypointsOutside.Add(n)) totalWaypointsOutside++;
                                nonFree.Add(n);
                            }
                    }
                }
                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

                // create envelope
                int s = 1;
                if (waypointsOutside.Count > 0 || entity as MyStaticAsteroid == null)  // voxel maps and prefabs are automatically subdivided more
                {
                    s = 2;
                    bigSubdivisions++;
                }
                MyWayPoint[, ,] envelope = new MyWayPoint[s + 1, s + 1, s + 1];

                for (int i = 0; i <= s; i++) for (int j = 0; j <= s; j++) for (int k = 0; k <= s; k++)
                {
                    if (s == 2 && i == 1 && j == 1 && k == 1) continue;
                    envelope[i, j, k] = CreateWaypoint(new Vector3(
                        extrudedBox.Min.X + i * (extrudedBox.Max.X - extrudedBox.Min.X) / s,
                        extrudedBox.Min.Y + j * (extrudedBox.Max.Y - extrudedBox.Min.Y) / s,
                        extrudedBox.Min.Z + k * (extrudedBox.Max.Z - extrudedBox.Min.Z) / s
                    ), null);
                    envelope[i, j, k].Save = false;  // don't save generated waypoints
                    nonFree.Add(envelope[i, j, k]);

                    // assume Madelyn's envelope has no blockers
                    if (i != 0) if (!(s == 2 && i - 1 == 1 && j == 1 && k == 1)) MyWayPoint.Connect(envelope[i, j, k], envelope[i - 1, j, k]);
                    if (j != 0) if (!(s == 2 && j - 1 == 1 && i == 1 && k == 1)) MyWayPoint.Connect(envelope[i, j, k], envelope[i, j - 1, k]);
                    if (k != 0) if (!(s == 2 && k - 1 == 1 && j == 1 && i == 1)) MyWayPoint.Connect(envelope[i, j, k], envelope[i, j, k - 1]);

                    // if it's a part of a face that faces an out-vertex, connect it
                    foreach (var v in waypointsOutside)
                        if ((i == 0 && v.Position.X <= envelope[i, j, k].Position.X) ||
                            (i == s && v.Position.X >= envelope[i, j, k].Position.X) ||
                            (j == 0 && v.Position.Y <= envelope[i, j, k].Position.Y) ||
                            (j == s && v.Position.Y >= envelope[i, j, k].Position.Y) ||
                            (k == 0 && v.Position.Z <= envelope[i, j, k].Position.Z) ||
                            (k == s && v.Position.Z >= envelope[i, j, k].Position.Z)
                        )
                        {
                            MyWayPoint.Connect(v, envelope[i, j, k]);
                        }
                }

                envelopes.Add(envelope);
                envelopeEntity.Add(entity);
                envelopeBvh.AddProxy(ref extrudedBox, envelopes.Count - 1, 0);
                largeObjects++;

                madelynsBox = envelopes.Count - 1;
            }

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("disconnect from old waypoints");
            var madelynWaypoints = new HashSet<MyWayPoint>();
            {
                var entity = MyEntities.GetEntityByName("Madelyn");

                foreach (var child in entity.Children)
                {
                    var w = child as MyWayPoint;
                    if (w == null) continue;
                    madelynWaypoints.Add(w);
                }
                foreach (var v in madelynWaypoints)
                {
                    var outsiders = new List<MyWayPoint>();
                    foreach (var n in v.Neighbors)
                        if (!madelynWaypoints.Contains(n)) outsiders.Add(n);
                    foreach (var n in outsiders)
                        MyWayPoint.Disconnect(v, n);
                }
            }

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("connect to new surrounding waypoints");

            for (int eIndex = 0; eIndex < envelopes.Count; eIndex++)
            {
                var e = envelopes[eIndex];
                int es = e.GetLength(0) - 1;
                var eCenter = 0.5f * (e[0, 0, 0].Position + e[es, es, es].Position);

                // connect Madelyn's inner waypoints to waypoints around her
                if (eIndex == madelynsBox)
                {
                    MyEntity madelyn = envelopeEntity[madelynsBox];

                    madelyn.UpdateAABBHr();
                    BoundingBox extrudedAABB = madelyn.WorldAABBHr;
                    extrudedAABB.Min -= new Vector3(500);
                    extrudedAABB.Max += new Vector3(500);

                    List<MyWayPoint> nearMadelynWaypoints = new List<MyWayPoint>();

                    foreach (var waypoint in MyGamePruningStructure.GetAllEntitiesInBox(ref extrudedAABB, MyGamePruningStructure.QueryFlags.Waypoints))
                    {
                        MyWayPoint v = waypoint as MyWayPoint;
                        if (v != null)
                        {
                            if (!v.Save) continue;
                            if (madelyn.Children.Contains(v)) continue;
                            nearMadelynWaypoints.Add(v);
                        }
                    }
                    int connected = 0, raycasts = 0;
                    foreach (MyWayPoint v in nearMadelynWaypoints)
                    {
                        foreach (var child in madelyn.Children)
                        {
                            var w = child as MyWayPoint;
                            if (w == null) continue;

                            if (v.Neighbors.Contains(w)) continue;
                            raycasts++;
                            if (MyWayPoint.ConnectIfVisible(w, v))  // make a raycast
                            {
                                connected++;
                                break;
                            }
                        }
                    }
                }
            }

            // delete generated waypoints without edges
            foreach (var v in GetVertexListForModification())
            {
                if (!v.Save && v.Neighbors.Count == 0)
                {
                    v.MarkForClose();
                    closed++;
                }
            }

            InvalidateStoredPathCache();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
        }
        public void DoWork()
        {
            try
            {
                MyEntities.EntityCloseLock.AcquireShared();

                if (m_goalEntity == null)
                {
                    return;
                }
                // try the direct path
                {
                    var directLine = new MyLine(m_startPos, m_goalPos, true);
                    if (MyEntities.GetAnyIntersectionWithLine(ref directLine, m_goalEntity, null, true, true, true, false) == null)
                    {
                        Path.Add(m_startPos);
                        Path.Add(m_goalPos);
                        Message = new StringBuilder().AppendFormat(MyTextsWrapper.Get(MyTextsWrapperEnum.GPSDistance).ToString(), Vector3.Distance(m_startPos, m_goalPos));
                        return;
                    }
                }

                // get the closest waypoint to the goal (ignore visibility)
                MyWayPoint goal = MyWayPointGraph.GetClosestNonGeneratedWaypoint(m_goalPos);
                if (goal == null)
                {
                    return;
                }

                // remember which waypoints were visible/invisible from startPos
                // remember blocked/unblocked edges
                var visibleFromStartPosCache = new Dictionary <MyWayPoint, bool>();
                //var blockedEdges = new HashSet<Tuple<MyWayPoint, MyWayPoint>>();
                HashSet <Tuple <MyWayPoint, MyWayPoint> > blockedEdges = null;

                using (MyWayPoint.BlockedEdgesLock.AcquireSharedUsing())
                {
                    blockedEdges = new HashSet <Tuple <MyWayPoint, MyWayPoint> >(MyWayPoint.BlockedEdgesForPlayer);
                }

                var unblockedEdges = new HashSet <Tuple <MyWayPoint, MyWayPoint> >();

                // get 7 closest visible waypoints to startPos and compute shortest paths from them

                // first try 7 closest
                var closestVisibleWaypoints = MyWayPointGraph.GetClosestVisibleWaypoints(m_startPos, m_goalEntity, 7, 7, visibleFromStartPosCache);

                if (closestVisibleWaypoints.Count == 0 || !FindPathBetweenWaypoints(closestVisibleWaypoints, goal, visibleFromStartPosCache, blockedEdges, unblockedEdges))
                {
                    // failure: try 50 closest
                    closestVisibleWaypoints = MyWayPointGraph.GetClosestVisibleWaypoints(m_startPos, m_goalEntity, 12, 50, visibleFromStartPosCache);

                    if (closestVisibleWaypoints.Count == 0 || !FindPathBetweenWaypoints(closestVisibleWaypoints, goal, visibleFromStartPosCache, blockedEdges, unblockedEdges))
                    {
                        return;  // no use
                    }
                }
            }
            finally
            {
                if (m_goalEntity != null)
                {
                    m_goalEntity.OnClose -= goalEntity_OnClose;
                }

                MyEntities.EntityCloseLock.ReleaseShared();
            }
        }
        private bool FindPathBetweenWaypoints(
            List <MyWayPoint> closestVisibleWaypoints,
            MyWayPoint goal,
            Dictionary <MyWayPoint, bool> visibleFromStartPosCache,
            HashSet <Tuple <MyWayPoint, MyWayPoint> > blockedEdges,
            HashSet <Tuple <MyWayPoint, MyWayPoint> > unblockedEdges
            )
        {
            // find the best path candidate
            float shortestPathLength = float.MaxValue;
            int   retryCount         = 0;

            for (int j = 0; j < closestVisibleWaypoints.Count && retryCount < 30; j++)  // max retry count is 30
            {
                var path = closestVisibleWaypoints[j].GetShortestPathTo(goal, blockedEdges, true, false);
                if (path.Count == 0)
                {
                    continue;
                }

                // optimize the path: try to delete waypoints from the start of the path (if the next waypoints are visible)
                int farthestVisibleWaypointInPath = 0;

                for (int i = Math.Min(path.Count - 1, 20); i > 0; i--)  // path optimization: max 20 raycasts per path candidate, reuse previous results
                {
                    if (path[i].IsVisibleFrom(m_startPos, m_goalEntity, visibleFromStartPosCache))
                    {
                        farthestVisibleWaypointInPath = i;
                        break;
                    }
                }

                // compute the length of the path candidate
                float length = Vector3.Distance(m_startPos, path[farthestVisibleWaypointInPath].WorldMatrix.Translation) + Vector3.Distance(path[path.Count - 1].WorldMatrix.Translation, m_goalPos);
                for (int i = farthestVisibleWaypointInPath; i < path.Count - 1; i++)
                {
                    length += Vector3.Distance(path[i].WorldMatrix.Translation, path[i + 1].WorldMatrix.Translation);
                }

                // if it's the shortest path candidate yet, make it the new GPS path
                if (length < shortestPathLength)
                {
                    // but first check that the edges are free of any obstructions (and remember it)
                    bool pathBlocked = false;
                    for (int i = farthestVisibleWaypointInPath; i < path.Count - 2; i++)
                    {
                        // assume that edges between non-generated waypoints are always ok
                        if (path[i].Save && path[i + 1].Save)
                        {
                            continue;
                        }

                        var tuple = Tuple.Create(path[i], path[i + 1]);
                        if (unblockedEdges.Contains(tuple))  // already tested and it was ok
                        {
                        }
                        else if (path[i + 1].IsVisibleFrom(path[i].Position, m_goalEntity))
                        {
                            unblockedEdges.Add(tuple);
                            unblockedEdges.Add(Tuple.Create(path[i + 1], path[i]));
                        }
                        else
                        {
                            blockedEdges.Add(tuple);
                            blockedEdges.Add(Tuple.Create(path[i + 1], path[i]));
                            pathBlocked = true;
                            break;
                        }
                    }
                    if (pathBlocked)
                    {
                        j--;  // retry current waypoint with updated cache of blocked edges
                        retryCount++;
                        continue;
                    }

                    // seems legit
                    shortestPathLength = length;
                    Path = new List <Vector3>();
                    Path.Add(m_startPos);
                    for (int i = farthestVisibleWaypointInPath; i < path.Count; i++)
                    {
                        Path.Add(path[i].WorldMatrix.Translation);
                    }
                    Path.Add(m_goalPos);
                }
            }

            if (Path.Count != 0)
            {
                Message = new StringBuilder().AppendFormat(MyTextsWrapper.Get(MyTextsWrapperEnum.GPSDistance).ToString(), shortestPathLength);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #14
0
        /// <summary>
        /// Create and connect waypoints to enable navigation outside prefab containers.
        /// Needs to be called from the main thread (because it uses MyEntities.GetSafeIterationHelperForAll).
        /// </summary>
        public static void CreateWaypointsAroundLargeStaticObjects()
        {
            if (m_GPSWaypointsInited) return;

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("CreateWaypointsAroundLargeStaticObjects");

            // memory benchmark
            //GC.Collect(2);
            //MyMwcLog.WriteLine("#CreateWaypointsAroundLargeStaticObjects# before: working set " + MyValueFormatter.GetFormatedLong(Environment.WorkingSet) + ", gc " + MyValueFormatter.GetFormatedLong(GC.GetTotalMemory(false)));

            // counters for debugging
            int largeObjects = 0;
            int totalWaypointsOutside = 0;
            int bigSubdivisions = 0;
            int freeEnvelopes = 0;
            int edgesWithoutRaycasts = 0;
            int edgesWithRaycastsAdded = 0;
            int edgesWithRaycastsNotAdded = 0;
            int closed = 0;

            var envelopes = new List<MyWayPoint[, ,]>();
            var envelopeEntity = new List<MyEntity>();
            var envelopeBvh = new MyDynamicAABBTree(MyConstants.GAME_PRUNING_STRUCTURE_AABB_EXTENSION);

            var nonFree = new HashSet<MyWayPoint>();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("create envelopes");

            var interestingBoxInflation = new Vector3(MyWaypointConstants.MAXIMUM_BOX_DISTANCE_TO_INTERESTING_STUFF_TO_GENERATE_WAYPOINTS);
            var interestingBoxes = new List<BoundingBox>();

            // find interesting stuff (only prefab containers for now)
            foreach (var entity in MyEntities.GetEntities())
            {
                if (!(entity is MyPrefabContainer)) continue;

                entity.UpdateAABBHr();
                BoundingBox box = entity.WorldAABBHr;
                if (box.Max - box.Min == Vector3.Zero)
                {
                    box = entity.WorldAABB;
                    if (box.Max - box.Min == Vector3.Zero) continue;  // no bounding box
                }

                BoundingBox extrudedBox = new BoundingBox(box.Min - interestingBoxInflation, box.Max + interestingBoxInflation);
                interestingBoxes.Add(extrudedBox);
            }

            int ss = 0;
            int madelynsBox = -1;
            // create envelopes
            foreach (var entity in MyEntities.GetSafeIterationHelperForAll())
            {
                if (!(entity is MyVoxelMap || entity is MyPrefabContainer || entity is MyStaticAsteroid)) continue;

                entity.UpdateAABBHr();
                BoundingBox box = entity.WorldAABBHr;
                if (box.Max - box.Min == Vector3.Zero)
                    box = entity.WorldAABB;
                if (entity is MyStaticAsteroid &&
                    (box.Max - box.Min).LengthSquared() < MyWaypointConstants.MINIMUM_ASTEROID_DIAGONAL_LENGTH_TO_GENERATE_WAYPOINTS * MyWaypointConstants.MINIMUM_ASTEROID_DIAGONAL_LENGTH_TO_GENERATE_WAYPOINTS)
                {
                    continue;  // small static asteroids: ignore
                }
                if (entity is MyStaticAsteroid)
                {
                    ss++;
                    bool inInteresting = false;
                    foreach (var iBox in interestingBoxes)
                    {
                        if (iBox.Contains(box) != ContainmentType.Disjoint)
                        {
                            inInteresting = true;
                            break;
                        }
                    }
                    if (!inInteresting) continue;  // static asteroids far from interesting stuff: ignore
                }
                // enlarge by 1% and 15 meters on each side
                BoundingBox extrudedBox = new BoundingBox(box.Min - (box.Max - box.Min) * 0.01f - new Vector3(15, 15, 15), box.Max + (box.Max - box.Min) * 0.01f + new Vector3(15, 15, 15));

                //diagonals.Add((float)Math.Sqrt((box.Max - box.Min).LengthSquared()));

                var waypointsOutside = new HashSet<MyWayPoint>();

                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("find crossing");
                // add all edges that cross the non-extruded box from inside to outside (remember out-vertices)
                foreach (var waypoint in MyGamePruningStructure.GetAllEntitiesInBox(ref extrudedBox, MyGamePruningStructure.QueryFlags.Waypoints))
                {
                    var v = waypoint as MyWayPoint;
                    if (!v.Save) continue;
                    nonFree.Add(v);
                    using (MyWayPoint.NeighborsLock.AcquireSharedUsing())
                    {
                        foreach (var n in v.Neighbors) if (n.Save && extrudedBox.Contains(n.Position) != ContainmentType.Contains)
                            {
                                if (waypointsOutside.Add(n)) totalWaypointsOutside++;
                                nonFree.Add(n);
                            }
                    }
                }
                MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

                // create envelope
                int s = 1;
                if (waypointsOutside.Count > 0 || entity as MyStaticAsteroid == null)  // voxel maps and prefabs are automatically subdivided more
                {
                    s = 2;
                    bigSubdivisions++;
                }
                MyWayPoint[, ,] envelope = new MyWayPoint[s + 1, s + 1, s + 1];

                for (int i = 0; i <= s; i++) for (int j = 0; j <= s; j++) for (int k = 0; k <= s; k++)
                        {
                            if (s == 2 && i == 1 && j == 1 && k == 1) continue;
                            envelope[i, j, k] = CreateWaypoint(new Vector3(
                                extrudedBox.Min.X + i * (extrudedBox.Max.X - extrudedBox.Min.X) / s,
                                extrudedBox.Min.Y + j * (extrudedBox.Max.Y - extrudedBox.Min.Y) / s,
                                extrudedBox.Min.Z + k * (extrudedBox.Max.Z - extrudedBox.Min.Z) / s
                            ), null);
                            envelope[i, j, k].Save = false;  // don't save generated waypoints
                            nonFree.Add(envelope[i, j, k]);

                            // connect with neighbors
                            // use ConnectIfNoAABBBlockers only for non-static asteroids
                            // don't connect to the non-existing middle vertex
                            if (entity is MyStaticAsteroid)
                            {
                                if (i != 0) if (!(s == 2 && i - 1 == 1 && j == 1 && k == 1)) { MyWayPoint.Connect(envelope[i, j, k], envelope[i - 1, j, k]); edgesWithoutRaycasts++; }
                                if (j != 0) if (!(s == 2 && j - 1 == 1 && i == 1 && k == 1)) { MyWayPoint.Connect(envelope[i, j, k], envelope[i, j - 1, k]); edgesWithoutRaycasts++; }
                                if (k != 0) if (!(s == 2 && k - 1 == 1 && j == 1 && i == 1)) { MyWayPoint.Connect(envelope[i, j, k], envelope[i, j, k - 1]); edgesWithoutRaycasts++; }
                            }
                            else
                            {
                                if (i != 0) if (!(s == 2 && i - 1 == 1 && j == 1 && k == 1)) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i - 1, j, k])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                                if (j != 0) if (!(s == 2 && j - 1 == 1 && i == 1 && k == 1)) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i, j - 1, k])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                                if (k != 0) if (!(s == 2 && k - 1 == 1 && j == 1 && i == 1)) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i, j, k - 1])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                            }

                            // if it's a part of a face that faces an out-vertex, connect it
                            foreach (var v in waypointsOutside)
                                if ((i == 0 && v.Position.X <= envelope[i, j, k].Position.X) ||
                                    (i == s && v.Position.X >= envelope[i, j, k].Position.X) ||
                                    (j == 0 && v.Position.Y <= envelope[i, j, k].Position.Y) ||
                                    (j == s && v.Position.Y >= envelope[i, j, k].Position.Y) ||
                                    (k == 0 && v.Position.Z <= envelope[i, j, k].Position.Z) ||
                                    (k == s && v.Position.Z >= envelope[i, j, k].Position.Z)
                                )
                                {
                                    if (MyWayPoint.ConnectIfNoAABBBlockers(v, envelope[i, j, k]))
                                        edgesWithRaycastsAdded++;
                                    else
                                        edgesWithRaycastsNotAdded++;
                                }
                        }

                envelopes.Add(envelope);
                envelopeEntity.Add(entity);
                envelopeBvh.AddProxy(ref extrudedBox, envelopes.Count - 1, 0);
                largeObjects++;

                if (entity.Name == "Madelyn")
                {
                    madelynsBox = envelopes.Count - 1;
                }
            }

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
            var componentsDone = new HashSet<int>();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("connect free wps");

            // free waypoint: check whether it's connected to an envelope
            foreach (var v in GetVertexListForModification()) if (!nonFree.Contains(v))
                {
                    int id = GetConnectedComponentId(v);
                    if (componentsDone.Contains(id)) continue;

                    componentsDone.Add(id);

                    var connectedWaypoints = GetWaypointsWithConnectedComponentId(id);

                    // is this component already connected to an envelope?
                    var box = new BoundingBox(v.Position, v.Position);
                    foreach (var w in connectedWaypoints) if (w.Save)
                        {
                            var pos = w.Position;
                            box = box.Include(ref pos);
                            if (nonFree.Contains(w))
                                goto alreadyConnected;
                        }

                    BoundingBox extrudedBox = new BoundingBox(box.Min - (box.Max - box.Min) * 0.01f - new Vector3(5, 5, 5), box.Max + (box.Max - box.Min) * 0.01f + new Vector3(5, 5, 5));

                    // no - create a new one
                    int s = 1;
                    MyWayPoint[, ,] envelope = new MyWayPoint[s + 1, s + 1, s + 1];
                    for (int i = 0; i <= s; i++) for (int j = 0; j <= s; j++) for (int k = 0; k <= s; k++)
                            {
                                envelope[i, j, k] = CreateWaypoint(new Vector3(
                                    extrudedBox.Min.X + i * (extrudedBox.Max.X - extrudedBox.Min.X) / s,
                                    extrudedBox.Min.Y + j * (extrudedBox.Max.Y - extrudedBox.Min.Y) / s,
                                    extrudedBox.Min.Z + k * (extrudedBox.Max.Z - extrudedBox.Min.Z) / s
                                ), null);
                                envelope[i, j, k].Save = false;  // don't save generated waypoints
                                nonFree.Add(envelope[i, j, k]);

                                // connect with neighbors
                                // should use ConnectIfVisible, but it's slow and we can resolve it while computing the GPS
                                if (i != 0) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i - 1, j, k])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                                if (j != 0) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i, j - 1, k])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                                if (k != 0) { if (MyWayPoint.ConnectIfNoAABBBlockers(envelope[i, j, k], envelope[i, j, k - 1])) edgesWithRaycastsAdded++; else edgesWithRaycastsNotAdded++; }
                            }

                    // connect all waypoints to the closest corner of the new envelope
                    foreach (var w in connectedWaypoints)
                    {
                        var pos = w.Position;
                        if (MyWayPoint.ConnectIfNoAABBBlockers(w, envelope[pos.X < extrudedBox.GetCenter().X ? 0 : 1, pos.Y < extrudedBox.GetCenter().Y ? 0 : 1, pos.Z < extrudedBox.GetCenter().Z ? 0 : 1]))
                            edgesWithRaycastsAdded++;
                        else
                            edgesWithRaycastsNotAdded++;
                    }
                    envelopes.Add(envelope);
                    envelopeEntity.Add(null);
                    envelopeBvh.AddProxy(ref extrudedBox, envelopes.Count - 1, 0);
                    freeEnvelopes++;

                alreadyConnected: { }
                }

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().StartProfilingBlock("connect envelopes");

            // connect envelopes together
            for (int eIndex = 0; eIndex < envelopes.Count; eIndex++)
            {
                var e = envelopes[eIndex];
                int es = e.GetLength(0) - 1;
                var eCenter = 0.5f * (e[0, 0, 0].Position + e[es, es, es].Position);

                // get K closest indices
                var closestEnvelopeIndices = new List<int>();
                for (int i = 200; i <= 6400; i *= 2)  // try 200, 400, 800, 1600, 3200, 6400 m
                {
                    var halfExtent = new Vector3(i);
                    var bbox = new BoundingBox(eCenter - halfExtent, eCenter + halfExtent);
                    envelopeBvh.OverlapAllBoundingBox(ref bbox, closestEnvelopeIndices);
                    if (closestEnvelopeIndices.Count >= 16) break;
                }

                // connect them together
                int k = 0;
                foreach (var qIndex in closestEnvelopeIndices)
                {
                    if (++k == 16) break;  // take only 16 envelopes
                    if (qIndex == eIndex) continue;

                    var q = envelopes[qIndex];

                    int qs = q.GetLength(0) - 1;
                    var qCenter = 0.5f * (q[0, 0, 0].Position + q[qs, qs, qs].Position);

                    // connect the closest opposite vertices
                    int qx, qy, qz, ex, ey, ez;
                    if (qCenter.X < eCenter.X) { qx = qs; ex = 0; } else { qx = 0; ex = es; }
                    if (qCenter.Y < eCenter.Y) { qy = qs; ey = 0; } else { qy = 0; ey = es; }
                    if (qCenter.Z < eCenter.Z) { qz = qs; ez = 0; } else { qz = 0; ez = es; }

                    if (es > 1 || qs > 1)
                    {
                        if (MyWayPoint.ConnectIfNoAABBBlockers(e[ex, ey, ez], q[qx, qy, qz], envelopeEntity[eIndex], envelopeEntity[qIndex]))
                            edgesWithRaycastsAdded++;
                        else
                            edgesWithRaycastsNotAdded++;
                    }
                    else
                    {
                        // don't make a raycast if one of the envelopes isn't important
                        MyWayPoint.Connect(e[ex, ey, ez], q[qx, qy, qz]);
                        edgesWithoutRaycasts++;
                    }

                    // connect Madelyn's waypoint to envelopes
                    if (eIndex == madelynsBox)
                    {
                        MyEntity madelyn = envelopeEntity[madelynsBox];
                        foreach (var child in madelyn.Children)
                        {
                            var w = child as MyWayPoint;
                            if (w == null)
                                continue;
                            MyWayPoint.ConnectIfNoAABBBlockers(w, q[qx, qy, qz]);  // make a raycast
                        }
                    }
                }

                // connect Madelyn's waypoint to envelopes
                if (eIndex == madelynsBox)
                {
                    MyEntity madelyn = envelopeEntity[madelynsBox];

                    madelyn.UpdateAABBHr();
                    BoundingBox extrudedAABB = madelyn.WorldAABBHr;
                    extrudedAABB.Min -= new Vector3(500);
                    extrudedAABB.Max += new Vector3(500);

                    List<MyWayPoint> nearMadelynWaypoints = new List<MyWayPoint>();

                    foreach (var waypoint in MyGamePruningStructure.GetAllEntitiesInBox(ref extrudedAABB, MyGamePruningStructure.QueryFlags.Waypoints))
                    {
                        MyWayPoint v = waypoint as MyWayPoint;
                        if (v != null)
                        {
                            if (!v.Save)
                                continue;
                            nearMadelynWaypoints.Add(v);
                        }
                    }

                    foreach (var child in madelyn.Children)
                    {
                        var w = child as MyWayPoint;
                        if (w == null)
                            continue;

                        foreach (MyWayPoint v in nearMadelynWaypoints)
                        {
                            MyWayPoint.ConnectIfVisible(w, v);  // make a raycast
                        }
                    }
                }
            }

            // delete generated waypoints without edges
            foreach (var v in GetVertexListForModification())
            {
                if (!v.Save && v.Neighbors.Count == 0)
                {
                    v.MarkForClose();
                    closed++;
                }
            }

            m_GPSWaypointsInited = true;
            InvalidateStoredPathCache();

            // memory benchmark
            //GC.Collect(2);
            //MyMwcLog.WriteLine("#CreateWaypointsAroundLargeStaticObjects# after: working set " + MyValueFormatter.GetFormatedLong(Environment.WorkingSet) + ", gc " + MyValueFormatter.GetFormatedLong(GC.GetTotalMemory(false)));

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();

            MinerWars.AppCode.Game.Render.MyRender.GetRenderProfiler().EndProfilingBlock();
        }
Example #15
0
 // Return the component id, or -1 if the given waypoint doesn't lie in the waypoint graph.
 /// <summary>This function needs to be called with EntityCloseLock already acquired, or not an issue.</summary>
 public static int GetConnectedComponentId(MyWayPoint wp)
 {
     RecomputeConnectedComponents();
     int value;
     if (m_componentIds.TryGetValue(wp, out value))
         return value;
     return -1;
 }
Example #16
0
        // Return the complete shortest path between vertices in a list.
        public List<MyWayPoint> CompletePath(HashSet<Tuple<MyWayPoint, MyWayPoint>> blockedEdges, MyWayPoint currentWayPoint, bool useGeneratedWaypoints = true, bool cycle = false, bool cachedIsOk = true)
        {
            if (!cachedIsOk || m_cachedCompletePath == null)
            {
                using (MyEntities.EntityCloseLock.AcquireSharedUsing())
                {
                    m_cachedCompletePath = new List<MyWayPoint>();
                    if (WayPoints == null || WayPoints.Count == 0) return m_cachedCompletePath;

                    int currentIndex = currentWayPoint != null ? WayPoints.IndexOf(currentWayPoint) : 0;
                    m_cachedCompletePath.Add(WayPoints[0]);
                    //for (int i = 0; i < WayPoints.Count - 1; i++)
                    //{
                    //    var subpath = WayPoints[i].GetShortestPathTo(WayPoints[i + 1], blockedEdges, useGeneratedWaypoints);
                    //    if (subpath.Count == 0)
                    //        m_cachedCompletePath.Add(WayPoints[i + 1]);  // no path: add straight line to next waypoint
                    //    else
                    //        m_cachedCompletePath.AddRange(subpath.GetRange(1, subpath.Count - 1));  // the first point was the last point of the previous segment
                    //}
                    //if (cycle)
                    //{
                    //    var subpath = WayPoints[WayPoints.Count - 1].GetShortestPathTo(WayPoints[0], blockedEdges, useGeneratedWaypoints);
                    //    if (subpath.Count > 2)
                    //        m_cachedCompletePath.AddRange(subpath.GetRange(1, subpath.Count - 2));  // the first point was the last point of the previous segment, the last point was point 0
                    //}
                    for (int i = 0; i < WayPoints.Count - 1; i++)
                    {
                        var subpath = WayPoints[i].GetShortestPathTo(WayPoints[i + 1], blockedEdges, useGeneratedWaypoints);
                        if (subpath.Count == 0)
                        {
                            if (blockedEdges != null && blockedEdges.Contains(Tuple.Create(WayPoints[i], WayPoints[i + 1])))
                            {
                                // this part of the path is unreachable
                                if (currentIndex > i)
                                {
                                    m_cachedCompletePath.Clear();
                                    m_cachedCompletePath.Add(WayPoints[i + 1]);
                                }
                                else
                                {
                                    break;
                                }
                            }
                            else
                            {
                                m_cachedCompletePath.Add(WayPoints[i + 1]);  // no path: add straight line to next waypoint
                            }
                        }
                        else
                        {
                            m_cachedCompletePath.AddRange(subpath.GetRange(1, subpath.Count - 1));  // the first point was the last point of the previous segment
                        }
                    }

                    if (cycle)
                    {
                        var subpath = WayPoints[WayPoints.Count - 1].GetShortestPathTo(WayPoints[0], blockedEdges, useGeneratedWaypoints);
                        if (subpath.Count > 2)
                            m_cachedCompletePath.AddRange(subpath.GetRange(1, subpath.Count - 2));  // the first point was the last point of the previous segment, the last point was point 0
                    }
                }
            }
            return m_cachedCompletePath;
        }
        internal override void Update(MySmallShipBot bot)
        {
            base.Update(bot);

            if (ShouldFallAsleep(bot))
            {
                bot.IsSleeping = true;
                return;
            }

            bool pathChange = m_lastWayPointPath != bot.WaypointPath;
            if (pathChange) 
            {
                m_lastWayPointPath = bot.WaypointPath;
                m_currentWayPointIndex = 0;
            }

            bool cycle = bot.PatrolMode == MyPatrolMode.CYCLE;

            if (bot.WaypointPath != null && !bot.SuspendPatrol && bot.WaypointPath.WayPoints.Count > 0)
            {
                UpdateVisibility(bot, bot.CurrentWaypoint.GetPosition());

                if (!m_targetVisible)
                {
                    findSmallship.Update(bot, bot.CurrentWaypoint);
                    if (findSmallship.PathNotFound)
                    {
                        bot.IsSleeping = true;
                        m_isInvalid = true;
                    }
                }
                else
                {
                    bool blockedEdgesIdDirty = m_lastBlockedEdgesChangeId != MyWayPoint.BlockedEdgesChangeId;
                    m_path.Clear();
                    using (MyWayPoint.BlockedEdgesLock.AcquireSharedUsing())
                    {
                        m_path.AddRange(bot.WaypointPath.CompletePath(MyWayPoint.BlockedEdgesForBots, bot.CurrentWaypoint, false, cycle, !blockedEdgesIdDirty));
                    }
                    m_lastBlockedEdgesChangeId = MyWayPoint.BlockedEdgesChangeId;

                    if (blockedEdgesIdDirty)
                    {
                        if (bot.CurrentWaypoint == null)
                        {
                            m_currentWayPointIndex = 0;
                        }
                        else
                        {
                            m_currentWayPointIndex = m_path.IndexOf(bot.CurrentWaypoint);
                        }
                    }

                    // no path found
                    if (m_currentWayPointIndex == -1)
                    {
                        return;
                    }

                    bot.CurrentWaypoint = m_path[m_currentWayPointIndex];

                    if (Vector3.DistanceSquared(bot.GetPosition(), bot.CurrentWaypoint.GetPosition()) <= WAYPOINT_NEAR_DISTANCE_SQR)
                    {
                        if (bot.CurrentWaypoint.EntityId != null && m_lastWayPoint != bot.CurrentWaypoint)
                        {
                            m_lastWayPoint = bot.CurrentWaypoint;

                            MyScriptWrapper.BotReachedWaypoint(bot, bot.CurrentWaypoint);
                        }
                        //++processedWaypoints;

                        int count = m_path.Count;
                        switch (bot.PatrolMode)
                        {
                            case MyPatrolMode.CYCLE:
                                //bot.CurrentWaypointIndex = processedWaypoints % count;
                                m_currentWayPointIndex++;
                                if (m_currentWayPointIndex >= count)
                                {
                                    m_currentWayPointIndex = 0;
                                }
                                break;
                            case MyPatrolMode.PING_PONG:
                                if (count > 1)
                                {
                                    //bot.CurrentWaypointIndex = processedWaypoints % (count * 2 - 2);
                                    //if (bot.CurrentWaypointIndex >= count)
                                    //{
                                    //    bot.CurrentWaypointIndex = (count * 2 - 2) - bot.CurrentWaypointIndex;
                                    //}
                                    if (m_forward)
                                    {
                                        if (m_currentWayPointIndex < count - 1)
                                        {
                                            m_currentWayPointIndex++;
                                        }
                                        else
                                        {
                                            m_currentWayPointIndex--;
                                            m_forward = false;
                                        }
                                    }
                                    else
                                    {
                                        if (m_currentWayPointIndex > 0)
                                        {
                                            m_currentWayPointIndex--;
                                        }
                                        else
                                        {
                                            m_currentWayPointIndex++;
                                            m_forward = true;
                                        }
                                    }
                                }
                                else
                                {
                                    m_currentWayPointIndex = 0;
                                }
                                break;
                            case MyPatrolMode.ONE_WAY:
                                if (m_currentWayPointIndex < m_path.Count - 1)
                                {
                                    ++m_currentWayPointIndex;
                                }
                                break;
                        }

                        bot.CurrentWaypoint = m_path[m_currentWayPointIndex];
                    }

                    bot.Move(bot.CurrentWaypoint.GetPosition(), bot.CurrentWaypoint.GetPosition(), GetUpPlane(), false);
                    findSmallship.Init(bot);
                }
            }
        }
        internal override void Update(MySmallShipBot bot)
        {
            base.Update(bot);

            if (ShouldFallAsleep(bot))
            {
                bot.IsSleeping = true;
                return;
            }

            bool pathChange = m_lastWayPointPath != bot.WaypointPath;

            if (pathChange)
            {
                m_lastWayPointPath     = bot.WaypointPath;
                m_currentWayPointIndex = 0;
            }

            bool cycle = bot.PatrolMode == MyPatrolMode.CYCLE;

            if (bot.WaypointPath != null && !bot.SuspendPatrol && bot.WaypointPath.WayPoints.Count > 0)
            {
                UpdateVisibility(bot, bot.CurrentWaypoint.GetPosition());

                if (!m_targetVisible)
                {
                    findSmallship.Update(bot, bot.CurrentWaypoint);
                    if (findSmallship.PathNotFound)
                    {
                        bot.IsSleeping = true;
                        m_isInvalid    = true;
                    }
                }
                else
                {
                    bool blockedEdgesIdDirty = m_lastBlockedEdgesChangeId != MyWayPoint.BlockedEdgesChangeId;
                    m_path.Clear();
                    using (MyWayPoint.BlockedEdgesLock.AcquireSharedUsing())
                    {
                        m_path.AddRange(bot.WaypointPath.CompletePath(MyWayPoint.BlockedEdgesForBots, bot.CurrentWaypoint, false, cycle, !blockedEdgesIdDirty));
                    }
                    m_lastBlockedEdgesChangeId = MyWayPoint.BlockedEdgesChangeId;

                    if (blockedEdgesIdDirty)
                    {
                        if (bot.CurrentWaypoint == null)
                        {
                            m_currentWayPointIndex = 0;
                        }
                        else
                        {
                            m_currentWayPointIndex = m_path.IndexOf(bot.CurrentWaypoint);
                        }
                    }

                    // no path found
                    if (m_currentWayPointIndex == -1)
                    {
                        return;
                    }

                    bot.CurrentWaypoint = m_path[m_currentWayPointIndex];

                    if (Vector3.DistanceSquared(bot.GetPosition(), bot.CurrentWaypoint.GetPosition()) <= WAYPOINT_NEAR_DISTANCE_SQR)
                    {
                        if (bot.CurrentWaypoint.EntityId != null && m_lastWayPoint != bot.CurrentWaypoint)
                        {
                            m_lastWayPoint = bot.CurrentWaypoint;

                            MyScriptWrapper.BotReachedWaypoint(bot, bot.CurrentWaypoint);
                        }
                        //++processedWaypoints;

                        int count = m_path.Count;
                        switch (bot.PatrolMode)
                        {
                        case MyPatrolMode.CYCLE:
                            //bot.CurrentWaypointIndex = processedWaypoints % count;
                            m_currentWayPointIndex++;
                            if (m_currentWayPointIndex >= count)
                            {
                                m_currentWayPointIndex = 0;
                            }
                            break;

                        case MyPatrolMode.PING_PONG:
                            if (count > 1)
                            {
                                //bot.CurrentWaypointIndex = processedWaypoints % (count * 2 - 2);
                                //if (bot.CurrentWaypointIndex >= count)
                                //{
                                //    bot.CurrentWaypointIndex = (count * 2 - 2) - bot.CurrentWaypointIndex;
                                //}
                                if (m_forward)
                                {
                                    if (m_currentWayPointIndex < count - 1)
                                    {
                                        m_currentWayPointIndex++;
                                    }
                                    else
                                    {
                                        m_currentWayPointIndex--;
                                        m_forward = false;
                                    }
                                }
                                else
                                {
                                    if (m_currentWayPointIndex > 0)
                                    {
                                        m_currentWayPointIndex--;
                                    }
                                    else
                                    {
                                        m_currentWayPointIndex++;
                                        m_forward = true;
                                    }
                                }
                            }
                            else
                            {
                                m_currentWayPointIndex = 0;
                            }
                            break;

                        case MyPatrolMode.ONE_WAY:
                            if (m_currentWayPointIndex < m_path.Count - 1)
                            {
                                ++m_currentWayPointIndex;
                            }
                            break;
                        }

                        bot.CurrentWaypoint = m_path[m_currentWayPointIndex];
                    }

                    bot.Move(bot.CurrentWaypoint.GetPosition(), bot.CurrentWaypoint.GetPosition(), GetUpPlane(), false);
                    findSmallship.Init(bot);
                }
            }
        }