Decompiled source of DungeonGenerationPlus v1.4.1
DunGenPlus.dll
Decompiled a week ago
The result has been truncated due to the large size, download it to view full contents!
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 agousing 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(); } } } }