Changed Local Global Props to be based on Main Path Extender

This commit is contained in:
LadyAliceMargatroid 2024-12-01 03:35:34 -08:00
parent 7b4977c131
commit 075f3b5d85
10 changed files with 107 additions and 28 deletions

View File

@ -9,6 +9,7 @@ using DunGen.Graph;
using DunGenPlus.Generation;
using LethalLevelLoader;
using UnityEngine;
using static DunGenPlus.Components.DoorwayCleanupScripting.DCSConnectorBlockerSpawnedPrefab;
namespace DunGenPlus
{
@ -128,6 +129,8 @@ namespace DunGenPlus
/// <summary>
/// DO NOT USE!
///
/// Registers the connection between <see cref="TileProxy"/> to <see cref="Tile"/> that's specifically created during <see cref="DunGen.Dungeon.FromProxy(DungeonProxy, DungeonGenerator)"/>.
/// </summary>
/// <param name="dictionary"></param>
public static void AddTileToMainPathDictionary(Dictionary<TileProxy, Tile> dictionary){

View File

@ -17,8 +17,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 LocalMainPathGlobalPropsTooltip = "Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow.";
[Tooltip(MainPathCountTooltip)]
[Range(1, 9)]
@ -29,8 +28,6 @@ namespace DunGenPlus.Collections {
public CopyNodeBehaviour CopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition;
[Tooltip(MainPathDetailsTooltip)]
public List<MainPathExtender> MainPathDetails = new List<MainPathExtender>();
[Tooltip(LocalMainPathGlobalPropsTooltip)]
public List<DungeonFlow.GlobalPropSettings> LocalMainPathGlobalProps = new List<DungeonFlow.GlobalPropSettings>();
public MainPathExtender GetMainPathDetails(int index) {
var count = MainPathDetails.Count;
@ -44,7 +41,6 @@ namespace DunGenPlus.Collections {
MainRoomTilePrefab = props.MainRoomTilePrefab;
CopyNodeBehaviour = props.CopyNodeBehaviour;
MainPathDetails = props.MainPathDetails;
LocalMainPathGlobalProps = props.LocalMainPathGlobalProps;
}
internal MainPathProperties Copy() {

View File

@ -0,0 +1,26 @@
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 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.";
public int ID;
public IntRange Count;
[Tooltip(GlobalPropLimitTooltip)]
public bool UseToReachGlobalPropLimit;
public LocalGlobalPropSettings(int id, IntRange count, bool useToReachGlobalPropLimit) {
ID = id;
Count = count;
UseToReachGlobalPropLimit = useToReachGlobalPropLimit;
}
}
}

View File

@ -134,6 +134,7 @@
<Compile Include="Collections\DunGenExtenderPropertiesCollection.cs" />
<Compile Include="Collections\ExtenderEvent.cs" />
<Compile Include="Collections\ForcedTileSetList.cs" />
<Compile Include="Collections\LocalGlobalPropSettings.cs" />
<Compile Include="Collections\NodeArchetype.cs" />
<Compile Include="Collections\NullObject.cs" />
<Compile Include="Components\DoorwayCleanup.cs" />

View File

@ -126,6 +126,8 @@ namespace DunGenPlus.Generation {
}
public static void AddTileToMainPathDictionary(Dictionary<TileProxy, Tile> dictionary){
if (!DunGenPlusGenerator.Active) return;
foreach(var pair in dictionary){
tileMainPath.Add(pair.Value, GetMainPathIndexFromTileProxy(pair.Key));
}

View File

@ -98,7 +98,7 @@ namespace DunGenPlus.Generation {
// Copied and pasted from DunGen
public static void ProcessGlobalPropsPerMainPath(DungeonGenerator dungeonGenerator){
var localIDs = Properties.MainPathProperties.LocalMainPathGlobalProps.Select(x => x.ID).ToHashSet();
var localIDs = Properties.MainPathProperties.MainPathDetails.SelectMany(d => d.LocalGroupProps).Select(x => x.ID).ToHashSet();
// first parameter int is the GlobalProp ID
// second parameter is the List of GameObjectChanceTable indexed by the main path index
@ -166,6 +166,19 @@ namespace DunGenPlus.Generation {
return i;
}
int ProcessRemainingGlobalPropID(GameObjectChanceTable[] tables, int count){
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);
}
++i;
}
return i;
}
using(var enumerator = globalDictionary.GetEnumerator()){
while(enumerator.MoveNext()){
var pair = enumerator.Current;
@ -178,12 +191,12 @@ namespace DunGenPlus.Generation {
.Where(x => x.ID == pair.Key)
.FirstOrDefault();
if (globalPropSettings != null){
if (globalPropSettings != null){
var tableClone = pair.Value.Clone();
var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream);
var spawned = ProcessGlobalPropID(tableClone, globalMax, 0, globalMax);
//Plugin.logger.LogError($"Spawned {spawned} ({spawned}/{globalMax})");
Plugin.logger.LogDebug($"Global ID: {pair.Key} ({spawned} / {globalMax})");
list.Add(pair.Key);
}
}
@ -193,29 +206,65 @@ namespace DunGenPlus.Generation {
using(var enumerator = localDictionary.GetEnumerator()){
while(enumerator.MoveNext()){
var pair = enumerator.Current;
if (list.Contains(pair.Key)){
var globalPropId = pair.Key;
if (list.Contains(globalPropId)){
Plugin.logger.LogWarning("Dungeon Flow contains multiple entries for the global prop group ID: " + pair.Key.ToString() + ". Only the first entry will be used.");
} else {
//Plugin.logger.LogWarning($"{pair.Key}: Local");
var globalPropSettings = dungeonGenerator.DungeonFlow.GlobalProps
.Where(x => x.ID == pair.Key)
.Where(x => x.ID == globalPropId)
.FirstOrDefault();
var localPropSettings = Properties.MainPathProperties.LocalMainPathGlobalProps
.Where(x => x.ID == pair.Key)
.FirstOrDefault();
if (globalPropSettings != null && localPropSettings != null){
if (globalPropSettings != null){
var globalCount = 0;
foreach(var path in pair.Value.Values){
var tableClone = path.Clone();
var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream);
var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream);
var pathDictionary = pair.Value;
Plugin.logger.LogDebug($"Local ID: {pair.Key} (Max {globalMax})");
var toRemoveKeys = new List<int>();
foreach(var pathPair in pathDictionary){
// try and get local main path properites based on key of Dictionary<MainPathIndex (int), GlobalProps (GameObjectChanceTable)>
var mainPathIndex = pathPair.Key;
var localGroupProps = Properties.MainPathProperties.GetMainPathDetails(mainPathIndex).LocalGroupProps;
var localPropSettings = localGroupProps
.Where(x => x.ID == globalPropId)
.FirstOrDefault();
if (localPropSettings == null) {
Plugin.logger.LogDebug($"Main Path {mainPathIndex}: No local ID defined, skipping");
continue;
}
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);
globalCount += spawned;
Plugin.logger.LogDebug($"Main Path {mainPathIndex}: Local ({spawned} / {localMax}), Global ({globalCount} / {globalMax})");
// all dictionaries that we done using get throw out
if (!localPropSettings.UseToReachGlobalPropLimit) toRemoveKeys.Add(mainPathIndex);
//Plugin.logger.LogError($"Spawned {spawned} ({globalCount}/{globalMax})");
}
foreach(var key in toRemoveKeys){
pathDictionary.Remove(key);
}
// spawn the last remaining global props if possible
if (globalCount < globalMax && pathDictionary.Count > 0) {
var combine = string.Join(", ", pathDictionary.Keys);
Plugin.logger.LogDebug($"Combining main paths ({combine}) into one GameObjectChanceTable");
var combinedTable = pathDictionary.Select(d => d.Value).ToArray();
var spawned = ProcessRemainingGlobalPropID(combinedTable, globalMax - globalCount);
globalCount += spawned;
Plugin.logger.LogDebug($"Spawned remaining props ({globalCount} / {globalMax})");
}
list.Add(pair.Key);
}
}

View File

@ -6,6 +6,7 @@ using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGenPlus.Collections;
namespace DunGenPlus {
@ -24,6 +25,8 @@ namespace DunGenPlus {
[CreateAssetMenu(fileName = "Main Path Extender", menuName = "DunGenExtender/Main Path Extender", order = 2)]
public class MainPathExtender : ScriptableObject {
internal const string LocalMainPathGlobalPropsTooltip = "Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow.";
public PropertyOverride<IntRange> Length = new PropertyOverride<IntRange>(false, new IntRange(5, 10));
public PropertyOverride<BranchMode> BranchMode = new PropertyOverride<BranchMode>(false, DunGen.BranchMode.Local);
@ -32,6 +35,9 @@ namespace DunGenPlus {
public PropertyOverride<List<GraphNode>> Nodes = new PropertyOverride<List<GraphNode>>(false, new List<GraphNode>());
public PropertyOverride<List<GraphLine>> Lines = new PropertyOverride<List<GraphLine>>(false, new List<GraphLine>());
[Tooltip(LocalMainPathGlobalPropsTooltip)]
public List<LocalGlobalPropSettings> LocalGroupProps = new List<LocalGlobalPropSettings>();
[Header("DEV ONLY: DON'T TOUCH")]
[Attributes.ReadOnly]
public string Version = "0";

View File

@ -373,14 +373,10 @@ namespace DunGenPlus.Patches {
[HarmonyPrefix]
[HarmonyPatch(typeof(DungeonGenerator), "ProcessGlobalProps")]
public static bool ProcessGlobalPropsPatch(ref DungeonGenerator __instance){
if (DunGenPlusGenerator.Active){
var list = DunGenPlusGenerator.Properties.MainPathProperties.LocalMainPathGlobalProps;
if (list != null && list.Count > 0) {
Plugin.logger.LogDebug("Performing Local Global Props algorithm");
DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance);
return false;
}
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;
}
return true;
}

View File

@ -25,7 +25,7 @@ namespace DunGenPlus {
internal const string modGUID = "dev.ladyalice.dungenplus";
private const string modName = "Dungeon Generation Plus";
private const string modVersion = "1.2.1";
private const string modVersion = "1.3.0";
internal readonly Harmony Harmony = new Harmony(modGUID);