Redid BranchLoop from tile prioritization to branch path prioritization

Added performance logs for the generation
Refactored how the DunGenExtenderProperties are structured
This commit is contained in:
LadyAliceMargatroid 2024-08-25 19:02:43 -07:00
parent 7b16fd6f37
commit 1407e39703
12 changed files with 536 additions and 241 deletions

View File

@ -24,142 +24,39 @@ namespace DunGenPlus.Collections {
}
[Header("Main Path")]
[Tooltip("The number of main paths.\n\n1 means no additional main paths\n3 means two additional main paths\netc.")]
[Range(1, 9)]
public int MainPathCount = 1;
[Tooltip("The Tile Prefab where the additional main paths will start from. Cannot be null if MainPathCount is more than 1.")]
public GameObject MainRoomTilePrefab;
[Tooltip("CopyFromMainPathPosition means that nodes will copy from the MainRoomTilePrefab's position in the main path.\n\nCopyFromNodeList means that nodes will copy from the MainRoomTilePrefab's location from the node list + 1.")]
public CopyNodeBehaviour MainPathCopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition;
//public bool MainPathCopyInjectionTiles;
public MainPathProperties MainPathProperties = new MainPathProperties();
[Header("Dungeon Bounds")]
[Tooltip("If enabled, restricts the dungeon's generation to the bounds described below.\n\nThis will help in condensing the dungeon, but it will increase the chance of dungeon generation failure (potentially guarantees failure if the bounds is too small).")]
public bool UseDungeonBounds = false;
[Tooltip("The base size of the bounds.")]
public Vector3 DungeonSizeBase = new Vector3(120f, 40f, 80f);
[Tooltip("The factor that's multiplied with the base size AND the dungeon's size. The resulting value is added to the base size of the bounds.\n\n0 means that the bound size is not influenced by the dungeon's size and is therefore a constant.")]
public Vector3 DungeonSizeFactor = new Vector3(1f, 0f, 1f);
[Tooltip("The base positional offset of the bounds.")]
public Vector3 DungeonPositionOffset = Vector3.zero;
[Tooltip("The pivot of the bounds.")]
public Vector3 DungeonPositionPivot = new Vector3(0.5f, 0f, 0.5f);
public DungeonBoundsProperties DungeonBoundsProperties = new DungeonBoundsProperties();
[Header("Archetypes on Normal Nodes")]
[Tooltip("If enabled, adds archetypes to the normal nodes in the DungeonFlow.\n\nBy default, nodes cannot have branching paths since they don't have archetype references. This allows nodes to have branching paths.")]
public bool AddArchetypesToNormalNodes = false;
public List<NodeArchetype> NormalNodeArchetypes = new List<NodeArchetype>();
internal Dictionary<string, NodeArchetype> _normalNodeArchetypesDictioanry;
internal NodeArchetype _defaultNodeArchetype;
[Header("Normal Nodes Archetypes")]
public NormalNodeArchetypesProperties NormalNodeArchetypesProperties = new NormalNodeArchetypesProperties();
[Header("Forced Tiles")]
[Tooltip("If enabled, attempts to forcefully spawn tiles from ForcedTileSets after branching paths are generated.\n\nCan only be used if MainPathCount > 1.")]
public bool UseForcedTiles = false;
[Tooltip("The list of tiles that will be attempted to forcefully spawn. Each entry will spawn only one tile from it's list.\n\nIf the tile cannot be forcefully spawned, the dungeon generation will not restart.")]
public List<ForcedTileSetList> ForcedTileSets = new List<ForcedTileSetList>();
public ForcedTilesProperties ForcedTilesProperties = new ForcedTilesProperties();
[Header("Branch Loop Boost")]
[Tooltip("If enabled, dungeon generation will prioritize branch tiles that connect to already generated tiles.\n\nThis increases the chance of circular/looping paths. Slows dungeon generation times a bit at the end.")]
public bool UseBranchLoopBoost = false;
[Tooltip("The maximum amount of tiles the dungeon generation will consider before choosing the best tile.\nIncreasing this value gives the dungeon generation a higher chance of finding a good tile but impacts dungeon generation times. Decreasing this value gives the dungeon generation a lower chance of finding a good tile but also lessens the impact to dungeon generation times.")]
public int BranchLoopBoostTileSearch = 5;
[Tooltip("The tile weight scale added for each additional doorway connection if that tile was selected.")]
public float BranchLoopBoostTileScale = 0.25f;
[Header("Branch Path Multi Simulation")]
public BranchPathMultiSimulationProperties BranchPathMultiSimulationProperties = new BranchPathMultiSimulationProperties();
[Header("Line Randomizer")]
[Tooltip("If enabled, every archetype in LineRandomizerArchetypes will have the last LineRandomizerTakeCount tilesets replaced by a randomly selected set of tilesets from LineRandomizerTileSets. This applies for both archetype's TileSets and BranchCapTileSets.\n\nThis is designed for the scenario where dungeon generation takes a long time due to the combination of too many tiles and/or doorways in those tiles. This can reduce dungeon generation time while keeping some of the randomness of dungeon generation.\n\nAs stated previously, this WILL replace the last LineRandomizerTakeCount tilesets in the archetype's TileSets and BranchCapTileSets. As such you must guarantee that those elements can be replaced.")]
public bool UseLineRandomizer = false;
[Tooltip("The archetypes whose tilesets will be replaced.\n\nThese archetypes should ideally used in the Lines section of DungeonFlow, but it's a free country.")]
public List<DungeonArchetype> LineRandomizerArchetypes = new List<DungeonArchetype>();
[Tooltip("The tilesets that will be used for replacement.")]
public List<TileSet> LineRandomizerTileSets = new List<TileSet>();
[Tooltip("The amount of tilesets that will be replaced from the archetypes, starting from the last element to the first element.\n\nAs stated previously, this WILL replace the tilesets in the archetype's TileSets and BranchCapTileSets. As such you must guarantee that those elements can be replaced.")]
public int LineRandomizerTakeCount = 3;
[Header("Max Shadows Request")]
[Tooltip("If enabled, updates the MaxShadowsRequest to MaxShadowsRequestAmount when your dungeon loads.\n\nThis is designed for the scenario where your dungeon, for whatever reason, has too many lights nearby and causes the annoying 'Max shadow requests count reached' warning to spam the logs.")]
public bool UseMaxShadowsRequestUpdate = false;
[Tooltip("The amount of MaxShadowsRequest.\n\n4 is the game's default value. I find 8 to be more than acceptable.")]
public int MaxShadowsRequestAmount = 8;
public LineRandomizerProperties LineRandomizerProperties = new LineRandomizerProperties();
[Header("Miscellaneous")]
[Tooltip("If enabled, the DoorwaySisters component will become active.\n\nThe component prevents an intersecting doorway from generating if it's 'sister' doorway already generated and both doorways would lead to the same neighboring tile.\n\nThis is designed for the scenario where, two neighboring doorways would lead to the same tile, one doorway is a locked door and the other is an open doorway. This would defeat the purpose of the locked door, and such as, this feature exists if needed.\n\nThis feature slows down dungeon generation slightly when enabled.")]
public bool UseDoorwaySisters = false;
[Tooltip("If enabled, the RandomGuaranteedScrapSpawn component will be come active.\n\nThe component allows random scrap of a specified minimum value to always be spawned on a specific point.")]
public bool UseRandomGuaranteedScrapSpawn = false;
public MiscellaneousProperties MiscellaneousProperties = new MiscellaneousProperties();
internal void SetupProperties(DungeonGenerator generator){
_normalNodeArchetypesDictioanry = new Dictionary<string, NodeArchetype>();
_defaultNodeArchetype = null;
foreach(var n in NormalNodeArchetypes) {
if (_normalNodeArchetypesDictioanry.ContainsKey(n.label)) {
Plugin.logger.LogError($"Label {n.label} already exists. Ignoring latest entry.");
continue;
}
_normalNodeArchetypesDictioanry.Add(n.label, n);
if (string.IsNullOrWhiteSpace(n.label)) {
_defaultNodeArchetype = n;
}
}
}
internal DungeonArchetype GetRandomArchetype(string label, RandomStream randomStream) {
NodeArchetype node;
if (!_normalNodeArchetypesDictioanry.TryGetValue(label, out node)) {
node = _defaultNodeArchetype;
}
if (node != null) {
var archetypes = node.archetypes;
var count = archetypes.Count;
if (count == 0) return null;
var index = randomStream.Next(0, count);
return archetypes[index];
}
return null;
}
internal Bounds GetDungeonBounds(float dungeonScale) {
var size = DungeonSizeBase + Vector3.Scale(DungeonSizeBase * (dungeonScale - 1), DungeonSizeFactor);
var offset = DungeonPositionOffset + Vector3.Scale(size, DungeonPositionPivot - Vector3.one * 0.5f);
return new Bounds(offset, size);
}
[Header("Asset Cache (FOR DEV DEBUG PURPOSES ONLY)")]
public List<GameObject> AssetCacheTileList = new List<GameObject>();
public List<TileSet> AssetCacheTileSetList = new List<TileSet>();
public List<DungeonArchetype> AssetCacheArchetypeList = new List<DungeonArchetype>();
internal void CopyFrom(DunGenExtenderProperties props) {
MainPathCount = props.MainPathCount;
MainRoomTilePrefab = props.MainRoomTilePrefab;
MainPathCopyNodeBehaviour = props.MainPathCopyNodeBehaviour;
UseDungeonBounds = props.UseDungeonBounds;
DungeonSizeBase = props.DungeonSizeBase;
DungeonSizeFactor = props.DungeonSizeFactor;
DungeonPositionOffset = props.DungeonPositionOffset;
DungeonPositionPivot = props.DungeonPositionPivot;
AddArchetypesToNormalNodes = props.AddArchetypesToNormalNodes;
NormalNodeArchetypes = props.NormalNodeArchetypes;
UseForcedTiles = props.UseForcedTiles;
ForcedTileSets = props.ForcedTileSets;
UseBranchLoopBoost = props.UseBranchLoopBoost;
BranchLoopBoostTileSearch = props.BranchLoopBoostTileSearch;
BranchLoopBoostTileScale = props.BranchLoopBoostTileScale;
UseLineRandomizer = props.UseLineRandomizer;
LineRandomizerTileSets = props.LineRandomizerTileSets;
LineRandomizerArchetypes = props.LineRandomizerArchetypes;
LineRandomizerTakeCount = props.LineRandomizerTakeCount;
UseMaxShadowsRequestUpdate = props.UseMaxShadowsRequestUpdate;
MaxShadowsRequestAmount = props.MaxShadowsRequestAmount;
UseDoorwaySisters = props.UseDoorwaySisters;
UseRandomGuaranteedScrapSpawn = props.UseRandomGuaranteedScrapSpawn;
MainPathProperties = props.MainPathProperties.Copy();
DungeonBoundsProperties = props.DungeonBoundsProperties.Copy();
NormalNodeArchetypesProperties = props.NormalNodeArchetypesProperties.Copy();
ForcedTilesProperties = props.ForcedTilesProperties.Copy();
BranchPathMultiSimulationProperties = props.BranchPathMultiSimulationProperties.Copy();
LineRandomizerProperties = props.LineRandomizerProperties.Copy();
MiscellaneousProperties = props.MiscellaneousProperties.Copy();
}
internal DunGenExtenderProperties Copy() {

View File

@ -0,0 +1,256 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static DunGenPlus.Collections.DunGenExtenderProperties;
using UnityEngine;
using DunGen;
namespace DunGenPlus.Collections {
[System.Serializable]
public class MainPathProperties {
[Tooltip("The number of main paths.\n\n1 means no additional main paths\n3 means two additional main paths\netc.")]
[Range(1, 9)]
public int MainPathCount = 1;
[Tooltip("The Tile Prefab where the additional main paths will start from. Cannot be null if MainPathCount is more than 1.")]
public GameObject MainRoomTilePrefab;
[Tooltip("CopyFromMainPathPosition means that nodes will copy from the MainRoomTilePrefab's position in the main path.\n\nCopyFromNodeList means that nodes will copy from the MainRoomTilePrefab's location from the node list + 1.")]
public CopyNodeBehaviour CopyNodeBehaviour = CopyNodeBehaviour.CopyFromMainPathPosition;
internal void CopyFrom(MainPathProperties props) {
MainPathCount = props.MainPathCount;
MainRoomTilePrefab = props.MainRoomTilePrefab;
CopyNodeBehaviour = props.CopyNodeBehaviour;
}
internal MainPathProperties Copy() {
var copy = new MainPathProperties();
copy.CopyFrom(this);
return copy;
}
}
[System.Serializable]
public class DungeonBoundsProperties {
[Tooltip("If enabled, restricts the dungeon's generation to the bounds described below.\n\nThis will help in condensing the dungeon, but it will increase the chance of dungeon generation failure (potentially guarantees failure if the bounds is too small).")]
public bool UseDungeonBounds = false;
[Tooltip("The base size of the bounds.")]
public Vector3 SizeBase = new Vector3(120f, 40f, 80f);
[Tooltip("The factor that's multiplied with the base size AND the dungeon's size. The resulting value is added to the base size of the bounds.\n\n0 means that the bound size is not influenced by the dungeon's size and is therefore a constant.")]
public Vector3 SizeFactor = new Vector3(1f, 0.5f, 1f);
[Tooltip("The base positional offset of the bounds.")]
public Vector3 PositionOffset = Vector3.zero;
[Tooltip("The pivot of the bounds.")]
public Vector3 PositionPivot = new Vector3(0.5f, 0.5f, 0.5f);
internal void CopyFrom(DungeonBoundsProperties props) {
UseDungeonBounds = props.UseDungeonBounds;
SizeBase = props.SizeBase;
SizeFactor = props.SizeFactor;
PositionOffset = props.PositionOffset;
PositionPivot = props.PositionPivot;
}
internal DungeonBoundsProperties Copy() {
var copy = new DungeonBoundsProperties();
copy.CopyFrom(this);
return copy;
}
internal Bounds GetDungeonBounds(float dungeonScale) {
var size = SizeBase + Vector3.Scale(SizeBase * (dungeonScale - 1), SizeFactor);
var offset = PositionOffset + Vector3.Scale(size, PositionPivot - Vector3.one * 0.5f);
return new Bounds(offset, size);
}
}
[System.Serializable]
public class NormalNodeArchetypesProperties {
[Tooltip("If enabled, adds archetypes to the normal nodes in the DungeonFlow.\n\nBy default, nodes cannot have branching paths since they don't have archetype references. This allows nodes to have branching paths.")]
public bool AddArchetypesToNormalNodes = false;
public List<NodeArchetype> NormalNodeArchetypes = new List<NodeArchetype>();
internal Dictionary<string, NodeArchetype> _normalNodeArchetypesDictioanry;
internal NodeArchetype _defaultNodeArchetype;
internal void CopyFrom(NormalNodeArchetypesProperties props)
{
AddArchetypesToNormalNodes = props.AddArchetypesToNormalNodes;
NormalNodeArchetypes = props.NormalNodeArchetypes;
}
internal NormalNodeArchetypesProperties Copy()
{
var copy = new NormalNodeArchetypesProperties();
copy.CopyFrom(this);
return copy;
}
internal void SetupProperties(DungeonGenerator generator)
{
_normalNodeArchetypesDictioanry = new Dictionary<string, NodeArchetype>();
_defaultNodeArchetype = null;
foreach (var n in NormalNodeArchetypes)
{
if (_normalNodeArchetypesDictioanry.ContainsKey(n.label))
{
Plugin.logger.LogError($"Label {n.label} already exists. Ignoring latest entry.");
continue;
}
_normalNodeArchetypesDictioanry.Add(n.label, n);
if (string.IsNullOrWhiteSpace(n.label))
{
_defaultNodeArchetype = n;
}
}
}
internal DungeonArchetype GetRandomArchetype(string label, RandomStream randomStream)
{
NodeArchetype node;
if (!_normalNodeArchetypesDictioanry.TryGetValue(label, out node))
{
node = _defaultNodeArchetype;
}
if (node != null)
{
var archetypes = node.archetypes;
var count = archetypes.Count;
if (count == 0) return null;
var index = randomStream.Next(0, count);
return archetypes[index];
}
return null;
}
}
[System.Serializable]
public class ForcedTilesProperties {
[Tooltip("If enabled, attempts to forcefully spawn tiles from ForcedTileSets after branching paths are generated.\n\nCan only be used if MainPathCount > 1.")]
public bool UseForcedTiles = false;
[Tooltip("The list of tiles that will be attempted to forcefully spawn. Each entry will spawn only one tile from it's list.\n\nIf the tile cannot be forcefully spawned, the dungeon generation will not restart.")]
public List<ForcedTileSetList> ForcedTileSets = new List<ForcedTileSetList>();
internal void CopyFrom(ForcedTilesProperties props) {
UseForcedTiles = props.UseForcedTiles;
ForcedTileSets = props.ForcedTileSets;
}
internal ForcedTilesProperties Copy() {
var copy = new ForcedTilesProperties();
copy.CopyFrom(this);
return copy;
}
}
[System.Serializable]
public class BranchPathMultiSimulationProperties {
[Tooltip("If enabled, dungeon generation will simulate a number of branch paths for each branch path, then choose the best branch path based on its weight. The weight is decided by the following criteria. Slows down Branch Path Times by a second or two.")]
public bool UseBranchPathMultiSim = false;
[Tooltip("The number pf simulations per branch path.\n\nIncreasing this value can increase your chances of finding your best path, but will increase Branch Path Times and vice versa.")]
public int SimulationCount = 5;
[Tooltip("The weight scale for the branch path's length. The length of the branch path is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize very long branch paths.")]
public float LengthWeightScale = 0.125f;
[Tooltip("The weight scale for the branch path's normalized length. The normalized length (0 -> 1) of the branch path (PathLength / MaxPathLength) is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who meet their maximum path length.")]
public float NormalizedLengthWeightScale = 1f;
[Tooltip("The weight scale for the branch path's number of connections to the same main path. The number of possible connections is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make path loops in their main path in general.")]
public float SamePathBaseWeightScale = 0.125f;
[Tooltip("The weight scale for the branch path's number of connections to the same main path. For each possible connection, the main path depth difference is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make deep path loops to their main paths")]
public float SamePathDepthWeightScale = 0.125f;
[Tooltip("The weight scale for the branch path's number of connections to the same main path. For each possible connection, the main path normalized depth difference is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make generally deep path loops to their main paths")]
public float SamePathNormalizedDepthWeightScale = 1f;
[Tooltip("The weight scale for the branch path's number of connections to other main paths. The number of possible connections is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make path loops to other main paths in general.")]
public float DiffPathBaseWeightScale = 0.25f;
[Tooltip("The weight scale for the branch path's number of connections to other main paths. For each possible connection, the main path depth difference is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make deep path loops to other main paths.")]
public float DiffPathDepthWeightScale = 0.25f;
[Tooltip("The weight scale for the branch path's number of connections to other main paths. For each possible connection, the main path normalized depth difference is multiplied by the scale and is added to the branch path's weight.\n\nIncreasing this value will prioritize branch paths who make generally deep path loops to other main paths.")]
public float DiffPathNormalizedDepthWeightScale = 2f;
internal void CopyFrom(BranchPathMultiSimulationProperties props) {
UseBranchPathMultiSim = props.UseBranchPathMultiSim;
SimulationCount = props.SimulationCount;
LengthWeightScale = props.LengthWeightScale;
NormalizedLengthWeightScale = props.NormalizedLengthWeightScale;
SamePathBaseWeightScale = props.SamePathBaseWeightScale;
DiffPathBaseWeightScale = props.DiffPathBaseWeightScale;
SamePathDepthWeightScale = props.SamePathDepthWeightScale;
DiffPathDepthWeightScale = props.DiffPathDepthWeightScale;
SamePathNormalizedDepthWeightScale = props.SamePathNormalizedDepthWeightScale;
DiffPathNormalizedDepthWeightScale = props.DiffPathNormalizedDepthWeightScale;
}
internal BranchPathMultiSimulationProperties Copy() {
var copy = new BranchPathMultiSimulationProperties();
copy.CopyFrom(this);
return copy;
}
}
[System.Serializable]
public class LineRandomizerProperties {
[Tooltip("If enabled, every archetype in LineRandomizerArchetypes will have the last LineRandomizerTakeCount tilesets replaced by a randomly selected set of tilesets from LineRandomizerTileSets. This applies for both archetype's TileSets and BranchCapTileSets.\n\nThis is designed for the scenario where dungeon generation takes a long time due to the combination of too many tiles and/or doorways in those tiles. This can reduce dungeon generation time while keeping some of the randomness of dungeon generation.\n\nAs stated previously, this WILL replace the last LineRandomizerTakeCount tilesets in the archetype's TileSets and BranchCapTileSets. As such you must guarantee that those elements can be replaced.")]
public bool UseLineRandomizer = false;
[Tooltip("The archetypes whose tilesets will be replaced.\n\nThese archetypes should ideally used in the Lines section of DungeonFlow, but it's a free country.")]
public List<DungeonArchetype> Archetypes = new List<DungeonArchetype>();
[Tooltip("The tilesets that will be used for replacement.")]
public List<TileSet> TileSets = new List<TileSet>();
[Tooltip("The amount of tilesets that will be replaced from the archetypes, starting from the last element to the first element.\n\nAs stated previously, this WILL replace the tilesets in the archetype's TileSets and BranchCapTileSets. As such you must guarantee that those elements can be replaced.")]
public int TileSetsTakeCount = 3;
internal void CopyFrom(LineRandomizerProperties props) {
UseLineRandomizer = props.UseLineRandomizer;
Archetypes = props.Archetypes;
TileSets = props.TileSets;
}
internal LineRandomizerProperties Copy() {
var copy = new LineRandomizerProperties();
copy.CopyFrom(this);
return copy;
}
}
[System.Serializable]
public class MiscellaneousProperties {
[Tooltip("If enabled, updates the MaxShadowsRequest to MaxShadowsRequestAmount when your dungeon loads.\n\nThis is designed for the scenario where your dungeon, for whatever reason, has too many lights nearby and causes the annoying 'Max shadow requests count reached' warning to spam the logs.")]
public bool UseMaxShadowsRequestUpdate = false;
[Tooltip("The amount of MaxShadowsRequest.\n\n4 is the game's default value. I find 8 to be more than acceptable.")]
public int MaxShadowsRequestCount = 8;
[Tooltip("If enabled, the DoorwaySisters component will become active.\n\nThe component prevents an intersecting doorway from generating if it's 'sister' doorway already generated and both doorways would lead to the same neighboring tile.\n\nThis is designed for the scenario where, two neighboring doorways would lead to the same tile, one doorway is a locked door and the other is an open doorway. This would defeat the purpose of the locked door, and such as, this feature exists if needed.\n\nThis feature slows down dungeon generation slightly when enabled.")]
public bool UseDoorwaySisters = false;
[Tooltip("If enabled, the RandomGuaranteedScrapSpawn component will be come active.\n\nThe component allows random scrap of a specified minimum value to always be spawned on a specific point.")]
public bool UseRandomGuaranteedScrapSpawn = false;
internal void CopyFrom(MiscellaneousProperties props) {
UseMaxShadowsRequestUpdate = props.UseMaxShadowsRequestUpdate;
MaxShadowsRequestCount = props.MaxShadowsRequestCount;
UseDoorwaySisters = props.UseDoorwaySisters;
UseRandomGuaranteedScrapSpawn = props.UseRandomGuaranteedScrapSpawn;
}
internal MiscellaneousProperties Copy() {
var copy = new MiscellaneousProperties();
copy.CopyFrom(this);
return copy;
}
}
}

View File

@ -12,6 +12,7 @@ using LethalLevelLoader;
using UnityEngine.InputSystem;
using DunGenPlus.DevTools.Panels;
using DunGenPlus.DevTools.UIElements;
using DunGenPlus.Generation;
namespace DunGenPlus.DevTools {
internal partial class DevDebugManager : MonoBehaviour {
@ -101,6 +102,10 @@ namespace DunGenPlus.DevTools {
selectedDungeonFlow.DungeonEvents.onBeforeDungeonGenerate?.Invoke(fakeRoundManager);
DungeonManager.GlobalDungeonEvents?.onBeforeDungeonGenerate?.Invoke(fakeRoundManager);
DunGenPlusGenerator.GenerateBranchBoostedPathsTime = 0f;
DunGenPlusGenerator.GetTileResultTime = 0f;
DunGenPlusGenerator.DoorwayPairTime = 0f;
DunGenPlusGenerator.CalculateWeightTime = 0f;
dungeon.Generate();
}
@ -156,6 +161,12 @@ namespace DunGenPlus.DevTools {
textList.AppendLine($"Post Process Time: {stats.PostProcessTime:F2} ms");
textList.AppendLine($"Total Time: {stats.TotalTime:F2} ms");
textList.AppendLine("");
textList.AppendLine($"GenerateBranch Time: {DunGenPlusGenerator.GenerateBranchBoostedPathsTime:F2} ms");
textList.AppendLine($"GetTileResult Time: {DunGenPlusGenerator.GetTileResultTime:F2} ms");
textList.AppendLine($"DoorwayPair Time: {DunGenPlusGenerator.DoorwayPairTime:F2} ms");
textList.AppendLine($"CalculateWeight Time: {DunGenPlusGenerator.CalculateWeightTime:F2} ms");
statsTextMesh.text = textList.ToString();
}

View File

@ -52,42 +52,41 @@ namespace DunGenPlus.DevTools.Panels.Collections {
}
foreach(var t in extender.DungeonFlow.Nodes.SelectMany(n => n.TileSets)) {
tileSetsHashSet.Add(t);
foreach(var x in t.TileWeights.Weights) {
tilesHashSet.Add(x.Value);
}
}
foreach(var a in extender.DungeonFlow.Lines.SelectMany(l => l.DungeonArchetypes)) {
archetypesHashSet.Add(a);
foreach(var t in a.TileSets) {
tileSetsHashSet.Add(t);
foreach(var x in t.TileWeights.Weights) {
tilesHashSet.Add(x.Value);
}
}
}
foreach(var n in extender.Properties.NormalNodeArchetypes) {
foreach(var a in n.archetypes){
archetypesHashSet.Add(a);
foreach(var t in a.TileSets){
tileSetsHashSet.Add(t);
foreach(var x in t.TileWeights.Weights){
tilesHashSet.Add(x.Value);
}
}
void AddTiles(IEnumerable<GameObject> tiles){
foreach(var x in tiles) {
tilesHashSet.Add(x);
}
}
foreach(var t in extender.Properties.ForcedTileSets.SelectMany(l => l.Tilesets)){
tileSetsHashSet.Add(t);
foreach(var x in t.TileWeights.Weights){
void AddTilesW(IEnumerable<GameObjectChance> tiles){
foreach(var x in tiles) {
tilesHashSet.Add(x.Value);
}
}
void AddTileSets(IEnumerable<TileSet> tileSets){
foreach(var x in tileSets){
tileSetsHashSet.Add(x);
AddTilesW(x.TileWeights.Weights);
}
}
void AddArchetypes(IEnumerable<DungeonArchetype> archetypes){
foreach(var x in archetypes){
archetypesHashSet.Add(x);
AddTileSets(x.TileSets);
}
}
AddTileSets(extender.DungeonFlow.Nodes.SelectMany(n => n.TileSets));
AddArchetypes(extender.DungeonFlow.Lines.SelectMany(l => l.DungeonArchetypes));
AddArchetypes(extender.Properties.NormalNodeArchetypesProperties.NormalNodeArchetypes.SelectMany(l => l.archetypes));
AddTileSets(extender.Properties.ForcedTilesProperties.ForcedTileSets.SelectMany(l => l.Tilesets));
AddTiles(extender.Properties.AssetCacheTileList);
AddTileSets(extender.Properties.AssetCacheTileSetList);
AddArchetypes(extender.Properties.AssetCacheArchetypeList);
tileSets = new Collection<NullObject<TileSet>>(tileSetsHashSet.ToList());
tiles = new Collection<NullObject<GameObject>>(tilesHashSet.ToList());
archetypes = new Collection<NullObject<DungeonArchetype>>(archetypesHashSet.ToList());

View File

@ -98,63 +98,73 @@ namespace DunGenPlus.DevTools.Panels {
var mainPathTransform = manager.CreateVerticalLayoutUIField(parentTransform);
mainPathParentGameobject = mainPathTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Main Path");
manager.CreateIntSliderField(parentTransform, "Main Path Count", new IntParameter(properties.MainPathCount, 1, 10), SetMainPathCount);
manager.CreateIntSliderField(parentTransform, "Main Path Count", new IntParameter(properties.MainPathProperties.MainPathCount, 1, 10), SetMainPathCount);
mainPathTransform.SetAsLastSibling();
manager.CreateTileOptionsUIField(mainPathTransform, "Main Room Tile Prefab", selectedAssetCache.tiles.dictionary[properties.MainRoomTilePrefab], SetMainRoom);
manager.CreateCopyNodeBehaviourOptionsUIField(mainPathTransform, "Copy Node Behaviour", (int)properties.MainPathCopyNodeBehaviour, SetCopyNodeBehaviour);
manager.CreateTileOptionsUIField(mainPathTransform, "Main Room Tile Prefab", selectedAssetCache.tiles.dictionary[properties.MainPathProperties.MainRoomTilePrefab], SetMainRoom);
manager.CreateCopyNodeBehaviourOptionsUIField(mainPathTransform, "Copy Node Behaviour", (int)properties.MainPathProperties.CopyNodeBehaviour, SetCopyNodeBehaviour);
manager.CreateSpaceUIField(parentTransform);
var dungeonBoundsTransform = manager.CreateVerticalLayoutUIField(parentTransform);
dungeonBoundsParentGameobject = dungeonBoundsTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Dungeon Bounds");
manager.CreateBoolInputField(parentTransform, "Use Dungeon Bounds", properties.UseDungeonBounds, SetUseDungeonBounds);
manager.CreateBoolInputField(parentTransform, "Use Dungeon Bounds", properties.DungeonBoundsProperties.UseDungeonBounds, SetUseDungeonBounds);
dungeonBoundsTransform.SetAsLastSibling();
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Base", properties.DungeonSizeBase, SetDungeonBoundsSizeBase);
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Factor", properties.DungeonSizeFactor, SetDungeonBoundsSizeFactor);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Offset", properties.DungeonPositionOffset, SetDungeonBoundsPosOffset);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Pivot", properties.DungeonPositionPivot, SetDungeonBoundsPosPivot);
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Base", properties.DungeonBoundsProperties.SizeBase, SetDungeonBoundsSizeBase);
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Factor", properties.DungeonBoundsProperties.SizeFactor, SetDungeonBoundsSizeFactor);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Offset", properties.DungeonBoundsProperties.PositionOffset, SetDungeonBoundsPosOffset);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Pivot", properties.DungeonBoundsProperties.PositionPivot, SetDungeonBoundsPosPivot);
manager.CreateSpaceUIField(parentTransform);
var archetypesTransform = manager.CreateVerticalLayoutUIField(parentTransform);
archetypesNodesParentGameobject = archetypesTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Archetypes Normal Nodes");
manager.CreateBoolInputField(parentTransform, "Add Archetypes", properties.AddArchetypesToNormalNodes, SetAddArchetypes);
manager.CreateBoolInputField(parentTransform, "Add Archetypes", properties.NormalNodeArchetypesProperties.AddArchetypesToNormalNodes, SetAddArchetypes);
archetypesTransform.SetAsLastSibling();
manager.CreateListUIField(archetypesTransform, "Normal Node Archetypes", properties.NormalNodeArchetypes);
manager.CreateListUIField(archetypesTransform, "Normal Node Archetypes", properties.NormalNodeArchetypesProperties.NormalNodeArchetypes);
manager.CreateSpaceUIField(parentTransform);
var forcedTilesTransform = manager.CreateVerticalLayoutUIField(parentTransform);
forcedTilesParentGameobject = forcedTilesTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Forced Tiles");
manager.CreateBoolInputField(parentTransform, "Use Forced Tiles", properties.UseForcedTiles, SetUseForcedTiles);
manager.CreateBoolInputField(parentTransform, "Use Forced Tiles", properties.ForcedTilesProperties.UseForcedTiles, SetUseForcedTiles);
forcedTilesTransform.SetAsLastSibling();
manager.CreateListUIField(forcedTilesTransform, "Forced Tile Sets", properties.ForcedTileSets);
manager.CreateListUIField(forcedTilesTransform, "Forced Tile Sets", properties.ForcedTilesProperties.ForcedTileSets);
manager.CreateSpaceUIField(parentTransform);
var branchLoopTransform = manager.CreateVerticalLayoutUIField(parentTransform);
branchLoopBoostParentGameobject = branchLoopTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Branch Loop Boost");
manager.CreateBoolInputField(parentTransform, "Use Branch Loop Boost", properties.UseBranchLoopBoost, SetUseBranchLoopBoost);
manager.CreateHeaderUIField(parentTransform, "Branch Path Multi Sim");
manager.CreateBoolInputField(parentTransform, "Use Branch Path Multi Sim", properties.BranchPathMultiSimulationProperties.UseBranchPathMultiSim, SetUseBranchPathMultiSim);
branchLoopTransform.SetAsLastSibling();
manager.CreateIntInputField(branchLoopTransform, "Tile Search Count", new IntParameter(properties.BranchLoopBoostTileSearch, 1, 100, 1), SetTileBoostSearch);
manager.CreateFloatInputField(branchLoopTransform, "Tile Boost Search", new FloatParameter(properties.BranchLoopBoostTileScale, 0f, 2f, 0f), SetTileBoostScale);
manager.CreateIntInputField(branchLoopTransform, "Simulation Count", new IntParameter(properties.BranchPathMultiSimulationProperties.SimulationCount, 1, 10, 1), SetSimulationCount);
manager.CreateFloatInputField(branchLoopTransform, "Length Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.LengthWeightScale, 0f, 2f, 0f), SetLengthScale);
manager.CreateFloatInputField(branchLoopTransform, "Norm. Length Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.NormalizedLengthWeightScale, 0f, 2f, 0f), SetNormalizedLengthScale);
manager.CreateSpaceUIField(parentTransform);
var maxShadowsTransform = manager.CreateVerticalLayoutUIField(parentTransform);
maxShadowsParentGameobject = maxShadowsTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Max Shadows Request");
manager.CreateBoolInputField(parentTransform, "Use Max Shadows Request", properties.UseMaxShadowsRequestUpdate, SetUseMaxShadows);
maxShadowsTransform.SetAsLastSibling();
manager.CreateIntInputField(maxShadowsTransform, "Shadows Request Amount", new IntParameter(properties.MaxShadowsRequestAmount, 4, 20, 4), SetMaxShadowsAmount);
manager.CreateTextUIField(branchLoopTransform, "Same Path Connect");
manager.CreateFloatInputField(branchLoopTransform, "Base Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.SamePathBaseWeightScale, 0f, 2f, 0f), SamePathBaseConnectScale);
manager.CreateFloatInputField(branchLoopTransform, "Depth Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.SamePathDepthWeightScale, 0f, 2f, 0f), SamePathConnectDepthScale);
manager.CreateFloatInputField(branchLoopTransform, "Norm. Depth Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.SamePathNormalizedDepthWeightScale, 0f, 2f, 0f), SamePathConnectNormalizedDepthScale);
manager.CreateSpaceUIField(parentTransform);
manager.CreateTextUIField(branchLoopTransform, "Diff Path Connect");
manager.CreateFloatInputField(branchLoopTransform, "Base Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.DiffPathBaseWeightScale, 0f, 2f, 0f), DiffPathBaseConnectScale);
manager.CreateFloatInputField(branchLoopTransform, "Depth Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.DiffPathDepthWeightScale, 0f, 2f, 0f), DiffPathConnectDepthScale);
manager.CreateFloatInputField(branchLoopTransform, "Norm. Depth Weight Scale", new FloatParameter(properties.BranchPathMultiSimulationProperties.DiffPathNormalizedDepthWeightScale, 0f, 2f, 0f), DiffPathConnectNormalizedDepthScale);
manager.CreateSpaceUIField(parentTransform);
// miss
manager.CreateHeaderUIField(parentTransform, "Miscellaneous");
manager.CreateBoolInputField(parentTransform, "Use Doorway Sisters", properties.UseDoorwaySisters, SetUseDoorwaySisters);
manager.CreateBoolInputField(parentTransform, "Use Random Guaranteed Scrap", properties.UseRandomGuaranteedScrapSpawn, SetUseRandomGuaranteedScrap);
var maxShadowTransform = manager.CreateVerticalLayoutUIField(parentTransform);
maxShadowsParentGameobject = maxShadowTransform.gameObject;
manager.CreateBoolInputField(parentTransform, "Use Max Shadows Request", properties.MiscellaneousProperties.UseMaxShadowsRequestUpdate, SetUseMaxShadows);
manager.CreateIntInputField(maxShadowTransform, "Shadows Request Amount", new IntParameter(properties.MiscellaneousProperties.MaxShadowsRequestCount, 4, 20, 4), SetMaxShadowsCount);
maxShadowTransform.SetAsLastSibling();
manager.CreateBoolInputField(parentTransform, "Use Doorway Sisters", properties.MiscellaneousProperties.UseDoorwaySisters, SetUseDoorwaySisters);
manager.CreateBoolInputField(parentTransform, "Use Random Guaranteed Scrap", properties.MiscellaneousProperties.UseRandomGuaranteedScrapSpawn, SetUseRandomGuaranteedScrap);
manager.CreateSpaceUIField(parentTransform);
dungeonBoundsHelperGameObject.SetActive(selectedExtenderer.Properties.UseDungeonBounds);
dungeonBoundsHelperGameObject.SetActive(selectedExtenderer.Properties.DungeonBoundsProperties.UseDungeonBounds);
UpdateDungeonBoundsHelper();
}
@ -167,20 +177,20 @@ namespace DunGenPlus.DevTools.Panels {
}
public void SetMainPathCount(int value) {
selectedExtenderer.Properties.MainPathCount = value;
selectedExtenderer.Properties.MainPathProperties.MainPathCount = value;
mainPathParentGameobject.SetActive(value > 1);
}
public void SetMainRoom(GameObject value) {
selectedExtenderer.Properties.MainRoomTilePrefab = value;
selectedExtenderer.Properties.MainPathProperties.MainRoomTilePrefab = value;
}
public void SetCopyNodeBehaviour(DunGenExtenderProperties.CopyNodeBehaviour value) {
selectedExtenderer.Properties.MainPathCopyNodeBehaviour = value;
selectedExtenderer.Properties.MainPathProperties.CopyNodeBehaviour = value;
}
public void SetUseDungeonBounds(bool state){
selectedExtenderer.Properties.UseDungeonBounds = state;
selectedExtenderer.Properties.DungeonBoundsProperties.UseDungeonBounds = state;
dungeonBoundsHelperGameObject.SetActive(state);
dungeonBoundsParentGameobject.SetActive(state);
}
@ -189,69 +199,98 @@ namespace DunGenPlus.DevTools.Panels {
if (selectedExtenderer == null) return;
var t = dungeonBoundsHelperGameObject.transform;
var result = selectedExtenderer.Properties.GetDungeonBounds(dungeon.Generator.LengthMultiplier);
var result = selectedExtenderer.Properties.DungeonBoundsProperties.GetDungeonBounds(dungeon.Generator.LengthMultiplier);
t.localPosition = result.center;
t.localScale = result.size;
}
public void SetDungeonBoundsSizeBase(Vector3 value) {
selectedExtenderer.Properties.DungeonSizeBase = value;
selectedExtenderer.Properties.DungeonBoundsProperties.SizeBase = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsSizeFactor(Vector3 value) {
selectedExtenderer.Properties.DungeonSizeFactor = value;
selectedExtenderer.Properties.DungeonBoundsProperties.SizeFactor = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsPosOffset(Vector3 value) {
selectedExtenderer.Properties.DungeonPositionOffset = value;
selectedExtenderer.Properties.DungeonBoundsProperties.PositionOffset = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsPosPivot(Vector3 value) {
selectedExtenderer.Properties.DungeonPositionPivot = value;
selectedExtenderer.Properties.DungeonBoundsProperties.PositionPivot = value;
UpdateDungeonBoundsHelper();
}
public void SetAddArchetypes(bool state){
selectedExtenderer.Properties.AddArchetypesToNormalNodes = state;
selectedExtenderer.Properties.NormalNodeArchetypesProperties.AddArchetypesToNormalNodes = state;
archetypesNodesParentGameobject.SetActive(state);
}
public void SetUseForcedTiles(bool state){
selectedExtenderer.Properties.UseForcedTiles = state;
selectedExtenderer.Properties.ForcedTilesProperties.UseForcedTiles = state;
forcedTilesParentGameobject.SetActive(state);
}
public void SetUseBranchLoopBoost(bool state){
selectedExtenderer.Properties.UseBranchLoopBoost = state;
public void SetUseBranchPathMultiSim(bool state){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.UseBranchPathMultiSim = state;
branchLoopBoostParentGameobject.SetActive(state);
}
public void SetTileBoostSearch(int value){
selectedExtenderer.Properties.BranchLoopBoostTileSearch = value;
public void SetSimulationCount(int value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.SimulationCount = value;
}
public void SetTileBoostScale(float value){
selectedExtenderer.Properties.BranchLoopBoostTileScale = value;
public void SetLengthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.LengthWeightScale = value;
}
public void SetNormalizedLengthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.NormalizedLengthWeightScale = value;
}
public void SamePathBaseConnectScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.SamePathBaseWeightScale = value;
}
public void DiffPathBaseConnectScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.DiffPathBaseWeightScale = value;
}
public void SamePathConnectDepthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.SamePathDepthWeightScale = value;
}
public void DiffPathConnectDepthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.DiffPathDepthWeightScale = value;
}
public void SamePathConnectNormalizedDepthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.SamePathNormalizedDepthWeightScale = value;
}
public void DiffPathConnectNormalizedDepthScale(float value){
selectedExtenderer.Properties.BranchPathMultiSimulationProperties.DiffPathNormalizedDepthWeightScale = value;
}
public void SetUseMaxShadows(bool state){
selectedExtenderer.Properties.UseMaxShadowsRequestUpdate = state;
selectedExtenderer.Properties.MiscellaneousProperties.UseMaxShadowsRequestUpdate = state;
maxShadowsParentGameobject.SetActive(state);
}
public void SetMaxShadowsAmount(int value){
selectedExtenderer.Properties.MaxShadowsRequestAmount = value;
public void SetMaxShadowsCount(int value){
selectedExtenderer.Properties.MiscellaneousProperties.MaxShadowsRequestCount = value;
}
public void SetUseDoorwaySisters(bool state){
selectedExtenderer.Properties.UseDoorwaySisters = state;
selectedExtenderer.Properties.MiscellaneousProperties.UseDoorwaySisters = state;
}
public void SetUseRandomGuaranteedScrap(bool state){
selectedExtenderer.Properties.UseRandomGuaranteedScrapSpawn = state;
selectedExtenderer.Properties.MiscellaneousProperties.UseRandomGuaranteedScrapSpawn = state;
}
public void RestoreOriginalState(){

View File

@ -130,6 +130,7 @@
<Compile Include="API.cs" />
<Compile Include="Assets.cs" />
<Compile Include="Collections\DunGenExtenderEvents.cs" />
<Compile Include="Collections\DunGenExtenderPropertiesCollection.cs" />
<Compile Include="Collections\ExtenderEvent.cs" />
<Compile Include="Collections\ForcedTileSetList.cs" />
<Compile Include="Collections\NodeArchetype.cs" />

View File

@ -20,7 +20,7 @@ namespace DunGenPlus.Generation {
public static Dictionary<DoorwayProxy, Data> doorwayProxyDictionary;
public static void UpdateCache(IEnumerable<DoorwayProxy> list){
if (!DunGenPlusGenerator.Active || !DunGenPlusGenerator.Properties.UseDoorwaySisters) return;
if (!DunGenPlusGenerator.Active || !DunGenPlusGenerator.Properties.MiscellaneousProperties.UseDoorwaySisters) return;
Plugin.logger.LogDebug("Updating DoorwayProxy cache for DoorwaySistersRule");
doorwayDictionary = new Dictionary<Doorway, Data>();
@ -55,7 +55,7 @@ namespace DunGenPlus.Generation {
//Plugin.logger.LogInfo($"{tileA.Prefab.name} <-> {tileB.Prefab.name}: {(doorwayA.Position - doorwayB.Position).sqrMagnitude}");
if (!result) return false;
if (!DunGenPlusGenerator.Active || !DunGenPlusGenerator.Properties.UseDoorwaySisters) return true;
if (!DunGenPlusGenerator.Active || !DunGenPlusGenerator.Properties.MiscellaneousProperties.UseDoorwaySisters) return true;
var infoA = doorwayProxyDictionary[doorwayA].info;
var infoB = doorwayProxyDictionary[doorwayB].info;

View File

@ -22,6 +22,7 @@ namespace DunGenPlus.Generation {
internal partial class DunGenPlusGenerator {
public static DunGenExtender Instance { get; internal set; }
public static DunGenExtenderProperties Properties { get; internal set; }
public static bool Active { get; internal set; }
public static bool ActiveAlternative { get; internal set; }
@ -36,25 +37,25 @@ namespace DunGenPlus.Generation {
var props = extender.Properties.Copy();
var callback = new EventCallbackScenario(DevDebugManager.Instance);
Instance.Events.OnModifyDunGenExtenderProperties.Invoke(props, callback);
props.SetupProperties(generator);
props.NormalNodeArchetypesProperties.SetupProperties(generator);
Properties = props;
if (Properties.UseDungeonBounds) {
if (Properties.DungeonBoundsProperties.UseDungeonBounds) {
generator.DebugRender = true;
generator.RestrictDungeonToBounds = Properties.UseDungeonBounds;
var bounds = Properties.GetDungeonBounds(generator.LengthMultiplier);
generator.RestrictDungeonToBounds = true;
var bounds = Properties.DungeonBoundsProperties.GetDungeonBounds(generator.LengthMultiplier);
generator.TilePlacementBounds = bounds;
Plugin.logger.LogDebug($"Dungeon Bounds: {bounds}");
}
if (Properties.UseMaxShadowsRequestUpdate) {
Plugin.logger.LogDebug($"Updating HDRP asset: setting max shadows request to {Properties.MaxShadowsRequestAmount}");
if (Properties.MiscellaneousProperties.UseMaxShadowsRequestUpdate) {
Plugin.logger.LogDebug($"Updating HDRP asset: setting max shadows request to {Properties.MiscellaneousProperties.MaxShadowsRequestCount}");
try {
previousHDRPAsset = QualitySettings.renderPipeline as HDRenderPipelineAsset;
newHDRPAsset = ScriptableObject.Instantiate(previousHDRPAsset);
var settings = newHDRPAsset.currentPlatformRenderPipelineSettings;
settings.hdShadowInitParams.maxScreenSpaceShadowSlots = Properties.MaxShadowsRequestAmount;
settings.hdShadowInitParams.maxScreenSpaceShadowSlots = Properties.MiscellaneousProperties.MaxShadowsRequestCount;
newHDRPAsset.currentPlatformRenderPipelineSettings = settings;
QualitySettings.renderPipeline = newHDRPAsset;
@ -83,9 +84,27 @@ namespace DunGenPlus.Generation {
}
}
private static Dictionary<TileProxy, int> tileProxyMainPath = new Dictionary<TileProxy, int>();
public static int GetMainPathIndexFromTileProxy(TileProxy tileProxy){
return tileProxyMainPath[tileProxy];
}
private static void AddTileProxyToMainPathDictionary(IEnumerable<TileProxy> tileProxies, int index) {
var totalLength = (float)tileProxies.Last().Placement.PathDepth;
foreach(var t in tileProxies) {
tileProxyMainPath.Add(t, index);
t.Placement.NormalizedPathDepth = t.Placement.PathDepth / totalLength;
}
}
public static IEnumerator GenerateAlternativeMainPaths(DungeonGenerator gen) {
var altCount = Properties.MainPathCount - 1;
var altCount = Properties.MainPathProperties.MainPathCount - 1;
tileProxyMainPath.Clear();
var mainRoomTilePrefab = Properties.MainPathProperties.MainRoomTilePrefab;
var copyNodeBehaviour = Properties.MainPathProperties.CopyNodeBehaviour;
// default behaviour in case the multiple main paths are not considered
if (!Active) {
@ -103,7 +122,7 @@ namespace DunGenPlus.Generation {
yield break;
}
if (Properties.MainRoomTilePrefab == null) {
if (mainRoomTilePrefab == null) {
Plugin.logger.LogWarning($"Switching to default dungeon branch generation due to MainRoomTilePrefab being null");
ActiveAlternative = false;
yield return gen.Wait(gen.GenerateBranchPaths());
@ -112,11 +131,13 @@ namespace DunGenPlus.Generation {
}
var allMainPathTiles = new List<List<TileProxy>>();
allMainPathTiles.Add(gen.proxyDungeon.MainPathTiles.ToList());
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
var mainRoom = gen.proxyDungeon.MainPathTiles.FirstOrDefault(t => t.Prefab == Properties.MainRoomTilePrefab);
var mainRoom = gen.proxyDungeon.MainPathTiles.FirstOrDefault(t => t.Prefab == mainRoomTilePrefab);
if (mainRoom == null) {
Plugin.logger.LogWarning($"Switching to default dungeon branch generation due to MainRoomTilePrefab not spawning on the main path");
ActiveAlternative = false;
@ -133,8 +154,8 @@ namespace DunGenPlus.Generation {
// nodes
var nodesSorted = gen.DungeonFlow.Nodes.OrderBy(n => n.Position).ToList();
var startingNodeIndexCache = -1;
if (Properties.MainPathCopyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
startingNodeIndexCache = nodesSorted.FindIndex(n => n.TileSets.SelectMany(t => t.TileWeights.Weights).Any(t => t.Value == Properties.MainRoomTilePrefab));
if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
startingNodeIndexCache = nodesSorted.FindIndex(n => n.TileSets.SelectMany(t => t.TileWeights.Weights).Any(t => t.Value == mainRoomTilePrefab));
if (startingNodeIndexCache == -1) {
Plugin.logger.LogWarning($"Switching to default dungeon branch generation due to CopyNodeBehaviour being CopyFromNodeList AND MainRoomTilePrefab not existing in the Nodes' tilesets");
@ -158,16 +179,17 @@ namespace DunGenPlus.Generation {
var archetypes = new List<DungeonArchetype>(targetLength);
var newMainPathTiles = new List<TileProxy>();
newMainPathTiles.Add(mainRoom);
// this causes the main room to create three sets of branch paths
// newMainPathTiles.Add(mainRoom);
int startingNodeIndex;
if (Properties.MainPathCopyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromMainPathPosition) {
if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromMainPathPosition) {
var lineDepthRatio = Mathf.Clamp01(1f / (targetLength - 1));
startingNodeIndex = nodesSorted.FindIndex(n => n.Position >= lineDepthRatio);
} else if (Properties.MainPathCopyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
} else if (copyNodeBehaviour == DunGenExtenderProperties.CopyNodeBehaviour.CopyFromNodeList) {
startingNodeIndex = startingNodeIndexCache;
} else {
Plugin.logger.LogError($"{Properties.MainPathCopyNodeBehaviour} is not yet defined. How did this happen?");
Plugin.logger.LogError($"{copyNodeBehaviour} is not yet defined. How did this happen?");
startingNodeIndex = -1;
}
@ -189,9 +211,6 @@ namespace DunGenPlus.Generation {
gen.previousLineSegment = lineAtDepth;
}
// terrible solution but FUCK it
// and yet it worked
// this is how my last node cannot be a target of pruning
GraphNode graphNode = null;
DungeonArchetype archetype = null;
foreach(var g in nodes) {
@ -256,8 +275,8 @@ namespace DunGenPlus.Generation {
if (gen.ShouldSkipFrame(true)) yield return gen.GetRoomPause();
}
AddTileProxyToMainPathDictionary(newMainPathTiles, b + 1);
allMainPathTiles.Add(newMainPathTiles);
}
// okay lets fix the fakes
@ -277,7 +296,13 @@ namespace DunGenPlus.Generation {
RandomizeLineArchetypes(gen, false);
gen.proxyDungeon.MainPathTiles = allMainPathTiles[b];
if (Properties.UseBranchLoopBoost) yield return gen.Wait(GenerateBranchBoostedPaths(gen));
if (Properties.BranchPathMultiSimulationProperties.UseBranchPathMultiSim) {
GenerateBranchBoostedPathsStopWatch.Reset();
GenerateBranchBoostedPathsStopWatch.Start();
yield return gen.Wait(GenerateMultiBranchPaths(gen));
GenerateBranchBoostedPathsStopWatch.Stop();
GenerateBranchBoostedPathsTime += (float)GenerateBranchBoostedPathsStopWatch.Elapsed.TotalMilliseconds;
}
else yield return gen.Wait(gen.GenerateBranchPaths());
}

View File

@ -2,6 +2,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using UnityEngine;
@ -9,8 +10,22 @@ namespace DunGenPlus.Generation
{
internal partial class DunGenPlusGenerator {
public static Stopwatch GenerateBranchBoostedPathsStopWatch = new Stopwatch();
public static float GenerateBranchBoostedPathsTime = 0f;
public static Stopwatch GetTileResultStopwatch = new Stopwatch();
public static float GetTileResultTime = 0f;
public static Stopwatch DoorwayPairStopwatch = new Stopwatch();
public static float DoorwayPairTime = 0f;
public static Stopwatch CalculateWeightStopwatch = new Stopwatch();
public static float CalculateWeightTime = 0f;
private class BranchPathProxy {
public TileProxy attachTileProxy;
public TileProxy mainPathTile;
public int mainPathIndex;
public List<TilePlacementResultProxy> list;
public float weight;
@ -18,7 +33,9 @@ namespace DunGenPlus.Generation
public List<InjectedTile> tilesPendingInjection;
public BranchPathProxy(DungeonGenerator gen, TileProxy attachTileProxy){
this.attachTileProxy = attachTileProxy;
mainPathTile = attachTileProxy;
mainPathIndex = GetMainPathIndexFromTileProxy(attachTileProxy);
list = new List<TilePlacementResultProxy>();
weight = 0f;
@ -27,21 +44,48 @@ namespace DunGenPlus.Generation
}
public void CalculateWeight(DungeonGenerator gen){
weight = list.Count * 0.25f;
var count = list.Count;
if (count == 0) return;
var lengthWeightScale = Properties.BranchPathMultiSimulationProperties.LengthWeightScale;
var normalizedWeightScale = Properties.BranchPathMultiSimulationProperties.NormalizedLengthWeightScale;
var samePathWeightScale = Properties.BranchPathMultiSimulationProperties.SamePathBaseWeightScale;
var diffPathWeightScale = Properties.BranchPathMultiSimulationProperties.DiffPathBaseWeightScale;
var samePathDepthWeightScale = Properties.BranchPathMultiSimulationProperties.SamePathDepthWeightScale;
var diffPathDepthWeightScale = Properties.BranchPathMultiSimulationProperties.DiffPathDepthWeightScale;
var samePathNormalizedDepthWeightScale = Properties.BranchPathMultiSimulationProperties.SamePathNormalizedDepthWeightScale;
var diffPathNormalizedDepthWeightScale = Properties.BranchPathMultiSimulationProperties.DiffPathNormalizedDepthWeightScale;
var lastNode = list[count - 1];
weight += lastNode.tileProxy.Placement.BranchDepth * lengthWeightScale;
weight += lastNode.tileProxy.Placement.NormalizedBranchDepth * normalizedWeightScale;
var allDungeonDoorways = gen.proxyDungeon.AllTiles.SelectMany(t => t.Doorways);
foreach(var t in list) {
foreach(var d in allDungeonDoorways) {
if (d.TileProxy == mainPathTile) continue;
var dIndex = GetMainPathIndexFromTileProxy(d.TileProxy);
foreach(var l in t.tileProxy.doorways) {
if (d.TileProxy == t.previousDoorway.TileProxy || d.TileProxy == attachTileProxy) continue;
if (d.TileProxy == t.previousDoorway.TileProxy) continue;
// favor paths that connect to other depths
if (gen.DungeonFlow.CanDoorwaysConnect(d.TileProxy.PrefabTile, l.TileProxy.PrefabTile, d.DoorwayComponent, l.DoorwayComponent) && Vector3.SqrMagnitude(d.Position - l.Position) < 1E-05){
var diff = Mathf.Abs(d.TileProxy.Placement.PathDepth - l.TileProxy.Placement.PathDepth);
weight += diff;
var normalDiff = Mathf.Abs(d.TileProxy.Placement.NormalizedPathDepth - l.TileProxy.Placement.NormalizedPathDepth);
var samePath = mainPathIndex == dIndex;
weight += samePath ? samePathWeightScale : diffPathWeightScale;
weight += diff * (samePath ? samePathDepthWeightScale : diffPathDepthWeightScale);
weight += normalDiff * (samePath ? samePathNormalizedDepthWeightScale : diffPathNormalizedDepthWeightScale);
}
}
}
}
//Plugin.logger.LogInfo($"Path({lastNode.tileProxy.Placement.NormalizedBranchDepth}): {weight}");
}
}
@ -68,7 +112,7 @@ namespace DunGenPlus.Generation
}
public static IEnumerator GenerateBranchBoostedPaths(DungeonGenerator gen){
public static IEnumerator GenerateMultiBranchPaths(DungeonGenerator gen){
gen.ChangeStatus(GenerationStatus.Branching);
var mainPathBranches = new int[gen.proxyDungeon.MainPathTiles.Count];
BranchCountHelper.ComputeBranchCounts(gen.DungeonFlow, gen.RandomStream, gen.proxyDungeon, ref mainPathBranches);
@ -88,7 +132,8 @@ namespace DunGenPlus.Generation
// create a bunch of proxy paths
// we evaulate later on the best one
var pathProxys = new List<BranchPathProxy>();
for(var x = 0; x < 5; ++x){
//Plugin.logger.LogInfo("New Path");
for(var x = 0; x < Properties.BranchPathMultiSimulationProperties.SimulationCount; ++x){
var currentPathProxy = new BranchPathProxy(gen, tile);
var previousTile = tile;
var branchDepth = tile.Placement.Archetype.BranchingDepth.GetRandom(gen.RandomStream);
@ -108,7 +153,13 @@ namespace DunGenPlus.Generation
// get potential tile to add
var normalizedDepth = (branchDepth <= 1) ? 1f : (float)depth / (branchDepth - 1);
GetTileResultStopwatch.Reset();
GetTileResultStopwatch.Start();
var tileResult = GetTileResult(gen, currentPathProxy, previousTile, useableTileSets, normalizedDepth, tile.Placement.Archetype);
GetTileResultStopwatch.Stop();
GetTileResultTime += (float)GetTileResultStopwatch.Elapsed.TotalMilliseconds;
var tileProxy = tileResult.tileProxy;
if (tileProxy == null) {
// it's over, we done
@ -126,13 +177,20 @@ namespace DunGenPlus.Generation
if (currentPathProxy.list.Count == 0) break;
// record path
CalculateWeightStopwatch.Reset();
CalculateWeightStopwatch.Start();
currentPathProxy.CalculateWeight(gen);
CalculateWeightStopwatch.Stop();
CalculateWeightTime += (float)CalculateWeightStopwatch.Elapsed.TotalMilliseconds;
pathProxys.Add(currentPathProxy);
}
// time to evaulate best path then add
var bestPath = pathProxys.OrderByDescending(p => p.weight).FirstOrDefault();
if (bestPath != null) {
//Plugin.logger.LogInfo($"Best path: {bestPath.weight}");
//Plugin.logger.LogInfo("");
foreach(var item in bestPath.list){
MakeTileProxyConnection(gen, item);
@ -143,6 +201,8 @@ namespace DunGenPlus.Generation
gen.injectedTiles = bestPath.injectedTiles;
gen.tilesPendingInjection = bestPath.tilesPendingInjection;
AddTileProxyToMainPathDictionary(bestPath.list.Select(x => x.tileProxy), bestPath.mainPathIndex);
if (gen.ShouldSkipFrame(true)){
yield return gen.GetRoomPause();
}
@ -225,7 +285,13 @@ namespace DunGenPlus.Generation
};
var maxCount = gen.UseMaximumPairingAttempts ? new int?(gen.MaxPairingAttempts) : null;
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();
@ -270,6 +336,7 @@ namespace DunGenPlus.Generation
if (tile == null) return new TilePlacementResultProxy(TilePlacementResult.NewTileIsNull);
tile.Placement.PathDepth = pair.PreviousTile.Placement.PathDepth;
tile.Placement.NormalizedPathDepth = pair.PreviousTile.Placement.NormalizedPathDepth;
tile.Placement.BranchDepth = pair.PreviousTile.Placement.IsOnMainPath ? 0 : (pair.PreviousTile.Placement.BranchDepth + 1);
return new TilePlacementResultProxy(TilePlacementResult.None, tile, previousDoorway, tile.Doorways[index]);

View File

@ -10,9 +10,9 @@ namespace DunGenPlus.Generation {
internal partial class DunGenPlusGenerator {
public static void AddForcedTiles(DungeonGenerator gen){
if (!Properties.UseForcedTiles) return;
if (!Properties.ForcedTilesProperties.UseForcedTiles) return;
var forcedTileSetLists = Properties.ForcedTileSets.ToList();
var forcedTileSetLists = Properties.ForcedTilesProperties.ForcedTileSets.ToList();
while(forcedTileSetLists.Count > 0){
var item = forcedTileSetLists[forcedTileSetLists.Count - 1];
@ -48,16 +48,16 @@ namespace DunGenPlus.Generation {
}
public static void RandomizeLineArchetypes(DungeonGenerator gen, bool randomizeMainPath){
if (!Properties.UseLineRandomizer) return;
if (!Properties.LineRandomizerProperties.UseLineRandomizer) return;
var flow = Instance.DungeonFlow;
var lines = flow.Lines;
var tilesetsUsed = new Dictionary<TileSet, int>();
foreach(var t in Properties.LineRandomizerTileSets){
foreach(var t in Properties.LineRandomizerProperties.TileSets){
tilesetsUsed.Add(t, 0);
}
foreach(var a in Properties.LineRandomizerArchetypes) {
foreach(var a in Properties.LineRandomizerProperties.Archetypes) {
var tiles = randomizeMainPath ? a.TileSets : a.BranchCapTileSets;
RandomizeArchetype(gen, tiles, tilesetsUsed);
}
@ -65,9 +65,9 @@ namespace DunGenPlus.Generation {
public static void RandomizeArchetype(DungeonGenerator gen, List<TileSet> targetTileSet, Dictionary<TileSet, int> tilesetsUsed){
// get 3 random
var newTiles = Properties.LineRandomizerTileSets
var newTiles = Properties.LineRandomizerProperties.TileSets
.OrderBy(t => tilesetsUsed[t] + gen.RandomStream.NextDouble())
.Take(Properties.LineRandomizerTakeCount);
.Take(Properties.LineRandomizerProperties.TileSetsTakeCount);
var i = targetTileSet.Count - 1;
foreach(var n in newTiles){
@ -81,8 +81,8 @@ namespace DunGenPlus.Generation {
public static DungeonArchetype ModifyMainBranchNodeArchetype(DungeonArchetype archetype, GraphNode node, RandomStream randomStream){
if (!DunGenPlusGenerator.Active) return archetype;
if (Properties.AddArchetypesToNormalNodes && node.NodeType == NodeType.Normal) {
return Properties.GetRandomArchetype(node.Label, randomStream);;
if (Properties.NormalNodeArchetypesProperties.AddArchetypesToNormalNodes && node.NodeType == NodeType.Normal) {
return Properties.NormalNodeArchetypesProperties.GetRandomArchetype(node.Label, randomStream);;
}
return archetype;
}

View File

@ -24,7 +24,7 @@ namespace DunGenPlus.Patches {
[HarmonyPrefix]
[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
public static void waitForScrapToSpawnToSyncPatch (ref RoundManager __instance, ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues) {
if (DunGenPlusGenerator.Active && DunGenPlusGenerator.Properties.UseRandomGuaranteedScrapSpawn) {
if (DunGenPlusGenerator.Active && DunGenPlusGenerator.Properties.MiscellaneousProperties.UseRandomGuaranteedScrapSpawn) {
var spawnedScrapList = spawnedScrap.ToList();
var scrapValuesList = scrapValues.ToList();

View File

@ -46,8 +46,8 @@ namespace DunGenPlus.Patches {
if (validStartTileTargets.TryGetValue(t.name, out var paths)) {
var extender = API.CreateDunGenExtender(d);
var props = extender.Properties;
props.MainPathCount = paths;
props.MainRoomTilePrefab = t;
props.MainPathProperties.MainPathCount = paths;
props.MainPathProperties.MainRoomTilePrefab = t;
d.Length = new DunGen.IntRange(d.Length.Min / 2, d.Length.Max / 2);
Plugin.logger.LogInfo($"New length: {d.Length}");