diff --git a/Sources/Sandbox.Common/ModAPI/Ingame/IMyOreDetector.cs b/Sources/Sandbox.Common/ModAPI/Ingame/IMyOreDetector.cs index 84b88e931..07e501b94 100644 --- a/Sources/Sandbox.Common/ModAPI/Ingame/IMyOreDetector.cs +++ b/Sources/Sandbox.Common/ModAPI/Ingame/IMyOreDetector.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Text; +using VRageMath; namespace Sandbox.ModAPI.Ingame { @@ -9,5 +10,22 @@ public interface IMyOreDetector : IMyFunctionalBlock { float Range {get;} bool BroadcastUsingAntennas {get;} + + /// + ///Returns your own List filled with visible ore markers. + /// + void GetOreMarkers (List outputList); + } + + public struct MyOreMarker + { + public readonly string ElementName; + public readonly Vector3D Location; + + public MyOreMarker (string inputElement, Vector3D inputCoords) + { + this.ElementName = inputElement; + this.Location = inputCoords; + } } } diff --git a/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetector.cs b/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetector.cs index ab3bd438d..81cf9db72 100644 --- a/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetector.cs +++ b/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetector.cs @@ -1,10 +1,13 @@ #region Using +using System.Collections.Generic; + using Sandbox.Common.ObjectBuilders; using Sandbox.Definitions; using Sandbox.Game.Gui; using Sandbox.Game.Multiplayer; using System.Text; +using System.Diagnostics; using Sandbox.Game.EntityComponents; using VRageMath; using Sandbox.ModAPI; @@ -24,13 +27,17 @@ namespace Sandbox.Game.Entities.Cube public class MyOreDetector : MyFunctionalBlock, IMyComponentOwner, IMyOreDetector { private MyOreDetectorDefinition m_definition; + private Dictionary m_closestEachElement = new Dictionary (); //I use the same collection to reduce heap allocations. - MyOreDetectorComponent m_oreDetectorComponent = new MyOreDetectorComponent(); + private MyOreDetectorComponent m_oreDetectorComponent = new MyOreDetectorComponent(); + bool getOreRateLimited; Sync m_broadcastUsingAntennas; public MyOreDetector() { + getOreRateLimited = true; + #if XB1 // XB1_SYNC_NOREFLECTION m_broadcastUsingAntennas = SyncType.CreateAndAddProp(); #endif // XB1 @@ -151,11 +158,14 @@ public override void OnUnregisteredFromGridSystems() public override void UpdateBeforeSimulation100() { + getOreRateLimited = true; + base.UpdateBeforeSimulation100(); if (HasLocalPlayerAccess()) { - m_oreDetectorComponent.Update(PositionComp.GetPosition()); + m_oreDetectorComponent.Update (PositionComp.GetPosition()); } + else { m_oreDetectorComponent.Clear(); @@ -180,8 +190,7 @@ public float Range { m_oreDetectorComponent.DetectionRadius = (value / 100f) * m_definition.MaximumRange; RaisePropertiesChanged(); - } - + } } } @@ -203,5 +212,51 @@ public bool BroadcastUsingAntennas bool ModAPI.Ingame.IMyOreDetector.BroadcastUsingAntennas { get { return m_oreDetectorComponent.BroadcastUsingAntennas; } } float ModAPI.Ingame.IMyOreDetector.Range { get { return Range; } } + + public void GetOreMarkers (List userList) //Imprinting on the reference parameter is cheaper than a return List due to heap allocations. + { + if (getOreRateLimited) + { + getOreRateLimited = false; + userList.Clear(); + Vector3D blockCoordinates = new Vector3D (base.PositionComp.GetPosition()); + m_oreDetectorComponent.Update (blockCoordinates, false); + + foreach (MyEntityOreDeposit deposit in m_oreDetectorComponent.DetectedDeposits) + { + for (int i = 0; i < deposit.Materials.Count; i++) + { + MyEntityOreDeposit.Data depositData = deposit.Materials[i]; + Vector3D cachesPosition = new Vector3D(); + depositData.ComputeWorldPosition (deposit.VoxelMap, out cachesPosition); + string cachesElement = deposit.Materials[i].Material.MinedOre; + + if (m_closestEachElement.ContainsKey (cachesElement) == false) + { + m_closestEachElement.Add (cachesElement, cachesPosition); //I decided Dictionary was the best way to group nearest markers since all I need is two variables. + } + + else + { + Vector3D difference = blockCoordinates - cachesPosition; + Vector3D previousDifference = m_closestEachElement[cachesElement] - cachesPosition; + float distanceToCache = (float) difference.LengthSquared(); //explicitly converted in order to estimate the actual hud markers as close as possible. + float previousDistance = (float) previousDifference.LengthSquared(); + + if (distanceToCache < previousDistance) + { + m_closestEachElement[cachesElement] = cachesPosition; //I only want the nearest of each element. + } + } + } + } + + foreach (KeyValuePair marker in m_closestEachElement) + { + userList.Add (new ModAPI.Ingame.MyOreMarker (marker.Key, marker.Value)); + } + m_closestEachElement.Clear(); + } + } } } diff --git a/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetectorComponent.cs b/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetectorComponent.cs index 9e60c98df..9b6d166c5 100644 --- a/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetectorComponent.cs +++ b/Sources/Sandbox.Game/Game/Entities/Blocks/MyOreDetectorComponent.cs @@ -180,6 +180,8 @@ class MyOreDetectorComponent private static readonly List m_inRangeCache = new List(); private static readonly List m_notInRangeCache = new List(); + public HashSet DetectedDeposits { get; private set; } + public delegate bool CheckControlDelegate(); public float DetectionRadius { get; set; } @@ -194,34 +196,41 @@ public MyOreDetectorComponent() DetectionRadius = 50; SetRelayedRequest = false; BroadcastUsingAntennas = false; + DetectedDeposits = new HashSet (); } public bool SetRelayedRequest { get; set; } - public void Update(Vector3D position, bool checkControl = true) - { - Clear(); - - if (!SetRelayedRequest && checkControl && !OnCheckControl()) + public void Update (Vector3D position, bool checkControl = true) + { + if (checkControl == true) { - m_depositGroupsByEntity.Clear(); - return; + Clear(); + + if (!SetRelayedRequest && !OnCheckControl()) + { + //m_depositGroupsByEntity.Clear(); I commented this out because it, in some states, causes DetectedDeposits to ouput incorrectly as empty. m_depositGroupsByEntity seems to take more than one run to fully load. + return; + } + SetRelayedRequest = false; } - SetRelayedRequest = false; - - var sphere = new BoundingSphereD(position, DetectionRadius); - MyGamePruningStructure.GetAllVoxelMapsInSphere(ref sphere, m_inRangeCache); + else + { + DetectedDeposits.Clear(); //Deposits needs to remove duplicates but also leave the HUD unchanged. + } + var sphere = new BoundingSphereD (position, DetectionRadius); + MyGamePruningStructure.GetAllVoxelMapsInSphere (ref sphere, m_inRangeCache); { // Find voxel maps which went out of range and then remove them. foreach (var voxelMap in m_depositGroupsByEntity.Keys) { - if (!m_inRangeCache.Contains(voxelMap)) - m_notInRangeCache.Add(voxelMap); + if (!m_inRangeCache.Contains (voxelMap)) + m_notInRangeCache.Add (voxelMap); } foreach (var notInRange in m_notInRangeCache) { - m_depositGroupsByEntity.Remove(notInRange); + m_depositGroupsByEntity.Remove (notInRange); } m_notInRangeCache.Clear(); } @@ -229,8 +238,8 @@ public void Update(Vector3D position, bool checkControl = true) { // Add voxel maps which came into range. foreach (var voxelMap in m_inRangeCache) { - if (!m_depositGroupsByEntity.ContainsKey(voxelMap)) - m_depositGroupsByEntity.Add(voxelMap, new MyOreDepositGroup(voxelMap)); + if (!m_depositGroupsByEntity.ContainsKey (voxelMap)) + m_depositGroupsByEntity.Add (voxelMap, new MyOreDepositGroup (voxelMap)); } m_inRangeCache.Clear(); } @@ -240,18 +249,26 @@ public void Update(Vector3D position, bool checkControl = true) { var voxelMap = entry.Key; var group = entry.Value; - group.UpdateDeposits(ref sphere); + group.UpdateDeposits (ref sphere); foreach (var deposit in group.Deposits) { if (deposit != null) - { - MyHud.OreMarkers.RegisterMarker(deposit); + { + switch (checkControl) //the method has been divided into these two choices because previously, oremarkers could not be fetched without a radio antenna. + { + case true: + MyHud.OreMarkers.RegisterMarker (deposit); + break; + + case false: + DetectedDeposits.Add (deposit); + break; + } } } - } - - m_inRangeCache.Clear(); + } + m_inRangeCache.Clear(); } public void Clear() @@ -261,11 +278,13 @@ public void Clear() foreach (var deposit in group.Deposits) { if (deposit != null) - MyHud.OreMarkers.UnregisterMarker(deposit); + { + MyHud.OreMarkers.UnregisterMarker (deposit); + } } - } + } + DetectedDeposits.Clear(); } - } /// diff --git a/Sources/Sandbox.Game/Game/Entities/Blocks/MyRadioAntenna.cs b/Sources/Sandbox.Game/Game/Entities/Blocks/MyRadioAntenna.cs index fca2e9404..daa92f557 100644 --- a/Sources/Sandbox.Game/Game/Entities/Blocks/MyRadioAntenna.cs +++ b/Sources/Sandbox.Game/Game/Entities/Blocks/MyRadioAntenna.cs @@ -350,7 +350,7 @@ public override List GetHudParams(bool allowBlink) MyOreDetectorComponent oreDetector; if (oreDetectorOwner.GetComponent(out oreDetector) && oreDetector.BroadcastUsingAntennas) { - oreDetector.Update(terminalBlock.PositionComp.GetPosition(), false); + oreDetector.Update (terminalBlock.PositionComp.GetPosition(), false); oreDetector.SetRelayedRequest = true; } } diff --git a/Sources/Sandbox.Game/Game/Weapons/Guns/MyHandDrill.cs b/Sources/Sandbox.Game/Game/Weapons/Guns/MyHandDrill.cs index b8fcfdbf4..6599253d5 100644 --- a/Sources/Sandbox.Game/Game/Weapons/Guns/MyHandDrill.cs +++ b/Sources/Sandbox.Game/Game/Weapons/Guns/MyHandDrill.cs @@ -391,7 +391,7 @@ public override void UpdateBeforeSimulation100() { base.UpdateBeforeSimulation100(); m_drillBase.UpdateSoundEmitter(); - m_oreDetectorBase.Update(PositionComp.GetPosition()); + m_oreDetectorBase.Update (PositionComp.GetPosition()); } public void UpdateSoundEmitter()