Added API to create extender asset

Added RandomGuaranteedScrapSpawn component
This commit is contained in:
LadyAliceMargatroid 2024-08-02 03:55:36 -07:00
parent 70f6ce5154
commit aeb8ea576e
11 changed files with 202 additions and 7 deletions

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DunGen; using DunGen;
using DunGen.Graph; using DunGen.Graph;
using UnityEngine;
namespace DunGenPlus namespace DunGenPlus
{ {
@ -16,7 +17,7 @@ namespace DunGenPlus
return false; return false;
} }
if (Plugin.DunGenExtenders.ContainsKey(dungeonFlow)) { if (ContainsDungeonFlow(dungeonFlow)) {
Plugin.logger.LogWarning($"Already contains DunGenExtender asset for {dungeonFlow.name}"); Plugin.logger.LogWarning($"Already contains DunGenExtender asset for {dungeonFlow.name}");
return false; return false;
} }
@ -36,5 +37,16 @@ namespace DunGenPlus
return AddDunGenExtender(dunGenExtender.DungeonFlow, dunGenExtender); return AddDunGenExtender(dunGenExtender.DungeonFlow, dunGenExtender);
} }
public static bool ContainsDungeonFlow(DungeonFlow dungeonFlow) {
return Plugin.DunGenExtenders.ContainsKey(dungeonFlow);
}
public static DunGenExtender CreateDunGenExtender(DungeonFlow dungeonFlow){
var extender = ScriptableObject.CreateInstance<DunGenExtender>();
extender.DungeonFlow = dungeonFlow;
return extender;
}
} }
} }

View File

@ -42,7 +42,7 @@ namespace DunGenPlus.Collections {
[Header("Archetypes on Normal Nodes")] [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.")] [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 bool AddArchetypesToNormalNodes = false;
public List<NodeArchetype> NormalNodeArchetypes; public List<NodeArchetype> NormalNodeArchetypes = new List<NodeArchetype>();
internal Dictionary<string, NodeArchetype> _normalNodeArchetypesDictioanry; internal Dictionary<string, NodeArchetype> _normalNodeArchetypesDictioanry;
internal NodeArchetype _defaultNodeArchetype; internal NodeArchetype _defaultNodeArchetype;
@ -54,9 +54,9 @@ namespace DunGenPlus.Collections {
[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.")] [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; 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.")] [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; public List<DungeonArchetype> LineRandomizerArchetypes = new List<DungeonArchetype>();
[Tooltip("The tilesets that will be used for replacement.")] [Tooltip("The tilesets that will be used for replacement.")]
public List<TileSet> LineRandomizerTileSets; 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.")] [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; public int LineRandomizerTakeCount = 3;

View File

@ -13,7 +13,7 @@ namespace DunGenPlus.Collections {
[Tooltip("The normal node with this label will gain a randomly chosen archetype.\n\nIf empty, this becomes the default choice for any normal node without a NodeArchetype specified in this list.")] [Tooltip("The normal node with this label will gain a randomly chosen archetype.\n\nIf empty, this becomes the default choice for any normal node without a NodeArchetype specified in this list.")]
public string label; public string label;
[Tooltip("The list of archetypes. One will be randomly chosen.")] [Tooltip("The list of archetypes. One will be randomly chosen.")]
public List<DungeonArchetype> archetypes; public List<DungeonArchetype> archetypes = new List<DungeonArchetype>();
} }
} }

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Unity.Netcode;
namespace DunGenPlus.Components.Scrap {
public class RandomGuaranteedScrapSpawn : MonoBehaviour {
public float spawnChance = 1f;
public int minimumScrapValue = 0;
public static Dictionary<int, IEnumerable<Item>> scrapItemCache;
public static void ResetCache(){
scrapItemCache = new Dictionary<int, IEnumerable<Item>>();
}
public static IEnumerable<Item> GetCachedItemList(List<SpawnableItemWithRarity> allMoonItems, int scrapValue) {
if (!scrapItemCache.TryGetValue(scrapValue, out var list)){
list = allMoonItems.Select(i => i.spawnableItem).Where(i => i.minValue >= scrapValue).ToArray();
scrapItemCache.Add(scrapValue, list);
}
return list;
}
public (NetworkObject itemReference, int scrapValue) CreateItem(RoundManager roundManager, List<SpawnableItemWithRarity> allMoonItems){
var anomalyRandom = roundManager.AnomalyRandom;
if (anomalyRandom.NextDouble() >= spawnChance) return (null, 0);
var itemList = GetCachedItemList(allMoonItems, minimumScrapValue);
var itemListCount = itemList.Count();
if (itemListCount == 0) return (null, 0);
var randomItem = itemList.ElementAt(anomalyRandom.Next(itemListCount));
var randomValue = (int)(anomalyRandom.Next(randomItem.minValue, randomItem.maxValue) * roundManager.scrapValueMultiplier);
var gameObject = Instantiate(randomItem.spawnPrefab, transform.position, Quaternion.identity, roundManager.spawnedScrapContainer);
var itemComp = gameObject.GetComponent<GrabbableObject>();
gameObject.transform.rotation = Quaternion.Euler(randomItem.restingRotation);
itemComp.fallTime = 0f;
itemComp.scrapValue = randomValue;
var networkComp = gameObject.GetComponent<NetworkObject>();
networkComp.Spawn(false);
return (networkComp, randomValue);
}
}
}

View File

@ -15,8 +15,8 @@ namespace DunGenPlus {
[Tooltip("DunGenExtender will only influence this DungeonFlow")] [Tooltip("DunGenExtender will only influence this DungeonFlow")]
public DungeonFlow DungeonFlow; public DungeonFlow DungeonFlow;
public DunGenExtenderProperties Properties; public DunGenExtenderProperties Properties = new DunGenExtenderProperties();
public DunGenExtenderEvents Events; public DunGenExtenderEvents Events = new DunGenExtenderEvents();
[Header("DEV ONLY: DON'T TOUCH")] [Header("DEV ONLY: DON'T TOUCH")]
public string Version = "0"; public string Version = "0";

View File

@ -60,6 +60,14 @@
<Reference Include="Unity.Collections"> <Reference Include="Unity.Collections">
<HintPath>..\..\..\Libraries\Unity.Collections.dll</HintPath> <HintPath>..\..\..\Libraries\Unity.Collections.dll</HintPath>
</Reference> </Reference>
<Reference Include="Unity.Netcode.Components, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.Netcode.Components.dll</HintPath>
</Reference>
<Reference Include="Unity.Netcode.Runtime, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.Netcode.Runtime.dll</HintPath>
</Reference>
<Reference Include="Unity.RenderPipelines.Core.Runtime, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Unity.RenderPipelines.Core.Runtime, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.RenderPipelines.Core.Runtime.dll</HintPath> <HintPath>..\..\..\Libraries\Unity.RenderPipelines.Core.Runtime.dll</HintPath>
@ -99,6 +107,7 @@
<Compile Include="Components\DoorwaySisters.cs" /> <Compile Include="Components\DoorwaySisters.cs" />
<Compile Include="Components\MainRoomDoorwayGroups.cs" /> <Compile Include="Components\MainRoomDoorwayGroups.cs" />
<Compile Include="Components\Props\SpawnSyncedObjectCycle.cs" /> <Compile Include="Components\Props\SpawnSyncedObjectCycle.cs" />
<Compile Include="Components\Scrap\RandomGuaranteedScrapSpawn.cs" />
<Compile Include="DunGenExtender.cs" /> <Compile Include="DunGenExtender.cs" />
<Compile Include="Collections\DunGenExtenderProperties.cs" /> <Compile Include="Collections\DunGenExtenderProperties.cs" />
<Compile Include="Generation\DunGenPlusGenerator.cs" /> <Compile Include="Generation\DunGenPlusGenerator.cs" />
@ -106,6 +115,8 @@
<Compile Include="Patches\DoorwayConnectionPatch.cs" /> <Compile Include="Patches\DoorwayConnectionPatch.cs" />
<Compile Include="Generation\DoorwaySistersRule.cs" /> <Compile Include="Generation\DoorwaySistersRule.cs" />
<Compile Include="Patches\DungeonGeneratorPatch.cs" /> <Compile Include="Patches\DungeonGeneratorPatch.cs" />
<Compile Include="Patches\RoundManagerPatch.cs" />
<Compile Include="Patches\StartOfRoundPatch.cs" />
<Compile Include="Plugin.cs" /> <Compile Include="Plugin.cs" />
<Compile Include="Properties\AssemblyInfo.cs" /> <Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Utils\TranspilerUtilities.cs" /> <Compile Include="Utils\TranspilerUtilities.cs" />

View File

@ -39,6 +39,7 @@ namespace DunGenPlus.Generation {
Properties = props; Properties = props;
if (Properties.UseDungeonBounds) { if (Properties.UseDungeonBounds) {
generator.DebugRender = true;
generator.RestrictDungeonToBounds = Properties.UseDungeonBounds; generator.RestrictDungeonToBounds = Properties.UseDungeonBounds;
var bounds = Properties.GetDungeonBounds(generator.LengthMultiplier); var bounds = Properties.GetDungeonBounds(generator.LengthMultiplier);
generator.TilePlacementBounds = bounds; generator.TilePlacementBounds = bounds;

View File

@ -0,0 +1,40 @@
using DunGen;
using DunGenPlus.Components.Scrap;
using DunGenPlus.Generation;
using HarmonyLib;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Netcode;
namespace DunGenPlus.Patches {
public class RoundManagerPatch {
[HarmonyPrefix]
[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
public static void waitForScrapToSpawnToSyncPatch (ref RoundManager __instance, ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues) {
if (DunGenPlusGenerator.Active) {
var spawnedScrapList = spawnedScrap.ToList();
var scrapValuesList = scrapValues.ToList();
var sources = UnityEngine.Object.FindObjectsOfType<RandomGuaranteedScrapSpawn>();
RandomGuaranteedScrapSpawn.ResetCache();
foreach(var s in sources) {
var result = s.CreateItem(__instance, __instance.currentLevel.spawnableScrap);
if (result.itemReference != null) {
Plugin.logger.LogInfo($"Created guaranteed item {result.itemReference.gameObject.name} w/ value {result.scrapValue}");
spawnedScrapList.Add(result.itemReference);
scrapValuesList.Add(result.scrapValue);
}
}
spawnedScrap = spawnedScrapList.ToArray();
scrapValues = scrapValuesList.ToArray();
}
}
}
}

View File

@ -0,0 +1,70 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
namespace DunGenPlus.Patches {
// like could be it's own mod
// but I don't wanna be the guy who messes with the original dungeon flows
// and break someone else's mod cause of X edge case
// and have to deal with that
// nah bruh, let someone else deal with it
internal class StartOfRoundPatch {
public static readonly string[] validDungeonFlowTargets = new [] {
"Level1Flow", "Level2Flow", "Level1FlowExtraLarge", "Level1Flow3Exits"
};
public static readonly Dictionary<string, int> validStartTileTargets = new Dictionary<string, int>() {
{ "StartRoom", 2 },
{ "ManorStartRoom", 3 }
};
[HarmonyPatch(typeof(RoundManager), "Awake")]
[HarmonyPrefix]
public static void AwakePatch(ref RoundManager __instance){
var dungeonFlows = __instance.dungeonFlowTypes.Select(d => d.dungeonFlow);
foreach(var d in dungeonFlows) {
if (!validDungeonFlowTargets.Contains(d.name)) continue;
if (API.ContainsDungeonFlow(d)) continue;
Plugin.logger.LogInfo($"Creating DunGenExtender for {d.name}");
var tiles = d.Lines
.Select(i => i.DungeonArchetypes)
.SelectMany(i => i)
.Select(i => i.TileSets)
.SelectMany(i => i)
.Select(i => i.TileWeights.Weights)
.SelectMany(i => i)
.Select(i => i.Value);
foreach(var t in tiles) {
if (validStartTileTargets.TryGetValue(t.name, out var paths)) {
var extender = API.CreateDunGenExtender(d);
var props = extender.Properties;
props.MainPathCount = paths;
props.MainRoomTilePrefab = t;
d.Length = new DunGen.IntRange(d.Length.Min / 2, d.Length.Max / 2);
Plugin.logger.LogInfo($"New length: {d.Length}");
if (t.name == "StartRoom") {
var lines = d.Lines;
lines[0].Length = 0.2f;
lines[1].Length -= 0.2f - lines[1].Position;
lines[1].Position = 0.2f;
}
API.AddDunGenExtender(extender);
break;
}
}
}
}
}
}

View File

@ -42,6 +42,9 @@ namespace DunGenPlus {
Harmony.PatchAll(typeof(DungeonGeneratorPatch)); Harmony.PatchAll(typeof(DungeonGeneratorPatch));
Harmony.PatchAll(typeof(DoorwayConnectionPatch)); Harmony.PatchAll(typeof(DoorwayConnectionPatch));
Harmony.PatchAll(typeof(RoundManagerPatch));
//Harmony.PatchAll(typeof(StartOfRoundPatch));
Assets.LoadAssets(); Assets.LoadAssets();
DungeonManager.GlobalDungeonEvents.onBeforeDungeonGenerate.AddListener(OnDunGenExtenderLoad); DungeonManager.GlobalDungeonEvents.onBeforeDungeonGenerate.AddListener(OnDunGenExtenderLoad);

View File

@ -14,6 +14,10 @@ Please refer to the [wiki](https://git.touhou.dev/Raphtalia/DungeonGenerationPlu
The prominent feature of this API is the ability to seemlesly add multiple main paths to your interior. Below are some examples. The prominent feature of this API is the ability to seemlesly add multiple main paths to your interior. Below are some examples.
![](https://i.imgur.com/XvygIZx.png)
![](https://i.imgur.com/GKZVqOa.png)
![](https://i.imgur.com/nN5Zz5e.png) ![](https://i.imgur.com/nN5Zz5e.png)
![](https://i.imgur.com/ogrUKAI.png) ![](https://i.imgur.com/ogrUKAI.png)