public PlanetBiome(MyPlanetMaterialGroup group) { Value = group.Value; Name = group.Name; Rules = new List <PlanetMaterialRule>(group.MaterialRules.Length); for (int i = 0; i < group.MaterialRules.Length; i++) { Rules.Add(new PlanetMaterialRule(group.MaterialRules[i])); } MateriaTree = new MyDynamicAABBTree(Vector3.Zero); foreach (var rule in Rules) { BoundingBox bb = new BoundingBox(new Vector3(rule.Height.Min, rule.Latitude.Min, rule.Longitude.Min), new Vector3(rule.Height.Max, rule.Latitude.Max, rule.Longitude.Max)); MateriaTree.AddProxy(ref bb, rule, 0); if (rule.Latitude.Mirror) { float min = -bb.Max.Y; bb.Max.Y = -bb.Min.Y; bb.Min.Y = min; MateriaTree.AddProxy(ref bb, rule, 0); } } }
public void AddRoom(ProceduralRoom room) { if (m_rooms.ContainsKey(room.RoomID)) { throw new ArgumentException("Room ID already used"); } m_rooms[room.RoomID] = room; var aabb = room.BoundingBoxBoth; room.m_aabbProxyID = m_roomTree.AddProxy(ref aabb, room, 0); m_roomsSafeOrder.Add(room); foreach (var k in room.MountPoints) { foreach (var p in k.MountLocations) { if (m_mountPoints.ContainsKey(p)) { Logger.Warning("Room {0} at {1} has mount point {4}:{5} that intersect with mount point {6}:{7} of room {2} at {3}", m_mountPoints[p].Owner.Part.Name, m_mountPoints[p].Owner.Transform.Translation, room.Part.Name, room.Transform.Translation, m_mountPoints[p].MountPoint.MountType, m_mountPoints[p].MountPoint.MountName, k.MountPoint.MountType, k.MountPoint.MountName); } else { m_mountPoints.Add(p, k); } } } room.TakeOwnership(this); using (room.Part.LockSharedUsing()) BlockSetInfo.AddToSelf(room.Part.BlockSetInfo); RoomAdded?.Invoke(room); }
private void GetChunk(ref Vector3I coord, out VoxelChunk chunk, MyStorageDataTypeFlags required) { using (m_cacheLock.AcquireExclusiveUsing()) { if (!m_cachedChunks.TryGetValue(coord, out chunk)) { chunk = new VoxelChunk(coord); var rangeStart = coord << VoxelChunk.SizeBits; var rangeEnd = ((coord + 1) << VoxelChunk.SizeBits) - 1; if (required != 0) { using (m_storageLock.AcquireSharedUsing()) ReadDatForChunk(chunk, required); } m_chunksbyAge.Enqueue(coord); m_cachedChunks.Add(coord, chunk); var bb = new BoundingBox(rangeStart, rangeEnd); chunk.TreeProxy = m_cacheMap.AddProxy(ref bb, chunk, 0); } else if ((chunk.Cached & required) != required) { using (m_storageLock.AcquireSharedUsing()) ReadDatForChunk(chunk, required & ~chunk.Cached); } } }
private void CheckWaiting() { Dictionary <string, IMyModelDummy> tmp = null; var limit = _waitingInsert.Count; while (_waitingInsert.Count > 0 && (limit-- > 0)) { var ins = _waitingInsert.Dequeue(); if (tmp == null) { tmp = new Dictionary <string, IMyModelDummy>(); } if (ins.Entity.Model != null) { tmp.Clear(); ins.Entity.Model.GetDummies(tmp); IMyModelDummy dummy; if (tmp.TryGetValue(ins.Path, out dummy)) { var bb = new BoundingBox(-Vector3.Half, Vector3.Half).Transform( dummy.Matrix * ins.Entity.LocalMatrix); var proxyId = _detectorTree.AddProxy(ref bb, ins, 0); ins.Update(proxyId, bb); DoConnect(ins); continue; } } _waitingInsert.Enqueue(ins); } }
public static void UpdateLightProxy(MyLight light) { if ((!light.LightOn || light.LightType == MyLight.LightTypeEnum.None) && light.ProxyId != MyDynamicAABBTree.NullNode) { m_tree.RemoveProxy(light.ProxyId); light.ProxyId = MyDynamicAABBTree.NullNode; } BoundingBox bbox = BoundingBoxHelper.InitialBox; if (light.IsTypePoint || light.IsTypeHemisphere) { bbox = BoundingBox.CreateFromSphere(light.PointBoundingSphere); } if (light.IsTypeSpot) { var box = light.SpotBoundingBox; BoundingBoxHelper.AddBBox(box, ref bbox); } if (light.ProxyId == MyDynamicAABBTree.NullNode) { light.ProxyId = m_tree.AddProxy(ref bbox, light, 0); } else { m_tree.MoveProxy(light.ProxyId, ref bbox, Vector3.Zero); } }
public int Register(MySmallShipBot entity) { System.Diagnostics.Debug.Assert(entity == null || !entity.Closed); entity.OnPositionChanged += OnPositionChangedHandler; MyDangerZoneElement element = new MyDangerZoneElement(entity); BoundingBox bbox = new BoundingBox(entity.WorldAABB.Min - new Vector3(DANGER_ZONE_SIZE), entity.WorldAABB.Max + new Vector3(DANGER_ZONE_SIZE)); int proxyId = m_dangerZoneStructure.AddProxy(ref bbox, element, 0); return(proxyId); }
internal static int UpdateBvh(MyDynamicAABBTree bvh, LightId lid, bool enabled, int proxy, ref BoundingBox aabb) { if (enabled && proxy == -1) { return(bvh.AddProxy(ref aabb, lid, 0)); } else if (enabled && proxy != -1) { bvh.MoveProxy(proxy, ref aabb, Vector3.Zero); return(proxy); } else { bvh.RemoveProxy(proxy); } return(-1); }
public static void Add(MyEntity entity) { if (entity.GamePruningProxyId != MyConstants.GAME_PRUNING_STRUCTURE_PROXY_ID_NOT_INSERTED) { return; // already inserted } BoundingBox bbox = entity.WorldAABB; if (bbox.Size() == Vector3.Zero) { return; // don't add entities with zero bounding boxes } if (entity is MyWayPoint) { entity.GamePruningProxyId = m_waypoints.AddProxy(ref bbox, entity, 0); } else { entity.GamePruningProxyId = m_others.AddProxy(ref bbox, entity, 0); } }
internal static int UpdateBvh(MyDynamicAABBTree bvh, LightId lid, bool enabled, int proxy, ref BoundingBox aabb) { if(enabled && proxy == -1) { return bvh.AddProxy(ref aabb, lid, 0); } else if(enabled && proxy != -1) { bvh.MoveProxy(proxy, ref aabb, Vector3.Zero); return proxy; } else { bvh.RemoveProxy(proxy); } return -1; }
public PlanetBiome(MyPlanetMaterialGroup group) { Value = group.Value; Name = group.Name; Rules = new List<PlanetMaterialRule>(group.MaterialRules.Length); for (int i = 0; i < group.MaterialRules.Length; i++) { Rules.Add(new PlanetMaterialRule(group.MaterialRules[i])); } MateriaTree = new MyDynamicAABBTree(Vector3.Zero); foreach (var rule in Rules) { BoundingBox bb = new BoundingBox(new Vector3(rule.Height.Min, rule.Latitude.Min, rule.Longitude.Min), new Vector3(rule.Height.Max, rule.Latitude.Max, rule.Longitude.Max)); MateriaTree.AddProxy(ref bb, rule, 0); if (rule.Latitude.Mirror) { float min = -bb.Max.Y; bb.Max.Y = -bb.Min.Y; bb.Min.Y = min; MateriaTree.AddProxy(ref bb, rule, 0); } } }
private void AddSectorEntities(MySectorObjectCounts asteroidCounts, MyMwcVector3Int sectorPosition, Random random, float entityMinimalSize, int maxEntityCount, List<MySolarSystemMapEntity> entities, bool onlyStaticAsteroids) { // Space around asteroid should be at least 1.2x - 2x it's size float asteroidSpacingCoeficient = 0.7f; // Asteroid count mean is 40% float asteroidCountMean = 0.4f; Dictionary<int, int> entityCounts = new Dictionary<int, int>(); foreach (MySolarSystemEntityEnum t in Enum.GetValues(typeof(MySolarSystemEntityEnum))) { entityCounts.Add((int)t, 0); } MyDynamicAABBTree prunningStructure = new MyDynamicAABBTree(Vector3.Zero); foreach (BoundingSphere boundingSphere in m_safeAreas) { BoundingBox bb = BoundingBox.CreateFromSphere(boundingSphere); prunningStructure.AddProxy(ref bb, new Render.MyRenderObject(null, null), 0); } // Generate asteroids, check collisions (order asteroids by size) //var asteroids = GetAsteroids(asteroidCounts, entityMinimalSize); var asteroids = GetAsteroids(asteroidCounts, entityMinimalSize); foreach (var info in asteroids) { if (info.EntityType != MySolarSystemEntityEnum.StaticAsteroid && onlyStaticAsteroids) continue; float radius = info.SizeInMeters / 2; float count = info.ObjectCount; float positionOffset = 1.3f; count = (float)Math.Round(count * random.Float(1 - asteroidCountMean, 1 + asteroidCountMean)); if (info.EntityType == MySolarSystemEntityEnum.VoxelAsteroid) { positionOffset = 0.6f; //generate voxels more in center } while (entityCounts[(int)info.EntityType] < count && entityCounts[(int)info.EntityType] < maxEntityCount) { Vector3? pos = FindEntityPosition(prunningStructure, random, radius, positionOffset, asteroidSpacingCoeficient); if (pos.HasValue) { MySolarSystemMapEntity entity = new MySolarSystemMapEntity(sectorPosition, pos.Value, info.SizeInMeters, info.EntityType.ToString(), info.EntityType); entities.Add(entity); if (!MySectorGenerator.IsOutsideSector(pos.Value, radius)) { entityCounts[(int)info.EntityType]++; } BoundingBox bb = new BoundingBox(pos.Value - new Vector3(radius), pos.Value + new Vector3(radius)); prunningStructure.AddProxy(ref bb, new Render.MyRenderObject(null, null), 0); } else entityCounts[(int)info.EntityType]++; } } }
/// <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(); }
/// <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(); }