Decompiled source of FATE PermanentStorage v0.7.33
BepInEx/plugins/FATE_PermanentStorage/mikhailkillszombies.FatePermanentStorage.dll
Decompiled 3 hours 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.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Runtime.Versioning; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Cleverous.VaultInventory; using Deftly; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using Tableflip; using Unity.AI.Navigation; using UnityEngine; using UnityEngine.AI; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MikhailKillsZombies")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 MikhailKillsZombies")] [assembly: AssemblyFileVersion("0.7.33.0")] [assembly: AssemblyInformationalVersion("0.7.33")] [assembly: AssemblyProduct("mikhailkillszombies.FatePermanentStorage")] [assembly: AssemblyTitle("mikhailkillszombies.FatePermanentStorage")] [assembly: AssemblyVersion("0.7.33.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [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 MikhailKillsZombies.FatePermanentStorage { [Serializable] public sealed class CeilingOffsetEntry { public int x; public int z; public float ox; public float oy; public float oz; public float sx; public float sy; public float sz; public bool removed; public bool added; } [Serializable] public sealed class CeilingOffsetFile { public int version = 4; public List<CeilingOffsetEntry> tiles = new List<CeilingOffsetEntry>(); } internal static class CeilingOffsets { private const float LegacyEdgeOffset = 1.5429688f; private static readonly Dictionary<string, Vector3> offsets = new Dictionary<string, Vector3>(); private static readonly Dictionary<string, Vector3> scaleOffsets = new Dictionary<string, Vector3>(); private static readonly HashSet<string> removedTiles = new HashSet<string>(); private static readonly HashSet<string> addedTiles = new HashSet<string>(); private static readonly HashSet<string> legacyOffsetKeys = new HashSet<string>(); private static bool loaded; private static string pluginDir; public static int Count { get { EnsureLoaded(); HashSet<string> hashSet = new HashSet<string>(offsets.Keys); hashSet.UnionWith(scaleOffsets.Keys); hashSet.UnionWith(removedTiles); hashSet.UnionWith(addedTiles); return hashSet.Count; } } public static string Key(int x, int z) { return x + "," + z; } public static void EnsureLoaded() { if (!loaded) { loaded = true; offsets.Clear(); scaleOffsets.Clear(); removedTiles.Clear(); addedTiles.Clear(); legacyOffsetKeys.Clear(); LoadBakedDefaults(); LoadFrom(UserPath()); PermanentStoragePlugin.Log.LogInfo((object)("Ceiling offsets loaded: " + offsets.Count + " tile override(s); baked path=" + BakedPath() + ".")); } } private static void LoadBakedDefaults() { List<string> list = new List<string>(); list.Add(BakedPath()); try { string pluginPath = Paths.PluginPath; if (!string.IsNullOrEmpty(pluginPath)) { list.Add(Path.Combine(pluginPath, "FATE_PermanentStorage-FATE_PermanentStorage", "FATE_PermanentStorage", "ceiling_offsets.baked.json")); if (Directory.Exists(pluginPath)) { string[] files = Directory.GetFiles(pluginPath, "ceiling_offsets.baked.json", SearchOption.AllDirectories); foreach (string text in files) { if (text.IndexOf("FATE_PermanentStorage", StringComparison.OrdinalIgnoreCase) >= 0) { list.Add(text); } } } } } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not search plugin folders for the shipped roof bake: " + ex.Message)); } HashSet<string> hashSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase); foreach (string item in list) { if (!string.IsNullOrEmpty(item) && hashSet.Add(item) && File.Exists(item)) { int count = offsets.Count; LoadFrom(item); if (offsets.Count > count) { PermanentStoragePlugin.Log.LogInfo((object)("Loaded shipped ceiling offsets from " + item + ".")); } } } } public static void Reload() { loaded = false; EnsureLoaded(); } public static bool TryGet(int x, int z, out Vector3 offset) { EnsureLoaded(); return offsets.TryGetValue(Key(x, z), out offset); } public static bool IsLegacyOffset(int x, int z) { EnsureLoaded(); return legacyOffsetKeys.Contains(Key(x, z)); } public static Vector3 NormalizeLegacyOffset(int x, int z, Vector3 offset) { //IL_0045: 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_0072: Unknown result type (might be due to invalid IL or missing references) float num = x switch { 6 => 1.5429688f, -1 => -1.5429688f, _ => 0f, }; float num2 = z switch { 6 => 1.5429688f, -1 => -1.5429688f, _ => 0f, }; if (Mathf.Abs(num) > 0.0001f && Mathf.Abs(offset.x - num) < 0.05f) { offset.x -= num; } if (Mathf.Abs(num2) > 0.0001f && Mathf.Abs(offset.z - num2) < 0.05f) { offset.z -= num2; } return offset; } public static void Set(int x, int z, Vector3 offset) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) EnsureLoaded(); string text = Key(x, z); offsets[text] = offset; legacyOffsetKeys.Remove(text); } public static bool TryGetScale(int x, int z, out Vector3 multiplier) { EnsureLoaded(); return scaleOffsets.TryGetValue(Key(x, z), out multiplier); } public static void SetScale(int x, int z, Vector3 multiplier) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) EnsureLoaded(); scaleOffsets[Key(x, z)] = multiplier; } public static void ClearPosition(int x, int z) { EnsureLoaded(); string text = Key(x, z); offsets.Remove(text); legacyOffsetKeys.Remove(text); } public static void Clear(int x, int z) { EnsureLoaded(); string text = Key(x, z); offsets.Remove(text); scaleOffsets.Remove(text); legacyOffsetKeys.Remove(text); } public static bool IsRemoved(int x, int z) { EnsureLoaded(); return removedTiles.Contains(Key(x, z)); } public static bool IsAdded(int x, int z) { EnsureLoaded(); return addedTiles.Contains(Key(x, z)); } public static void SetRemoved(int x, int z, bool removed) { EnsureLoaded(); string item = Key(x, z); if (removed) { removedTiles.Add(item); addedTiles.Remove(item); } else { removedTiles.Remove(item); } } public static void SetAdded(int x, int z, bool added) { EnsureLoaded(); string item = Key(x, z); if (added) { addedTiles.Add(item); removedTiles.Remove(item); } else { addedTiles.Remove(item); } } public static void SaveUser() { MigrateLegacyOffsets(); string text = UserPath(); if (SaveTo(text)) { PermanentStoragePlugin.Log.LogInfo((object)("Ceiling tile overrides saved (" + Count + ") to " + text)); } } public static string BakeForRelease() { try { MigrateLegacyOffsets(); if (!SaveTo(UserPath())) { return null; } string text = BakedPath(); if (!SaveTo(text)) { return null; } PermanentStoragePlugin.Log.LogInfo((object)("Ceiling offsets baked for release (" + Count + " tile record(s)) to " + text + ". Include this file in the next package to ship these positions.")); return text; } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not bake ceiling offsets: " + ex.Message)); return null; } } private static string UserPath() { string text = null; try { text = Paths.ConfigPath; } catch { } if (string.IsNullOrEmpty(text)) { text = Path.Combine(Application.persistentDataPath, "BepInEx", "config"); } return Path.Combine(text, "mikhailkillszombies.fate.permanentstorage.ceiling_offsets.json"); } private static string BakedPath() { return Path.Combine(PluginDirectory(), "ceiling_offsets.baked.json"); } private static string PluginDirectory() { if (pluginDir != null) { return pluginDir; } try { string location = Assembly.GetExecutingAssembly().Location; if (!string.IsNullOrEmpty(location)) { pluginDir = Path.GetDirectoryName(location); } } catch { } if (string.IsNullOrEmpty(pluginDir)) { pluginDir = Path.Combine(Application.persistentDataPath, "BepInEx", "plugins"); } return pluginDir; } private static void LoadFrom(string path) { //IL_019e: 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) try { if (string.IsNullOrEmpty(path) || !File.Exists(path)) { return; } string text = File.ReadAllText(path); int num = JsonInt(text, "version", 1); int num2 = 0; foreach (Match item in Regex.Matches(text, "\\{[^{}]*\\\"x\\\"\\s*:\\s*-?\\d+[^{}]*\\}")) { string value = item.Value; int x = JsonInt(value, "x", 0); int z = JsonInt(value, "z", 0); float num3 = JsonFloat(value, "ox", 0f); float num4 = JsonFloat(value, "oy", 0f); float num5 = JsonFloat(value, "oz", 0f); float num6 = JsonFloat(value, "sx", 0f); float num7 = JsonFloat(value, "sy", 0f); float num8 = JsonFloat(value, "sz", 0f); bool flag = JsonBool(value, "removed", fallback: false); bool flag2 = JsonBool(value, "added", fallback: false); string text2 = Key(x, z); num2++; if (num >= 4) { legacyOffsetKeys.Remove(text2); } else if (num == 3) { legacyOffsetKeys.Add(text2); } if (num >= 3) { if (flag) { removedTiles.Add(text2); } else { removedTiles.Remove(text2); } if (flag2) { addedTiles.Add(text2); } else { addedTiles.Remove(text2); } } if (Mathf.Abs(num3) > 0.0001f || Mathf.Abs(num4) > 0.0001f || Mathf.Abs(num5) > 0.0001f) { offsets[text2] = new Vector3(num3, num4, num5); } if (num6 > 0f && num7 > 0f && num8 > 0f) { scaleOffsets[text2] = new Vector3(num6, num7, num8); } } if (num2 > 0) { PermanentStoragePlugin.Log.LogInfo((object)("Read " + num2 + " ceiling tile record(s) from " + path + ".")); } } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not read ceiling offsets from " + path + ": " + ex.Message)); } } private static int JsonInt(string json, string name, int fallback) { Match match = Regex.Match(json, "\\\"" + Regex.Escape(name) + "\\\"\\s*:\\s*(-?\\d+)"); if (!match.Success || !int.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } private static float JsonFloat(string json, string name, float fallback) { Match match = Regex.Match(json, "\\\"" + Regex.Escape(name) + "\\\"\\s*:\\s*([-+]?(?:\\d+\\.?\\d*|\\.\\d+)(?:[eE][-+]?\\d+)?)"); if (!match.Success || !float.TryParse(match.Groups[1].Value, NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { return fallback; } return result; } private static bool JsonBool(string json, string name, bool fallback) { Match match = Regex.Match(json, "\\\"" + Regex.Escape(name) + "\\\"\\s*:\\s*(true|false)", RegexOptions.IgnoreCase); if (!match.Success) { return fallback; } return string.Equals(match.Groups[1].Value, "true", StringComparison.OrdinalIgnoreCase); } private static bool SaveTo(string path) { //IL_00d8: 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_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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) try { string directoryName = Path.GetDirectoryName(path); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) { Directory.CreateDirectory(directoryName); } HashSet<string> hashSet = new HashSet<string>(offsets.Keys); hashSet.UnionWith(scaleOffsets.Keys); hashSet.UnionWith(removedTiles); hashSet.UnionWith(addedTiles); List<CeilingOffsetEntry> list = new List<CeilingOffsetEntry>(); foreach (string item in hashSet) { string[] array = item.Split(','); if (array.Length == 2 && int.TryParse(array[0], out var result) && int.TryParse(array[1], out var result2)) { offsets.TryGetValue(item, out var value); scaleOffsets.TryGetValue(item, out var value2); list.Add(new CeilingOffsetEntry { x = result, z = result2, ox = value.x, oy = value.y, oz = value.z, sx = value2.x, sy = value2.y, sz = value2.z, removed = removedTiles.Contains(item), added = addedTiles.Contains(item) }); } } list.Sort((CeilingOffsetEntry a, CeilingOffsetEntry b) => (a.x == b.x) ? a.z.CompareTo(b.z) : a.x.CompareTo(b.x)); StringBuilder stringBuilder = new StringBuilder("{\n \"version\": 4,\n \"tiles\": ["); for (int num = 0; num < list.Count; num++) { CeilingOffsetEntry ceilingOffsetEntry = list[num]; stringBuilder.Append((num == 0) ? "\n {" : ",\n {"); stringBuilder.Append("\"x\": ").Append(ceilingOffsetEntry.x).Append(", \"z\": ") .Append(ceilingOffsetEntry.z); stringBuilder.Append(", \"ox\": ").Append(JsonFloat(ceilingOffsetEntry.ox)); stringBuilder.Append(", \"oy\": ").Append(JsonFloat(ceilingOffsetEntry.oy)); stringBuilder.Append(", \"oz\": ").Append(JsonFloat(ceilingOffsetEntry.oz)); stringBuilder.Append(", \"sx\": ").Append(JsonFloat(ceilingOffsetEntry.sx)); stringBuilder.Append(", \"sy\": ").Append(JsonFloat(ceilingOffsetEntry.sy)); stringBuilder.Append(", \"sz\": ").Append(JsonFloat(ceilingOffsetEntry.sz)); stringBuilder.Append(", \"removed\": ").Append(ceilingOffsetEntry.removed ? "true" : "false"); stringBuilder.Append(", \"added\": ").Append(ceilingOffsetEntry.added ? "true" : "false").Append("}"); } if (list.Count > 0) { stringBuilder.Append('\n').Append(" "); } stringBuilder.Append("]\n}"); File.WriteAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); PermanentStoragePlugin.Log.LogInfo((object)("Wrote " + list.Count + " ceiling tile record(s) to " + path + ".")); return true; } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not write ceiling offsets to " + path + ": " + ex.Message)); return false; } } private static void MigrateLegacyOffsets() { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //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_00a2: Unknown result type (might be due to invalid IL or missing references) if (!loaded || legacyOffsetKeys.Count == 0) { return; } foreach (string item in new List<string>(legacyOffsetKeys)) { string[] array = item.Split(','); if (array.Length == 2 && int.TryParse(array[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) && int.TryParse(array[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out var result2) && offsets.TryGetValue(item, out var value)) { value = NormalizeLegacyOffset(result, result2, value); if (((Vector3)(ref value)).sqrMagnitude < 0.0001f) { offsets.Remove(item); } else { offsets[item] = value; } } legacyOffsetKeys.Remove(item); } } private static string JsonFloat(float value) { if (float.IsNaN(value) || float.IsInfinity(value)) { return "0"; } return value.ToString("R", CultureInfo.InvariantCulture); } } internal static class ChestRotationInput { private static bool registered; private static object button; private static PropertyInfo wasPressed; public static void EnsureRegistered() { if (registered) { return; } try { Type type = FindType("ZombieGhost.Rebind.RebindApi"); if (type == null) { return; } MethodInfo method = type.GetMethod("RegisterProvider", BindingFlags.Static | BindingFlags.Public); if (method == null) { return; } object obj = method.Invoke(null, new object[2] { "mikhailkillszombies.fate.permanentstorage", "FATE Permanent Storage" }); if (obj == null) { return; } MethodInfo method2 = obj.GetType().GetMethod("RegisterButton", BindingFlags.Instance | BindingFlags.Public); if (!(method2 == null)) { button = method2.Invoke(obj, new object[4] { "storage.rotatechest", "Rotate storage chest", "<Keyboard>/r", "Storage" }); if (button != null) { wasPressed = button.GetType().GetProperty("WasPressedThisFrame", BindingFlags.Instance | BindingFlags.Public); } registered = true; PermanentStoragePlugin.Log.LogInfo((object)"Registered the chest rotation key with FATE Rebind (default R)."); } } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not register the chest rotation key with FATE Rebind: " + ex.Message)); } } public static bool WasPressedThisFrame() { EnsureRegistered(); if (button != null && wasPressed != null) { try { return (bool)wasPressed.GetValue(button); } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Chest rotation key read failed: " + ex.Message)); } } return Input.GetKeyDown((KeyCode)114); } private static Type FindType(string fullName) { Type type = Type.GetType(fullName + ", ZombieGhost.Rebind"); if (type != null) { return type; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { Type type2 = assembly.GetType(fullName, throwOnError: false); if (type2 != null) { return type2; } } catch (Exception) { } } return null; } } public sealed class StorageRoomDoor : InteractableSceneObject { private StorageRoomManager manager; public void Init(StorageRoomManager owner) { manager = owner; ((InteractableSceneObject)this).InteractableName = "Permanent Storage Room"; ((InteractableSceneObject)this).InteractRange = 3.5f; ((InteractableSceneObject)this).InteractionPriority = 20; } public override void Interact(Character interactor = null) { //IL_0006: 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) StorageDoorAudio.Play(((Component)this).transform.position); manager?.EnterRoom(manager.EntranceReturnPosition, useReturnTo: true); } } public sealed class StorageExitDoor : InteractableSceneObject { private StorageRoomManager manager; public void Init(StorageRoomManager owner) { manager = owner; ((InteractableSceneObject)this).InteractableName = "Return to the Village"; ((InteractableSceneObject)this).InteractRange = 2.4f; ((InteractableSceneObject)this).InteractionPriority = 5; } public override void Interact(Character interactor = null) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) StorageDoorAudio.Play(((Component)this).transform.position); manager?.ExitRoom(); } } public sealed class StorageStashProxy : MonoBehaviour { } internal static class KeyState { private static bool probed; private static Type keyboardType; private static PropertyInfo currentProperty; private static bool legacyUsable = true; public static bool Pressed(KeyCode legacyKey, string keyboardControl) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) object obj = CurrentKeyboard(); if (obj != null) { try { PropertyInfo property = obj.GetType().GetProperty(keyboardControl); object obj2 = ((property != null) ? property.GetValue(obj) : null); if (obj2 == null) { return false; } PropertyInfo property2 = obj2.GetType().GetProperty("wasPressedThisFrame"); return property2 != null && (bool)property2.GetValue(obj2); } catch (Exception) { return false; } } if (!legacyUsable) { return false; } try { return Input.GetKeyDown(legacyKey); } catch (Exception) { legacyUsable = false; return false; } } public static bool PressedAny(KeyCode[] legacyKeys, params string[] keyboardControls) { //IL_0098: 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) object obj = CurrentKeyboard(); if (obj != null) { foreach (string name in keyboardControls) { try { PropertyInfo property = obj.GetType().GetProperty(name); object obj2 = ((property != null) ? property.GetValue(obj) : null); if (obj2 != null) { PropertyInfo property2 = obj2.GetType().GetProperty("wasPressedThisFrame"); if (property2 != null && (bool)property2.GetValue(obj2)) { return true; } } } catch (Exception) { } } return false; } if (!legacyUsable || legacyKeys == null) { return false; } foreach (KeyCode val in legacyKeys) { try { if (Input.GetKeyDown(val)) { return true; } } catch (Exception) { legacyUsable = false; return false; } } return false; } private static object CurrentKeyboard() { if (!probed) { probed = true; keyboardType = Type.GetType("UnityEngine.InputSystem.Keyboard, Unity.InputSystem"); if (keyboardType == null) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { try { keyboardType = assembly.GetType("UnityEngine.InputSystem.Keyboard", throwOnError: false); } catch (Exception) { } if (keyboardType != null) { break; } } } if (keyboardType != null) { currentProperty = keyboardType.GetProperty("current", BindingFlags.Static | BindingFlags.Public); } PermanentStoragePlugin.Log.LogInfo((object)("Input keys: " + ((currentProperty != null) ? "using the new Input System keyboard." : "no new-input keyboard found; using legacy Input."))); } if (currentProperty == null) { return null; } try { return currentProperty.GetValue(null); } catch (Exception) { return null; } } } internal static class MimicChestItem { public const string ItemName = "Mimic Chest"; public const string RefId = "MimicChest"; public const string IconName = "mimicchest"; private static bool registered; private static Sprite icon; private static GameObject worldDropPrefab; private static readonly object DropRolledMarker = new object(); private static readonly ConditionalWeakTable<Monster, object> DropRolled = new ConditionalWeakTable<Monster, object>(); public static ItemData Data { get; private set; } public static void ShowPlacementMessage(string message) { if (string.IsNullOrWhiteSpace(message)) { return; } try { TooltipUI[] array = Object.FindObjectsOfType<TooltipUI>(true); if (array != null && array.Length != 0 && (Object)(object)array[0] != (Object)null) { array[0].ShowTooltip("Chest Placement", message); } } catch (Exception ex) { ManualLogSource log = PermanentStoragePlugin.Log; if (log != null) { log.LogWarning((object)("Could not show the chest placement message in the item tooltip panel: " + ex.Message)); } } } public static void EnsureRegistered() { //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) if ((registered && (Object)(object)Data != (Object)null) || !SingletonBehaviour<FateDB>.InstanceExists()) { return; } FateDB instance = SingletonBehaviour<FateDB>.Instance; FieldRef<FateDB, ItemData[]> val = AccessTools.FieldRefAccess<FateDB, ItemData[]>("allItems"); FieldRef<FateDB, int> val2 = AccessTools.FieldRefAccess<FateDB, int>("allItemsGameVersionIndex"); ItemData[] array = val.Invoke(instance); if (array == null) { return; } ItemData[] array2 = array; foreach (ItemData val3 in array2) { if ((Object)(object)val3 != (Object)null && val3.displayName == "Mimic Chest") { Data = val3; registered = true; return; } } ItemData val4 = FindTemplate(array); ItemData val5 = ((!((Object)(object)val4 != (Object)null)) ? ScriptableObject.CreateInstance<ItemData>() : Object.Instantiate<ItemData>(val4)); ((Object)val5).name = "Item_MimicChest"; val5.displayName = "Mimic Chest"; val5.refId = "MimicChest"; val5.description = "A strange chest recovered from a Mimic. Bring it to your storage room to unlock an additional storage chest."; val5.itemType = (ItemType)28; val5.heroType = (HeroType)0; val5.rarity = 1; val5.fishingRarity = 0; val5.minimumDepth = 0; val5.maximumDepth = 0; val5.value = 0; val5.merchantMinimum = 0; val5.merchantMaximum = 0; val5.itemTarget = (ItemTarget)21; val5.takeable = true; val5.autoPickup = false; val5.forcePickupHold = false; val5.usable = false; val5.destructible = false; val5.uses = -9999; val5.sockets = 0; val5.reserved = false; val5.identified = true; val5.notPurchasable = true; val5.notSellable = true; val5.artifact = false; val5.expansion = false; val5.collision = false; val5.hasShadow = true; val5.preCalcSize = new Vector2Int(2, 2); val5.iconPath = "icons/mimicchest.png:0"; FieldInfo fieldInfo = AccessTools.Field(typeof(ItemData), "iconName"); if (fieldInfo != null) { fieldInfo.SetValue(val5, "mimicchest"); } EnsureIconSprite(instance); EnsureWorldDropPrefab(instance); List<ItemData> list = new List<ItemData>(array); list.Add(val5); val.Invoke(instance) = list.ToArray(); val2.Invoke(instance) = -1; Data = val5; registered = true; PermanentStoragePlugin.Log.LogInfo((object)"Registered Mimic Chest item."); } private static ItemData FindTemplate(ItemData[] items) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 ItemData val = null; ItemData[] array = items; foreach (ItemData val2 in array) { if (!((Object)(object)val2 == (Object)null)) { if ((int)val2.itemType == 55) { return val2; } if ((Object)(object)val == (Object)null && (int)val2.itemType == 28 && !string.IsNullOrEmpty(val2.iconPath)) { val = val2; } } } if ((Object)(object)val != (Object)null) { return val; } array = items; foreach (ItemData val3 in array) { if ((Object)(object)val3 != (Object)null && !string.IsNullOrEmpty(val3.iconPath)) { return val3; } } return null; } private static void EnsureIconSprite(FateDB db) { if (db.spriteStash != null) { Sprite[] spriteStash = db.spriteStash; foreach (Sprite val in spriteStash) { if ((Object)(object)val != (Object)null && ((Object)val).name == "mimicchest") { return; } } } if ((Object)(object)icon == (Object)null) { icon = BuildIcon(); } List<Sprite> list = new List<Sprite>(); if (db.spriteStash != null) { list.AddRange(db.spriteStash); } list.Add(icon); db.spriteStash = list.ToArray(); } private static Sprite BuildIcon() { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_0075: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_015d: Unknown result type (might be due to invalid IL or missing references) //IL_01a7: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_0287: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Unknown result type (might be due to invalid IL or missing references) //IL_0260: Unknown result type (might be due to invalid IL or missing references) try { using Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("MikhailKillsZombies.FatePermanentStorage.Assets.mimicchest.png"); if (stream != null) { byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (ImageConversion.LoadImage(val, array, false)) { ((Object)val).name = "mimicchest"; Sprite obj = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 256f); ((Object)obj).name = "mimicchest"; return obj; } } } catch (Exception ex) { ManualLogSource log = PermanentStoragePlugin.Log; if (log != null) { log.LogWarning((object)("Could not load the embedded Mimic Chest icon: " + ex.Message)); } } Texture2D val2 = new Texture2D(32, 32, (TextureFormat)4, false); ((Object)val2).name = "mimicchest"; Color32 val3 = default(Color32); ((Color32)(ref val3))..ctor((byte)0, (byte)0, (byte)0, (byte)0); Color32 val4 = default(Color32); ((Color32)(ref val4))..ctor((byte)112, (byte)70, (byte)34, byte.MaxValue); Color32 val5 = default(Color32); ((Color32)(ref val5))..ctor((byte)148, (byte)96, (byte)48, byte.MaxValue); Color32 val6 = default(Color32); ((Color32)(ref val6))..ctor((byte)48, (byte)31, (byte)18, byte.MaxValue); Color32 val7 = default(Color32); ((Color32)(ref val7))..ctor((byte)232, (byte)190, (byte)72, byte.MaxValue); for (int i = 0; i < 32; i++) { for (int j = 0; j < 32; j++) { val2.SetPixel(j, i, Color32.op_Implicit(val3)); } } for (int k = 8; k < 24; k++) { for (int l = 5; l < 27; l++) { val2.SetPixel(l, k, Color32.op_Implicit((l == 5 || l == 26 || k == 8 || k == 23) ? val6 : val4)); } } for (int m = 22; m < 27; m++) { for (int n = 6; n < 26; n++) { val2.SetPixel(n, m, Color32.op_Implicit((m == 26) ? val6 : val5)); } } for (int num = 8; num < 24; num++) { val2.SetPixel(num, 18, Color32.op_Implicit(val7)); } for (int num2 = 12; num2 < 22; num2++) { val2.SetPixel(16, num2, Color32.op_Implicit(val7)); } for (int num3 = 13; num3 < 17; num3++) { for (int num4 = 14; num4 < 19; num4++) { val2.SetPixel(num4, num3, Color32.op_Implicit(val7)); } } val2.SetPixel(16, 15, Color32.op_Implicit(val6)); val2.Apply(false, false); Sprite obj2 = Sprite.Create(val2, new Rect(0f, 0f, 32f, 32f), new Vector2(0.5f, 0.5f), 32f); ((Object)obj2).name = "mimicchest"; return obj2; } private static GameObject EnsureWorldDropPrefab(FateDB db) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_0090: Unknown result type (might be due to invalid IL or missing references) if (db.itemPrefabs != null) { GameObject[] itemPrefabs = db.itemPrefabs; foreach (GameObject val in itemPrefabs) { if ((Object)(object)val != (Object)null && ((Object)val).name.Replace("P_", "").Trim().ToLowerInvariant() == "mimic chest") { EnsureDropTracking(val); EnsureMimicCorpse(val); worldDropPrefab = val; return val; } } } GameObject val2 = new GameObject("P_Mimic Chest"); val2.transform.position = new Vector3(9000f, -9000f, 9000f); EnsureDropTracking(val2); EnsureMimicCorpse(val2); List<GameObject> list = new List<GameObject>(); if (db.itemPrefabs != null) { list.AddRange(db.itemPrefabs); } list.Add(val2); db.itemPrefabs = list.ToArray(); worldDropPrefab = val2; return val2; } private static void EnsureDropTracking(GameObject root) { if (!((Object)(object)root == (Object)null) && !((Object)(object)root.GetComponent<MimicChestDropVisual>() != (Object)null)) { root.AddComponent<MimicChestDropVisual>(); } } private static void EnsureMimicCorpse(GameObject root) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)root == (Object)null) { return; } MimicChestDropVisual component = root.GetComponent<MimicChestDropVisual>(); if ((Object)(object)component == (Object)null) { return; } Transform val = root.transform.Find("MimicCorpse"); if ((Object)(object)val != (Object)null) { component.SetStandInCorpse(val); return; } GameObject val2 = FindMimicPrefab(); if ((Object)(object)val2 == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"No Mimic model was found for the Mimic Chest drop visual."); return; } GameObject val3; try { val3 = Object.Instantiate<GameObject>(val2, root.transform, false); } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not clone the Mimic model for the chest drop: " + ex.Message)); return; } ((Object)val3).name = "MimicCorpse"; val3.SetActive(false); val3.transform.localPosition = Vector3.zero; val3.transform.localRotation = Quaternion.identity; DisarmMimicVisual(val3); val3.SetActive(true); component.SetStandInCorpse(val3.transform); PermanentStoragePlugin.Log.LogInfo((object)"Mimic Chest drop now carries a Mimic corpse visual."); } private static GameObject FindMimicPrefab() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Invalid comparison between Unknown and I4 if (SingletonBehaviour<FateDB>.InstanceExists()) { FateDB instance = SingletonBehaviour<FateDB>.Instance; if (instance.allMonsters != null) { MonsterData[] allMonsters = instance.allMonsters; foreach (MonsterData val in allMonsters) { if ((Object)(object)val != (Object)null && (int)val.family == 46 && (Object)(object)val.modelPrefab != (Object)null) { return val.modelPrefab; } } } } GameObject[] array = Resources.FindObjectsOfTypeAll<GameObject>(); foreach (GameObject val2 in array) { if (!((Object)(object)val2 == (Object)null) && (((Object)val2).name == "Monster_Mimic" || ((Object)val2).name == "P_Mimic")) { return val2; } } return Resources.Load<GameObject>("Monster_Mimic"); } private static void DisarmMimicVisual(GameObject body) { MonoBehaviour[] componentsInChildren = body.GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val in componentsInChildren) { if ((Object)(object)val != (Object)null) { ((Behaviour)val).enabled = false; } } NavMeshAgent[] componentsInChildren2 = body.GetComponentsInChildren<NavMeshAgent>(true); foreach (NavMeshAgent val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; } } Animator[] componentsInChildren3 = body.GetComponentsInChildren<Animator>(true); foreach (Animator val3 in componentsInChildren3) { if ((Object)(object)val3 != (Object)null) { val3.applyRootMotion = false; } } Collider[] componentsInChildren4 = body.GetComponentsInChildren<Collider>(true); foreach (Collider val4 in componentsInChildren4) { if ((Object)(object)val4 != (Object)null) { Object.Destroy((Object)(object)val4); } } Rigidbody[] componentsInChildren5 = body.GetComponentsInChildren<Rigidbody>(true); foreach (Rigidbody val5 in componentsInChildren5) { if ((Object)(object)val5 != (Object)null) { Object.Destroy((Object)(object)val5); } } Canvas[] componentsInChildren6 = body.GetComponentsInChildren<Canvas>(true); foreach (Canvas val6 in componentsInChildren6) { if ((Object)(object)val6 != (Object)null) { Object.Destroy((Object)(object)((Component)val6).gameObject); } } Renderer[] componentsInChildren7 = body.GetComponentsInChildren<Renderer>(true); foreach (Renderer val7 in componentsInChildren7) { if ((Object)(object)val7 != (Object)null) { val7.enabled = true; } } } internal static GameObject GetWorldDropPrefab() { if ((Object)(object)worldDropPrefab != (Object)null) { return worldDropPrefab; } if (!SingletonBehaviour<FateDB>.InstanceExists()) { return null; } return EnsureWorldDropPrefab(SingletonBehaviour<FateDB>.Instance); } public static bool HasOne() { Player playerChar = Player.PlayerChar; if ((Object)(object)playerChar == (Object)null || ((Character)playerChar).inventory == null) { return false; } foreach (Item item in ((Character)playerChar).inventory) { if (item != null && (item.refId == "MimicChest" || item.itemBaseName == "Mimic Chest")) { return true; } } return false; } public static bool ConsumeOne() { Player playerChar = Player.PlayerChar; if ((Object)(object)playerChar == (Object)null || ((Character)playerChar).inventory == null) { return false; } Item val = null; foreach (Item item in ((Character)playerChar).inventory) { if (item != null && (item.refId == "MimicChest" || item.itemBaseName == "Mimic Chest")) { val = item; break; } } if (val == null) { return false; } ((Character)playerChar).RemoveItemFromInventory(val, (RemoveItemReason)3, true); return true; } public static bool RollDrop(Monster monster) { //IL_00db: 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) if ((Object)(object)monster == (Object)null || monster.loadedAsDead || !((Character)monster).IsMimic() || ((Object)monster).name.IndexOf("mimic", StringComparison.OrdinalIgnoreCase) < 0) { return false; } if (DropRolled.TryGetValue(monster, out var _)) { return false; } DropRolled.Add(monster, DropRolledMarker); if ((Object)(object)LevelGenerator.currentInstance == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"Mimic death hook ran without an active dungeon level; no Mimic Chest was dropped."); return false; } int value2 = PermanentStoragePlugin.MimicChestDropChance.Value; if (value2 <= 0 || Random.Range(0f, 100f) >= (float)value2) { PermanentStoragePlugin.Log.LogInfo((object)("Mimic Chest drop roll failed at " + value2 + "% chance.")); return false; } EnsureRegistered(); if ((Object)(object)Data == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"Mimic died but the Mimic Chest item was not registered."); return false; } try { DroppedItem val = new Item(Data).Drop(((Component)monster).transform.position, true); if ((Object)(object)val == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"Mimic Chest drop roll succeeded, but the game did not create a dropped item object."); return false; } MimicChestDropVisual componentInChildren = ((Component)val).GetComponentInChildren<MimicChestDropVisual>(true); if ((Object)(object)componentInChildren != (Object)null) { componentInChildren.AttachCorpse(((Component)monster).transform); } else { PermanentStoragePlugin.Log.LogWarning((object)"The Mimic Chest dropped without its corpse indicator prefab; the item is still lootable."); } PermanentStoragePlugin.Log.LogInfo((object)"Mimic dropped a Mimic Chest on its corpse."); return true; } catch (Exception ex) { PermanentStoragePlugin.Log.LogError((object)("Mimic Chest drop failed after a successful roll: " + ex)); return false; } } } [HarmonyPatch(typeof(TooltipUI), "ShowTooltip", new Type[] { typeof(Item), typeof(bool), typeof(Character) })] internal static class MimicChestTooltipPatch { [HarmonyPostfix] private static void Postfix(TooltipUI __instance, Item targetItem) { if (targetItem != null && (!(targetItem.refId != "MimicChest") || !(targetItem.itemBaseName != "Mimic Chest"))) { __instance.ShowTooltip("Mimic Chest", "Take this Mimic Chest to the Storage Keeper in the Permanent Storage Room.\n\nTalk to the Keeper and choose Place chest, then left-click to place it. R rotates it; right-click or Esc cancels. The Mimic Chest is consumed when placement succeeds."); } } } internal sealed class MimicChestDropVisual : MonoBehaviour { private Transform corpse; private Transform standInCorpse; public void SetStandInCorpse(Transform body) { standInCorpse = body; if ((Object)(object)body != (Object)null) { corpse = body; } } public void AttachCorpse(Transform body) { //IL_00cb: 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) if ((Object)(object)body == (Object)null) { return; } if ((Object)(object)standInCorpse != (Object)null) { Object.Destroy((Object)(object)((Component)standInCorpse).gameObject); standInCorpse = null; } corpse = body; Collider[] componentsInChildren = ((Component)body).GetComponentsInChildren<Collider>(true); foreach (Collider val in componentsInChildren) { if ((Object)(object)val != (Object)null) { val.enabled = false; } } NavMeshAgent[] componentsInChildren2 = ((Component)body).GetComponentsInChildren<NavMeshAgent>(true); foreach (NavMeshAgent val2 in componentsInChildren2) { if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = false; } } Canvas[] componentsInChildren3 = ((Component)body).GetComponentsInChildren<Canvas>(true); foreach (Canvas val3 in componentsInChildren3) { if ((Object)(object)val3 != (Object)null) { ((Behaviour)val3).enabled = false; } } body.SetParent(((Component)this).transform, false); body.localPosition = Vector3.zero; body.localRotation = Quaternion.identity; PermanentStoragePlugin.Log.LogInfo((object)"Mimic corpse attached to the dropped Mimic Chest."); } } [HarmonyPatch(typeof(Monster), "Die")] internal static class MimicDeathPatch { [HarmonyPostfix] private static void Postfix(Monster __instance) { try { MimicChestItem.RollDrop(__instance); } catch (Exception ex) { PermanentStoragePlugin.Log.LogError((object)("Mimic death hook failed: " + ex)); } } } [HarmonyPatch(typeof(FateDB), "get_AllItems")] internal static class FateDbItemsPatch { [HarmonyPrefix] private static void Prefix() { MimicChestItem.EnsureRegistered(); } } [HarmonyPatch(typeof(Item), "GetItemPrefab")] internal static class MimicItemPrefabPatch { [HarmonyPrefix] private static bool Prefix(Item __instance, ref GameObject __result) { if (__instance == null || (__instance.refId != "MimicChest" && __instance.itemBaseName != "Mimic Chest")) { return true; } GameObject worldDropPrefab = MimicChestItem.GetWorldDropPrefab(); if ((Object)(object)worldDropPrefab != (Object)null) { __result = worldDropPrefab; return false; } return true; } } [HarmonyPatch(typeof(Item), "get_ItemDisplayName")] internal static class MimicItemNamePatch { [HarmonyPostfix] private static void Postfix(Item __instance, ref string __result) { if (__instance != null && __instance.itemBaseName == "Mimic Chest" && string.IsNullOrEmpty(__result)) { __result = "Mimic Chest"; } } } [BepInPlugin("mikhailkillszombies.fate.permanentstorage", "FATE Permanent Storage", "0.7.33")] public sealed class PermanentStoragePlugin : BaseUnityPlugin { public const string Guid = "mikhailkillszombies.fate.permanentstorage"; internal static ManualLogSource Log; internal static ConfigEntry<int> GoldUnlockCost; internal static ConfigEntry<int> MimicChestDropChance; internal static ConfigEntry<string> EntrancePosition; internal static ConfigEntry<string> EntranceOffset; internal static ConfigEntry<int> WallStyle; internal static ConfigEntry<int> FloorStyle; internal static ConfigEntry<string> KeeperName; internal static ConfigEntry<int> KeeperModel; internal static ConfigEntry<string> KeeperModelName; internal static StorageRoomManager Manager; private bool tickErrorReported; private Harmony harmony; private void Awake() { //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Expected O, but got Unknown //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; GoldUnlockCost = ((BaseUnityPlugin)this).Config.Bind<int>("Storage", "GoldUnlockCost", 10000, "Gold required to unlock one storage position. Set to 0 for free gold unlocks."); MimicChestDropChance = ((BaseUnityPlugin)this).Config.Bind<int>("Mimic", "MimicChestDropChance", 35, "Percent chance for a Mimic's ordinary death loot to also include one Mimic Chest. 0 disables the drop."); EntrancePosition = ((BaseUnityPlugin)this).Config.Bind<string>("Entrance", "ManualPosition", "", "Optional exact entrance position as 'x,y,z'; empty places it automatically beside the house behind the fishing dock. Stand where the entrance should be, press F10 to write Player XYZ to the log, and copy those numbers here."); EntranceOffset = ((BaseUnityPlugin)this).Config.Bind<string>("Entrance", "Offset", "0,0,0", "Offset added to the automatic entrance position as 'x,y,z'. Use this to nudge the entrance without setting an exact position."); WallStyle = ((BaseUnityPlugin)this).Config.Bind<int>("Walls", "Style", 0, "Wall tile set for the inside of the storage room, as a 0-based index into every complete dungeon wall set the game ships. Cycle it live with the 'Storage room wall set' slider in FATE Mod Menu, or change this number and the room picks it up within a second."); FloorStyle = ((BaseUnityPlugin)this).Config.Bind<int>("Floors", "Style", 0, "Floor texture set for the inside of the storage room, as a 0-based index into every dungeon floor material the game ships. Cycle it live with the 'Storage room floor set' slider in FATE Mod Menu, or change this number and the room picks it up within a second. The floor is independent of the wall set."); KeeperName = ((BaseUnityPlugin)this).Config.Bind<string>("Storage Keeper", "Name", "Storage Keeper", "Name shown above the Storage Keeper and in the interaction prompt. Edit it live with the 'Storage Keeper name' text box in FATE Mod Menu."); KeeperModel = ((BaseUnityPlugin)this).Config.Bind<int>("Storage Keeper", "Model", 0, "NPC model used by the Storage Keeper, as a 0-based index into the town, merchant, party and curated character models. Cycle it live with the 'Storage Keeper model' slider in FATE Mod Menu."); KeeperModelName = ((BaseUnityPlugin)this).Config.Bind<string>("Storage Keeper", "ModelName", "DreyaTheHealer", "Preferred Storage Keeper model by character name. The default is Dreya the Healer. An empty value falls back to the Model index above. Changing the model slider writes this name so the choice survives scene reloads and model-list changes."); GameObject val = new GameObject("FATE_PermanentStorageManager"); Manager = val.AddComponent<StorageRoomManager>(); Object.DontDestroyOnLoad((Object)val); Log.LogInfo((object)("FATE Permanent Storage 0.7.33 manager created: " + ((Object)(object)Manager != (Object)null) + ".")); try { MimicChestItem.EnsureRegistered(); } catch (Exception ex) { Log.LogError((object)("Mimic Chest item registration failed: " + ex)); } harmony = new Harmony("mikhailkillszombies.fate.permanentstorage"); TryPatchAll(typeof(MimicDeathPatch)); TryPatchAll(typeof(FateDbItemsPatch)); TryPatchAll(typeof(MimicItemPrefabPatch)); TryPatchAll(typeof(MimicItemNamePatch)); TryPatchAll(typeof(MimicChestTooltipPatch)); TryPatchAll(typeof(StoragePlayerUpdatePatch)); PatchStash("FlushStashSave", "Skip", "SkipFlush"); PatchStash("OnInventoryInit", "Skip", "SkipInit"); Log.LogInfo((object)"FATE Permanent Storage 0.7.33 ready. The entrance is at the open spot beside the fishing dock; F10 logs your XYZ."); } private void Update() { if ((Object)(object)Manager == (Object)null) { return; } try { Manager.PluginTick(); } catch (Exception ex) { if (!tickErrorReported) { tickErrorReported = true; Log.LogError((object)("Permanent storage tick failed: " + ex)); } } } private void TryPatchAll(Type patchType) { try { harmony.PatchAll(patchType); } catch (Exception ex) { Log.LogError((object)("Harmony patch " + patchType.Name + " failed: " + ex)); } } private void PatchStash(string methodName, string prefixName, string prefixMethod) { //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Expected O, but got Unknown try { MethodInfo methodInfo = AccessTools.Method(typeof(Stash), methodName, (Type[])null, (Type[])null); if (methodInfo == null) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Stash." + methodName + " is missing; the storage proxy may affect the vanilla stash.")); } else { harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(StashProxyPatches), prefixMethod, (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not patch Stash." + methodName + ": " + ex.Message)); } } } [HarmonyPatch(typeof(Player), "Update")] internal static class StoragePlayerUpdatePatch { private static bool errorReported; private static void Postfix() { try { StorageRoomManager.EnsureRuntime(); if ((Object)(object)StorageRoomManager.Instance != (Object)null) { StorageRoomManager.Instance.PluginTick(); } } catch (Exception ex) { if (!errorReported) { errorReported = true; PermanentStoragePlugin.Log.LogError((object)("Permanent storage Player.Update driver failed: " + ex)); } } } } internal static class StashProxyPatches { public static bool Skip(Stash __instance) { if (!((Object)(object)__instance == (Object)null)) { return (Object)(object)((Component)__instance).GetComponent<StorageStashProxy>() == (Object)null; } return true; } public static bool SkipFlush(Stash __instance) { return Skip(__instance); } public static bool SkipInit(Stash __instance) { return Skip(__instance); } } internal sealed class ChestAnchor { public Vector3 LocalPosition; public Quaternion LocalRotation; } internal sealed class BuiltRoom { public GameObject Root; public Vector3 Spawn; public GameObject ExitDoor; public List<ChestAnchor> Chests = new List<ChestAnchor>(); public NavMeshSurface Surface; public Stash Proxy; } internal struct WallStyle { public TemplateData Template; public int Set; public int Variant; public string Name; } internal struct FloorStyle { public TemplateData Template; public GameObject Prefab; public string Name; } internal static class RoomBuilder { private enum Quadrant { NW, NE, SW, SE } public const int Cells = 6; public const int CeilingTilePadding = 6; private const float CeilingHeight = 3.2f; private const float RoofEdgeOffset = 1.5429688f; private const float ExitDoorLocalX = 3f; private const float ExitDoorLocalZ = -1.5f; private static readonly WallTypes[] QuadrantTypes; private static readonly List<WallStyle> styles; private static readonly List<FloorStyle> floorStyles; private static GameObject wallsRoot; private static GameObject doorwayRoot; private static Vector3 wallOrigin; private static float wallTile; private static int wallDoorCell; private static int wallStyleIndex; private static int floorStyleIndex; private static GameObject floorRoot; private static GameObject roofRoot; private static GameObject ceilingPrefab; private static float ceilingTop; private static float ceilingDelta; private static GameObject roomRoot; private static Vector3 wallShift; private static readonly List<CeilingTileMarker> ceilingMarkers; private static readonly List<WallTileMarker> wallMarkers; private const float WallInset = 0.6f; private static TemplateData floorTemplate; private static int placedThisFill; private static Material cream; private static Material wood; public static int CeilingTileCount => ceilingMarkers.Count; public static int WallTileCount => wallMarkers.Count; public static Vector3 WallOrigin => wallOrigin; public static float WallPlacementHeight => wallOrigin.y + 1.6f; public static float CeilingPlacementHeight => ceilingTop + ceilingDelta; internal static string WallLayoutStyleKey { get { if (styles.Count == 0) { return "fallback"; } WallStyle wallStyle = styles[Mathf.Clamp(wallStyleIndex, 0, styles.Count - 1)]; string text = (((Object)(object)wallStyle.Template != (Object)null) ? wallStyle.Template.templateName : "unknown"); return text + "|set=" + wallStyle.Set + "|variant=" + wallStyle.Variant + "|" + wallStyle.Name; } } public static int WallStyleCount => styles.Count; public static int WallStyleIndex => wallStyleIndex; public static int FloorStyleCount => floorStyles.Count; public static int FloorStyleIndex => floorStyleIndex; public static string FloorStyleName { get { if (floorStyles.Count == 0) { return "none"; } return floorStyles[Mathf.Clamp(floorStyleIndex, 0, floorStyles.Count - 1)].Name; } } public static string WallStyleName { get { if (styles.Count == 0) { return "none"; } return styles[Mathf.Clamp(wallStyleIndex, 0, styles.Count - 1)].Name; } } public static IEnumerable<CeilingTileMarker> CeilingMarkers() { for (int i = ceilingMarkers.Count - 1; i >= 0; i--) { if ((Object)(object)ceilingMarkers[i] == (Object)null) { ceilingMarkers.RemoveAt(i); } else { yield return ceilingMarkers[i]; } } } public static IEnumerable<WallTileMarker> WallMarkers() { for (int i = wallMarkers.Count - 1; i >= 0; i--) { if ((Object)(object)wallMarkers[i] == (Object)null) { wallMarkers.RemoveAt(i); } else { yield return wallMarkers[i]; } } } public static WallTileMarker FirstWallMarker() { using (IEnumerator<WallTileMarker> enumerator = WallMarkers().GetEnumerator()) { if (enumerator.MoveNext()) { return enumerator.Current; } } return null; } public static TemplateData FindGroveTemplate() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) if (!SingletonBehaviour<FateDB>.InstanceExists()) { return null; } TemplateData[] allTemplates = SingletonBehaviour<FateDB>.Instance.allTemplates; if (allTemplates == null) { return null; } TemplateData val = null; TemplateData[] array = allTemplates; foreach (TemplateData val2 in array) { if (!((Object)(object)val2 == (Object)null) && val2.wallSets != null && val2.wallSets.Count != 0 && (int)val2.realmId == 0) { if (!string.IsNullOrEmpty(val2.templateName) && val2.templateName.IndexOf("grove", StringComparison.OrdinalIgnoreCase) >= 0) { return val2; } if ((Object)(object)val == (Object)null) { val = val2; } } } if ((Object)(object)val != (Object)null) { return val; } array = allTemplates; foreach (TemplateData val3 in array) { if ((Object)(object)val3 != (Object)null && val3.wallSets != null && val3.wallSets.Count > 0) { return val3; } } return null; } public unsafe static void InitStyles(TemplateData preferred) { //IL_01be: 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_0456: Unknown result type (might be due to invalid IL or missing references) //IL_045b: Unknown result type (might be due to invalid IL or missing references) //IL_045d: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_04ae: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_051e: Unknown result type (might be due to invalid IL or missing references) styles.Clear(); floorStyles.Clear(); if (!SingletonBehaviour<FateDB>.InstanceExists()) { wallStyleIndex = 0; floorStyleIndex = 0; return; } TemplateData[] allTemplates = SingletonBehaviour<FateDB>.Instance.allTemplates; if (allTemplates == null) { wallStyleIndex = 0; floorStyleIndex = 0; return; } float num = (((Object)(object)preferred != (Object)null && preferred.tileWidth > 0.1f) ? preferred.tileWidth : 2f); List<TemplateData> list = new List<TemplateData>(); if ((Object)(object)preferred != (Object)null) { list.Add(preferred); } TemplateData[] array = allTemplates; foreach (TemplateData val in array) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)preferred) && val.wallSets != null && val.wallSets.Count != 0 && (!(val.tileWidth > 0.1f) || !(Mathf.Abs(val.tileWidth - num) > 0.05f))) { list.Add(val); } } List<TemplateData> list2 = new List<TemplateData>(); if ((Object)(object)preferred != (Object)null) { list2.Add(preferred); } array = allTemplates; foreach (TemplateData val2 in array) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2 == (Object)(object)preferred) && (!(val2.tileWidth > 0.1f) || !(Mathf.Abs(val2.tileWidth - num) > 0.05f))) { list2.Add(val2); } } HashSet<GameObject> hashSet = new HashSet<GameObject>(); foreach (TemplateData item2 in list) { if (item2.wallSets == null) { continue; } for (int j = 0; j < item2.wallSets.Count; j++) { WallSet val3 = item2.wallSets[j]; if (val3 == null) { continue; } bool flag = true; WallTypes[] quadrantTypes = QuadrantTypes; foreach (WallTypes type in quadrantTypes) { List<GameObject> walls = GetWalls(item2, j, type); if (walls == null || walls.Count == 0 || (Object)(object)walls[0] == (Object)null) { flag = false; break; } } if (flag && hashSet.Add(GetWalls(item2, j, (WallTypes)17)[0])) { string text = (string.IsNullOrEmpty(item2.templateName) ? "Dungeon walls" : item2.templateName); if (!string.IsNullOrEmpty(val3.texture)) { text = text + " - " + val3.texture; } else if (item2.wallSets.Count > 1) { text = text + " " + (j + 1); } styles.Add(new WallStyle { Template = item2, Set = j, Variant = 0, Name = text }); } } } if (styles.Count == 0) { PermanentStoragePlugin.Log.LogWarning((object)"No complete dungeon wall set was found; the room falls back to the wooden shell walls."); } HashSet<string> hashSet2 = new HashSet<string>(); foreach (TemplateData item3 in list2) { if ((Object)(object)item3 == (Object)null || item3.floorMaterials == null || item3.floorMaterials.Count == 0) { continue; } GameObject val4 = FindRoomFloorPrefab(item3); if ((Object)(object)val4 == (Object)null) { val4 = FindRoomFloorPrefab(preferred); } if (!((Object)(object)val4 == (Object)null)) { string item = FloorMaterialKey(item3.floorMaterials); if (hashSet2.Add(item)) { string text2 = (string.IsNullOrEmpty(item3.templateName) ? "Dungeon" : item3.templateName); floorStyles.Add(new FloorStyle { Template = item3, Prefab = val4, Name = text2 + " floor" }); } } } if (floorStyles.Count == 0) { HashSet<GameObject> hashSet3 = new HashSet<GameObject>(); foreach (TemplateData item4 in list2) { if (item4.floorPrefabs == null) { continue; } for (int k = 0; k < item4.floorPrefabs.Count; k++) { FloorSet val5 = item4.floorPrefabs[k]; if (!((Object)(object)val5.floorPrefab == (Object)null) && hashSet3.Add(val5.floorPrefab)) { string text3 = (string.IsNullOrEmpty(item4.templateName) ? "Dungeon" : item4.templateName); text3 += " floor"; if ((int)val5.floorType != 0) { text3 = text3 + " (" + ((object)(*(CellTypes*)(&val5.floorType))/*cast due to .constrained prefix*/).ToString() + ")"; } if (item4.floorPrefabs.Count > 1) { text3 = text3 + " " + (k + 1); } floorStyles.Add(new FloorStyle { Template = item4, Prefab = val5.floorPrefab, Name = text3 }); } } } } if (floorStyles.Count == 0) { GameObject val6 = FindRoomFloorPrefab(preferred); if ((Object)(object)val6 != (Object)null) { string text4 = (((Object)(object)preferred != (Object)null && !string.IsNullOrEmpty(preferred.templateName)) ? preferred.templateName : "Dungeon"); floorStyles.Add(new FloorStyle { Template = preferred, Prefab = val6, Name = text4 + " floor" }); } } wallStyleIndex = ClampStyle((PermanentStoragePlugin.WallStyle != null) ? PermanentStoragePlugin.WallStyle.Value : 0); floorStyleIndex = ClampFloor((PermanentStoragePlugin.FloorStyle != null) ? PermanentStoragePlugin.FloorStyle.Value : 0); List<string> list3 = new List<string>(); foreach (WallStyle style in styles) { list3.Add(style.Name); } PermanentStoragePlugin.Log.LogInfo((object)("Storage room wall sets: " + styles.Count + " (" + string.Join(", ", list3.ToArray()) + "); using \"" + WallStyleName + "\".")); List<string> list4 = new List<string>(); foreach (FloorStyle floorStyle in floorStyles) { list4.Add(floorStyle.Name); } PermanentStoragePlugin.Log.LogInfo((object)("Storage room floor sets: " + floorStyles.Count + " (" + string.Join(", ", list4.ToArray()) + "); using \"" + FloorStyleName + "\".")); } private static int ClampStyle(int index) { if (styles.Count == 0) { return 0; } if (index < 0) { index = 0; } if (index >= styles.Count) { index = styles.Count - 1; } return index; } private static int ClampFloor(int index) { if (floorStyles.Count == 0) { return 0; } if (index < 0) { index = 0; } if (index >= floorStyles.Count) { index = floorStyles.Count - 1; } return index; } public static int SetWallStyle(int index) { if (styles.Count == 0) { return 0; } int num = ClampStyle(index); bool flag = num != wallStyleIndex; wallStyleIndex = num; if (flag) { PermanentStoragePlugin.Log.LogInfo((object)("Storage room wall style set to \"" + WallStyleName + "\" (" + wallStyleIndex + "/" + (styles.Count - 1) + ").")); RebuildWalls(); if (floorStyles.Count == 0) { BuildFloor(); } } return num; } public static int SetFloorStyle(int index) { if (floorStyles.Count == 0) { return 0; } int num = ClampFloor(index); bool flag = num != floorStyleIndex; floorStyleIndex = num; if (flag) { PermanentStoragePlugin.Log.LogInfo((object)("Storage room floor style set to \"" + FloorStyleName + "\" (" + floorStyleIndex + "/" + (floorStyles.Count - 1) + ").")); BuildFloor(); } return num; } public static void SyncStyleFromConfig() { if (styles.Count > 0 && PermanentStoragePlugin.WallStyle != null && ClampStyle(PermanentStoragePlugin.WallStyle.Value) != wallStyleIndex) { SetWallStyle(PermanentStoragePlugin.WallStyle.Value); } if (floorStyles.Count > 0 && PermanentStoragePlugin.FloorStyle != null && ClampFloor(PermanentStoragePlugin.FloorStyle.Value) != floorStyleIndex) { SetFloorStyle(PermanentStoragePlugin.FloorStyle.Value); } } private static TemplateData CurrentWallTemplate() { if (styles.Count != 0) { return styles[Mathf.Clamp(wallStyleIndex, 0, styles.Count - 1)].Template; } return floorTemplate; } private static GameObject FindRoomFloorPrefab(TemplateData template) { //IL_0038: 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_003e: 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_0046: 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) if ((Object)(object)template == (Object)null) { return null; } if ((Object)(object)template.newFloorPrefab != (Object)null) { return template.newFloorPrefab; } if (template.floorPrefabs != null) { foreach (FloorSet floorPrefab in template.floorPrefabs) { if ((int)floorPrefab.floorType == 0 && (Object)(object)floorPrefab.floorPrefab != (Object)null) { return floorPrefab.floorPrefab; } } } if (template.floorDictionary == null) { try { template.UpdateFloorDictionary(); } catch (Exception ex) { PermanentStoragePlugin.Log.LogWarning((object)("Could not build the selected theme floor dictionary: " + ex.Message)); } } if (template.floorDictionary != null && template.floorDictionary.TryGetValue((CellTypes)0, out var value) && value != null && value.TryGetValue(key: false, out var value2) && (Object)(object)value2 != (Object)null) { return value2; } return null; } private static void BuildFloor() { //IL_0167: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01ac: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: 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_00ef: 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_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) if ((Object)(object)floorRoot == (Object)null) { return; } for (int num = floorRoot.transform.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)floorRoot.transform.GetChild(num)).gameObject); } FloorStyle floorStyle = ((floorStyles.Count > 0) ? floorStyles[Mathf.Clamp(floorStyleIndex, 0, floorStyles.Count - 1)] : default(FloorStyle)); GameObject val = ((floorStyles.Count > 0) ? floorStyle.Prefab : (FindRoomFloorPrefab(CurrentWallTemplate()) ?? FindRoomFloorPrefab(floorTemplate))); for (int i = -1; i <= 6; i++) { for (int j = -1; j <= 6; j++) { if ((Object)(object)val != (Object)null) { Vector3 val2 = wallOrigin + new Vector3(((float)i + 0.5f) * wallTile, 0f, ((float)j + 0.5f) * wallTile); GameObject tile = Object.Instantiate<GameObject>(val, val2, Quaternion.identity, floorRoot.transform); if (floorStyles.Count > 0) { ApplyFloorMaterials(floorStyle.Template, tile); } } } } if ((Object)(object)val == (Object)null) { float num2 = 6f * wallTile; CreateBox(floorRoot.transform, "FallbackFloor", wallOrigin + new Vector3(num2 * 0.5f, -0.15f, num2 * 0.5f), new Vector3(num2 + wallTile * 2f, 0.3f, num2 + wallTile * 2f), CreamMaterial(), collider: false); } } private static string FloorMaterialKey(List<Material> materials) { List<string> list = new List<string>(); foreach (Material material in materials) { list.Add(((Object)(object)material != (Object)null) ? ((Object)material).GetInstanceID().ToString() : "0"); } return string.Join(",", list.ToArray()); } private static void ApplyFloorMaterials(TemplateData template, GameObject tile) { if ((Object)(object)template == (Object)null || template.floorMaterials == null || template.floorMaterials.Count == 0 || (Object)(object)tile == (Object)null) { return; } MeshRenderer[] componentsInChildren = tile.GetComponentsInChildren<MeshRenderer>(true); foreach (MeshRenderer val in componentsInChildren) { if ((Object)(object)val != (Object)null) { ((Renderer)val).SetMaterials(template.floorMaterials); } } } private unsafe static void FillDoorway() { //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) //IL_0193: 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_012f: Unknown result type (might be due to invalid IL or missing references) PropData val = FindDoorProp(CurrentWallTemplate(), WallStyleName); if ((Object)(object)doorwayRoot != (Object)null) { Object.Destroy((Object)(object)doorwayRoot); } if ((Object)(object)val == (Object)null || (Object)(object)val.modelPrefab == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)("No themed NSDoor/EWDoor prop was found for '" + WallStyleName + "'; leaving the exit opening visible without a door model.")); return; } Vector3 val2 = wallOrigin + new Vector3(3f, 0f, -1.5f); Quaternion val3 = Quaternion.Euler(0f, val.baseRotation + 180f, 0f); doorwayRoot = new GameObject("FATE_StorageRoomThemedDoor"); doorwayRoot.transform.SetParent(((Object)(object)roomRoot != (Object)null) ? roomRoot.transform : null, true); doorwayRoot.transform.SetPositionAndRotation(val2, val3); GameObject val4 = Object.Instantiate<GameObject>(val.modelPrefab, val2, val3, doorwayRoot.transform); float num = Mathf.Max(0f, val.scaleVariation); if (num > 0f) { Transform transform = val4.transform; transform.localScale *= 1f + num * 0.5f; } StorageDoorAudio.TryCacheFromAsset(val.modelPrefab); ManualLogSource log = PermanentStoragePlugin.Log; string[] obj = new string[9] { "Doorway: themed door prop '", val.propName, "' / '", ((Object)val.modelPrefab).name, "' for wall theme '", WallStyleName, "' placed at ", null, null }; Vector3 val5 = val2; obj[7] = ((object)(*(Vector3*)(&val5))/*cast due to .constrained prefix*/).ToString(); obj[8] = "."; log.LogInfo((object)string.Concat(obj)); } private static PropData FindDoorProp(TemplateData preferred, string wallTheme) { List<TemplateData> list = new List<TemplateData>(); if ((Object)(object)preferred != (Object)null) { list.Add(preferred); } if ((Object)(object)floorTemplate != (Object)null && !list.Contains(floorTemplate)) { list.Add(floorTemplate); } try { FateDB val = (SingletonBehaviour<FateDB>.InstanceExists() ? SingletonBehaviour<FateDB>.Instance : null); TemplateData[] array = (((Object)(object)val != (Object)null) ? val.allTemplates : null); if (array != null) { TemplateData[] array2 = array; foreach (TemplateData val2 in array2) { if ((Object)(object)val2 != (Object)null && !list.Contains(val2)) { list.Add(val2); } } } } catch { } PropData val3 = null; int num = int.MinValue; string text = ""; foreach (TemplateData item in list) { if (item.props == null) { continue; } foreach (PropData prop in item.props) { if ((Object)(object)prop == (Object)null || (Object)(object)prop.modelPrefab == (Object)null || prop.locations == null) { continue; } bool flag = prop.locations.Contains((PropLocation)22); bool flag2 = prop.locations.Contains((PropLocation)23); if (flag || flag2) { bool flag3 = (Object)(object)prop.modelPrefab.GetComponentInChildren<Door>(true) != (Object)null; int num2 = ThemeScore(item.templateName, wallTheme, prop); int num3 = (flag ? 100 : 70) + (flag3 ? 60 : 0) + num2; if ((Object)(object)item == (Object)(object)preferred) { num3 += 30; } if (prop.isStairsUp || prop.isStairsDown) { num3 -= 1000; } if (num3 > num) { val3 = prop; num = num3; text = item.templateName; } } } } if ((Object)(object)val3 != (Object)null) { PermanentStoragePlugin.Log.LogInfo((object)("Selected themed door from template '" + text + "' (score=" + num + ").")); } return val3; } private static int ThemeScore(string templateName, string wallTheme, PropData prop) { if (string.IsNullOrEmpty(templateName) || (Object)(object)prop == (Object)null || (Object)(object)prop.modelPrefab == (Object)null) { return 0; } string text = (prop.propName + " " + ((Object)prop.modelPrefab).name + " " + prop.texturePath).ToLowerInvariant(); string[] array = new string[13] { "dungeon", "template", "theme", "door", "prop", "fate", "the", "and", "realms", "ekbatan", "tiletextures", "triad0", "png" }; string[] array2 = (templateName + " " + wallTheme).ToLowerInvariant().Split(new char[8] { ' ', '_', '-', '.', '/', '\\', '(', ')' }, StringSplitOptions.RemoveEmptyEntries); int num = 0; string[] array3 = array2; foreach (string text2 in array3) { if (text2.Length >= 2 && !int.TryParse(text2, out var _) && Array.IndexOf(array, text2) < 0 && text.Contains(text2)) { num += text2.Length + ((text2.Length < 4) ? 1 : 2); } } return num; } private static void RebuildWalls() { if (!((Object)(object)wallsRoot == (Object)null)) { for (int num = wallsRoot.transform.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)wallsRoot.transform.GetChild(num)).gameObject); } FillWalls(); BuildCeilingSurround(); FillDoorway(); } } private static void BuildCeilingSurround() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown //IL_005a: 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_0127: 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) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015a: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_0192: Unknown result type (might be due to invalid IL or missing references) ceilingMarkers.Clear(); if ((Object)(object)roofRoot == (Object)null) { roofRoot = new GameObject("CeilingSurround"); roofRoot.transform.SetParent(((Object)(object)roomRoot != (Object)null) ? roomRoot.transform : null, true); roofRoot.transform.position = wallOrigin; roofRoot.transform.rotation = Quaternion.identity; } for (int num = roofRoot.transform.childCount - 1; num >= 0; num--) { Object.Destroy((Object)(object)((Component)roofRoot.transform.GetChild(num)).gameObject); } GameObject val = FindCeilingPrefab((styles.Count > 0) ? styles[Mathf.Clamp(wallStyleIndex, 0, styles.Count - 1)].Template : null); if ((Object)(object)val == (Object)null) { val = FindCeilingPrefab(floorTemplate); } if ((Object)(object)val == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"No ceiling prefab was found; the room has no ceiling surround."); return; } CeilingOffsets.EnsureLoaded(); float num2 = WallTop(); Vector3 val2 = wallOrigin + wallShift + new Vector3(-2.5f * wallTile, num2, -2.5f * wallTile); GameObject obj = Object.Instantiate<GameObject>(val, val2, Quaternion.identity, roofRoot.transform); float num3 = 0f; Renderer componentInChildren = obj.GetComponentInChildren<Renderer>(); if ((Object)(object)componentInChildren != (Object)null) { float num4 = num2; Bounds bounds = componentInChildren.bounds; num3 = num4 - ((Bounds)(ref bounds)).min.y; } Object.Destroy((Object)(object)obj); ceilingPrefab = val; ceilingTop = num2; ceilingDelta = num3; int num5 = 0; int num6 = 0; for (int i = -6; i < 12; i++) { for (int j = -6; j < 12; j++) { bool flag = IsDefaultCeilingCell(i, j); if (!CeilingOffsets.IsRemoved(i, j) && (flag || CeilingOffsets.IsAdded(i, j)) && !((Object)(object)CreateCeilingTile(i, j) == (Object)null)) { num5++; if (HasCustomCeilingOffset(i, j) || CeilingOffsets.TryGetScale(i, j, out var _) || !flag) { num6++; } } } } PermanentStoragePlugin.Log.LogInfo((object)("Ceiling surround: '" + ((Object)val).name + "' " + num5 + " grid tile(s) at wall-top height " + num2.ToString("0.00") + ((num6 > 0) ? (", " + num6 + " with baked/editor offsets") : "") + ".")); } private static bool IsDefaultCeilingCell(int x, int z) { if (x >= 0 && x < 6 && z >= 0) { return z >= 6; } return true; } private static CeilingTileMarker CreateCeilingTile(int x, int z) { //IL_001c: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //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_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0085: 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_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: 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_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: 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) if ((Object)(object)ceilingPrefab == (Object)null || (Object)(object)roofRoot == (Object)null) { return null; } Vector3 val = wallOrigin + wallShift + new Vector3(((float)x + 0.5f) * wallTile, ceilingTop, ((float)z + 0.5f) * wallTile) + Vector3.up * ceilingDelta + DefaultCeilingEdgeOffset(x, z); Vector3 val2 = SavedCeilingAdjustment(x, z); GameObject val3 = Object.Instantiate<GameObject>(ceilingPrefab, val + val2, Quaternion.identity, roofRoot.transform); CeilingTileMarker ceilingTileMarker = val3.AddComponent<CeilingTileMarker>(); ceilingTileMarker.GridX = x; ceilingTileMarker.GridZ = z; ceilingTileMarker.BaseWorldPosition = val; ceilingTileMarker.BaseLocalScale = val3.transform.localScale; if (CeilingOffsets.TryGetScale(x, z, out var multiplier)) { val3.transform.localScale = Vector3.Scale(ceilingTileMarker.BaseLocalScale, multiplier); } ceilingMarkers.Add(ceilingTileMarker); return ceilingTileMarker; } private static Vector3 DefaultCeilingEdgeOffset(int x, int z) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) bool num = x == -1 || x == 6; bool flag = z == -1 || z == 6; bool flag2 = num && flag; float num2 = (flag2 ? 0.7714844f : 1.5429688f); bool num3 = num && (flag2 || (z >= 0 && z < 6)); bool flag3 = flag && (flag2 || (x >= 0 && x < 6)); float num4 = ((!num3) ? 0f : ((x < 0) ? (0f - num2) : num2)); float num5 = ((!flag3) ? 0f : ((z < 0) ? (0f - num2) : num2)); return new Vector3(num4, 0f, num5); } private static Vector3 SavedCeilingAdjustment(int x, int z) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: 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_001a: Unknown result type (might be due to invalid IL or missing references) if (!CeilingOffsets.TryGet(x, z, out var offset)) { return Vector3.zero; } if (!CeilingOffsets.IsLegacyOffset(x, z)) { return offset; } return CeilingOffsets.NormalizeLegacyOffset(x, z, offset); } private static bool HasCustomCeilingOffset(int x, int z) { //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) Vector3 val = SavedCeilingAdjustment(x, z); return ((Vector3)(ref val)).sqrMagnitude > 0.0001f; } public static CeilingTileMarker InsertCeilingTileAt(Vector3 worldPosition) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)ceilingPrefab == (Object)null || (Object)(object)roofRoot == (Object)null || wallTile <= 0f) { return null; } int num = Mathf.RoundToInt((worldPosition.x - wallOrigin.x - wallShift.x) / wallTile - 0.5f); int num2 = Mathf.RoundToInt((worldPosition.z - wallOrigin.z - wallShift.z) / wallTile - 0.5f); if (num < -6 || num >= 12 || num2 < -6 || num2 >= 12) { return null; } foreach (CeilingTileMarker item in CeilingMarkers()) { if (item.GridX == num && item.GridZ == num2) { return item; } } if (IsDefaultCeilingCell(num, num2)) { if (!CeilingOffsets.IsRemoved(num, num2)) { return null; } CeilingOffsets.SetRemoved(num, num2, removed: false); } else { CeilingOffsets.SetAdded(num, num2, added: true); } CeilingOffsets.Clear(num, num2); CeilingTileMarker result = CreateCeilingTile(num, num2); CeilingOffsets.SaveUser(); return result; } public static void DeleteCeilingTile(CeilingTileMarker marker) { if (!((Object)(object)marker == (Object)null)) { int gridX = marker.GridX; int gridZ = marker.GridZ; if (IsDefaultCeilingCell(gridX, gridZ)) { CeilingOffsets.SetRemoved(gridX, gridZ, removed: true); } else { CeilingOffsets.SetAdded(gridX, gridZ, added: false); } CeilingOffsets.Clear(gridX, gridZ); ceilingMarkers.Remove(marker); Object.Destroy((Object)(object)((Component)marker).gameObject); CeilingOffsets.SaveUser(); } } private static float WallTop() { //IL_0072: 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_007b: 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_005c: 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) float num = wallOrigin.y + 3.2f; if ((Object)(object)wallsRoot == (Object)null) { return num; } bool flag = false; Renderer[] componentsInChildren = wallsRoot.GetComponentsInChildren<Renderer>(); foreach (Renderer val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(val is TrailRenderer) && !(val is LineRenderer)) { Bounds bounds; if (!flag) { bounds = val.bounds; num = ((Bounds)(ref bounds)).max.y; flag = true; } else { float num2 = num; bounds = val.bounds; num = Mathf.Max(num2, ((Bounds)(ref bounds)).max.y); } } } return num; } public static BuiltRoom Build(Vector3 origin, int interactableLayer, StorageRoomManager manager) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0017: 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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00e5: Expected O, but got Unknown //IL_0105: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0151: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0164: 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_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_0211: Unknown result type (might be due to invalid IL or missing references) //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) //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0247: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0266: Unknown result type (might be due to invalid IL or missing references) //IL_026b: Unknown result type (might be due to invalid IL or missing references) //IL_027c: Unknown result type (might be due to invalid IL or missing references) //IL_0294: Unknown result type (might be due to invalid IL or missing references) //IL_02a1: Unknown result type (might be due to invalid IL or missing references) //IL_02a6: 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_02ca: Unknown result type (might be due to invalid IL or missing references) //IL_02da: Unknown result type (might be due to invalid IL or missing references) //IL_02df: Unknown result type (might be due to invalid IL or missing references) //IL_02f9: Unknown result type (might be due to invalid IL or missing references) //IL_030c: Unknown result type (might be due to invalid IL or missing references) //IL_0311: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0373: Unknown result type (might be due to invalid IL or missing references) //IL_0378: Unknown result type (might be due to invalid IL or missing references) //IL_0392: Unknown result type (might be due to invalid IL or missing references) //IL_03a8: Unknown result type (might be due to invalid IL or missing references) //IL_03ad: Unknown result type (might be due to invalid IL or missing references) //IL_03c7: Unknown result type (might be due to invalid IL or missing references) //IL_03dd: Unknown result type (might be due to invalid IL or missing references) //IL_03e2: Unknown result type (might be due to invalid IL or missing references) //IL_03fc: Unknown result type (might be due to invalid IL or missing references) //IL_0412: Unknown result type (might be due to invalid IL or missing references) //IL_0417: Unknown result type (might be due to invalid IL or missing references) //IL_0431: Unknown result type (might be due to invalid IL or missing references) //IL_0447: Unknown result type (might be due to invalid IL or missing references) //IL_044c: Unknown result type (might be due to invalid IL or missing references) //IL_0466: Unknown result type (might be due to invalid IL or missing references) //IL_047c: Unknown result type (might be due to invalid IL or missing references) //IL_0481: Unknown result type (might be due to invalid IL or missing references) //IL_0495: Unknown result type (might be due to invalid IL or missing references) //IL_04a5: Unknown result type (might be due to invalid IL or missing references) //IL_04aa: Unknown result type (might be due to invalid IL or missing references) //IL_04af: Unknown result type (might be due to invalid IL or missing references) //IL_04b6: Unknown result type (might be due to invalid IL or missing references) //IL_04bd: Expected O, but got Unknown //IL_04d7: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_0506: Unknown result type (might be due to invalid IL or missing references) //IL_0510: Unknown result type (might be due to invalid IL or missing references) //IL_0538: Unknown result type (might be due to invalid IL or missing references) //IL_0548: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Unknown result type (might be due to invalid IL or missing references) //IL_0552: Unknown result type (might be due to invalid IL or missing references) //IL_055c: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Expected O, but got Unknown //IL_057d: Unknown result type (might be due to invalid IL or missing references) //IL_05bf: Unknown result type (might be due to invalid IL or missing references) //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b5: Unknown result type (might be due to invalid IL or missing references) //IL_01bb: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Expected O, but got Unknown BuiltRoom builtRoom = new BuiltRoom(); GameObject val = new GameObject("FATE_PermanentStorageRoom"); val.transform.position = origin; val.transform.rotation = Quaternion.identity; builtRoom.Root = val; roomRoot = val; TemplateData val2 = FindGroveTemplate(); if ((Object)(object)val2 == (Object)null) { PermanentStoragePlugin.Log.LogWarning((object)"No Grove dungeon template was found; the storage room will use a simple fallback shell."); } else { PermanentStoragePlugin.Log.LogInfo((object)("Building storage room from dungeon template '" + val2.templateName + "'.")); } InitStyles(val2); float num = (((Object)(object)val2 != (Object)null && val2.tileWidth > 0.1f) ? val2.tileWidth : 2f); float num2 = 6f * num; wallOrigin = origin; wallTile = num; wallDoorCell = Mathf.Clamp(Mathf.FloorToInt(3f / num), 0, 5); floorTemplate = val2; floorRoot = new GameObject("Floor"); floorRoot.transform.SetParent(val.transform, true); floorRoot.transform.position = origin; floorRoot.transform.rotation = Quaternion.identity; BuildFloor(); float num3 = num2 + num * 2f; CreateBox(val.transform, "FloorSafetyCollider", origin + new Vector3(num2 * 0.5f, -0.15f, num2 * 0.5f), new Vector3(num3, 0.3f, num3), null, collider: true); wallOrigin = origin; wallTile = num; if ((Object)(object)val2 != (Object)null && styles.Count > 0) { GameObject val3 = new GameObject("Walls"); val3.transform.SetParent(val.transform, true); val3.transform.position = origin; val3.transform.rotation = Quaternion.identity; wallsRoot = val3; FillWalls(); } else { wallsRoot = null; BuildFallbackWalls(val.transform, origin, num2); } BuildCeilingSurround(); FillDoorway(); float num4 = num2 * 0.5f; float num5 = 1.6f; CreateBox(val.transform, "NorthCollider", origin + new Vector3(num4, num5, num2 + 0.15f), new Vector3(num2, 3.2f, 0.3f), null, collider: true); BuildSouthColliderWithDoorway(val.transform, origin, num2, num5); CreateBox(val.transform, "WestCollider", origin + new Vector3(-0.15f, num5, num4), new Vector3(0.3f, 3.2f, num2), null, collider: true); CreateBox(val.transform, "EastCollider", origin + new Vector3(num2 + 0.15f, num5, num4), new Vector3(0.3f, 3.2f, num2), null, collider: true); AddLight(val.transform, origin + new Vector3(2.5f, 2.7f, 2.5f), 9f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 - 2.5f, 2.7f, 2.5f), 9f, 1.5f); AddLight(val.transform, origin + new Vector3(2.5f, 2.7f, num2 - 2.5f), 9f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 - 2.5f, 2.7f, num2 - 2.5f), 9f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 * 0.25f, 2.7f, num2 * 0.5f), 10f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 * 0.75f, 2.7f, num2 * 0.5f), 10f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 * 0.5f, 2.7f, num2 * 0.25f), 10f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 * 0.5f, 2.7f, num2 * 0.75f), 10f, 1.5f); AddLight(val.transform, origin + new Vector3(num2 * 0.5f, 2.8f, num2 * 0.5f), 14f, 1.8f); Vector3 position = origin + new Vector3(3f, 1.1f, -0.95f); GameObject val4 = new GameObject("FATE_StorageRoomExit"); val4.transform.SetParent(val.transform, true); val4.transform.position = position; val4.transform.rotation = Quaternion.identity; BoxCollider obj = val4.AddComponent<BoxCollider>(); obj.size = new Vector3(1.8f, 2.2f, 0.7f); obj.center = Vector3.zero; val4.layer = interactableLayer; val4.AddComponent<StorageExitDoor>().Init(manager); builtRoom.ExitDoor = val4; builtRoom.Spawn = origin + new Vector3(3f, 0.15f, 1.5f); GameObject val5 = new GameObject("FATE_StorageStashProxy"); val5.transform.SetParent(val.