Added MainPathExtender

This commit is contained in:
LadyAliceMargatroid 2024-09-10 04:42:07 -07:00
parent 9ca2b662e3
commit 99d9d7ae1e
8 changed files with 299 additions and 25 deletions

View File

@ -15,6 +15,8 @@ namespace DunGenPlus.Collections {
internal const string MainPathCountTooltip = "The number of main paths.\n\n1 means no additional main paths\n3 means two additional main paths\netc.";
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 = "Tooltip";
[Tooltip(MainPathCountTooltip)]
[Range(1, 9)]
@ -23,11 +25,21 @@ namespace DunGenPlus.Collections {
public GameObject MainRoomTilePrefab;
[Tooltip(CopyNodeBehaviourTooltip)]
public CopyNodeBehaviour CopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition;
[Tooltip(MainPathDetailsTooltip)]
public List<MainPathExtender> MainPathDetails = new List<MainPathExtender>();
public MainPathExtender GetMainPathDetails(int index) {
var count = MainPathDetails.Count;
if (count == 0) return null;
if (index < count) return MainPathDetails[index];
return MainPathDetails[count - 1];
}
internal void CopyFrom(MainPathProperties props) {
MainPathCount = props.MainPathCount;
MainRoomTilePrefab = props.MainRoomTilePrefab;
CopyNodeBehaviour = props.CopyNodeBehaviour;
MainPathDetails = props.MainPathDetails;
}
internal MainPathProperties Copy() {

View File

@ -10,7 +10,7 @@ using DunGenPlus.Collections;
namespace DunGenPlus {
[CreateAssetMenu(fileName = "DunGenExtender", menuName = "DunGenExtender", order = 1)]
[CreateAssetMenu(fileName = "DunGen Extender", menuName = "DunGenExtender/DunGen Extender", order = 1)]
public class DunGenExtender : ScriptableObject {
[Tooltip("DunGenExtender will only influence this DungeonFlow")]

View File

@ -146,6 +146,8 @@
<Compile Include="Components\MainRoomDoorwayGroups.cs" />
<Compile Include="Components\Props\SpawnSyncedObjectCycle.cs" />
<Compile Include="Components\Scrap\RandomGuaranteedScrapSpawn.cs" />
<Compile Include="Generation\DunGenPlusGenerationPaths.cs" />
<Compile Include="MainPathExtender.cs" />
<Compile Include="PluginConfig.cs" />
<Compile Include="DevTools\DevDebugManager.cs" />
<Compile Include="DevTools\DevDebugManagerUI.cs" />

View File

@ -0,0 +1,84 @@
using DunGen;
using DunGen.Graph;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace DunGenPlus.Generation {
internal partial class DunGenPlusGenerator {
public static MainPathExtender currentMainPathExtender;
public static void SetCurrentMainPathExtender(int mainPathIndex){
currentMainPathExtender = Properties.MainPathProperties.GetMainPathDetails(mainPathIndex);
}
public static GraphLine GetLineAtDepth(DungeonFlow flow, float depth) {
if (!DunGenPlusGenerator.Active) {
//Plugin.logger.LogInfo("Default");
return flow.GetLineAtDepth(depth);
}
//Plugin.logger.LogInfo(currentMainPathExtender == null ? "NULL" : "ITEM");
var lines = MainPathExtender.GetLines(currentMainPathExtender, flow);
return GetLineAtDepthHelper(lines, depth);
}
public static GraphLine GetLineAtDepthHelper(List<GraphLine> graphLines, float normalizedDepth) {
normalizedDepth = Mathf.Clamp(normalizedDepth, 0f, 1f);
if (normalizedDepth == 0f) return graphLines[0];
if (normalizedDepth == 1f) return graphLines[graphLines.Count - 1];
foreach (GraphLine graphLine in graphLines){
if (normalizedDepth >= graphLine.Position && normalizedDepth < graphLine.Position + graphLine.Length) {
return graphLine;
}
}
Debug.LogError("GetLineAtDepth was unable to find a line at depth " + normalizedDepth.ToString() + ". This shouldn't happen.");
return null;
}
public static List<GraphNode> GetNodes(DungeonFlow flow){
if (!DunGenPlusGenerator.Active) {
//Plugin.logger.LogInfo("Default");
return flow.Nodes;
}
//Plugin.logger.LogInfo(currentMainPathExtender == null ? "NULL" : "ITEM");
return MainPathExtender.GetNodes(currentMainPathExtender, flow);
}
public static BranchMode GetBranchMode(DungeonFlow flow) {
if (!DunGenPlusGenerator.Active) {
//Plugin.logger.LogInfo("Default M");
return flow.BranchMode;
}
//Plugin.logger.LogInfo(currentMainPathExtender == null ? "NULL" : "ITEM M");
return MainPathExtender.GetBranchMode(currentMainPathExtender, flow);
}
public static IntRange GetBranchCount(DungeonFlow flow) {
if (!DunGenPlusGenerator.Active) {
//Plugin.logger.LogInfo("Default C");
return flow.BranchCount;
}
//Plugin.logger.LogInfo(currentMainPathExtender == null ? "NULL" : "ITEM C");
return MainPathExtender.GetBranchCount(currentMainPathExtender, flow);
}
public static IntRange GetLength(DungeonFlow flow) {
if (!DunGenPlusGenerator.Active) {
Plugin.logger.LogInfo("Default");
return flow.Length;
}
Plugin.logger.LogInfo(currentMainPathExtender == null ? "NULL" : "ITEM");
return MainPathExtender.GetLength(currentMainPathExtender, flow);
}
}
}

View File

@ -142,42 +142,39 @@ namespace DunGenPlus.Generation {
// index of MaxValue is how we tell which doorway proxy is fake
var fakeDoorwayProxy = new DoorwayProxy(mainRoom, int.MaxValue, mainRoom.doorways[0].DoorwayComponent, Vector3.zero, Quaternion.identity);
// nodes
var nodesSorted = gen.DungeonFlow.Nodes.OrderBy(n => n.Position).ToList();
var startingNodeIndexCache = -1;
if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
startingNodeIndexCache = nodesSorted.FindIndex(n => n.TileSets.SelectMany(t => t.TileWeights.Weights).Any(t => t.Value == mainRoomTilePrefab));
if (startingNodeIndexCache == -1) {
yield return gen.Wait(GenerateBranchPaths(gen, $"CopyNodeBehaviour being CopyFromNodeList AND MainRoomTilePrefab not existing in the Nodes' tilesets", LogLevel.Warning));
yield break;
}
startingNodeIndexCache++;
}
//FixDoorwaysToAllFloors(mainRoom, doorwayGroups);
gen.ChangeStatus(GenerationStatus.MainPath);
for (var b = 0; b < altCount; ++b) {
SetCurrentMainPathExtender(b + 1);
RandomizeLineArchetypes(gen, true);
var previousTile = mainRoom;
var targetLength = Mathf.RoundToInt(gen.DungeonFlow.Length.GetRandom(gen.RandomStream) * gen.LengthMultiplier);
var targetLength = Mathf.RoundToInt(GetLength(gen.DungeonFlow).GetRandom(gen.RandomStream) * gen.LengthMultiplier);
var archetypes = new List<DungeonArchetype>(targetLength);
var newMainPathTiles = new List<TileProxy>();
// this causes the main room to create three sets of branch paths
// newMainPathTiles.Add(mainRoom);
// nodes
var nodesSorted = GetNodes(gen.DungeonFlow).OrderBy(n => n.Position).ToList();
int startingNodeIndex;
if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromMainPathPosition) {
if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
var index = nodesSorted.FindIndex(n => n.TileSets.SelectMany(t => t.TileWeights.Weights).Any(t => t.Value == mainRoomTilePrefab));
if (index == -1) {
yield return gen.Wait(GenerateBranchPaths(gen, $"CopyNodeBehaviour being CopyFromNodeList AND MainRoomTilePrefab not existing in the Nodes' tilesets", LogLevel.Warning));
yield break;
}
startingNodeIndex = index + 1;
} else if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromMainPathPosition) {
var lineDepthRatio = Mathf.Clamp01(1f / (targetLength - 1));
startingNodeIndex = nodesSorted.FindIndex(n => n.Position >= lineDepthRatio);
} else if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
startingNodeIndex = startingNodeIndexCache;
} else {
Plugin.logger.LogError($"{copyNodeBehaviour} is not yet defined. How did this happen?");
Plugin.logger.LogFatal($"{copyNodeBehaviour} is not yet defined. Really really bad");
startingNodeIndex = -1;
}
@ -188,7 +185,7 @@ namespace DunGenPlus.Generation {
// and GenerateBranch() code
for(var t = 1; t < targetLength; ++t){
var lineDepthRatio = Mathf.Clamp01((float)t / (targetLength - 1));
var lineAtDepth = gen.DungeonFlow.GetLineAtDepth(lineDepthRatio);
var lineAtDepth = GetLineAtDepth(gen.DungeonFlow, lineDepthRatio);
if (lineAtDepth == null){
yield return gen.Wait(gen.InnerGenerate(true));
yield break;
@ -281,6 +278,7 @@ namespace DunGenPlus.Generation {
// this is major trickery and it works still
for(var b = 0; b < altCount + 1; ++b){
Plugin.logger.LogDebug($"Branch {b}");
SetCurrentMainPathExtender(b);
RandomizeLineArchetypes(gen, false);
gen.proxyDungeon.MainPathTiles = allMainPathTiles[b];
@ -305,6 +303,7 @@ namespace DunGenPlus.Generation {
Plugin.logger.Log(logLevel, $"Switching to default dungeon branch generation: {message}");
ActiveAlternative = false;
SetCurrentMainPathExtender(0);
yield return gen.Wait(gen.GenerateBranchPaths());
ActiveAlternative = true;

View File

@ -0,0 +1,64 @@
using DunGen;
using DunGen.Graph;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace DunGenPlus {
[System.Serializable]
public class PropertyOverride<T> {
[Tooltip("If false, use the value found in DungeonFlow. If true, use this Value instead.")]
public bool Override;
public T Value;
public PropertyOverride(bool _override, T value) {
Override = _override;
Value = value;
}
}
[CreateAssetMenu(fileName = "Main Path Extender", menuName = "DunGenExtender/Main Path Extender", order = 2)]
public class MainPathExtender : ScriptableObject {
public PropertyOverride<IntRange> Length = new PropertyOverride<IntRange>(false, new IntRange(5, 10));
public PropertyOverride<BranchMode> BranchMode = new PropertyOverride<BranchMode>(false, DunGen.BranchMode.Local);
public PropertyOverride<IntRange> BranchCount = new PropertyOverride<IntRange>(false, new IntRange(1, 5));
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>());
[Header("DEV ONLY: DON'T TOUCH")]
public string Version = "0";
public static IntRange GetLength(MainPathExtender extender, DungeonFlow flow) {
if (extender && extender.Length.Override) return extender.Length.Value;
return flow.Length;
}
public static BranchMode GetBranchMode(MainPathExtender extender, DungeonFlow flow) {
if (extender && extender.BranchMode.Override) return extender.BranchMode.Value;
return flow.BranchMode;
}
public static IntRange GetBranchCount(MainPathExtender extender, DungeonFlow flow) {
if (extender && extender.BranchCount.Override) return extender.BranchCount.Value;
return flow.BranchCount;
}
public static List<GraphNode> GetNodes(MainPathExtender extender, DungeonFlow flow) {
if (extender && extender.Nodes.Override) return extender.Nodes.Value;
return flow.Nodes;
}
public static List<GraphLine> GetLines(MainPathExtender extender, DungeonFlow flow) {
if (extender && extender.Lines.Override) return extender.Lines.Value;
return flow.Lines;
}
}
}

View File

@ -13,6 +13,8 @@ using DunGenPlus.Generation;
using DunGenPlus.Managers;
using DunGenPlus.Collections;
using DunGenPlus.DevTools;
using DunGen.Graph;
using UnityEngine;
namespace DunGenPlus.Patches {
internal class DungeonGeneratorPatch {
@ -23,6 +25,10 @@ namespace DunGenPlus.Patches {
if (DevDebugManager.Instance && !isRetry) {
DevDebugManager.Instance.RecordNewSeed(__instance.ChosenSeed);
}
if (DunGenPlusGenerator.Active && DunGenPlusGenerator.ActiveAlternative) {
DunGenPlusGenerator.SetCurrentMainPathExtender(0);
}
}
[HarmonyPostfix]
@ -42,9 +48,6 @@ namespace DunGenPlus.Patches {
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]
public static IEnumerable<CodeInstruction> GenerateMainPathPatch(IEnumerable<CodeInstruction> instructions){
@ -78,6 +81,116 @@ namespace DunGenPlus.Patches {
archSequence.ReportComplete();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]
public static IEnumerable<CodeInstruction> GenerateMainPathGetLineAtDepthPatch(IEnumerable<CodeInstruction> instructions){
var getLineFunction = typeof(DungeonFlow).GetMethod("GetLineAtDepth", BindingFlags.Instance | BindingFlags.Public);
var nodesField = typeof(DungeonFlow).GetField("Nodes", BindingFlags.Instance | BindingFlags.Public);
var lineSequence = new InstructionSequenceStandard("GetLineAtDepth");
lineSequence.AddBasic(OpCodes.Callvirt, getLineFunction);
var nodesSequence = new InstructionSequenceStandard("Nodes", false);
nodesSequence.AddBasic(OpCodes.Ldfld, nodesField);
foreach(var instruction in instructions){
if (lineSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetLineAtDepth", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
if (nodesSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetNodes", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
lineSequence.ReportComplete();
nodesSequence.ReportComplete();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BranchCountHelper), "ComputeBranchCounts")]
public static IEnumerable<CodeInstruction> ComputeBranchCountsPatch(IEnumerable<CodeInstruction> instructions){
var branchModeField = typeof(DungeonFlow).GetField("BranchMode", BindingFlags.Instance | BindingFlags.Public);
var branchSequence = new InstructionSequenceStandard("BranchMode", false);
branchSequence.AddBasic(OpCodes.Ldfld, branchModeField);
foreach(var instruction in instructions){
if (branchSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetBranchMode", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
branchSequence.ReportComplete();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(BranchCountHelper), "ComputeBranchCountsGlobal")]
public static IEnumerable<CodeInstruction> ComputeBranchCountsGlobalPatch(IEnumerable<CodeInstruction> instructions){
var branchCountField = typeof(DungeonFlow).GetField("BranchCount", BindingFlags.Instance | BindingFlags.Public);
var branchSequence = new InstructionSequenceStandard("BranchCount");
branchSequence.AddBasic(OpCodes.Ldfld, branchCountField);
foreach(var instruction in instructions){
if (branchSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetBranchCount", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
branchSequence.ReportComplete();
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "InnerGenerate", MethodType.Enumerator)]
public static IEnumerable<CodeInstruction> InnerGenerateLengthPatch(IEnumerable<CodeInstruction> instructions){
var lengthField = typeof(DungeonFlow).GetField("Length", BindingFlags.Instance | BindingFlags.Public);
var lengthSequence = new InstructionSequenceStandard("Length");
lengthSequence.AddBasic(OpCodes.Ldfld, lengthField);
foreach(var instruction in instructions){
if (lengthSequence.VerifyStage(instruction)) {
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetLength", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
lengthSequence.ReportComplete();
}
/*
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]

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.1.2";
private const string modVersion = "1.2.0";
internal readonly Harmony Harmony = new Harmony(modGUID);