/// <summary> /// Performs a binary search for intersection using spheres. /// </summary> /// <param name="pointOfObstruction">a point on the capsule's line close to obstruction</param> public static bool Intersects(this Capsule capsule, IMyVoxelMap asteroid, out Vector3?pointOfObstruction, float capsuleLength = -1) { if (capsuleLength < 0) { capsuleLength = capsule.get_length(); } float halfLength = capsuleLength / 2; Vector3 middle = capsule.get_Middle(); BoundingSphereD containingSphere = new BoundingSphereD(middle, halfLength + capsule.Radius); if (!asteroid.GetIntersectionWithSphere(ref containingSphere)) { pointOfObstruction = null; return(false); } if (capsuleLength < 1f) { pointOfObstruction = containingSphere.Center; return(true); } return(Intersects(new Capsule(capsule.P0, middle, capsule.Radius), asteroid, out pointOfObstruction, halfLength) || Intersects(new Capsule(capsule.P1, middle, capsule.Radius), asteroid, out pointOfObstruction, halfLength)); }
/// <summary> /// Tests for path intersection with voxel. /// </summary> /// <returns>True iff path is clear; voxel does not intersect path.</returns> private bool TestVoxel(MyVoxelBase voxel, Capsule path, out Vector3?pointOfObstruction) { if (m_ignoreAsteroid) { m_logger.debugLog("Ignoring asteroid: " + voxel.getBestName()); pointOfObstruction = null; return(true); } Vector3[] intersection = new Vector3[2]; if (!path.IntersectsAABB(voxel, out intersection[0])) { m_logger.debugLog("path does not intersect AABB. " + voxel.getBestName(), Logger.severity.TRACE); pointOfObstruction = null; return(true); } if (!path.get_Reverse().IntersectsAABB(voxel, out intersection[1])) { m_logger.debugLog("Reversed path does not intersect AABB, perhaps it moved? " + voxel.getBestName(), Logger.severity.WARNING); pointOfObstruction = null; return(true); } Capsule testSection = new Capsule(intersection[0], intersection[1], path.Radius); IMyVoxelMap asteroid = voxel as IMyVoxelMap; if (asteroid != null) { if (testSection.Intersects(asteroid, out pointOfObstruction)) { return(false); } } // planet test is done by PlanetChecker m_logger.debugLog("Does not intersect path: " + voxel.getBestName(), Logger.severity.TRACE); pointOfObstruction = null; return(true); }
protected void RefreshCache( ) { IMyVoxelMap voxelMap = (IMyVoxelMap)BackingObject; m_cache = new MyStorageDataCache( ); Vector3I size = voxelMap.Storage.Size; m_cache.Resize(size); // SandboxGameAssemblyWrapper.Instance.GameAction(() => // { voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, 0, Vector3I.Zero, size - 1); //voxelMap.Storage.ReadRange(m_cache, MyStorageDataTypeFlags.Material, Vector3I.Zero, size - 1); // }); foreach (byte materialIndex in m_cache.Data) { try { MyVoxelMaterialDefinition material = MyDefinitionManager.Static.GetVoxelMaterialDefinition(materialIndex); if (material == null) { continue; } if (!m_materialTotals.ContainsKey(material)) { m_materialTotals.Add(material, 1); } else { m_materialTotals[material]++; } } catch (Exception ex) { ApplicationLog.BaseLog.Error(ex); } } }
/// <summary> /// Gets a point outside of an asteroid. /// </summary> /// <param name="startPoint">Where to start the search from, must be inside WorldAABB, can be inside or outside asteroid.</param> /// <param name="direction">Direction from outside asteroid towards inside asteroid</param> /// <param name="buffer">Minimum distance between the voxel and exterior point</param> private Vector3D GetExteriorPoint_Asteroid(Vector3D startPoint, Vector3 direction, float buffer) { IMyVoxelMap voxel = m_targetVoxel as IMyVoxelMap; if (voxel == null) { m_logger.alwaysLog("m_targetVoxel is not IMyVoxelMap: " + m_targetVoxel.getBestName(), Logger.severity.FATAL); throw new InvalidOperationException("m_targetVoxel is not IMyVoxelMap"); } Vector3 v = direction * m_targetVoxel.LocalAABB.GetLongestDim(); Capsule surfaceFinder = new Capsule(startPoint - v, startPoint + v, buffer); Vector3?obstruction; if (surfaceFinder.Intersects(voxel, out obstruction)) { return(obstruction.Value); } else { m_logger.debugLog("Failed to intersect asteroid, using surfaceFinder.P0", Logger.severity.WARNING); return(surfaceFinder.P0); } }
private void ProcessAsteroid(string displayType, string displayName, IMyVoxelMap voxelMap, double distance, BoundingBoxD aabb) { Vector3I min = Vector3I.MaxValue; Vector3I max = Vector3I.MinValue; Vector3I block; Dictionary <byte, long> assetCount = new Dictionary <byte, long>(); // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < voxelMap.Storage.Size.Z; block.Z += 64) { for (block.Y = 0; block.Y < voxelMap.Storage.Size.Y; block.Y += 64) { for (block.X = 0; block.X < voxelMap.Storage.Size.X; block.X += 64) { var cacheSize = new Vector3I(64); var oldCache = new MyStorageData(); oldCache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. voxelMap.Storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); Vector3I p; for (p.Z = 0; p.Z < cacheSize.Z; ++p.Z) { for (p.Y = 0; p.Y < cacheSize.Y; ++p.Y) { for (p.X = 0; p.X < cacheSize.X; ++p.X) { var content = oldCache.Content(ref p); if (content > 0) { min = Vector3I.Min(min, p + block); max = Vector3I.Max(max, p + block + 1); var material = oldCache.Material(ref p); if (assetCount.ContainsKey(material)) { assetCount[material] += content; } else { assetCount.Add(material, content); } } } } } } } } var assetNameCount = new Dictionary <string, long>(); foreach (var kvp in assetCount) { var name = MyDefinitionManager.Static.GetVoxelMaterialDefinition(kvp.Key).Id.SubtypeName; if (assetNameCount.ContainsKey(name)) { assetNameCount[name] += kvp.Value; } else { assetNameCount.Add(name, kvp.Value); } } assetNameCount = assetNameCount.OrderByDescending(e => e.Value).ToDictionary(kvp => kvp.Key, kvp => kvp.Value); var sum = assetNameCount.Values.Sum(); var ores = new StringBuilder(); foreach (var kvp in assetNameCount) { ores.AppendFormat("{0} {1:N} {2:P}\r\n", kvp.Key, (double)kvp.Value / 255, (double)kvp.Value / (double)sum); } var contentBox = new BoundingBoxD(voxelMap.PositionLeftBottomCorner + min, voxelMap.PositionLeftBottomCorner + max); var description = string.Format("Distance: {0:N}\r\nSize: {1}\r\nBoundingBox Center: [X:{2:N} Y:{3:N} Z:{4:N}]\r\n\r\nContent Size:{5}\r\nLOD0 Content Center: [X:{6:N} Y:{7:N} Z:{8:N}]\r\n\r\nMaterial Mass Percent\r\n{9}", distance, voxelMap.Storage.Size, aabb.Center.X, aabb.Center.Y, aabb.Center.Z, max - min, contentBox.Center.X, contentBox.Center.Y, contentBox.Center.Z, ores); MyAPIGateway.Utilities.ShowMissionScreen(string.Format("ID {0}:", displayType), string.Format("'{0}'", displayName), " ", description, null, "OK"); }
private static Dictionary <long, long> ProcessAsteroidOwnership() { Dictionary <long, long> result = new Dictionary <long, long>(); HashSet <IMyEntity> entities = new HashSet <IMyEntity>(); MyAPIGateway.Entities.GetEntities(entities); foreach (IMyEntity entity in entities) { if (!(entity is IMyVoxelMap)) { continue; } if (!entity.Save) { continue; } IMyVoxelMap voxel = (IMyVoxelMap)entity; BoundingSphereD sphere = new BoundingSphereD(entity.GetPosition(), 500); // Size of sphere around Roid List <IMyEntity> blocks = MyAPIGateway.Entities.GetEntitiesInSphere(ref sphere); Dictionary <long, int> asteroidScore = new Dictionary <long, int>(); foreach (IMyEntity block in blocks) { if (block is IMyCubeBlock) { IMyCubeBlock cube = (IMyCubeBlock)block; if (!(cube.GetTopMostParent() is IMyCubeGrid)) { continue; } IMyCubeGrid parent = (IMyCubeGrid)cube.GetTopMostParent(); if (!parent.IsStatic) { continue; } if (cube.OwnerId != 0 && TestBeacon(cube)) // Test Valid Beacon. { if (!asteroidScore.ContainsKey(cube.OwnerId)) { asteroidScore.Add(cube.OwnerId, 0); } asteroidScore[cube.OwnerId] = asteroidScore[cube.OwnerId] + 1; } } } long asteroidOwner = asteroidScore.OrderBy(x => x.Value).Where(x => x.Value > 0).Select(x => x.Key).FirstOrDefault(); if (asteroidOwner != 0) { MyObjectBuilder_Checkpoint.PlayerItem item = PlayerMap.Instance.GetPlayerItemFromPlayerId(asteroidOwner); //Console.WriteLine(string.Format("Owner of asteroid at: {0} is {1}", General.Vector3DToString(entity.GetPosition()), item.Name)); result.Add(entity.EntityId, asteroidOwner); } } return(result); }
public VoxelData(Ingame.IMyOreDetector oreDetector, IMyVoxelMap voxel, float maxRange) { this.m_logger = new Logger(GetType().Name, () => oreDetector.CubeGrid.DisplayName, () => oreDetector.DisplayNameText, () => voxel.ToString()); this.m_oreDetector = oreDetector; this.m_voxel = voxel; this.m_storage.Resize(new Vector3I(QUERY_STEP, QUERY_STEP, QUERY_STEP)); this.m_maxRange = maxRange; m_logger.debugLog("Created for voxel at " + voxel.PositionLeftBottomCorner, "VoxelData()"); }
/// <summary> /// Find the closest ore to position that matches one of the oreType /// </summary> /// <param name="position">The position to search near</param> /// <param name="oreType">The types of ore to search for</param> /// <param name="orePosition">The postion of the ore that was found</param> /// <param name="voxel">The voxel map that contains the ore that was found</param> /// <param name="oreName">The name of the ore that was found</param> /// <returns>True iff an ore was found</returns> public bool FindClosestOre(Vector3D position, byte[] oreType, out Vector3D orePosition, out IMyVoxelMap voxel, out string oreName) { IOrderedEnumerable<IMyVoxelMap> sortedByDistance; using (l_voxelDate.AcquireExclusiveUsing()) sortedByDistance = m_voxelData.Keys.OrderBy(map => Vector3.DistanceSquared(position, map.GetPosition())); foreach (IMyVoxelMap map in sortedByDistance) { VoxelData data; using (l_voxelDate.AcquireSharedUsing()) data = m_voxelData[map]; //Vector3I myVoxelCoord; MyVoxelCoordSystems.WorldPositionToVoxelCoord(map.PositionLeftBottomCorner, ref position, out myVoxelCoord); m_logger.debugLog("PositionLeftBottomCorner: " + map.PositionLeftBottomCorner + ", pos: " + position, "FindClosestOre()"); //Vector3D closest; byte foundOreType; if (data.GetClosest(oreType, ref position, out orePosition, out foundOreType)) { oreName = MyDefinitionManager.Static.GetVoxelMaterialDefinition(foundOreType).MinedOre; //MyVoxelCoordSystems.VoxelCoordToWorldPosition(map.PositionLeftBottomCorner, ref closest, out orePosition); m_logger.debugLog("PositionLeftBottomCorner: " + map.PositionLeftBottomCorner + ", worldPosition: " + orePosition, "FindClosestOre()"); voxel = map; return true; } } orePosition = Vector3D.Zero; voxel = null; oreName = null; return false; }
/// <summary> /// Test if it is safe for the grid to rotate. /// </summary> /// <param name="axis">Normalized axis of rotation in world space.</param> /// <returns>True iff the path is clear.</returns> private bool in_TestRotate(Vector3 axis) { IMyCubeGrid myGrid = m_block.CubeGrid; Vector3 centreOfMass = myGrid.Physics.CenterOfMassWorld; float longestDim = myGrid.GetLongestDim(); // calculate height Matrix toMyLocal = myGrid.WorldMatrixNormalizedInv; Vector3 myLocalCoM = Vector3.Transform(centreOfMass, toMyLocal); Vector3 myLocalAxis = Vector3.Transform(axis, toMyLocal.GetOrientation()); Vector3 myLocalCentre = myGrid.LocalAABB.Center; // CoM may not be on ship (it now considers mass from attached grids) Ray upper = new Ray(myLocalCentre + myLocalAxis * longestDim * 2f, -myLocalAxis); float? upperBound = myGrid.LocalAABB.Intersects(upper); if (!upperBound.HasValue) { Log.AlwaysLog("Math fail, upperBound does not have a value", Logger.severity.FATAL); } Ray lower = new Ray(myLocalCentre - myLocalAxis * longestDim * 2f, myLocalAxis); float?lowerBound = myGrid.LocalAABB.Intersects(lower); if (!lowerBound.HasValue) { Log.AlwaysLog("Math fail, lowerBound does not have a value", Logger.severity.FATAL); } //Log.DebugLog("LocalAABB: " + myGrid.LocalAABB + ", centre: " + myLocalCentre + ", axis: " + myLocalAxis + ", longest dimension: " + longestDim + ", upper ray: " + upper + ", lower ray: " + lower); float height = longestDim * 4f - upperBound.Value - lowerBound.Value; float furthest = 0f; foreach (IMyCubeGrid grid in AttachedGrid.AttachedGrids(myGrid, Attached.AttachedGrid.AttachmentKind.Physics, true)) { CubeGridCache cache = CubeGridCache.GetFor(grid); if (cache == null) { return(false); } foreach (Vector3I cell in cache.OccupiedCells()) { Vector3 rejection = Vector3.Reject(cell * myGrid.GridSize, myLocalAxis); float cellDistSquared = Vector3.DistanceSquared(myLocalCoM, rejection); if (cellDistSquared > furthest) { furthest = cellDistSquared; } } } float length = (float)Math.Sqrt(furthest) + myGrid.GridSize; //Log.DebugLog("height: " + height + ", length: " + length); BoundingSphereD surroundingSphere = new BoundingSphereD(centreOfMass, Math.Max(length, height) * MathHelper.Sqrt2); m_obstructions.Clear(); MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref surroundingSphere, m_obstructions); LineSegment axisSegment = new LineSegment(); m_closestPlanet = null; foreach (MyEntity entity in m_collector.Invoke(m_obstructions)) { if (entity is IMyVoxelBase) { IMyVoxelMap voxel = entity as IMyVoxelMap; if (voxel != null) { if (voxel.GetIntersectionWithSphere(ref surroundingSphere)) { Log.DebugLog("Too close to " + voxel.getBestName() + ", CoM: " + centreOfMass.ToGpsTag("Centre of Mass") + ", required distance: " + surroundingSphere.Radius); ObstructingEntity = voxel; return(false); } continue; } if (m_closestPlanet == null) { MyPlanet planet = entity as MyPlanet; if (planet == null) { continue; } double distToPlanetSq = Vector3D.DistanceSquared(centreOfMass, planet.PositionComp.GetPosition()); if (distToPlanetSq < planet.MaximumRadius * planet.MaximumRadius) { m_closestPlanet = planet; if (m_planetObstruction) { Log.DebugLog("planet blocking"); ObstructingEntity = m_closestPlanet; return(false); } } } continue; } IMyCubeGrid grid = entity as IMyCubeGrid; if (grid != null) { Matrix toLocal = grid.WorldMatrixNormalizedInv; Vector3 localAxis = Vector3.Transform(axis, toLocal.GetOrientation()); Vector3 localCentre = Vector3.Transform(centreOfMass, toLocal); axisSegment.From = localCentre - localAxis * height; axisSegment.To = localCentre + localAxis * height; CubeGridCache cache = CubeGridCache.GetFor(grid); if (cache == null) { return(false); } foreach (Vector3I cell in cache.OccupiedCells()) { if (axisSegment.PointInCylinder(length, cell * grid.GridSize)) { Log.DebugLog("axis segment: " + axisSegment.From + " to " + axisSegment.To + ", radius: " + length + ", hit " + grid.nameWithId() + " at " + cell); ObstructingEntity = grid; return(false); } } continue; } Log.DebugLog("No tests for object: " + entity.getBestName(), Logger.severity.INFO); ObstructingEntity = entity; return(false); } MyAPIGateway.Utilities.TryInvokeOnGameThread(TestPlanet); ObstructingEntity = null; return(true); }
private void ProcessAsteroid(string displayType, string displayName, IMyVoxelMap voxelMap, double distance, BoundingBoxD aabb) { Vector3I min = Vector3I.MaxValue; Vector3I max = Vector3I.MinValue; Vector3I block; Dictionary<byte, long> assetCount = new Dictionary<byte, long>(); // read the asteroid in chunks of 64 to avoid the Arithmetic overflow issue. for (block.Z = 0; block.Z < voxelMap.Storage.Size.Z; block.Z += 64) for (block.Y = 0; block.Y < voxelMap.Storage.Size.Y; block.Y += 64) for (block.X = 0; block.X < voxelMap.Storage.Size.X; block.X += 64) { var cacheSize = new Vector3I(64); var oldCache = new MyStorageDataCache(); oldCache.Resize(cacheSize); // LOD1 is not detailed enough for content information on asteroids. voxelMap.Storage.ReadRange(oldCache, MyStorageDataTypeFlags.ContentAndMaterial, 0, block, block + cacheSize - 1); Vector3I p; for (p.Z = 0; p.Z < cacheSize.Z; ++p.Z) for (p.Y = 0; p.Y < cacheSize.Y; ++p.Y) for (p.X = 0; p.X < cacheSize.X; ++p.X) { var content = oldCache.Content(ref p); if (content > 0) { min = Vector3I.Min(min, p + block); max = Vector3I.Max(max, p + block + 1); var material = oldCache.Material(ref p); if (assetCount.ContainsKey(material)) assetCount[material] += content; else assetCount.Add(material, content); } } } var assetNameCount = new Dictionary<string, long>(); foreach (var kvp in assetCount) { var name = MyDefinitionManager.Static.GetVoxelMaterialDefinition(kvp.Key).Id.SubtypeName; if (assetNameCount.ContainsKey(name)) { assetNameCount[name] += kvp.Value; } else { assetNameCount.Add(name, kvp.Value); } } var sum = assetNameCount.Values.Sum(); var ores = new StringBuilder(); foreach (var kvp in assetNameCount) ores.AppendFormat("{0} {1:N} {2:P}\r\n", kvp.Key, (double)kvp.Value / 255, (double)kvp.Value / (double)sum); var contentBox = new BoundingBoxD(voxelMap.PositionLeftBottomCorner + min, voxelMap.PositionLeftBottomCorner + max); var description = string.Format("Distance: {0:N}\r\nSize: {1}\r\nBoundingBox Center: [X:{2:N} Y:{3:N} Z:{4:N}]\r\n\r\nContent Size:{5}\r\nLOD0 Content Center: [X:{6:N} Y:{7:N} Z:{8:N}]\r\n\r\nMaterial Mass Percent\r\n{9}", distance, voxelMap.Storage.Size, aabb.Center.X, aabb.Center.Y, aabb.Center.Z, max - min, contentBox.Center.X, contentBox.Center.Y, contentBox.Center.Z, ores); MyAPIGateway.Utilities.ShowMissionScreen(string.Format("ID {0}:", displayType), string.Format("'{0}'", displayName), " ", description, null, "OK"); }
/// <summary> /// Performs a binary search for intersection using spheres. /// </summary> /// <param name="pointOfObstruction">a point on the capsule's line close to obstruction</param> public static bool Intersects(this Capsule capsule, IMyVoxelMap asteroid, out Vector3? pointOfObstruction, float capsuleLength = -1) { if (capsuleLength < 0) capsuleLength = capsule.get_length(); float halfLength = capsuleLength / 2; Vector3 middle = capsule.get_Middle(); BoundingSphereD containingSphere = new BoundingSphereD(middle, halfLength + capsule.Radius); if (!asteroid.GetIntersectionWithSphere(ref containingSphere)) { pointOfObstruction = null; return false; } if (capsuleLength < 1f) { pointOfObstruction = containingSphere.Center; return true; } return Intersects(new Capsule(capsule.P0, middle, capsule.Radius), asteroid, out pointOfObstruction, halfLength) || Intersects(new Capsule(capsule.P1, middle, capsule.Radius), asteroid, out pointOfObstruction, halfLength); }
public static void CheckAndSendVoxels( ) { if (m_voxelCheck) { return; } m_voxelCheck = true; try { DateTime start = DateTime.Now; HashSet <IMyEntity> entities = new HashSet <IMyEntity>( ); List <IMyPlayer> players = new List <IMyPlayer>( ); try { MyAPIGateway.Entities.GetEntities(entities); MyAPIGateway.Players.GetPlayers(players); } catch { Essentials.Log.Info("Entity list busy, skipping check"); return; } HashSet <Tuple <ulong, IMyEntity> > voxelsToSend = new HashSet <Tuple <ulong, IMyEntity> >( ); foreach (IMyEntity entity in entities) { if (!(entity is IMyVoxelMap)) { continue; } IMyVoxelMap voxel = (IMyVoxelMap)entity; foreach (IMyPlayer player in players) { double distance = 0d; if (Entity.GetDistanceBetweenPointAndPlayer(entity.GetPosition( ), player, out distance)) { if (!m_userVoxels.ContainsKey(player.SteamUserId)) { m_userVoxels.Add(player.SteamUserId, new HashSet <long>( )); } HashSet <long> voxels = m_userVoxels[player.SteamUserId]; if (distance < PluginSettings.Instance.DynamicVoxelDistance && !voxels.Contains(entity.EntityId)) { voxelsToSend.Add(new Tuple <ulong, IMyEntity>(player.SteamUserId, entity)); } } } } if (voxelsToSend.Count > 0) { Wrapper.GameAction(() => { foreach (Tuple <ulong, IMyEntity> p in voxelsToSend) { SendVoxel(p.Item1, p.Item2); } }); } if ((DateTime.Now - start).TotalSeconds > 1) { Essentials.Log.Debug("CheckAndSendVoxels(): {0}ms", (DateTime.Now - start).TotalMilliseconds); } } catch (Exception ex) { Essentials.Log.Error(ex, "Check and send voxels"); } finally { m_voxelCheck = false; } }
private static void SendVoxelData(ulong steamId, IMyEntity voxel) { try { IMyVoxelMap voxelMap = (IMyVoxelMap)voxel; byte[] voxelData; voxelMap.Storage.Save(out voxelData); VoxelHeaderData header = new VoxelHeaderData( ); header.EntityId = voxel.EntityId; header.HalfExtent = voxelMap.Storage.Size / 2; header.Position = voxel.GetPosition( ); header.Name = voxelMap.StorageName; header.DataLength = voxelData.Length; string headerString = MyAPIGateway.Utilities.SerializeToXML <VoxelHeaderData>(header); ushort length = (ushort)headerString.Length; byte[] headerData = new byte[2 + headerString.Length]; headerData[0] = (byte)length; headerData[1] = (byte)(length >> 8); for (int r = 0; r < headerString.Length; r++) { headerData[r + 2] = (byte)headerString[r]; } Essentials.Log.Debug("Sending Voxel Header Data: {0} / {1} - {2} ({3})", voxelData.Length, headerData.Length, steamId, voxel.GetPosition( )); Communication.SendDataMessage(steamId, Communication.DataMessageType.VoxelHeader, headerData); int blockSize = 4096; for (ushort r = 0; r < (voxelData.Length / blockSize) + 1; r++) { int partLength = voxelData.Length - (r * blockSize); if (partLength > blockSize) { partLength = blockSize; } byte[] outData = new byte[partLength + 12]; for (int s = 0; s < 8; s++) { outData[s] = (byte)(header.EntityId >> (s * 8)); } for (int s = 0; s < 2; s++) { outData[s + 8] = (byte)(partLength >> (s * 8)); } for (int s = 0; s < 2; s++) { outData[s + 10] = (byte)(r >> (s * 8)); } Buffer.BlockCopy(voxelData, r * blockSize, outData, 12, partLength); Communication.SendDataMessage(steamId, Communication.DataMessageType.VoxelPart, outData); } } catch (Exception ex) { Essentials.Log.Error(ex, "Send voxel data"); } }
public override void UpdateAfterSimulation10() { try { var antenna = (Sandbox.ModAPI.Ingame.IMyTerminalBlock)Entity; var entityBlock = (IMyCubeBlock)Entity; // called multiple times for ships, to be kept up to date. if (antenna.CustomName != null && antenna.CustomName.StartsWith(CustomNameKeyPos, StringComparison.InvariantCultureIgnoreCase)) { var pos = antenna.CubeGrid.GridIntegerToWorld(antenna.Position); //dont really care about the decimal places so cast as int. antenna.SetCustomName(string.Format("{0} [X:{1:N0} Y:{2:N0} Z:{3:N0}]", CustomNameKeyPos, (int)(pos.X), (int)(pos.Y), (int)(pos.Z))); } else if (antenna.CustomName != null && antenna.CustomName.StartsWith(CustomNameKeyDir, StringComparison.InvariantCultureIgnoreCase)) { var orientation = antenna.WorldMatrix.Up; //care about the decimal places as being off a few degrees can be very significant. vector3.tostring is already localized. antenna.SetCustomName(string.Format("{0} [X:{1:N5} Y:{2:N5} Z:{3:N5}]", CustomNameKeyDir, orientation.X, orientation.Y, orientation.Z)); } else if (antenna.CustomName != null && antenna.CustomName.StartsWith(CustomNameKeyProbe, StringComparison.InvariantCultureIgnoreCase)) { antenna.SetCustomName(CustomNameKeyProbe); var pos = antenna.CubeGrid.GridIntegerToWorld(antenna.Position); Vector3 closestpos = Vector3.Zero; float closestdist = float.MaxValue; int i = 0; IMyVoxelMap map = null; for (i = 0; (map = MyAPIGateway.Session.VoxelMaps.GetVoxelMap(i)) != null; i++) { var mappos = map.PositionLeftBottomCorner + map.SizeInMetresHalf; if (Vector3.Distance(mappos, pos) < closestdist) { closestpos = mappos; closestdist = Vector3.Distance(mappos, pos); } } if (closestpos != Vector3.Zero) { var direction = closestpos - pos; direction = Vector3.Normalize(direction); var obj = (MyObjectBuilder_RadioAntenna)entityBlock.GetObjectBuilderCubeBlock(); if (closestdist < 1000 && obj.BroadcastRadius > closestdist) { antenna.SetCustomName(string.Format("{0} Asteroid too close. Distance: {1:N}", CustomNameKeyProbe, closestdist)); } else if (obj.BroadcastRadius > closestdist) { antenna.SetCustomName(string.Format("{0} [X:{1:N5} Y:{2:N5} Z:{3:N5}]", CustomNameKeyProbe, direction.X, direction.Y, direction.Z)); } else { antenna.SetCustomName(string.Format("{0} {1} Broadcast Range: {2:N}", CustomNameKeyProbe, "No asteroids in range. ", obj.BroadcastRadius)); } } else { antenna.SetCustomName(string.Format("{0} {1}", CustomNameKeyProbe, "No asteroids detected.")); } } } catch (Exception) { var antenna = (Sandbox.ModAPI.Ingame.IMyTerminalBlock)Entity; antenna.SetCustomName(string.Format("{0} Error.", CustomNameKeyProbe)); } }
public void Update() { if (_targetHit) { Kill(); return; } // Update velocity due to gravity Vector3D totalGravity = MyParticlesManager.CalculateGravityInPoint(_position); // Does this get affected by artificial grav? If so... cooooool Vector3D naturalGravity = RailgunCore.GetNaturalGravityAtPoint(_position); Vector3D artificialGravity = totalGravity - naturalGravity; _velocity += (naturalGravity * RailgunCore.MyConfig.NaturalGravityMultiplier + artificialGravity * RailgunCore.MyConfig.ArtificialGravityMultiplier) * _tick; // Update direction if velocity has changed if (!_velocity.Equals(_lastVelocity, 1e-3)) { _direction = Vector3D.Normalize(_velocity); } _lastVelocity = _velocity; // Update position _position += _velocity * _tick; var _toOrigin = _position - _origin; //draw tracer line if (_drawTrail && _currentTracerFadeTicks < _maxTracerFadeTicks) { _lineColor *= _trailColorDecayRatio; _currentTracerFadeTicks++; } if (_toOrigin.LengthSquared() > _maxTrajectory * _maxTrajectory) { MyLog.Default.WriteLine(">> Max range hit"); _targetHit = true; _hitPosition = _position; Kill(); if (_shouldExplode) { CreateExplosion(_position, _direction, _explosionRadius, _explosionDamage); } return; } _checkIntersectionIndex = ++_checkIntersectionIndex % 5; if (_checkIntersectionIndex != 0 && _positionChecked) { return; } // Add current position to trajectory list _trajectoryPoints.Add(_position); var to = _position; //_position + 5.0 * _velocity * _tick; var from = _lastPositionChecked; _positionChecked = true; _lastPositionChecked = _position; IHitInfo hitInfo; bool hit = false; if (Vector3D.DistanceSquared(to, from) > 50 * 50) { // Use faster raycast if ray is long enough hit = MyAPIGateway.Physics.CastLongRay(from, to, out hitInfo, true); } else { hit = MyAPIGateway.Physics.CastRay(from, to, out hitInfo, 0); } if (hit) { MyLog.Default.WriteLine(">> Raycast hit"); _hitPosition = hitInfo.Position + -0.5 * _direction; if ((_hitPosition - _origin).LengthSquared() > _minimumArmDistance * _minimumArmDistance) //only explode if beyond arm distance { if (_shouldExplode) { CreateExplosion(_hitPosition, _direction, _explosionRadius, _explosionDamage); } if (_shouldPenetrate) { GetObjectsToPenetrate(_hitPosition, _hitPosition + _direction * _penetrationRange); } _targetHit = true; Kill(); } else { _targetHit = true; _hitPosition = _position; Kill(); } return; } // implied else var line = new LineD(from, to); MyGamePruningStructure.GetVoxelMapsOverlappingRay(ref line, _voxelOverlap); foreach (var result in _voxelOverlap) { MatrixD matrix; MatrixD matrixInv; Vector3 sizeInMetersHalf; MyPlanet planet = result.Element as MyPlanet; IMyVoxelMap voxelMap = result.Element as IMyVoxelMap; if (planet == null && voxelMap == null) { continue; } if (planet != null) { matrix = planet.WorldMatrix; matrixInv = planet.PositionComp.WorldMatrixInvScaled; sizeInMetersHalf = planet.SizeInMetresHalf; } else { matrix = voxelMap.WorldMatrix; matrixInv = voxelMap.PositionComp.WorldMatrixInvScaled; sizeInMetersHalf = new Vector3(voxelMap.Storage.Size) * 0.5f; } Vector3 localTo; Vector3 localFrom; MyVoxelCoordSystems.WorldPositionToLocalPosition(from, matrix, matrixInv, sizeInMetersHalf, out localFrom); MyVoxelCoordSystems.WorldPositionToLocalPosition(to, matrix, matrixInv, sizeInMetersHalf, out localTo); var localLine = new LineD(localFrom, localTo); if (planet != null && ((IMyStorage)(planet.Storage)).Intersect(ref localLine)) { MyLog.Default.WriteLine(">> Railgun projectile hit planet"); _hitPosition = _position; _targetHit = true; Kill(); return; } // This is very broken //if (voxelMap != null && ((IMyStorage)(voxelMap.Storage)).Intersect(ref localLine)) //{ // MyLog.Default.WriteLine(">> Railgun projectile hit voxel"); // _hitPosition = _position; // _targetHit = true; // Kill(); // return; //} } }
/// <summary> /// Test if it is safe for the grid to rotate. /// </summary> /// <param name="axis">Normalized axis of rotation in world space.</param> /// <param name="ignoreAsteroids"></param> /// <returns>True iff the path is clear.</returns> public bool TestRotate(Vector3 axis, bool ignoreAsteroids, out IMyEntity obstruction) { Vector3 centreOfMass = m_grid.Physics.CenterOfMassWorld; float longestDim = m_grid.GetLongestDim(); // calculate height Matrix toMyLocal = m_grid.WorldMatrixNormalizedInv; Vector3 myLocalCoM = Vector3.Transform(centreOfMass, toMyLocal); Vector3 myLocalAxis = Vector3.Transform(axis, toMyLocal.GetOrientation()); Vector3 myLocalCentre = m_grid.LocalAABB.Center; // CoM may not be on ship (it now considers mass from attached grids) Ray upper = new Ray(myLocalCentre + myLocalAxis * longestDim * 2f, -myLocalAxis); float? upperBound = m_grid.LocalAABB.Intersects(upper); if (!upperBound.HasValue) { m_logger.alwaysLog("Math fail, upperBound does not have a value", Logger.severity.FATAL); } Ray lower = new Ray(myLocalCentre - myLocalAxis * longestDim * 2f, myLocalAxis); float?lowerBound = m_grid.LocalAABB.Intersects(lower); if (!lowerBound.HasValue) { m_logger.alwaysLog("Math fail, lowerBound does not have a value", Logger.severity.FATAL); } m_logger.debugLog("LocalAABB: " + m_grid.LocalAABB + ", centre: " + myLocalCentre + ", axis: " + myLocalAxis + ", longest dimension: " + longestDim + ", upper ray: " + upper + ", lower ray: " + lower); float height = longestDim * 4f - upperBound.Value - lowerBound.Value; float furthest = 0f; m_cells.ForEach(cell => { Vector3 rejection = Vector3.Reject(cell * m_grid.GridSize, myLocalAxis); float cellDistSquared = Vector3.DistanceSquared(myLocalCoM, rejection); if (cellDistSquared > furthest) { furthest = cellDistSquared; } }); float length = (float)Math.Sqrt(furthest) + m_grid.GridSize * 0.5f; m_logger.debugLog("height: " + height + ", length: " + length); BoundingSphereD surroundingSphere = new BoundingSphereD(centreOfMass, Math.Max(length, height)); m_obstructions.Clear(); MyGamePruningStructure.GetAllTopMostEntitiesInSphere(ref surroundingSphere, m_obstructions); LineSegment axisSegment = new LineSegment(); ClosestPlanet = MyPlanetExtensions.GetClosestPlanet(centreOfMass); MyAPIGateway.Utilities.TryInvokeOnGameThread(TestPlanet); foreach (MyEntity entity in m_obstructions) { if (PathChecker.collect_Entity(m_grid, entity)) { if (entity is IMyVoxelBase) { if (ignoreAsteroids) { continue; } IMyVoxelMap voxel = entity as IMyVoxelMap; if (voxel != null) { if (voxel.GetIntersectionWithSphere(ref surroundingSphere)) { m_logger.debugLog("Too close to " + voxel.getBestName() + ", CoM: " + centreOfMass.ToGpsTag("Centre of Mass") + ", required distance: " + surroundingSphere.Radius); obstruction = voxel; return(false); } continue; } if (PlanetState != Pathfinder.PathState.No_Obstruction) { m_logger.debugLog("planet blocking"); obstruction = ClosestPlanet; return(false); } continue; } IMyCubeGrid grid = entity as IMyCubeGrid; if (grid != null) { Matrix toLocal = grid.WorldMatrixNormalizedInv; Vector3 localAxis = Vector3.Transform(axis, toLocal.GetOrientation()); Vector3 localCentre = Vector3.Transform(centreOfMass, toLocal); axisSegment.From = localCentre - localAxis * height; axisSegment.To = localCentre + localAxis * height; bool found = false; GridCellCache.GetCellCache(grid).ForEach(cell => { if (axisSegment.PointInCylinder(length, cell * grid.GridSize)) { found = true; return(true); } return(false); }); if (found) { obstruction = grid; return(false); } continue; } m_logger.debugLog("No tests for object: " + entity.getBestName(), Logger.severity.INFO); obstruction = entity; return(false); } } obstruction = null; return(true); }