diff --git a/DunGenPlus/DunGenPlus/DunGenPlus.csproj b/DunGenPlus/DunGenPlus/DunGenPlus.csproj
index 93d47c9..4d55dd1 100644
--- a/DunGenPlus/DunGenPlus/DunGenPlus.csproj
+++ b/DunGenPlus/DunGenPlus/DunGenPlus.csproj
@@ -168,6 +168,8 @@
+
+
diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs
index 5f432ee..e6ceddc 100644
--- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs
+++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGenerator.cs
@@ -276,7 +276,9 @@ namespace DunGenPlus.Generation {
Plugin.logger.LogDebug($"Branch {b}");
RandomizeLineArchetypes(gen, false);
gen.proxyDungeon.MainPathTiles = allMainPathTiles[b];
- yield return gen.Wait(gen.GenerateBranchPaths());
+
+ if (Properties.UseBranchLoopBoost) yield return gen.Wait(GenerateBranchBoostedPaths(gen));
+ else yield return gen.Wait(gen.GenerateBranchPaths());
}
ActiveAlternative = true;
diff --git a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorBranchLoop.cs b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorBranchLoop.cs
index be4662b..a3757f6 100644
--- a/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorBranchLoop.cs
+++ b/DunGenPlus/DunGenPlus/Generation/DunGenPlusGeneratorBranchLoop.cs
@@ -1,108 +1,262 @@
using DunGen;
using System;
+using System.Collections;
using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using UnityEngine;
-namespace DunGenPlus.Generation {
+namespace DunGenPlus.Generation
+{
internal partial class DunGenPlusGenerator {
- public static (TilePlacementResult result, TileProxy tile) ProcessDoorwayPairs(DungeonGenerator gen, DungeonArchetype archetype, Queue doorwayPairs) {
- if (Properties != null && Properties.UseBranchLoopBoost && gen.Status == GenerationStatus.Branching) {
- return EncourageBranchPathLoopEncouragement(gen, doorwayPairs);
- }
+ private class BranchPathProxy {
+ public TileProxy attachTileProxy;
+ public List list;
+ public float weight;
- while(doorwayPairs.Count > 0) {
- var pair = doorwayPairs.Dequeue();
- var result = gen.TryPlaceTile(pair, archetype, out var tileProxy);
- if (result == TilePlacementResult.None) return (result, tileProxy);
- gen.AddTilePlacementResult(result);
+ public Dictionary injectedTiles;
+ public List tilesPendingInjection;
+
+ public BranchPathProxy(DungeonGenerator gen, TileProxy attachTileProxy){
+ this.attachTileProxy = attachTileProxy;
+ list = new List();
+ weight = 0f;
+
+ injectedTiles = new Dictionary(gen.injectedTiles);
+ tilesPendingInjection = new List(gen.tilesPendingInjection);
}
- return (TilePlacementResult.NoValidTile, null);
- }
+ public void CalculateWeight(DungeonGenerator gen){
+ weight = list.Count * 0.25f;
+ var allDungeonDoorways = gen.proxyDungeon.AllTiles.SelectMany(t => t.Doorways);
+ foreach(var t in list) {
+ foreach(var d in allDungeonDoorways) {
+ foreach(var l in t.tileProxy.doorways) {
+ if (d.TileProxy == t.previousDoorway.TileProxy || d.TileProxy == attachTileProxy) continue;
- public static (TilePlacementResult result, TileProxy tile) EncourageBranchPathLoopEncouragement(DungeonGenerator gen, Queue doorwayPairs) {
- // get list of 5 potential targets
- var validTiles = new List();
- while(doorwayPairs.Count > 0) {
- var pair = doorwayPairs.Dequeue();
- var value = GetTileProxyOfDoorwayPair(gen, pair);
- if (value.result == TilePlacementResult.None) {
- validTiles.Add(value);
- if (validTiles.Count >= Properties.BranchLoopBoostTileSearch) break;
- }
- }
-
- if (validTiles.Count == 0) {
- return (TilePlacementResult.NoValidTile, null);
- }
-
- // update their weight based on their potential doorway partners
- var allDungeonDoorways = gen.proxyDungeon.AllTiles.SelectMany(t => t.Doorways);
- //Plugin.logger.LogInfo("NEW TILES");
- foreach(var t in validTiles) {
- var doorwayCount = 0;
- foreach(var d in allDungeonDoorways) {
- foreach(var l in t.tile.doorways) {
- if (d.TileProxy == t.previousDoorway.TileProxy) continue;
- if (gen.DungeonFlow.CanDoorwaysConnect(d.TileProxy.PrefabTile, l.TileProxy.PrefabTile, d.DoorwayComponent, l.DoorwayComponent) && Vector3.SqrMagnitude(d.Position - l.Position) < 1E-05)
- doorwayCount++;
+ // 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;
+ }
+ }
}
}
-
- if (doorwayCount > 0) {
- //Plugin.logger.LogInfo($"{t.weight} -> {t.weight * (1f + doorwayCount * Properties.BranchLoopBoostTileScale)} ({doorwayCount})");
- t.weight *= (1f + doorwayCount * Properties.BranchLoopBoostTileScale);
- } else {
- //Plugin.logger.LogInfo($"{t.weight}");
- }
}
- var bestChoice = validTiles.OrderByDescending(t => t.weight).FirstOrDefault();
- //Plugin.logger.LogInfo($"Best: {bestChoice.weight}");
-
- MakeTileProxyConnection(gen, bestChoice);
- gen.AddTilePlacementResult(bestChoice.result);
-
- return (bestChoice.result, bestChoice.tile);
}
private class TilePlacementResultProxy {
public TilePlacementResult result;
- public TileProxy tile;
+ public TileProxy tileProxy;
public DoorwayProxy previousDoorway;
public DoorwayProxy nextDoorway;
- public float weight;
public TilePlacementResultProxy(TilePlacementResult result) {
this.result = result;
- tile = null;
+ tileProxy = null;
previousDoorway = null;
nextDoorway = null;
- weight = 0f;
}
- public TilePlacementResultProxy(TilePlacementResult result, TileProxy tile, DoorwayProxy previousDoorway, DoorwayProxy nextDoorway, float weight) {
+ public TilePlacementResultProxy(TilePlacementResult result, TileProxy tile, DoorwayProxy previousDoorway, DoorwayProxy nextDoorway) {
this.result = result;
- this.tile = tile;
+ this.tileProxy = tile;
this.previousDoorway = previousDoorway;
this.nextDoorway = nextDoorway;
- this.weight = weight;
}
}
- private static TilePlacementResultProxy GetTileProxyOfDoorwayPair(DungeonGenerator gen, DoorwayPair pair){
+ public static IEnumerator GenerateBranchBoostedPaths(DungeonGenerator gen){
+ gen.ChangeStatus(GenerationStatus.Branching);
+ var mainPathBranches = new int[gen.proxyDungeon.MainPathTiles.Count];
+ BranchCountHelper.ComputeBranchCounts(gen.DungeonFlow, gen.RandomStream, gen.proxyDungeon, ref mainPathBranches);
+
+ // do all nodes on main path
+ for(var b = 0; b < mainPathBranches.Length; ++b){
+ var tile = gen.proxyDungeon.MainPathTiles[b];
+ var branchCount = mainPathBranches[b];
+
+ // skip if not branchable tile
+ if (tile.Placement.Archetype == null || branchCount == 0) {
+ continue;
+ }
+
+ // the amount of branches per tile
+ for(var i = 0; i < branchCount; ++i){
+ // create a bunch of proxy paths
+ // we evaulate later on the best one
+ var pathProxys = new List();
+ for(var x = 0; x < 5; ++x){
+ var currentPathProxy = new BranchPathProxy(gen, tile);
+ var previousTile = tile;
+ var branchDepth = tile.Placement.Archetype.BranchingDepth.GetRandom(gen.RandomStream);
+ for(var depth = 0; depth < branchDepth; ++depth){
+
+ // get tilesets, branch cap or regular
+ List useableTileSets;
+ if (depth == branchDepth - 1 && tile.Placement.Archetype.GetHasValidBranchCapTiles()){
+ if (tile.Placement.Archetype.BranchCapType == BranchCapType.InsteadOf) {
+ useableTileSets = tile.Placement.Archetype.BranchCapTileSets;
+ } else {
+ useableTileSets = tile.Placement.Archetype.TileSets.Concat(tile.Placement.Archetype.BranchCapTileSets).ToList();
+ }
+ } else {
+ useableTileSets = tile.Placement.Archetype.TileSets;
+ }
+
+ // get potential tile to add
+ var normalizedDepth = (branchDepth <= 1) ? 1f : (float)depth / (branchDepth - 1);
+ var tileResult = GetTileResult(gen, currentPathProxy, previousTile, useableTileSets, normalizedDepth, tile.Placement.Archetype);
+ var tileProxy = tileResult.tileProxy;
+ if (tileProxy == null) {
+ // it's over, we done
+ break;
+ }
+
+ // add
+ currentPathProxy.list.Add(tileResult);
+ tileProxy.Placement.BranchDepth = depth;
+ tileProxy.Placement.NormalizedBranchDepth = normalizedDepth;
+ previousTile = tileProxy;
+ }
+
+ // we can't save this path
+ if (currentPathProxy.list.Count == 0) break;
+
+ // record path
+ currentPathProxy.CalculateWeight(gen);
+ pathProxys.Add(currentPathProxy);
+ }
+
+ // time to evaulate best path then add
+ var bestPath = pathProxys.OrderByDescending(p => p.weight).FirstOrDefault();
+ if (bestPath != null) {
+ foreach(var item in bestPath.list){
+ MakeTileProxyConnection(gen, item);
+
+ item.tileProxy.Placement.GraphNode = item.previousDoorway.TileProxy.Placement.GraphNode;
+ item.tileProxy.Placement.GraphLine = item.previousDoorway.TileProxy.Placement.GraphLine;
+ }
+
+ gen.injectedTiles = bestPath.injectedTiles;
+ gen.tilesPendingInjection = bestPath.tilesPendingInjection;
+
+ if (gen.ShouldSkipFrame(true)){
+ yield return gen.GetRoomPause();
+ }
+ }
+ }
+
+ // why null?
+ tile = null;
+ }
+
+ yield break;
+
+ }
+
+ private static TilePlacementResultProxy GetTileResult(DungeonGenerator gen, BranchPathProxy pathProxy, TileProxy attachTo, IEnumerable useableTileSets, float normalizedDepth, DungeonArchetype archetype){
+ // get tile injection
+ InjectedTile injectedTile = null;
+ var index = -1;
+ if (pathProxy.tilesPendingInjection != null) {
+ var pathDepth = (float)attachTo.Placement.PathDepth / gen.targetLength - 1f;
+ var branchDepth = normalizedDepth;
+ for(var i = 0; i < pathProxy.tilesPendingInjection.Count; ++i){
+ var injectedTile2 = pathProxy.tilesPendingInjection[i];
+ if (injectedTile2.ShouldInjectTileAtPoint(false, pathDepth, branchDepth)) {
+ injectedTile = injectedTile2;
+ index = i;
+ break;
+ }
+ }
+ }
+
+ // get tiles to consider
+ IEnumerable collection;
+ if (injectedTile != null) {
+ collection = new List(injectedTile.TileSet.TileWeights.Weights);
+ } else {
+ collection = useableTileSets.SelectMany(t => t.TileWeights.Weights);
+ }
+
+ // get rotation state
+ var value = attachTo.PrefabTile.AllowRotation;
+ if (gen.OverrideAllowTileRotation) {
+ value = gen.AllowTileRotation;
+ }
+
+ var doorwayPairFinder = new DoorwayPairFinder();
+ doorwayPairFinder.DungeonFlow = gen.DungeonFlow;
+ doorwayPairFinder.RandomStream = gen.RandomStream;
+ doorwayPairFinder.Archetype = archetype;
+ doorwayPairFinder.GetTileTemplateDelegate = new GetTileTemplateDelegate(gen.GetTileTemplate);
+ doorwayPairFinder.IsOnMainPath = false;
+ doorwayPairFinder.NormalizedDepth = normalizedDepth;
+ doorwayPairFinder.PreviousTile = attachTo;
+ doorwayPairFinder.UpVector = gen.UpVector;
+ doorwayPairFinder.AllowRotation = new bool?(value);
+ doorwayPairFinder.TileWeights = new List(collection);
+ doorwayPairFinder.IsTileAllowedPredicate = (TileProxy prev, TileProxy next, ref float weight) => {
+ var flag4 = prev != null && next.Prefab == prev.Prefab;
+ var tileRepeatMode = TileRepeatMode.Allow;
+ if (gen.OverrideRepeatMode) {
+ tileRepeatMode = gen.RepeatMode;
+ } else if (next != null) {
+ tileRepeatMode = next.PrefabTile.RepeatMode;
+ }
+ bool result2;
+ switch(tileRepeatMode) {
+ case TileRepeatMode.Allow:
+ result2 = true;
+ break;
+ case TileRepeatMode.DisallowImmediate:
+ result2 = !flag4;
+ break;
+ case TileRepeatMode.Disallow:
+ result2 = !gen.proxyDungeon.AllTiles.Where(x => x.Prefab == next.Prefab).Any();
+ break;
+ default:
+ throw new NotImplementedException($"TileRepeatMode {tileRepeatMode} is not implemented");
+ }
+ return result2;
+ };
+
+ var maxCount = gen.UseMaximumPairingAttempts ? new int?(gen.MaxPairingAttempts) : null;
+ var doorwayPairs = doorwayPairFinder.GetDoorwayPairs(maxCount);
+ var tilePlacementResult = new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
+ while(doorwayPairs.Count > 0) {
+ var pair = doorwayPairs.Dequeue();
+ tilePlacementResult = TryPlaceTileResult(gen, pathProxy, pair, archetype);
+ if (tilePlacementResult.result == TilePlacementResult.None) break;
+ }
+
+ if (tilePlacementResult.result == TilePlacementResult.None){
+ if (injectedTile != null) {
+ var tileProxy = tilePlacementResult.tileProxy;
+ tileProxy.Placement.InjectionData = injectedTile;
+ pathProxy.injectedTiles[tileProxy] = injectedTile;
+ pathProxy.tilesPendingInjection.RemoveAt(index);
+ }
+ return tilePlacementResult;
+ }
+
+ return new TilePlacementResultProxy(TilePlacementResult.NoValidTile);
+
+ }
+
+ private static TilePlacementResultProxy TryPlaceTileResult(DungeonGenerator gen, BranchPathProxy pathProxy, DoorwayPair pair, DungeonArchetype archetype){
var nextTemplate = pair.NextTemplate;
var previousDoorway = pair.PreviousDoorway;
if (nextTemplate == null) return new TilePlacementResultProxy(TilePlacementResult.TemplateIsNull);
var index = pair.NextTemplate.Doorways.IndexOf(pair.NextDoorway);
+
var tile = new TileProxy(nextTemplate);
- tile.Placement.isOnMainPath = false;
+ tile.Placement.IsOnMainPath = false;
+ tile.Placement.Archetype = archetype;
tile.Placement.TileSet = pair.NextTileSet;
if (previousDoorway != null) {
@@ -110,7 +264,7 @@ namespace DunGenPlus.Generation {
tile.PositionBySocket(myDoorway, previousDoorway);
var bounds = tile.Placement.Bounds;
if (gen.RestrictDungeonToBounds && !gen.TilePlacementBounds.Contains(bounds)) return new TilePlacementResultProxy(TilePlacementResult.OutOfBounds);
- if (gen.IsCollidingWithAnyTile(tile, previousDoorway.TileProxy)) return new TilePlacementResultProxy(TilePlacementResult.TileIsColliding);
+ if (IsCollidingWithAnyTileAndTileResult(gen, pathProxy, tile, previousDoorway.TileProxy)) return new TilePlacementResultProxy(TilePlacementResult.TileIsColliding);
}
if (tile == null) return new TilePlacementResultProxy(TilePlacementResult.NewTileIsNull);
@@ -118,14 +272,25 @@ namespace DunGenPlus.Generation {
tile.Placement.PathDepth = pair.PreviousTile.Placement.PathDepth;
tile.Placement.BranchDepth = pair.PreviousTile.Placement.IsOnMainPath ? 0 : (pair.PreviousTile.Placement.BranchDepth + 1);
- return new TilePlacementResultProxy(TilePlacementResult.None, tile, previousDoorway, tile.Doorways[index], pair.TileWeight);
+ return new TilePlacementResultProxy(TilePlacementResult.None, tile, previousDoorway, tile.Doorways[index]);
+ }
+
+ private static bool IsCollidingWithAnyTileAndTileResult(DungeonGenerator gen, BranchPathProxy pathProxy, TileProxy newTile, TileProxy previousTile){
+ foreach(var tileproxy in gen.proxyDungeon.AllTiles.Concat(pathProxy.list.Select(t => t.tileProxy))){
+ var flag = previousTile == tileproxy;
+ var maxOverlap = flag ? gen.OverlapThreshold : (-gen.Padding);
+ if (gen.DisallowOverhangs && !flag){
+ if (newTile.IsOverlappingOrOverhanging(tileproxy, gen.UpDirection, maxOverlap)) return true;
+ } else if (newTile.IsOverlapping(tileproxy, maxOverlap)) return true;
+ }
+ return false;
}
private static void MakeTileProxyConnection(DungeonGenerator gen, TilePlacementResultProxy proxy) {
if (proxy.previousDoorway != null) {
gen.proxyDungeon.MakeConnection(proxy.previousDoorway, proxy.nextDoorway);
}
- gen.proxyDungeon.AddTile(proxy.tile);
+ gen.proxyDungeon.AddTile(proxy.tileProxy);
}
}
diff --git a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs
index 2d1cfdc..b587e76 100644
--- a/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs
+++ b/DunGenPlus/DunGenPlus/Patches/DungeonGeneratorPatch.cs
@@ -78,6 +78,7 @@ namespace DunGenPlus.Patches {
archSequence.ReportComplete();
}
+ /*
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]
public static IEnumerable AddTilePatch(IEnumerable instructions, ILGenerator generator) {
@@ -145,6 +146,8 @@ namespace DunGenPlus.Patches {
}
+ */
+
[HarmonyPostfix]
[HarmonyPatch(typeof(RoundManager), "FinishGeneratingLevel")]
public static void GenerateBranchPathsPatch(){