diff --git a/DunGenPlus/DunGenPlus/Collections/DetailedGlobalPropSettings.cs b/DunGenPlus/DunGenPlus/Collections/DetailedGlobalPropSettings.cs new file mode 100644 index 0000000..eef5375 --- /dev/null +++ b/DunGenPlus/DunGenPlus/Collections/DetailedGlobalPropSettings.cs @@ -0,0 +1,27 @@ +using DunGen; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; + +namespace DunGenPlus.Collections { + + [System.Serializable] + public class DetailedGlobalPropSettings { + + internal const string MinimumDistanceTooltip = "The minimum distance between each Global Props of this id."; + + public int ID; + + [Space] + [Tooltip(MinimumDistanceTooltip)] + public float MinimumDistance; + + public DetailedGlobalPropSettings(int id, float minimumDistance) { + ID = id; + MinimumDistance = minimumDistance; + } + } +} diff --git a/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs b/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs index 2d8d79b..293cc76 100644 --- a/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs +++ b/DunGenPlus/DunGenPlus/Collections/DunGenExtenderPropertiesCollection.cs @@ -6,7 +6,6 @@ using System.Threading.Tasks; using static DunGenPlus.Collections.DunGenExtenderProperties; using UnityEngine; using DunGen; -using DunGen.Graph; namespace DunGenPlus.Collections { @@ -17,7 +16,7 @@ namespace DunGenPlus.Collections { internal const string MainRoomTilePrefabTooltip = "The Tile prefab where the additional main paths will start from.\n\nCannot be null if MainPathCount is more than 1."; internal const string CopyNodeBehaviourTooltip = "Defines how the nodes list is copied onto the additional main paths.\n\nCopyFromMainPathPosition: nodes will copy based on the MainRoomTilePrefab's position in the main path.\nCopyFromNodeList: nodes will copy based on the MainRoomTilePrefab's position in the node list + 1."; internal const string MainPathDetailsTooltip = "Overrides certain DungeonFlow values during the main path generation.\n\nThe order of items in this list correspond to the order of the main paths being generated.\nThe first item in this list will activate for the first main path, the second item for the second main path, and so on. If there are more main paths than items in this list, the last item is used instead."; - + internal const string DetailedGlobalPropSettingsTooltip = "Additional settings for how Global Props spawn."; [Tooltip(MainPathCountTooltip)] [Range(1, 9)] @@ -28,6 +27,8 @@ namespace DunGenPlus.Collections { public CopyNodeBehaviour CopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition; [Tooltip(MainPathDetailsTooltip)] public List MainPathDetails = new List(); + [Tooltip(DetailedGlobalPropSettingsTooltip)] + public List DetailedGlobalPropSettings = new List(); public MainPathExtender GetMainPathDetails(int index) { var count = MainPathDetails.Count; @@ -41,6 +42,7 @@ namespace DunGenPlus.Collections { MainRoomTilePrefab = props.MainRoomTilePrefab; CopyNodeBehaviour = props.CopyNodeBehaviour; MainPathDetails = props.MainPathDetails; + DetailedGlobalPropSettings = props.DetailedGlobalPropSettings; } internal MainPathProperties Copy() { diff --git a/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs b/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs index 874083f..10e5839 100644 --- a/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs +++ b/DunGenPlus/DunGenPlus/Collections/LocalGlobalPropSettings.cs @@ -11,13 +11,16 @@ namespace DunGenPlus.Collections { public class LocalGlobalPropSettings { internal const string GlobalPropLimitTooltip = "If true, when PostProcess reaches the local limit of Global Props for all main paths but does not reach the global limit, use the remaining props in this main path to reach the global limit."; + internal const string MinimumDistanceBetweenPropsTooltip = "If true, Global Props of this id MUST have a minimum distance between each other."; public int ID; + + [Space] public IntRange Count; [Tooltip(GlobalPropLimitTooltip)] public bool UseToReachGlobalPropLimit; - public LocalGlobalPropSettings(int id, IntRange count, bool useToReachGlobalPropLimit) { + public LocalGlobalPropSettings(int id, IntRange count, bool useToReachGlobalPropLimit = false) { ID = id; Count = count; UseToReachGlobalPropLimit = useToReachGlobalPropLimit; diff --git a/DunGenPlus/DunGenPlus/DunGenPlus.csproj b/DunGenPlus/DunGenPlus/DunGenPlus.csproj index ca0ec62..ce6d631 100644 --- a/DunGenPlus/DunGenPlus/DunGenPlus.csproj +++ b/DunGenPlus/DunGenPlus/DunGenPlus.csproj @@ -137,6 +137,7 @@ + diff --git a/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll b/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll index 0a99fc5..4aee102 100644 Binary files a/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll and b/DunGenPlus/DunGenPlus/DunGenPlus/DunGenPlus.dll differ diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs index 43ede05..713cea5 100644 --- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs +++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs @@ -97,6 +97,8 @@ namespace DunGenPlus.Generation { if (tileMainPath.TryGetValue(tile, out var value)){ return value; } + + Plugin.logger.LogWarning("Error with GetMainPathIndexFromTile.\nPLEASE REPORT TO MR. DEV WITH YOUR MOD PACK. THIS SHOULD NOT BE HAPPENING!"); return 0; } diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorGlobalProps.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorGlobalProps.cs index 39e8561..75a51ad 100644 --- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorGlobalProps.cs +++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorGlobalProps.cs @@ -16,6 +16,7 @@ namespace DunGenPlus.Generation { // Copied and pasted from DunGen public static void ProcessGlobalPropsPerMainPath(DungeonGenerator dungeonGenerator){ var localIDs = Properties.MainPathProperties.MainPathDetails.SelectMany(d => d.LocalGroupProps).Select(x => x.ID).ToHashSet(); + var detailedSettings = Properties.MainPathProperties.DetailedGlobalPropSettings; // first parameter int is the GlobalProp ID // second parameter is the List of GameObjectChanceTable indexed by the main path index @@ -69,26 +70,46 @@ namespace DunGenPlus.Generation { var list = new List(localDictionary.Count + globalDictionary.Count); - int ProcessGlobalPropID(GameObjectChanceTable table, int localMax, int globalCount, int globalMax){ + void RemoveElementsTooClose(GameObjectChanceTable table, Vector3 position, float minDistance){ + if (minDistance <= 0f) return; + + var elementsToRemove = new List(); + foreach(var item in table.Weights){ + if (Vector3.SqrMagnitude(position - item.Value.transform.position) < minDistance * minDistance) { + elementsToRemove.Add(item); + } + } + + foreach(var e in elementsToRemove){ + table.Weights.Remove(e); + } + } + + int ProcessGlobalPropID(GameObjectChanceTable table, int localMax, int globalCount, int globalMax, float minDistance){ localMax = Mathf.Clamp(localMax, 0, table.Weights.Count); var i = 0; while(i < localMax && i + globalCount < globalMax){ var random = table.GetRandom(dungeonGenerator.RandomStream, true, 0f, null, true, true); if (random != null && random.Value != null) { random.Value.SetActive(true); + RemoveElementsTooClose(table, random.Value.transform.position, minDistance); } ++i; } return i; } - int ProcessRemainingGlobalPropID(GameObjectChanceTable[] tables, int count){ + int ProcessRemainingGlobalPropID(GameObjectChanceTable[] tables, int count, float minDistance){ count = Mathf.Clamp(count, 0, tables.Sum(t => t.Weights.Count)); var i = 0; while(i < count){ var random = GameObjectChanceTable.GetCombinedRandom(dungeonGenerator.RandomStream, true, 0f, tables); if (random != null) { random.SetActive(true); + + foreach(var t in tables){ + RemoveElementsTooClose(t, random.transform.position, minDistance); + } } ++i; } @@ -107,12 +128,17 @@ namespace DunGenPlus.Generation { .Where(x => x.ID == pair.Key) .FirstOrDefault(); + var detailedPropSettings = detailedSettings + .Where(x => x.ID == pair.Key) + .FirstOrDefault(); + var minDistance = detailedPropSettings != null ? detailedPropSettings.MinimumDistance : -1f; + if (globalPropSettings != null){ var tableClone = pair.Value.Clone(); var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); - var spawned = ProcessGlobalPropID(tableClone, globalMax, 0, globalMax); - Plugin.logger.LogDebug($"Global ID: {pair.Key} ({spawned} / {globalMax})"); + var spawned = ProcessGlobalPropID(tableClone, globalMax, 0, globalMax, minDistance); + Plugin.logger.LogDebug($"Global ID: {pair.Key} ({spawned} / {globalMax}). Min Dist: {minDistance}"); list.Add(pair.Key); } } @@ -131,16 +157,23 @@ namespace DunGenPlus.Generation { var globalPropSettings = dungeonGenerator.DungeonFlow.GlobalProps .Where(x => x.ID == globalPropId) .FirstOrDefault(); - + + var detailedPropSettings = detailedSettings + .Where(x => x.ID == pair.Key) + .FirstOrDefault(); + var minDistance = detailedPropSettings != null ? detailedPropSettings.MinimumDistance : -1f; + if (globalPropSettings != null){ var globalCount = 0; var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); var pathDictionary = pair.Value; - Plugin.logger.LogDebug($"Local ID: {pair.Key} (Max {globalMax})"); + Plugin.logger.LogDebug($"Local ID: {pair.Key} (Max {globalMax}). Min Dist: {minDistance}"); var toRemoveKeys = new List(); foreach(var pathPair in pathDictionary){ + + // try and get local main path properites based on key of Dictionary var mainPathIndex = pathPair.Key; var localGroupProps = Properties.MainPathProperties.GetMainPathDetails(mainPathIndex).LocalGroupProps; @@ -156,7 +189,7 @@ namespace DunGenPlus.Generation { var tableClone = pathPair.Value.Clone(); var localMax = localPropSettings.Count.GetRandom(dungeonGenerator.RandomStream); - var spawned = ProcessGlobalPropID(tableClone, localMax, globalCount, globalMax); + var spawned = ProcessGlobalPropID(tableClone, localMax, globalCount, globalMax, minDistance); globalCount += spawned; Plugin.logger.LogDebug($"Main Path {mainPathIndex}: Local ({spawned} / {localMax}), Global ({globalCount} / {globalMax})"); @@ -176,7 +209,7 @@ namespace DunGenPlus.Generation { Plugin.logger.LogDebug($"Combining main paths ({combine}) into one GameObjectChanceTable"); var combinedTable = pathDictionary.Select(d => d.Value).ToArray(); - var spawned = ProcessRemainingGlobalPropID(combinedTable, globalMax - globalCount); + var spawned = ProcessRemainingGlobalPropID(combinedTable, globalMax - globalCount, minDistance); globalCount += spawned; Plugin.logger.LogDebug($"Spawned remaining props ({globalCount} / {globalMax})"); } @@ -187,45 +220,6 @@ namespace DunGenPlus.Generation { } } - /* - Plugin.logger.LogError("Spawned"); - - - var colors = new Color[] { Color.red, Color.blue }; - - foreach(var tile in dungeonGenerator.CurrentDungeon.AllTiles){ - var mainPathIndex = GetMainPathIndexFromTile(tile); - - foreach(var globalProp in tile.GetComponentsInChildren()){ - if (globalProp.PropGroupID == 1717){ - //var newGameObject = GameObject.Instantiate(DunGenPlusPanel.Instance.dungeonBoundsHelperGameObject); - //newGameObject.transform.position = globalProp.transform.position; - //newGameObject.transform.localScale = Vector3.one * 1f; - Plugin.logger.LogError($"{globalProp.PropGroupID}: {globalProp.transform.position}"); - - //var renderer = newGameObject.GetComponent(); - //renderer.material.color = colors[0]; - - // newGameObject.SetActive(true); - } - - if (globalProp.PropGroupID == 1718){ - //var newGameObject = GameObject.Instantiate(DunGenPlusPanel.Instance.dungeonBoundsHelperGameObject); - //newGameObject.transform.position = globalProp.transform.position; - //newGameObject.transform.localScale = Vector3.one * 1f; - Plugin.logger.LogError($"{globalProp.PropGroupID}: {globalProp.transform.position}"); - - //var renderer = newGameObject.GetComponent(); - //renderer.material.color = colors[1]; - - //newGameObject.SetActive(true); - } - } - - - } - */ - } } diff --git a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs index 7a3265b..0c3e7db 100644 --- a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs +++ b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs @@ -394,10 +394,14 @@ namespace DunGenPlus.Patches { [HarmonyPrefix] [HarmonyPatch(typeof(DungeonGenerator), "ProcessGlobalProps")] public static bool ProcessGlobalPropsPatch(ref DungeonGenerator __instance){ - if (DunGenPlusGenerator.Active && DunGenPlusGenerator.Properties.MainPathProperties.MainPathDetails.Any(d => d.LocalGroupProps.Count > 0)){ - Plugin.logger.LogDebug("Performing Local Global Props algorithm"); - DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance); - return false; + if (DunGenPlusGenerator.Active){ + var anyGlobalSettings = DunGenPlusGenerator.Properties.MainPathProperties.DetailedGlobalPropSettings.Count > 0; + var anyLocalSettings = DunGenPlusGenerator.Properties.MainPathProperties.MainPathDetails.Any(d => d.LocalGroupProps.Count > 0); + if (anyGlobalSettings || anyLocalSettings){ + Plugin.logger.LogDebug("Performing Local Global Props algorithm"); + DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance); + return false; + } } return true; } diff --git a/DunGenPlus/DunGenPlus/Plugin.cs b/DunGenPlus/DunGenPlus/Plugin.cs index 4ca87fc..644b459 100644 --- a/DunGenPlus/DunGenPlus/Plugin.cs +++ b/DunGenPlus/DunGenPlus/Plugin.cs @@ -19,13 +19,13 @@ using UnityEngine.Assertions; namespace DunGenPlus { [BepInPlugin(modGUID, modName, modVersion)] - [BepInDependency("imabatby.lethallevelloader", "1.2.0.3")] + [BepInDependency("imabatby.lethallevelloader", "1.4.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { internal const string modGUID = "dev.ladyalice.dungenplus"; private const string modName = "Dungeon Generation Plus"; - private const string modVersion = "1.3.3"; + private const string modVersion = "1.3.4"; internal readonly Harmony Harmony = new Harmony(modGUID);