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("Luckstone")] [assembly: AssemblyConfiguration("Deploy")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+fba5a770148283f326e7870607ac144d786a0428")] [assembly: AssemblyProduct("Luckstone")] [assembly: AssemblyTitle("Luckstone")] [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); } } public class Prefabricator { [HarmonyPatch(typeof(ZNetScene), "Awake")] public static class ZNetScene_Awake_Patch { [HarmonyPrefix] private static void Prefix(ZNetScene __instance) { foreach (Prefabricator item in Registry) { if (!((Object)(object)item.Prefab == (Object)null) && !__instance.m_prefabs.Contains(item.Prefab)) { __instance.m_prefabs.Add(item.Prefab); } } } [HarmonyPostfix] private static void Postfix(ZNetScene __instance) { //IL_0042: Unknown result type (might be due to invalid IL or missing references) foreach (Prefabricator item in Registry) { if ((Object)(object)item.Prefab != (Object)null && item.TintColor.HasValue) { ApplyTintToMaterial(item.Prefab, item.TintColor.Value); } } } } [HarmonyPatch(typeof(ObjectDB), "CopyOtherDB")] public static class ObjectDB_CopyOtherDB_Patch { [HarmonyPostfix] public static void ObjectDB_CopyOtherDB_Postfix(ObjectDB __instance) { foreach (Prefabricator item in Registry) { GameObject itemPrefab = __instance.GetItemPrefab(item.NewPrefabName); if ((Object)(object)itemPrefab != (Object)null) { item.Prefab = itemPrefab; continue; } GameObject itemPrefab2 = __instance.GetItemPrefab(item.PrototypeName); if ((Object)(object)itemPrefab2 == (Object)null) { Log.Debug("Can't find prototype " + item.PrototypeName); continue; } GameObject val = Object.Instantiate(itemPrefab2, GetAssetContainer().transform); ((Object)val).name = item.NewPrefabName; ItemDrop component = val.GetComponent(); if ((Object)(object)component != (Object)null) { component.m_itemData = component.m_itemData.Clone(); SharedData val2 = CopySharedData(component.m_itemData.m_shared); val2.m_name = item.NewItemName; val2.m_description = item.Description; component.m_itemData.m_shared = val2; component.m_itemData.m_dropPrefab = val; item.ConfigureItem?.Invoke(component.m_itemData); } if (!__instance.m_items.Contains(val)) { __instance.m_items.Add(val); } __instance.m_itemByHash[StringExtensionMethods.GetStableHashCode(((Object)val).name)] = val; if (component?.m_itemData?.m_shared != null) { __instance.m_itemByData[component.m_itemData.m_shared] = val; } item.Prefab = val; } } } [HarmonyPatch(typeof(ItemDrop), "OnCreateNew", new Type[] { typeof(GameObject) })] private static class ItemDrop_OnCreateNew_Patch { [HarmonyPrefix] private static void Prefix(ItemDrop __instance, GameObject go) { ItemDrop val = default(ItemDrop); foreach (Prefabricator item in Registry) { if (!((Object)(object)item.Prefab == (Object)null) && ((Object)go).name.StartsWith(item.NewPrefabName) && ZNetScene.instance.m_namedPrefabs.ContainsKey(StringExtensionMethods.GetStableHashCode(item.NewPrefabName)) && go.TryGetComponent(ref val)) { val.m_itemData.m_dropPrefab = item.Prefab; } } } } [HarmonyPatch(typeof(ObjectDB), "Awake")] public static class ObjectDB_Awake_Patch { [HarmonyPrefix] public static void ObjectDB_Awake_Prefix(ObjectDB __instance) { foreach (Prefabricator item in Registry) { if (!((Object)(object)item.Prefab == (Object)null) && !__instance.m_items.Contains(item.Prefab)) { __instance.m_items.Add(item.Prefab); } } } } internal static readonly List Registry = new List(); private static GameObject s_assetContainer; private static Logging Log = Logging.Instance; public string NewPrefabName { get; } public string PrototypeName { get; } public string NewItemName { get; } public string Description { get; } public GameObject Prefab { get; private set; } public Action ConfigureItem { get; set; } public Color? TintColor { get; set; } internal static GameObject GetAssetContainer() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown if ((Object)(object)s_assetContainer == (Object)null) { s_assetContainer = new GameObject("CustomAssets"); s_assetContainer.SetActive(false); Object.DontDestroyOnLoad((Object)(object)s_assetContainer); } return s_assetContainer; } public Prefabricator(string newPrefabName, string prototypeName, string newItemName, string description, Action configureItem = null) { NewPrefabName = newPrefabName; PrototypeName = prototypeName; NewItemName = newItemName; Description = description; ConfigureItem = configureItem; Registry.Add(this); } public static SharedData CopySharedData(SharedData source) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Expected O, but got Unknown //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown if (source == null) { return null; } SharedData val = new SharedData(); Type? typeFromHandle = typeof(SharedData); BindingFlags bindingAttr = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic; FieldInfo[] fields = typeFromHandle.GetFields(bindingAttr); foreach (FieldInfo fieldInfo in fields) { object value = fieldInfo.GetValue(source); if (value == null) { fieldInfo.SetValue(val, null); continue; } if (value is Array array) { fieldInfo.SetValue(val, array.Clone()); continue; } if (fieldInfo.FieldType.IsGenericType && fieldInfo.FieldType.GetGenericTypeDefinition() == typeof(List<>)) { object value2 = Activator.CreateInstance(fieldInfo.FieldType, value); fieldInfo.SetValue(val, value2); continue; } EffectList val2 = (EffectList)((value is EffectList) ? value : null); if (val2 != null) { EffectList val3 = new EffectList(); if (val2.m_effectPrefabs != null) { val3.m_effectPrefabs = (EffectData[])val2.m_effectPrefabs.Clone(); } fieldInfo.SetValue(val, val3); } else { Attack val4 = (Attack)((value is Attack) ? value : null); if (val4 != null) { fieldInfo.SetValue(val, val4.Clone()); } else { fieldInfo.SetValue(val, value); } } } return val; } private static Texture2D TintTexture(Texture2D origTex, Color tint) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Expected O, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)origTex == (Object)null) { return null; } RenderTexture temporary = RenderTexture.GetTemporary(((Texture)origTex).width, ((Texture)origTex).height, 0, (RenderTextureFormat)7, (RenderTextureReadWrite)1); Graphics.Blit((Texture)(object)origTex, temporary); RenderTexture.active = temporary; Texture2D val = new Texture2D(((Texture)origTex).width, ((Texture)origTex).height, (TextureFormat)4, false); val.ReadPixels(new Rect(0f, 0f, (float)((Texture)temporary).width, (float)((Texture)temporary).height), 0, 0); val.Apply(); RenderTexture.active = null; RenderTexture.ReleaseTemporary(temporary); Color[] pixels = val.GetPixels(); for (int i = 0; i < pixels.Length; i++) { float a = pixels[i].a; pixels[i] *= tint; pixels[i].a = a; } val.SetPixels(pixels); val.Apply(); return val; } private static void ApplyTintToMaterial(GameObject prefab, Color tint) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)prefab == (Object)null) { return; } Renderer[] componentsInChildren = prefab.GetComponentsInChildren(true); foreach (Renderer val in componentsInChildren) { if ((Object)(object)val == (Object)null || val.sharedMaterials == null) { continue; } Material[] array = (Material[])(object)new Material[val.sharedMaterials.Length]; for (int j = 0; j < val.sharedMaterials.Length; j++) { if ((Object)(object)val.sharedMaterials[j] == (Object)null) { continue; } array[j] = new Material(val.sharedMaterials[j]); if (array[j].HasProperty("_MainTex")) { Texture texture = array[j].GetTexture("_MainTex"); Texture2D val2 = (Texture2D)(object)((texture is Texture2D) ? texture : null); if ((Object)(object)val2 != (Object)null) { array[j].SetTexture("_MainTex", (Texture)(object)TintTexture(val2, tint)); } } if (array[j].HasProperty("_Color")) { array[j].SetColor("_Color", tint); } if (array[j].HasProperty("_EmissionColor")) { array[j].SetColor("_EmissionColor", tint * 0.5f); } } val.sharedMaterials = array; } } } } 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; private bool isEmbedded; public ImageHelper(string externalFolder) : this(externalFolder, embedded: false) { } public ImageHelper(string externalFolder, bool embedded = true) { this.externalFolder = externalFolder; logger = Logging.GetLogger(); isEmbedded = embedded; } 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_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Expected O, but got Unknown image = null; byte[] array = null; if (isEmbedded) { Stream manifestResourceStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(externalFolder + "." + name); if (manifestResourceStream == null) { throw new FileNotFoundException("Can't find " + name + " in " + externalFolder); } array = new byte[manifestResourceStream.Length]; manifestResourceStream.Read(array, 0, (int)manifestResourceStream.Length); } else { string text = Path.Combine(externalFolder, name); logger.Debug("Reading external file " + text); if (!File.Exists(text)) { throw new FileNotFoundException("Cannot find image " + name); } 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); string? name = pluginType.Assembly.GetName().Name; if (!Directory.Exists(orCreateModConfigFolder)) { Directory.CreateDirectory(orCreateModConfigFolder); Logging.Instance.Debug("Created subfolder layout: " + orCreateModConfigFolder); } string text = name + ".Resources."; Logging.Instance.Debug("Scanning assembly for standard prefix: " + text); ExtractResources(pluginType.Assembly, text, orCreateModConfigFolder); return orCreateModConfigFolder; } private static void ExtractResources(Assembly asm, string prefix, string targetFolder) { string[] manifestResourceNames = asm.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { continue; } string text2 = text.Substring(prefix.Length); string text3 = Path.Combine(targetFolder, text2); if (File.Exists(text3)) { continue; } try { Logging.Instance.Debug("Extracting asset: " + text2 + " -> " + text3); using Stream stream = asm.GetManifestResourceStream(text); if (stream == null) { Logging.Instance.Error("Could not access resource stream for: " + text); continue; } using FileStream destination = File.Create(text3); stream.CopyTo(destination); } catch (Exception ex) { Logging.Instance.Error("Failed to unpack embedded asset " + text2 + ": " + ex.Message); } } } } 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 Luckstone { internal class Cfg { public static DelegatedConfigEntry resourceMagnitude; public static DelegatedConfigEntry combatMagnitude; public static DelegatedConfigEntry luckChance; public static DelegatedConfigEntry luckDrain; public static DelegatedConfigEntry dropChance; public static DelegatedConfigEntry chestChance; public static DelegatedConfigEntry statusEffect; public static DelegatedConfigEntry bossChance; public static DelegatedConfigEntry starScaling; public static DelegatedConfigEntry rechargeTime; public static DelegatedConfigEntry showLuckPickupEffect; public static DelegatedConfigEntry displayLuckMessage; public static DelegatedConfigEntry playLuckPing; public static DelegatedConfigEntry showBonus; public static DelegatedConfigEntry mining; public static DelegatedConfigEntry woodcutting; public static DelegatedConfigEntry picking; public static DelegatedConfigEntry looting; public static DelegatedConfigEntry fishing; public static DelegatedConfigEntry damage; public static DelegatedConfigEntry attack; public static DelegatedConfigEntry crafting; public static DelegatedConfigEntry food; public static DelegatedConfigEntry debugLevel; private static Logging Log; public static void BepInExConfig(BaseUnityPlugin plugin, string modName) { BepInExConfig(plugin); } public static void BepInExConfig(BaseUnityPlugin _instance) { //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected O, but got Unknown //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_019a: Expected O, but got Unknown //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0234: Expected O, but got Unknown //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_02b1: Expected O, but got Unknown //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_02fe: Expected O, but got Unknown Log = Logging.Instance; ServerConfiguration.Instance.Setup(_instance.Config, _instance); debugLevel = new DelegatedConfigEntry(Logging.ChangeLogging); debugLevel.ConfigEntry = _instance.Config.Bind("Utility", "LogLevel", Logging.LogLevels.Info, "Controls the level of information contained in the log"); Log.LogLevel = debugLevel.Value; resourceMagnitude = new DelegatedConfigEntry(useServerDelegate: true); resourceMagnitude.ConfigEntry = _instance.Config.Bind("Luck", "Luck Magnitude", 1.5f, new ConfigDescription("The maximum amount of 'luck advantage' to apply to non-combat Luck Events. This is a multipier applied to random values.@", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 2f), Array.Empty())); combatMagnitude = new DelegatedConfigEntry(useServerDelegate: true); combatMagnitude.ConfigEntry = _instance.Config.Bind("Luck", "Luck Magnitude (Combat)", 1.5f, new ConfigDescription("The maximum amount of 'luck advantage' to apply to combat Luck Events. This is a multipier applied to existing multipliers.@", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 2f), Array.Empty())); luckChance = new DelegatedConfigEntry(useServerDelegate: true); luckChance.ConfigEntry = _instance.Config.Bind("Luck", "Luck Chance", 0.1f, new ConfigDescription("The percentage chance of you getting 'lucky'. This chance is applied to every configured Luck Event.@", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); luckDrain = new DelegatedConfigEntry(useServerDelegate: true); luckDrain.ConfigEntry = _instance.Config.Bind("Luck", "Luck Drain", 1f, new ConfigDescription("The amount of 'luck' drained from the Luckstone when 'lucky'.@", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 10f), Array.Empty())); rechargeTime = new DelegatedConfigEntry(useServerDelegate: true); rechargeTime.ConfigEntry = _instance.Config.Bind("Luck", "Luck Recharge Time", 5f, new ConfigDescription("The amount of time a Luckstone takes to recover before it can apply luck again (in seconds).@", (AcceptableValueBase)(object)new AcceptableValueRange(1f, 60f), Array.Empty())); dropChance = new DelegatedConfigEntry(useServerDelegate: true); dropChance.ConfigEntry = _instance.Config.Bind("Luckstone", "Drop Chance", 0.05f, new ConfigDescription("The chance of getting a Luckstone dropped by 'starred' creatures.@", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); starScaling = new DelegatedConfigEntry(useServerDelegate: true); starScaling.ConfigEntry = _instance.Config.Bind("Luckstone", "Drops Scale", true, "Drop Chance scales by number of creature 'stars'.@"); bossChance = new DelegatedConfigEntry(useServerDelegate: true); bossChance.ConfigEntry = _instance.Config.Bind("Luckstone", "Boss Drop Chance", 0.25f, new ConfigDescription("The base chance of getting a Luckstone dropped by a Boss.@", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); chestChance = new DelegatedConfigEntry(useServerDelegate: true); chestChance.ConfigEntry = _instance.Config.Bind("Luckstone", "Chest Chance", 0.03f, new ConfigDescription("The chance of finding a Luckstone in a world container.@", (AcceptableValueBase)(object)new AcceptableValueRange(0f, 1f), Array.Empty())); mining = new DelegatedConfigEntry(useServerDelegate: true); mining.ConfigEntry = _instance.Config.Bind("Luck Events", "Mining", true, "Apply luck when mining ores and other pickaxe use.@"); woodcutting = new DelegatedConfigEntry(useServerDelegate: true); woodcutting.ConfigEntry = _instance.Config.Bind("Luck Events", "Woodcutting", true, "Apply luck when chopping trees.@"); picking = new DelegatedConfigEntry(useServerDelegate: true); picking.ConfigEntry = _instance.Config.Bind("Luck Events", "Picking", true, "Apply luck when picking treasure, gathering, harvesting and other things that 'pop'.@"); looting = new DelegatedConfigEntry(useServerDelegate: true); looting.ConfigEntry = _instance.Config.Bind("Luck Events", "Looting", true, "Apply luck to loot drops from creatures.@"); fishing = new DelegatedConfigEntry(useServerDelegate: true); fishing.ConfigEntry = _instance.Config.Bind("Luck Events", "Fishing", true, "Apply luck to fishing extra drops.@"); crafting = new DelegatedConfigEntry(useServerDelegate: true); crafting.ConfigEntry = _instance.Config.Bind("Luck Events", "Crafting Output", true, "Apply luck to crafting output for stackable items.@"); food = new DelegatedConfigEntry(useServerDelegate: true); food.ConfigEntry = _instance.Config.Bind("Luck Events", "Food Creation", true, "Apply luck to recipe-based, stackable food creation.@"); damage = new DelegatedConfigEntry(useServerDelegate: true); damage.ConfigEntry = _instance.Config.Bind("Luck Events", "Combat Defense", false, "Apply luck to avoid some combat damage (not PvP).@"); attack = new DelegatedConfigEntry(useServerDelegate: true); attack.ConfigEntry = _instance.Config.Bind("Luck Events", "Combat Offense", false, "Apply luck to add some combat damage to attacks (not PvP).@"); statusEffect = new DelegatedConfigEntry(); statusEffect.ConfigEntry = _instance.Config.Bind("Notification", "Show Luck Status", true, "Display the lucky icon in the status bar when a Luckstone is in your inventory."); displayLuckMessage = new DelegatedConfigEntry(); displayLuckMessage.ConfigEntry = _instance.Config.Bind("Notification", "Display Luck Message", true, "Display a message in the notification area when you get lucky."); playLuckPing = new DelegatedConfigEntry(); playLuckPing.ConfigEntry = _instance.Config.Bind("Notification", "Play Luck Ding", true, "Play a 'ding' sound when you get lucky."); showBonus = new DelegatedConfigEntry(); showBonus.ConfigEntry = _instance.Config.Bind("Notification", "Show Luck Bonus", true, "Show the amount of luck bonus in the active area."); showLuckPickupEffect = new DelegatedConfigEntry(); showLuckPickupEffect.ConfigEntry = _instance.Config.Bind("Notification", "Show Luck Aura", true, "Show a luck 'aura' effect when first adding a Luckstone to your inventory."); ServerConfiguration.Instance.CreateConfigWatcher(); } } public static class LuckPulseVFX { private static GameObject s_pulsePrefab; private static Material s_pulseMaterial; private static Material GetPulseMaterial() { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if ((Object)(object)s_pulseMaterial != (Object)null) { return s_pulseMaterial; } GameObject prefab = ZNetScene.instance.GetPrefab("vfx_Potion_eitr_minor"); if (Object.op_Implicit((Object)(object)prefab)) { Transform val = prefab.transform.Find("flare"); if (Object.op_Implicit((Object)(object)val)) { ParticleSystemRenderer component = ((Component)val).GetComponent(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)((Renderer)component).sharedMaterial)) { s_pulseMaterial = new Material(((Renderer)component).sharedMaterial); } return s_pulseMaterial; } } Logging.Instance.Warning("Unable to find effectLayer"); return null; } public static GameObject GetOrCreate() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown //IL_003f: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_0110: 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_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Expected O, but got Unknown //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0136: 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_0142: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_017a: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_018f: 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) if (Object.op_Implicit((Object)(object)s_pulsePrefab)) { return s_pulsePrefab; } Color val = default(Color); ((Color)(ref val))..ctor(0.25f, 0.65f, 0.25f); GameObject val2 = new GameObject("vfx_LuckPulse_Root"); val2.SetActive(false); GameObject val3 = new GameObject("vfx_LuckPulse"); val3.transform.SetParent(val2.transform); ParticleSystem val4 = val3.AddComponent(); MainModule main = val4.main; ((MainModule)(ref main)).duration = 0.3f; ((MainModule)(ref main)).startLifetime = MinMaxCurve.op_Implicit(1f); ((MainModule)(ref main)).startSpeed = MinMaxCurve.op_Implicit(0f); ((MainModule)(ref main)).startSize = MinMaxCurve.op_Implicit(0.5f); ((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.white); ((MainModule)(ref main)).loop = false; ((MainModule)(ref main)).playOnAwake = false; ((MainModule)(ref main)).simulationSpace = (ParticleSystemSimulationSpace)0; ShapeModule shape = val4.shape; ((ShapeModule)(ref shape)).shapeType = (ParticleSystemShapeType)0; ((ShapeModule)(ref shape)).radius = 0.3f; EmissionModule emission = val4.emission; ((EmissionModule)(ref emission)).rateOverTime = MinMaxCurve.op_Implicit(0f); ((EmissionModule)(ref emission)).SetBursts((Burst[])(object)new Burst[1] { new Burst(0f, (short)30) }); Gradient val5 = new Gradient(); val5.SetKeys((GradientColorKey[])(object)new GradientColorKey[2] { new GradientColorKey(val, 0f), new GradientColorKey(val, 1f) }, (GradientAlphaKey[])(object)new GradientAlphaKey[2] { new GradientAlphaKey(0.1f, 0f), new GradientAlphaKey(0f, 1f) }); ColorOverLifetimeModule colorOverLifetime = val4.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled = true; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = new MinMaxGradient(val5); ParticleSystemRenderer component = ((Component)val4).GetComponent(); component.renderMode = (ParticleSystemRenderMode)0; Material pulseMaterial = GetPulseMaterial(); if (!Object.op_Implicit((Object)(object)pulseMaterial)) { return null; } ((Renderer)component).material = pulseMaterial; s_pulsePrefab = val2; return s_pulsePrefab; } public static void Pulse(Player player) { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)player)) { return; } GameObject orCreate = GetOrCreate(); if (Object.op_Implicit((Object)(object)orCreate)) { GameObject obj = Object.Instantiate(orCreate, ((Component)player).transform); obj.transform.localPosition = new Vector3(0f, 1.5f, 0f); obj.transform.localRotation = Quaternion.identity; obj.SetActive(true); ParticleSystem componentInChildren = obj.GetComponentInChildren(); if (componentInChildren != null) { componentInChildren.Play(); } MainModule main = componentInChildren.main; float duration = ((MainModule)(ref main)).duration; main = componentInChildren.main; MinMaxCurve startLifetime = ((MainModule)(ref main)).startLifetime; Object.Destroy((Object)(object)obj, duration + ((MinMaxCurve)(ref startLifetime)).constantMax + 0.1f); } } } [BepInPlugin("neobotics.valheim_mod.Luckstone", "Luckstone", "0.1.0")] [BepInProcess("valheim.exe")] [BepInProcess("valheim_server.exe")] public class Luckstone : BaseUnityPlugin { private static Luckstone _modInstance; internal const string PLUGIN_NAME = "Luckstone"; internal const string PLUGIN_VERSION = "0.1.0"; internal const string PLUGIN_GUID = "neobotics.valheim_mod.Luckstone"; internal static Logging Log; internal static bool s_isLuckstoneInInventory = false; internal static ImageHelper s_imageHelper = null; internal static float s_maxDurabilityPerLucksone = 200f; internal static string s_configFolder = string.Empty; internal static Prefabricator s_luckstonePrefab = null; public static SE_Luckstone s_luckSE = null; private static AudioClip s_pingClip = null; private static Harmony harmony = null; internal const string c_luckstonePrefabName = "Neobotics_Luckstone"; public const string c_prototypePrefabName = "Ruby"; public const string c_luckstoneItem = "$item_neobotics_luckstone"; public const string c_luckstoneDescription = "$item_neobotics_luckstone_desc"; public const float c_auraDist = 5f; internal const string c_chestCheck = "Luckstone_Chest"; internal const string c_inventoryCheck = "Luckstone_Stone"; internal const string c_rollTimeCheck = "Luckstone_Time"; internal const string c_ragdollSender = "Luckstone_RS"; internal const string c_ragdollBonus = "Luckstone_RB"; internal static readonly Dictionary PlayerIdToZdoidMap = new Dictionary(); private static int s_bounceFrame = 0; public static Luckstone GetInstance() { return _modInstance; } public static string GetModName() { return "Luckstone"; } public static string GetModVersion() { return "0.1.0"; } private void Awake() { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown //IL_0098: Unknown result type (might be due to invalid IL or missing references) _modInstance = this; Log = Logging.Initialize(Logging.LogLevels.Info, "Luckstone"); harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); harmony.PatchAll(Assembly.GetExecutingAssembly()); ConfigureMod("Luckstone"); s_configFolder = ModResourceBootstrap.InitializeModResources(typeof(Luckstone), "Luckstone"); s_imageHelper = new ImageHelper(s_configFolder); s_luckstonePrefab = new Prefabricator("Neobotics_Luckstone", "Ruby", "$item_neobotics_luckstone", "$item_neobotics_luckstone_desc", ConfigureLuckstone) { TintColor = Color.green }; new Localizer("Luckstone"); Log.Info("0.1.0 Awake"); } private void ConfigureMod(string modName) { Cfg.BepInExConfig((BaseUnityPlugin)(object)_modInstance); } private void OnDestroy() { harmony.UnpatchSelf(); } internal static void CreateLuckStatusEffect() { s_luckSE = ScriptableObject.CreateInstance(); } internal static Sprite GetSprite(string imageFilename) { try { if (s_imageHelper.TryLoadImage(imageFilename + ".png", 1, 1, linear: true, out var image)) { return s_imageHelper.LoadSprite(image); } } catch (Exception) { Log.Warning("Can't create sprite from file"); } return null; } internal static float RandomMagnitude(float magnitude) { return Random.Range(1f, magnitude); } internal static void PlayPing(Vector3 location, float volume = 0.5f) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)s_pingClip)) { GameObject prefab = Utils.GetPrefab("sfx_secretfound"); ZSFX val = default(ZSFX); if (Object.op_Implicit((Object)(object)prefab) && prefab.TryGetComponent(ref val)) { s_pingClip = val.m_audioClips[0]; } else { Log.Warning("Can't find ping clip"); } } if (Object.op_Implicit((Object)(object)s_pingClip)) { AudioSource.PlayClipAtPoint(s_pingClip, location, volume); } } internal static bool TryGetPlayerPosition(long playerId, out Vector3 position) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) position = Vector3.zero; ZDO playerZDO = GetPlayerZDO(playerId); if (playerZDO != null) { position = playerZDO.GetPosition(); return true; } return false; } public static ZDO GetPlayerZDO(long playerId) { //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) if (playerId == 0L || ((Object)(object)Player.m_localPlayer != (Object)null && playerId == ((ZDOID)(ref ((Character)Player.m_localPlayer).m_nview.m_zdo.m_uid)).UserID)) { return ((Character)(Player.m_localPlayer?)).m_nview?.m_zdo; } if (PlayerIdToZdoidMap.TryGetValue(playerId, out var value)) { ZDO zDO = ZDOMan.instance.GetZDO(value); if (zDO != null) { return zDO; } PlayerIdToZdoidMap.Remove(playerId); } foreach (Player allPlayer in Player.GetAllPlayers()) { if (((Character)(allPlayer?)).m_nview?.m_zdo != null && ((ZDOID)(ref ((Character)allPlayer).m_nview.m_zdo.m_uid)).UserID == playerId) { PlayerIdToZdoidMap[playerId] = ((Character)allPlayer).m_nview.m_zdo.m_uid; return ((Character)allPlayer).m_nview.m_zdo; } } return null; } internal static bool TestLucky(long playerId) { Log.Debug($"TestLucky playerId {playerId}"); if (Time.frameCount == s_bounceFrame) { Log.Debug("Debounced"); return false; } s_bounceFrame = Time.frameCount; ZDO playerZDO = GetPlayerZDO(playerId); if (playerZDO == null) { return false; } if (!playerZDO.GetBool("Luckstone_Stone", false)) { Log.Debug("Luckstone not in inventory"); return false; } if ((double)playerZDO.GetFloat("Luckstone_Time", 0f) > ZNet.instance.GetTimeSeconds()) { Log.Debug("Cooldown not elapsed"); return false; } bool flag = Random.value <= GetCurrentLuckChance(); if (!flag) { return false; } return flag; } public static bool UpdateLuckstoneStatus() { Player localPlayer = Player.m_localPlayer; if (!Object.op_Implicit((Object)(object)localPlayer)) { s_isLuckstoneInInventory = false; return false; } bool num = ((Character)localPlayer).m_nview.m_zdo.GetBool("Luckstone_Stone", false); s_isLuckstoneInInventory = IsLuckstoneInInventory(localPlayer); if (num != s_isLuckstoneInInventory) { if (Cfg.showLuckPickupEffect.Value && s_isLuckstoneInInventory) { ((Character)localPlayer).Message((MessageType)1, "$msg_neobotics_new_luck", 0, (Sprite)null); LuckPulseVFX.Pulse(localPlayer); } ((Character)localPlayer).m_nview.m_zdo.Set("Luckstone_Stone", s_isLuckstoneInInventory); } return s_isLuckstoneInInventory; } internal static void RPC_ImLucky(long sender, Vector3 position, int bonus) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) Log.Debug("RPC_ImLucky"); ImLucky(position, bonus); } internal static void ImLucky(Vector3 position, int bonus) { //IL_0041: 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) Log.Debug("You got lucky!"); Player localPlayer = Player.m_localPlayer; if (Cfg.displayLuckMessage.Value) { ((Character)localPlayer).Message((MessageType)1, "$msg_neobotics_got_lucky", 0, (Sprite)null); } if (Cfg.playLuckPing.Value) { PlayPing(((Component)localPlayer).transform.position, 1f); } if (Cfg.showBonus.Value && bonus > 0) { ShowBonusAmount(position, bonus); } ((Character)localPlayer).m_nview.m_zdo.Set("Luckstone_Time", (float)ZNet.instance.GetTimeSeconds() + Cfg.rechargeTime.Value); ItemData val = null; foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if (!(allItem.m_shared.m_name != "$item_neobotics_luckstone") && (val == null || allItem.m_durability < val.m_durability)) { val = allItem; } } if (val != null) { ItemData obj = val; obj.m_durability -= Cfg.luckDrain.Value; if (val.m_durability < Cfg.luckDrain.Value) { ((Humanoid)localPlayer).GetInventory().RemoveItem(val); Log.Debug("A depleted luckstone was removed"); MessageHud.instance.ShowMessage((MessageType)2, "$msg_neobotics_luckstone_break", 0, (Sprite)null, false); } } } internal static void ShowBonusAmount(Vector3 position, int bonusAmount) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) DamageText.instance.ShowText((TextType)7, position, $"++{bonusAmount}", false); Log.Debug($"Bonus amount: {bonusAmount}"); } internal static float GetCurrentLuckChance() { return Cfg.luckChance.Value; } internal static bool IsLuckstoneInInventory(Player player) { if (!Object.op_Implicit((Object)(object)player) || ((Humanoid)player).GetInventory() == null) { return false; } foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (allItem.m_shared.m_name == "$item_neobotics_luckstone") { return true; } } return false; } public static void ConfigureLuckstone(ItemData item) { if (item != null) { item.m_shared.m_maxDurability = 200f; item.m_shared.m_maxStackSize = 1; item.m_shared.m_value = 190; item.m_shared.m_useDurability = true; item.m_shared.m_canBeReparied = false; item.m_shared.m_icons = (Sprite[])(object)new Sprite[1] { GetSprite("Neobotics_Luckstone") }; item.m_durability = item.m_shared.m_maxDurability; } } internal static int DropExtraItems(DropTable dt, Vector3 position) { //IL_00a5: Unknown result type (might be due to invalid IL or missing references) Logging.Instance.Debug("DropExtraItems"); List list = new List(); dt.m_dropChance = 1f; Log.Debug($"Drop Table max drops {dt.m_dropMax}"); int num = (int)Math.Ceiling((float)dt.m_dropMax * RandomMagnitude(Cfg.resourceMagnitude.Value) - (float)dt.m_dropMax); int num2 = Math.Max(1, Random.Range(1, num + 1)); RecalculateDropTable(ref dt); list = dt.GetDropList(num2); Log.Debug($"Luck gave you {list.Count} extra items."); return DropExtraItems(list, position); } internal static int DropExtraItems(List dropList, Vector3 position) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) foreach (GameObject drop in dropList) { Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); _ = Random.insideUnitSphere * 0.5f; SpawnOne(drop, position); } return dropList.Count; } public static void RecalculateDropTable(ref DropTable dropTable) { //IL_0039: 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_00ed: 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_00fc: 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_0106: Unknown result type (might be due to invalid IL or missing references) //IL_0144: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_0089: 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_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) if (dropTable.m_drops != null && dropTable.m_drops.Count > 1) { int count = dropTable.m_drops.Count; float num = 0f; for (int i = 0; i < count; i++) { num += dropTable.m_drops[i].m_weight; } dropTable.m_drops.Sort((DropData a, DropData b) => a.m_weight.CompareTo(b.m_weight)); if (count == 2) { DropData value = dropTable.m_drops[0]; DropData val = dropTable.m_drops[1]; float num2 = val.m_weight / 2f; value.m_weight += num2; val.m_weight -= num2; dropTable.m_drops[0] = value; dropTable.m_drops[1] = val; } else { DropData val2 = dropTable.m_drops[0]; DropData val3 = dropTable.m_drops[1]; float num3 = (num - (val2.m_weight + val3.m_weight)) / 2f; val2.m_weight += num3; val3.m_weight += num3; dropTable.m_drops.Clear(); dropTable.m_drops.Add(val2); dropTable.m_drops.Add(val3); } } } internal static void SpawnMany(GameObject obj, Vector3 position, int count) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < count; i++) { SpawnOne(obj, position); } } internal static GameObject SpawnOne(GameObject obj, Vector3 position) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_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) //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_002f: 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) Quaternion rotation = Quaternion.Euler(0f, (float)Random.Range(0, 360), 0f); Vector3 val = Random.insideUnitSphere * 0.5f; return Utils.SpawnObject(obj, position + val, rotation); } } internal class CombatPatches { [HarmonyPatch(typeof(Character), "RPC_Damage")] private static class Character_Damage_Patch { [HarmonyPrefix] private static void Character_RPC_Damage_Prefix(Character __instance, long sender, HitData hit) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Unknown result type (might be due to invalid IL or missing references) if (!ShouldIRun(__instance.m_nview) || hit == null || hit.m_attacker == ZDOID.None) { return; } bool flag = __instance.IsPlayer(); ZDO zDO = ZDOMan.instance.GetZDO(hit.m_attacker); bool flag2 = zDO != null && zDO.GetLong(ZDOVars.s_playerID, 0L) != 0; if (flag && flag2) { return; } float num = 0f; long num2 = 0L; if (flag) { if (!Cfg.damage.Value) { return; } Log.Debug("Applying damage reduction luck."); num2 = ((ZDOID)(ref __instance.m_nview.m_zdo.m_uid)).UserID; if (!Luckstone.TestLucky(num2)) { return; } num = 1f / Luckstone.RandomMagnitude(Cfg.combatMagnitude.Value); if (Log.Testing()) { Log.Debug($"Luck reduced incoming damage to player {num2} by {(1.0 - (double)num) * 100.0:F1}%"); } } else if (flag2) { if (!Cfg.attack.Value) { return; } Log.Debug("Applying damage increase luck."); num2 = ((ZDOID)(ref zDO.m_uid)).UserID; if (!Luckstone.TestLucky(num2)) { return; } num = Luckstone.RandomMagnitude(Cfg.combatMagnitude.Value); if (Log.Testing()) { Log.Debug($"Luck increased outgoing damage from player {num2} by {((double)num - 1.0) * 100.0:F1}%"); } } if (num != 0f) { hit.ApplyModifier(num); ZRoutedRpc.instance.InvokeRoutedRPC(num2, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position, 0 }); } } } private static Logging Log = Logging.Instance; private static bool ShouldIRun(ZNetView view) { if ((Object)(object)view != (Object)null && view.IsValid()) { return view.IsOwner(); } return false; } } internal class DebugPatches { private static Logging Log = Logging.Instance; } internal class LuckstonePatches { [HarmonyPatch(typeof(Container), "RPC_OpenRespons")] public static class Container_RPC_OpenRespons_Patch { [HarmonyPostfix] private static void Container_RPC_OpenRespons_Postfix(Container __instance, long uid, bool granted) { if (!granted || !Object.op_Implicit((Object)(object)Luckstone.s_luckstonePrefab.Prefab)) { return; } ZNetView nview = __instance.m_nview; if (!ShouldIRun(nview)) { return; } ZDO zDO = nview.GetZDO(); if (zDO == null || zDO.GetLong(ZDOVars.s_creator, 0L) != 0L) { return; } if (zDO.GetBool("Luckstone_Chest", false)) { Logging.Instance.Debug("Container already checked for luckstone"); return; } zDO.Set("Luckstone_Chest", true); if (__instance.m_inventory.HaveEmptySlot() && Random.value <= Cfg.chestChance.Value) { __instance.m_inventory.AddItem(Luckstone.s_luckstonePrefab.Prefab, 1); } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public static class CharacterDrop_GenerateDropList_Patch { [HarmonyPostfix] private static void CharacterDrop_GenerateDropList_Postfix(CharacterDrop __instance, ref List> __result) { if (!Object.op_Implicit((Object)(object)Luckstone.s_luckstonePrefab.Prefab) || !Object.op_Implicit((Object)(object)__instance.m_character) || !__instance.m_character.IsOwner()) { return; } MonsterAI val = default(MonsterAI); ((Component)__instance.m_character).TryGetComponent(ref val); if (__instance.m_character.IsPlayer() || __instance.m_character.IsTamed()) { return; } float num = 0f; if (__instance.m_character.IsBoss()) { num = Cfg.bossChance.Value; } else { int level = __instance.m_character.m_level; if (level > 1 && Cfg.starScaling.Value) { num = Mathf.Clamp(Cfg.dropChance.Value * (float)(level - 1), 0f, 1f); } } if (num > 0f && Random.value <= num) { GameObject prefab = Luckstone.s_luckstonePrefab.Prefab; if (Object.op_Implicit((Object)(object)prefab)) { __result.Add(new KeyValuePair(prefab, 1)); } } } } private static bool ShouldIRun(ZNetView view) { if ((Object)(object)view != (Object)null && view.IsValid()) { return view.IsOwner(); } return false; } } internal class PlayerPatches { [HarmonyPatch(typeof(Player), "Update")] public static class Player_Update_Patch { private static void Postfix(Player __instance) { if (Time.unscaledTime >= s_nextUnscaledTime) { Luckstone.UpdateLuckstoneStatus(); s_nextUnscaledTime = Mathf.Max(s_nextUnscaledTime, Time.unscaledTime) + 1f; } } } private static float s_nextUnscaledTime = 0f; private static Logging Log = Logging.GetLogger(); } internal class ResourcePatches { [HarmonyPatch(typeof(InventoryGui), "DoCrafting")] public static class InventoryGui_DoCrafting_Patch { [HarmonyPrefix] private static void InventoryGui_DoCrafting_Prefix(InventoryGui __instance, Player player) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) Log.Debug("InventoryGui_DoCrafting_Prefix"); s_isLuckable = false; s_bonus = 0; if (player.m_noPlacementCost) { return; } CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation != (Object)null) { if (foodStations.Contains(currentCraftingStation.m_name)) { if (!Cfg.food.Value) { return; } } else if (!Cfg.crafting.Value) { return; } } SharedData shared = __instance.m_craftRecipe.m_item.m_itemData.m_shared; if (shared.m_maxStackSize > 1 && luckableTypes.Contains(shared.m_itemType) && (!(shared.m_name == "$item_fish_raw") || Cfg.food.Value)) { s_isLuckable = Luckstone.TestLucky(((ZDOID)(ref ((Character)player).m_nview.m_zdo.m_uid)).UserID); } } [HarmonyPostfix] private static void Inventory_Do_Crafting_Postfix(InventoryGui __instance, Player player) { //IL_0057: Unknown result type (might be due to invalid IL or missing references) Log.Debug("InventoryGui_DoCrafting_Postfix"); if (s_bonus > 0) { long userID = ((ZDOID)(ref ((Character)player).m_nview.m_zdo.m_uid)).UserID; CraftingStation currentCraftingStation = player.GetCurrentCraftingStation(); if (!((Object)(object)currentCraftingStation == (Object)null)) { ZRoutedRpc.instance.InvokeRoutedRPC(userID, "RPC_ImLucky", new object[2] { ((Component)currentCraftingStation).transform.position, s_bonus }); s_bonus = 0; } } } [HarmonyFinalizer] private static void Inventory_Do_Crafting_Finalizer(InventoryGui __instance, Player player) { s_bonus = 0; s_isLuckable = false; } } [HarmonyPatch(typeof(Recipe), "GetAmount")] private static class Recipe_GetAmount_Patch { [HarmonyPostfix] private static void Recipe_GetAmount_Postfix(Recipe __instance, ref int __result) { Log.Debug("Recipe_GetAmount_Patch_Postfix"); if (s_isLuckable) { int num = __result; __result = Mathf.CeilToInt((float)__result * Luckstone.RandomMagnitude(Cfg.resourceMagnitude.Value)); s_bonus = __result - num; } } } [HarmonyPatch(typeof(Pickable), "RPC_Pick")] private static class Pickable_RPC_Pick_Patch { [HarmonyPrefix] private static void Pickable_RPC_Pick_Prefix(Pickable __instance, long sender, ref int bonus) { //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: 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_011e: Unknown result type (might be due to invalid IL or missing references) Log.Debug("Pickable_RPC_Pick_Prefix"); if (!Cfg.picking.Value || !ShouldIRun(__instance.m_nview)) { return; } SharedData shared = __instance.m_itemPrefab.GetComponent().m_itemData.m_shared; if (shared.m_maxStackSize <= 1) { return; } Vector3 position; if (!luckableTypes.Contains(shared.m_itemType)) { if (Log.Testing()) { Log.Debug($"Skipping {shared.m_name} type {shared.m_itemType}"); } } else if (Luckstone.TryGetPlayerPosition(sender, out position) && !(Vector3.Distance(position, ((Component)__instance).transform.position) >= 5f) && Luckstone.TestLucky(sender)) { int num = bonus; bonus = Mathf.RoundToInt(Luckstone.RandomMagnitude(Cfg.resourceMagnitude.Value) + (float)bonus); if (Log.Testing()) { Log.Debug($"Luck increased pick bonus from {num} to {bonus}"); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position, bonus }); } } } [HarmonyPatch(typeof(PickableItem), "RPC_Pick")] private static class PickableItem_RPC_Pickp_Patch { [HarmonyPrefix] private static void PickableItem_RPC_Pick_Prefix(PickableItem __instance, long sender) { //IL_004d: 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) Log.Debug("PickableItem_Drop_Patch_Prefix"); s_bonus = 0; s_isLuckable = false; if (ShouldIRun(__instance.m_nview) && Cfg.picking.Value) { ItemData itemData = __instance.m_itemPrefab.m_itemData; if (luckableTypes.Contains(itemData.m_shared.m_itemType) && Luckstone.TryGetPlayerPosition(sender, out var position) && !(Vector3.Distance(position, ((Component)__instance).transform.position) >= 5f) && Luckstone.TestLucky(sender)) { s_isLuckable = true; } } } [HarmonyPostfix] private static void PickableItem_RPC_Pick_Postfix(PickableItem __instance, long sender) { //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_0055: Unknown result type (might be due to invalid IL or missing references) if (s_bonus > 0) { if (Log.Testing()) { Log.Debug($"Luck increased pickable item stack size BY {s_bonus}"); } ZRoutedRpc.instance.InvokeRoutedRPC(sender, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position + Vector3.up, s_bonus }); s_bonus = 0; } } [HarmonyFinalizer] private static void PickableItem_RPC_Pick_Finalizer(PickableItem __instance, long sender) { Log.Debug("PickableItem_Drop_Patch_Finalizer"); s_isLuckable = false; s_bonus = 0; } } [HarmonyPatch(typeof(PickableItem), "GetStackSize")] private static class PickableItem_GetStackSize_Patch { [HarmonyPostfix] private static void PickableItem_GetStackSize_Postfix(PickableItem __instance, int __result) { if (s_isLuckable) { s_isLuckable = false; Log.Debug("PickableItem_GetStackSize_Patch_Postfix"); s_bonus = 0; int num = __result; _ = __instance.m_itemPrefab.m_itemData.m_shared.m_maxStackSize; __result = Mathf.CeilToInt((float)__result * Luckstone.RandomMagnitude(Cfg.resourceMagnitude.Value)); s_bonus = __result - num; } } } [HarmonyPatch(typeof(MineRock), "RPC_Hit")] private static class MineRock_RPC_Hit_Patch { [HarmonyPrefix] private static void MineRock_RPC_Damage_Prefix(long sender, MineRock __instance, HitData hit, int hitAreaIndex, out bool __state) { Log.Debug("MineRock_RPC_Damage_Prefix"); __state = ShouldIRun(__instance.m_nview); } [HarmonyPostfix] private static void MineRock_RPC_Hit_Postfix(long sender, MineRock __instance, HitData hit, int hitAreaIndex, bool __state) { //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //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) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) Log.Debug("MineRock_RPC_Hit_Postfix"); if (!Cfg.mining.Value || !__state) { return; } Collider hitArea = __instance.GetHitArea(hitAreaIndex); if (!((Object)(object)hitArea == (Object)null) && ((Component)hitArea).gameObject.activeInHierarchy) { return; } ZDO zDO = ZDOMan.instance.GetZDO(hit.m_attacker); if (zDO == null) { Log.Debug("Can't get attacker's ZDO"); return; } Vector3 position = zDO.GetPosition(); long owner = zDO.GetOwner(); if (hit.m_point == Vector3.zero) { Log.Debug("Can't get last hit position."); } else if (Vector3.Distance(position, hit.m_point) >= 5f) { Log.Debug("Hit location outside of Luckstone aura"); } else if (Luckstone.TestLucky(owner)) { int num = Luckstone.DropExtraItems(__instance.m_dropItems.Clone(), hit.m_point); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "RPC_ImLucky", new object[2] { hit.m_point, num }); } } } [HarmonyPatch(typeof(MineRock5), "DamageArea")] private static class MineRock5_DamageArea_Patch { [HarmonyPrefix] private static void MineRock5_DamageArea_Prefix(MineRock5 __instance, int hitAreaIndex, HitData hit, out bool __state) { Log.Debug("MineRock5_DamageArea_Prefix"); __state = ShouldIRun(__instance.m_nview); } [HarmonyPostfix] private static void MineRock5_DamageArea_Postfix(MineRock5 __instance, int hitAreaIndex, HitData hit, bool __state) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: 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) Log.Debug("MineRock5_DamageArea_Postfix"); if (!Cfg.mining.Value || !__state) { return; } HitArea hitArea = __instance.GetHitArea(hitAreaIndex); if (hitArea != null && !(hitArea.m_health <= 0f)) { return; } ZDO zDO = ZDOMan.instance.GetZDO(hit.m_attacker); if (zDO == null) { Log.Debug("Can't get attacker's ZDO"); return; } Vector3 position = zDO.GetPosition(); long owner = zDO.GetOwner(); if (hit.m_point == Vector3.zero) { Log.Debug("Can't get last hit position."); } else if (Vector3.Distance(position, hit.m_point) >= 5f) { Log.Debug("Hit location outside of Luckstone aura"); } else if (Luckstone.TestLucky(owner)) { int num = Luckstone.DropExtraItems(__instance.m_dropItems.Clone(), hit.m_point); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "RPC_ImLucky", new object[2] { hit.m_point, num }); } } } [HarmonyPatch(typeof(Destructible), "Destroy")] private static class Destructible_Destroy_Patch { [HarmonyPostfix] private static void Destructible_Destroy_Postfix(Destructible __instance, HitData hit) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) Log.Debug("Destructible_Destroy_Patch_Postfix"); if (!__instance.m_destroyed || hit == null) { return; } if (!allowedDestructables.Contains(Utils.UnClonifiedName(((Object)__instance).name))) { if (Log.Testing()) { Log.Debug(((Object)__instance).name + " is not a luckable type"); } } else { if (!Cfg.mining.Value) { return; } DropOnDestroyed val = default(DropOnDestroyed); if (!((Component)__instance).TryGetComponent(ref val)) { Log.Debug("No drop on destroyed found"); return; } ZDO zDO = ZDOMan.instance.GetZDO(hit.m_attacker); if (zDO == null) { Log.Debug("Can't get attacker's ZDO"); return; } Vector3 position = zDO.GetPosition(); long owner = zDO.GetOwner(); if (hit.m_point == Vector3.zero) { Log.Debug("Can't get last hit position."); } else if (Vector3.Distance(position, hit.m_point) >= 5f) { Log.Debug("Hit location outside of Luckstone aura"); } else if (Luckstone.TestLucky(owner)) { int num = Luckstone.DropExtraItems(val.m_dropWhenDestroyed.Clone(), hit.m_point); ZRoutedRpc.instance.InvokeRoutedRPC(owner, "RPC_ImLucky", new object[2] { hit.m_point, num }); } } } } [HarmonyPatch(typeof(TreeBase), "RPC_Damage")] private static class TreeBase_RPC_Damage_Patch { [HarmonyPostfix] private static void TreeBase_RPC_Damage_Postfix(TreeBase __instance, long sender, HitData hit) { //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_0067: 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) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Log.Debug("TreeBase_RPC_Damage_Postfix"); if (Cfg.woodcutting.Value && !__instance.m_nview.IsValid() && !(hit.m_attacker == ZDOID.None)) { long userID = ((ZDOID)(ref hit.m_attacker)).UserID; Character attacker = hit.GetAttacker(); if (Object.op_Implicit((Object)(object)attacker) && attacker.IsPlayer() && !(Vector3.Distance(((Component)attacker).transform.position, ((Component)__instance).transform.position) >= 5f) && Luckstone.TestLucky(userID)) { int num = Luckstone.DropExtraItems(__instance.m_dropWhenDestroyed.Clone(), ((Component)__instance).transform.position + Vector3.up); ZRoutedRpc.instance.InvokeRoutedRPC(userID, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position + Vector3.up, num }); } } } } [HarmonyPatch(typeof(TreeLog), "RPC_Damage")] private static class TreeLog_RPC_Damage_Patch { [HarmonyPostfix] private static void TreeLog_RPC_Damage_Postfix(TreeLog __instance, long sender, HitData hit) { //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_0067: 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) //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) Log.Debug("TreeLog_RPC_Damage_Postfix"); if (Cfg.woodcutting.Value && !__instance.m_nview.IsValid() && !(hit.m_attacker == ZDOID.None)) { long userID = ((ZDOID)(ref hit.m_attacker)).UserID; Character attacker = hit.GetAttacker(); if (Object.op_Implicit((Object)(object)attacker) && attacker.IsPlayer() && !(Vector3.Distance(((Component)attacker).transform.position, ((Component)__instance).transform.position) >= 5f) && Luckstone.TestLucky(userID)) { int num = Luckstone.DropExtraItems(__instance.m_dropWhenDestroyed.Clone(), ((Component)__instance).transform.position + Vector3.up); ZRoutedRpc.instance.InvokeRoutedRPC(userID, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position + Vector3.up, num }); } } } } [HarmonyPatch(typeof(FishingFloat), "Catch")] private static class FishingFloat_Catch_Patch { [HarmonyPrefix] private static void FishingFloat_Catch_Prefix(Fish fish, Character owner) { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) Log.Debug("FishingFloat_Catch_Prefix"); if (Cfg.fishing.Value && Object.op_Implicit((Object)(object)fish)) { long userID = ((ZDOID)(ref owner.m_nview.m_zdo.m_uid)).UserID; if (Luckstone.TestLucky(userID)) { int num = Luckstone.DropExtraItems(fish.m_extraDrops, ((Component)fish).transform.position); ZRoutedRpc.instance.InvokeRoutedRPC(userID, "RPC_ImLucky", new object[2] { ((Component)fish).transform.position, num }); } } } } private static Logging Log = Logging.Instance; private static HashSet foodStations = new HashSet { "$piece_cauldron", "$piece_meadcauldron", "$piece_preptable" }; private static HashSet allowedDestructables = new HashSet { "GuckSack", "MineRock_Obsidian", "MineRock_Tin", "MineRock_Iron", "MineRock_Copper", "MineRock_Silver", "GuckSack_small", "Barnacle" }; private static HashSet luckableTypes = new HashSet { (ItemType)9, (ItemType)2, (ItemType)23, (ItemType)1 }; private static bool s_isLuckable = false; private static int s_bonus = 0; private static bool ShouldIRun(ZNetView view) { if ((Object)(object)view != (Object)null && view.IsValid()) { return view.IsOwner(); } return false; } } internal class SEManPatches { [HarmonyPatch(typeof(SEMan), "GetHUDStatusEffects")] private static class SEMan_GetHUDStatusEffects_Patch { [HarmonyPrefix] private static void SEMan_GetHUDStatusEffects_Prefix(List effects) { if (Cfg.statusEffect.Value) { if (!Object.op_Implicit((Object)(object)Luckstone.s_luckSE)) { Luckstone.CreateLuckStatusEffect(); } if (Luckstone.s_isLuckstoneInInventory) { effects.Add((StatusEffect)(object)Luckstone.s_luckSE); } } } } } public class SE_Luckstone : SE_Stats { public SE_Luckstone() { ((Object)this).name = "se_luckstone_luck"; ((StatusEffect)this).m_name = "$status_neobotics_luckstone"; ((StatusEffect)this).m_tooltip = "$status_neobotics_luckstone_tooltip"; ((StatusEffect)this).m_startMessage = "$status_neobotics_luckstone_active"; ((StatusEffect)this).m_icon = Luckstone.GetSprite("Neobotics_Luckstone"); } } } namespace Luckstone.Patches { internal class CharacterPatches { [HarmonyPatch(typeof(CharacterDrop), "OnDeath")] private static class CharacterDrop_OnDeath_Patch { [HarmonyPostfix] private static void CharacterDrop_OnDeath_Postfix(CharacterDrop __instance) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) Log.Debug("CharacterDrop_OnDeath_Patch_Postfix"); if (s_dropData.bonus > 0) { ZRoutedRpc.instance.InvokeRoutedRPC(s_dropData.playerId, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position, s_dropData.bonus }); } } [HarmonyFinalizer] private static void CharacterDrop_OnDeath_Finalizer(CharacterDrop __instance) { s_dropData = (playerId: 0L, bonus: 0); } } [HarmonyPatch(typeof(Ragdoll), "SaveLootList")] private static class Ragdoll_SaveLootList_Patch { [HarmonyPostfix] private static void Ragdoll_SaveLootList_Postfix(Ragdoll __instance, CharacterDrop characterDrop) { Log.Debug("Ragdoll_SaveLootList_Patch_Postfix"); if (s_dropData.bonus > 0) { if (Log.Testing()) { Log.Debug($"Saving sender {s_dropData.playerId} and bonus {s_dropData.bonus} on Ragdoll"); } ZDO zdo = __instance.m_nview.m_zdo; zdo.Set("Luckstone_RS", s_dropData.playerId); zdo.Set("Luckstone_RB", s_dropData.bonus); } } [HarmonyFinalizer] private static void Ragdoll_SaveLootList_Finalizer(Ragdoll __instance) { s_dropData = (playerId: 0L, bonus: 0); } } [HarmonyPatch(typeof(Ragdoll), "SpawnLoot")] private static class Ragdoll_SpawnLoot_Patch { [HarmonyPostfix] private static void Ragdoll_SpawnLoot_Postfix(Ragdoll __instance) { //IL_007c: Unknown result type (might be due to invalid IL or missing references) Log.Debug("Ragdoll_SpawnLoot_Patch_Postfix"); ZDO zdo = __instance.m_nview.m_zdo; long num = zdo.GetLong("Luckstone_RS", 0L); int num2 = zdo.GetInt("Luckstone_RB", 0); if (Log.Testing()) { Log.Debug($"Ragdoll sender {num} bonus {num2}"); } if (num != 0L) { ZRoutedRpc.instance.InvokeRoutedRPC(num, "RPC_ImLucky", new object[2] { ((Component)__instance).transform.position, num2 }); } } } [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] private static class CharacterDrop_GenerateDropList_Patch { [HarmonyPostfix] private static void Character_GenerateDropList_Postfix(CharacterDrop __instance, List> __result) { Log.Debug("CharacterDrop_GenerateDropList_Postfix"); s_dropData = (playerId: 0L, bonus: 0); if (!Cfg.looting.Value) { return; } Character character = __instance.m_character; if (character.IsPlayer() || character.IsBoss() || __result == null || __result.Count == 0 || !TryGetPlayerIdFromDropsHit(__instance, out var playerId) || !Luckstone.TestLucky(playerId)) { return; } int count = __result.Count; float num = Luckstone.RandomMagnitude(Cfg.resourceMagnitude.Value); int num2 = Mathf.CeilToInt((float)count * num - (float)count); if (num2 > 0) { List> list = new List>(num2); if (Log.Testing()) { Log.Debug($"Adding {num2} extra items to {count} (x{num})"); } for (int i = 0; i < num2; i++) { KeyValuePair keyValuePair = __result[Random.Range(0, count)]; KeyValuePair item = new KeyValuePair(keyValuePair.Key, keyValuePair.Value); list.Add(item); } __result.AddRange(list); s_dropData = (playerId: playerId, bonus: num2); } } } private static Logging Log = Logging.Instance; private static (long playerId, int bonus) s_dropData = (playerId: 0L, bonus: 0); internal static bool TryGetPlayerIdFromDropsHit(CharacterDrop characterDrop, out long playerId) { //IL_001b: 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) playerId = 0L; HitData val = characterDrop.m_character?.m_lastHit; if (val == null || val.m_attacker == ZDOID.None) { return false; } Character attacker = val.GetAttacker(); if ((Object)(object)attacker == (Object)null || !attacker.IsPlayer()) { return false; } playerId = ((ZDOID)(ref val.m_attacker)).UserID; return true; } } internal class ZSystemPatches { [HarmonyPatch(typeof(ZNet), "Awake")] private static class ZNet_Awake_Patch { [HarmonyPostfix] private static void ZNet_Awake_Postfix(ZNet __instance) { Log.Debug("ZNet_Awake_Patch_Postfix"); ZRoutedRpc.instance.Register("RPC_ImLucky", (Action)Luckstone.RPC_ImLucky); } } [HarmonyPatch(typeof(Game), "Start")] public static class Game_Start_Patch { [HarmonyPostfix] public static void Postfix() { Log.Debug("Game_Start_Prefix"); Luckstone.PlayerIdToZdoidMap.Clear(); } } private static Logging Log = Logging.Instance; } }