Added setup for DunGen generation dev tools

This commit is contained in:
LadyAliceMargatroid 2024-08-23 12:23:16 -07:00
parent e2aba5fcdb
commit 3160685123
28 changed files with 1502 additions and 44 deletions

View File

@ -1,10 +1,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection.Emit;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using DunGen; using DunGen;
using DunGen.Graph; using DunGen.Graph;
using DunGenPlus.Generation;
using LethalLevelLoader;
using UnityEngine; using UnityEngine;
namespace DunGenPlus namespace DunGenPlus
@ -68,6 +71,31 @@ namespace DunGenPlus
return Plugin.DunGenExtenders.ContainsKey(dungeonFlow); return Plugin.DunGenExtenders.ContainsKey(dungeonFlow);
} }
/// <summary>
/// Checks if <paramref name="extendedDungeonFlow"/> has a registered <see cref="DunGenExtender"/>.
/// </summary>
/// <param name="extendedDungeonFlow"></param>
/// <returns>
/// <see langword="true"/> if <paramref name="extendedDungeonFlow"/> has a registered <see cref="DunGenExtender"/>.
/// <see langword="false"/> otherwise.
/// </returns>
public static bool ContainsDungeonFlow(ExtendedDungeonFlow extendedDungeonFlow) {
if (extendedDungeonFlow == null) return false;
return ContainsDungeonFlow(extendedDungeonFlow.DungeonFlow);
}
/// <summary>
/// Returns corresponding <see cref="DunGenExtender"/> for <paramref name="dungeonFlow"/>.
/// </summary>
/// <param name="dungeonFlow"></param>
/// <returns></returns>
public static DunGenExtender GetDunGenExtender(DungeonFlow dungeonFlow) {
if (Plugin.DunGenExtenders.TryGetValue(dungeonFlow, out var value)) {
return value;
}
return null;
}
/// <summary> /// <summary>
/// Creates and returns an empty <see cref="DunGenExtender"/>. /// Creates and returns an empty <see cref="DunGenExtender"/>.
/// </summary> /// </summary>

View File

@ -8,18 +8,23 @@ using System.Threading.Tasks;
using BepInEx; using BepInEx;
using UnityEngine; using UnityEngine;
using LethalLevelLoader; using LethalLevelLoader;
using DunGen.Graph;
using DunGen;
using System.Reflection;
using Unity.Netcode;
namespace DunGenPlus { namespace DunGenPlus {
internal class Assets { internal class Assets {
public static void LoadAssets(){ public static void LoadAssets() {
foreach (string text in Directory.GetFiles(Paths.PluginPath, "*.lethalbundle", SearchOption.AllDirectories)) { foreach (string text in Directory.GetFiles(Paths.PluginPath, "*.lethalbundle", SearchOption.AllDirectories)) {
FileInfo fileInfo = new FileInfo(text); FileInfo fileInfo = new FileInfo(text);
LethalLevelLoader.AssetBundleLoader.AddOnLethalBundleLoadedListener(AutoAddLethalBundle, fileInfo.Name); LethalLevelLoader.AssetBundleLoader.AddOnLethalBundleLoadedListener(AutoAddLethalBundle, fileInfo.Name);
} }
} }
static void AutoAddLethalBundle(AssetBundle assetBundle){ static void AutoAddLethalBundle(AssetBundle assetBundle) {
if (assetBundle.isStreamedSceneAssetBundle) return; if (assetBundle.isStreamedSceneAssetBundle) return;
var extenders = assetBundle.LoadAllAssets<DunGenExtender>(); var extenders = assetBundle.LoadAllAssets<DunGenExtender>();
@ -29,10 +34,49 @@ namespace DunGenPlus {
Plugin.logger.LogWarning($".lethalbundle does not contain any ExtendedContent. Unless you are manually creating and adding your ExtendedDungeonFlow with code, the DunGenExtender will probably not work."); Plugin.logger.LogWarning($".lethalbundle does not contain any ExtendedContent. Unless you are manually creating and adding your ExtendedDungeonFlow with code, the DunGenExtender will probably not work.");
} }
foreach(var e in extenders){ foreach (var e in extenders) {
API.AddDunGenExtender(e); API.AddDunGenExtender(e);
} }
} }
public static AssetBundle MainAssetBundle = null;
public static GameObject DevDebugPrefab;
public static T Load<T>(string name, bool onlyReportErrors = true) where T : UnityEngine.Object {
if (MainAssetBundle == null) {
Plugin.logger.LogError($"Trying to load in asset but asset bundle is missing");
return null;
}
var asset = MainAssetBundle.LoadAsset<T>(name);
var missingasset = asset == null;
if (missingasset || onlyReportErrors == true) {
Plugin.logger.LogDebug($"Loading asset {name}");
}
if (missingasset) {
Plugin.logger.LogError($"...but it was not found");
}
return asset;
}
public static void LoadAssetBundle() {
if (MainAssetBundle == null) {
var assembly = Assembly.GetExecutingAssembly();
var resourceNames = assembly.GetManifestResourceNames();
if (resourceNames.Length >= 1) {
var name = resourceNames[0];
using (var assetStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name)) {
Plugin.logger.LogDebug($"Loading resource {name}");
MainAssetBundle = AssetBundle.LoadFromStream(assetStream);
}
}
}
DevDebugPrefab = Load<GameObject>("DevDebug");
}
} }
} }

View File

@ -125,45 +125,46 @@ namespace DunGenPlus.Collections {
internal Bounds GetDungeonBounds(float dungeonScale) { internal Bounds GetDungeonBounds(float dungeonScale) {
var size = DungeonSizeBase + Vector3.Scale(DungeonSizeBase * (dungeonScale - 1), DungeonSizeFactor); var size = DungeonSizeBase + Vector3.Scale(DungeonSizeBase * (dungeonScale - 1), DungeonSizeFactor);
var offset = DungeonPositionOffset + Vector3.Scale(size, DungeonPositionPivot); var offset = DungeonPositionOffset + Vector3.Scale(size, DungeonPositionPivot - Vector3.one * 0.5f);
return new Bounds(offset, size); return new Bounds(offset, size);
} }
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;
}
internal DunGenExtenderProperties Copy() { internal DunGenExtenderProperties Copy() {
var copy = new DunGenExtenderProperties(); var copy = new DunGenExtenderProperties();
copy.CopyFrom(this);
copy.MainPathCount = MainPathCount;
copy.MainRoomTilePrefab = MainRoomTilePrefab;
copy.MainPathCopyNodeBehaviour = MainPathCopyNodeBehaviour;
//copy.MainPathCopyInjectionTiles = MainPathCopyInjectionTiles;
copy.UseDungeonBounds = UseDungeonBounds;
copy.DungeonSizeBase = DungeonSizeBase;
copy.DungeonSizeFactor = DungeonSizeFactor;
copy.DungeonPositionOffset = DungeonPositionOffset;
copy.DungeonPositionPivot = DungeonPositionPivot;
copy.AddArchetypesToNormalNodes = AddArchetypesToNormalNodes;
copy.NormalNodeArchetypes = NormalNodeArchetypes;
copy.UseForcedTiles = UseForcedTiles;
copy.ForcedTileSets = ForcedTileSets;
copy.UseBranchLoopBoost = UseBranchLoopBoost;
copy.BranchLoopBoostTileSearch = BranchLoopBoostTileSearch;
copy.BranchLoopBoostTileScale = BranchLoopBoostTileScale;
copy.UseLineRandomizer = UseLineRandomizer;
copy.LineRandomizerTileSets = LineRandomizerTileSets;
copy.LineRandomizerArchetypes = LineRandomizerArchetypes;
copy.LineRandomizerTakeCount = LineRandomizerTakeCount;
copy.UseMaxShadowsRequestUpdate = UseMaxShadowsRequestUpdate;
copy.MaxShadowsRequestAmount = MaxShadowsRequestAmount;
copy.UseDoorwaySisters = UseDoorwaySisters;
copy.UseRandomGuaranteedScrapSpawn = UseRandomGuaranteedScrapSpawn;
return copy; return copy;
} }

View File

@ -0,0 +1,54 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DunGenPlus.Collections {
// https://stackoverflow.com/questions/4632945/why-doesnt-dictionarytkey-tvalue-support-null-key
internal struct NullObject<T> where T: class{
public T Item;
private bool isNull;
public NullObject(T item, bool isNull) {
this.Item = item;
this.isNull = isNull;
}
public NullObject(T item) : this(item, item == null){
}
public static implicit operator T(NullObject<T> nullObject) {
return nullObject.Item;
}
public static implicit operator NullObject<T>(T item) {
return new NullObject<T>(item);
}
public override string ToString() {
return (Item != null) ? Item.ToString() : "NULL";
}
public override bool Equals(object obj) {
if (obj == null) return isNull;
if (!(obj is NullObject<T>)) return false;
var no = (NullObject<T>)obj;
if (isNull) return no.isNull;
if (no.isNull) return false;
return Item.Equals(no.Item);
}
public override int GetHashCode(){
if (isNull) return 0;
var result = Item.GetHashCode();
if (result >= 0) result++;
return result;
}
}
}

View File

@ -0,0 +1,201 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using DunGen;
using UnityEngine.UI;
using TMPro;
using DunGen.Graph;
using LethalLevelLoader;
using UnityEngine.InputSystem;
using DunGenPlus.DevTools.Panels;
using DunGenPlus.DevTools.UIElements;
namespace DunGenPlus.DevTools {
internal partial class DevDebugManager : MonoBehaviour {
public static DevDebugManager Instance { get; private set; }
[Header("References")]
public RuntimeDungeon dungeon;
public GameObject devCamera;
public BasePanel[] panels;
public TMP_Dropdown dungeonFlowSelectionDropDown;
private ExtendedDungeonFlow[] dungeonFlows;
internal ExtendedDungeonFlow selectedDungeonFlow;
public TextMeshProUGUI statusTextMesh;
public TextMeshProUGUI statsTextMesh;
// fake
private GameObject disabledGameObject;
private RoundManager fakeRoundManager;
// cache
private Camera lastMainCamera;
private Vector3 lastCameraPosition;
private Quaternion lastCameraRotation;
void Awake(){
Instance = this;
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
CacheMainCamera();
BeginDevCamera();
GetAllDungeonFlows();
foreach(var p in panels) p.AwakeCall();
OpenPanel(0);
dungeon.Generator.OnGenerationStatusChanged += OnDungeonFinished;
disabledGameObject = new GameObject("Disabled GOBJ");
disabledGameObject.SetActive(false);
disabledGameObject.transform.SetParent(transform);
}
void OnDestroy(){
Instance = null;
EndDevCamera();
}
void Update(){
statusTextMesh.text = dungeon.Generator.Status.ToString();
if (!DevDebugOpen.IsSinglePlayerInShip()) {
CloseDevDebug();
}
if (Mouse.current.middleButton.isPressed) {
var delta = Mouse.current.delta.value;
var movement = delta;
devCamera.transform.position += new Vector3(-movement.x, 0f, -movement.y);
}
}
public void OpenPanel(int index) {
for(var i = 0; i < panels.Length; ++i) {
panels[i].SetPanelVisibility(i == index);
}
}
public void SelectDungeonFlow(int index){
selectedDungeonFlow = dungeonFlows[index];
dungeon.Generator.DungeonFlow = selectedDungeonFlow.DungeonFlow;
UpdatePlusPanel();
Plugin.logger.LogInfo($"Selecting {selectedDungeonFlow.DungeonName}");
}
public void GenerateDungeon(){
DeleteDungeon();
Plugin.logger.LogInfo($"Generating dungeon: {dungeon.Generator.IsGenerating}");
fakeRoundManager = disabledGameObject.AddComponent<RoundManager>();
fakeRoundManager.dungeonGenerator = dungeon;
selectedDungeonFlow.DungeonEvents.onBeforeDungeonGenerate?.Invoke(fakeRoundManager);
DungeonManager.GlobalDungeonEvents?.onBeforeDungeonGenerate?.Invoke(fakeRoundManager);
dungeon.Generate();
}
public void DeleteDungeon(){
Plugin.logger.LogInfo($"Deleting dungeon");
dungeon.Generator.Clear(true);
dungeon.Generator.Cancel();
dungeon.Generator.RestrictDungeonToBounds = false;
if (fakeRoundManager) Destroy(fakeRoundManager);
ClearTransformChildren(dungeon.Root.transform);
}
public void ClearTransformChildren(Transform root){
var childCount = root.childCount;
for(var i = childCount - 1; i >= 0; --i) {
GameObject.Destroy(root.GetChild(i).gameObject);
}
}
public void CloseDevDebug(){
DeleteDungeon();
Destroy(gameObject);
}
public void OnDungeonFinished(DungeonGenerator generator, GenerationStatus status) {
var textList = new List<string>();
if (status == GenerationStatus.Complete) {
textList.Add($"Tiles: {generator.CurrentDungeon.AllTiles.Count}");
textList.Add($"Main Tiles: {generator.CurrentDungeon.MainPathTiles.Count}");
textList.Add($"Branch Tiles: {generator.CurrentDungeon.BranchPathTiles.Count}");
textList.Add($"Doors: {generator.CurrentDungeon.Doors.Count}");
} else if (status == GenerationStatus.Failed) {
textList.Add("<color=red>Failed</color>");
}
textList.Add("<u>DunGen</u>");
textList.Add(generator.GenerationStats.ToString());
SetNewSeed();
statsTextMesh.text = string.Join("\n", textList);
}
private void SetNewSeed(){
foreach(var p in panels) {
var mainPanel = p as MainPanel;
if (mainPanel) mainPanel.seedInputField.Set(dungeon.Generator.ChosenSeed);
}
}
private void UpdatePlusPanel() {
foreach(var p in panels) {
var plusPanel = p as DunGenPlusPanel;
if (plusPanel) plusPanel.UpdatePanel();
}
}
public void UpdateDungeonBounds(){
foreach(var p in panels) {
var plusPanel = p as DunGenPlusPanel;
if (plusPanel) plusPanel.UpdateDungeonBoundsHelper();
}
}
private void GetAllDungeonFlows(){
dungeonFlows = LethalLevelLoader.PatchedContent.ExtendedDungeonFlows.ToArray();
dungeonFlowSelectionDropDown.options = dungeonFlows.Select(d => new TMP_Dropdown.OptionData(d.DungeonName)).ToList();
SelectDungeonFlow(0);
}
private void CacheMainCamera() {
var main = Camera.main;
if (main) {
lastMainCamera = main;
lastCameraPosition = main.transform.position;
lastCameraRotation = main.transform.rotation;
}
}
private void BeginDevCamera(){
lastMainCamera?.gameObject.SetActive(false);
devCamera.SetActive(true);
}
private void EndDevCamera(){
devCamera.SetActive(false);
if (lastMainCamera) {
lastMainCamera.transform.position = lastCameraPosition;
lastMainCamera.transform.rotation = lastCameraRotation;
lastMainCamera.gameObject.SetActive(true);
}
}
}
}

View File

@ -0,0 +1,140 @@
using DunGen;
using DunGenPlus.Collections;
using DunGenPlus.DevTools.Panels;
using DunGenPlus.DevTools.UIElements;
using LethalLevelLoader;
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
using TMPro;
using UnityEngine;
using static System.Collections.Specialized.BitVector32;
namespace DunGenPlus.DevTools {
internal partial class DevDebugManager : MonoBehaviour {
[Header("UI Prefabs")]
[Header("UI")]
public GameObject headerUIPrefab;
public GameObject textUIPrefab;
public GameObject spaceUIPrefab;
public GameObject verticalLayoutUIPrefab;
[Header("Input Fields")]
public GameObject intInputFieldPrefab;
public GameObject floatInputFieldPrefab;
public GameObject boolInputFieldPrefab;
public GameObject stringInputFieldPrefab;
public GameObject vector3InputFieldPrefab;
public GameObject intSliderFieldPrefab;
[Header("Special Fields")]
public GameObject listUIPrefab;
public GameObject optionsUIPrefab;
public TextUIElement CreateHeaderUIField(Transform parentTransform, string title, float offset) {
var gameObject = Instantiate(headerUIPrefab, parentTransform);
var field = gameObject.GetComponent<TextUIElement>();
field.SetupBase(title, offset);
return field;
}
public TextUIElement CreateTextUIField(Transform parentTransform, string title, float offset) {
var gameObject = Instantiate(textUIPrefab, parentTransform);
var field = gameObject.GetComponent<TextUIElement>();
field.SetupBase(title, offset);
return field;
}
public void CreateSpaceUIField(Transform parentTransform) {
Instantiate(spaceUIPrefab, parentTransform);
}
public Transform CreateVerticalLayoutUIField(Transform parentTransform){
return Instantiate(verticalLayoutUIPrefab, parentTransform).transform;
}
public IntInputField CreateIntInputField(Transform parentTransform, string title, float offset, int baseValue, Action<int> setAction, int defaultValue = 0){
var gameObject = Instantiate(intInputFieldPrefab, parentTransform);
var field = gameObject.GetComponent<IntInputField>();
field.SetupInputField(title, offset, baseValue, setAction, defaultValue);
return field;
}
public FloatInputField CreateFloatInputField(Transform parentTransform, string title, float offset, float baseValue, Action<float> setAction, float defaultValue = 0f){
var gameObject = Instantiate(floatInputFieldPrefab, parentTransform);
var field = gameObject.GetComponent<FloatInputField>();
field.SetupInputField(title, offset, baseValue, setAction, defaultValue);
return field;
}
public BoolInputField CreateBoolInputField(Transform parentTransform, string title, float offset, bool baseValue, Action<bool> setAction){
var gameObject = Instantiate(boolInputFieldPrefab, parentTransform);
var field = gameObject.GetComponent<BoolInputField>();
field.SetupInputField(title, offset, baseValue, setAction, false);
return field;
}
public StringInputField CreateStringInputField(Transform parentTransform, string title, float offset, string baseValue, Action<string> setAction){
var gameObject = Instantiate(stringInputFieldPrefab, parentTransform);
var field = gameObject.GetComponent<StringInputField>();
field.SetupInputField(title, offset, baseValue, setAction, string.Empty);
return field;
}
public Vector3InputField CreateVector3InputField(Transform parentTransform, string title, float offset, Vector3 baseValue, Action<Vector3> setAction){
var gameObject = Instantiate(vector3InputFieldPrefab, parentTransform);
var field = gameObject.GetComponent<Vector3InputField>();
field.SetupInputField(title, offset, baseValue, setAction, Vector3.zero);
return field;
}
public IntSliderField CreateIntSliderField(Transform parentTransform, string title, float offset, int baseValue, Action<int> setAction, int defaultValue = 0){
var gameObject = Instantiate(intSliderFieldPrefab, parentTransform);
var field = gameObject.GetComponent<IntSliderField>();
field.SetupInputField(title, offset, baseValue, setAction, defaultValue);
return field;
}
public ListUIElement CreateListUIField<T>(Transform parentTransform, string title, float offset, List<T> list){
var gameObject = Instantiate(listUIPrefab, parentTransform);
var field = gameObject.GetComponent<ListUIElement>();
field.SetupList(title, offset, list);
return field;
}
public DropdownInputField CreateOptionsUIField<T>(Transform parentTransform, string title, float offset, int baseValue, Action<T> setAction, Func<int, T> convertIndex, IEnumerable<string> options){
var gameObject = Instantiate(optionsUIPrefab, parentTransform);
var field = gameObject.GetComponent<DropdownInputField>();
field.SetupDropdown(title, offset, baseValue, setAction, convertIndex, options);
return field;
}
public DropdownInputField CreateLevelOptionsUIField(Transform parentTransform, string title, float offset, int baseValue, Action<ExtendedLevel> setAction){
var mainPanel = MainPanel.Instance;
return CreateOptionsUIField(parentTransform, title, offset, baseValue, setAction, (i) => mainPanel.levels[i], mainPanel.levelOptions);
}
public DropdownInputField CreateTileOptionsUIField(Transform parentTransform, string title, float offset, int baseValue, Action<GameObject> setAction){
var assetCache = DunGenPlusPanel.Instance.selectedAssetCache;
return CreateOptionsUIField(parentTransform, title, offset, baseValue, setAction, (i) => assetCache.tiles.list[i].Item, assetCache.tiles.options);
}
public DropdownInputField CreateArchetypeOptionsUIField(Transform parentTransform, string title, float offset, int baseValue, Action<DungeonArchetype> setAction){
var assetCache = DunGenPlusPanel.Instance.selectedAssetCache;
return CreateOptionsUIField(parentTransform, title, offset, baseValue, setAction, (i) => assetCache.archetypes.list[i].Item, assetCache.archetypes.options);
}
public DropdownInputField CreateCopyNodeBehaviourOptionsUIField(Transform parentTransform, string title, float offset, int baseValue, Action<DunGenExtenderProperties.CopyNodeBehaviour> setAction){
var options = Enum.GetNames(typeof(DunGenExtenderProperties.CopyNodeBehaviour));
return CreateOptionsUIField(parentTransform, title, offset, baseValue, setAction, (i) => (DunGenExtenderProperties.CopyNodeBehaviour)i, options);
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
namespace DunGenPlus.DevTools {
internal class DevDebugOpen : MonoBehaviour {
public static bool IsSinglePlayerInShip(){
var startOfRound = StartOfRound.Instance;
var roundManager = RoundManager.Instance;
if (startOfRound && roundManager) {
return startOfRound.connectedPlayersAmount == 0 && startOfRound.inShipPhase;
}
return false;
}
public void Update(){
if (IfKeyPress(Keyboard.current.mKey) && DevDebugManager.Instance == null && IsSinglePlayerInShip()){
Instantiate(Assets.DevDebugPrefab);
}
}
bool IfKeyPress(params KeyControl[] keys){
foreach(var k in keys){
if (k.wasPressedThisFrame) return true;
}
return false;
}
}
}

View File

@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
namespace DunGenPlus.DevTools {
internal class PanelTab : MonoBehaviour {
public bool active;
[Header("References")]
public RectTransform rectTransform;
public Image image;
void Update() {
var targetHeight = active ? 48f : 36f;
var targetColor = active ? new Color(100f / 255f, 100f / 255f, 100f / 255f, 1f) : new Color(50f / 255f, 50f / 255f, 50f / 255f, 1f);
var size = rectTransform.sizeDelta;
size.y = Mathf.Lerp(size.y, targetHeight, Time.deltaTime * 10f);
rectTransform.sizeDelta = size;
var color = image.color;
color = Color.Lerp(color, targetColor, Time.deltaTime * 10f);
image.color = color;
}
}
}

View File

@ -0,0 +1,53 @@
using DunGen;
using DunGen.Graph;
using LethalLevelLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
namespace DunGenPlus.DevTools.Panels {
internal abstract class BasePanel : MonoBehaviour {
public DevDebugManager manager => DevDebugManager.Instance;
public RuntimeDungeon dungeon => manager.dungeon;
public ExtendedDungeonFlow selectedExtendedDungeonFlow => manager.selectedDungeonFlow;
public DungeonFlow selectedDungeonFlow => selectedExtendedDungeonFlow.DungeonFlow;
[Header("Renders")]
public GameObject mainGameObject;
public PanelTab tab;
public virtual void AwakeCall() {
}
public virtual void SetPanelVisibility(bool visible) {
mainGameObject.SetActive(visible);
tab.active = visible;
}
protected int ParseTextInt(string text, int defaultValue = 0) {
if (int.TryParse(text, out var result)){
return result;
} else {
Plugin.logger.LogWarning($"Couldn't parse {text} into an int");
return defaultValue;
}
}
protected float ParseTextFloat(string text, float defaultValue = 0f) {
if (float.TryParse(text, out var result)){
return result;
} else {
Plugin.logger.LogWarning($"Couldn't parse {text} into a float");
return defaultValue;
}
}
}
}

View File

@ -0,0 +1,258 @@
using DunGen;
using DunGen.Graph;
using DunGenPlus.Collections;
using LethalLevelLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using DunGenPlus.DevTools.UIElements;
namespace DunGenPlus.DevTools.Panels {
internal class DunGenPlusPanel : BasePanel {
public static DunGenPlusPanel Instance { get; private set; }
internal DungeonFlow previousDungeonFlow;
internal DunGenExtender selectedExtenderer;
internal DungeonFlowCacheAssets selectedAssetCache;
[Header("Panel References")]
public GameObject createGameObject;
public GameObject selectedGameObject;
[Header("Dungeon Bounds Helper")]
public GameObject dungeonBoundsHelperGameObject;
[Header("Selected Panel References")]
public Toggle activateDunGenPlusToggle;
private GameObject mainPathParentGameobject;
private GameObject dungeonBoundsParentGameobject;
private GameObject archetypesNodesParentGameobject;
public class DungeonFlowCacheAssets {
public DunGenExtenderProperties originalProperties;
public struct Collection<T> {
public List<T> list;
public Dictionary<T, int> dictionary;
public IEnumerable<string> options;
public Collection(List<T> list) {
this.list = list;
dictionary = new Dictionary<T, int>();
for(var i = 0; i < list.Count; i++) {
dictionary.Add(list[i], i);
}
options = list.Select(l => l.ToString());
}
}
public Collection<NullObject<TileSet>> tileSets;
public Collection<NullObject<GameObject>> tiles;
public Collection<NullObject<DungeonArchetype>> archetypes;
public DungeonFlowCacheAssets(DunGenExtender extender){
originalProperties = extender.Properties.Copy();
var tileSetsHashSet = new HashSet<NullObject<TileSet>>() { new NullObject<TileSet>(null) };
var tilesHashSet = new HashSet<NullObject<GameObject>>() { new NullObject<GameObject>(null) };
var archetypesHashSet = new HashSet<NullObject<DungeonArchetype>>() { new NullObject<DungeonArchetype>(null) };
foreach(var t in extender.DungeonFlow.Nodes) {
var label = t.Label.ToLowerInvariant();
if (label == "lchc gate" || label == "goal"){
foreach(var n in t.TileSets.SelectMany(x => x.TileWeights.Weights)) {
n.Value.GetComponent<Tile>().RepeatMode = TileRepeatMode.Allow;
}
}
}
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);
}
}
tileSets = new Collection<NullObject<TileSet>>(tileSetsHashSet.ToList());
tiles = new Collection<NullObject<GameObject>>(tilesHashSet.ToList());
archetypes = new Collection<NullObject<DungeonArchetype>>(archetypesHashSet.ToList());
}
}
public Dictionary<DungeonFlow, DungeonFlowCacheAssets> cacheDictionary = new Dictionary<DungeonFlow, DungeonFlowCacheAssets>();
public override void AwakeCall() {
Instance = this;
dungeonBoundsHelperGameObject.SetActive(false);
}
public override void SetPanelVisibility(bool visible) {
base.SetPanelVisibility(visible);
if (visible) UpdatePanel();
}
public void CreateDunGenPlusExtenderer(){
var asset = API.CreateDunGenExtender(selectedDungeonFlow);
selectedDungeonFlow.TileInjectionRules = new List<TileInjectionRule>();
API.AddDunGenExtender(asset);
SetPanelVisibility(true);
UpdatePanel();
}
public void UpdatePanel(){
if (previousDungeonFlow == selectedDungeonFlow) return;
var hasAsset = API.ContainsDungeonFlow(selectedDungeonFlow);
selectedGameObject.SetActive(hasAsset);
createGameObject.SetActive(!hasAsset);
ClearPanel();
if (hasAsset) {
SetupPanel();
} else {
previousDungeonFlow = null;
selectedExtenderer = null;
selectedAssetCache = null;
dungeonBoundsHelperGameObject.SetActive(false);
}
}
public void SetupPanel() {
var dungeonFlow = selectedDungeonFlow;
var extender = API.GetDunGenExtender(dungeonFlow);
if (!cacheDictionary.TryGetValue(dungeonFlow, out var cache)) {
cache = new DungeonFlowCacheAssets(extender);
cacheDictionary.Add(dungeonFlow, cache);
}
previousDungeonFlow = dungeonFlow;
selectedExtenderer = extender;
selectedAssetCache = cache;
var parentTransform = selectedGameObject.transform;
var properties = selectedExtenderer.Properties;
manager.CreateBoolInputField(parentTransform, "Activate DunGenPlus", 0f, selectedExtenderer.Active, SetActivateDunGenPlus);
manager.CreateSpaceUIField(parentTransform);
var mainPathTransform = manager.CreateVerticalLayoutUIField(parentTransform);
mainPathParentGameobject = mainPathTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Main Path", 0f);
manager.CreateIntSliderField(parentTransform, "Main Path Count", 0f, properties.MainPathCount, SetMainPathCount);
mainPathTransform.SetAsLastSibling();
manager.CreateTileOptionsUIField(mainPathTransform, "Main Room Tile Prefab", 0f, selectedAssetCache.tiles.dictionary[properties.MainRoomTilePrefab], SetMainRoom);
manager.CreateCopyNodeBehaviourOptionsUIField(mainPathTransform, "Copy Node Behaviour", 0f, (int)properties.MainPathCopyNodeBehaviour, SetCopyNodeBehaviour);
manager.CreateSpaceUIField(parentTransform);
var dungeonBoundsTransform = manager.CreateVerticalLayoutUIField(parentTransform);
dungeonBoundsParentGameobject = dungeonBoundsTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Dungeon Bounds", 0f);
manager.CreateBoolInputField(parentTransform, "Use Dungeon Bounds", 0f, properties.UseDungeonBounds, SetUseDungeonBounds);
dungeonBoundsTransform.SetAsLastSibling();
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Base", 0f, properties.DungeonSizeBase, SetDungeonBoundsSizeBase);
manager.CreateVector3InputField(dungeonBoundsTransform, "Size Factor", 0f, properties.DungeonSizeFactor, SetDungeonBoundsSizeFactor);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Offset", 0f, properties.DungeonPositionOffset, SetDungeonBoundsPosOffset);
manager.CreateVector3InputField(dungeonBoundsTransform, "Position Pivot", 0f, properties.DungeonPositionPivot, SetDungeonBoundsPosPivot);
manager.CreateSpaceUIField(parentTransform);
var archetypesTransform = manager.CreateVerticalLayoutUIField(parentTransform);
archetypesNodesParentGameobject = archetypesTransform.gameObject;
manager.CreateHeaderUIField(parentTransform, "Archetypes Normal Nodes", 0f);
manager.CreateBoolInputField(parentTransform, "Add Archetypes", 0f, properties.AddArchetypesToNormalNodes, SetAddArchetypes);
archetypesTransform.SetAsLastSibling();
manager.CreateListUIField(archetypesTransform, "Normal Node Archetypes", 0f, properties.NormalNodeArchetypes);
manager.CreateSpaceUIField(parentTransform);
dungeonBoundsHelperGameObject.SetActive(selectedExtenderer.Properties.UseDungeonBounds);
UpdateDungeonBoundsHelper();
}
public void ClearPanel(){
manager.ClearTransformChildren(selectedGameObject.transform);
}
public void SetActivateDunGenPlus(bool state){
selectedExtenderer.Active = state;
}
public void SetMainPathCount(int value) {
selectedExtenderer.Properties.MainPathCount = value;
mainPathParentGameobject.SetActive(value > 1);
}
public void SetMainRoom(GameObject value) {
selectedExtenderer.Properties.MainRoomTilePrefab = value;
}
public void SetCopyNodeBehaviour(DunGenExtenderProperties.CopyNodeBehaviour value) {
selectedExtenderer.Properties.MainPathCopyNodeBehaviour = value;
}
public void SetUseDungeonBounds(bool state){
selectedExtenderer.Properties.UseDungeonBounds = state;
dungeonBoundsHelperGameObject.SetActive(state);
dungeonBoundsParentGameobject.SetActive(state);
}
public void UpdateDungeonBoundsHelper(){
if (selectedExtenderer == null) return;
var t = dungeonBoundsHelperGameObject.transform;
var result = selectedExtenderer.Properties.GetDungeonBounds(dungeon.Generator.LengthMultiplier);
t.localPosition = result.center;
t.localScale = result.size;
}
public void SetDungeonBoundsSizeBase(Vector3 value) {
selectedExtenderer.Properties.DungeonSizeBase = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsSizeFactor(Vector3 value) {
selectedExtenderer.Properties.DungeonSizeFactor = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsPosOffset(Vector3 value) {
selectedExtenderer.Properties.DungeonPositionOffset = value;
UpdateDungeonBoundsHelper();
}
public void SetDungeonBoundsPosPivot(Vector3 value) {
selectedExtenderer.Properties.DungeonPositionPivot = value;
UpdateDungeonBoundsHelper();
}
public void SetAddArchetypes(bool state){
selectedExtenderer.Properties.AddArchetypesToNormalNodes = state;
archetypesNodesParentGameobject.SetActive(state);
}
}
}

View File

@ -0,0 +1,98 @@
using DunGen;
using DunGenPlus.DevTools.UIElements;
using LethalLevelLoader;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.Panels {
internal class MainPanel : BasePanel {
public static MainPanel Instance { get; private set; }
internal IntInputField seedInputField;
internal TextUIElement lengthMultiplierField;
internal ExtendedLevel[] levels;
internal IEnumerable<string> levelOptions;
public override void AwakeCall(){
Instance = this;
GetAllLevels();
var gen = dungeon.Generator;
var parentTransform = mainGameObject.transform;
manager.CreateHeaderUIField(parentTransform, "Dungeon Generator", 0f);
seedInputField = manager.CreateIntInputField(parentTransform, "Seed", 0f, gen.Seed, SetSeed);
manager.CreateBoolInputField(parentTransform, "Randomize Seed", 0f, gen.ShouldRandomizeSeed, SetRandomSeed);
manager.CreateSpaceUIField(parentTransform);
manager.CreateIntInputField(parentTransform, "Max Attempts", 0f, gen.MaxAttemptCount, SetMaxAttempts, 10);
manager.CreateSpaceUIField(parentTransform);
manager.CreateBoolInputField(parentTransform, "Generate Async", 0f, gen.GenerateAsynchronously, SetGenerateAsync);
manager.CreateFloatInputField(parentTransform, "Max Async (ms)", 0f, gen.MaxAsyncFrameMilliseconds, SetMaxAsync);
manager.CreateFloatInputField(parentTransform, "Pause Betwoon Rooms", 0f, gen.PauseBetweenRooms, SetPauseBetweenRooms);
manager.CreateSpaceUIField(parentTransform);
manager.CreateHeaderUIField(parentTransform, "Levels", 0f);
manager.CreateLevelOptionsUIField(parentTransform, "Level", 0f, 0, SetLevel);
lengthMultiplierField = manager.CreateTextUIField(parentTransform, "Length Multiplier", 0f);
SetLevel(levels[0]);
}
public void SetSeed(int value) {
dungeon.Generator.Seed = value;
}
public void SetRandomSeed(bool state) {
dungeon.Generator.ShouldRandomizeSeed = state;
}
public void SetMaxAttempts(int value) {
dungeon.Generator.MaxAttemptCount = value;
}
public void SetGenerateAsync(bool state) {
dungeon.Generator.GenerateAsynchronously = state;
}
public void SetMaxAsync(float value) {
dungeon.Generator.MaxAsyncFrameMilliseconds = value;
}
public void SetPauseBetweenRooms(float value) {
dungeon.Generator.PauseBetweenRooms = value;
}
private void GetAllLevels(){
levels = LethalLevelLoader.PatchedContent.ExtendedLevels.ToArray();
levelOptions = levels.Select(l => l.NumberlessPlanetName);
}
public void SetLevel(ExtendedLevel level){
var currentLevelLengthMultlpier = GetLevelMultiplier(level);
dungeon.Generator.LengthMultiplier = currentLevelLengthMultlpier;
manager.UpdateDungeonBounds();
lengthMultiplierField.SetText($"Length multiplier: {currentLevelLengthMultlpier.ToString("F2")}");
}
private float GetLevelMultiplier(ExtendedLevel level){
var roundManager = RoundManager.Instance;
if (roundManager == null) {
Plugin.logger.LogError("RoundManager somehow null. Can't set level length multiplier");
return 1f;
}
return roundManager.mapSizeMultiplier * level.SelectableLevel.factorySizeMultiplier;
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements {
internal abstract class BaseInputField<T> : BaseUIElement {
public virtual void SetupInputField(string titleText, float offset, T baseValue, Action<T> setAction, T defaultValue){
SetupBase(titleText, offset);
}
public abstract void Set(T value);
protected int ParseTextInt(string text, int defaultValue = 0) {
if (int.TryParse(text, out var result)){
return result;
} else {
Plugin.logger.LogWarning($"Couldn't parse {text} into an int");
return defaultValue;
}
}
protected float ParseTextFloat(string text, float defaultValue = 0f) {
if (float.TryParse(text, out var result)){
return result;
} else {
Plugin.logger.LogWarning($"Couldn't parse {text} into a float");
return defaultValue;
}
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements {
internal abstract class BaseUIElement : MonoBehaviour {
public TextMeshProUGUI titleTextMesh;
internal string title;
public LayoutElement layoutElement;
internal float layoutOffset;
public void SetupBase(string titleText, float offset) {
title = titleText;
SetText(title);
layoutOffset = offset;
if (layoutElement) {
layoutElement.minWidth -= layoutOffset;
}
}
public void SetText(string value) {
titleTextMesh.text = value;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements {
internal class BoolInputField : BaseInputField<bool> {
public Toggle toggle;
public override void SetupInputField(string title, float offset, bool baseValue, Action<bool> setAction, bool defaultValue) {
base.SetupInputField(title, offset, baseValue, setAction, defaultValue);
toggle.onValueChanged.AddListener((t) => SetValue(setAction, t));
Set(baseValue);
}
private void SetValue(Action<bool> setAction, bool state) {
Plugin.logger.LogInfo($"Setting {title} to {state}");
setAction.Invoke(state);
}
public override void Set(bool state){
toggle.isOn = state;
}
}
}

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements
{
internal class DropdownInputField : BaseUIElement {
public TMP_Dropdown dropDown;
public void SetupDropdown<T>(string titleText, float offset, int baseValue, Action<T> setAction, Func<int, T> convertIndex, IEnumerable<string> options) {
SetupBase(titleText, offset);
dropDown.options = options.Select(c => {
return new TMP_Dropdown.OptionData(c.Substring(0, Math.Min(24, c.Length)));
}).ToList();
dropDown.onValueChanged.AddListener((t) => SetValue(setAction, convertIndex, t));
dropDown.value = baseValue;
}
private void SetValue<T>(Action<T> setAction, Func<int, T> convertIndex, int index) {
var value = convertIndex.Invoke(index);
Plugin.logger.LogInfo($"Setting {title} to {value}");
setAction.Invoke(value);
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
namespace DunGenPlus.DevTools.UIElements
{
internal class FloatInputField : BaseInputField<float> {
public TMP_InputField inputField;
internal float defaultValue = 0f;
public override void SetupInputField(string title, float offset, float baseValue, Action<float> setAction , float defaultValue) {
base.SetupInputField(title, offset, baseValue, setAction, defaultValue);
this.defaultValue = defaultValue;
inputField.onValueChanged.AddListener((t) => SetValue(setAction, t));
Set(baseValue);
}
private void SetValue(Action<float> setAction, string text) {
Plugin.logger.LogInfo($"Setting {title} to {text}");
setAction.Invoke(ParseTextFloat(text, defaultValue));
}
public override void Set(float value){
inputField.text = value.ToString();
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
namespace DunGenPlus.DevTools.UIElements {
internal class IntInputField : BaseInputField<int> {
public TMP_InputField inputField;
internal int defaultValue = 0;
public override void SetupInputField(string title, float offset, int baseValue, Action<int> setAction , int defaultValue) {
base.SetupInputField(title, offset, baseValue, setAction, defaultValue);
this.defaultValue = defaultValue;
inputField.onValueChanged.AddListener((t) => SetValue(setAction, t));
Set(baseValue);
}
private void SetValue(Action<int> setAction, string text) {
Plugin.logger.LogInfo($"Setting {title} to {text}");
setAction.Invoke(ParseTextInt(text, defaultValue));
}
public override void Set(int value){
inputField.text = value.ToString();
}
}
}

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements {
internal class IntSliderField : BaseInputField<int> {
public Slider inputField;
public TextMeshProUGUI textMesh;
internal int defaultValue = 0;
public override void SetupInputField(string title, float offset, int baseValue, Action<int> setAction , int defaultValue) {
base.SetupInputField(title, offset, baseValue, setAction, defaultValue);
this.defaultValue = defaultValue;
inputField.onValueChanged.AddListener((t) => SetValue(setAction, t));
Set(baseValue);
}
private void SetValue(Action<int> setAction, float value) {
Plugin.logger.LogInfo($"Setting {title} to {value}");
setAction.Invoke((int)value);
}
public override void Set(int value){
inputField.value = value;
textMesh.text = value.ToString();
}
}
}

View File

@ -0,0 +1,77 @@
using DunGen;
using DunGenPlus.Collections;
using DunGenPlus.DevTools.Panels;
using LethalLevelLoader;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
namespace DunGenPlus.DevTools.UIElements {
internal class ListUIElement : BaseUIElement {
public GameObject templatePrefab;
public Transform listTransform;
internal IList list;
internal Type listType;
public void SetupList<T>(string titleText, float offset, List<T> list) {
SetupBase(titleText, offset);
this.list = list;
listType = typeof(T);
for(var i = 0; i < list.Count; ++i) {
CreateEntry(i);
}
}
public void AddElement() {
object item = null;
if (listType == typeof(DungeonArchetype)) {
item = null;
} else if (listType == typeof(NodeArchetype)) {
item = new NodeArchetype();
}
list.Add(item);
CreateEntry(list.Count - 1);
}
public void RemoveElement(){
if (list.Count == 0) return;
list.RemoveAt(list.Count - 1);
Destroy(listTransform.GetChild(listTransform.childCount - 1).gameObject);
}
public void CreateEntry(int index){
var copy = CreateCopy(index);
var copyParentTransform = copy.transform.Find("Items");
if (listType == typeof(DungeonArchetype)){
var entry = (DungeonArchetype)list[index];
var baseValue = DunGenPlusPanel.Instance.selectedAssetCache.archetypes.dictionary[entry];
DevDebugManager.Instance.CreateArchetypeOptionsUIField(copyParentTransform, "Archetype", layoutOffset + 24f, baseValue, (t) => list[index] = t);
}
else if (listType == typeof(NodeArchetype)) {
var entry = (NodeArchetype)list[index];
DevDebugManager.Instance.CreateStringInputField(copyParentTransform, "Label", layoutOffset + 24f, entry.label, (t) => entry.label = t);
DevDebugManager.Instance.CreateListUIField(copyParentTransform, "Archetypes", layoutOffset + 24f, entry.archetypes);
}
copy.SetActive(true);
}
public GameObject CreateCopy(int index){
var copy = Instantiate(templatePrefab, listTransform);
copy.transform.Find("Element").GetComponent<TextMeshProUGUI>().text = $"Element {index}";
return copy;
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
namespace DunGenPlus.DevTools.UIElements
{
internal class StringInputField : BaseInputField<string> {
public TMP_InputField inputField;
public override void SetupInputField(string title, float offset, string baseValue, Action<string> setAction, string defaultValue) {
base.SetupInputField(title, offset, baseValue, setAction, defaultValue);
inputField.onValueChanged.AddListener((t) => SetValue(setAction, t));
Set(baseValue);
}
private void SetValue(Action<string> setAction, string text) {
Plugin.logger.LogInfo($"Setting {title} to {text}");
setAction.Invoke(text);
}
public override void Set(string value){
inputField.text = value;
}
}
}

View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DunGenPlus.DevTools.UIElements {
internal class TextUIElement : BaseUIElement {
}
}

View File

@ -0,0 +1,57 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
namespace DunGenPlus.DevTools.UIElements {
internal class Vector3InputField : BaseInputField<Vector3> {
public TMP_InputField xInputField;
public TMP_InputField yInputField;
public TMP_InputField zInputField;
private Vector3 _value;
public override void SetupInputField(string titleText, float offset, Vector3 baseValue, Action<Vector3> setAction, Vector3 defaultValue) {
base.SetupInputField(titleText, offset, baseValue, setAction, defaultValue);
xInputField.onValueChanged.AddListener((t) => SetXValue(setAction, t));
yInputField.onValueChanged.AddListener((t) => SetYValue(setAction, t));
zInputField.onValueChanged.AddListener((t) => SetZValue(setAction, t));
Set(baseValue);
}
private void SetXValue(Action<Vector3> setAction, string text){
Plugin.logger.LogInfo($"Setting {title}.x to {text}");
_value.x = ParseTextFloat(text);
setAction.Invoke(_value);
}
private void SetYValue(Action<Vector3> setAction, string text){
Plugin.logger.LogInfo($"Setting {title}.y to {text}");
_value.y = ParseTextFloat(text);
setAction.Invoke(_value);
}
private void SetZValue(Action<Vector3> setAction, string text){
Plugin.logger.LogInfo($"Setting {title}.z to {text}");
_value.z = ParseTextFloat(text);
setAction.Invoke(_value);
}
public override void Set(Vector3 value){
_value = value;
xInputField.text = value.x.ToString();
yInputField.text = value.y.ToString();
zInputField.text = value.z.ToString();
}
}
}

View File

@ -20,6 +20,7 @@ namespace DunGenPlus {
[Header("DEV ONLY: DON'T TOUCH")] [Header("DEV ONLY: DON'T TOUCH")]
public string Version = "0"; public string Version = "0";
internal bool Active = true;
} }
} }

View File

@ -46,8 +46,8 @@
<Reference Include="BepInEx.Harmony"> <Reference Include="BepInEx.Harmony">
<HintPath>..\..\..\Libraries\BepInEx.Harmony.dll</HintPath> <HintPath>..\..\..\Libraries\BepInEx.Harmony.dll</HintPath>
</Reference> </Reference>
<Reference Include="LethalLevelLoader"> <Reference Include="LethalLevelLoader-publicized">
<HintPath>..\..\..\Libraries\LethalLevelLoader.dll</HintPath> <HintPath>..\..\..\Libraries\LethalLevelLoader-publicized.dll</HintPath>
</Reference> </Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -60,6 +60,10 @@
<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.InputSystem, Version=1.7.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.InputSystem.dll</HintPath>
</Reference>
<Reference Include="Unity.Netcode.Components, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL"> <Reference Include="Unity.Netcode.Components, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.Netcode.Components.dll</HintPath> <HintPath>..\..\..\Libraries\Unity.Netcode.Components.dll</HintPath>
@ -80,6 +84,10 @@
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.RenderPipelines.HighDefinition.Runtime.dll</HintPath> <HintPath>..\..\..\Libraries\Unity.RenderPipelines.HighDefinition.Runtime.dll</HintPath>
</Reference> </Reference>
<Reference Include="Unity.TextMeshPro, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\Unity.TextMeshPro.dll</HintPath>
</Reference>
<Reference Include="UnityEngine"> <Reference Include="UnityEngine">
<HintPath>..\..\..\Libraries\UnityEngine.dll</HintPath> <HintPath>..\..\..\Libraries\UnityEngine.dll</HintPath>
</Reference> </Reference>
@ -90,6 +98,33 @@
<Reference Include="UnityEngine.CoreModule"> <Reference Include="UnityEngine.CoreModule">
<HintPath>..\..\..\Libraries\UnityEngine.CoreModule.dll</HintPath> <HintPath>..\..\..\Libraries\UnityEngine.CoreModule.dll</HintPath>
</Reference> </Reference>
<Reference Include="UnityEngine.IMGUIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.IMGUIModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputLegacyModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.InputLegacyModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.InputModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.InputModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UI, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.UI.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.UIElementsModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIElementsNativeModule">
<HintPath>..\..\..\Libraries\UnityEngine.UIElementsNativeModule.dll</HintPath>
</Reference>
<Reference Include="UnityEngine.UIModule, Version=0.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion>
<HintPath>..\..\..\Libraries\UnityEngine.UIModule.dll</HintPath>
</Reference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="API.cs" /> <Compile Include="API.cs" />
@ -98,6 +133,7 @@
<Compile Include="Collections\ExtenderEvent.cs" /> <Compile Include="Collections\ExtenderEvent.cs" />
<Compile Include="Collections\ForcedTileSetList.cs" /> <Compile Include="Collections\ForcedTileSetList.cs" />
<Compile Include="Collections\NodeArchetype.cs" /> <Compile Include="Collections\NodeArchetype.cs" />
<Compile Include="Collections\NullObject.cs" />
<Compile Include="Components\DoorwayCleanup.cs" /> <Compile Include="Components\DoorwayCleanup.cs" />
<Compile Include="Components\DoorwayCleanupScripting\DCSRemoveDoorwayConnectedDoorway.cs" /> <Compile Include="Components\DoorwayCleanupScripting\DCSRemoveDoorwayConnectedDoorway.cs" />
<Compile Include="Components\DoorwayCleanupScripting\DCSRemoveDoorwaySpawnedPrefab.cs" /> <Compile Include="Components\DoorwayCleanupScripting\DCSRemoveDoorwaySpawnedPrefab.cs" />
@ -109,6 +145,24 @@
<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="Components\Scrap\RandomGuaranteedScrapSpawn.cs" />
<Compile Include="DevTools\DevDebugManager.cs" />
<Compile Include="DevTools\DevDebugManagerUI.cs" />
<Compile Include="DevTools\DevDebugOpen.cs" />
<Compile Include="DevTools\Panels\BasePanel.cs" />
<Compile Include="DevTools\Panels\DunGenPlusPanel.cs" />
<Compile Include="DevTools\Panels\MainPanel.cs" />
<Compile Include="DevTools\PanelTab.cs" />
<Compile Include="DevTools\UIElements\BaseInputField.cs" />
<Compile Include="DevTools\UIElements\BaseUIElement.cs" />
<Compile Include="DevTools\UIElements\BoolInputField.cs" />
<Compile Include="DevTools\UIElements\DropdownInputField.cs" />
<Compile Include="DevTools\UIElements\FloatInputField.cs" />
<Compile Include="DevTools\UIElements\IntInputField.cs" />
<Compile Include="DevTools\UIElements\IntSliderField.cs" />
<Compile Include="DevTools\UIElements\ListUIElement.cs" />
<Compile Include="DevTools\UIElements\StringInputField.cs" />
<Compile Include="DevTools\UIElements\TextUIElement.cs" />
<Compile Include="DevTools\UIElements\Vector3InputField.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" />
@ -116,6 +170,7 @@
<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\LethalLevelLoaderPatches.cs" />
<Compile Include="Patches\RoundManagerPatch.cs" /> <Compile Include="Patches\RoundManagerPatch.cs" />
<Compile Include="Patches\StartOfRoundPatch.cs" /> <Compile Include="Patches\StartOfRoundPatch.cs" />
<Compile Include="Plugin.cs" /> <Compile Include="Plugin.cs" />
@ -124,8 +179,17 @@
<Compile Include="Utils\Utility.cs" /> <Compile Include="Utils\Utility.cs" />
</ItemGroup> </ItemGroup>
<ItemGroup /> <ItemGroup />
<ItemGroup>
<None Remove="dungen" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="dungen" />
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup> <PropertyGroup>
<PostBuildEvent>copy "$(TargetPath)" "C:\Users\Jose Garcia\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\SDM Debug\BepInEx\plugins\Alice-DungeonGenerationPlus\$(TargetName).dll"</PostBuildEvent> <PostBuildEvent>copy "$(TargetPath)" "C:\Users\Jose Garcia\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\SDM Debug\BepInEx\plugins\Alice-DungeonGenerationPlus\$(TargetName).dll"</PostBuildEvent>
</PropertyGroup> </PropertyGroup>
<PropertyGroup>
<PreBuildEvent>copy "D:\Previous Computer\Desktop\LethalCompany Modding\Unity Template\Assets\AssetBundles\dungen" "$(ProjectDir)\dungen"</PreBuildEvent>
</PropertyGroup>
</Project> </Project>

View File

@ -0,0 +1,20 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DunGenPlus.DevTools;
using HarmonyLib;
namespace DunGenPlus.Patches {
internal class LethalLevelLoaderPatches {
[HarmonyPrefix]
[HarmonyPatch(typeof(LethalLevelLoader.Patches), "DungeonGeneratorGenerate_Prefix")]
public static bool DungeonGeneratorGenerate_Prefix_Prefix(){
return DevDebugManager.Instance == null;
}
}
}

View File

@ -1,5 +1,6 @@
using DunGen; using DunGen;
using DunGenPlus.Components.Scrap; using DunGenPlus.Components.Scrap;
using DunGenPlus.DevTools;
using DunGenPlus.Generation; using DunGenPlus.Generation;
using HarmonyLib; using HarmonyLib;
using System; using System;
@ -9,10 +10,17 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Unity.Netcode; using Unity.Netcode;
using UnityEngine;
namespace DunGenPlus.Patches { namespace DunGenPlus.Patches {
public class RoundManagerPatch { public class RoundManagerPatch {
[HarmonyPostfix]
[HarmonyPatch(typeof(RoundManager), "Awake")]
public static void AwakePatch(){
var devDebug = new GameObject("DevDebugOpen", typeof(DevDebugOpen));
}
[HarmonyPrefix] [HarmonyPrefix]
[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")] [HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
public static void waitForScrapToSpawnToSyncPatch (ref RoundManager __instance, ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues) { public static void waitForScrapToSpawnToSyncPatch (ref RoundManager __instance, ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues) {

View File

@ -19,6 +19,7 @@ using UnityEngine.Assertions;
namespace DunGenPlus { namespace DunGenPlus {
[BepInPlugin(modGUID, modName, modVersion)] [BepInPlugin(modGUID, modName, modVersion)]
[BepInDependency("imabatby.lethallevelloader", "1.2.0.3")]
[BepInProcess("Lethal Company.exe")] [BepInProcess("Lethal Company.exe")]
public class Plugin : BaseUnityPlugin { public class Plugin : BaseUnityPlugin {
@ -44,9 +45,17 @@ namespace DunGenPlus {
Harmony.PatchAll(typeof(DoorwayConnectionPatch)); Harmony.PatchAll(typeof(DoorwayConnectionPatch));
Harmony.PatchAll(typeof(RoundManagerPatch)); Harmony.PatchAll(typeof(RoundManagerPatch));
try {
Harmony.PatchAll(typeof(LethalLevelLoaderPatches));
} catch (Exception e) {
Plugin.logger.LogError("Failed to patch LLL for dev debug. You can ignore this.");
Plugin.logger.LogError(e);
}
//Harmony.PatchAll(typeof(StartOfRoundPatch)); //Harmony.PatchAll(typeof(StartOfRoundPatch));
Assets.LoadAssets(); Assets.LoadAssets();
Assets.LoadAssetBundle();
DungeonManager.GlobalDungeonEvents.onBeforeDungeonGenerate.AddListener(OnDunGenExtenderLoad); DungeonManager.GlobalDungeonEvents.onBeforeDungeonGenerate.AddListener(OnDunGenExtenderLoad);
DoorwayManager.onMainEntranceTeleportSpawnedEvent.AddEvent("DoorwayCleanup", DoorwayManager.onMainEntranceTeleportSpawnedFunction); DoorwayManager.onMainEntranceTeleportSpawnedEvent.AddEvent("DoorwayCleanup", DoorwayManager.onMainEntranceTeleportSpawnedFunction);
} }
@ -56,9 +65,10 @@ namespace DunGenPlus {
var generator = roundManager.dungeonGenerator.Generator; var generator = roundManager.dungeonGenerator.Generator;
var flow = generator.DungeonFlow; var flow = generator.DungeonFlow;
if (DunGenExtenders.TryGetValue(flow, out var value)) { var extender = API.GetDunGenExtender(flow);
if (extender && extender.Active) {
Plugin.logger.LogInfo($"Loading DunGenExtender for {flow.name}"); Plugin.logger.LogInfo($"Loading DunGenExtender for {flow.name}");
DunGenPlusGenerator.Activate(generator, value); DunGenPlusGenerator.Activate(generator, extender);
return; return;
} }

Binary file not shown.