Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Echohold Fix Plus v1.0.0
EchoholdFixPlus.dll
Decompiled 20 hours agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("Midorino")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+b24e3fcb591b98a2e17e6d618a7603905068ceed")] [assembly: AssemblyProduct("EchoholdFixPlus")] [assembly: AssemblyTitle("EchoholdFixPlus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EchoholdFixPlus { [HarmonyPatch(typeof(ItemDrone), "SphereCheck")] internal static class DroneFallback { [HarmonyPostfix] private static void Postfix(ItemDrone __instance, float _radius, ref bool __result) { if (__result || !Plugin.FixDroneTargeting.Value || (Object)(object)__instance == (Object)null || !__instance.targetValuables) { return; } try { __result = TryTargetEchoholdValuable(__instance, _radius); } catch (Exception ex) { Plugin.Log.LogDebug((object)("Drone fallback failed: " + ex.Message)); } } private static bool TryTargetEchoholdValuable(ItemDrone drone, float radius) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)drone.itemBattery != (Object)null && drone.itemBattery.batteryLife <= 0f) { return false; } Vector3 position = ((Component)drone).transform.position; int mask = LayerMask.GetMask(new string[1] { "Default" }); Collider val = null; Transform val2 = null; PhysGrabObjectCollider val3 = null; float num = float.MaxValue; Collider[] array = Physics.OverlapSphere(position, radius); foreach (Collider val4 in array) { PhysGrabObjectCollider component = ((Component)val4).GetComponent<PhysGrabObjectCollider>(); if ((Object)(object)component == (Object)null) { continue; } Transform highestParentWithRigidbody = drone.GetHighestParentWithRigidbody(((Component)val4).transform); if ((Object)(object)highestParentWithRigidbody == (Object)null || (Object)(object)highestParentWithRigidbody == (Object)(object)((Component)drone).transform || !((Component)highestParentWithRigidbody).gameObject.activeSelf) { continue; } ValuableObject component2 = ((Component)highestParentWithRigidbody).GetComponent<ValuableObject>(); PhysGrabObjectImpactDetector component3 = ((Component)highestParentWithRigidbody).GetComponent<PhysGrabObjectImpactDetector>(); if (!((Object)(object)component2 == (Object)null) && !((Object)(object)component3 == (Object)null) && component3.isValuable && ValuableFixes.IsEchoholdValuable((Component)(object)component2) && (drone.customTargetingCondition == null || drone.customTargetingCondition.CustomTargetingCondition(((Component)highestParentWithRigidbody).gameObject))) { Vector3 val5 = val4.ClosestPoint(position); float num2 = Vector3.Distance(position, val5); if (!(num2 >= num) && !Blocked(position, val5, highestParentWithRigidbody, ((Component)drone).transform, mask)) { val = val4; val2 = highestParentWithRigidbody; val3 = component; num = num2; } } } if ((Object)(object)val == (Object)null || (Object)(object)val2 == (Object)null || (Object)(object)val3 == (Object)null) { return false; } drone.playerTumbleTarget = null; drone.playerAvatarTarget = null; drone.targetIsPlayer = false; drone.targetIsEnemy = false; drone.targetIsLocalPlayer = false; drone.magnetTarget = ((Component)val).transform; drone.magnetTargetPhysGrabObject = ((Component)val2).GetComponent<PhysGrabObject>(); drone.magnetTargetRigidbody = ((Component)val2).GetComponent<Rigidbody>(); drone.NewRayHitPoint(((Component)val).transform.position, ((Component)val2).GetComponent<PhotonView>().ViewID, val3.colliderID, val2); drone.attachPoint = drone.rayHitPosition; drone.enemyTarget = null; Plugin.Log.LogDebug((object)("Drone: targeted " + ValuableFixes.TypeName((Component)(object)val2) + " by the fallback check")); return true; } private static bool Blocked(Vector3 from, Vector3 to, Transform target, Transform drone, int mask) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.01f) { return false; } RaycastHit[] array = Physics.RaycastAll(from, val / magnitude, magnitude, mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; Transform transform = ((Component)((RaycastHit)(ref val2)).collider).transform; if (!transform.IsChildOf(target) && !transform.IsChildOf(drone)) { return true; } } return false; } } internal static class ExtractionAreaFix { internal static void Apply(ExtractionPoint ep, ExtractionPoint vanilla) { //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_013c: Unknown result type (might be due to invalid IL or missing references) GameObject extractionArea = ep.extractionArea; GameObject extractionArea2 = vanilla.extractionArea; if (!((Object)(object)extractionArea == (Object)null) && !((Object)(object)extractionArea2 == (Object)null) && !((Object)(object)extractionArea == (Object)(object)extractionArea2)) { MeshFilter component = extractionArea.GetComponent<MeshFilter>(); MeshFilter component2 = extractionArea2.GetComponent<MeshFilter>(); if ((Object)(object)component != (Object)null && (Object)(object)component2 != (Object)null) { component.sharedMesh = component2.sharedMesh; } MeshRenderer component3 = extractionArea.GetComponent<MeshRenderer>(); MeshRenderer component4 = extractionArea2.GetComponent<MeshRenderer>(); if ((Object)(object)component3 != (Object)null && (Object)(object)component4 != (Object)null) { ((Renderer)component3).sharedMaterials = ((Renderer)component4).sharedMaterials; ((Renderer)component3).enabled = ((Renderer)component4).enabled; } Transform transform = ((Component)ep).transform; Transform transform2 = ((Component)vanilla).transform; Vector3 val = transform2.InverseTransformPoint(extractionArea2.transform.position); Quaternion val2 = Quaternion.Inverse(transform2.rotation) * extractionArea2.transform.rotation; Vector3 val3 = Divide(extractionArea2.transform.lossyScale, transform2.lossyScale); extractionArea.transform.SetPositionAndRotation(transform.TransformPoint(val), transform.rotation * val2); Vector3 val4 = Vector3.Scale(val3, transform.lossyScale); Transform parent = extractionArea.transform.parent; extractionArea.transform.localScale = (((Object)(object)parent != (Object)null) ? Divide(val4, parent.lossyScale) : val4); } } private static Vector3 Divide(Vector3 a, Vector3 b) { //IL_0000: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) return new Vector3(Mathf.Approximately(b.x, 0f) ? a.x : (a.x / b.x), Mathf.Approximately(b.y, 0f) ? a.y : (a.y / b.y), Mathf.Approximately(b.z, 0f) ? a.z : (a.z / b.z)); } } [HarmonyPatch(typeof(LoadingUI), "LevelAnimationStart")] internal static class LevelNamePatch { [HarmonyPostfix] private static void Postfix(LoadingUI __instance) { try { Level val = (((Object)(object)LevelGenerator.Instance != (Object)null) ? LevelGenerator.Instance.Level : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)__instance.levelNameText == (Object)null) && Plugin.Names != null) { string text = ((TMP_Text)__instance.levelNameText).text; if (text == val.NarrativeName && Plugin.Names.TryTranslate(text, out string translated)) { ((TMP_Text)__instance.levelNameText).text = translated; } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Level name failed: " + ex.Message)); } } } internal sealed class MiniJson { private readonly string _text; private int _pos; private MiniJson(string text) { _text = text; } internal static object? Parse(string text) { MiniJson miniJson = new MiniJson(text); if (miniJson._pos < text.Length && text[miniJson._pos] == '\ufeff') { miniJson._pos++; } object? result = miniJson.ReadValue(); miniJson.SkipWhitespace(); if (miniJson._pos < text.Length) { throw miniJson.Error("unexpected text after the end"); } return result; } private object? ReadValue() { SkipWhitespace(); if (_pos >= _text.Length) { throw Error("unexpected end of file"); } char c = _text[_pos]; switch (c) { case '{': return ReadObject(); case '[': return ReadArray(); case '"': return ReadString(); case 't': ReadWord("true"); return true; case 'f': ReadWord("false"); return false; case 'n': ReadWord("null"); return null; default: switch (c) { case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': return ReadNumber(); default: throw Error($"unexpected character '{c}'"); } } } private Dictionary<string, object?> ReadObject() { Dictionary<string, object> dictionary = new Dictionary<string, object>(); _pos++; SkipWhitespace(); if (Peek() == '}') { _pos++; return dictionary; } while (true) { SkipWhitespace(); if (Peek() != '"') { break; } string key = ReadString(); SkipWhitespace(); Expect(':'); dictionary[key] = ReadValue(); SkipWhitespace(); switch (Peek()) { case ',': break; case '}': _pos++; return dictionary; default: throw Error("expected ',' or '}' (a comma may be missing)"); } _pos++; } throw Error("expected a \"name\""); } private List<object?> ReadArray() { List<object> list = new List<object>(); _pos++; SkipWhitespace(); if (Peek() == ']') { _pos++; return list; } while (true) { list.Add(ReadValue()); SkipWhitespace(); switch (Peek()) { case ',': break; case ']': _pos++; return list; default: throw Error("expected ',' or ']'"); } _pos++; } } private string ReadString() { _pos++; StringBuilder stringBuilder = new StringBuilder(); while (_pos < _text.Length) { char c = _text[_pos++]; switch (c) { case '"': return stringBuilder.ToString(); case '\n': throw Error("a string is not closed with \" before the end of the line"); default: stringBuilder.Append(c); break; case '\\': { if (_pos >= _text.Length) { throw Error("unexpected end of file"); } char c2 = _text[_pos++]; switch (c2) { case '"': stringBuilder.Append('"'); break; case '\\': stringBuilder.Append('\\'); break; case '/': stringBuilder.Append('/'); break; case 'b': stringBuilder.Append('\b'); break; case 'f': stringBuilder.Append('\f'); break; case 'n': stringBuilder.Append('\n'); break; case 'r': stringBuilder.Append('\r'); break; case 't': stringBuilder.Append('\t'); break; case 'u': { if (_pos + 4 > _text.Length || !int.TryParse(_text.Substring(_pos, 4), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out var result)) { throw Error("bad \\u escape"); } stringBuilder.Append((char)result); _pos += 4; break; } default: throw Error($"bad escape '\\{c2}'"); } break; } } } throw Error("a string is not closed with \""); } private double ReadNumber() { int pos = _pos; while (_pos < _text.Length && "+-0123456789.eE".IndexOf(_text[_pos]) >= 0) { _pos++; } string text = _text.Substring(pos, _pos - pos); if (!double.TryParse(text, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { _pos = pos; throw Error("bad number '" + text + "'"); } return result; } private void ReadWord(string word) { if (string.CompareOrdinal(_text, _pos, word, 0, word.Length) != 0) { throw Error("unexpected word (did you forget \"quotes\"?)"); } _pos += word.Length; } private void Expect(char c) { if (Peek() != c) { throw Error($"expected '{c}'"); } _pos++; } private char Peek() { if (_pos >= _text.Length) { return '\0'; } return _text[_pos]; } private void SkipWhitespace() { while (_pos < _text.Length && char.IsWhiteSpace(_text[_pos])) { _pos++; } } private FormatException Error(string message) { int num = 1; int num2 = 1; for (int i = 0; i < _pos && i < _text.Length; i++) { if (_text[i] == '\n') { num++; num2 = 1; } else { num2++; } } return new FormatException($"{message} (line {num}, column {num2})"); } } internal sealed class NameTable { private const float ReloadCheckInterval = 2f; private readonly ManualLogSource _log; private readonly string _path; private readonly string _fileName; private readonly string _label; private DateTime _loadedWriteTime; private float _nextReloadCheck; private Dictionary<string, Dictionary<string, string>> _tables = NewTables(); private string? _cachedLocale; private Dictionary<string, string>? _cachedTable; private readonly HashSet<string> _reported = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal NameTable(ManualLogSource log, string path, string defaultJson, string label, params string[] legacyPaths) { _log = log; _path = path; _fileName = Path.GetFileName(path); _label = label; try { if (!File.Exists(path)) { string text = Array.Find(legacyPaths, File.Exists); if (text != null) { File.Copy(text, path); _log.LogInfo((object)("Copied " + Path.GetFileName(text) + " to " + _fileName)); } else { File.WriteAllText(path, defaultJson, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); _log.LogInfo((object)("Created " + path)); } } } catch (Exception ex) { _log.LogError((object)("Could not create " + path + ": " + ex.Message)); } Load(); } internal bool TryTranslate(string name, out string translated) { translated = name; try { ReloadIfChanged(); Dictionary<string, string> dictionary = CurrentTable(); if (dictionary != null && dictionary.TryGetValue(name.Trim(), out var value) && !string.IsNullOrEmpty(value)) { translated = value; return true; } } catch (Exception arg) { if (_reported.Add("\0error")) { _log.LogError((object)$"Translate failed: {arg}"); } } return false; } internal void ReportIfMissing(string name) { try { if (!string.IsNullOrEmpty(name)) { Dictionary<string, string> dictionary = CurrentTable(); if (dictionary != null && !dictionary.ContainsKey(name.Trim()) && _reported.Add(name.Trim())) { _log.LogDebug((object)("No translation for \"" + name.Trim() + "\" (language " + SemiFunc.LocaleGetCode() + "). Add it to " + _fileName + " if you want.")); } } } catch (Exception ex) { _log.LogDebug((object)("ReportIfMissing failed: " + ex.Message)); } } private Dictionary<string, string>? CurrentTable() { string text = SemiFunc.LocaleGetCode() ?? ""; if (text == _cachedLocale) { return _cachedTable; } _cachedLocale = text; _cachedTable = null; if (_tables.TryGetValue(text, out Dictionary<string, string> value)) { _cachedTable = value; } else { int num = text.IndexOf('-'); if (num > 0 && _tables.TryGetValue(text.Substring(0, num), out Dictionary<string, string> value2)) { _cachedTable = value2; } } return _cachedTable; } private void ReloadIfChanged() { float realtimeSinceStartup = Time.realtimeSinceStartup; if (!(realtimeSinceStartup < _nextReloadCheck)) { _nextReloadCheck = realtimeSinceStartup + 2f; if (File.Exists(_path) && File.GetLastWriteTimeUtc(_path) != _loadedWriteTime) { Load(); } } } private void Load() { try { if (!File.Exists(_path)) { _log.LogWarning((object)(_path + " not found. No names are translated.")); return; } _loadedWriteTime = File.GetLastWriteTimeUtc(_path); string text = File.ReadAllText(_path, Encoding.UTF8); Dictionary<string, Dictionary<string, string>> dictionary = (_tables = Parse(text)); _cachedLocale = null; _cachedTable = null; _reported.Clear(); List<string> list = new List<string>(); foreach (KeyValuePair<string, Dictionary<string, string>> item in dictionary) { list.Add($"{item.Key}={item.Value.Count}"); } _log.LogInfo((object)(_label + ": loaded " + _fileName + " (" + ((list.Count > 0) ? string.Join(", ", list) : "no languages") + ")")); } catch (Exception ex) { _log.LogError((object)("Could not read " + _path + ": " + ex.Message + " (keeping the previous names)")); } } private Dictionary<string, Dictionary<string, string>> Parse(string text) { Dictionary<string, object> obj = (MiniJson.Parse(text) as Dictionary<string, object>) ?? throw new FormatException("the top level must be { ... }"); Dictionary<string, Dictionary<string, string>> dictionary = NewTables(); foreach (KeyValuePair<string, object> item in obj) { if (item.Key.StartsWith("_", StringComparison.Ordinal) || !(item.Value is Dictionary<string, object> dictionary2)) { continue; } Dictionary<string, string> dictionary3 = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); foreach (KeyValuePair<string, object> item2 in dictionary2) { if (!item2.Key.StartsWith("_", StringComparison.Ordinal)) { if (item2.Value is string value) { dictionary3[item2.Key.Trim()] = value; } else { _log.LogWarning((object)(item.Key + ".\"" + item2.Key + "\": the value must be a string in \"quotes\" (ignored)")); } } } dictionary[item.Key.Trim()] = dictionary3; } return dictionary; } private static Dictionary<string, Dictionary<string, string>> NewTables() { return new Dictionary<string, Dictionary<string, string>>(StringComparer.OrdinalIgnoreCase); } } [BepInPlugin("Midorino.EchoholdFixPlus", "Echohold_Fix_Plus", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public enum UnstickMode { Off, EchoholdOnly, All } public const string Guid = "Midorino.EchoholdFixPlus"; public const string Name = "Echohold_Fix_Plus"; public const string Version = "1.0.0"; public const string LocalizeFileName = "Echohold_Fix_Plus.Localize.json"; private const string DefaultLocalizeJson = "{\n \"_readme\": \"Level names on the loading screen per game language (ja = Japanese). Left: English level name, right: name to show. Add other languages the same way. Keys starting with _ are ignored. Changes are reloaded while the game is running.\",\n \"ja\": {\n \"Echohold Station\": \"エコーホールド・ステーション\"\n }\n}\n"; internal static NameTable? Names; internal static ConfigEntry<UnstickMode> UnstickValuables; internal static ConfigEntry<bool> FixDroneTargeting; internal static ConfigEntry<bool> LayDownUnderLowCeiling; internal static ConfigEntry<float> LowCeilingGap; internal static ConfigEntry<bool> FixExtractionArea; private const string EchoholdFixGuid = "empress.repo.echoholdcompatpatch"; internal const string EchoholdLevelName = "Level - Echohold"; internal static ManualLogSource Log; private void Awake() { //IL_00e1: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; UnstickValuables = ((BaseUnityPlugin)this).Config.Bind<UnstickMode>("Valuables", "UnstickValuables", UnstickMode.EchoholdOnly, "Push valuables out of walls/floors when the level starts. EchoholdOnly = Echohold valuables on any level. All = every valuable."); FixDroneTargeting = ((BaseUnityPlugin)this).Config.Bind<bool>("Valuables", "FixDroneTargeting", true, "Let drones target Echohold valuables (e.g. Plant Container, Alien Canister) that the game's line-of-sight check misses."); LayDownUnderLowCeiling = ((BaseUnityPlugin)this).Config.Bind<bool>("Valuables", "LayDownUnderLowCeiling", true, "On Echohold, lay tall valuables (e.g. server rack, cryo pod) on their side when the ceiling above them is too low to carry them out."); LowCeilingGap = ((BaseUnityPlugin)this).Config.Bind<float>("Valuables", "LowCeilingGap", 0.5f, "Space (m) above a tall valuable below which it is laid down."); FixExtractionArea = ((BaseUnityPlugin)this).Config.Bind<bool>("Extraction", "FixExtractionArea", true, "Use the vanilla look for the red extraction area shown during the extraction alarm."); Names = new NameTable(Log, Path.Combine(Paths.ConfigPath, "Echohold_Fix_Plus.Localize.json"), "{\n \"_readme\": \"Level names on the loading screen per game language (ja = Japanese). Left: English level name, right: name to show. Add other languages the same way. Keys starting with _ are ignored. Changes are reloaded while the game is running.\",\n \"ja\": {\n \"Echohold Station\": \"エコーホールド・ステーション\"\n }\n}\n", "Echohold_Fix_Plus 1.0.0"); new Harmony("Midorino.EchoholdFixPlus").PatchAll(typeof(Plugin).Assembly); } internal static bool IsEchoholdLevel() { Level val = (((Object)(object)RunManager.instance != (Object)null) ? RunManager.instance.levelCurrent : null); if ((Object)(object)val != (Object)null) { return string.Equals(((Object)val).name, "Level - Echohold", StringComparison.OrdinalIgnoreCase); } return false; } } internal static class VanillaTemplates { private static bool _searched; private static ExtractionPoint? _extractionPoint; private static Transform? _chargeArea; private static readonly string[] FallbackStartRoomPaths = new string[4] { "level/arctic/start room/Start Room - Arctic - Lobby", "level/wizard/start room/Start Room - Wizard - Chairs", "level/museum/start room/Start Room - Museum - Column", "level/desert/start room/Start Room - Desert - Exit" }; public static ExtractionPoint? ExtractionPoint { get { Search(); return _extractionPoint; } } public static Transform? ChargeArea { get { Search(); return _chargeArea; } } private static bool Done { get { if ((Object)(object)_extractionPoint != (Object)null) { return (Object)(object)_chargeArea != (Object)null; } return false; } } private static void Search() { //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_0223: Unknown result type (might be due to invalid IL or missing references) if (_searched) { return; } _searched = true; int num = 0; int num2 = 0; int num3 = 0; try { if ((Object)(object)RunManager.instance != (Object)null && RunManager.instance.levels != null) { foreach (Level level in RunManager.instance.levels) { if ((Object)(object)level == (Object)null || level.StartRooms == null || string.Equals(((Object)level).name, "Level - Echohold", StringComparison.OrdinalIgnoreCase)) { continue; } num++; foreach (PrefabRef startRoom in level.StartRooms) { num2++; GameObject val = TryGetPrefab(startRoom); if (!((Object)(object)val == (Object)null)) { num3++; Inspect(val); if (Done) { break; } } } if (Done) { break; } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Searching level start rooms failed: " + ex.GetType().Name + ": " + ex.Message)); } Plugin.Log.LogDebug((object)$"Vanilla template search: {num} level(s), {num2} start room(s), {num3} loaded"); string[] fallbackStartRoomPaths = FallbackStartRoomPaths; foreach (string text in fallbackStartRoomPaths) { if (Done) { break; } try { GameObject val2 = Resources.Load<GameObject>(text); Plugin.Log.LogDebug((object)("Resources.Load(\"" + text + "\") -> " + (((Object)(object)val2 != (Object)null) ? "ok" : "not found"))); if ((Object)(object)val2 != (Object)null) { Inspect(val2); } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("Resources.Load(\"" + text + "\") failed: " + ex2.Message)); } } if (Done) { return; } ExtractionPoint[] array = Resources.FindObjectsOfTypeAll<ExtractionPoint>(); foreach (ExtractionPoint val3 in array) { if ((Object)(object)val3 != (Object)null) { Scene scene = ((Component)val3).gameObject.scene; if (!((Scene)(ref scene)).IsValid() && !IsEchohold(((Component)val3).transform)) { Inspect(((Component)((Component)val3).transform.root).gameObject); } } } } private static GameObject? TryGetPrefab(PrefabRef? prefabRef) { if (prefabRef == null) { return null; } try { if (((PrefabRef<GameObject>)(object)prefabRef).IsValid()) { return ((PrefabRef<GameObject>)(object)prefabRef).Prefab; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("PrefabRef '" + ((PrefabRef<GameObject>)(object)prefabRef).PrefabName + "' could not be loaded: " + ex.Message)); } return null; } private static void Inspect(GameObject prefab) { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null || IsEchohold(prefab.transform)) { return; } if ((Object)(object)_extractionPoint == (Object)null) { ExtractionPoint componentInChildren = prefab.GetComponentInChildren<ExtractionPoint>(true); if ((Object)(object)componentInChildren != (Object)null && (Object)(object)componentInChildren.localizedBigMessageExtractionActivated != (Object)null && (Object)(object)componentInChildren.emojiScreen != (Object)null) { _extractionPoint = componentInChildren; Plugin.Log.LogDebug((object)("Vanilla extraction point template: " + ((Object)prefab).name)); } } if (!((Object)(object)_chargeArea == (Object)null)) { return; } ChargingStation[] componentsInChildren = prefab.GetComponentsInChildren<ChargingStation>(true); for (int i = 0; i < componentsInChildren.Length; i++) { Transform val = FindChild(((Component)componentsInChildren[i]).transform, "Charge Area"); if ((Object)(object)val != (Object)null) { _chargeArea = val; Plugin.Log.LogDebug((object)$"Vanilla charge area template: {((Object)prefab).name} scale={val.localScale}"); break; } } } private static bool IsEchohold(Transform t) { return ((Object)t.root).name.IndexOf("echohold", StringComparison.OrdinalIgnoreCase) >= 0; } internal static Transform? FindChild(Transform root, string name) { return ((IEnumerable<Transform>)((Component)root).GetComponentsInChildren<Transform>(true)).FirstOrDefault((Func<Transform, bool>)((Transform t) => (Object)(object)t != (Object)null && string.Equals(((Object)t).name, name, StringComparison.OrdinalIgnoreCase))); } } [HarmonyPatch(typeof(ExtractionPoint), "Start")] internal static class ExtractionPointStartPatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ExtractionPoint __instance) { if ((Object)(object)__instance == (Object)null || !Plugin.IsEchoholdLevel()) { return; } try { ExtractionPoint extractionPoint = VanillaTemplates.ExtractionPoint; if ((Object)(object)extractionPoint == (Object)null) { Plugin.Log.LogWarning((object)"No vanilla extraction point found; extraction texts are not fixed."); FixEmojiSpritesByName(__instance); return; } int num = 0; num += Copy(ref __instance.localizedExtractionCompleted, extractionPoint.localizedExtractionCompleted); num += Copy(ref __instance.localizedExtractionExtracting, extractionPoint.localizedExtractionExtracting); num += Copy(ref __instance.localizedExtractionLocked, extractionPoint.localizedExtractionLocked); num += Copy(ref __instance.localizedExtractionReady, extractionPoint.localizedExtractionReady); num += Copy(ref __instance.localizedExtractionActive, extractionPoint.localizedExtractionActive); num += Copy(ref __instance.localizedExtractionTaxReturn, extractionPoint.localizedExtractionTaxReturn); num += Copy(ref __instance.localizedBigMessageExtractionActivated, extractionPoint.localizedBigMessageExtractionActivated); num += Copy(ref __instance.localizedBigMessageExtractionCompleted, extractionPoint.localizedBigMessageExtractionCompleted); num += Copy(ref __instance.localizedFocusFillValuables, extractionPoint.localizedFocusFillValuables); num += Copy(ref __instance.localizedFocusAvoidGrenades, extractionPoint.localizedFocusAvoidGrenades); num += Copy(ref __instance.localizedFocusFindNext, extractionPoint.localizedFocusFindNext); num += Copy(ref __instance.localizedFocusBackToTruck, extractionPoint.localizedFocusBackToTruck); if (num > 0) { __instance.RefreshLocalizations(); } CopyTextLayout((TMP_Text?)(object)__instance.haulGoalScreen, (TMP_Text?)(object)extractionPoint.haulGoalScreen, copyRect: false); CopyTextLayout((TMP_Text?)(object)__instance.tubeScreenText, (TMP_Text?)(object)extractionPoint.tubeScreenText, copyRect: true); if (Plugin.FixExtractionArea.Value) { ExtractionAreaFix.Apply(__instance, extractionPoint); } bool flag = false; if ((Object)(object)__instance.emojiScreen != (Object)null && (Object)(object)extractionPoint.emojiScreen != (Object)null && (Object)(object)((TMP_Text)extractionPoint.emojiScreen).spriteAsset != (Object)null && (Object)(object)((TMP_Text)__instance.emojiScreen).spriteAsset != (Object)(object)((TMP_Text)extractionPoint.emojiScreen).spriteAsset) { ((TMP_Text)__instance.emojiScreen).spriteAsset = ((TMP_Text)extractionPoint.emojiScreen).spriteAsset; flag = true; } Plugin.Log.LogDebug((object)$"Extraction point '{((Object)__instance).name}': {num} localized text(s) copied, emoji sprites fixed={flag}"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Fixing extraction point failed: " + ex.Message)); } } private static void CopyTextLayout(TMP_Text? target, TMP_Text? source, bool copyRect) { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_0038: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)target == (Object)null) && !((Object)(object)source == (Object)null)) { if (copyRect) { target.rectTransform.sizeDelta = source.rectTransform.sizeDelta; target.rectTransform.pivot = source.rectTransform.pivot; } target.font = source.font; target.fontSharedMaterial = source.fontSharedMaterial; target.enableAutoSizing = source.enableAutoSizing; target.fontSize = source.fontSize; target.fontSizeMin = source.fontSizeMin; target.fontSizeMax = source.fontSizeMax; target.alignment = source.alignment; target.characterSpacing = source.characterSpacing; target.wordSpacing = source.wordSpacing; target.lineSpacing = source.lineSpacing; target.textWrappingMode = source.textWrappingMode; target.overflowMode = source.overflowMode; target.margin = source.margin; } } private static void FixEmojiSpritesByName(ExtractionPoint ep) { if (!((Object)(object)ep.emojiScreen == (Object)null)) { TMP_SpriteAsset current = ((TMP_Text)ep.emojiScreen).spriteAsset; TMP_SpriteAsset val = ((IEnumerable<TMP_SpriteAsset>)Resources.FindObjectsOfTypeAll<TMP_SpriteAsset>()).FirstOrDefault((Func<TMP_SpriteAsset, bool>)((TMP_SpriteAsset s) => (Object)(object)s != (Object)null && (Object)(object)s != (Object)(object)current && string.Equals(((Object)s).name, "emojis Extraction Point", StringComparison.OrdinalIgnoreCase))); if ((Object)(object)val != (Object)null) { ((TMP_Text)ep.emojiScreen).spriteAsset = val; Plugin.Log.LogDebug((object)("Extraction point '" + ((Object)ep).name + "': emoji sprites fixed by name")); } else { Plugin.Log.LogWarning((object)("Extraction point '" + ((Object)ep).name + "': game emoji sprites not found")); } } } private static int Copy(ref LocalizedAsset target, LocalizedAsset? source) { if ((Object)(object)source == (Object)null || (Object)(object)target == (Object)(object)source) { return 0; } target = source; return 1; } } [HarmonyPatch(typeof(StartRoom), "Start")] internal static class StartRoomStartPatch { [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(StartRoom __instance) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !Plugin.IsEchoholdLevel()) { return; } try { Transform chargeArea = VanillaTemplates.ChargeArea; if ((Object)(object)chargeArea == (Object)null) { Plugin.Log.LogWarning((object)"No vanilla charge area found; truck charger range is not fixed."); return; } ChargingStation[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<ChargingStation>(true); foreach (ChargingStation val in componentsInChildren) { if (string.Equals(((Object)val).name, "Charging Station New", StringComparison.OrdinalIgnoreCase)) { Transform val2 = VanillaTemplates.FindChild(((Component)val).transform, "Charge Area"); if (!((Object)(object)val2 == (Object)null)) { Vector3 localScale = val2.localScale; val2.localScale = chargeArea.localScale; val2.localPosition = chargeArea.localPosition; val2.localRotation = chargeArea.localRotation; Plugin.Log.LogDebug((object)$"Truck charge area: {localScale} -> {val2.localScale}"); } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Fixing truck charger failed: " + ex.Message)); } } } [HarmonyPatch(typeof(ValuableObject), "Start")] internal static class ValuableFixes { private static readonly Regex EchoholdValuableName = new Regex("(^|[\\s\\-_])EH([\\s\\-_]|$)", RegexOptions.Compiled); private static readonly HashSet<string> LoggedLayerFix = new HashSet<string>(StringComparer.OrdinalIgnoreCase); internal static string TypeName(Component valuable) { return ((Object)valuable).name.Replace("(Clone)", string.Empty).Trim(); } internal static bool IsEchoholdValuable(Component valuable) { return EchoholdValuableName.IsMatch(TypeName(valuable)); } [HarmonyPostfix] [HarmonyPriority(0)] private static void Postfix(ValuableObject __instance) { try { if (!((Object)(object)__instance == (Object)null)) { string name = TypeName((Component)(object)__instance); bool flag = IsEchoholdValuable((Component)(object)__instance); if (flag && Plugin.FixDroneTargeting.Value) { FixSelfBlockingColliders(__instance, name); } Plugin.UnstickMode value = Plugin.UnstickValuables.Value; bool flag2 = value == Plugin.UnstickMode.All || (value == Plugin.UnstickMode.EchoholdOnly && flag); bool flag3 = Plugin.LayDownUnderLowCeiling.Value && Plugin.IsEchoholdLevel(); if (flag2 || flag3) { ((MonoBehaviour)__instance).StartCoroutine(PlaceWhenLevelReady(__instance, name, flag2, flag3)); } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Valuable fix failed: " + ex.Message)); } } private static void FixSelfBlockingColliders(ValuableObject valuable, string name) { int num = LayerMask.NameToLayer("Default"); int num2 = LayerMask.NameToLayer("PhysGrabObject"); if (num < 0 || num2 < 0) { return; } int num3 = 0; Collider[] componentsInChildren = ((Component)valuable).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if ((Object)(object)val != (Object)null && !val.isTrigger && ((Component)val).gameObject.layer == num) { ((Component)val).gameObject.layer = num2; num3++; } } if (num3 > 0 && LoggedLayerFix.Add(name)) { Plugin.Log.LogDebug((object)$"{name}: {num3} collider(s) moved from Default to PhysGrabObject layer (drones can target it)"); } } private static IEnumerator PlaceWhenLevelReady(ValuableObject valuable, string name, bool unstick, bool layDown) { while ((Object)(object)LevelGenerator.Instance == (Object)null || !LevelGenerator.Instance.Generated) { yield return null; } if ((Object)(object)valuable == (Object)null || !SemiFunc.IsMasterClientOrSingleplayer()) { yield break; } try { ValuablePlacement.Fix(valuable, name, unstick, layDown); } catch (Exception ex) { Plugin.Log.LogWarning((object)(name + ": placement fix failed: " + ex.Message)); } } } internal static class ValuablePlacement { private readonly struct Pose { public readonly Quaternion Rotation; public readonly Vector3 Pivot; public readonly Vector3 Offset; public readonly string Label; public readonly float Penalty; public float Score => ((Vector3)(ref Offset)).magnitude + Penalty; public bool IsIdentity { get { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) if (Quaternion.Angle(Rotation, Quaternion.identity) < 0.1f) { return ((Vector3)(ref Offset)).sqrMagnitude < 1E-06f; } return false; } } public Pose(Quaternion rotation, Vector3 pivot, Vector3 offset, string label, float penalty) { //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) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: 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_0010: Unknown result type (might be due to invalid IL or missing references) Rotation = rotation; Pivot = pivot; Offset = offset; Label = label; Penalty = penalty; } public Pose WithOffset(Vector3 offset) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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) return new Pose(Rotation, Pivot, offset, Label, Penalty); } public Vector3 Point(Vector3 p) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: 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_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) return Pivot + Rotation * (p - Pivot) + Offset; } } private sealed class Shape { public Collider[] Own; public HashSet<Collider> OwnSet; public Vector3 Origin; public Bounds Box; public Bounds ColliderBox; public Vector3[] Points; public int Mask; } private struct Check { public float Depth; public Vector3 Direction; public int Hidden; public bool Ok { get { if (Depth < 0.03f) { return Hidden == 0; } return false; } } } private const float Tolerance = 0.03f; private const float Margin = 0.01f; private const float MaxMove = 1.5f; private const float TallHeight = 1.2f; private const float BoxShrink = 0.03f; private static readonly Vector3[] Offsets = BuildOffsets(); private static readonly Dictionary<int, int> LayerMasks = new Dictionary<int, int>(); private static Vector3[] BuildOffsets() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) List<Vector3> list = new List<Vector3>(); float[] array = new float[6] { 0f, 0.05f, 0.1f, 0.2f, 0.3f, 0.5f }; foreach (float num in array) { list.Add(Vector3.up * num); for (int j = 1; j <= 10; j++) { float num2 = (float)j * 0.1f; for (int k = 0; k < 8; k++) { float num3 = (float)k * 45f * (MathF.PI / 180f); list.Add(new Vector3(Mathf.Cos(num3) * num2, num, Mathf.Sin(num3) * num2)); } } } return list.OrderBy((Vector3 v) => ((Vector3)(ref v)).magnitude).ToArray(); } internal static void Fix(ValuableObject valuable, string name, bool unstick, bool layDown) { //IL_0012: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01a3: Unknown result type (might be due to invalid IL or missing references) //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_02b2: Unknown result type (might be due to invalid IL or missing references) //IL_02b7: Unknown result type (might be due to invalid IL or missing references) //IL_02bc: Unknown result type (might be due to invalid IL or missing references) //IL_02c0: Unknown result type (might be due to invalid IL or missing references) //IL_02c7: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d1: Unknown result type (might be due to invalid IL or missing references) //IL_02d3: Unknown result type (might be due to invalid IL or missing references) //IL_02d7: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Unknown result type (might be due to invalid IL or missing references) //IL_02e1: Unknown result type (might be due to invalid IL or missing references) //IL_030d: Unknown result type (might be due to invalid IL or missing references) //IL_030f: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Unknown result type (might be due to invalid IL or missing references) //IL_0302: Unknown result type (might be due to invalid IL or missing references) Shape shape = BuildShape(valuable); if (shape == null) { return; } Physics.SyncTransforms(); Pose pose = new Pose(Quaternion.identity, ((Bounds)(ref shape.Box)).center, Vector3.zero, "", 0f); Check check = Evaluate(shape, pose); bool flag = unstick && !check.Ok; float num = CeilingGap(shape); bool flag2 = layDown && ((Bounds)(ref shape.ColliderBox)).size.y >= 1.2f && num < Plugin.LowCeilingGap.Value; if (!flag && !flag2) { return; } Vector3 center = ((Bounds)(ref shape.Box)).center; Transform transform = ((Component)valuable).transform; List<Pose> rotations = new List<Pose> { new Pose(Quaternion.AngleAxis(90f, transform.right), center, Vector3.zero, "laid down", 0f), new Pose(Quaternion.AngleAxis(-90f, transform.right), center, Vector3.zero, "laid down", 0f), new Pose(Quaternion.AngleAxis(90f, transform.forward), center, Vector3.zero, "laid down", 0.05f), new Pose(Quaternion.AngleAxis(-90f, transform.forward), center, Vector3.zero, "laid down", 0.05f) }; List<Pose> rotations2 = new List<Pose> { pose, new Pose(Quaternion.AngleAxis(180f, Vector3.up), center, Vector3.zero, "turned 180", 0.25f), new Pose(Quaternion.AngleAxis(90f, Vector3.up), center, Vector3.zero, "turned 90", 0.3f), new Pose(Quaternion.AngleAxis(-90f, Vector3.up), center, Vector3.zero, "turned 90", 0.3f) }; Pose? pose2 = null; if (flag2) { pose2 = SearchFree(shape, rotations) ?? Resolve(shape, rotations); } if (!pose2.HasValue && flag) { pose2 = SearchFree(shape, rotations2) ?? Resolve(shape, rotations2); } if (!pose2.HasValue) { Plugin.Log.LogDebug((object)$"{name}: no free spot found (depth {check.Depth:F2} m, hidden parts {check.Hidden}, ceiling gap {num:F2} m)"); return; } Pose pose3 = Settle(shape, pose2.Value); if (!pose3.IsIdentity) { Vector3 val = pose3.Point(transform.position); Quaternion val2 = pose3.Rotation * transform.rotation; Vector3 val3 = val - transform.position; float magnitude = ((Vector3)(ref val3)).magnitude; PhysGrabObject component = ((Component)valuable).GetComponent<PhysGrabObject>(); if ((Object)(object)component != (Object)null) { component.Teleport(val, val2); } else { transform.SetPositionAndRotation(val, val2); } string text = ((pose3.Label == "laid down") ? $"only {num:F2} m to the ceiling" : ($"{check.Depth:F2} m inside a wall/floor" + ((check.Hidden > 0) ? $", {check.Hidden} part(s) through a wall" : string.Empty))); string text2 = (string.IsNullOrEmpty(pose3.Label) ? string.Empty : (pose3.Label + ", ")); Plugin.Log.LogDebug((object)$"{name}: {text} -> {text2}moved {magnitude:F2} m"); } } private static Shape? BuildShape(ValuableObject valuable) { //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) Collider[] array = (from c in ((Component)valuable).GetComponentsInChildren<Collider>() where (Object)(object)c != (Object)null && c.enabled && !c.isTrigger select c).ToArray(); if (array.Length == 0) { return null; } Renderer[] array2 = (from r in ((Component)valuable).GetComponentsInChildren<Renderer>() where (Object)(object)r != (Object)null && r.enabled && ((Component)r).gameObject.activeInHierarchy && (r is MeshRenderer || r is SkinnedMeshRenderer) select r).ToArray(); Bounds bounds = array[0].bounds; Collider[] array3 = array; foreach (Collider val in array3) { ((Bounds)(ref bounds)).Encapsulate(val.bounds); } Bounds box = bounds; Renderer[] array4 = array2; foreach (Renderer val2 in array4) { ((Bounds)(ref box)).Encapsulate(val2.bounds); } List<Vector3> list = new List<Vector3> { ((Bounds)(ref box)).center }; list.AddRange(array.Select(delegate(Collider c) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = c.bounds; return ((Bounds)(ref bounds2)).center; })); list.AddRange(array2.Select(delegate(Renderer r) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) Bounds bounds2 = r.bounds; return ((Bounds)(ref bounds2)).center; })); return new Shape { Own = array, OwnSet = new HashSet<Collider>(array), Origin = ((Component)valuable).transform.position + Vector3.up * 0.05f, Box = box, ColliderBox = bounds, Points = list.ToArray(), Mask = CollidingLayers(((Component)array[0]).gameObject.layer) }; } private static Pose? SearchFree(Shape shape, List<Pose> rotations) { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) Pose? result = null; foreach (Pose rotation in rotations) { Vector3[] offsets = Offsets; foreach (Vector3 offset in offsets) { Pose pose = rotation.WithOffset(offset); if (result.HasValue && pose.Score >= result.Value.Score) { break; } if (BoxFree(shape, pose) && Evaluate(shape, pose).Ok) { result = pose; break; } } } return result; } private static Pose? Resolve(Shape shape, List<Pose> rotations) { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) foreach (Pose rotation in rotations) { Check check = Evaluate(shape, rotation); if (check.Ok) { return rotation; } Vector3 val = Vector3.zero; for (int i = 0; i < 12; i++) { if (!(check.Depth >= 0.03f)) { break; } if (!(((Vector3)(ref val)).magnitude <= 1.5f)) { break; } val += check.Direction * (check.Depth + 0.01f); check = Evaluate(shape, rotation.WithOffset(val)); } if (check.Ok && ((Vector3)(ref val)).magnitude <= 1.5f) { return rotation.WithOffset(val); } for (float num = 0.1f; num <= 1.501f; num += 0.1f) { Pose pose = rotation.WithOffset(Vector3.up * num); if (Evaluate(shape, pose).Ok) { return pose; } } } return null; } private static Check Evaluate(Shape shape, Pose pose) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_0163: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) Check result = new Check { Depth = 0f, Direction = Vector3.up, Hidden = 0 }; Collider[] own = shape.Own; Vector3 direction = default(Vector3); float num2 = default(float); foreach (Collider val in own) { int num = CollidingLayers(((Component)val).gameObject.layer); Bounds bounds = val.bounds; Vector3 val2 = pose.Point(((Bounds)(ref bounds)).center); Quaternion rotation = pose.Rotation; bounds = val.bounds; Vector3 val3 = RotatedExtents(rotation, ((Bounds)(ref bounds)).extents) + Vector3.one * 0.01f; Vector3 val4 = pose.Point(((Component)val).transform.position); Quaternion val5 = pose.Rotation * ((Component)val).transform.rotation; Collider[] array = Physics.OverlapBox(val2, val3, Quaternion.identity, num, (QueryTriggerInteraction)1); foreach (Collider val6 in array) { if (IsLevel(val6, shape.OwnSet) && Physics.ComputePenetration(val, val4, val5, val6, ((Component)val6).transform.position, ((Component)val6).transform.rotation, ref direction, ref num2) && num2 > result.Depth) { result.Depth = num2; result.Direction = direction; } } } Vector3[] points = shape.Points; foreach (Vector3 p in points) { if (LineBlocked(shape, shape.Origin, pose.Point(p))) { result.Hidden++; } } return result; } private static bool BoxFree(Shape shape, Pose pose) { //IL_0006: 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_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) Vector3 val = Vector3.Max(((Bounds)(ref shape.Box)).extents - Vector3.one * 0.03f, Vector3.one * 0.01f); Collider[] array = Physics.OverlapBox(pose.Point(((Bounds)(ref shape.Box)).center), val, pose.Rotation, shape.Mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { if (IsLevel(array[i], shape.OwnSet)) { return false; } } return true; } private static bool LineBlocked(Shape shape, Vector3 from, Vector3 to) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001b: 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_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) Vector3 val = to - from; float magnitude = ((Vector3)(ref val)).magnitude; if (magnitude < 0.01f) { return false; } RaycastHit[] array = Physics.RaycastAll(from, val / magnitude, magnitude, shape.Mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val2 = array[i]; if (IsLevel(((RaycastHit)(ref val2)).collider, shape.OwnSet)) { return true; } } return false; } private static float CeilingGap(Shape shape) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) Bounds colliderBox = shape.ColliderBox; Vector3 val = default(Vector3); ((Vector3)(ref val))..ctor(Mathf.Max(0.01f, ((Bounds)(ref colliderBox)).extents.x - 0.05f), 0.01f, Mathf.Max(0.01f, ((Bounds)(ref colliderBox)).extents.z - 0.05f)); Vector3 val2 = new Vector3(((Bounds)(ref colliderBox)).center.x, ((Bounds)(ref colliderBox)).max.y - 0.02f, ((Bounds)(ref colliderBox)).center.z); float num = 10f; RaycastHit[] array = Physics.BoxCastAll(val2, val, Vector3.up, Quaternion.identity, 10f, shape.Mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val3 = array[i]; if (((RaycastHit)(ref val3)).distance > 0f && IsLevel(((RaycastHit)(ref val3)).collider, shape.OwnSet)) { num = Mathf.Min(num, ((RaycastHit)(ref val3)).distance); } } return num; } private static Pose Settle(Shape shape, Pose pose) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) if (pose.IsIdentity) { return pose; } Vector3 val = Vector3.Max(((Bounds)(ref shape.ColliderBox)).extents - Vector3.one * 0.02f, Vector3.one * 0.01f); Vector3 val2 = pose.Point(((Bounds)(ref shape.ColliderBox)).center); float num = float.MaxValue; RaycastHit[] array = Physics.BoxCastAll(val2, val, Vector3.down, pose.Rotation, 1.5f, shape.Mask, (QueryTriggerInteraction)1); for (int i = 0; i < array.Length; i++) { RaycastHit val3 = array[i]; if (((RaycastHit)(ref val3)).distance > 0f && IsLevel(((RaycastHit)(ref val3)).collider, shape.OwnSet)) { num = Mathf.Min(num, ((RaycastHit)(ref val3)).distance); } } float num2 = num - 0.03f; if (num == float.MaxValue || num2 <= 0.02f) { return pose; } Pose pose2 = pose.WithOffset(pose.Offset + Vector3.down * num2); if (!Evaluate(shape, pose2).Ok) { return pose; } return pose2; } private static bool IsLevel(Collider? other, HashSet<Collider> ownSet) { if ((Object)(object)other != (Object)null && !other.isTrigger && (Object)(object)other.attachedRigidbody == (Object)null) { return !ownSet.Contains(other); } return false; } private static Vector3 RotatedExtents(Quaternion rotation, Vector3 extents) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: 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_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_002d: 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) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) Vector3 val = rotation * new Vector3(extents.x, 0f, 0f); Vector3 val2 = rotation * new Vector3(0f, extents.y, 0f); Vector3 val3 = rotation * new Vector3(0f, 0f, extents.z); return new Vector3(Mathf.Abs(val.x) + Mathf.Abs(val2.x) + Mathf.Abs(val3.x), Mathf.Abs(val.y) + Mathf.Abs(val2.y) + Mathf.Abs(val3.y), Mathf.Abs(val.z) + Mathf.Abs(val2.z) + Mathf.Abs(val3.z)); } private static int CollidingLayers(int layer) { if (LayerMasks.TryGetValue(layer, out var value)) { return value; } value = 0; for (int i = 0; i < 32; i++) { if (!Physics.GetIgnoreLayerCollision(layer, i)) { value |= 1 << i; } } LayerMasks[layer] = value; return value; } } }