Decompiled source of DungeonGenerationPlus v1.4.1

DunGenPlus.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security.Permissions;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using DunGen;
using DunGen.Adapters;
using DunGen.Graph;
using DunGenPlus.Attributes;
using DunGenPlus.Collections;
using DunGenPlus.Components;
using DunGenPlus.Components.Props;
using DunGenPlus.Components.Scrap;
using DunGenPlus.Components.Scripting;
using DunGenPlus.DevTools;
using DunGenPlus.DevTools.HoverUI;
using DunGenPlus.DevTools.Panels;
using DunGenPlus.DevTools.Panels.Collections;
using DunGenPlus.DevTools.UIElements;
using DunGenPlus.DevTools.UIElements.Collections;
using DunGenPlus.Generation;
using DunGenPlus.Managers;
using DunGenPlus.Patches;
using DunGenPlus.Utils;
using HarmonyLib;
using LethalLevelLoader;
using Soukoku.ExpressionParser;
using Soukoku.ExpressionParser.Parsing;
using TMPro;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;
using UnityEngine.InputSystem;
using UnityEngine.InputSystem.Controls;
using UnityEngine.Rendering;
using UnityEngine.Rendering.HighDefinition;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("DunGenPlus")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("DunGenPlus")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("13cde60e-1975-463b-9da1-ccb3f3ebabd8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
namespace Soukoku.ExpressionParser
{
	public class EvaluationContext
	{
		private static Dictionary<string, FunctionRoutine> BuiltInFunctions = new Dictionary<string, FunctionRoutine>(StringComparer.OrdinalIgnoreCase)
		{
			{
				"pow",
				new FunctionRoutine(2, (EvaluationContext ctx, ExpressionToken[] args) => new ExpressionToken(Math.Pow(args[0].ToDouble(ctx), args[1].ToDouble(ctx)).ToString(ctx.FormatCulture)))
			},
			{
				"sin",
				new FunctionRoutine(1, (EvaluationContext ctx, ExpressionToken[] args) => new ExpressionToken(Math.Sin(args[0].ToDouble(ctx)).ToString(ctx.FormatCulture)))
			},
			{
				"cos",
				new FunctionRoutine(1, (EvaluationContext ctx, ExpressionToken[] args) => new ExpressionToken(Math.Cos(args[0].ToDouble(ctx)).ToString(ctx.FormatCulture)))
			},
			{
				"tan",
				new FunctionRoutine(1, (EvaluationContext ctx, ExpressionToken[] args) => new ExpressionToken(Math.Tan(args[0].ToDouble(ctx)).ToString(ctx.FormatCulture)))
			}
		};

		private static readonly Dictionary<string, FunctionRoutine> __staticFuncs = new Dictionary<string, FunctionRoutine>(StringComparer.OrdinalIgnoreCase);

		private readonly Dictionary<string, FunctionRoutine> _instanceFuncs = new Dictionary<string, FunctionRoutine>(StringComparer.OrdinalIgnoreCase);

		private Func<string, (object, ValueTypeHint)> _fieldLookup;

		private readonly CultureInfo _usCulture = new CultureInfo("en-US");

		private CultureInfo _formatCulture = null;

		public CultureInfo FormatCulture
		{
			get
			{
				return _formatCulture ?? _usCulture;
			}
			set
			{
				_formatCulture = value;
			}
		}

		public EvaluationContext()
		{
		}

		public EvaluationContext(Func<string, (object Value, ValueTypeHint TypeHint)> fieldLookupRoutine)
		{
			_fieldLookup = fieldLookupRoutine;
		}

		public (object Value, ValueTypeHint TypeHint) ResolveFieldValue(string field)
		{
			if (_fieldLookup != null)
			{
				return _fieldLookup(field);
			}
			return OnResolveFieldValue(field);
		}

		protected virtual (object Value, ValueTypeHint TypeHint) OnResolveFieldValue(string field)
		{
			return (string.Empty, ValueTypeHint.Auto);
		}

		public static void RegisterGlobalFunction(string functionName, FunctionRoutine info)
		{
			__staticFuncs[functionName] = info;
		}

		public void RegisterFunction(string functionName, FunctionRoutine info)
		{
			_instanceFuncs[functionName] = info;
		}

		public FunctionRoutine GetFunction(string functionName)
		{
			if (_instanceFuncs.ContainsKey(functionName))
			{
				return _instanceFuncs[functionName];
			}
			if (__staticFuncs.ContainsKey(functionName))
			{
				return __staticFuncs[functionName];
			}
			if (BuiltInFunctions.ContainsKey(functionName))
			{
				return BuiltInFunctions[functionName];
			}
			return OnGetFunction(functionName) ?? throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Function \"{0}\" is not supported.", functionName));
		}

		protected virtual FunctionRoutine OnGetFunction(string functionName)
		{
			return null;
		}
	}
	public class Evaluator
	{
		private EvaluationContext _context;

		private Stack<ExpressionToken> _stack;

		public Evaluator(EvaluationContext context)
		{
			_context = context ?? throw new ArgumentNullException("context");
		}

		public ExpressionToken Evaluate(string input, bool coerseToBoolean = false)
		{
			if (string.IsNullOrWhiteSpace(input))
			{
				return coerseToBoolean ? ExpressionToken.False : new ExpressionToken(input);
			}
			ExpressionToken[] array = new InfixToPostfixTokenizer().Tokenize(input);
			foreach (ExpressionToken item in array.Where((ExpressionToken tk) => tk.TokenType == ExpressionTokenType.Field))
			{
				item.FieldValue = _context.ResolveFieldValue(item.Value);
			}
			ListReader<ExpressionToken> listReader = new ListReader<ExpressionToken>(array);
			_stack = new Stack<ExpressionToken>();
			while (!listReader.IsEnd)
			{
				ExpressionToken expressionToken = listReader.Read();
				switch (expressionToken.TokenType)
				{
				case ExpressionTokenType.Field:
				case ExpressionTokenType.SingleQuoted:
				case ExpressionTokenType.DoubleQuoted:
				case ExpressionTokenType.Value:
					_stack.Push(expressionToken);
					break;
				case ExpressionTokenType.Operator:
					HandleOperator(expressionToken.OperatorType);
					break;
				case ExpressionTokenType.Function:
					HandleFunction(expressionToken.Value);
					break;
				}
			}
			if (_stack.Count == 1)
			{
				ExpressionToken expressionToken2 = _stack.Pop();
				if (coerseToBoolean)
				{
					return ConvertTokenToFalseTrue(expressionToken2);
				}
				return expressionToken2;
			}
			throw new NotSupportedException("Unbalanced expression.");
		}

		public ExpressionToken ConvertTokenToFalseTrue(ExpressionToken token)
		{
			if (IsFalse(token.ToString()))
			{
				return ExpressionToken.False;
			}
			return ExpressionToken.True;
		}

		private void HandleFunction(string functionName)
		{
			FunctionRoutine function = _context.GetFunction(functionName);
			Stack<ExpressionToken> stack = new Stack<ExpressionToken>(function.ArgumentCount);
			while (stack.Count < function.ArgumentCount)
			{
				stack.Push(_stack.Pop());
			}
			_stack.Push(function.Evaluate(_context, stack.ToArray()));
		}

		private static bool IsDate(string lhs, string rhs, out DateTime lhsDate, out DateTime rhsDate)
		{
			lhsDate = default(DateTime);
			rhsDate = default(DateTime);
			if (DateTime.TryParse(lhs, out lhsDate))
			{
				DateTime.TryParse(rhs, out rhsDate);
				return true;
			}
			if (DateTime.TryParse(rhs, out rhsDate))
			{
				DateTime.TryParse(lhs, out lhsDate);
				return true;
			}
			return false;
		}

		private bool IsNumber(string lhs, string rhs, out decimal lhsNumber, out decimal rhsNumber)
		{
			lhsNumber = default(decimal);
			rhsNumber = default(decimal);
			bool flag = decimal.TryParse(lhs, ExpressionToken.NumberParseStyle, _context.FormatCulture, out lhsNumber);
			bool flag2 = decimal.TryParse(rhs, ExpressionToken.NumberParseStyle, _context.FormatCulture, out rhsNumber);
			return flag && flag2;
		}

		private static bool IsBoolean(string lhs, string rhs, out bool lhsBool, out bool rhsBool)
		{
			bool flag = false;
			bool flag2 = false;
			lhsBool = false;
			rhsBool = false;
			if (!string.IsNullOrEmpty(lhs))
			{
				if (string.Equals(lhs, "true", StringComparison.OrdinalIgnoreCase) || lhs == "1")
				{
					lhsBool = true;
					flag = true;
				}
				else if (string.Equals(lhs, "false", StringComparison.OrdinalIgnoreCase) || lhs == "0")
				{
					flag = true;
				}
			}
			if (flag && !string.IsNullOrEmpty(rhs))
			{
				if (string.Equals(rhs, "true", StringComparison.OrdinalIgnoreCase) || rhs == "1")
				{
					rhsBool = true;
					flag2 = true;
				}
				else if (string.Equals(rhs, "false", StringComparison.OrdinalIgnoreCase) || rhs == "0")
				{
					flag2 = true;
				}
			}
			return flag && flag2;
		}

		private void HandleOperator(OperatorType op)
		{
			decimal lhsNumber;
			decimal rhsNumber;
			bool lhsBool;
			bool rhsBool;
			switch (op)
			{
			case OperatorType.Addition:
				BinaryNumberOperation((decimal a, decimal b) => a + b);
				break;
			case OperatorType.Subtraction:
				BinaryNumberOperation((decimal a, decimal b) => a - b);
				break;
			case OperatorType.Multiplication:
				BinaryNumberOperation((decimal a, decimal b) => a * b);
				break;
			case OperatorType.Division:
				BinaryNumberOperation((decimal a, decimal b) => a / b);
				break;
			case OperatorType.Modulus:
				BinaryNumberOperation((decimal a, decimal b) => a % b);
				break;
			case OperatorType.LessThan:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate;
				DateTime rhsDate;
				if (IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber < rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate, out rhsDate))
				{
					_stack.Push((lhsDate < rhsDate) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) < 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.LessThanOrEqual:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate6;
				DateTime rhsDate6;
				if (IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber <= rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate6, out rhsDate6))
				{
					_stack.Push((lhsDate6 <= rhsDate6) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) <= 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.GreaterThan:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate2;
				DateTime rhsDate2;
				if (IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber > rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate2, out rhsDate2))
				{
					_stack.Push((lhsDate2 > rhsDate2) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) > 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.GreaterThanOrEqual:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate3;
				DateTime rhsDate3;
				if (IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber >= rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate3, out rhsDate3))
				{
					_stack.Push((lhsDate3 >= rhsDate3) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) >= 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.Equal:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate5;
				DateTime rhsDate5;
				if (IsBoolean(text2, text, out lhsBool, out rhsBool))
				{
					_stack.Push((lhsBool == rhsBool) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if ((AllowAutoFormat(expressionToken2) || AllowAutoFormat(expressionToken)) && IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber == rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate5, out rhsDate5))
				{
					_stack.Push((lhsDate5 == rhsDate5) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) == 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.NotEqual:
			{
				ExpressionToken expressionToken = _stack.Pop();
				ExpressionToken expressionToken2 = _stack.Pop();
				string text = expressionToken.ToString();
				string text2 = expressionToken2.ToString();
				DateTime lhsDate4;
				DateTime rhsDate4;
				if (IsBoolean(text2, text, out lhsBool, out rhsBool))
				{
					_stack.Push((lhsBool != rhsBool) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if ((AllowAutoFormat(expressionToken2) || AllowAutoFormat(expressionToken)) && IsNumber(text2, text, out lhsNumber, out rhsNumber))
				{
					_stack.Push((lhsNumber != rhsNumber) ? ExpressionToken.True : ExpressionToken.False);
				}
				else if (IsDate(text2, text, out lhsDate4, out rhsDate4))
				{
					_stack.Push((lhsDate4 != rhsDate4) ? ExpressionToken.True : ExpressionToken.False);
				}
				else
				{
					_stack.Push((string.Compare(text2, text, StringComparison.OrdinalIgnoreCase) != 0) ? ExpressionToken.True : ExpressionToken.False);
				}
				break;
			}
			case OperatorType.BitwiseAnd:
				BinaryNumberOperation((decimal a, decimal b) => (int)a & (int)b);
				break;
			case OperatorType.BitwiseOr:
				BinaryNumberOperation((decimal a, decimal b) => (int)a | (int)b);
				break;
			case OperatorType.LogicalAnd:
				BinaryLogicOperation((string a, string b) => IsTrue(a) && IsTrue(b));
				break;
			case OperatorType.LogicalOr:
				BinaryLogicOperation((string a, string b) => IsTrue(a) || IsTrue(b));
				break;
			case OperatorType.UnaryMinus:
				UnaryNumberOperation((decimal a) => -1m * a);
				break;
			case OperatorType.UnaryPlus:
				break;
			case OperatorType.LogicalNegation:
				UnaryLogicOperation((string a) => !IsTrue(a));
				break;
			case OperatorType.PreIncrement:
				UnaryNumberOperation((decimal a) => a + 1m);
				break;
			case OperatorType.PreDecrement:
				UnaryNumberOperation((decimal a) => a - 1m);
				break;
			default:
				throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "The {0} operation is not currently supported.", op));
			}
		}

		private static bool AllowAutoFormat(ExpressionToken token)
		{
			return token.TokenType != ExpressionTokenType.Field || token.FieldValue.TypeHint != ValueTypeHint.Text;
		}

		private static bool IsTrue(string value)
		{
			return string.Equals("true", value, StringComparison.OrdinalIgnoreCase) || value == "1";
		}

		private static bool IsFalse(string value)
		{
			return string.Equals("false", value, StringComparison.OrdinalIgnoreCase) || value == "0" || string.IsNullOrWhiteSpace(value);
		}

		private void UnaryNumberOperation(Func<decimal, decimal> operation)
		{
			decimal arg = _stack.Pop().ToDecimal(_context);
			decimal num = operation(arg);
			_stack.Push(new ExpressionToken(num.ToString(_context.FormatCulture)));
		}

		private void UnaryLogicOperation(Func<string, bool> operation)
		{
			ExpressionToken expressionToken = _stack.Pop();
			string value = (operation(expressionToken.ToString()) ? "1" : "0");
			_stack.Push(new ExpressionToken(value));
		}

		private void BinaryLogicOperation(Func<string, string, bool> operation)
		{
			ExpressionToken expressionToken = _stack.Pop();
			ExpressionToken expressionToken2 = _stack.Pop();
			string value = (operation(expressionToken2.ToString(), expressionToken.ToString()) ? "1" : "0");
			_stack.Push(new ExpressionToken(value));
		}

		private void BinaryNumberOperation(Func<decimal, decimal, decimal> operation)
		{
			decimal arg = _stack.Pop().ToDecimal(_context);
			decimal arg2 = _stack.Pop().ToDecimal(_context);
			decimal num = operation(arg2, arg);
			_stack.Push(new ExpressionToken(num.ToString(_context.FormatCulture)));
		}
	}
	public class ExpressionToken
	{
		public static readonly ExpressionToken True = new ExpressionToken("1");

		public static readonly ExpressionToken False = new ExpressionToken("0");

		internal static readonly NumberStyles NumberParseStyle = NumberStyles.Number | NumberStyles.AllowCurrencySymbol;

		private RawToken _rawToken;

		private const string FrozenErrorMsg = "Cannot modify frozen token.";

		private ExpressionTokenType _type;

		private string _value;

		public RawToken RawToken => _rawToken;

		public bool IsFrozen => _value != null;

		public ExpressionTokenType TokenType
		{
			get
			{
				return _type;
			}
			set
			{
				if (_value == null)
				{
					_type = value;
				}
			}
		}

		public OperatorType OperatorType { get; set; }

		public string Value => _value ?? _rawToken?.ToString();

		public (object Value, ValueTypeHint TypeHint) FieldValue { get; internal set; }

		public ExpressionToken()
		{
		}

		public ExpressionToken(string value)
		{
			_type = ExpressionTokenType.Value;
			_value = value;
		}

		public void Append(RawToken token)
		{
			if (IsFrozen)
			{
				throw new InvalidOperationException("Cannot modify frozen token.");
			}
			if (_rawToken == null)
			{
				_rawToken = token;
			}
			else
			{
				_rawToken.Append(token);
			}
		}

		public void Freeze()
		{
			if (IsFrozen)
			{
				throw new InvalidOperationException("Cannot modify frozen token.");
			}
			_value = _rawToken?.ToString();
		}

		public override string ToString()
		{
			ExpressionTokenType tokenType = TokenType;
			ExpressionTokenType expressionTokenType = tokenType;
			if (expressionTokenType == ExpressionTokenType.Field)
			{
				return FieldValue.Value?.ToString() ?? "";
			}
			return Value ?? "";
		}

		public double ToDouble(EvaluationContext context)
		{
			switch (TokenType)
			{
			case ExpressionTokenType.SingleQuoted:
			case ExpressionTokenType.DoubleQuoted:
			case ExpressionTokenType.Value:
				return double.Parse(Value, NumberParseStyle, context.FormatCulture);
			case ExpressionTokenType.Field:
				return double.Parse(FieldValue.Value?.ToString(), NumberParseStyle, context.FormatCulture);
			default:
				throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Cannot convert {0}({1}) to a numeric value.", TokenType, Value));
			}
		}

		public decimal ToDecimal(EvaluationContext context)
		{
			switch (TokenType)
			{
			case ExpressionTokenType.SingleQuoted:
			case ExpressionTokenType.DoubleQuoted:
			case ExpressionTokenType.Value:
				return decimal.Parse(Value, NumberParseStyle, context.FormatCulture);
			case ExpressionTokenType.Field:
				return decimal.Parse(FieldValue.Value?.ToString(), NumberParseStyle, context.FormatCulture);
			default:
				throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Cannot convert {0}({1}) to a numeric value.", TokenType, Value));
			}
		}
	}
	public enum ExpressionTokenType
	{
		None,
		Operator,
		OpenParenthesis,
		CloseParenthesis,
		Function,
		Comma,
		Field,
		SingleQuoted,
		DoubleQuoted,
		Value
	}
	public class FunctionRoutine
	{
		private Func<EvaluationContext, ExpressionToken[], ExpressionToken> _routine;

		public int ArgumentCount { get; private set; }

		public FunctionRoutine(int argCount, Func<EvaluationContext, ExpressionToken[], ExpressionToken> routine)
		{
			if (routine == null)
			{
				throw new ArgumentNullException("routine");
			}
			ArgumentCount = argCount;
			_routine = routine;
		}

		public ExpressionToken Evaluate(EvaluationContext context, ExpressionToken[] args)
		{
			return _routine(context, args);
		}
	}
	public enum ValueTypeHint
	{
		Auto,
		Text
	}
}
namespace Soukoku.ExpressionParser.Parsing
{
	public interface IExpressionTokenizer
	{
		ExpressionToken[] Tokenize(string input);
	}
	public class InfixTokenizer : IExpressionTokenizer
	{
		private List<ExpressionToken> _currentTokens;

		public ExpressionToken[] Tokenize(string input)
		{
			_currentTokens = new List<ExpressionToken>();
			ExpressionToken expressionToken = null;
			ListReader<RawToken> listReader = new ListReader<RawToken>(new RawTokenizer().Tokenize(input));
			while (!listReader.IsEnd)
			{
				RawToken rawToken = listReader.Read();
				switch (rawToken.TokenType)
				{
				case RawTokenType.WhiteSpace:
					expressionToken = null;
					break;
				case RawTokenType.Literal:
					if (expressionToken == null || expressionToken.TokenType != ExpressionTokenType.Value)
					{
						expressionToken = new ExpressionToken
						{
							TokenType = ExpressionTokenType.Value
						};
						_currentTokens.Add(expressionToken);
					}
					expressionToken.Append(rawToken);
					break;
				case RawTokenType.Symbol:
					if (KnownOperators.IsKnown(rawToken.Value))
					{
						if (expressionToken != null && expressionToken.TokenType == ExpressionTokenType.Operator)
						{
							string operatorValue = expressionToken.Value + rawToken.Value;
							if (KnownOperators.IsKnown(operatorValue))
							{
								expressionToken.Append(rawToken);
								break;
							}
						}
						expressionToken = new ExpressionToken
						{
							TokenType = ExpressionTokenType.Operator
						};
						_currentTokens.Add(expressionToken);
						expressionToken.Append(rawToken);
					}
					else
					{
						expressionToken = HandleNonOperatorSymbolToken(listReader, expressionToken, rawToken);
					}
					break;
				default:
					throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Unsupported token type {0} at position {1}.", rawToken.TokenType, rawToken.Position));
				}
			}
			MassageTokens(_currentTokens);
			return _currentTokens.ToArray();
		}

		private ExpressionToken HandleNonOperatorSymbolToken(ListReader<RawToken> reader, ExpressionToken lastExpToken, RawToken curRawToken)
		{
			switch (curRawToken.Value)
			{
			case ",":
				lastExpToken = new ExpressionToken
				{
					TokenType = ExpressionTokenType.Comma
				};
				_currentTokens.Add(lastExpToken);
				lastExpToken.Append(curRawToken);
				break;
			case "(":
				if (lastExpToken != null && lastExpToken.TokenType == ExpressionTokenType.Value)
				{
					lastExpToken.TokenType = ExpressionTokenType.Function;
				}
				lastExpToken = new ExpressionToken
				{
					TokenType = ExpressionTokenType.OpenParenthesis
				};
				_currentTokens.Add(lastExpToken);
				lastExpToken.Append(curRawToken);
				break;
			case ")":
				lastExpToken = new ExpressionToken
				{
					TokenType = ExpressionTokenType.CloseParenthesis
				};
				_currentTokens.Add(lastExpToken);
				lastExpToken.Append(curRawToken);
				break;
			case "{":
				lastExpToken = ReadToLiteralAs(reader, "}", ExpressionTokenType.Field);
				break;
			case "\"":
				lastExpToken = ReadToLiteralAs(reader, "\"", ExpressionTokenType.DoubleQuoted);
				break;
			case "'":
				lastExpToken = ReadToLiteralAs(reader, "'", ExpressionTokenType.SingleQuoted);
				break;
			}
			return lastExpToken;
		}

		private ExpressionToken ReadToLiteralAs(ListReader<RawToken> reader, string literalValue, ExpressionTokenType tokenType)
		{
			ExpressionToken expressionToken = new ExpressionToken
			{
				TokenType = tokenType
			};
			_currentTokens.Add(expressionToken);
			while (!reader.IsEnd)
			{
				RawToken rawToken = reader.Read();
				if (rawToken.TokenType == RawTokenType.Symbol && rawToken.Value == literalValue)
				{
					break;
				}
				expressionToken.Append(rawToken);
			}
			return expressionToken;
		}

		private static void MassageTokens(List<ExpressionToken> tokens)
		{
			ListReader<ExpressionToken> listReader = new ListReader<ExpressionToken>(tokens);
			while (!listReader.IsEnd)
			{
				ExpressionToken expressionToken = listReader.Read();
				if (expressionToken.TokenType == ExpressionTokenType.Operator)
				{
					DetermineOperatorType(listReader, expressionToken);
				}
				expressionToken.Freeze();
			}
		}

		private static void DetermineOperatorType(ListReader<ExpressionToken> reader, ExpressionToken tk)
		{
			tk.OperatorType = KnownOperators.TryMap(tk.Value);
			switch (tk.OperatorType)
			{
			case OperatorType.PreIncrement:
			case OperatorType.PreDecrement:
			{
				ExpressionToken expressionToken = ((reader.Position > 1) ? reader.Peek(-2) : null);
				if (expressionToken != null && expressionToken.TokenType == ExpressionTokenType.Value)
				{
					if (tk.OperatorType == OperatorType.PreIncrement)
					{
						tk.OperatorType = OperatorType.PostIncrement;
					}
					else
					{
						tk.OperatorType = OperatorType.PostDecrement;
					}
				}
				break;
			}
			case OperatorType.Addition:
			case OperatorType.Subtraction:
			{
				ExpressionToken expressionToken = ((reader.Position > 1) ? reader.Peek(-2) : null);
				if (expressionToken == null || (expressionToken.TokenType == ExpressionTokenType.Operator && expressionToken.OperatorType != OperatorType.PostDecrement && expressionToken.OperatorType != OperatorType.PostIncrement))
				{
					if (tk.OperatorType == OperatorType.Addition)
					{
						tk.OperatorType = OperatorType.UnaryPlus;
					}
					else
					{
						tk.OperatorType = OperatorType.UnaryMinus;
					}
				}
				break;
			}
			case OperatorType.None:
				throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Operator {0} is not supported.", tk.Value));
			}
		}
	}
	public class InfixToPostfixTokenizer : IExpressionTokenizer
	{
		private const string UnbalancedParenMsg = "Unbalanced parenthesis in expression.";

		private List<ExpressionToken> _output;

		private Stack<ExpressionToken> _stack;

		public ExpressionToken[] Tokenize(string input)
		{
			ExpressionToken[] array = new InfixTokenizer().Tokenize(input);
			_output = new List<ExpressionToken>();
			_stack = new Stack<ExpressionToken>();
			ExpressionToken[] array2 = array;
			foreach (ExpressionToken expressionToken in array2)
			{
				switch (expressionToken.TokenType)
				{
				case ExpressionTokenType.Field:
				case ExpressionTokenType.SingleQuoted:
				case ExpressionTokenType.DoubleQuoted:
				case ExpressionTokenType.Value:
					_output.Add(expressionToken);
					break;
				case ExpressionTokenType.Function:
					_stack.Push(expressionToken);
					break;
				case ExpressionTokenType.Comma:
					HandleComma();
					break;
				case ExpressionTokenType.Operator:
					HandleOperatorToken(expressionToken);
					break;
				case ExpressionTokenType.OpenParenthesis:
					_stack.Push(expressionToken);
					break;
				case ExpressionTokenType.CloseParenthesis:
					HandleCloseParenthesis();
					break;
				}
			}
			while (_stack.Count > 0)
			{
				ExpressionToken expressionToken2 = _stack.Pop();
				if (expressionToken2.TokenType == ExpressionTokenType.OpenParenthesis)
				{
					throw new NotSupportedException("Unbalanced parenthesis in expression.");
				}
				_output.Add(expressionToken2);
			}
			return _output.ToArray();
		}

		private void HandleComma()
		{
			bool flag = false;
			while (_stack.Count > 1)
			{
				ExpressionToken expressionToken = _stack.Peek();
				if (expressionToken.TokenType == ExpressionTokenType.OpenParenthesis)
				{
					flag = true;
					break;
				}
				_output.Add(_stack.Pop());
			}
			if (!flag)
			{
				throw new NotSupportedException("Unbalanced parenthesis in expression.");
			}
		}

		private void HandleOperatorToken(ExpressionToken inToken)
		{
			while (_stack.Count > 0)
			{
				ExpressionToken expressionToken = _stack.Peek();
				if (expressionToken.TokenType == ExpressionTokenType.Operator)
				{
					int precedence = KnownOperators.GetPrecedence(inToken.OperatorType);
					int precedence2 = KnownOperators.GetPrecedence(expressionToken.OperatorType);
					bool flag = KnownOperators.IsLeftAssociative(inToken.OperatorType);
					if ((flag && precedence <= precedence2) || (!flag && precedence < precedence2))
					{
						_output.Add(_stack.Pop());
						continue;
					}
					break;
				}
				break;
			}
			_stack.Push(inToken);
		}

		private void HandleCloseParenthesis()
		{
			bool flag = false;
			while (_stack.Count > 0)
			{
				ExpressionToken expressionToken = _stack.Pop();
				if (expressionToken.TokenType == ExpressionTokenType.OpenParenthesis)
				{
					flag = true;
					break;
				}
				_output.Add(expressionToken);
			}
			if (!flag)
			{
				throw new NotSupportedException("Unbalanced parenthesis in expression.");
			}
			if (_stack.Count > 0)
			{
				ExpressionToken expressionToken2 = _stack.Peek();
				if (expressionToken2 != null && expressionToken2.TokenType == ExpressionTokenType.Function)
				{
					_output.Add(_stack.Pop());
				}
			}
		}
	}
	public static class KnownOperators
	{
		private static readonly Dictionary<string, OperatorType> DefaultMap = new Dictionary<string, OperatorType>
		{
			{
				"++",
				OperatorType.PreIncrement
			},
			{
				"--",
				OperatorType.PreDecrement
			},
			{
				"+=",
				OperatorType.AdditionAssignment
			},
			{
				"-=",
				OperatorType.SubtractionAssignment
			},
			{
				"*=",
				OperatorType.MultiplicationAssignment
			},
			{
				"/=",
				OperatorType.DivisionAssignment
			},
			{
				"%=",
				OperatorType.ModulusAssignment
			},
			{
				"==",
				OperatorType.Equal
			},
			{
				"!=",
				OperatorType.NotEqual
			},
			{
				"<=",
				OperatorType.LessThanOrEqual
			},
			{
				">=",
				OperatorType.GreaterThanOrEqual
			},
			{
				"&&",
				OperatorType.LogicalAnd
			},
			{
				"||",
				OperatorType.LogicalOr
			},
			{
				"+",
				OperatorType.Addition
			},
			{
				"-",
				OperatorType.Subtraction
			},
			{
				"*",
				OperatorType.Multiplication
			},
			{
				"/",
				OperatorType.Division
			},
			{
				"=",
				OperatorType.Assignment
			},
			{
				"%",
				OperatorType.Modulus
			},
			{
				"<",
				OperatorType.LessThan
			},
			{
				">",
				OperatorType.GreaterThan
			},
			{
				"&",
				OperatorType.BitwiseAnd
			},
			{
				"|",
				OperatorType.BitwiseOr
			},
			{
				"!",
				OperatorType.LogicalNegation
			}
		};

		public static bool IsKnown(string operatorValue)
		{
			return DefaultMap.ContainsKey(operatorValue);
		}

		public static OperatorType TryMap(string operatorValue)
		{
			if (DefaultMap.ContainsKey(operatorValue))
			{
				return DefaultMap[operatorValue];
			}
			return OperatorType.None;
		}

		public static int GetPrecedence(OperatorType type)
		{
			switch (type)
			{
			case OperatorType.PostIncrement:
			case OperatorType.PostDecrement:
				return 100;
			case OperatorType.PreIncrement:
			case OperatorType.PreDecrement:
			case OperatorType.UnaryPlus:
			case OperatorType.UnaryMinus:
			case OperatorType.LogicalNegation:
				return 90;
			case OperatorType.Multiplication:
			case OperatorType.Division:
			case OperatorType.Modulus:
				return 85;
			case OperatorType.Addition:
			case OperatorType.Subtraction:
				return 80;
			case OperatorType.LessThan:
			case OperatorType.LessThanOrEqual:
			case OperatorType.GreaterThan:
			case OperatorType.GreaterThanOrEqual:
				return 75;
			case OperatorType.Equal:
			case OperatorType.NotEqual:
				return 70;
			case OperatorType.BitwiseAnd:
			case OperatorType.BitwiseOr:
				return 65;
			case OperatorType.LogicalAnd:
			case OperatorType.LogicalOr:
				return 60;
			case OperatorType.Assignment:
			case OperatorType.AdditionAssignment:
			case OperatorType.SubtractionAssignment:
			case OperatorType.MultiplicationAssignment:
			case OperatorType.DivisionAssignment:
			case OperatorType.ModulusAssignment:
				return 20;
			default:
				return 0;
			}
		}

		public static bool IsLeftAssociative(OperatorType type)
		{
			if ((uint)(type - 3) <= 4u || (uint)(type - 23) <= 5u)
			{
				return false;
			}
			return true;
		}
	}
	public class ListReader<TItem>
	{
		private IList<TItem> _list;

		private int _position;

		public int Position
		{
			get
			{
				return _position;
			}
			set
			{
				if (value < 0 || value > _list.Count)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				_position = value;
			}
		}

		public bool IsEnd => _position >= _list.Count;

		public ListReader(IList<TItem> list)
		{
			if (list == null)
			{
				throw new ArgumentNullException("list");
			}
			_list = list;
		}

		public TItem Read()
		{
			return _list[Position++];
		}

		public TItem Peek()
		{
			return Peek(0);
		}

		public TItem Peek(int offset)
		{
			return _list[Position + offset];
		}
	}
	public enum OperatorType
	{
		None,
		PostIncrement,
		PostDecrement,
		PreIncrement,
		PreDecrement,
		UnaryPlus,
		UnaryMinus,
		LogicalNegation,
		Multiplication,
		Division,
		Modulus,
		Addition,
		Subtraction,
		LessThan,
		LessThanOrEqual,
		GreaterThan,
		GreaterThanOrEqual,
		Equal,
		NotEqual,
		BitwiseAnd,
		BitwiseOr,
		LogicalAnd,
		LogicalOr,
		Assignment,
		AdditionAssignment,
		SubtractionAssignment,
		MultiplicationAssignment,
		DivisionAssignment,
		ModulusAssignment
	}
	public class RawToken
	{
		public RawTokenType TokenType { get; private set; }

		public int Position { get; private set; }

		internal StringBuilder ValueBuilder { get; private set; }

		public string Value => ValueBuilder.ToString();

		internal RawToken(RawTokenType type, int position)
		{
			TokenType = type;
			Position = position;
			ValueBuilder = new StringBuilder();
		}

		internal void Append(RawToken token)
		{
			if (token != null)
			{
				ValueBuilder.Append((object?)token.ValueBuilder);
			}
		}

		public override string ToString()
		{
			return Value;
		}
	}
	public enum RawTokenType
	{
		None,
		WhiteSpace,
		Symbol,
		Literal
	}
	public class RawTokenizer
	{
		private static readonly char[] DefaultSymbols = new char[22]
		{
			'+', '-', '*', '/', '=', '%', '^', ',', '<', '>',
			'&', '|', '!', '(', ')', '{', '}', '[', ']', '"',
			'\'', '~'
		};

		private char[] _symbols;

		public RawTokenizer()
			: this(null)
		{
		}

		public RawTokenizer(params char[] symbols)
		{
			_symbols = symbols ?? DefaultSymbols;
		}

		public char[] GetSymbols()
		{
			return (char[])_symbols.Clone();
		}

		public RawToken[] Tokenize(string input)
		{
			List<RawToken> list = new List<RawToken>();
			if (input != null)
			{
				RawToken rawToken = null;
				for (int i = 0; i < input.Length; i++)
				{
					char c = input[i];
					rawToken = (char.IsWhiteSpace(c) ? NewTokenIfNecessary(list, rawToken, RawTokenType.WhiteSpace, i) : ((!_symbols.Contains(c)) ? NewTokenIfNecessary(list, rawToken, RawTokenType.Literal, i) : NewTokenIfNecessary(list, rawToken, RawTokenType.Symbol, i)));
					if (c == '\\' && ++i < input.Length)
					{
						char value = input[i];
						rawToken.ValueBuilder.Append(value);
					}
					else
					{
						rawToken.ValueBuilder.Append(c);
					}
				}
			}
			return list.ToArray();
		}

		private static RawToken NewTokenIfNecessary(List<RawToken> tokens, RawToken lastToken, RawTokenType curTokenType, int position)
		{
			if (lastToken == null || lastToken.TokenType != curTokenType || curTokenType == RawTokenType.Symbol)
			{
				lastToken = new RawToken(curTokenType, position);
				tokens.Add(lastToken);
			}
			return lastToken;
		}
	}
}
namespace DunGenPlus
{
	public class API
	{
		public static bool AddDunGenExtender(DungeonFlow dungeonFlow, DunGenExtender dunGenExtender)
		{
			if ((Object)(object)dungeonFlow == (Object)null)
			{
				Plugin.logger.LogError((object)"dungeonFlow was null");
				return false;
			}
			if (ContainsDungeonFlow(dungeonFlow))
			{
				Plugin.logger.LogWarning((object)("Already contains DunGenExtender asset for " + ((Object)dungeonFlow).name));
				return false;
			}
			Plugin.DunGenExtenders.Add(dungeonFlow, dunGenExtender);
			Plugin.logger.LogInfo((object)("Added DunGenExtender asset for " + ((Object)dungeonFlow).name));
			return true;
		}

		public static bool AddDunGenExtender(DunGenExtender dunGenExtender)
		{
			if ((Object)(object)dunGenExtender == (Object)null)
			{
				Plugin.logger.LogError((object)"dunGenExtender was null");
				return false;
			}
			return AddDunGenExtender(dunGenExtender.DungeonFlow, dunGenExtender);
		}

		public static bool ContainsDungeonFlow(DungeonFlow dungeonFlow)
		{
			return Plugin.DunGenExtenders.ContainsKey(dungeonFlow);
		}

		public static bool ContainsDungeonFlow(ExtendedDungeonFlow extendedDungeonFlow)
		{
			if ((Object)(object)extendedDungeonFlow == (Object)null)
			{
				return false;
			}
			return ContainsDungeonFlow(extendedDungeonFlow.DungeonFlow);
		}

		public static DunGenExtender GetDunGenExtender(DungeonFlow dungeonFlow)
		{
			if (Plugin.DunGenExtenders.TryGetValue(dungeonFlow, out var value))
			{
				return value;
			}
			return null;
		}

		public static bool IsDunGenExtenderActive(DungeonFlow dungeonFlow)
		{
			return IsDunGenExtenderActive(GetDunGenExtender(dungeonFlow));
		}

		public static bool IsDunGenExtenderActive(DunGenExtender extender)
		{
			return (Object)(object)extender != (Object)null && (Object)(object)extender == (Object)(object)DunGenPlusGenerator.Instance;
		}

		public static DunGenExtender CreateDunGenExtender(DungeonFlow dungeonFlow)
		{
			DunGenExtender dunGenExtender = ScriptableObject.CreateInstance<DunGenExtender>();
			dunGenExtender.DungeonFlow = dungeonFlow;
			return dunGenExtender;
		}

		public static void AddTileToMainPathDictionary(Dictionary<TileProxy, Tile> dictionary)
		{
			DunGenPlusGenerator.AddTileToMainPathDictionary(dictionary);
		}

		public static bool IsDevDebugModeActive()
		{
			return DevDebugManager.IsActive;
		}
	}
	internal class Assets
	{
		public static AssetBundle MainAssetBundle;

		public static GameObject DevDebugPrefab;

		public static void LoadAssets()
		{
			string[] files = Directory.GetFiles(Paths.PluginPath, "*.lethalbundle", SearchOption.AllDirectories);
			foreach (string fileName in files)
			{
				FileInfo fileInfo = new FileInfo(fileName);
				AssetBundleLoader.AddOnLethalBundleLoadedListener((Action<AssetBundle>)AutoAddLethalBundle, fileInfo.Name);
			}
		}

		private static void AutoAddLethalBundle(AssetBundle assetBundle)
		{
			if (!assetBundle.isStreamedSceneAssetBundle)
			{
				DunGenExtender[] array = assetBundle.LoadAllAssets<DunGenExtender>();
				ExtendedContent[] array2 = assetBundle.LoadAllAssets<ExtendedContent>();
				if (array2.Length == 0 && array.Length != 0)
				{
					Plugin.logger.LogWarning((object)".lethalbundle does not contain any ExtendedContent. Unless you are manually creating and adding your ExtendedDungeonFlow with code, the DunGenExtender will probably not work.");
				}
				DunGenExtender[] array3 = array;
				foreach (DunGenExtender dunGenExtender in array3)
				{
					API.AddDunGenExtender(dunGenExtender);
				}
			}
		}

		public static T Load<T>(string name, bool onlyReportErrors = true) where T : Object
		{
			if ((Object)(object)MainAssetBundle == (Object)null)
			{
				Plugin.logger.LogError((object)"Trying to load in asset but asset bundle is missing");
				return default(T);
			}
			T val = MainAssetBundle.LoadAsset<T>(name);
			bool flag = (Object)(object)val == (Object)null;
			if (flag || onlyReportErrors)
			{
				Plugin.logger.LogDebug((object)("Loading asset " + name));
			}
			if (flag)
			{
				Plugin.logger.LogError((object)"...but it was not found");
			}
			return val;
		}

		public static void LoadAssetBundle()
		{
			if ((Object)(object)MainAssetBundle == (Object)null)
			{
				Assembly executingAssembly = Assembly.GetExecutingAssembly();
				string[] manifestResourceNames = executingAssembly.GetManifestResourceNames();
				if (manifestResourceNames.Length >= 1)
				{
					string text = manifestResourceNames[0];
					using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(text);
					Plugin.logger.LogDebug((object)("Loading resource " + text));
					MainAssetBundle = AssetBundle.LoadFromStream(stream);
				}
			}
			DevDebugPrefab = Assets.Load<GameObject>("DevDebug", onlyReportErrors: true);
		}
	}
	[Serializable]
	public class PropertyOverride<T>
	{
		[Tooltip("If false, use the value found in DungeonFlow. If true, use this Value instead.")]
		public bool Override;

		public T Value;

		public PropertyOverride(bool _override, T value)
		{
			Override = _override;
			Value = value;
		}
	}
	[CreateAssetMenu(fileName = "Main Path Extender", menuName = "DunGenExtender/Main Path Extender", order = 2)]
	public class MainPathExtender : ScriptableObject
	{
		internal const string LocalMainPathGlobalPropsTooltip = "Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow.";

		public PropertyOverride<IntRange> Length = new PropertyOverride<IntRange>(_override: false, new IntRange(5, 10));

		public PropertyOverride<BranchMode> BranchMode = new PropertyOverride<BranchMode>(_override: false, (BranchMode)0);

		public PropertyOverride<IntRange> BranchCount = new PropertyOverride<IntRange>(_override: false, new IntRange(1, 5));

		public PropertyOverride<List<GraphNode>> Nodes = new PropertyOverride<List<GraphNode>>(_override: false, new List<GraphNode>());

		public PropertyOverride<List<GraphLine>> Lines = new PropertyOverride<List<GraphLine>>(_override: false, new List<GraphLine>());

		[Tooltip("Limits the amount of Global Props that can spawn on a single main path.\n\nThis does not afffect the global limit defined in DungeonFlow.")]
		public List<LocalGlobalPropSettings> LocalGroupProps = new List<LocalGlobalPropSettings>();

		[Header("DEV ONLY: DON'T TOUCH")]
		[ReadOnly]
		public string Version = "0";

		public static IntRange GetLength(MainPathExtender extender, DungeonFlow flow)
		{
			if (Object.op_Implicit((Object)(object)extender) && extender.Length.Override)
			{
				return extender.Length.Value;
			}
			return flow.Length;
		}

		public static BranchMode GetBranchMode(MainPathExtender extender, DungeonFlow flow)
		{
			//IL_002a: Unknown result type (might be due to invalid IL or missing references)
			//IL_002f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Unknown result type (might be due to invalid IL or missing references)
			//IL_0026: Unknown result type (might be due to invalid IL or missing references)
			//IL_0032: Unknown result type (might be due to invalid IL or missing references)
			if (Object.op_Implicit((Object)(object)extender) && extender.BranchMode.Override)
			{
				return extender.BranchMode.Value;
			}
			return flow.BranchMode;
		}

		public static IntRange GetBranchCount(MainPathExtender extender, DungeonFlow flow)
		{
			if (Object.op_Implicit((Object)(object)extender) && extender.BranchCount.Override)
			{
				return extender.BranchCount.Value;
			}
			return flow.BranchCount;
		}

		public static List<GraphNode> GetNodes(MainPathExtender extender, DungeonFlow flow)
		{
			if (Object.op_Implicit((Object)(object)extender) && extender.Nodes.Override)
			{
				return extender.Nodes.Value;
			}
			return flow.Nodes;
		}

		public static List<GraphLine> GetLines(MainPathExtender extender, DungeonFlow flow)
		{
			if (Object.op_Implicit((Object)(object)extender) && extender.Lines.Override)
			{
				return extender.Lines.Value;
			}
			return flow.Lines;
		}
	}
	internal class PluginConfig
	{
		public static ConfigEntry<bool> EnableDevDebugTools;

		public static void SetupConfig(ConfigFile cfg)
		{
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0027: Expected O, but got Unknown
			//IL_0027: Expected O, but got Unknown
			EnableDevDebugTools = cfg.Bind<bool>(new ConfigDefinition("Dev", "Enable Dev Debug Tools"), false, new ConfigDescription("If enabled, allows the dev debug tools to be usable in the ship.\n\nPress LeftAlt + M to activate.", (AcceptableValueBase)null, Array.Empty<object>()));
		}
	}
	[CreateAssetMenu(fileName = "DunGen Extender", menuName = "DunGenExtender/DunGen Extender", order = 1)]
	public class DunGenExtender : ScriptableObject
	{
		[Tooltip("DunGenExtender will only influence this DungeonFlow")]
		public DungeonFlow DungeonFlow;

		public DunGenExtenderProperties Properties = new DunGenExtenderProperties();

		public DunGenExtenderEvents Events = new DunGenExtenderEvents();

		[Header("DEV ONLY: DON'T TOUCH")]
		[ReadOnly]
		public string Version = CURRENT_VERSION;

		internal bool Active = true;

		public static readonly string CURRENT_VERSION = "1";

		public void OnValidate()
		{
			if (Version == "0")
			{
				Properties.AdditionalTilesProperties.CopyFrom(Properties.ForcedTilesProperties);
				Version = "1";
			}
		}
	}
	[BepInPlugin("dev.ladyalice.dungenplus", "Dungeon Generation Plus", "1.4.1")]
	[BepInDependency("imabatby.lethallevelloader", "1.4.1")]
	[BepInProcess("Lethal Company.exe")]
	public class Plugin : BaseUnityPlugin
	{
		internal const string modGUID = "dev.ladyalice.dungenplus";

		private const string modName = "Dungeon Generation Plus";

		private const string modVersion = "1.4.1";

		internal readonly Harmony Harmony = new Harmony("dev.ladyalice.dungenplus");

		internal static Dictionary<DungeonFlow, DunGenExtender> DunGenExtenders = new Dictionary<DungeonFlow, DunGenExtender>();

		internal static Plugin Instance { get; private set; }

		internal static ManualLogSource logger { get; private set; }

		private void Awake()
		{
			if ((Object)(object)Instance == (Object)null)
			{
				Instance = this;
			}
			logger = Logger.CreateLogSource("dev.ladyalice.dungenplus");
			logger.LogInfo((object)"Plugin Dungeon Generation Plus has been added!");
			PluginConfig.SetupConfig(((BaseUnityPlugin)this).Config);
			Harmony.PatchAll(typeof(DungeonGeneratorPatch));
			Harmony.PatchAll(typeof(DungeonPatch));
			Harmony.PatchAll(typeof(DungeonProxyPatch));
			Harmony.PatchAll(typeof(RoundManagerPatch));
			Harmony.PatchAll(typeof(BranchCountHelperPatch));
			Harmony.PatchAll(typeof(TileProxyPatch));
			Harmony.PatchAll(typeof(DoorwayPairFinderPatch));
			try
			{
				Harmony.PatchAll(typeof(LethalLevelLoaderPatches));
			}
			catch (Exception ex)
			{
				logger.LogError((object)"Failed to patch LLL for dev debug. You can ignore this.");
				logger.LogError((object)ex);
			}
			Assets.LoadAssets();
			Assets.LoadAssetBundle();
			DoorwayManager.onMainEntranceTeleportSpawnedEvent.AddEvent("DoorwayCleanup", DoorwayManager.OnMainEntranceTeleportSpawnedFunction);
		}
	}
}
namespace DunGenPlus.Utils
{
	internal class InjectionDictionary
	{
		public string name;

		public List<CodeInstruction> instructions;

		public CodeInstruction[] injections;

		private int counter;

		public InjectionDictionary(string name, MethodInfo methodInjection, params CodeInstruction[] instructions)
		{
			//IL_001e: Unknown result type (might be due to invalid IL or missing references)
			//IL_0024: Expected O, but got Unknown
			this.name = name;
			injections = (CodeInstruction[])(object)new CodeInstruction[1]
			{
				new CodeInstruction(OpCodes.Call, (object)methodInjection)
			};
			this.instructions = instructions.ToList();
		}

		public InjectionDictionary(string name, CodeInstruction[] codeInjections, params CodeInstruction[] instructions)
		{
			this.name = name;
			injections = codeInjections;
			this.instructions = instructions.ToList();
		}

		public void ResetCounter()
		{
			counter = 0;
		}

		public void AddCounter()
		{
			counter++;
		}

		public void Report(string debugFunction, int? expectedCounter)
		{
			if (counter == 0)
			{
				Plugin.logger.LogError((object)(debugFunction + " could not inject " + name + ". Probably scary"));
			}
			else if (!expectedCounter.HasValue)
			{
				Plugin.logger.LogDebug((object)$"{debugFunction} inject {name} {counter} time(s)");
			}
			else if (expectedCounter.Value != counter)
			{
				Plugin.logger.LogWarning((object)$"{debugFunction} inject {name} {counter} time(s) (Expected {expectedCounter.Value}). Probably not an error but be warned");
			}
		}
	}
	internal abstract class InstructionSequence
	{
		protected enum AdvanceResult
		{
			Failed,
			Advanced,
			Finished
		}

		protected List<Func<CodeInstruction, bool>> seq;

		protected string name;

		protected string extraErrorMessage;

		protected int stage;

		protected bool completed;

		protected bool single;

		public InstructionSequence(string name, bool single = true, string extraErrorMessage = null)
		{
			seq = new List<Func<CodeInstruction, bool>>();
			stage = 0;
			completed = false;
			this.name = name;
			this.single = single;
			this.extraErrorMessage = extraErrorMessage;
		}

		public void Add(Func<CodeInstruction, bool> next)
		{
			seq.Add(next);
		}

		public void AddBasic(OpCode opcode)
		{
			seq.Add((CodeInstruction i) => i.opcode == opcode);
		}

		public void AddBasic(OpCode opcode, object operand)
		{
			seq.Add((CodeInstruction i) => i.opcode == opcode && i.operand == operand);
		}

		public void AddBasicLocal(OpCode opcode, int operand)
		{
			seq.Add((CodeInstruction i) => i.opcode == opcode && (i.operand as LocalBuilder).LocalIndex == operand);
		}

		public void AddAny()
		{
			seq.Add(null);
		}

		public void AddOperandTypeCheck(OpCode opcode, Type operandType)
		{
			seq.Add(delegate(CodeInstruction i)
			{
				FieldInfo fieldInfo = i.operand as FieldInfo;
				return i.opcode == opcode && fieldInfo != null && fieldInfo.FieldType == operandType;
			});
		}

		public void AddBasicWithAlternateMethodName(OpCode opcode, object operand, string methodName)
		{
			seq.Add(delegate(CodeInstruction i)
			{
				if (i.opcode == opcode && i.operand == operand)
				{
					return true;
				}
				MethodInfo methodInfo = i.operand as MethodInfo;
				return (methodInfo != null && methodInfo.Name == methodName) ? true : false;
			});
		}

		public void AddSpecial(OpCode opcode, Func<CodeInstruction, bool> extra)
		{
			seq.Add((CodeInstruction i) => i.opcode == opcode && extra(i));
		}

		public void ReportComplete()
		{
			if (!completed)
			{
				string text = (string.IsNullOrWhiteSpace(extraErrorMessage) ? "BIG PROBLEM!" : extraErrorMessage);
				Plugin.logger.LogError((object)("HarmonyTranspiler for " + name + " has failed. " + text));
			}
		}

		protected AdvanceResult AdvanceStage(CodeInstruction current)
		{
			Func<CodeInstruction, bool> func = seq[stage];
			AdvanceResult advanceResult = AdvanceResult.Failed;
			if (func == null)
			{
				func = seq[stage + 1];
				if (func(current))
				{
					stage += 2;
				}
				advanceResult = AdvanceResult.Advanced;
			}
			else if (func(current))
			{
				stage++;
				advanceResult = AdvanceResult.Advanced;
			}
			else
			{
				stage = 0;
				advanceResult = AdvanceResult.Failed;
			}
			if (stage >= seq.Count)
			{
				if (completed && single)
				{
					throw new Exception("Found multiple valid " + name + " instructions");
				}
				stage = 0;
				completed = true;
				advanceResult = AdvanceResult.Finished;
			}
			return advanceResult;
		}
	}
	internal class InstructionSequenceStandard : InstructionSequence
	{
		public InstructionSequenceStandard(string name, bool single = true, string extraErrorMessage = null)
			: base(name, single, extraErrorMessage)
		{
		}

		public bool VerifyStage(CodeInstruction current)
		{
			return AdvanceStage(current) == AdvanceResult.Finished;
		}
	}
	internal class InstructionSequenceHold : InstructionSequence
	{
		public enum HoldResult
		{
			None,
			Hold,
			Release,
			Finished
		}

		public List<CodeInstruction> Instructions;

		private new List<Func<CodeInstruction, bool>> seq;

		private new string name;

		private new string extraErrorMessage;

		private new int stage = 0;

		private new bool completed = false;

		public InstructionSequenceHold(string name, bool single = true, string extraErrorMessage = null)
			: base(name, single, extraErrorMessage)
		{
			Instructions = new List<CodeInstruction>();
		}

		public HoldResult VerifyStage(CodeInstruction current)
		{
			switch (AdvanceStage(current))
			{
			case AdvanceResult.Failed:
				if (Instructions.Count > 0)
				{
					Instructions.Add(current);
					return HoldResult.Release;
				}
				return HoldResult.None;
			case AdvanceResult.Advanced:
				Instructions.Add(current);
				return HoldResult.Hold;
			default:
				Instructions.Add(current);
				return HoldResult.Finished;
			}
		}

		public void ClearInstructions()
		{
			Instructions.Clear();
		}
	}
	internal class TranspilerUtilities
	{
		public static IEnumerable<CodeInstruction> InjectMethod(IEnumerable<CodeInstruction> instructions, InjectionDictionary injection, string debugFunction, int? expectedCounter = null)
		{
			List<CodeInstruction> targets = injection.instructions;
			CodeInstruction[] codeInjections = injection.injections;
			injection.ResetCounter();
			foreach (CodeInstruction i in instructions)
			{
				foreach (CodeInstruction t in targets)
				{
					if (!(i.opcode == t.opcode) || i.operand != t.operand)
					{
						continue;
					}
					yield return i;
					CodeInstruction[] array = codeInjections;
					for (int j = 0; j < array.Length; j++)
					{
						yield return array[j];
					}
					injection.AddCounter();
					goto IL_0215;
				}
				yield return i;
				IL_0215:;
			}
			injection.Report(debugFunction, expectedCounter);
		}

		public static bool IsInstructionNearFloatValue(CodeInstruction instruction, float value)
		{
			return Mathf.Abs((float)instruction.operand - value) < 0.1f;
		}

		public static void PrintInstructions(IEnumerable<CodeInstruction> instructions)
		{
			foreach (CodeInstruction instruction in instructions)
			{
				PrintInstruction(instruction);
			}
		}

		public static void PrintInstruction(CodeInstruction inst)
		{
			string text = inst.opcode.ToString();
			string text2 = ((inst.operand != null) ? inst.operand.ToString() : "NULL");
			Plugin.logger.LogInfo((object)(text + ": " + text2));
		}
	}
	public class ActionList
	{
		public string name;

		public List<(string name, Action action)> actionList;

		public List<(string name, Action action)> temporaryActionList;

		public ActionList(string name)
		{
			this.name = name;
			actionList = new List<(string, Action)>();
			temporaryActionList = new List<(string, Action)>();
		}

		public void AddEvent(string name, Action act)
		{
			actionList.Add((name, act));
		}

		public void AddTemporaryEvent(string name, Action act)
		{
			temporaryActionList.Add((name, act));
		}

		public void Call()
		{
			foreach (var action in actionList)
			{
				try
				{
					action.action();
				}
				catch (Exception ex)
				{
					Plugin.logger.LogError((object)("Error with event " + name + "/" + action.name));
					Plugin.logger.LogError((object)ex.ToString());
				}
			}
			foreach (var temporaryAction in temporaryActionList)
			{
				try
				{
					temporaryAction.action();
				}
				catch (Exception ex2)
				{
					Plugin.logger.LogError((object)("Error with event " + name + "/" + temporaryAction.name));
					Plugin.logger.LogError((object)ex2.ToString());
				}
			}
			ClearTemporaryActionList();
		}

		public void ClearTemporaryActionList()
		{
			temporaryActionList.Clear();
		}
	}
	public static class Utility
	{
		public static void PrintLog(string message, LogLevel logLevel)
		{
			//IL_0041: Unknown result type (might be due to invalid IL or missing references)
			//IL_000b: Unknown result type (might be due to invalid IL or missing references)
			//IL_000c: Unknown result type (might be due to invalid IL or missing references)
			//IL_000d: Unknown result type (might be due to invalid IL or missing references)
			//IL_000e: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0011: Unknown result type (might be due to invalid IL or missing references)
			//IL_0013: Invalid comparison between Unknown and I4
			//IL_0017: Unknown result type (might be due to invalid IL or missing references)
			//IL_0019: Invalid comparison between Unknown and I4
			if (DunGenPlusScript.InDebugMode)
			{
				if (logLevel - 1 > 1)
				{
					if ((int)logLevel == 4)
					{
						Debug.LogWarning((object)message);
					}
					else
					{
						Debug.Log((object)message);
					}
				}
				else
				{
					Debug.LogError((object)message);
				}
			}
			else
			{
				Plugin.logger.Log(logLevel, (object)message);
			}
		}
	}
}
namespace DunGenPlus.Patches
{
	internal class BranchCountHelperPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(BranchCountHelper), "ComputeBranchCounts")]
		public static IEnumerable<CodeInstruction> ComputeBranchCountsPatch(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo branchModeField = typeof(DungeonFlow).GetField("BranchMode", BindingFlags.Instance | BindingFlags.Public);
			InstructionSequenceStandard branchSequence = new InstructionSequenceStandard("BranchMode", single: false);
			branchSequence.AddBasic(OpCodes.Ldfld, branchModeField);
			foreach (CodeInstruction instruction in instructions)
			{
				if (branchSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetBranchMode", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
				}
				else
				{
					yield return instruction;
				}
			}
			branchSequence.ReportComplete();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(BranchCountHelper), "ComputeBranchCountsGlobal")]
		public static IEnumerable<CodeInstruction> ComputeBranchCountsGlobalPatch(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo branchCountField = typeof(DungeonFlow).GetField("BranchCount", BindingFlags.Instance | BindingFlags.Public);
			InstructionSequenceStandard branchSequence = new InstructionSequenceStandard("BranchCount");
			branchSequence.AddBasic(OpCodes.Ldfld, branchCountField);
			foreach (CodeInstruction instruction in instructions)
			{
				if (branchSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetBranchCount", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
				}
				else
				{
					yield return instruction;
				}
			}
			branchSequence.ReportComplete();
		}
	}
	internal class DoorwayPairFinderPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(DoorwayPairFinder), "GetPotentialDoorwayPairsForNonFirstTile")]
		public static void GenerateBranchPathsPatch(ref DoorwayPairFinder __instance, ref IEnumerable<DoorwayPair> __result)
		{
			if (DunGenPlusGenerator.Active)
			{
				__result = DunGenPlusGenerator.GetPotentialDoorwayPairsForNonFirstTileAlternate(__instance);
			}
		}
	}
	internal class DungeonPatch
	{
		[HarmonyTranspiler]
		[HarmonyPatch(typeof(Dungeon), "FromProxy")]
		public static IEnumerable<CodeInstruction> FromProxyPatch(IEnumerable<CodeInstruction> instructions)
		{
			InstructionSequenceStandard endSequence = new InstructionSequenceStandard("Forloop End");
			endSequence.AddBasicLocal(OpCodes.Ldloca_S, 1);
			endSequence.AddBasic(OpCodes.Constrained);
			endSequence.AddBasic(OpCodes.Callvirt);
			endSequence.AddBasic(OpCodes.Endfinally);
			foreach (CodeInstruction instruction in instructions)
			{
				if (endSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("AddTileToMainPathDictionary", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Ldloc_0, (object)null);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
				}
				yield return instruction;
			}
			endSequence.ReportComplete();
		}
	}
	internal class TileProxyPatch
	{
		public static Dictionary<TileProxy, TileExtenderProxy> TileExtenderProxyDictionary = new Dictionary<TileProxy, TileExtenderProxy>();

		public static void ResetDictionary()
		{
			TileExtenderProxyDictionary.Clear();
		}

		public static TileExtenderProxy GetTileExtenderProxy(TileProxy proxy)
		{
			return TileExtenderProxyDictionary[proxy];
		}

		public static void AddTileExtenderProxy(TileProxy tileProxy, TileExtenderProxy tileExtenderProxy)
		{
			TileExtenderProxyDictionary.Add(tileProxy, tileExtenderProxy);
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void TileProxyConstructorNewPatch(ref TileProxy __instance)
		{
			AddTileExtenderProxy(__instance, new TileExtenderProxy(__instance));
		}

		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		[HarmonyPostfix]
		public static void TileProxyConstructorExistingPatch(ref TileProxy __instance, TileProxy existingTile)
		{
			AddTileExtenderProxy(__instance, new TileExtenderProxy(__instance, GetTileExtenderProxy(existingTile)));
		}
	}
	internal class DungeonProxyPatch
	{
		[HarmonyPatch(typeof(DungeonProxy), "ConnectOverlappingDoorways")]
		[HarmonyPrefix]
		public static void ConnectOverlappingDoorwaysPrePatch(ref DungeonProxy __instance)
		{
			IEnumerable<DoorwayProxy> list = __instance.AllTiles.SelectMany((TileProxy t) => t.Doorways);
			DoorwaySistersRule.UpdateCache(list);
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(DungeonProxy), "ConnectOverlappingDoorways")]
		public static IEnumerable<CodeInstruction> ConnectOverlappingDoorwaysPatch(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo callFunction = typeof(DungeonFlow).GetMethod("CanDoorwaysConnect", BindingFlags.Instance | BindingFlags.Public);
			InstructionSequenceStandard sequence = new InstructionSequenceStandard("doorway connect", single: false);
			sequence.AddBasic(OpCodes.Callvirt, callFunction);
			sequence.AddBasic(OpCodes.Brfalse);
			foreach (CodeInstruction instruction in instructions)
			{
				if (sequence.VerifyStage(instruction))
				{
					MethodInfo method = typeof(DoorwaySistersRule).GetMethod("CanDoorwaysConnect", BindingFlags.Static | BindingFlags.Public);
					MethodInfo getTileProxy = typeof(DoorwayProxy).GetMethod("get_TileProxy", BindingFlags.Instance | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
					yield return new CodeInstruction(OpCodes.Callvirt, (object)getTileProxy);
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)4);
					yield return new CodeInstruction(OpCodes.Callvirt, (object)getTileProxy);
					yield return new CodeInstruction(OpCodes.Ldloc_2, (object)null);
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)4);
					yield return new CodeInstruction(OpCodes.Call, (object)method);
					yield return instruction;
				}
				else
				{
					yield return instruction;
				}
			}
			sequence.ReportComplete();
		}
	}
	internal class DungeonGeneratorPatch
	{
		public static TileProxy lastAttachTo;

		public static IEnumerable<TileSet> lastUseableTileSets;

		public static float lastNormalizedDepth;

		public static DungeonArchetype lastArchetype;

		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(DungeonGenerator), "Generate")]
		[HarmonyPrefix]
		public static void GeneratePatch(ref DungeonGenerator __instance)
		{
			DunGenPlusGenerator.Deactivate();
			DungeonFlow dungeonFlow = __instance.DungeonFlow;
			DunGenExtender dunGenExtender = API.GetDunGenExtender(dungeonFlow);
			if (Object.op_Implicit((Object)(object)dunGenExtender) && dunGenExtender.Active)
			{
				Plugin.logger.LogInfo((object)("Loading DunGenExtender for " + ((Object)dungeonFlow).name));
				DunGenPlusGenerator.Activate(__instance, dunGenExtender);
			}
			else
			{
				Plugin.logger.LogInfo((object)"Did not load a DunGenExtenderer");
				DunGenPlusGenerator.Deactivate();
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DungeonGenerator), "InnerGenerate")]
		public static void InnerGeneratePatch(ref DungeonGenerator __instance, bool isRetry)
		{
			if (API.IsDevDebugModeActive() && !isRetry)
			{
				DevDebugManager.Instance.RecordNewSeed(__instance.ChosenSeed);
			}
			if (DunGenPlusGenerator.Active && DunGenPlusGenerator.ActiveAlternative)
			{
				TileProxyPatch.ResetDictionary();
				DunGenPlusGenerator.SetCurrentMainPathExtender(0);
				MainRoomDoorwayGroups.ModifyGroupBasedOnBehaviourSimpleOnce = false;
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath")]
		public static void GenerateMainPathPatch(ref DungeonGenerator __instance)
		{
			if (DunGenPlusGenerator.Active && DunGenPlusGenerator.ActiveAlternative)
			{
				DunGenPlusGenerator.RandomizeLineArchetypes(__instance, randomizeMainPath: true);
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DungeonGenerator), "GenerateBranchPaths")]
		public static void GenerateBranchPathsPatch(ref DungeonGenerator __instance, ref IEnumerator __result)
		{
			if (DunGenPlusGenerator.Active && DunGenPlusGenerator.ActiveAlternative)
			{
				__result = DunGenPlusGenerator.GenerateAlternativeMainPaths(__instance);
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static IEnumerable<CodeInstruction> GenerateMainPathPatch(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo addArchFunction = typeof(List<DungeonArchetype>).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);
			InstructionSequenceStandard archSequence = new InstructionSequenceStandard("archetype node");
			archSequence.AddOperandTypeCheck(OpCodes.Ldfld, typeof(List<DungeonArchetype>));
			archSequence.AddBasic(OpCodes.Ldnull);
			archSequence.AddBasic(OpCodes.Callvirt, addArchFunction);
			InstructionSequenceStandard attachToSequence = new InstructionSequenceStandard("attach to");
			attachToSequence.AddBasicLocal(OpCodes.Stloc_S, 13);
			foreach (CodeInstruction instruction in instructions)
			{
				if (archSequence.VerifyStage(instruction))
				{
					MethodInfo randomStreamMethod = typeof(DungeonGenerator).GetMethod("get_RandomStream", BindingFlags.Instance | BindingFlags.Public);
					MethodInfo modifyMethod2 = typeof(DunGenPlusGenerator).GetMethod("ModifyMainBranchNodeArchetype", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)8);
					yield return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
					yield return new CodeInstruction(OpCodes.Call, (object)randomStreamMethod);
					yield return new CodeInstruction(OpCodes.Call, (object)modifyMethod2);
					yield return instruction;
				}
				else if (attachToSequence.VerifyStage(instruction))
				{
					yield return instruction;
					MethodInfo modifyMethod = typeof(MainRoomDoorwayGroups).GetMethod("ModifyGroupBasedOnBehaviourSimple", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)13);
					yield return new CodeInstruction(OpCodes.Call, (object)modifyMethod);
				}
				else
				{
					yield return instruction;
				}
			}
			archSequence.ReportComplete();
			attachToSequence.ReportComplete();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static IEnumerable<CodeInstruction> GenerateMainPathGetLineAtDepthPatch(IEnumerable<CodeInstruction> instructions)
		{
			MethodInfo getLineFunction = typeof(DungeonFlow).GetMethod("GetLineAtDepth", BindingFlags.Instance | BindingFlags.Public);
			FieldInfo nodesField = typeof(DungeonFlow).GetField("Nodes", BindingFlags.Instance | BindingFlags.Public);
			InstructionSequenceStandard lineSequence = new InstructionSequenceStandard("GetLineAtDepth");
			lineSequence.AddBasic(OpCodes.Callvirt, getLineFunction);
			InstructionSequenceStandard nodesSequence = new InstructionSequenceStandard("Nodes", single: false);
			nodesSequence.AddBasic(OpCodes.Ldfld, nodesField);
			foreach (CodeInstruction instruction in instructions)
			{
				if (lineSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction2 = typeof(DunGenPlusGenerator).GetMethod("GetLineAtDepth", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction2);
				}
				else if (nodesSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("GetNodes", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
				}
				else
				{
					yield return instruction;
				}
			}
			lineSequence.ReportComplete();
			nodesSequence.ReportComplete();
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static IEnumerable<CodeInstruction> InnerGenerateLengthPatch(IEnumerable<CodeInstruction> instructions)
		{
			FieldInfo lengthField = typeof(DungeonFlow).GetField("Length", BindingFlags.Instance | BindingFlags.Public);
			MethodInfo getIsEditor = typeof(Application).GetMethod("get_isEditor", BindingFlags.Static | BindingFlags.Public);
			InstructionSequenceStandard lengthSequence = new InstructionSequenceStandard("Length");
			lengthSequence.AddBasic(OpCodes.Ldfld, lengthField);
			InstructionSequenceStandard editorCheck = new InstructionSequenceStandard("Editor");
			editorCheck.AddBasic(OpCodes.Call, getIsEditor);
			foreach (CodeInstruction instruction in instructions)
			{
				if (lengthSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction2 = typeof(DunGenPlusGenerator).GetMethod("GetLength", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction2);
				}
				else if (editorCheck.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("AllowRetryStop", BindingFlags.Static | BindingFlags.Public);
					yield return instruction;
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
				}
				else
				{
					yield return instruction;
				}
			}
			lengthSequence.ReportComplete();
			editorCheck.ReportComplete();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(DungeonGenerator), "PostProcess")]
		public static void GenerateBranchPathsPatch(ref DungeonGenerator __instance)
		{
			if (DunGenPlusGenerator.Active)
			{
				int value = __instance.RandomStream.Next(999);
				SpawnSyncedObjectCycle.UpdateCycle(value);
			}
		}

		[HarmonyTranspiler]
		[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]
		public static IEnumerable<CodeInstruction> AddTileDebugPatch(IEnumerable<CodeInstruction> instructions)
		{
			InstructionSequenceStandard addTileSequence = new InstructionSequenceStandard("Add Tile Placement");
			addTileSequence.AddBasic(OpCodes.Callvirt);
			addTileSequence.AddBasic(OpCodes.Ldc_I4_0);
			addTileSequence.AddBasic(OpCodes.Bgt);
			addTileSequence.AddBasicLocal(OpCodes.Ldloc_S, 9);
			foreach (CodeInstruction instruction in instructions)
			{
				if (addTileSequence.VerifyStage(instruction))
				{
					MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("RecordLastTilePlacementResult", BindingFlags.Static | BindingFlags.Public);
					yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
					yield return new CodeInstruction(OpCodes.Ldloc_S, (object)9);
					yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
					yield return instruction;
				}
				else
				{
					yield return instruction;
				}
			}
			addTileSequence.ReportComplete();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(DungeonGenerator), "ProcessGlobalProps")]
		public static bool ProcessGlobalPropsPatch(ref DungeonGenerator __instance)
		{
			if (DunGenPlusGenerator.Active)
			{
				bool flag = DunGenPlusGenerator.Properties.MainPathProperties.DetailedGlobalPropSettings.Count > 0;
				bool flag2 = DunGenPlusGenerator.Properties.MainPathProperties.MainPathDetails.Any((MainPathExtender d) => d.LocalGroupProps.Count > 0);
				if (flag || flag2)
				{
					Plugin.logger.LogDebug((object)"Performing Local Global Props algorithm");
					DunGenPlusGenerator.ProcessGlobalPropsPerMainPath(__instance);
					return false;
				}
			}
			return true;
		}

		[HarmonyTranspiler]
		[HarmonyPatch(/*Could not decode attribute arguments.*/)]
		public static IEnumerable<CodeInstruction> GenerateMainPathDebugPatch(IEnumerable<CodeInstruction> instructions)
		{
			InstructionSequenceStandard tileProxyNullSequence = new InstructionSequenceStandard("TileProxyNull");
			tileProxyNullSequence.AddBasic(OpCodes.Br);
			tileProxyNullSequence.AddBasicLocal(OpCodes.Ldloc_S, 14);
			tileProxyNullSequence.AddBasic(OpCodes.Brtrue);
			FieldInfo indexField = null;
			foreach (CodeInstruction instruction in instructions)
			{
				object operand = instruction.operand;
				FieldInfo field = operand as FieldInfo;
				if (field?.Name.StartsWith("<j>") ?? false)
				{
					indexField = field;
				}
				if (tileProxyNullSequence.VerifyStage(instruction))
				{
					yield return instruction;
					if (indexField != null)
					{
						MethodInfo specialFunction = typeof(DunGenPlusGenerator).GetMethod("PrintAddTileErrorQuick", BindingFlags.Static | BindingFlags.Public);
						yield return new CodeInstruction(OpCodes.Ldloc_1, (object)null);
						yield return new CodeInstruction(OpCodes.Ldarg_0, (object)null);
						yield return new CodeInstruction(OpCodes.Ldfld, (object)indexField);
						yield return new CodeInstruction(OpCodes.Call, (object)specialFunction);
					}
					else
					{
						Plugin.logger.LogWarning((object)"Failed to find current tile index field in the main path enumerator");
					}
				}
				else
				{
					yield return instruction;
				}
			}
			tileProxyNullSequence.ReportComplete();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]
		public static void AddTileDebugPatch(TileProxy attachTo, IEnumerable<TileSet> useableTileSets, float normalizedDepth, DungeonArchetype archetype)
		{
			lastAttachTo = attachTo;
			lastUseableTileSets = useableTileSets;
			lastNormalizedDepth = normalizedDepth;
			lastArchetype = archetype;
		}
	}
	internal class LethalLevelLoaderPatches
	{
		[HarmonyPrefix]
		[HarmonyPatch(typeof(Patches), "DungeonGeneratorGenerate_Prefix")]
		public static bool DungeonGeneratorGenerate_Prefix_Patches_Prefix()
		{
			return (Object)(object)DevDebugManager.Instance == (Object)null;
		}

		[HarmonyPatch(typeof(EventPatches), "DungeonGeneratorGenerate_Prefix")]
		[HarmonyPrefix]
		public static void DungeonGeneratorGenerate_Prefix_EventPatches_Prefix()
		{
			ScrapItemManager.Initialize(Patches.RoundManager);
			EnemyManager.Initialize(Patches.RoundManager);
		}
	}
	internal class RoundManagerPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundManager), "FinishGeneratingLevel")]
		public static void GenerateBranchPathsPatch()
		{
			if (DunGenPlusGenerator.Active)
			{
				Plugin.logger.LogDebug((object)"Alt. InnerGenerate() function complete");
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundManager), "SetPowerOffAtStart")]
		public static void SetPowerOffAtStartPatch()
		{
			DoorwayManager.onMainEntranceTeleportSpawnedEvent.Call();
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundManager), "Awake")]
		public static void AwakePatch()
		{
			//IL_0028: Unknown result type (might be due to invalid IL or missing references)
			//IL_002e: Expected O, but got Unknown
			if (PluginConfig.EnableDevDebugTools.Value)
			{
				GameObject val = new GameObject("DevDebugOpen", new Type[1] { typeof(DevDebugOpen) });
			}
		}

		[HarmonyPostfix]
		[HarmonyPatch(typeof(RoundManager), "Start")]
		public static void StartPatch(ref RoundManager __instance)
		{
			ScrapItemManager.UndoPreviousChanges();
			EnemyManager.UndoPreviousChanges();
		}

		[HarmonyPrefix]
		[HarmonyPatch(typeof(RoundManager), "waitForScrapToSpawnToSync")]
		public static void waitForScrapToSpawnToSyncPatch(ref RoundManager __instance, ref NetworkObjectReference[] spawnedScrap, ref int[] scrapValues)
		{
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			if (!DunGenPlusGenerator.Active || !DunGenPlusGenerator.Properties.MiscellaneousProperties.UseRandomGuaranteedScrapSpawn)
			{
				return;
			}
			List<NetworkObjectReference> list = spawnedScrap.ToList();
			List<int> list2 = scrapValues.ToList();
			RandomGuaranteedScrapSpawn[] array = Object.FindObjectsOfType<RandomGuaranteedScrapSpawn>();
			RandomGuaranteedScrapSpawn.ResetCache();
			RandomGuaranteedScrapSpawn[] array2 = array;
			foreach (RandomGuaranteedScrapSpawn randomGuaranteedScrapSpawn in array2)
			{
				(NetworkObject, int) tuple = randomGuaranteedScrapSpawn.CreateItem(__instance, __instance.currentLevel.spawnableScrap);
				if ((Object)(object)tuple.Item1 != (Object)null)
				{
					Plugin.logger.LogDebug((object)$"Created guaranteed item {((Object)((Component)tuple.Item1).gameObject).name} w/ value {tuple.Item2}");
					list.Add(NetworkObjectReference.op_Implicit(tuple.Item1));
					list2.Add(tuple.Item2);
				}
			}
			spawnedScrap = list.ToArray();
			scrapValues = list2.ToArray();
		}

		[HarmonyPrefix]
		[HarmonyPriority(800)]
		[HarmonyPatch(typeof(RoundManager), "SetLevelObjectVariables")]
		public static void SetLevelObjectVariablesPatch(ref RoundManager __instance)
		{
			DoorwayManager.SetLevelObjectVariablesFunction();
		}
	}
	internal class StartOfRoundPatch
	{
	}
}
namespace DunGenPlus.Managers
{
	public static class EnemyManager
	{
		internal static SelectableLevel previousLevel;

		internal static List<SpawnableEnemyWithRarity> previouslyAddedEnemies = new List<SpawnableEnemyWithRarity>();

		internal static List<SpawnableEnemyWithRarity> previouslyModifiedEnemies = new List<SpawnableEnemyWithRarity>();

		internal static void UndoPreviousChanges()
		{
			if (!((Object)(object)previousLevel != (Object)null))
			{
				return;
			}
			Plugin.logger.LogDebug((object)("Undoing changes of EnemyManager for " + previousLevel.PlanetName));
			List<SpawnableEnemyWithRarity> enemies = previousLevel.Enemies;
			if (previouslyAddedEnemies.Count > 0)
			{
				for (int num = previouslyAddedEnemies.Count - 1; num >= 0; num--)
				{
					SpawnableEnemyWithRarity val = previouslyAddedEnemies[num];
					int num2 = enemies.Count - 1;
					while (true)
					{
						if (num2 >= 0)
						{
							SpawnableEnemyWithRarity val2 = enemies[num2];
							if (val2 == val)
							{
								enemies.RemoveAt(num2);
								Plugin.logger.LogDebug((object)("Properly removed temporary enemy " + val.enemyType.enemyName));
								break;
							}
							num2--;
							continue;
						}
						Plugin.logger.LogWarning((object)("Couldn't find/remove temporary enemy " + val.enemyType.enemyName));
						break;
					}
				}
				previouslyAddedEnemies.Clear();
			}
			if (previouslyModifiedEnemies.Count > 0)
			{
				for (int i = 0; i < previouslyModifiedEnemies.Count; i++)
				{
					SpawnableEnemyWithRarity val3 = previouslyModifiedEnemies[i];
					int num3 = 0;
					while (true)
					{
						if (num3 < enemies.Count)
						{
							if ((Object)(object)enemies[num3].enemyType == (Object)(object)val3.enemyType)
							{
								enemies[num3] = val3;
								Plugin.logger.LogDebug((object)("Properly fixed modified enemy " + val3.enemyType.enemyName));
								break;
							}
							num3++;
							continue;
						}
						Plugin.logger.LogWarning((object)("Couldn't find/fix modified enemy " + val3.enemyType.enemyName));
						break;
					}
				}
				previouslyModifiedEnemies.Clear();
			}
			previousLevel = null;
		}

		internal static void Initialize(RoundManager roundManager)
		{
			UndoPreviousChanges();
			previousLevel = roundManager.currentLevel;
			Plugin.logger.LogDebug((object)("Initialized EnemyManager to " + previousLevel.PlanetName));
		}

		public static void AddEnemies(IEnumerable<SpawnableEnemyWithRarity> newEnemies)
		{
			foreach (SpawnableEnemyWithRarity newEnemy in newEnemies)
			{
				AddEnemy(newEnemy);
			}
		}

		public static void AddEnemy(SpawnableEnemyWithRarity newEnemy)
		{
			List<SpawnableEnemyWithRarity> enemies = previousLevel.Enemies;
			for (int i = 0; i < enemies.Count; i++)
			{
				if ((Object)(object)enemies[i].enemyType == (Object)(object)newEnemy.enemyType)
				{
					if (enemies[i].rarity == newEnemy.rarity)
					{
						Plugin.logger.LogDebug((object)("Skipping " + newEnemy.enemyType.enemyName + " as it has the same rarity"));
						return;
					}
					previouslyModifiedEnemies.Add(enemies[i]);
					enemies[i] = newEnemy;
					Plugin.logger.LogDebug((object)$"Modifying already existing enemy {newEnemy.enemyType.enemyName} to new weight {newEnemy.rarity}");
					return;
				}
			}
			previouslyAddedEnemies.Add(newEnemy);
			enemies.Add(newEnemy);
			Plugin.logger.LogDebug((object)$"Adding temporary enemy {newEnemy.enemyType.enemyName} with weight {newEnemy.rarity}");
		}
	}
	public static class ScrapItemManager
	{
		internal static SelectableLevel previousLevel;

		internal static List<SpawnableItemWithRarity> previouslyAddedItems = new List<SpawnableItemWithRarity>();

		internal static List<SpawnableItemWithRarity> previouslyModifiedItems = new List<SpawnableItemWithRarity>();

		internal static void UndoPreviousChanges()
		{
			if (!((Object)(object)previousLevel != (Object)null))
			{
				return;
			}
			Plugin.logger.LogDebug((object)("Undoing changes of ScrapItemManager for " + previousLevel.PlanetName));
			List<SpawnableItemWithRarity> spawnableScrap = previousLevel.spawnableScrap;
			if (previouslyAddedItems.Count > 0)
			{
				for (int num = previouslyAddedItems.Count - 1; num >= 0; num--)
				{
					SpawnableItemWithRarity val = previouslyAddedItems[num];
					int num2 = spawnableScrap.Count - 1;
					while (true)
					{
						if (num2 >= 0)
						{
							SpawnableItemWithRarity val2 = spawnableScrap[num2];
							if (val2 == val)
							{
								spawnableScrap.RemoveAt(num2);
								Plugin.logger.LogDebug((object)("Properly removed temporary item " + val.spawnableItem.itemName));
								break;
							}
							num2--;
							continue;
						}
						Plugin.logger.LogWarning((object)("Couldn't find/remove temporary item " + val.spawnableItem.itemName));
						break;
					}
				}
				previouslyAddedItems.Clear();
			}
			if (previouslyModifiedItems.Count > 0)
			{
				for (int i = 0; i < previouslyModifiedItems.Count; i++)
				{
					SpawnableItemWithRarity val3 = previouslyModifiedItems[i];
					int num3 = 0;
					while (true)
					{
						if (num3 < spawnableScrap.Count)
						{
							if ((Object)(object)spawnableScrap[num3].spawnableItem == (Object)(object)val3.spawnableItem)
							{
								spawnableScrap[num3] = val3;
								Plugin.logger.LogDebug((object)("Properly fixed modified item " + val3.spawnableItem.itemName));
								break;
							}
							num3++;
							continue;
						}
						Plugin.logger.LogWarning((object)("Couldn't find/fix modified item " + val3.spawnableItem.itemName));
						break;
					}
				}
				previouslyModifiedItems.Clear();
			}
			previousLevel = null;
		}

		internal static void Initialize(RoundManager roundManager)
		{
			UndoPreviousChanges();
			previousLevel = roundManager.currentLevel;
			Plugin.logger.LogDebug((object)("Initialized ScrapItemManager to " + previousLevel.PlanetName));
		}

		public static void AddItems(IEnumerable<SpawnableItemWithRarity> newItems)
		{
			foreach (SpawnableItemWithRarity newItem in newItems)
			{
				AddItem(newItem);
			}
		}

		public static void AddItem(SpawnableItemWithRarity newItem)
		{
			List<SpawnableItemWithRarity> spawnableScrap = previousLevel.spawnableScrap;
			for (int i = 0; i < spawnableScrap.Count; i++)
			{
				if ((Object)(object)spawnableScrap[i].spawnableItem == (Object)(object)newItem.spawnableItem)
				{
					if (spawnableScrap[i].rarity == newItem.rarity)
					{
						Plugin.logger.LogDebug((object)("Skipping " + newItem.spawnableItem.itemName + " as it has the same rarity"));
						return;
					}
					previouslyModifiedItems.Add(spawnableScrap[i]);
					spawnableScrap[i] = newItem;
					Plugin.logger.LogDebug((object)$"Modifying already existing item {newItem.spawnableItem.itemName} to new weight {newItem.rarity}");
					return;
				}
			}
			previouslyAddedItems.Add(newItem);
			spawnableScrap.Add(newItem);
			Plugin.logger.LogDebug((object)$"Adding temporary item {newItem.spawnableItem.itemName} with weight {newItem.rarity}");
		}
	}
	public static class DoorwayManager
	{
		public class Scripts
		{
			public List<IDunGenScriptingParent> scriptList;

			public List<Action> actionList;

			public Scripts()
			{
				scriptList = new List<IDunGenScriptingParent>();
				actionList = new List<Action>();
			}

			public void Add(IDunGenScriptingParent script)
			{
				scriptList.Add(script);
			}

			public void Add(Action action)
			{
				actionList.Add(action);
			}

			public bool Call()
			{
				foreach (IDunGenScriptingParent script in scriptList)
				{
					script.Call();
				}
				foreach (Action action in actionList)
				{
					action();
				}
				return scriptList.Count + actionList.Count > 0;
			}
		}

		public static ActionList onMainEntranceTeleportSpawnedEvent = new ActionList("onMainEntranceTeleportSpawned");

		public static Dictionary<DunGenScriptingHook, Scripts> scriptingLists;

		public static void ResetList()
		{
			scriptingLists = new Dictionary<DunGenScriptingHook, Scripts>();
			foreach (DunGenScriptingHook value in Enum.GetValues(typeof(DunGenScriptingHook)))
			{
				scriptingLists.Add(value, new Scripts());
			}
		}

		public static void AddDunGenScriptHook(IDunGenScriptingParent script)
		{
			scriptingLists[script.GetScriptingHook].Add(script);
		}

		public static void AddActionHook(DunGenScriptingHook hook, Action action)
		{
			scriptingLists[hook].Add(action);
		}

		public static void OnMainEntranceTeleportSpawnedFunction()
		{
			if (!DunGenPlusGenerator.Active)
			{
				return;
			}
			bool flag = false;
			foreach (Scripts value in scriptingLists.Values)
			{
				flag |= value.Call();
			}
			if (flag)
			{
				try
				{
					RuntimeDungeon dungeonGenerator = RoundManager.Instance.dungeonGenerator;
					UnityNavMeshAdapter componentInChildren = ((Component)((Component)dungeonGenerator).transform.parent).GetComponentInChildren<UnityNavMeshAdapter>();
					((BaseAdapter)componentInChildren).Run(dungeonGenerator.Generator);
					Plugin.logger.LogDebug((object)"Rebuild nav mesh");
				}
				catch (Exception ex)
				{
					Plugin.logger.LogError((object)"Failed to rebuild nav mesh");
					Plugin.logger.LogError((object)ex.ToString());
				}
			}
		}

		public static void SetLevelObjectVariablesFunction()
		{
			if (DunGenPlusGenerator.Active)
			{
				scriptingLists[DunGenScriptingHook.SetLevelObjectVariables].Call();
			}
		}
	}
}
namespace DunGenPlus.Generation
{
	internal class DunGenPlusGenerator
	{
		private class BranchPathProxy
		{
			public TileProxy mainPathTile;

			public int mainPathIndex;

			public List<TilePlacementResultProxy> list;

			public float weight;

			public Dictionary<TileProxy, InjectedTile> injectedTiles;

			public List<InjectedTile> tilesPendingInjection;

			public BranchPathProxy(DungeonGenerator gen, TileProxy attachTileProxy)
			{
				mainPathTile = attachTileProxy;
				mainPathIndex = GetMainPathIndexFromTileProxy(attachTileProxy);
				list = new List<TilePlacementResultProxy>();
				weight = 0f;
				injectedTiles = new Dictionary<TileProxy, InjectedTile>(gen.injectedTiles);
				tilesPendingInjection = new List<InjectedTile>(gen.tilesPendingInjection);
			}

			public void CalculateWeight(DungeonGenerator gen)
			{
				//IL_0177: Unknown result type (might be due to invalid IL or missing references)
				//IL_017e: Unknown result type (might be due to invalid IL or missing references)
				//IL_0183: Unknown result type (might be due to invalid IL or missing references)
				int count = list.Count;
				if (count == 0)
				{
					return;
				}
				TilePlacementResultProxy tilePlacementResultProxy = list[count - 1];
				BranchPathMultiSimulationProperties branchPathMultiSimulationProperties = Properties.BranchPathMultiSimulationProperties;
				int branchDepth = tilePlacementResultProxy.tileProxy.Placement.BranchDepth;
				float normalizedBranchDepth = tilePlacementResultProxy.tileProxy.Placement.NormalizedBranchDepth;
				weight += branchPathMultiSimulationProperties.GetWeightBase(branchDepth, normalizedBranchDepth);
				IEnumerable<DoorwayProxy> enumerable = gen.proxyDungeon.AllTiles.SelectMany((TileProxy t) => t.Doorways);
				foreach (TilePlacementResultProxy item in list)
				{
					foreach (DoorwayProxy item2 in enumerable)
					{
						if (item2.TileProxy == mainPathTile)
						{
							continue;
						}
						int mainPathIndexFromTileProxy = GetMainPathIndexFromTileProxy(item2.TileProxy);
						foreach (DoorwayProxy doorway in item.tileProxy.doorways)
						{
							if (item2.TileProxy != item.previousDoorway.TileProxy && gen.DungeonFlow.CanDoorwaysConnect(item2.TileProxy.PrefabTile, doorway.TileProxy.PrefabTile, item2.DoorwayComponent, doorway.DoorwayComponent) && (double)Vector3.SqrMagnitude(item2.Position - doorway.Position) < 1E-05)
							{
								int num = Mathf.Abs(item2.TileProxy.Placement.PathDepth - doorway.TileProxy.Placement.PathDepth);
								float normalizedDepthDifference = Mathf.Abs(item2.TileProxy.Placement.NormalizedPathDepth - doorway.TileProxy.Placement.NormalizedPathDepth);
								bool samePath = mainPathIndex == mainPathIndexFromTileProxy;
								weight += branchPathMultiSimulationProperties.GetWeightPathConnection(samePath, num, normalizedDepthDifference);
							}
						}
					}
				}
			}
		}

		private class TilePlacementResultProxy
		{
			public TilePlacementResult result;

			public TileProxy tileProxy;

			public DoorwayProxy previousDoorway;

			public DoorwayProxy nextDoorway;

			public TilePlacementResultProxy(TilePlacementResult result)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				this.result = result;
				tileProxy = null;
				previousDoorway = null;
				nextDoorway = null;
			}

			public TilePlacementResultProxy(TilePlacementResult result, TileProxy tile, DoorwayProxy previousDoorway, DoorwayProxy nextDoorway)
			{
				//IL_0009: Unknown result type (might be due to invalid IL or missing references)
				//IL_000a: Unknown result type (might be due to invalid IL or missing references)
				this.result = result;
				tileProxy = tile;
				this.previousDoorway = previousDoorway;
				this.nextDoorway = nextDoorway;
			}
		}

		[StructLayout(LayoutKind.Auto)]
		[CompilerGenerated]
		private struct <>c__DisplayClass66_0
		{
			public DoorwayProxy nextDoor;
		}

		public static MainPathExtender currentMainPathExtender;

		public static TilePlacementResult lastTilePlacementResult;

		internal static HDRenderPipelineAsset previousHDRPAsset;

		internal static HDRenderPipelineAsset newHDRPAsset;

		private static Dictionary<TileProxy, int> tileProxyMainPath = new Dictionary<TileProxy, int>();

		private static Dictionary<Tile, int> tileMainPath = new Dictionary<Tile, int>();

		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;

		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; }

		public static void SetCurrentMainPathExtender(int mainPathIndex)
		{
			currentMainPathExtender = Properties.MainPathProperties.GetMainPathDetails(mainPathIndex);
		}

		public static GraphLine GetLineAtDepth(DungeonFlow flow, float depth)
		{
			if (!Active)
			{
				return flow.GetLineAtDepth(depth);
			}
			List<GraphLine> lines = MainPathExtender.GetLines(currentMainPathExtender, flow);
			return GetLineAtDepthHelper(lines, depth);
		}

		public static GraphLine GetLineAtDepthHelper(List<GraphLine> graphLines, float normalizedDepth)
		{
			normalizedDepth = Mathf.Clamp(normalizedDepth, 0f, 1f);
			if (normalizedDepth == 0f)
			{
				return graphLines[0];
			}
			if (normalizedDepth == 1f)
			{
				return graphLines[graphLines.Count - 1];
			}
			foreach (GraphLine graphLine in graphLines)
			{
				if (normalizedDepth >= graphLine.Position && normalizedDepth < graphLine.Position + graphLine.Length)
				{
					return graphLine;
				}
			}
			Debug.LogError((object)("GetLineAtDepth was unable to find a line at depth " + normalizedDepth + ". This shouldn't happen."));
			return null;
		}

		public static List<GraphNode> GetNodes(DungeonFlow flow)
		{
			if (!Active)
			{
				return flow.Nodes;
			}
			return MainPathExtender.GetNodes(currentMainPathExtender, flow);
		}

		public static BranchMode GetBranchMode(DungeonFlow flow)
		{
			//IL_001d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_000f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0014: Unknown result type (might be due to invalid IL or missing references)
			//IL_0025: Unknown result type (might be due to invalid IL or missing references)
			if (!Active)
			{
				return flow.BranchMode;
			}
			return MainPathExtender.GetBranchMode(currentMainPathExtender, flow);
		}

		public static IntRange GetBranchCount(DungeonFlow flow)
		{
			if (!Active)
			{
				return flow.BranchCount;
			}
			return MainPathExtender.GetBranchCount(currentMainPathExtender, flow);
		}

		public static IntRange GetLength(DungeonFlow flow)
		{
			if (!Active)
			{
				return flow.Length;
			}
			return MainPathExtender.GetLength(currentMainPathExtender, flow);
		}

		public static void PrintAddTileError(DungeonGenerator gen, TileProxy previousTile, DungeonArchetype archetype, IEnumerable<TileSet> useableTileSets, int branchId, int lineLength, float lineRatio)
		{
			//IL_00a1: Unknown result type (might be due to invalid IL or missing references)
			string text = ((previousTile != null) ? ((Object)previousTile.Prefab).name : "NULL");
			string text2 = (Object.op_Implicit((Object)(object)archetype) ? ((Object)archetype).name : "NULL");
			string text3 = string.Join(", ", useableTileSets);
			List<string> list = new List<string>();
			list.Add($"Main branch gen failed at Branch {branchId} (Length: {lineLength}, Ratio: {lineRatio})");
			list.Add("Prev tile: " + text);
			list.Add("Archetype: " + text2);
			list.Add("Tilesets: " + text3);
			list.Add($"Reason: {lastTilePlacementResult}");
			if (previousTile != null)
			{
				string text4 = string.Join(", ", previousTile.UnusedDoorways.Select((DoorwayProxy d) => ((Object)((Component)d.DoorwayComponent).gameObject).name));
				string text5 = string.Join(", ", previousTile.UsedDoorways.Select((DoorwayProxy d) => ((Object)((Component)d.DoorwayComponent).gameObject).name));
				list.Add("Available Doorways: " + text4);
				list.Add("Used Doorways: " + text5);
				if (API.IsDevDebugModeActive())
				{
					Queue<DoorwayPair> doorwayPairs = GetDoorwayPairs(gen, previousTile, useableTileSets, archetype, lineRatio);
					string text6 = string.Join(", ", from d in doorwayPairs.Select((DoorwayPair t) => ((DoorwayPair)(ref t)).NextTemplate.Prefab).Distinct()
						select ((Object)d).name);
					list.Add("Next Possible Tiles: " + text6);
				}
			}
			list.Add(string.Empty);
			Plugin.logger.LogDebug((object)string.Join("\n", list));
		}

		public static void PrintAddTileErrorQuick(DungeonGenerator gen, int lineLength)
		{
			PrintAddTileError(gen, DungeonGeneratorPatch.lastAttachTo, DungeonGeneratorPatch.lastArchetype, DungeonGeneratorPatch.lastUseableTileSets, 0, lineLength, DungeonGeneratorPatch.lastNormalizedDepth);
		}

		public static void RecordLastTilePlacementResult(DungeonGenerator gen, TilePlacementResult result)
		{
			//IL_0001: Unknown result type (might be due to invalid IL or missing references)
			//IL_0002: Unknown result type (might be due to invalid IL or missing references)
			lastTilePlacementResult = result;
		}

		public static void ProcessGlobalPropsPerMainPath(DungeonGenerator dungeonGenerator)
		{
			//IL_0159: Unknown result type (might be due to invalid IL or missing references)
			//IL_0160: Expected O, but got Unknown
			//IL_0127: Unknown result type (might be due to invalid IL or missing references)
			//IL_012e: Expected O, but got Unknown
			//IL_01c6: Unknown result type (might be due to invalid IL or missing references)
			//IL_01d0: Expected O, but got Unknown
			//IL_03ff: Unknown result type (might be due to invalid IL or missing references)
			//IL_0406: Expected O, but got Unknown
			//IL_0629: Unknown result type (might be due to invalid IL or missing references)
			//IL_0630: Expected O, but got Unknown
			HashSet<int> hashSet = (from x in Properties.MainPathProperties.MainPathDetails.SelectMany((MainPathExtender d) => d.LocalGroupProps)
				select x.ID).ToHashSet();
			List<DetailedGlobalPropSettings> detailedGlobalPropSettings = Properties.MainPathProperties.DetailedGlobalPropSettings;
			Dictionary<int, Dictionary<int, GameObjectChanceTable>> dictionary = new Dictionary<int, Dictionary<int, GameObjectChanceTable>>();
			Dictionary<int, GameObjectChanceTable> dictionary2 = new Dictionary<int, GameObjectChanceTable>();
			foreach (Tile allTile in dungeonGenerator.CurrentDungeon.AllTiles)
			{
				GlobalProp[] componentsInChildren = ((Component)allTile).GetComponentsInChildren<GlobalProp>();
				foreach (GlobalProp val in componentsInChildren)
				{
					GameObjectChanceTable value2;
					if (hashSet.Contains(val.PropGroupID))
					{
						if (!dictionary.TryGetValue(val.PropGroupID, out var value))
						{
							value = new Dictionary<int, GameObjectChanceTable>();
							dictionary.Add(val.PropGroupID, value);
						}
						int mainPathIndexFromTile = GetMainPathIndexFromTile(allTile);
						if (!value.TryGetValue(mainPathIndexFromTile, out value2))
						{
							value2 = new GameObjectChanceTable();
							value.Add(mainPathIndexFromTile, value2);
						}
					}
					else if (!dictionary2.TryGetValue(val.PropGroupID, out value2))
					{
						value2 = new GameObjectChanceTable();
						dictionary2.Add(val.PropGroupID, value2);
					}
					float num = (allTile.Placement.IsOnMainPath ? val.MainPathWeight : val.BranchPathWeight);
					num *= val.DepthWeightScale.Evaluate(allTile.Placement.NormalizedDepth);
					value2.Weights.Add(new GameObjectChance(((Component)val).gameObject, num, 0f, (TileSet)null));
				}
			}
			foreach (Dictionary<int, GameObjectChanceTable> value6 in dictionary.Values)
			{
				foreach (GameObjectChanceTable value7 in value6.Values)
				{
					foreach (GameObjectChance weight in value7.Weights)
					{
						weight.Value.SetActive(false);
					}
				}
			}
			foreach (GameObjectChanceTable value8 in dictionary2.Values)
			{
				foreach (GameObjectChance weight2 in value8.Weights)
				{
					weight2.Value.SetActive(false);
				}
			}
			List<int> list = new List<int>(dictionary.Count + dictionary2.Count);
			foreach (KeyValuePair<int, GameObjectChanceTable> pair2 in dictionary2)
			{
				if (list.Contains(pair2.Key))
				{
					Plugin.logger.LogWarning((object)("Dungeon Flow contains multiple entries for the global prop group ID: " + pair2.Key + ". Only the first entry will be used."));
					continue;
				}
				GlobalPropSettings val2 = dungeonGenerator.DungeonFlow.GlobalProps.Where((GlobalPropSettings x) => x.ID == pair2.Key).FirstOrDefault();
				DetailedGlobalPropSettings detailedGlobalPropSettings2 = detailedGlobalPropSettings.Where((DetailedGlobalPropSettings x) => x.ID == pair2.Key).FirstOrDefault();
				GameObjectChanceTable val3 = new GameObjectChanceTable();
				float num2 = detailedGlobalPropSettings2?.MinimumDistance ?? (-1f);
				bool flag = detailedGlobalPropSettings2?.GlobalCountMustBeReached ?? true;
				if (val2 != null)
				{
					GameObjectChanceTable value3 = pair2.Value;
					int random = val2.Count.GetRandom(dungeonGenerator.RandomStream);
					int num3 = ProcessGlobalPropID(value3, val3, random, 0, random, num2);
					Plugin.logger.LogDebug((object)$"Global ID: {pair2.Key} ({num3} / {random}). Min Dist: {num2}");
					list.Add(pair2.Key);
					if (flag && num3 < random)
					{
						Plugin.logg

LoadstoneNighty.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Bootstrap;
using BepInEx.Logging;
using DunGen;
using DunGen.Graph;
using DunGenPlus;
using DunGenPlus.Collections;
using HarmonyLib;
using Loadstone.Patches;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("LoadstoneNighty")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LoadstoneNighty")]
[assembly: AssemblyCopyright("Copyright ©  2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("b7c6eabd-16db-4de8-8013-1fa7da6e8de8")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace LoadstoneNighty;

public class PatchVer16
{
	public static void Activate()
	{
		try
		{
			Plugin.Instance.harmony.PatchAll(typeof(PatchVer16));
		}
		catch
		{
		}
		Plugin.logger.LogInfo((object)"FromProxyEnd function has been patched!");
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(FromProxyPatches), "FromProxyEnd")]
	public static void FromProxyEndPatch(Dictionary<TileProxy, Tile> dictionary)
	{
		API.AddTileToMainPathDictionary(dictionary);
	}
}
public class PatchVer17
{
	public static void Activate()
	{
		DungenOptimizationPatches.tileCollectors.Add(GetTiles);
		Plugin.logger.LogInfo((object)"DungenOptimizationPatches function has been patched!");
	}

	private static HashSet<Tile> GetTiles(DungeonGenerator generator)
	{
		DungeonFlow dungeonFlow = generator.DungeonFlow;
		DunGenExtender dunGenExtender = API.GetDunGenExtender(dungeonFlow);
		HashSet<Tile> tiles = new HashSet<Tile>();
		if (API.IsDunGenExtenderActive(dunGenExtender))
		{
			Plugin.logger.LogDebug((object)"Creating custom hashset for Loadstone");
			DunGenExtenderProperties properties = dunGenExtender.Properties;
			GenerateTileHashSet(ref tiles, properties.MainPathProperties.MainPathDetails);
			GenerateTileHashSet(ref tiles, properties.AdditionalTilesProperties.AdditionalTileSets);
			GenerateTileHashSet(ref tiles, properties.NormalNodeArchetypesProperties.NormalNodeArchetypes);
			GenerateTileHashSet(ref tiles, properties.LineRandomizerProperties.Archetypes);
		}
		return tiles;
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<NodeArchetype> nodes)
	{
		foreach (NodeArchetype node in nodes)
		{
			GenerateTileHashSet(ref tiles, node.Archetypes);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<AdditionalTileSetList> list)
	{
		foreach (AdditionalTileSetList item in list)
		{
			GenerateTileHashSet(ref tiles, item.TileSets);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<MainPathExtender> extenders)
	{
		foreach (MainPathExtender extender in extenders)
		{
			GenerateTileHashSet(ref tiles, extender.Nodes.Value);
			GenerateTileHashSet(ref tiles, extender.Lines.Value);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<GraphNode> nodes)
	{
		foreach (GraphNode node in nodes)
		{
			GenerateTileHashSet(ref tiles, node.TileSets);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<GraphLine> lines)
	{
		foreach (GraphLine line in lines)
		{
			GenerateTileHashSet(ref tiles, line.DungeonArchetypes);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<DungeonArchetype> archetypes)
	{
		foreach (DungeonArchetype archetype in archetypes)
		{
			GenerateTileHashSet(ref tiles, archetype.TileSets);
			GenerateTileHashSet(ref tiles, archetype.BranchCapTileSets);
		}
	}

	private static void GenerateTileHashSet(ref HashSet<Tile> tiles, List<TileSet> tileSets)
	{
		foreach (TileSet tileSet in tileSets)
		{
			foreach (GameObjectChance weight in tileSet.TileWeights.Weights)
			{
				Tile component = weight.Value.GetComponent<Tile>();
				if ((Object)(object)component != (Object)null)
				{
					tiles.Add(component);
				}
			}
		}
	}

	[HarmonyPrefix]
	[HarmonyPatch(typeof(FromProxyPatches), "FromProxyEnd")]
	public static void FromProxyEndPatch(Dictionary<TileProxy, Tile> dictionary)
	{
		API.AddTileToMainPathDictionary(dictionary);
	}
}
[BepInPlugin("dev.ladyalice.dungenplus.loadstonepatch", "Dungeon Generation Plus Loadstone Patch", "1.0.0")]
[BepInDependency("dev.ladyalice.dungenplus", "1.2.1")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class Plugin : BaseUnityPlugin
{
	public const string modGUID = "dev.ladyalice.dungenplus.loadstonepatch";

	private const string modName = "Dungeon Generation Plus Loadstone Patch";

	private const string modVersion = "1.0.0";

	public const string targetModGUID = "com.adibtw.loadstone";

	public const string targetModVersion = "0.1.17";

	public readonly Harmony harmony = new Harmony("dev.ladyalice.dungenplus.loadstonepatch");

	public static Plugin Instance { get; private set; }

	public static ManualLogSource logger { get; internal set; }

	private void Awake()
	{
		if ((Object)(object)Instance == (Object)null)
		{
			Instance = this;
		}
		logger = Logger.CreateLogSource("dev.ladyalice.dungenplus.loadstonepatch");
		if (Chainloader.PluginInfos.ContainsKey("com.adibtw.loadstone"))
		{
			logger.LogInfo((object)"Plugin Dungeon Generation Plus Loadstone Patch has been added!");
			PatchVer16.Activate();
			PluginInfo val = Chainloader.PluginInfos["com.adibtw.loadstone"];
			Version version = val.Metadata.Version;
			bool flag;
			if (string.IsNullOrWhiteSpace("0.1.17"))
			{
				flag = true;
			}
			else
			{
				Version version2 = new Version("0.1.17");
				flag = version >= version2;
			}
			if (flag)
			{
				PatchVer17.Activate();
			}
		}
	}
}