Added local Global Props

This commit is contained in:
LadyAliceMargatroid 2024-11-26 10:12:39 -08:00
parent 8970edffe8
commit 7b4977c131
10 changed files with 255 additions and 11 deletions

View File

@ -126,5 +126,13 @@ namespace DunGenPlus
return extender;
}
/// <summary>
/// DO NOT USE!
/// </summary>
/// <param name="dictionary"></param>
public static void AddTileToMainPathDictionary(Dictionary<TileProxy, Tile> dictionary){
DunGenPlusGenerator.AddTileToMainPathDictionary(dictionary);
}
}
}

View File

@ -6,6 +6,7 @@ using System.Threading.Tasks;
using static DunGenPlus.Collections.DunGenExtenderProperties;
using UnityEngine;
using DunGen;
using DunGen.Graph;
namespace DunGenPlus.Collections {
@ -16,6 +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)]
@ -27,6 +29,8 @@ 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;
@ -40,6 +44,7 @@ namespace DunGenPlus.Collections {
MainRoomTilePrefab = props.MainRoomTilePrefab;
CopyNodeBehaviour = props.CopyNodeBehaviour;
MainPathDetails = props.MainPathDetails;
LocalMainPathGlobalProps = props.LocalMainPathGlobalProps;
}
internal MainPathProperties Copy() {

View File

@ -87,19 +87,50 @@ namespace DunGenPlus.Generation {
}
private static Dictionary<TileProxy, int> tileProxyMainPath = new Dictionary<TileProxy, int>();
private static Dictionary<Tile, int> tileMainPath = new Dictionary<Tile, int>();
public static int GetMainPathIndexFromTileProxy(TileProxy tileProxy){
return tileProxyMainPath[tileProxy];
}
private static void AddTileProxyToMainPathDictionary(IEnumerable<TileProxy> tileProxies, int index) {
public static int GetMainPathIndexFromTile(Tile tile){
return tileMainPath[tile];
}
public static void AddTileProxy(TileProxy tileProxy, int index) {
//Plugin.logger.LogWarning($"Adding: {tileProxy.Prefab.name} ({tileProxy.Placement.IsOnMainPath}): {index}");
tileProxyMainPath.Add(tileProxy, index);
}
public static void AddMainPathTileProxies(IEnumerable<TileProxy> tileProxies, int index){
var totalLength = (float)tileProxies.Last().Placement.PathDepth;
foreach(var t in tileProxies) {
tileProxyMainPath.Add(t, index);
AddTileProxy(t, index);
t.Placement.NormalizedPathDepth = t.Placement.PathDepth / totalLength;
}
}
public static void BuildBranchPathTileProxiesDictionary(DungeonProxy dungeonProxy){
var lastIndex = 0;
foreach(var connection in dungeonProxy.Connections){
var aTileProxy = connection.A.TileProxy;
if (aTileProxy.Placement.IsOnMainPath) {
lastIndex = GetMainPathIndexFromTileProxy(aTileProxy);
}
var bTileProxy = connection.B.TileProxy;
if (!bTileProxy.Placement.IsOnMainPath){
AddTileProxy(bTileProxy, lastIndex);
}
}
}
public static void AddTileToMainPathDictionary(Dictionary<TileProxy, Tile> dictionary){
foreach(var pair in dictionary){
tileMainPath.Add(pair.Value, GetMainPathIndexFromTileProxy(pair.Key));
}
}
public static IEnumerator GenerateAlternativeMainPaths(DungeonGenerator gen) {
// default behaviour
@ -112,6 +143,10 @@ namespace DunGenPlus.Generation {
var altCount = Properties.MainPathProperties.MainPathCount - 1;
tileProxyMainPath.Clear();
tileMainPath.Clear();
var firstMainPathTiles = gen.proxyDungeon.MainPathTiles.ToList();
AddMainPathTileProxies(firstMainPathTiles, 0);
var mainRoomTilePrefab = Properties.MainPathProperties.MainRoomTilePrefab;
var copyNodeBehaviour = Properties.MainPathProperties.CopyNodeBehaviour;
@ -127,9 +162,7 @@ namespace DunGenPlus.Generation {
}
var allMainPathTiles = new List<List<TileProxy>>();
var firstMainPathTiles = gen.proxyDungeon.MainPathTiles.ToList();
allMainPathTiles.Add(firstMainPathTiles);
AddTileProxyToMainPathDictionary(firstMainPathTiles, 0);
// main room is the true main room and not the fake room
// this MUST have multiple doorways as you can imagine
@ -267,7 +300,7 @@ namespace DunGenPlus.Generation {
if (gen.ShouldSkipFrame(true)) yield return gen.GetRoomPause();
}
AddTileProxyToMainPathDictionary(newMainPathTiles, b + 1);
AddMainPathTileProxies(newMainPathTiles, b + 1);
allMainPathTiles.Add(newMainPathTiles);
}
@ -291,13 +324,17 @@ namespace DunGenPlus.Generation {
yield return gen.Wait(GenerateMultiBranchPaths(gen));
GenerateBranchBoostedPathsStopWatch.Stop();
GenerateBranchBoostedPathsTime += (float)GenerateBranchBoostedPathsStopWatch.Elapsed.TotalMilliseconds;
} else {
yield return gen.Wait(gen.GenerateBranchPaths());
}
else yield return gen.Wait(gen.GenerateBranchPaths());
}
ActiveAlternative = true;
gen.proxyDungeon.MainPathTiles = allMainPathTiles[0];
if (!Properties.BranchPathMultiSimulationProperties.UseBranchPathMultiSim){
BuildBranchPathTileProxiesDictionary(gen.proxyDungeon);
}
AddForcedTiles(gen);
}
@ -312,6 +349,7 @@ namespace DunGenPlus.Generation {
yield return gen.Wait(gen.GenerateBranchPaths());
ActiveAlternative = true;
BuildBranchPathTileProxiesDictionary(gen.proxyDungeon);
AddForcedTiles(gen);
}

View File

@ -191,7 +191,7 @@ namespace DunGenPlus.Generation
gen.injectedTiles = bestPath.injectedTiles;
gen.tilesPendingInjection = bestPath.tilesPendingInjection;
AddTileProxyToMainPathDictionary(bestPath.list.Select(x => x.tileProxy), bestPath.mainPathIndex);
AddMainPathTileProxies(bestPath.list.Select(x => x.tileProxy), bestPath.mainPathIndex);
if (gen.ShouldSkipFrame(true)){
yield return gen.GetRoomPause();

View File

@ -2,10 +2,13 @@
using DunGen.Graph;
using DunGenPlus.DevTools;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using static UnityEngine.Rendering.DebugUI;
namespace DunGenPlus.Generation {
internal partial class DunGenPlusGenerator {
@ -33,6 +36,7 @@ namespace DunGenPlus.Generation {
var tileProxy = gen.AddTile(t, item.TileSets, t.Placement.NormalizedDepth, null, TilePlacementResult.None);
if (tileProxy == null) continue;
AddTileProxy(tileProxy, GetMainPathIndexFromTileProxy(t));
tileProxy.Placement.BranchDepth = t.Placement.BranchDepth;
tileProxy.Placement.NormalizedBranchDepth = t.Placement.NormalizedDepth;
tileProxy.Placement.GraphNode = t.Placement.GraphNode;
@ -92,5 +96,133 @@ namespace DunGenPlus.Generation {
return defaultState || DevDebugManager.IsActive;
}
// Copied and pasted from DunGen
public static void ProcessGlobalPropsPerMainPath(DungeonGenerator dungeonGenerator){
var localIDs = Properties.MainPathProperties.LocalMainPathGlobalProps.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
var localDictionary = new Dictionary<int, Dictionary<int, GameObjectChanceTable>>();
// default dictionary
var globalDictionary = new Dictionary<int, GameObjectChanceTable>();
foreach(var tile in dungeonGenerator.CurrentDungeon.AllTiles){
foreach(var globalProp in tile.GetComponentsInChildren<GlobalProp>()){
GameObjectChanceTable gameObjectChanceTable;
if (localIDs.Contains(globalProp.PropGroupID)){
if (!localDictionary.TryGetValue(globalProp.PropGroupID, out var dictionary)){
dictionary = new Dictionary<int, GameObjectChanceTable>();
localDictionary.Add(globalProp.PropGroupID, dictionary);
}
// The game will softlock if it can't find the tile
// THIS IS SCARY!!!
var mainPathIndex = GetMainPathIndexFromTile(tile);
if (!dictionary.TryGetValue(mainPathIndex, out gameObjectChanceTable)){
gameObjectChanceTable = new GameObjectChanceTable();
dictionary.Add(mainPathIndex, gameObjectChanceTable);
}
} else {
if (!globalDictionary.TryGetValue(globalProp.PropGroupID, out gameObjectChanceTable)){
gameObjectChanceTable = new GameObjectChanceTable();
globalDictionary.Add(globalProp.PropGroupID, gameObjectChanceTable);
}
}
var num = tile.Placement.IsOnMainPath ? globalProp.MainPathWeight : globalProp.BranchPathWeight;
num *= globalProp.DepthWeightScale.Evaluate(tile.Placement.NormalizedDepth);
gameObjectChanceTable.Weights.Add(new GameObjectChance(globalProp.gameObject, num, 0f, null));
}
}
foreach(var dictionary in localDictionary.Values){
foreach(var table2 in dictionary.Values){
foreach(var gameObjectChance in table2.Weights){
gameObjectChance.Value.SetActive(false);
}
}
}
foreach(var table2 in globalDictionary.Values){
foreach(var gameObjectChance in table2.Weights){
gameObjectChance.Value.SetActive(false);
}
}
var list = new List<int>(localDictionary.Count + globalDictionary.Count);
int ProcessGlobalPropID(GameObjectChanceTable table, int localMax, int globalCount, int globalMax){
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);
}
++i;
}
return i;
}
using(var enumerator = globalDictionary.GetEnumerator()){
while(enumerator.MoveNext()){
var pair = enumerator.Current;
if (list.Contains(pair.Key)){
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}: Global");
var globalPropSettings = dungeonGenerator.DungeonFlow.GlobalProps
.Where(x => x.ID == pair.Key)
.FirstOrDefault();
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})");
list.Add(pair.Key);
}
}
}
}
using(var enumerator = localDictionary.GetEnumerator()){
while(enumerator.MoveNext()){
var pair = enumerator.Current;
if (list.Contains(pair.Key)){
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)
.FirstOrDefault();
var localPropSettings = Properties.MainPathProperties.LocalMainPathGlobalProps
.Where(x => x.ID == pair.Key)
.FirstOrDefault();
if (globalPropSettings != null && localPropSettings != null){
var globalCount = 0;
foreach(var path in pair.Value.Values){
var tableClone = path.Clone();
var globalMax = globalPropSettings.Count.GetRandom(dungeonGenerator.RandomStream);
var localMax = localPropSettings.Count.GetRandom(dungeonGenerator.RandomStream);
var spawned = ProcessGlobalPropID(tableClone, localMax, globalCount, globalMax);
globalCount += spawned;
//Plugin.logger.LogError($"Spawned {spawned} ({globalCount}/{globalMax})");
}
list.Add(pair.Key);
}
}
}
}
}
}
}

View File

@ -343,6 +343,49 @@ namespace DunGenPlus.Patches {
lastTilePlacementResult = result;
}
[HarmonyTranspiler]
[HarmonyPatch(typeof(Dungeon), "FromProxy")]
public static IEnumerable<CodeInstruction> FromProxyPatch(IEnumerable<CodeInstruction> instructions){
var endSequence = new InstructionSequenceStandard("Forloop End");
endSequence.AddBasicLocal(OpCodes.Ldloca_S, 1);
endSequence.AddBasic(OpCodes.Constrained);
endSequence.AddBasic(OpCodes.Callvirt);
endSequence.AddBasic(OpCodes.Endfinally);
foreach(var instruction in instructions){
if (endSequence.VerifyStage(instruction)) {
yield return instruction;
var specialFunction = typeof(DunGenPlusGenerator).GetMethod("AddTileToMainPathDictionary", BindingFlags.Static | BindingFlags.Public);
yield return new CodeInstruction(OpCodes.Ldloc_0);
yield return new CodeInstruction(OpCodes.Call, specialFunction);
continue;
}
yield return instruction;
}
endSequence.ReportComplete();
}
[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;
}
}
return true;
}
/*
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]

View File

@ -255,11 +255,15 @@ namespace DunGenPlus.Utils {
public static void PrintInstructions(IEnumerable<CodeInstruction> instructions) {
foreach(var i in instructions){
var opString = i.opcode.ToString();
var objString = i.operand != null ? i.operand.ToString() : "NULL";
Plugin.logger.LogInfo($"{opString}: {objString}");
PrintInstruction(i);
}
}
public static void PrintInstruction(CodeInstruction inst) {
var opString = inst.opcode.ToString();
var objString = inst.operand != null ? inst.operand.ToString() : "NULL";
Plugin.logger.LogInfo($"{opString}: {objString}");
}
}
}

View File

@ -7,6 +7,7 @@ using DunGen;
using DunGen.Graph;
using DunGenPlus;
using DunGenPlus.Collections;
using HarmonyLib;
namespace LoadstoneNighty {
@ -79,5 +80,11 @@ namespace LoadstoneNighty {
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Loadstone.Patches.FromProxyPatches), "FromProxyEnd")]
public static void FromProxyEndPatch(Dictionary<TileProxy, Tile> dictionary){
DunGenPlus.API.AddTileToMainPathDictionary(dictionary);
}
}
}

View File

@ -47,6 +47,13 @@ namespace LoadstoneNighty {
if (validVersion){
logger.LogInfo($"Plugin {modName} has been added!");
try {
harmony.PatchAll(typeof(Patch));
} catch {
}
Patch.Activate();
}
}