using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using HarmonyLib; using UnityEngine; using UnityEngine.Networking; using neobotics.ModSdk; using neobotics.ValheimMods; [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("SeidrChest")] [assembly: AssemblyConfiguration("Deploy")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+015ae888807e3a8a8f1d1973bb4422ddcb31a367")] [assembly: AssemblyProduct("SeidrChest")] [assembly: AssemblyTitle("SeidrChest")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] public sealed class ConfigurationManagerAttributes { public delegate void CustomHotkeyDrawerFunc(ConfigEntryBase setting, ref bool isCurrentlyAcceptingInput); public bool? ShowRangeAsPercent; public Action CustomDrawer; public CustomHotkeyDrawerFunc CustomHotkeyDrawer; public bool? Browsable; public string Category; public object DefaultValue; public bool? HideDefaultButton; public bool? HideSettingName; public string Description; public string DispName; public int? Order; public bool? ReadOnly; public bool? IsAdvanced; public Func ObjToStr; public Func StrToObj; } namespace neobotics.ValheimMods { public class Localizer { [HarmonyPatch(typeof(Localization), "SetupLanguage")] private static class Localization_SetupLanguage_Patch { [HarmonyPostfix] private static void Postfix(Localization __instance) { //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown try { if (string.IsNullOrEmpty(LocFolder)) { return; } string selectedLanguage = __instance.GetSelectedLanguage(); string path = Path.Combine(LocFolder, selectedLanguage + ".loc"); if (!File.Exists(path)) { Logging.Instance.Warning("[" + ModName + "] Localization file not found for " + selectedLanguage + ", trying English fallback"); path = Path.Combine(LocFolder, "English.loc"); if (!File.Exists(path)) { Logging.Instance.Warning("[" + ModName + "] English fallback localization file not found"); return; } } TextAsset val = new TextAsset(File.ReadAllText(path)); __instance.LoadCSV(val, selectedLanguage); Logging.Instance.Info("[" + ModName + "] Loaded localization file: " + Path.GetFileName(path)); } catch (Exception ex) { Logging.Instance.Error("Localization load failed: " + ex); } } } internal static string ModName; internal static string LocFolder; public Localizer(string modName) { ModName = modName; LocFolder = ConfigFolderHelper.GetOrCreateModConfigFolder(modName); } public string Localize(string key) { return Localization.instance.Localize(key); } } } namespace neobotics.ModSdk { public class AudioHelper : MonoBehaviour { private readonly Dictionary audioClips = new Dictionary(); private Logging logger; public void Awake() { logger = Logging.GetLogger(); logger.Debug("AudidHelper.Awake"); } public void Start() { logger.Debug("AudioHelper.Start"); ZRoutedRpc.instance.Register("NeoPlayClip", (Action)RPC_NeoPlayClip); } public void RPC_NeoPlayClip(long sender, Vector3 sourcePoint, string clipName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (ZNet.instance.IsDedicated()) { return; } try { NeoPlayClip(sourcePoint, clipName); } catch (Exception e) { logger.Error(e, stackTrace: false); } } public void Play(Vector3 sourcePoint, string clipName) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "NeoPlayClip", new object[2] { sourcePoint, clipName }); } public void NeoPlayClip(Vector3 sourcePoint, string clipName) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) Vector3 position = ((Component)Player.m_localPlayer).transform.position; NeoPlayClip(sourcePoint, position, clipName); } public void NeoPlayClip(Vector3 sourcePoint, Vector3 targetPoint, string clipName) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_003c: 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_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) if (!audioClips.TryGetValue(clipName.ToLower(), out var value)) { logger.Warning("Couldn't find audio clip for " + clipName); return; } Vector3 val = sourcePoint - targetPoint; Vector3 normalized = ((Vector3)(ref val)).normalized; float num = (Vector3.Distance(sourcePoint, targetPoint) + 1f) / 10f; AudioSource.PlayClipAtPoint(value, targetPoint + normalized * num, 1f); } public float GetClipDuration(string clipName) { if (!audioClips.TryGetValue(clipName.ToLower(), out var value)) { return -1f; } return value.length; } internal void LoadAudioResources(string resourceFolder) { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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) audioClips.Clear(); logger.Debug("LoadAudioResources"); string[] files = Directory.GetFiles(resourceFolder, "*.*", SearchOption.TopDirectoryOnly); foreach (string text in files) { string text2 = Path.GetExtension(text).ToLowerInvariant(); AudioType val = (AudioType)0; if (!(text2 == ".wav")) { if (text2 == ".mp3") { val = (AudioType)13; } } else { val = (AudioType)20; } if ((int)val != 0) { ((MonoBehaviour)this).StartCoroutine(LoadExternalClip(text, val)); } } } private IEnumerator LoadExternalClip(string filePath, AudioType type) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) string uri = new Uri(filePath).AbsoluteUri; string clipName = Path.GetFileName(filePath).ToLowerInvariant(); UnityWebRequest req = UnityWebRequestMultimedia.GetAudioClip(uri, type); yield return req.SendWebRequest(); if ((int)req.result == 1) { AudioClip content = DownloadHandlerAudioClip.GetContent(req); audioClips[clipName] = content; logger.Debug("Loaded external audio: " + clipName); } else { logger.Warning("Failed to load external audio: " + uri); } } } internal class CircularList { private List circle; private int index; public int Index => index; public CircularList(List source, T startingElement) { circle = new List(source); index = circle.FindIndex((T x) => x.Equals(startingElement)); } public T Next() { index = ((index < circle.Count - 1) ? (index + 1) : 0); return circle[index]; } public T Previous() { index = ((index > 0) ? (index - 1) : (circle.Count - 1)); return circle[index]; } } public static class ConfigFolderHelper { private const string ROOT = "Neobotics"; public static string GetOrCreateModConfigFolder(string modName) { string text = Path.Combine(Paths.ConfigPath, "Neobotics", modName); Directory.CreateDirectory(text); return text; } } public class ConfigMock { public bool Value { get; set; } } public class CrossPlatformRandom : Random { private const int LCG_MULTIPLIER = 134775813; private const int LCG_INCREMENT = 1; private int _seed; public float value => (float)NextDouble(); public CrossPlatformRandom() { Random random = new Random(); _seed = random.Next(); } public CrossPlatformRandom(int seed) { _seed = seed; } public float Range(int min, int max) { return Next(min, max); } public float Range(float min, float max) { return Mathf.Lerp(min, max, (float)NextDouble()); } private int GetNext() { _seed = _seed * 134775813 + 1; return _seed; } public override int Next() { return Next(int.MaxValue); } public override int Next(int maxValue) { if (maxValue < 0) { throw new ArgumentOutOfRangeException("maxValue is less than zero."); } return (int)((long)(uint)GetNext() * (long)(uint)maxValue >>> 32); } public override int Next(int minValue, int maxValue) { if (minValue > maxValue) { throw new ArgumentOutOfRangeException("minValue is greater than maxValue."); } return minValue + Next(maxValue - minValue); } public override double NextDouble() { return Sample(); } protected override double Sample() { return (double)Next() / 2147483647.0; } } internal class CustomDataWrapper { private Dictionary playerData; private Dictionary Data { get; set; } public CustomDataWrapper(Dictionary sourceData, string keyPrefix) { CustomDataWrapper customDataWrapper = this; playerData = sourceData; Data = new Dictionary(); sourceData.Keys.ToList().ForEach(delegate(string key) { if (key.StartsWith(keyPrefix)) { customDataWrapper.Data.Add(key, sourceData[key]); } }); } public void Add(string key, string value) { Data.Add(key, value); playerData.Add(key, value); } public bool Remove(string key) { return Data.Remove(key) & playerData.Remove(key); } public void Set(string key, string value) { if (Data.ContainsKey(key)) { Data[key] = value; } else { Data.Add(key, value); } if (playerData.ContainsKey(key)) { playerData[key] = value; } else { playerData.Add(key, value); } } public string Get(string key) { if (Data.ContainsKey(key)) { return Data[key]; } return null; } public bool ContainsKey(string key) { return Data.ContainsKey(key); } public void PreSaveSync() { foreach (KeyValuePair datum in Data) { if (!playerData.ContainsKey(datum.Key)) { playerData.Add(datum.Key, datum.Value); } } } } internal class DebugUtils { internal static void ObjectInspector(object o) { if (o == null) { Debug.Log((object)"Object is null"); return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type type = o.GetType(); Debug.Log((object)("Object: " + o.ToString() + " Type " + type.Name)); PropertyInfo[] properties = type.GetProperties(bindingAttr); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.CanRead) { Debug.Log((object)$"Property: {type.Name}.{propertyInfo.Name} = {propertyInfo.GetValue(o)}"); continue; } Debug.Log((object)("Property: " + type.Name + "." + propertyInfo.Name + " is write-only")); } FieldInfo[] fields = type.GetFields(bindingAttr); foreach (FieldInfo field in fields) { FieldPrinter(o, type, field); } } internal static void MethodInspector(object o) { if (o == null) { Debug.Log((object)"Object is null"); return; } BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic; Type type = o.GetType(); Debug.Log((object)("Method: " + o.ToString() + " Type " + type.Name)); MethodInfo[] methods = type.GetMethods(bindingAttr); foreach (MethodInfo methodInfo in methods) { methodInfo.GetParameters(); string arg = string.Join(", ", (from x in methodInfo.GetParameters() select x.ParameterType?.ToString() + " " + x.Name).ToArray()); Debug.Log((object)$"{methodInfo.ReturnType} {methodInfo.Name} ({arg})"); } } private static void ItemDataInspector(ItemData item) { ObjectInspector(item); ObjectInspector(item?.m_shared); } private static void FieldPrinter(object o, Type t, FieldInfo field) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Expected O, but got Unknown try { if (field.FieldType == typeof(ItemData)) { ItemData val = (ItemData)field.GetValue(o); if (val != null) { ItemDataInspector(val); } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else if (field.FieldType == typeof(Transform)) { Transform val2 = (Transform)field.GetValue(o); if ((Object)(object)val2 != (Object)null) { Debug.Log((object)("\tTransform.parent = " + ((Object)val2.parent).name)); } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else if (field.FieldType == typeof(EffectList)) { EffectList val3 = (EffectList)field.GetValue(o); if (val3 != null) { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}:"); EffectData[] effectPrefabs = val3.m_effectPrefabs; foreach (EffectData val4 in effectPrefabs) { Debug.Log((object)("\tEffectData.m_prefab = " + ((Object)val4.m_prefab).name)); } } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)} [null]"); } } else { Debug.Log((object)$"{t.Name}.{field.Name} = {field.GetValue(o)}"); } } catch (Exception) { Debug.Log((object)("Exception accessing " + t?.Name + "." + field?.Name)); } } internal static void GameObjectInspector(GameObject go) { if ((Object)(object)go == (Object)null) { Debug.Log((object)"\n\nGame Object is null"); return; } Debug.Log((object)("\n\nInspecting GameObject " + ((Object)go).name)); ObjectInspector(go); Component[] componentsInChildren = go.GetComponentsInChildren(); if (componentsInChildren.Length == 0) { return; } Component[] array = componentsInChildren; foreach (Component c in array) { try { ComponentInspector(c); } catch (Exception) { } } } internal static void PrintList(List l) { foreach (T item in l) { Debug.Log((object)item.ToString()); } } internal static void ComponentInspector(Component c) { string obj = ((c != null) ? ((Object)c).name : null); object obj2; if (c == null) { obj2 = null; } else { Transform transform = c.transform; if (transform == null) { obj2 = null; } else { Transform parent = transform.parent; obj2 = ((parent != null) ? ((Object)parent).name : null); } } Debug.Log((object)("\n\nInspecting Component " + obj + " with parent " + (string?)obj2)); ObjectInspector(c); } internal static void EffectsInspector(EffectList e) { EffectData[] effectPrefabs = e.m_effectPrefabs; Debug.Log((object)$"Effect list has effects {e.HasEffects()} count {effectPrefabs.Length}"); EffectData[] array = effectPrefabs; foreach (EffectData val in array) { Debug.Log((object)$"Effect Data {val} prefab name {((Object)val.m_prefab).name} prefab GameObject name {((Object)val.m_prefab.gameObject).name}"); } } internal static void PrintInventory() { foreach (ItemData allItem in ((Humanoid)Player.m_localPlayer).GetInventory().GetAllItems()) { Debug.Log((object)allItem.m_shared.m_name); } } internal static void PrintAllObjects() { ZNetScene.instance.m_prefabs.ForEach(delegate(GameObject x) { Debug.Log((object)("GameObject " + ((Object)x).name)); }); } internal static void PrintAllCharacters() { Character.GetAllCharacters().ForEach(delegate(Character x) { Debug.Log((object)("Character " + ((Object)x).name)); }); } internal static void PrintAllLayers() { string[] array = (from index in Enumerable.Range(0, 31) select LayerMask.LayerToName(index) into l where !string.IsNullOrEmpty(l) select l).ToArray(); foreach (string text in array) { Debug.Log((object)("Layer " + text + " " + Convert.ToString(LayerMask.NameToLayer(text), 2).PadLeft(32, '0'))); } } } public class DelegatedConfigEntry : DelegatedConfigEntryBase { private ConfigEntry _entry; private EventHandler rootHandler; private Action clientDelegate; private Logging Log; public ConfigEntry ConfigEntry { get { return _entry; } set { _entry = value; if (_entry != null && rootHandler != null) { _entry.SettingChanged += rootHandler; } Name = ((ConfigEntryBase)_entry).Definition.Key; Section = ((ConfigEntryBase)_entry).Definition.Section; ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue(); Log.Trace("Set " + Section + " " + Name + " to serialized value " + ServerValue); } } public T Value { get { return _entry.Value; } set { _entry.Value = value; } } public DelegatedConfigEntry(bool useServerDelegate = false) : this((Action)null, useServerDelegate) { } public DelegatedConfigEntry(Action delegateHandler, bool useServerDelegate = false) { Log = Logging.GetLogger(); Log.Trace("DelegatedConfigEntry"); if (delegateHandler != null) { clientDelegate = delegateHandler; } if (useServerDelegate) { Log.Trace("Configuring server delegate"); rootHandler = delegate(object s, EventArgs e) { ServerDelegate(s, e); }; ServerConfiguration.ServerDelegatedEntries.Add(this); } else if (clientDelegate != null) { rootHandler = delegate(object s, EventArgs e) { clientDelegate(s, e); }; } } private void ServerDelegate(object sender, EventArgs args) { //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Expected O, but got Unknown Logging.GetLogger().Trace("ServerDelegate"); _entry.SettingChanged -= rootHandler; ZNet instance = ZNet.instance; bool? flag = ((instance != null) ? new bool?(instance.IsServer()) : ((bool?)null)); if (flag.HasValue) { if (flag == false && ServerConfiguration.Instance.ReceivedServerValues) { if (ServerValue != null) { ((ConfigEntryBase)_entry).SetSerializedValue(ServerValue); Log.Debug("Setting " + Name + " to server value " + ServerValue); } } else if (flag == true) { ServerValue = ((ConfigEntryBase)_entry).GetSerializedValue(); ServerConfiguration.Instance.SendConfigToAllClients(sender, (SettingChangedEventArgs)args); } } if (clientDelegate != null) { clientDelegate(sender, args); } _entry.SettingChanged += rootHandler; } public void EnableHandler(bool setActive) { if (setActive) { _entry.SettingChanged += rootHandler; } else { _entry.SettingChanged -= rootHandler; } } public bool IsKeyPressed() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry val) { return InputEvaluator.IsPressed(val.Value); } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } public bool IsKeyDown() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry val) { return InputEvaluator.IsDown(val.Value); } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } public bool IsKeyReleased() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) if (ConfigEntry is ConfigEntry val) { return InputEvaluator.IsReleased(val.Value); } Log.Error("Keyboard read attempted on non-KeyboardShortcut config."); return false; } } public class DelegatedConfigEntryBase { public string Name; public string Section; public string ServerValue; } internal class HarmonyHelper { public enum PatchType { Prefix, Postfix, Transpiler, Finalizer } private static Dictionary detectionSet = new Dictionary(); private static Dictionary unpatchMods = new Dictionary(); public static IReadOnlyDictionary DetectionSet => detectionSet; public static void GetDetectionSet(Dictionary harmonyIds) { Logging logger = Logging.GetLogger(); foreach (KeyValuePair harmonyId in harmonyIds) { if (Harmony.HasAnyPatches(harmonyId.Key)) { logger.Debug("Detected " + harmonyId.Value + " from Harmony"); if (!detectionSet.ContainsKey(harmonyId.Key)) { detectionSet.Add(harmonyId.Key, harmonyId.Value); } } else if (Chainloader.PluginInfos.ContainsKey(harmonyId.Key)) { logger.Debug("Detected " + harmonyId.Value + " from BepInEx"); if (!detectionSet.ContainsKey(harmonyId.Key)) { detectionSet.Add(harmonyId.Key, harmonyId.Value); } } } } public static void AddToUnpatch(string key) { if (detectionSet.ContainsKey(key)) { unpatchMods.Add(key, detectionSet[key]); } } public static void UnpatchMods(Harmony harmony) { Logging logger = Logging.GetLogger(); foreach (KeyValuePair unpatchMod in unpatchMods) { logger.Warning("Not compatible with " + unpatchMod.Value); Harmony.UnpatchID(unpatchMod.Key); detectionSet.Remove(unpatchMod.Key); logger.Warning("Disabled " + unpatchMod.Value); } } public static bool IsModDetected(string key) { return detectionSet.ContainsKey(key); } public static bool IsModNameDetected(string value) { return detectionSet.ContainsValue(value); } public static bool TryGetDetectedModName(string key, out string mod) { return detectionSet.TryGetValue(key, out mod); } public static bool TryGetDetectedModKey(string value, out string key) { key = null; foreach (string key2 in detectionSet.Keys) { if (detectionSet[key2] == value) { key = key2; return true; } } return false; } public static string AddAnonymousPatch(string baseMethodName, PatchType patchType, string modName, string patchMethodName = null) { string text = null; int num = 0; Logging logger = Logging.GetLogger(); foreach (MethodBase item in Harmony.GetAllPatchedMethods().ToList()) { MethodBaseExtensions.HasMethodBody(item); Patches patchInfo = Harmony.GetPatchInfo(item); ReadOnlyCollection readOnlyCollection = patchInfo.Prefixes; switch (patchType) { case PatchType.Postfix: readOnlyCollection = patchInfo.Postfixes; break; case PatchType.Prefix: readOnlyCollection = patchInfo.Prefixes; break; case PatchType.Transpiler: readOnlyCollection = patchInfo.Transpilers; break; case PatchType.Finalizer: readOnlyCollection = patchInfo.Finalizers; break; } foreach (Patch item2 in readOnlyCollection) { if (!item2.owner.StartsWith("harmony-auto") || !(item.Name == baseMethodName)) { continue; } if (patchMethodName != null) { if (item2.PatchMethod.Name == patchMethodName) { num++; text = item2.owner; } } else { num++; text = item2.owner; } } if (num == 1) { detectionSet.Add(text, modName); logger.Info($"Added unique anonymous {baseMethodName} {patchType}: {text} as {modName}"); } else if (num > 1) { text = null; logger.Warning($"Found multiple anonymous {baseMethodName} {patchType} entries. Can't identify correct patch to remove or modify."); } } if (num == 0) { logger.Info("No patch found for " + modName); } return text; } } public class ImageHelper { private readonly string externalFolder; private readonly Logging logger; public ImageHelper(string externalFolder) { this.externalFolder = externalFolder; logger = Logging.GetLogger(); } public Sprite LoadSprite(string name, int width, int height, bool linear = false, float pixelsPerUnit = 100f) { logger.Debug("Reading image and creating sprite " + name); if (TryLoadImage(name, width, height, linear, out var image)) { return LoadSprite(image, pixelsPerUnit); } return null; } public Sprite LoadSprite(Texture2D texture, float pixelsPerUnit = 100f) { return LoadSprite(texture, ((Object)texture).name, ((Texture)texture).width, ((Texture)texture).height, pixelsPerUnit); } public Sprite LoadSprite(Texture2D texture, string name, float width, float height, float pixelsPerUnit = 100f) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null) { return null; } if (string.IsNullOrWhiteSpace(name)) { name = ((Object)texture).name; } logger.Debug("Creating sprite " + name + " from existing texture"); Sprite obj = Sprite.Create(texture, new Rect(0f, 0f, width, height), Vector2.zero, pixelsPerUnit); if ((Object)(object)obj == (Object)null) { throw new ApplicationException("Can't create sprite " + name); } ((Object)obj).name = name; return obj; } public bool TryLoadImage(string name, int width, int height, bool linear, out Texture2D image) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown image = null; string text = Path.Combine(externalFolder, name); logger.Debug("Reading external file " + text); if (!File.Exists(text)) { throw new FileNotFoundException("Cannot find image " + name); } byte[] array = File.ReadAllBytes(text); Texture2D val = new Texture2D(width, height, (TextureFormat)4, true, linear); if (!ImageConversion.LoadImage(val, array, false)) { throw new FileLoadException("Can't load image " + name); } image = val; return true; } } internal class InputCycler { private static InputCycler _instance; private bool useMouseWheel; private DelegatedConfigEntry keyAdvance; private DelegatedConfigEntry keyReferse; public static InputCycler Instance { get { if (_instance == null) { _instance = new InputCycler(); } return _instance; } } private InputCycler() { } public void Init(bool useMouseWheel, DelegatedConfigEntry keyAdvance, DelegatedConfigEntry keyReverse = null) { this.useMouseWheel = useMouseWheel; this.keyAdvance = keyAdvance; keyReferse = keyReverse; } } internal static class InputEvaluator { public unsafe static bool IsPressed(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) object obj = KeyboardShortcut.Empty; if (((object)(*(KeyboardShortcut*)(&shortcut))/*cast due to .constrained prefix*/).Equals(obj)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if ((int)modifier != 0 && !Input.GetKey(modifier)) { return false; } } return Input.GetKeyDown(((KeyboardShortcut)(ref shortcut)).MainKey); } public unsafe static bool IsDown(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) object obj = KeyboardShortcut.Empty; if (((object)(*(KeyboardShortcut*)(&shortcut))/*cast due to .constrained prefix*/).Equals(obj)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if ((int)modifier != 0 && !Input.GetKey(modifier)) { return false; } } return Input.GetKey(((KeyboardShortcut)(ref shortcut)).MainKey); } public unsafe static bool IsReleased(KeyboardShortcut shortcut) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) object obj = KeyboardShortcut.Empty; if (((object)(*(KeyboardShortcut*)(&shortcut))/*cast due to .constrained prefix*/).Equals(obj)) { return false; } foreach (KeyCode modifier in ((KeyboardShortcut)(ref shortcut)).Modifiers) { if ((int)modifier != 0 && !Input.GetKeyUp(modifier)) { return false; } } return Input.GetKeyUp(((KeyboardShortcut)(ref shortcut)).MainKey); } } public class IterativeStopwatch : Stopwatch { private double startMillis; private Logging Log = Logging.GetLogger(); public long Iterations { get; private set; } public double IterationMicroseconds { get; private set; } public double TotalElapsedMicroseconds { get; private set; } public double IterationMilliseconds { get; private set; } public double TotalElapsedMilliseconds { get; private set; } public double AverageMicroseconds { get; private set; } public double AverageMilliseconds { get; private set; } public IterativeStopwatch() { Iterations = 0L; } public new void Start() { startMillis = base.Elapsed.TotalMilliseconds; base.Start(); } public new void Stop() { if (base.IsRunning) { base.Stop(); Iterations++; IterationMilliseconds = base.Elapsed.TotalMilliseconds - startMillis; IterationMicroseconds = IterationMilliseconds * 1000.0; TotalElapsedMilliseconds = base.Elapsed.TotalMilliseconds; TotalElapsedMicroseconds = base.Elapsed.TotalMilliseconds * 1000.0; AverageMilliseconds = TotalElapsedMilliseconds / (double)Iterations; AverageMicroseconds = TotalElapsedMicroseconds / (double)Iterations; } } public new void Reset() { startMillis = 0.0; Iterations = 0L; base.Reset(); } public new void Restart() { startMillis = 0.0; Iterations = 0L; base.Restart(); } } public static class JsonHelper { [Serializable] private class JsonWrapper { public T[] Items; } public static T[] FromJson(string json) { return JsonUtility.FromJson>(json).Items; } public static string ToJson(T[] array) { return JsonUtility.ToJson((object)new JsonWrapper { Items = array }); } public static string ToJson(T[] array, bool prettyPrint) { return JsonUtility.ToJson((object)new JsonWrapper { Items = array }, prettyPrint); } } public class Logging { internal enum LogLevels { Critical, Error, Warning, Info, Debug, Trace } private static Logging _instance; public static Logging Instance { get { if (_instance == null) { throw new InvalidOperationException("Logging.Instance was accessed before initialization. Call Logging.Initialize() in your mod's startup code first."); } return _instance; } private set { _instance = value; } } internal LogLevels LogLevel { get; set; } internal string ModName { get; private set; } private Logging(LogLevels level, string name) { LogLevel = level; ModName = name; } internal static Logging Initialize(LogLevels level, string name) { if (_instance != null) { Instance.Warning("Logger is already initialized. Using existing logger"); return _instance; } Instance = new Logging(level, name); return _instance; } internal static Logging GetLogger(LogLevels level, string name) { if (_instance == null) { Initialize(level, name); } return Instance; } internal static Logging GetLogger() { return Instance; } internal void Trace(string msg) { if (LogLevel >= LogLevels.Trace) { Debug.Log((object)Message(msg)); } } internal void Debug(string msg) { if (LogLevel >= LogLevels.Debug) { Debug.Log((object)Message(msg)); } } internal void Info(string msg) { if (LogLevel >= LogLevels.Info) { Debug.Log((object)Message(msg)); } } internal void Warning(string msg) { if (LogLevel >= LogLevels.Warning) { Debug.LogWarning((object)Message(msg)); } } internal void Error(string msg) { if (LogLevel >= LogLevels.Error) { Debug.LogWarning((object)Message(msg)); } } internal void Error(Exception e) { Error(e, stackTrace: false); } internal void Error(Exception e, bool stackTrace) { if (LogLevel >= LogLevels.Error) { Warning(Message(e.Message)); if (stackTrace) { Warning(e.StackTrace); } } } internal void Critical(Exception e) { if (LogLevel >= LogLevels.Critical) { Debug(Message(e.Message)); Error(e.StackTrace); } } private string Message(string msg) { return ModName + ": " + msg; } internal bool Testing() { return Instance.LogLevel >= LogLevels.Debug; } internal static void ChangeLogging(object s, EventArgs e) { ConfigEntry val = s as ConfigEntry; if (_instance != null) { Instance.LogLevel = val.Value; Instance.Info($"Change {((ConfigEntryBase)val).Definition.Key} to {val.Value}"); } } } public static class ModResourceBootstrap { public static string InitializeModResources(Type pluginType, string modName) { string orCreateModConfigFolder = ConfigFolderHelper.GetOrCreateModConfigFolder(modName); Logging.Instance.Debug("Mod config folder: " + orCreateModConfigFolder); string prefix = modName + ".Resources."; Logging.Instance.Debug("Mod resources: " + orCreateModConfigFolder); ExtractResources(pluginType.Assembly, prefix, orCreateModConfigFolder); return orCreateModConfigFolder; } private static void ExtractResources(Assembly asm, string prefix, string targetFolder) { Logging.Instance.Debug("Checking resources for " + prefix); string[] manifestResourceNames = asm.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { Logging.Instance.Debug("Resource " + text); if (!text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { continue; } string text2 = text.Substring(prefix.Length); string text3 = Path.Combine(targetFolder, text2); Logging.Instance.Debug("Extracting " + text2 + " to " + text3); if (File.Exists(text3)) { continue; } using Stream stream = asm.GetManifestResourceStream(text); using FileStream destination = File.Create(text3); stream.CopyTo(destination); } } } public class ServerConfiguration { [HarmonyPatch(typeof(ZNet), "StopAll")] private static class ZNet_Shutdown_Patch { [HarmonyPrefix] private static void ZNet_StopAll_Prefix(ZNet __instance) { if (_instance != null) { Log.Debug("ZNet_StopAll_Patch_Prefix"); _instance.ReceivedServerValues = false; } } } [HarmonyPatch(typeof(ZNet), "OnNewConnection")] private static class ZNet_OnNewConnection_Patch { private static void Postfix(ZNet __instance, ZNetPeer peer) { Log.Debug("ZNet OnNewConnection postfix"); if (!__instance.IsServer()) { try { peer.m_rpc.Register("ClientConfigReceiver." + GetPluginGuid(), (Action)Instance.RPC_ClientConfigReceiver); Log.Debug("Player registered RPC_ClientConfigReceiver"); return; } catch (Exception) { Log.Warning("Failed to register RPC"); return; } } try { Instance.SendConfigToClient(peer); } catch (Exception) { Log.Warning("Error sending server configuration to client"); } } } public static List ServerDelegatedEntries = new List(); private static ConfigFile LocalConfig; private static BaseUnityPlugin Mod; private static string ConfigFileName; private static ServerConfiguration _instance; private static Logging Log; public bool IsSetup; public bool ReceivedServerValues; public FileSystemWatcher ConfigWatcher; private const string NOT_CONFIGURED = "ServerConfiguration not initialized. Setup first."; public static ServerConfiguration Instance { get { if (_instance == null) { _instance = new ServerConfiguration(); } return _instance; } } private ServerConfiguration() { } public void Setup(ConfigFile config, BaseUnityPlugin modInstance) { LocalConfig = config; Log = Logging.GetLogger(); Log.Trace("ServerConfiguration Setup"); Mod = modInstance; ConfigFileName = Path.GetFileName(LocalConfig.ConfigFilePath); IsSetup = true; } public void CreateConfigWatcher() { ConfigWatcher = Utils.CreateFileWatcher(LocalConfig.ConfigFilePath, LoadConfig); } private void LoadConfig(object sender, FileSystemEventArgs e) { if (!File.Exists(LocalConfig.ConfigFilePath)) { return; } try { Log.Debug($"Loading configuration {e.ChangeType}"); LocalConfig.Reload(); } catch { Log.Error("Error loading configuration file " + ConfigFileName); } } public static string GetPluginGuid() { return Mod.Info.Metadata.GUID; } public void RPC_ClientConfigReceiver(ZRpc zrpc, ZPackage package) { if (!Instance.IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); return; } Log.Debug("ClientConfigReceiver"); string section; string name; while (package.GetPos() < package.Size()) { section = package.ReadString(); name = package.ReadString(); string text = package.ReadString(); Log.Trace("Reading " + section + " " + name + " value " + text + " from ZPackage"); DelegatedConfigEntryBase delegatedConfigEntryBase = ServerDelegatedEntries.Find((DelegatedConfigEntryBase e) => e.Name == name && e.Section == section); if (delegatedConfigEntryBase != null) { Log.Trace("Found DCEB on client and setting to server value " + text); delegatedConfigEntryBase.ServerValue = text; } ConfigEntryBase val = LocalConfig[section, name]; if (val != null) { Log.Trace("Found local CEB and setting underlying config value " + text); val.SetSerializedValue(text); } } ReceivedServerValues = true; } internal void WriteConfigEntries(ZPackage zpkg) { foreach (DelegatedConfigEntryBase serverDelegatedEntry in ServerDelegatedEntries) { Log.Trace("Writing " + serverDelegatedEntry.Section + " " + serverDelegatedEntry.Name + " value " + serverDelegatedEntry.ServerValue + " to ZPackage"); zpkg.Write(serverDelegatedEntry.Section); zpkg.Write(serverDelegatedEntry.Name); zpkg.Write(serverDelegatedEntry.ServerValue); } } internal void SendConfigToClient(ZNetPeer peer) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown if (!Instance.IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); return; } Log.Debug("SendConfigToClient"); ZPackage val = new ZPackage(); WriteConfigEntries(val); peer.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { val }); Log.Trace("Invoked ClientConfigReceiver on peer"); } public void SendConfigToAllClients(object o, SettingChangedEventArgs e) { //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown if (!IsSetup) { Log.Error("ServerConfiguration not initialized. Setup first."); } else if ((Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer() && ZNet.instance.GetPeerConnections() > 0) { Log.Debug("SendConfigToAllClients"); ZPackage zpkg = new ZPackage(); WriteConfigEntries(zpkg); ((MonoBehaviour)Mod).StartCoroutine(_instance.Co_BroadcastConfig(zpkg)); } } private IEnumerator Co_BroadcastConfig(ZPackage zpkg) { Log.Debug("Co_BroadcastConfig"); List connectedPeers = ZNet.instance.GetConnectedPeers(); foreach (ZNetPeer item in connectedPeers) { if (item != ZNet.instance.GetServerPeer()) { item.m_rpc.Invoke("ClientConfigReceiver." + GetPluginGuid(), new object[1] { zpkg }); Log.Trace("Invoked ClientConfigReceiver on peer"); } yield return null; } } } public class Utils { public static TEnum Guardrails(string value, TEnum enumDefault) where TEnum : struct { if (Enum.TryParse(value, ignoreCase: true, out var result)) { return result; } return enumDefault; } public static int Guardrails(int value, int lbound, int ubound) { if (value < lbound) { return lbound; } if (value > ubound) { return ubound; } return value; } public static string Truncate(string value, int maxChars) { if (value == null) { return null; } if (value.Length <= maxChars) { return value; } return value.Substring(0, maxChars); } public static void GetCharactersInRangeXZ(Vector3 point, float radius, List characters) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) float num = radius * radius; foreach (Character s_character in Character.s_characters) { if (DistanceSqrXZ(((Component)s_character).transform.position, point) < num) { characters.Add(s_character); } } } public static PinData GetClosestPin(Vector3 pos, float radius, PinType pType) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0053: 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_007b: 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) PinData result = null; float num = float.MaxValue; float num2 = radius * radius; if ((Object)(object)Minimap.instance != (Object)null) { foreach (PinData pin in Minimap.instance.m_pins) { if ((Object)(object)pin.m_uiElement != (Object)null && pin.m_type == pType) { float num3 = DistanceSqrXZ(pos, pin.m_pos); if (Logging.Instance.LogLevel >= Logging.LogLevels.Debug) { Logging.Instance.Debug($"Testing for pin at {pin.m_pos} within radius {radius} from {pos}"); } if (num3 < num2 && num3 < num) { Logging.Instance.Debug("Pin is within radius"); num = num3; result = pin; } } } } return result; } public static float DistanceSqr(Vector3 v0, Vector3 v1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) Vector3 val = v1 - v0; return ((Vector3)(ref val)).sqrMagnitude; } public static float DistanceSqrXZ(Vector3 v0, Vector3 v1) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) float num = v1.x - v0.x; float num2 = v1.z - v0.z; return num * num + num2 * num2; } public static Vector3 ClosestPoint(Vector3 point, IEnumerable collection, Func selector) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) Vector3 result = default(Vector3); float num = float.MaxValue; foreach (T item in collection) { Vector3 val = selector(item); Vector3 val2 = val - point; float sqrMagnitude = ((Vector3)(ref val2)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = val; } } return result; } public static T ClosestObject(Vector3 point, IEnumerable collection, Func selector) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) T result = default(T); float num = float.MaxValue; foreach (T item in collection) { Vector3 val = selector(item) - point; float sqrMagnitude = ((Vector3)(ref val)).sqrMagnitude; if (sqrMagnitude < num) { num = sqrMagnitude; result = item; } } return result; } public static Vector3 ClosestPointXZ(Vector3 point, IEnumerable collection, Func selector) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) Vector3 result = default(Vector3); float num = float.MaxValue; foreach (T item in collection) { Vector3 val = selector(item); float num2 = DistanceSqrXZ(val, point); if (num2 < num) { num = num2; result = val; } } return result; } public static T ClosestObjectXZ(Vector3 point, IEnumerable collection, Func selector) { //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) T result = default(T); float num = float.MaxValue; foreach (T item in collection) { float num2 = DistanceSqrXZ(selector(item), point); if (num2 < num) { num = num2; result = item; } } return result; } public static float Guardrails(float value, float lbound, float ubound) { if (value < lbound) { return lbound; } if (value > ubound) { return ubound; } return value; } public static string UnClonifiedName(string name) { if (name == null) { return null; } int num = name.IndexOf("(Clone)"); if (num < 1) { return name; } return name.Substring(0, num); } public static void SetTranslator(int id, string idText) { Localization.instance.AddWord("skill_" + id, idText); } public static string GetTranslated(int id) { Logging.GetLogger().Debug(string.Format("Got translation for id {0} to {1}", id, Localization.instance.Localize("skill_" + id))); return Localization.instance.Localize("$skill_" + id); } public static string GetAssemblyPathedFile(string fileName) { return new FileInfo(Assembly.GetExecutingAssembly().Location).DirectoryName.Replace('\\', '/') + "/" + fileName; } public static Sprite GetPrefabIcon(string prefabName) { Sprite result = null; GameObject prefab = GetPrefab(prefabName); ItemDrop val = default(ItemDrop); if (Object.op_Implicit((Object)(object)prefab) && prefab.TryGetComponent(ref val)) { result = val.m_itemData.GetIcon(); } return result; } public static Player GetPlayerByZDOID(ZDOID zid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) foreach (Player allPlayer in Player.GetAllPlayers()) { ZDOID zDOID = ((Character)allPlayer).GetZDOID(); if (((ZDOID)(ref zDOID)).Equals(zid)) { return allPlayer; } } return null; } public static Character GetCharacterByZDOID(string cid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) foreach (Character allCharacter in Character.GetAllCharacters()) { if (((object)allCharacter.GetZDOID()/*cast due to .constrained prefix*/).ToString().Equals(cid)) { return allCharacter; } } return null; } public static Character GetCharacterByZDOID(ZDOID cid) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) foreach (Character allCharacter in Character.GetAllCharacters()) { ZDOID zDOID = allCharacter.GetZDOID(); if (((ZDOID)(ref zDOID)).Equals(cid)) { return allCharacter; } } return null; } public static ZNetPeer GetPeerByRPC(ZRpc rpc) { foreach (ZNetPeer peer in ZNet.instance.GetPeers()) { if (peer.m_rpc == rpc) { return peer; } } return null; } public static List GetGameObjectsOfType(Type t) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Object[] array = Object.FindObjectsByType(t, (FindObjectsSortMode)0); foreach (Object val in array) { list.Add(((Component)val).gameObject); } return list; } public static GameObject GetClosestGameObjectOfType(Type t, Vector3 point, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) return GetGameObjectsOfTypeInRangeByDistance(t, point, radius)?[0]; } public static List GetGameObjectsOfTypeInRangeByDistance(Type t, Vector3 point, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) List> list = new List>(); List gameObjectsOfTypeInRange = GetGameObjectsOfTypeInRange(t, point, radius); if (gameObjectsOfTypeInRange.Count > 0) { foreach (GameObject item in gameObjectsOfTypeInRange) { list.Add(new KeyValuePair(item, Vector3.Distance(item.transform.position, point))); } list.Sort((KeyValuePair pair1, KeyValuePair pair2) => pair1.Value.CompareTo(pair2.Value)); return list.ConvertAll((KeyValuePair x) => x.Key); } return null; } public static List GetGameObjectsOfTypeInRange(Type t, Vector3 point, float radius) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) float radiusSq = radius * radius; return GetGameObjectsOfType(t).Where(delegate(GameObject x) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) Vector3 val = x.transform.position - point; return ((Vector3)(ref val)).sqrMagnitude < radiusSq; }).ToList(); } public static float GetPointDepth(Vector3 p) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) return ZoneSystem.instance.m_waterLevel - GetSolidHeight(p); } public static List GetDelimitedStringAsList(string delimitedString, char delimiter) { List list = new List(); string[] array = delimitedString.Split(new char[1] { delimiter }, StringSplitOptions.RemoveEmptyEntries); foreach (string text in array) { list.Add(text.Trim()); } return list; } public static float GetSolidHeight(Vector3 p) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) int solidRayMask = ZoneSystem.instance.m_solidRayMask; float result = 0f; p.y += 1000f; RaycastHit val = default(RaycastHit); if (Physics.Raycast(p, Vector3.down, ref val, 2000f, solidRayMask) && !Object.op_Implicit((Object)(object)((RaycastHit)(ref val)).collider.attachedRigidbody)) { result = ((RaycastHit)(ref val)).point.y; } return result; } public static Transform FindChild(Transform aParent, string aName) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown foreach (Transform item in aParent) { Transform val = item; if (((Object)val).name == aName) { return val; } Transform val2 = FindChild(val, aName); if ((Object)(object)val2 != (Object)null) { return val2; } } return null; } public static Transform FindParent(Transform go) { while ((Object)(object)go.parent != (Object)null) { go = go.parent; } return go; } public static bool IsPrefabInScene(string prefabName) { return IsPrefabInScene(StringExtensionMethods.GetStableHashCode(prefabName)); } public static bool IsPrefabInScene(int prefabHash) { ZNetScene instance = ZNetScene.instance; return (Object)(object)((instance != null) ? instance.GetPrefab(prefabHash) : null) != (Object)null; } public static bool TryGetPrefab(string prefabName, out GameObject prefab) { return TryGetPrefab(StringExtensionMethods.GetStableHashCode(prefabName), out prefab); } public static bool TryGetPrefab(int prefabHash, out GameObject prefab) { prefab = GetPrefabByHash(prefabHash); return (Object)(object)prefab != (Object)null; } public static GameObject GetPrefabByHash(int prefabHash) { GameObject val = null; Logging logger = Logging.GetLogger(); ZNetScene instance = ZNetScene.instance; val = ((instance != null) ? instance.GetPrefab(prefabHash) : null); if ((Object)(object)val != (Object)null) { logger.Debug("Found prefab in Scene"); return val; } val = ObjectDB.instance.GetItemPrefab(prefabHash); if ((Object)(object)val != (Object)null) { logger.Debug("Found prefab in ObjectDB"); return val; } logger.Debug("No prefab found"); return val; } public static GameObject GetPrefab(int prefabHash) { return GetPrefabByHash(prefabHash); } public static GameObject GetPrefab(string prefabName) { return GetPrefabByHash(StringExtensionMethods.GetStableHashCode(prefabName)); } public static void LoadPrefabInScene(GameObject prefab) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)prefab).name); if ((Object)(object)ZNetScene.instance != (Object)null && !ZNetScene.instance.m_namedPrefabs.ContainsKey(stableHashCode)) { ZNetScene.instance.m_prefabs.Add(prefab); ZNetScene.instance.m_namedPrefabs[stableHashCode] = prefab; } } public static GameObject SpawnObject(string prefabName, Vector3 position, Quaternion rotation, bool persist = true) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) if (TryGetPrefab(prefabName, out var prefab)) { return SpawnObject(prefab, position, rotation, persist); } return null; } public static GameObject SpawnObject(GameObject prefab, Vector3 position, Quaternion rotation, bool persist = true) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) LoadPrefabInScene(prefab); GameObject val = Object.Instantiate(prefab, position, rotation); ZNetView val2 = default(ZNetView); if (persist && val.TryGetComponent(ref val2)) { val2.GetZDO().Persistent = true; } return val; } public static string SerializeFromDictionary(string delimp, string delimc, IDictionary dict) { if (dict == null) { return null; } IEnumerable values = dict.Select(delegate(KeyValuePair kvp) { KeyValuePair keyValuePair = kvp; string? obj = keyValuePair.Key?.ToString(); string text = delimc; keyValuePair = kvp; return obj + text + keyValuePair.Value; }); return string.Join(delimp, values); } public static void DeserializeToDictionary(string serializedString, string delimp, string delimc, ref IDictionary dict) { if (dict == null) { return; } dict.Clear(); string[] separator = new string[1] { delimp }; string[] separator2 = new string[1] { delimc }; string[] array = serializedString.Split(separator, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string[] array2 = array[i].Split(separator2, StringSplitOptions.RemoveEmptyEntries); if (array2.Length == 2) { dict.Add(TypedValue(array2[0]), TypedValue(array2[1])); } } } public static FileSystemWatcher CreateFileWatcher(string fullPath, FileSystemEventHandler handler) { string fileName = Path.GetFileName(fullPath); FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(fullPath.Substring(0, fullPath.Length - fileName.Length), fileName); fileSystemWatcher.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.Size | NotifyFilters.LastWrite | NotifyFilters.CreationTime; fileSystemWatcher.Changed += handler; fileSystemWatcher.Created += handler; fileSystemWatcher.IncludeSubdirectories = false; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; return fileSystemWatcher; } public static T TypedValue(object a) { return (T)Convert.ChangeType(a, typeof(T)); } public static float TimeAdjustedRamp(float maxValue, float duration, float elapsedTime, float pctFromStartRise, float pctFromEndFall) { float num = elapsedTime / duration; if (num <= pctFromStartRise) { return maxValue * (num / pctFromStartRise); } if (num >= 1f - pctFromEndFall) { return maxValue * ((1f - num) / pctFromEndFall); } return maxValue; } public static Color IntToColor(int rgba) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) float num = (float)((rgba >> 16) & 0xFF) / 255f; float num2 = (float)((rgba >> 8) & 0xFF) / 255f; float num3 = (float)(rgba & 0xFF) / 255f; float num4 = (float)((rgba >> 24) & 0xFF) / 255f; return new Color(num, num2, num3, num4); } public static bool CopyComponentToGameObject(Component original, ref GameObject destination) { //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown Logging logger = Logging.GetLogger(); Type type = ((object)original).GetType(); logger.Debug($"Original Type is {type}"); GameObject obj = destination; logger.Debug("Destination GameObject " + ((obj != null) ? ((Object)obj).name : null)); Component val = destination.GetComponent(type); if (!Object.op_Implicit((Object)(object)val)) { val = destination.AddComponent(type); } if (!Object.op_Implicit((Object)(object)val)) { logger.Debug("Destination component is null"); return false; } Component val2 = (Component)Activator.CreateInstance(type); if (!Object.op_Implicit((Object)(object)val2)) { logger.Debug("Destination component is null"); return false; } if (!Object.op_Implicit((Object)(object)val2)) { logger.Debug("Boxed component is null"); return false; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(val2, fieldInfo.GetValue(original)); } val = val2; return true; } public static bool CopyObject(object original, object target) { Logging logger = Logging.GetLogger(); Type type = original.GetType(); Type type2 = target.GetType(); if (type == null) { logger.Warning("Copy Object: Source object is null"); return false; } if (type2 == null) { logger.Warning("Copy Object: Destination object is null"); return false; } if (type2 != type) { logger.Warning("Copy Object: Source and destination components are different types"); return false; } FieldInfo[] fields = type.GetFields(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (FieldInfo fieldInfo in fields) { fieldInfo.SetValue(target, fieldInfo.GetValue(original)); } return true; } } } namespace SeidrChest { internal class Cfg { private static Logging Log = Logging.Instance; public static KeyCode[] keyModifiers = (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }; public static KeyboardShortcut chestBindKeyDefault = new KeyboardShortcut((KeyCode)106, keyModifiers); public static DelegatedConfigEntry debugLevel = null; public static DelegatedConfigEntry chestBindKey = null; public static KeyboardShortcut chestOpenKeyDefault = new KeyboardShortcut((KeyCode)104, Array.Empty()); public static DelegatedConfigEntry chestOpenKey = null; public static DelegatedConfigEntry useStrictCost = null; public static DelegatedConfigEntry teleportRestriction = null; public static DelegatedConfigEntry bindCost = null; public static DelegatedConfigEntry openCost = null; public static DelegatedConfigEntry chestMode = null; public static DelegatedConfigEntry costMode = null; public static DelegatedConfigEntry invertEnderKey = null; public static void BepInExConfig(BaseUnityPlugin _instance) { //IL_00e1: 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_01f0: Unknown result type (might be due to invalid IL or missing references) //IL_01fa: Expected O, but got Unknown //IL_0236: Unknown result type (might be due to invalid IL or missing references) //IL_0240: Expected O, but got Unknown ServerConfiguration.Instance.Setup(_instance.Config, _instance); debugLevel = new DelegatedConfigEntry(ChangeLogging); debugLevel.ConfigEntry = _instance.Config.Bind("Utility", "LogLevel", Logging.LogLevels.Info, "Controls the level of information contained in the log. Default is 'Info'"); Log.LogLevel = debugLevel.Value; chestMode = new DelegatedConfigEntry(useServerDelegate: true); chestMode.ConfigEntry = _instance.Config.Bind("General", "ChestMode", SeidrChest.ChestModes.SeidrChest, "Seidr mode allows accessing the Seidr chest anyhwere. Ender mode links all personal chests to the same Seidr chest; you must open them to access the common toInventory."); costMode = new DelegatedConfigEntry(useServerDelegate: true); costMode.ConfigEntry = _instance.Config.Bind("Cost", "CostType", SeidrChest.CostModes.EitrThenStamina, "Set the type of energy used to bind and open Seidr chests. Can be exclusivley Eitr or Stamina, or Eitr first, followed by Stamina."); chestBindKey = new DelegatedConfigEntry(); chestBindKey.ConfigEntry = _instance.Config.Bind("General", "BindSeidrChest", chestBindKeyDefault, "Press this key to seidr bind a Personal Chest to a Seidr Chest."); chestOpenKey = new DelegatedConfigEntry(); chestOpenKey.ConfigEntry = _instance.Config.Bind("General", "OpenSeidrChest", chestOpenKeyDefault, "Press this key to open your Seidr Chest. In EnderChest mode, hold this key down when opening a Personal chest to access the actual chest contents."); useStrictCost = new DelegatedConfigEntry(useServerDelegate: true); useStrictCost.ConfigEntry = _instance.Config.Bind("Cost", "StrictCost", false, "Require cost to be met before binding or opening. If Eitr and/or Stamina is less than this cost (depending on CostType setting), chest cannot be bound or open."); invertEnderKey = new DelegatedConfigEntry(); invertEnderKey.ConfigEntry = _instance.Config.Bind("General", "InvertEnderOpenKey", false, "Set True to invert Ender mode open action, i.e., open Personal Chest as default, open SeidrChest while holding the OpenSeidrChest key."); teleportRestriction = new DelegatedConfigEntry(useServerDelegate: true); teleportRestriction.ConfigEntry = _instance.Config.Bind("General", "RestrictNonTeleportable", false, "Set to true to prevent non-teleportable items in the Seidr chest."); bindCost = new DelegatedConfigEntry(useServerDelegate: true); bindCost.ConfigEntry = _instance.Config.Bind("Cost", "CostToBind", 50, new ConfigDescription("Sets the amount of eitr and/or stamina consumed to bind a Seidr chest.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 300), Array.Empty())); openCost = new DelegatedConfigEntry(useServerDelegate: true); openCost.ConfigEntry = _instance.Config.Bind("Cost", "CostToOpen", 10, new ConfigDescription("Sets the amount of eitr and/or stamina consumed to use a Seidr chest.", (AcceptableValueBase)(object)new AcceptableValueRange(0, 300), Array.Empty())); ServerConfiguration.Instance.CreateConfigWatcher(); } public static void ChangeLogging(object s, EventArgs e) { SettingChangedEventArgs e2 = (SettingChangedEventArgs)(object)((e is SettingChangedEventArgs) ? e : null); Log.Debug($"ChangeLog {e2.ChangedSetting.Definition.Key} to {e2.ChangedSetting.BoxedValue}"); Log.LogLevel = debugLevel.Value; } } [BepInPlugin("neobotics.valheim_mod.seidrchest", "SeidrChest", "0.1.19")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class SeidrChest : BaseUnityPlugin { public enum ChestModes { SeidrChest, EnderChest } public enum CostModes { EitrThenStamina, EitrOnly, StaminaOnly } [HarmonyPatch(typeof(Game), "Start")] private static class Game_Start_Patch { [HarmonyPostfix] private static void Game_Start_Patch_Postfix(Game __instance) { Log.Debug(" Game_Start_Patch_Postfix"); ZRoutedRpc.instance.Register("RequestSeidrZDO", (Action)RPC_RequestSeidrZDO); ZRoutedRpc.instance.Register("CancelRequestZDO", (Action)RPC_CancelRequestZDO); } } [HarmonyPatch(typeof(InventoryGui), "Hide")] private static class InventoryGui_Hide_Patch { [HarmonyPostfix] private static void InventoryGui_Hide_Postfix(InventoryGui __instance) { if (originalAutocloseDistance >= 0f) { __instance.m_autoCloseDistance = originalAutocloseDistance; } } } [HarmonyPatch(typeof(InventoryGui), "CloseContainer")] private static class InventoryGui_CloseContainer_Patch { [HarmonyPostfix] private static void InventoryGui_CloseContainer_Postfix(InventoryGui __instance) { Log.Debug("InventoryGui_CloseContainer_Patch_Postfix"); if (originalAutocloseDistance >= 0f) { __instance.m_autoCloseDistance = originalAutocloseDistance; } } } [HarmonyPatch(typeof(ZNetScene), "RemoveObjects")] public static class ZNetScene_RemoveObjects_Patch { private static void Prefix(List currentNearObjects, List currentDistantObjects) { if (voidZdo != null && voidZdo.IsValid() && !currentNearObjects.Contains(voidZdo) && !currentDistantObjects.Contains(voidZdo)) { currentDistantObjects.Add(voidZdo); Log.Debug("Protected Seidr chest ZDO from removal"); } } } [HarmonyPatch(typeof(InventoryGui), "Show")] public static class InventoryGui_Show_Patch { private static bool Prefix(InventoryGui __instance, ref Container container, out Container __state) { //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) __state = null; if (originalAutocloseDistance == -1f) { originalAutocloseDistance = __instance.m_autoCloseDistance; } if ((Object)(object)container != (Object)null) { if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("Showing container name " + container.m_name); } if (container.m_name == "$piece_chestprivate" && Cfg.chestMode.Value == ChestModes.EnderChest && ((!Cfg.chestOpenKey.IsKeyDown() && !Cfg.invertEnderKey.Value) || (Cfg.chestOpenKey.IsKeyDown() && Cfg.invertEnderKey.Value))) { if (!SetupSeidrChest()) { Log.Info("No Seidr chest is bound"); return true; } Container val = default(Container); if ((Object)(object)voidChest != (Object)null && voidChest.TryGetComponent(ref val)) { Log.Debug("Switching to Sedir chest"); container = val; } } if ((Object)(object)voidChest != (Object)null && (Object)(object)voidChest.GetComponent() == (Object)(object)container) { Log.Debug("Showing Seidr chest"); if (!HasSeidrCost(Player.m_localPlayer, Cfg.openCost.Value, binding: false)) { return false; } ApplySeidrCost(Player.m_localPlayer, Cfg.openCost.Value); container.GetInventory().m_name = "$piece_neobotics_sc_seidr_chest"; if (Vector3.Distance(((Component)Player.m_localPlayer).transform.position, voidChest.transform.position) > 5f) { __instance.m_autoCloseDistance = float.MaxValue; Log.Debug("Reset autoclose distance"); } else { __instance.m_autoCloseDistance = originalAutocloseDistance; } } } else { Log.Debug("Not a Container"); } return true; } } [HarmonyPatch(typeof(Player), "OnSpawned")] public static class Player_OnSpawned_Patch { public static void Postfix(Player __instance) { Log.Debug("Player OnSpawned"); voidChest = null; voidZdo = null; if (!SetupSeidrChest() && !ZNet.instance.IsServer()) { Log.Debug("No local ZDO. Requesting from server"); RequestSeidrZDOFromServer(Player.m_localPlayer.GetPlayerName()); ((MonoBehaviour)_modInstance).StartCoroutine(_modInstance.Co_WaitForZDO()); } } } [HarmonyPatch(typeof(Container), "CanBeRemoved")] public static class Container_CanBeRemoved_Patch { private static void Postfix(Container __instance, ref bool __result) { Logging log = Log; object arg = __result; object arg2 = ((Object)((Component)__instance).gameObject).GetInstanceID(); GameObject voidChest = SeidrChest.voidChest; log.Warning($"Can be removed result {arg} Container instance ID {arg2} void chest instance ID {((voidChest != null) ? new int?(((Object)voidChest).GetInstanceID()) : ((int?)null))}"); if (__result && (Object)(object)SeidrChest.voidChest != (Object)null && (Object)(object)SeidrChest.voidChest == (Object)(object)((Component)__instance).gameObject) { Log.Trace("Setting Seidr chest removal false"); __result = false; } } } [HarmonyPatch(typeof(Container), "GetHoverText")] public static class Container_GetHoverText_Patch { private static void Postfix(Container __instance, ref string __result) { if ((Object)(object)voidChest != (Object)null && Cfg.chestMode.Value == ChestModes.EnderChest && __instance.m_name == "$piece_chestprivate" && ((!Cfg.chestOpenKey.IsKeyDown() && !Cfg.invertEnderKey.Value) || (Cfg.chestOpenKey.IsKeyDown() && Cfg.invertEnderKey.Value))) { __result += " ($piece_neobotics_sc_seidr_chest)"; } } } [HarmonyPatch(typeof(Player), "Update")] public static class Player_Update_Patch { private static void Prefix(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer && OkToKey(__instance)) { if (Cfg.chestBindKey.IsKeyPressed()) { BindChest(); } else if (Cfg.chestMode.Value == ChestModes.SeidrChest && Cfg.chestOpenKey.IsKeyPressed()) { HandleChest(); } } } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData), typeof(int), typeof(int), typeof(int) })] private static class Inventory_AddItem_ToSlot_Patch { private static bool Prefix(Inventory __instance, ItemData item, int amount, int x, int y, string ___m_name, out bool __result) { __result = true; if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("AddItem_ToSlot " + item.m_shared.m_name + " to " + ___m_name); } if (!IsOkToMove(item, ___m_name)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(Inventory), "AddItem", new Type[] { typeof(ItemData) })] private static class Inventory_AddItem_Patch { private static bool Prefix(Inventory __instance, ItemData item, string ___m_name, out bool __result) { __result = true; if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("AddItem " + item.m_shared.m_name + " to " + ___m_name); } if (!IsOkToMove(item, ___m_name)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData), typeof(int), typeof(int), typeof(int) })] private static class Inventory_MoveItemToThis_Slot_Patch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, int amount, int x, int y, string ___m_name) { if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("MoveItemToThis_Slot " + item.m_shared.m_name + " to " + ___m_name); } ItemData itemAt = __instance.GetItemAt(x, y); if (itemAt != null && !IsOkToMove(itemAt, fromInventory.GetName())) { return false; } if (!IsOkToMove(item, ___m_name)) { return false; } return true; } } [HarmonyPatch(typeof(Inventory), "MoveItemToThis", new Type[] { typeof(Inventory), typeof(ItemData) })] private static class Inventory_MoveItemToThis_Patch { private static bool Prefix(Inventory __instance, Inventory fromInventory, ItemData item, string ___m_name) { if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("MoveItemToThis " + item.m_shared.m_name + " to " + ___m_name); } if (!IsOkToMove(item, ___m_name)) { return false; } return true; } } [HarmonyPatch(typeof(InventoryGrid), "DropItem")] private static class InventoryGrid_DropItem_Patch { private static bool Prefix(InventoryGrid __instance, Inventory fromInventory, ItemData item, int amount, Vector2i pos, Inventory ___m_inventory, out bool __result) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) __result = true; string name = ___m_inventory.GetName(); if (Log.LogLevel >= Logging.LogLevels.Trace) { Log.Trace("InventoryGrid_DropItem " + item.m_shared.m_name + " to " + name); } ItemData itemAt = ___m_inventory.GetItemAt(pos.x, pos.y); if (itemAt != null && !IsOkToMove(itemAt, fromInventory.GetName())) { return false; } if (!IsOkToMove(item, name)) { __result = false; return false; } return true; } } [HarmonyPatch(typeof(FejdStartup), "Awake")] private static class FejidStartup_Awake_Patch { private static void Postfix(FejdStartup __instance) { GetDetectionSet(new Dictionary { { "yay.spikehimself.xstorage.harmony", "XStorage" } }); } } private static SeidrChest _modInstance; internal const string PLUGIN_NAME = "SeidrChest"; private static string LcMod = "SeidrChest".ToLower(); public static Logging Log; private const string convertedName = "$piece_neobotics_sc_seidr_chest"; private const string personalChestTag = "$piece_chestprivate"; private Harmony harmony; private static float originalAutocloseDistance = -1f; private static GameObject voidChest = null; private static ZDO voidZdo = null; private static GameObject bindPrefab = null; private static bool cancelRequest = false; internal static string s_configFolder = null; private const string CANTBIND = "$msg_neobotics_sc_cant_bind"; public const string SEIDRPREFIX = "SeidrChest_1847_"; private const string XSTORAGESKIP = "XStorage_SkipMark"; private const string SEIDERCHEST_TEMP = "SeidrChest_Temp"; private static Dictionary detectionSet = new Dictionary(); private static Dictionary unpatchMods = new Dictionary(); public static SeidrChest GetInstance() { return _modInstance; } private void Awake() { //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown _modInstance = this; Log = Logging.GetLogger(Logging.LogLevels.Info, "SeidrChest"); harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); harmony.PatchAll(Assembly.GetExecutingAssembly()); ConfigureMod(); ModResourceBootstrap.InitializeModResources(typeof(SeidrChest), "SeidrChest"); new Localizer("SeidrChest"); Log.Info("Awake"); } private void ConfigureMod() { Log = Logging.GetLogger(Logging.LogLevels.Info, "SeidrChest"); Cfg.BepInExConfig((BaseUnityPlugin)(object)_modInstance); } private void OnDestroy() { harmony.UnpatchSelf(); } private static bool HasSeidrCost(Player aPlayer, float amount, bool binding = true) { bool flag = true; if (Cfg.useStrictCost.Value) { float eitr = aPlayer.GetEitr(); float stamina = aPlayer.GetStamina(); switch (Cfg.costMode.Value) { case CostModes.EitrOnly: if (eitr < amount) { flag = false; } break; case CostModes.StaminaOnly: if (stamina < amount) { flag = false; } break; default: if (eitr + stamina < amount) { flag = false; } break; } if (!flag) { Log.Info("Not enough energy to " + (binding ? "bind" : "use") + " the Seidr chest"); ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_neobotics_sc_no_energy", 0, (Sprite)null); } } return flag; } private static void ApplySeidrCost(Player aPlayer, float amount) { float eitr = aPlayer.GetEitr(); aPlayer.GetStamina(); if ((Cfg.costMode.Value == CostModes.EitrOnly || Cfg.costMode.Value == CostModes.EitrThenStamina) && eitr > 0f) { ((Character)aPlayer).UseEitr(amount); amount -= eitr; } if ((Cfg.costMode.Value == CostModes.StaminaOnly || Cfg.costMode.Value == CostModes.EitrThenStamina) && amount > 0f) { ((Character)aPlayer).UseStamina(amount); } } private static void RestoreToPersonalChest() { Log.Debug("RestoreToPersonalChest"); Container val = default(Container); if ((Object)(object)voidChest != (Object)null && voidChest.TryGetComponent(ref val)) { val.GetInventory().m_name = "$piece_chestprivate"; val.m_name = "$piece_chestprivate"; } } private static bool IsOkToMove(ItemData item, string name) { if (name == "$piece_neobotics_sc_seidr_chest" && item?.m_shared != null && Cfg.teleportRestriction.Value && !item.m_shared.m_teleportable) { Log.Info("Can't store non-teleportable items in the Seidr chest"); ((Character)Player.m_localPlayer).Message((MessageType)1, "$msg_neobotics_sc_cant_store", 0, (Sprite)null); return false; } return true; } private static void UnbindChest(bool message = true) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) Log.Debug("UnbindChest"); Container val = default(Container); if (!((Object)(object)voidChest != (Object)null) || !voidChest.TryGetComponent(ref val)) { return; } if (message) { CreateAura(voidChest); } RestoreToPersonalChest(); ZDO zDO = val.m_nview.GetZDO(); if (zDO.IsValid()) { zDO.Set(StringExtensionMethods.GetStableHashCode("XStorage_SkipMark"), false); if (ZDOHelper.Remove(ZDOExtraData.s_strings, zDO.m_uid, StringExtensionMethods.GetStableHashCode("SeidrChest_1847_"))) { Log.Debug($"Removed player reference from chest ZDO {zDO.m_uid}"); } } voidChest = null; voidZdo = null; Log.Info("Seidr Chest is unbound"); if (message) { ((Character)Player.m_localPlayer).Message((MessageType)2, "$msg_neobotics_sc_unbound", 0, (Sprite)null); } } private static bool HasNonTeleportableItems(Container container) { if (((container != null) ? container.GetInventory() : null) != null) { return container.GetInventory().GetAllItems().Find((ItemData x) => !x.m_shared.m_teleportable) != null; } return false; } private static void BindChest() { Player localPlayer = Player.m_localPlayer; Log.Debug("BindChest"); GameObject hoverObject = ((Humanoid)localPlayer).GetHoverObject(); GameObject val = ((hoverObject != null) ? ((Component)hoverObject.transform.root).gameObject : null); if ((Object)(object)val == (Object)null) { return; } if ((Object)(object)val == (Object)(object)voidChest) { Log.Debug("Unbinding hovered Seidr chest"); UnbindChest(); return; } if (((Object)val).name != "piece_chest_private(Clone)") { Log.Info("Hovered object is not a personal chest"); ((Character)localPlayer).Message((MessageType)2, "$msg_neobotics_sc_cant_bind", 0, (Sprite)null); return; } ZNetView val2 = default(ZNetView); if (!val.TryGetComponent(ref val2)) { Log.Warning("Hovering object has no view"); return; } ZDO zDO = val2.GetZDO(); Piece component = val.GetComponent(); Container container = default(Container); if (zDO == null || (Object)(object)component == (Object)null) { Log.Warning("Invalid hover object"); } else if (!component.IsCreator()) { Log.Info("You can only bind your own Personal chest"); ((Character)localPlayer).Message((MessageType)2, "$msg_neobotics_sc_cant_bind", 0, (Sprite)null); } else if (Cfg.teleportRestriction.Value && val.TryGetComponent(ref container) && HasNonTeleportableItems(container)) { Log.Info("You cannot bind a chest with items that can't be teleported"); ((Character)localPlayer).Message((MessageType)2, "$msg_neobotics_sc_cant_bind", 0, (Sprite)null); } else if (HasSeidrCost(localPlayer, Cfg.bindCost.Value)) { ApplySeidrCost(localPlayer, Cfg.bindCost.Value); if ((Object)(object)voidChest != (Object)null) { Log.Debug("Unbinding existing Seidr chest"); UnbindChest(message: false); } voidChest = val; Log.Debug("Player selected own Personal chest"); SaveSeidrChestZDO(zDO); Object.DontDestroyOnLoad((Object)(object)voidChest); CreateAura(voidChest); Container val3 = default(Container); if (voidChest.TryGetComponent(ref val3)) { val3.m_name = "$piece_neobotics_sc_seidr_chest"; zDO.Set(StringExtensionMethods.GetStableHashCode("XStorage_SkipMark"), true); } Log.Info("Seidr Chest is bound"); ((Character)localPlayer).Message((MessageType)2, "$msg_neobotics_sc_bound", 0, (Sprite)null); } } private static void CreateAura(GameObject go) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)bindPrefab == (Object)null) { bindPrefab = ZNetScene.instance.GetPrefab("fx_Immobilize"); } if ((Object)(object)bindPrefab != (Object)null) { Object.Instantiate(bindPrefab, go.transform.position, Quaternion.identity); } } private static string GetChestWorldKey() { return "SeidrChest_1847_" + ZNet.m_world.m_name; } private static ZDO GetSeidrChestZDO(string playerName) { Log.Debug("GetSeidrChestZDO"); int stableHashCode = StringExtensionMethods.GetStableHashCode("piece_chest_private"); if (ZDOMan.instance.m_objectsByID != null) { Log.Debug("Found Seidr chest ZDO"); foreach (ZDO value in ZDOMan.instance.m_objectsByID.Values) { if (value != null && value.m_prefab == stableHashCode && value.GetString("SeidrChest_1847_", "") == playerName) { return value; } } } Log.Debug("No Seidr chest ZDO found."); return null; } private static void RequestSeidrZDOFromServer(string playerName) { Log.Debug("RequestSeidrZDOFromServer"); ZRoutedRpc.instance.InvokeRoutedRPC("RequestSeidrZDO", new object[1] { playerName }); } private static void CancelRequestToServer(long peer) { Log.Debug("CancelRequestToServer"); ZRoutedRpc.instance.InvokeRoutedRPC(peer, "CancelRequestZDO", Array.Empty()); } private static void RPC_RequestSeidrZDO(long id, string playerName) { //IL_003f: 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) if (ZNet.instance.IsServer()) { Log.Debug("RPC_RequestSeidrZDO"); ZNetPeer peerByPlayerName = ZNet.instance.GetPeerByPlayerName(playerName); ZDO seidrChestZDO = GetSeidrChestZDO(playerName); if (seidrChestZDO != null && peerByPlayerName != null) { Log.Debug($"Server sending Seidr chest ZDO {seidrChestZDO.m_uid} to {playerName}"); ZDOMan.instance.ForceSendZDO(peerByPlayerName.m_uid, seidrChestZDO.m_uid); } else { Log.Warning("Server can't find requested Seidr chest for " + playerName); CancelRequestToServer(id); } } } private static void RPC_CancelRequestZDO(long id) { if (!ZNet.instance.IsServer()) { Log.Debug("RPC_CancelRequestZDO"); cancelRequest = true; } } private static void SaveSeidrChestZDO(ZDO zdo) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) Log.Debug("SaveSeidrChestZDO"); zdo.Set("SeidrChest_1847_", Player.m_localPlayer.GetPlayerName()); Log.Debug($"Saved player to Seidr chest ZDO {zdo.m_uid}"); } private static bool SetupSeidrChest() { Log.Debug("SetupSeidrChest"); if ((Object)(object)voidChest != (Object)null) { Log.Debug("Chest already exists"); return true; } Log.Debug("Finding chest"); ZDO seidrChestZDO = voidZdo; if (seidrChestZDO == null) { Log.Debug("No Seidr chest ZDO. Getting from local data."); seidrChestZDO = GetSeidrChestZDO(Player.m_localPlayer.GetPlayerName()); } if (seidrChestZDO == null) { Log.Debug("No pre-existing chest"); return false; } voidZdo = seidrChestZDO; if (!ZNetScene.instance.HaveInstance(seidrChestZDO)) { Log.Debug("No chest instance currently in scene... creating."); ZNetScene.instance.CreateObject(seidrChestZDO); } ZNetView val = ZNetScene.instance.FindInstance(seidrChestZDO); if ((Object)(object)val == (Object)null) { Log.Warning("Couldn't find or create existing chest instance"); return false; } Log.Debug("Re-binding existing chest"); voidChest = ((Component)val).gameObject; Container val2 = default(Container); if (voidChest.TryGetComponent(ref val2)) { val2.m_name = "$piece_neobotics_sc_seidr_chest"; } Object.DontDestroyOnLoad((Object)(object)voidChest); return true; } private static bool HandleChest() { //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) Player localPlayer = Player.m_localPlayer; Log.Debug("HandleChest"); if (!SetupSeidrChest()) { Log.Info("No Seidr chest is bound"); return false; } if (InventoryGui.instance.IsContainerOpen()) { Container currentContainer = InventoryGui.instance.m_currentContainer; if ((Object)(object)currentContainer != (Object)null && (Object)(object)((Component)currentContainer).gameObject != (Object)(object)voidChest) { InventoryGui.instance.Hide(); } } ZNetView val = default(ZNetView); if (voidChest.TryGetComponent(ref val)) { if (val.GetZDO() == null) { Log.Warning("Chest missing ZDO"); return false; } Container val2 = default(Container); if (voidChest.TryGetComponent(ref val2)) { if (val2.IsInUse()) { Log.Debug("Closing chest"); InventoryGui.instance.Hide(); return true; } Log.Debug($"Seidr chest is {Vector3.Distance(voidChest.transform.position, ((Component)localPlayer).transform.position)} meters away"); if (!HasSeidrCost(localPlayer, Cfg.openCost.Value, binding: false)) { return false; } val2.m_name = "$piece_neobotics_sc_seidr_chest"; val2.m_nview.ClaimOwnership(); if (val2.Interact((Humanoid)(object)localPlayer, false, false)) { Log.Debug("Interact successful"); val2.m_inUse = false; val2.SetInUse(true); return true; } Log.Warning("Can't interact with chest"); return false; } Log.Warning("Chest missing Container"); return false; } Log.Warning("Chest missing ZNetView"); return false; } private static bool OkToKey(Player player) { if (!Chat.instance.HasFocus() && !Console.IsVisible() && (Object)(object)TextViewer.instance != (Object)null && !TextViewer.instance.IsVisible() && !GameCamera.InFreeFly() && !Minimap.IsOpen() && !TextInput.IsVisible() && !StoreGui.IsVisible() && !((Character)player).InCutscene() && !((Character)player).InBed() && !((Character)player).IsTeleporting() && !((Character)player).IsDead()) { return !((Character)player).InPlaceMode(); } return false; } public static void GetDetectionSet(Dictionary harmonyIds) { foreach (KeyValuePair harmonyId in harmonyIds) { if (Harmony.HasAnyPatches(harmonyId.Key)) { Log.Debug("Detected " + harmonyId.Value); if (!detectionSet.ContainsKey(harmonyId.Key)) { detectionSet.Add(harmonyId.Key, harmonyId.Value); } } } } public static void AddExclusion(string key) { if (detectionSet.ContainsKey(key)) { unpatchMods.Add(key, detectionSet[key]); } } public static void UnpatchMods() { foreach (KeyValuePair unpatchMod in unpatchMods) { Log.Warning("Not compatible with " + unpatchMod.Value); Harmony.UnpatchID(unpatchMod.Key); detectionSet.Remove(unpatchMod.Key); Log.Warning("Disabled " + unpatchMod.Value); } } public static bool IsDetectedId(string key) { return detectionSet.ContainsKey(key); } private static void AddSectorObject(ZDOMan __instance, Vector2i sector, int area, List sectorObjects) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) ZNetView val = default(ZNetView); if (!((Object)(object)voidChest != (Object)null) || sectorObjects == null || !(ZoneSystem.GetZone(voidChest.transform.position) != sector) || !voidChest.TryGetComponent(ref val)) { return; } ZDO zDO = val.GetZDO(); if (zDO != null && (Object)(object)Player.m_localPlayer != (Object)null) { zDO.SetOwner(((Character)Player.m_localPlayer).GetOwner()); if (!sectorObjects.Contains(zDO)) { sectorObjects.Add(zDO); } } } private IEnumerator Co_WaitForZDO() { Log.Debug("Co_WaitForZDO"); float abortTime = Time.time + 20f; cancelRequest = false; while (!SetupSeidrChest() && !cancelRequest && Time.time < abortTime) { Log.Debug("Waiting for SeidrChest ZDO from server"); yield return (object)new WaitForSeconds(1f); } if (Time.time >= abortTime) { Log.Warning("Didn't receive SeidrChest ZDO from server."); } if (cancelRequest) { cancelRequest = false; Log.Warning("Server didn't find SeidrChest."); } } } }