From a978438ab1e5cd24ecf5ef222817d744531c4a74 Mon Sep 17 00:00:00 2001 From: thorwin99 Date: Sun, 12 Feb 2023 22:06:35 +0100 Subject: [PATCH] Added caching to the star system data structure for faster access to the objects whithin the star system. This will allow the plugin to skip a traversal of the whole star system tree and directly access objects by type, id, or just all at once in a set --- .../AsteroidRing/MyAsteroidRingProvider.cs | 1 + .../MyStarSystemGenerator.Networking.cs | 18 ++-- .../Generator/MyStarSystemGenerator.cs | 75 +++++++++-------- .../MyProceduralAsteroidsModule.cs | 7 +- .../MyObjectBuilder_SystemData.cs | 82 +++++++++++++++---- 5 files changed, 118 insertions(+), 65 deletions(-) diff --git a/SEWorldGenPlugin/Generator/AsteroidObjects/AsteroidRing/MyAsteroidRingProvider.cs b/SEWorldGenPlugin/Generator/AsteroidObjects/AsteroidRing/MyAsteroidRingProvider.cs index fd74553..126ba0b 100644 --- a/SEWorldGenPlugin/Generator/AsteroidObjects/AsteroidRing/MyAsteroidRingProvider.cs +++ b/SEWorldGenPlugin/Generator/AsteroidObjects/AsteroidRing/MyAsteroidRingProvider.cs @@ -80,6 +80,7 @@ public override MySystemAsteroids GenerateInstance(int systemIndex, in MySystemO asteroidObject.CenterPosition = Vector3D.Zero; asteroidObject.AsteroidSize = new MySerializableMinMax(256, 1024); asteroidObject.AsteroidTypeName = GetTypeName(); + asteroidObject.ParentId = parent != null ? parent.Id : Guid.Empty; MyAsteroidRingData belt = new MyAsteroidRingData(); belt.AngleDegrees = Vector3D.Zero; diff --git a/SEWorldGenPlugin/Generator/MyStarSystemGenerator.Networking.cs b/SEWorldGenPlugin/Generator/MyStarSystemGenerator.Networking.cs index 3ac2e26..ac7f183 100644 --- a/SEWorldGenPlugin/Generator/MyStarSystemGenerator.Networking.cs +++ b/SEWorldGenPlugin/Generator/MyStarSystemGenerator.Networking.cs @@ -98,8 +98,8 @@ private static void SendAddSystemObjectServer(MySystemObject obj, Guid parentId, var parent = Static.StarSystem.GetById(parentId); if (parent != null) { - parent.ChildObjects.Add(obj); obj.ParentId = parentId; + Static.StarSystem.Add(obj); PluginEventHandler.Static.RaiseStaticEvent(BroadcastObjectAdded, obj, callbackId, senderId); callback?.Invoke(true); } @@ -107,8 +107,8 @@ private static void SendAddSystemObjectServer(MySystemObject obj, Guid parentId, { if(Static.StarSystem.CenterObject != null) { - Static.StarSystem.CenterObject.ChildObjects.Add(obj); obj.ParentId = Static.StarSystem.CenterObject.Id; + Static.StarSystem.Add(obj); PluginEventHandler.Static.RaiseStaticEvent(BroadcastObjectAdded, obj, callbackId, senderId); callback?.Invoke(true); } @@ -121,18 +121,18 @@ private static void SendAddSystemObjectServer(MySystemObject obj, Guid parentId, sun.Type = MySystemObjectType.EMPTY; sun.ParentId = Guid.Empty; - Static.StarSystem.CenterObject = sun; + Static.StarSystem.Add(sun); obj.ParentId = sun.Id; - Static.StarSystem.CenterObject.ChildObjects.Add(obj); + Static.StarSystem.Add(obj); PluginEventHandler.Static.RaiseStaticEvent(BroadcastObjectAdded, obj, callbackId, senderId); callback?.Invoke(true); } else { - Static.StarSystem.CenterObject = obj; obj.ParentId = Guid.Empty; + Static.StarSystem.Add(obj); PluginEventHandler.Static.RaiseStaticEvent(BroadcastObjectAdded, obj, callbackId, senderId); callback?.Invoke(true); } @@ -168,7 +168,7 @@ private static void BroadcastObjectAdded(MySystemObject obj, uint callbackId, ul if(!Static.StarSystem.Contains(obj.Id) && parent != null) { - parent.ChildObjects.Add(obj); + Static.StarSystem.Add(obj); callback?.Invoke(true); } else if(obj.ParentId == Guid.Empty && Static.StarSystem.CenterObject == null) @@ -180,16 +180,16 @@ private static void BroadcastObjectAdded(MySystemObject obj, uint callbackId, ul sun.Type = MySystemObjectType.EMPTY; sun.ParentId = Guid.Empty; - Static.StarSystem.CenterObject = sun; + Static.StarSystem.Add(sun); obj.ParentId = sun.Id; - Static.StarSystem.CenterObject.ChildObjects.Add(obj); + Static.StarSystem.Add(obj); callback?.Invoke(true); } else { - Static.StarSystem.CenterObject = obj; + Static.StarSystem.Add(obj); callback?.Invoke(true); } } diff --git a/SEWorldGenPlugin/Generator/MyStarSystemGenerator.cs b/SEWorldGenPlugin/Generator/MyStarSystemGenerator.cs index a601122..870123d 100644 --- a/SEWorldGenPlugin/Generator/MyStarSystemGenerator.cs +++ b/SEWorldGenPlugin/Generator/MyStarSystemGenerator.cs @@ -12,6 +12,7 @@ using SEWorldGenPlugin.Utilities; using System; using System.Collections.Generic; +using System.Security.Cryptography; using VRage.Game; using VRage.Game.Components; using VRage.Game.Entity; @@ -128,7 +129,7 @@ public override void Init(MyObjectBuilder_SessionComponent sessionComponent) if (StarSystem.Count() <= 0 && MySettingsSession.Static.Settings.GeneratorSettings.SystemGenerator != SystemGenerationMethod.NONE) { - StarSystem = GenerateNewStarSystem(); + GenerateNewStarSystem(); } MyPluginLog.Log("Initializing Star system generator completed"); @@ -155,19 +156,16 @@ public override void LoadData() if(StarSystem != null && StarSystem.CenterObject != null) { - foreach (var obj in StarSystem.GetAll()) + foreach (var obj in StarSystem.GetAllByType(MySystemObjectType.ASTEROIDS)) { - if (obj.Type == MySystemObjectType.ASTEROIDS) - { - var asteroid = obj as MySystemAsteroids; + var asteroid = obj as MySystemAsteroids; - if (!MyAsteroidObjectsManager.Static.AsteroidObjectProviders.TryGetValue(asteroid.AsteroidTypeName, out var provider)) continue; + if (!MyAsteroidObjectsManager.Static.AsteroidObjectProviders.TryGetValue(asteroid.AsteroidTypeName, out var provider)) continue; - if (!provider.TryLoadObject(asteroid)) - { - MyPluginLog.Log("No data found associated with asteroid object " + asteroid.DisplayName + " (" + asteroid.Id + "), Removing it.", LogLevel.WARNING); - StarSystem.Remove(asteroid.Id); - } + if (!provider.TryLoadObject(asteroid)) + { + MyPluginLog.Log("No data found associated with asteroid object " + asteroid.DisplayName + " (" + asteroid.Id + "), Removing it.", LogLevel.WARNING); + StarSystem.Remove(asteroid.Id); } } } @@ -266,12 +264,12 @@ private void AddAllPersistentGps() /// world settings. /// /// - private MyObjectBuilder_SystemData GenerateNewStarSystem() + private void GenerateNewStarSystem() { MyPluginLog.Log("Generating a new Solar system ..."); int seed = MySession.Static.Settings.ProceduralSeed + Guid.NewGuid().GetHashCode(); - MyObjectBuilder_SystemData system = new MyObjectBuilder_SystemData(); + StarSystem = new MyObjectBuilder_SystemData(); var settings = MySettingsSession.Static.Settings.GeneratorSettings; @@ -316,18 +314,21 @@ private MyObjectBuilder_SystemData GenerateNewStarSystem() sun.SubtypeId = sunDef.Id.SubtypeId.String; sun.DisplayName = sunDef.Id.SubtypeId.String; sun.Diameter = CalculatePlanetDiameter(sunDef) * 2; - sun.ChildObjects = new HashSet(); sun.Generated = false; sun.Type = MySystemObjectType.PLANET; - system.CenterObject = sun; + StarSystem.Add(sun); currentOrbitDistance += (long)sun.Diameter * 2 + (long)sunDef.AtmosphereHeight; } else { - system.CenterObject = new MySystemObject(); - system.CenterObject.Type = MySystemObjectType.EMPTY; - system.CenterObject.DisplayName = "System center"; + MySystemObject center; + + center = new MySystemObject(); + center.Type = MySystemObjectType.EMPTY; + center.DisplayName = "System center"; + + StarSystem.Add(center); } while(planetCount > 0 || asteroidObjectCount > 0) @@ -335,13 +336,11 @@ private MyObjectBuilder_SystemData GenerateNewStarSystem() currentOrbitDistance += MyRandom.Instance.Next(orbitDistances.Min, orbitDistances.Max); //Maybe rework to override orbit distance, so all objects fit - if (worldSize >= 0 && currentOrbitDistance >= worldSize) return system; - - MySystemObject obj = null; + if (worldSize >= 0 && currentOrbitDistance >= worldSize) return; if (asteroidObjectCount <= 0 || (MyRandom.Instance.NextDouble() <= planetProb && planetCount > 0)) // Generate planet { - obj = GeneratePlanet(currentPlanetIndex++, Math.Sin((system.Count() - 1) * Math.PI / systemSize), currentOrbitDistance); + GeneratePlanet(currentPlanetIndex++, Math.Sin((StarSystem.Count() - 1) * Math.PI / systemSize), currentOrbitDistance, StarSystem.CenterObject.Id); planetCount--; } else if (asteroidObjectCount > 0) // Generate asteroid object @@ -365,34 +364,31 @@ private MyObjectBuilder_SystemData GenerateNewStarSystem() currentAsteroidIndices.Add(provider.GetTypeName(), 0); } - obj = provider.GenerateInstance(currentAsteroidIndices[provider.GetTypeName()]++, null, currentOrbitDistance); + MySystemAsteroids roid = provider.GenerateInstance(currentAsteroidIndices[provider.GetTypeName()]++, StarSystem.CenterObject, currentOrbitDistance); + roid.ParentId = StarSystem.CenterObject.Id; + + if (roid == null) continue; - if (obj == null) continue; + roid.AsteroidTypeName = provider.GetTypeName(); - (obj as MySystemAsteroids).AsteroidTypeName = provider.GetTypeName(); + StarSystem.Add(roid); asteroidObjectCount--; } - if (obj == null) continue; - - obj.ParentId = system.CenterObject.Id; - system.CenterObject.ChildObjects.Add(obj); } } MyPluginLog.Log("Solar system generated ..."); - - return system; } /// - /// Generates a planet for the star system. + /// Generates a planet for the star system and adds it to the system. /// /// Index of the planet in the system /// The largest diameter the planet should have /// The distance the planet is away from Vector3D.Zero /// A new MySystemPlanet - private MySystemPlanet GeneratePlanet(int planetIndex, double maxDiameter, long orbitDistance) + private MySystemPlanet GeneratePlanet(int planetIndex, double maxDiameter, long orbitDistance, Guid parent) { MyPluginLog.Log("Generating new planet"); @@ -421,11 +417,15 @@ private MySystemPlanet GeneratePlanet(int planetIndex, double maxDiameter, long DisplayName = name, Generated = false, SubtypeId = def.Id.SubtypeId.String, + ParentId = parent }; + StarSystem.Add(planet); + if(MyRandom.Instance.NextFloat() < settings.BaseRingProbability * def.SurfaceGravity) { - planet.ChildObjects.Add(GenrateRing(planet)); + MySystemAsteroids ring = GenrateRing(planet); + StarSystem.Add(ring); } if (MyRandom.Instance.NextFloat() < settings.BaseMoonProbability * def.SurfaceGravity) @@ -433,7 +433,7 @@ private MySystemPlanet GeneratePlanet(int planetIndex, double maxDiameter, long foreach(var moon in GeneratePlanetMoons(planet)) { if (moon == null) continue; - planet.ChildObjects.Add(moon); + StarSystem.Add(moon); } } MyPluginLog.Log("Planet generated"); @@ -511,6 +511,7 @@ private MySystemAsteroids GenrateRing(MySystemPlanet parentPlanet) var provider = MyAsteroidObjectsManager.Static.AsteroidObjectProviders[MyAsteroidRingProvider.TYPE_NAME]; var ring = provider.GenerateInstance(0, parentPlanet, 0); + ring.ParentId = parentPlanet.Id; return ring; } @@ -806,6 +807,8 @@ private MyObjectBuilder_SystemData LoadSystemData() data = new MyObjectBuilder_SystemData(); } + data.RebuildCache(); + return data; } return new MyObjectBuilder_SystemData(); @@ -825,7 +828,7 @@ public override void UpdateBeforeSimulation() var e = MyEntities.GetEntityById(p.EntityId) as MyPlanet; bool exists = false; - foreach(var obj in StarSystem.GetAll()) + foreach(var obj in StarSystem.GetAllByType(MySystemObjectType.PLANET)) { if(obj is MySystemPlanet) { diff --git a/SEWorldGenPlugin/Generator/ProceduralGeneration/MyProceduralAsteroidsModule.cs b/SEWorldGenPlugin/Generator/ProceduralGeneration/MyProceduralAsteroidsModule.cs index a08c114..30282a5 100644 --- a/SEWorldGenPlugin/Generator/ProceduralGeneration/MyProceduralAsteroidsModule.cs +++ b/SEWorldGenPlugin/Generator/ProceduralGeneration/MyProceduralAsteroidsModule.cs @@ -209,13 +209,11 @@ public override void UpdateGpsForPlayer(MyEntityTracker entity) var settings = MySettingsSession.Static.Settings.GeneratorSettings.GPSSettings; if (settings.AsteroidGPSMode != MyGPSGenerationMode.DISCOVERY) return; - var objects = MyStarSystemGenerator.Static.StarSystem.GetAll(); + var objects = MyStarSystemGenerator.Static.StarSystem.GetAllByType(MySystemObjectType.ASTEROIDS); MyCharacter player = entity.Entity as MyCharacter; foreach(var obj in objects) { - if (obj.Type != MySystemObjectType.ASTEROIDS) continue; - MySystemAsteroids asteroid = obj as MySystemAsteroids; Vector3D entityPosition = player.PositionComp.GetPosition(); @@ -347,11 +345,10 @@ private Vector3I GetAsteroidVoxelSize(double asteroidRadius) /// The first ring found, that contains the given position. private MySystemAsteroids GetAsteroidObjectAt(Vector3D position) { - var systemObjects = MyStarSystemGenerator.Static.StarSystem.GetAll(); + var systemObjects = MyStarSystemGenerator.Static.StarSystem.GetAllByType(MySystemObjectType.ASTEROIDS); foreach(var obj in systemObjects) { - if (obj.Type != MySystemObjectType.ASTEROIDS) continue; var asteroids = obj as MySystemAsteroids; if (!MyAsteroidObjectsManager.Static.AsteroidObjectProviders.TryGetValue(asteroids.AsteroidTypeName, out var prov)) continue; diff --git a/SEWorldGenPlugin/ObjectBuilders/MyObjectBuilder_SystemData.cs b/SEWorldGenPlugin/ObjectBuilders/MyObjectBuilder_SystemData.cs index 7e00a14..08320cf 100644 --- a/SEWorldGenPlugin/ObjectBuilders/MyObjectBuilder_SystemData.cs +++ b/SEWorldGenPlugin/ObjectBuilders/MyObjectBuilder_SystemData.cs @@ -2,6 +2,8 @@ using SEWorldGenPlugin.Generator.AsteroidObjects.AsteroidRing; using System; using System.Collections.Generic; +using System.Linq; +using System.Threading; using System.Xml.Serialization; using VRage; using VRage.Serialization; @@ -17,25 +19,67 @@ namespace SEWorldGenPlugin.ObjectBuilders public class MyObjectBuilder_SystemData { /// - /// Objects that are located in this star system. + /// A fast access cache to quickly retrieve system objects and avoid traversal of system tree each time. + /// + private Dictionary m_objectCache = new Dictionary(); + + /// + /// A fast access cache to quickly retrieve system objects fo certain type and avoid traversal of system tree each time. + /// + private Dictionary> m_objectTypeCache = new Dictionary>(); + + /// + /// Objects that are located in this star system. Do not set directly unless you are calling afterwards. /// [ProtoMember(1)] public MySystemObject CenterObject; /// - /// Gets all objects currently in the system + /// Constructs new System Data object builder and initializes cache. /// - /// All objects - public HashSet GetAll() + public MyObjectBuilder_SystemData() + { + RebuildCache(); + } + + /// + /// Rebuilds the system cache for fast access. Rebuild cache after setting system center object + /// or loading the system it from a storage file. + /// When adding or removing objects, the cache is automatically updated. + /// + public void RebuildCache() { - HashSet objs = new HashSet(); + m_objectCache.Clear(); + m_objectTypeCache.Clear(); + m_objectTypeCache.Add(MySystemObjectType.ASTEROIDS, new HashSet()); + m_objectTypeCache.Add(MySystemObjectType.PLANET, new HashSet()); + m_objectTypeCache.Add(MySystemObjectType.MOON, new HashSet()); + m_objectTypeCache.Add(MySystemObjectType.EMPTY, new HashSet()); Foreach(delegate (int i, MySystemObject obj) { - objs.Add(obj); + m_objectCache.Add(obj.Id, obj); + m_objectTypeCache[obj.Type].Add(obj); }); + } - return objs; + /// + /// Gets all objects currently in the system + /// + /// All objects + public HashSet GetAll() + { + return m_objectCache.Values.ToHashSet(); + } + + /// + /// Accesses system cache to return all objects of a specific system object type. + /// + /// + /// + public HashSet GetAllByType(MySystemObjectType type) + { + return m_objectTypeCache[type]; } /// @@ -45,7 +89,7 @@ public HashSet GetAll() public int Count() { if (CenterObject == null) return 0; - return 1 + CenterObject.ChildCount(); + return m_objectCache.Count; } /// @@ -68,17 +112,15 @@ public int GetDepth(Guid id) } /// - /// Searches the system for an object with the given - /// id and returns it if found, else null + /// Accesses system cache to quickly retrieve the object associated with the given id. /// /// Id of the object /// The object or null if not found public MySystemObject GetById(Guid id) { - if (id == Guid.Empty) return null; - foreach(var child in GetAll()) + if(m_objectCache.TryGetValue(id, out MySystemObject obj)) { - if (child.Id == id) return child; + return obj; } return null; } @@ -90,7 +132,7 @@ public MySystemObject GetById(Guid id) /// true if it exists public bool Contains(Guid id) { - return GetById(id) != null; + return m_objectCache.ContainsKey(id); } /// @@ -111,6 +153,8 @@ public bool Remove(Guid id) if (parent == null) return false; parent.ChildObjects.Remove(obj); + m_objectCache.Remove(id); + m_objectTypeCache[obj.Type].Remove(obj); return true; } @@ -131,6 +175,10 @@ public bool Add(MySystemObject obj, Guid parent) if(parent == Guid.Empty && CenterObject == null) { CenterObject = obj; + + m_objectCache.Add(obj.Id, obj); + m_objectTypeCache[obj.Type].Add(obj); + return true; } @@ -139,6 +187,10 @@ public bool Add(MySystemObject obj, Guid parent) { p.ChildObjects.Add(obj); obj.ParentId = parent; + + m_objectCache.Add(obj.Id, obj); + m_objectTypeCache[obj.Type].Add(obj); + return true; } return false; @@ -212,7 +264,7 @@ public class MySystemObject public Guid ParentId; /// - /// All Child objects, such as moons. + /// All Child objects, such as moons. Do not directly add or remove objects, as it will break the Solar system object cache. /// [ProtoMember(6)] [Serialize(MyObjectFlags.Nullable)]