Added some better debugging for failed dungeon generations

RandomGuaranteedScrapSpawn has more fields
This commit is contained in:
LadyAliceMargatroid 2024-12-16 12:51:39 -08:00
parent 15a550af53
commit a166b3d4a7
10 changed files with 168 additions and 65 deletions

View File

@ -9,7 +9,6 @@ using DunGen.Graph;
using DunGenPlus.Generation;
using LethalLevelLoader;
using UnityEngine;
using static DunGenPlus.Components.DoorwayCleanupScripting.DCSConnectorBlockerSpawnedPrefab;
namespace DunGenPlus
{
@ -137,5 +136,9 @@ namespace DunGenPlus
DunGenPlusGenerator.AddTileToMainPathDictionary(dictionary);
}
public static bool IsDevDebugModeActive(){
return DevTools.DevDebugManager.IsActive;
}
}
}

View File

@ -15,21 +15,42 @@ namespace DunGenPlus.Components.Scrap {
public float spawnChance = 1f;
[Tooltip("Minimum scrap value of the scrap item.")]
public int minimumScrapValue = 0;
[Tooltip("Maximum scrap value of the scrap item.")]
public int maximumScrapValue = 100;
[Tooltip("Forces this item in particular to spawn. Overrides min/max scrap values")]
public string specificScrapTarget;
internal static Dictionary<int, IEnumerable<SpawnableItemWithRarity>> scrapItemRarityCache;
internal static Dictionary<(int, int), IEnumerable<SpawnableItemWithRarity>> scrapItemRarityValueCache;
internal static Dictionary<string, IEnumerable<SpawnableItemWithRarity>> scrapItemRarityNameCache;
internal static void ResetCache(){
scrapItemRarityCache = new Dictionary<int, IEnumerable<SpawnableItemWithRarity>>();
scrapItemRarityValueCache = new Dictionary<(int, int), IEnumerable<SpawnableItemWithRarity>>();
scrapItemRarityNameCache = new Dictionary<string, IEnumerable<SpawnableItemWithRarity>>();
}
internal static IEnumerable<SpawnableItemWithRarity> GetCachedItemList(List<SpawnableItemWithRarity> allMoonItems, int scrapValue) {
if (!scrapItemRarityCache.TryGetValue(scrapValue, out var list)){
list = allMoonItems.Where(i => i.spawnableItem.minValue >= scrapValue).ToArray();
scrapItemRarityCache.Add(scrapValue, list);
internal static IEnumerable<SpawnableItemWithRarity> GetCachedItemList(List<SpawnableItemWithRarity> allMoonItems, int minScrapValue, int maxScrapValue) {
var pair = (minScrapValue, maxScrapValue);
if (!scrapItemRarityValueCache.TryGetValue(pair, out var list)){
list = allMoonItems.Where(i => i.spawnableItem.minValue >= minScrapValue && maxScrapValue <= i.spawnableItem.minValue).ToArray();
scrapItemRarityValueCache.Add(pair, list);
}
return list;
}
internal static IEnumerable<SpawnableItemWithRarity> GetCachedItemList(List<SpawnableItemWithRarity> allMoonItems, string scrapName) {
scrapName = scrapName.ToLowerInvariant();
if (!scrapItemRarityNameCache.TryGetValue(scrapName, out var list)){
list = allMoonItems.Where(i => i.spawnableItem.name.ToLowerInvariant().Contains(scrapName) || i.spawnableItem.itemName.ToLowerInvariant().Contains(scrapName)).ToArray();
scrapItemRarityNameCache.Add(scrapName, list);
}
return list;
}
internal IEnumerable<SpawnableItemWithRarity> GetCachedItemList(List<SpawnableItemWithRarity> allMoonItems) {
if (string.IsNullOrWhiteSpace(specificScrapTarget)) return GetCachedItemList(allMoonItems, minimumScrapValue, maximumScrapValue);
return GetCachedItemList(allMoonItems, specificScrapTarget);
}
internal static Item GetRandomItem(IEnumerable<SpawnableItemWithRarity> list) {
var weightList = new int[list.Count()];
for(var i = 0; i < weightList.Length; ++i) {
@ -45,7 +66,7 @@ namespace DunGenPlus.Components.Scrap {
var anomalyRandom = roundManager.AnomalyRandom;
if (anomalyRandom.NextDouble() >= spawnChance) return (null, 0);
var itemList = GetCachedItemList(allMoonItems, minimumScrapValue);
var itemList = GetCachedItemList(allMoonItems);
var itemListCount = itemList.Count();
if (itemListCount == 0) return (null, 0);

View File

@ -85,6 +85,7 @@ namespace DunGenPlus.DevTools {
MainPanel.Instance = null;
DunFlowPanel.Instance = null;
DunGenPlusPanel.Instance = null;
AssetsPanel.Instance = null;
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;

View File

@ -261,22 +261,8 @@ namespace DunGenPlus.Generation {
var tileProxy = gen.AddTile(previousTile, useableTileSets, lineDepthRatio, archetype, TilePlacementResult.None);
if (tileProxy == null) {
var prevName = previousTile != null ? previousTile.Prefab.name : "NULL";
var archetypeName = archetype ? archetype.name : "NULL";
var tileSetNames = string.Join(", ", useableTileSets);
Plugin.logger.LogDebug($"Alt. main branch gen failed at Branch {b} (Length: {t}, Ratio: {lineDepthRatio})");
Plugin.logger.LogDebug($"Prev tile: {prevName}\nArchetype: {archetypeName}\nTilesets: {tileSetNames}");
Plugin.logger.LogDebug($"Reason: {DungeonGeneratorPatch.lastTilePlacementResult}");
if (previousTile != null) {
var availableDoorways = string.Join(",", previousTile.UnusedDoorways);
var usedDoorways = string.Join(",", previousTile.UsedDoorways);
Plugin.logger.LogDebug($"Available Doorways: {availableDoorways}");
Plugin.logger.LogDebug($"Used Doorways: {usedDoorways}");
}
if (tileProxy == null) {
PrintAddTileError(gen, previousTile, archetype, useableTileSets, b + 1, t, lineDepthRatio);
yield return gen.Wait(gen.InnerGenerate(true));
yield break;
}
@ -341,6 +327,42 @@ namespace DunGenPlus.Generation {
AddForcedTiles(gen);
}
public static void PrintAddTileError(DungeonGenerator gen, TileProxy previousTile, DungeonArchetype archetype, IEnumerable<TileSet> useableTileSets, int branchId, int lineLength, float lineRatio){
var prevName = previousTile != null ? previousTile.Prefab.name : "NULL";
var archetypeName = archetype ? archetype.name : "NULL";
var tileSetNames = string.Join(", ", useableTileSets);
var stringList = new List<string>();
stringList.Add($"Main branch gen failed at Branch {branchId} (Length: {lineLength}, Ratio: {lineRatio})");
stringList.Add($"Prev tile: {prevName}");
stringList.Add($"Archetype: {archetypeName}");
stringList.Add($"Tilesets: {tileSetNames}");
stringList.Add($"Reason: {DungeonGeneratorPatch.lastTilePlacementResult}");
if (previousTile != null) {
var availableDoorways = string.Join(", ", previousTile.UnusedDoorways.Select(d => d.DoorwayComponent.gameObject.name));
var usedDoorways = string.Join(", ", previousTile.UsedDoorways.Select(d => d.DoorwayComponent.gameObject.name));
stringList.Add($"Available Doorways: {availableDoorways}");
stringList.Add($"Used Doorways: {usedDoorways}");
if (API.IsDevDebugModeActive()){
var allTiles = GetDoorwayPairs(gen, previousTile, useableTileSets, archetype, lineRatio);
var uniqueTiles = string.Join(", ", allTiles.Select(t => t.NextTemplate.Prefab).Distinct().Select(d => d.name));
stringList.Add($"Next Possible Tiles: {uniqueTiles}");
}
}
stringList.Add(string.Empty);
Plugin.logger.LogDebug(string.Join("\n", stringList));
}
public static void PrintAddTileErrorQuick(DungeonGenerator gen, int lineLength){
PrintAddTileError(gen, DungeonGeneratorPatch.lastAttachTo, DungeonGeneratorPatch.lastArchetype, DungeonGeneratorPatch.lastUseableTileSets, 0, lineLength, DungeonGeneratorPatch.lastNormalizedDepth);
}
private static IEnumerator GenerateBranchPaths(DungeonGenerator gen, TileProxy mainRoom, string message, LogLevel logLevel){
Plugin.logger.Log(logLevel, $"Switching to default dungeon branch generation: {message}");

View File

@ -232,6 +232,34 @@ namespace DunGenPlus.Generation
collection = useableTileSets.SelectMany(t => t.TileWeights.Weights);
}
DoorwayPairStopwatch.Reset();
DoorwayPairStopwatch.Start();
var doorwayPairs = GetDoorwayPairs(gen, attachTo, collection, archetype, normalizedDepth);
DoorwayPairStopwatch.Stop();
DoorwayPairTime += (float)DoorwayPairStopwatch.Elapsed.TotalMilliseconds;
var tilePlacementResult = new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
while(doorwayPairs.Count > 0) {
var pair = doorwayPairs.Dequeue();
tilePlacementResult = TryPlaceTileResult(gen, pathProxy, pair, archetype);
if (tilePlacementResult.result == TilePlacementResult.None) break;
}
if (tilePlacementResult.result == TilePlacementResult.None){
if (injectedTile != null) {
var tileProxy = tilePlacementResult.tileProxy;
tileProxy.Placement.InjectionData = injectedTile;
pathProxy.injectedTiles[tileProxy] = injectedTile;
pathProxy.tilesPendingInjection.RemoveAt(index);
}
return tilePlacementResult;
}
return new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
}
private static Queue<DoorwayPair> GetDoorwayPairs(DungeonGenerator gen, TileProxy attachTo, IEnumerable<GameObjectChance> collection, DungeonArchetype archetype, float normalizedDepth){
// get rotation state
var value = attachTo.PrefabTile.AllowRotation;
if (gen.OverrideAllowTileRotation) {
@ -275,32 +303,13 @@ namespace DunGenPlus.Generation
};
var maxCount = gen.UseMaximumPairingAttempts ? new int?(gen.MaxPairingAttempts) : null;
return doorwayPairFinder.GetDoorwayPairs(maxCount);
}
DoorwayPairStopwatch.Reset();
DoorwayPairStopwatch.Start();
var doorwayPairs = doorwayPairFinder.GetDoorwayPairs(maxCount);
DoorwayPairStopwatch.Stop();
DoorwayPairTime += (float)DoorwayPairStopwatch.Elapsed.TotalMilliseconds;
var tilePlacementResult = new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
while(doorwayPairs.Count > 0) {
var pair = doorwayPairs.Dequeue();
tilePlacementResult = TryPlaceTileResult(gen, pathProxy, pair, archetype);
if (tilePlacementResult.result == TilePlacementResult.None) break;
}
if (tilePlacementResult.result == TilePlacementResult.None){
if (injectedTile != null) {
var tileProxy = tilePlacementResult.tileProxy;
tileProxy.Placement.InjectionData = injectedTile;
pathProxy.injectedTiles[tileProxy] = injectedTile;
pathProxy.tilesPendingInjection.RemoveAt(index);
}
return tilePlacementResult;
}
return new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
private static Queue<DoorwayPair> GetDoorwayPairs(DungeonGenerator gen, TileProxy attachTo, IEnumerable<TileSet> useableTileSets, DungeonArchetype archetype, float normalizedDepth){
IEnumerable<GameObjectChance> collection;
collection = useableTileSets.SelectMany(t => t.TileWeights.Weights);
return GetDoorwayPairs(gen, attachTo, collection, archetype, normalizedDepth);
}
private static TilePlacementResultProxy TryPlaceTileResult(DungeonGenerator gen, BranchPathProxy pathProxy, DoorwayPair pair, DungeonArchetype archetype){

View File

@ -191,6 +191,7 @@ namespace DunGenPlus.Generation {
/*
Plugin.logger.LogError("Spawned");
var colors = new Color[] { Color.red, Color.blue };
foreach(var tile in dungeonGenerator.CurrentDungeon.AllTiles){
@ -198,27 +199,27 @@ namespace DunGenPlus.Generation {
foreach(var globalProp in tile.GetComponentsInChildren<GlobalProp>()){
if (globalProp.PropGroupID == 1717){
var newGameObject = GameObject.Instantiate(DunGenPlusPanel.Instance.dungeonBoundsHelperGameObject);
newGameObject.transform.position = globalProp.transform.position + Vector3.up * 10f;
newGameObject.transform.localScale = Vector3.one * 4f;
Plugin.logger.LogError($"{globalProp.PropGroupID}: {newGameObject.transform.position}");
//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>();
renderer.material.color = colors[0];
//var renderer = newGameObject.GetComponent<Renderer>();
//renderer.material.color = colors[0];
newGameObject.SetActive(true);
// newGameObject.SetActive(true);
}
if (globalProp.PropGroupID == 1718){
var newGameObject = GameObject.Instantiate(DunGenPlusPanel.Instance.dungeonBoundsHelperGameObject);
newGameObject.transform.position = globalProp.transform.position + Vector3.up * 10f;
newGameObject.transform.localScale = Vector3.one * 4f;
Plugin.logger.LogError($"{globalProp.PropGroupID}: {newGameObject.transform.position}");
//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>();
renderer.material.color = colors[1];
//var renderer = newGameObject.GetComponent<Renderer>();
//renderer.material.color = colors[1];
newGameObject.SetActive(true);
//newGameObject.SetActive(true);
}
}

View File

@ -92,7 +92,7 @@ namespace DunGenPlus.Generation {
}
public static bool AllowRetryStop(bool defaultState){
return defaultState || DevDebugManager.IsActive;
return defaultState || API.IsDevDebugModeActive();
}
}

View File

@ -42,7 +42,7 @@ namespace DunGenPlus.Patches {
[HarmonyPatch(typeof(DungeonGenerator), "InnerGenerate")]
public static void InnerGeneratePatch(ref DungeonGenerator __instance, bool isRetry, ref IEnumerator __result){
//Plugin.logger.LogWarning($"InnerGenerate: {DunGenPlusGenerator.Active}, {DunGenPlusGenerator.ActiveAlternative}, {__instance.Status}");
if (DevDebugManager.IsActive && !isRetry) {
if (API.IsDevDebugModeActive() && !isRetry) {
DevDebugManager.Instance.RecordNewSeed(__instance.ChosenSeed);
}
@ -382,6 +382,52 @@ namespace DunGenPlus.Patches {
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]
public static IEnumerable<CodeInstruction> GenerateMainPathDebugPatch(IEnumerable<CodeInstruction> instructions){
var tileProxyNullSequence = new InstructionSequenceStandard("TileProxyNull");
tileProxyNullSequence.AddBasic(OpCodes.Br);
tileProxyNullSequence.AddBasicLocal(OpCodes.Ldloc_S, 14);
tileProxyNullSequence.AddBasic(OpCodes.Brtrue);
foreach(var instruction in instructions){
if (tileProxyNullSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("PrintAddTileErrorQuick", BindingFlags.Static | BindingFlags.Public);
var field = typeof(DungeonGenerator).Assembly.GetType("DunGen.DungeonGenerator+<GenerateMainPath>d__100").GetField("<j>5__8", BindingFlags.NonPublic | BindingFlags.Instance);
yield return instruction;
yield return new CodeInstruction(OpCodes.Ldloc_1);
yield return new CodeInstruction(OpCodes.Ldarg_0);
yield return new CodeInstruction(OpCodes.Ldfld, field);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
tileProxyNullSequence.ReportComplete();
}
public static TileProxy lastAttachTo;
public static IEnumerable<TileSet> lastUseableTileSets;
public static float lastNormalizedDepth;
public static DungeonArchetype lastArchetype;
[HarmonyPrefix]
[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]
public static void AddTileDebugPatch(TileProxy attachTo, IEnumerable<TileSet> useableTileSets, float normalizedDepth, DungeonArchetype archetype){
lastAttachTo = attachTo;
lastUseableTileSets = useableTileSets;
lastNormalizedDepth = normalizedDepth;
lastArchetype = archetype;
}
/*
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]

Binary file not shown.