Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of NotYourLoot v0.7.1
NotYourLoot.dll
Decompiled 4 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using EpicLoot; using EpicLoot_UnityLib; using HarmonyLib; using Jotunn.Managers; using TMPro; using UnityEngine; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("NotYourLoot")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("NotYourLoot")] [assembly: AssemblyTitle("NotYourLoot")] [assembly: AssemblyVersion("1.0.0.0")] namespace NotYourLoot; internal static class AdventureBackpackTooltip { [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static class GetTooltipPatch { private static void Postfix(ItemData item, bool appending, ref string __result) { if (!appending && item != null && !string.IsNullOrEmpty(__result) && !__result.Contains("Items inside weigh ") && TryGetMultiplier(item, out var multiplier)) { int num = Mathf.RoundToInt((1f - multiplier) * 100f); if (num > 0) { __result = __result + "\nItems inside weigh " + num + "% less"; } } } } private const string AssemblyName = "AdventureBackpacks"; private const string Prefix = "Items inside weigh "; private static MethodInfo _tryGetBackpackItem; private static bool TryGetMultiplier(ItemData item, out float multiplier) { multiplier = 1f; try { if (item == null) { return false; } if (_tryGetBackpackItem == null && !ResolveBackpackMethod()) { return false; } object[] array = new object[2] { item, null }; object obj = _tryGetBackpackItem.Invoke(null, array); if (!(obj is bool) || !(bool)obj || array[1] == null) { return false; } object obj2 = array[1]; FieldInfo fieldInfo = AccessTools.Field(obj2.GetType(), "WeightMultiplier"); if (fieldInfo == null) { return false; } object value = fieldInfo.GetValue(obj2); if (value == null) { return false; } PropertyInfo property = value.GetType().GetProperty("Value", BindingFlags.Instance | BindingFlags.Public); if (property == null) { return false; } if (!(property.GetValue(value) is float num)) { return false; } multiplier = Mathf.Clamp01(num); return true; } catch { return false; } } private static bool ResolveBackpackMethod() { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => a.GetName().Name == "AdventureBackpacks"); if (assembly == null) { return false; } Type[] array; try { array = assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { array = ex.Types.Where((Type t) => t != null).ToArray(); } Type[] array2 = array; for (int num = 0; num < array2.Length; num++) { MethodInfo methodInfo = array2[num].GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo m) { if (m.Name != "TryGetBackpackItem") { return false; } ParameterInfo[] parameters = m.GetParameters(); return parameters.Length == 2 && parameters[0].ParameterType == typeof(ItemData) && parameters[1].ParameterType.IsByRef && m.ReturnType == typeof(bool); }); if (methodInfo != null) { _tryGetBackpackItem = methodInfo; return true; } } return false; } } internal static class AudioPatches { private static readonly HashSet<int> CaptainScaledObjects = new HashSet<int>(); private static readonly HashSet<int> EpicMmoScaledObjects = new HashSet<int>(); private static readonly HashSet<string> EpicMmoLoggedPrefabs = new HashSet<string>(StringComparer.Ordinal); private static bool _captainInstalled; private static AudioClip _heroAwakensReplacementClip; private static AudioSource _heroAwakensReplacementSource; private static AudioClip _questCompleteReplacementClip; private static AudioSource _questCompleteReplacementSource; internal static void Install(Harmony harmony) { if (harmony != null) { InstallCaptainPatches(harmony); InstallEpicMmoPatches(harmony); } } internal static IEnumerator DelayedEpicMmoScan() { int attempt = 0; while (attempt < 10) { if (attempt > 0) { yield return (object)new WaitForSeconds(1f); } int num = ScaleEpicMmoAssets(); if (num > 0) { NotYourLootPlugin.LogInfo($"EpicMMO audio normalization applied to {num} AudioSource(s)."); } int num2 = attempt + 1; attempt = num2; } } internal static IEnumerator DelayedEpicMmoOrbEffectCleanup() { int attempt = 0; while (attempt < 10) { if (attempt > 0) { yield return (object)new WaitForSeconds(1f); } if (!((Object)(object)ObjectDB.instance == (Object)null)) { bool flag = false; int num = 0; for (int i = 1; i <= 8; i++) { string text = $"mmo_orb{i}"; GameObject itemPrefab = ObjectDB.instance.GetItemPrefab(text); if ((Object)(object)itemPrefab == (Object)null) { continue; } ItemDrop component = itemPrefab.GetComponent<ItemDrop>(); if ((Object)(object)component == (Object)null || component.m_itemData == null || component.m_itemData.m_shared == null) { continue; } flag = true; StatusEffect consumeStatusEffect = component.m_itemData.m_shared.m_consumeStatusEffect; if ((Object)(object)consumeStatusEffect == (Object)null || consumeStatusEffect.m_startEffects == null || consumeStatusEffect.m_startEffects.m_effectPrefabs == null) { continue; } EffectData[] effectPrefabs = consumeStatusEffect.m_startEffects.m_effectPrefabs; foreach (EffectData val in effectPrefabs) { if (val != null && !((Object)(object)val.m_prefab == (Object)null) && val.m_enabled && (string.Equals(((Object)val.m_prefab).name, "fx_GP_Activation", StringComparison.Ordinal) || string.Equals(((Object)val.m_prefab).name, "sfx_Potion_stamina_Start", StringComparison.Ordinal))) { val.m_enabled = false; num++; } } } if (flag) { NotYourLootPlugin.LogInfo("EpicMMO XP orb cleanup: disabled " + $"{num} unwanted start effect(s)."); yield break; } } int j = attempt + 1; attempt = j; } NotYourLootPlugin.LogWarning("EpicMMO XP orb cleanup could not find registered XP orb prefabs."); } internal static int ScaleEpicMmoAssets() { if (NotYourLootPlugin.AudioEpicMmoEnabled == null || !NotYourLootPlugin.AudioEpicMmoEnabled.Value) { return 0; } float value = NotYourLootPlugin.AudioEpicMmoVolume.Value; int num = 0; bool flag = false; Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if ((assembly.GetName().Name ?? string.Empty).IndexOf("EpicMMO", StringComparison.OrdinalIgnoreCase) < 0) { continue; } flag = true; foreach (Type loadableType in GetLoadableTypes(assembly)) { FieldInfo[] fields; try { fields = loadableType.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); } catch { continue; } FieldInfo[] array = fields; foreach (FieldInfo fieldInfo in array) { if (string.Equals(fieldInfo.FieldType.FullName, "UnityEngine.AssetBundle", StringComparison.Ordinal)) { object value2; try { value2 = fieldInfo.GetValue(null); } catch { continue; } if (value2 != null) { num += ScaleGameObjectsFromAssetBundle(value2, fieldInfo.FieldType, value); } } } } } if ((Object)(object)ZNetScene.instance != (Object)null) { num += ScaleEpicPrefabByName("LevelUpVFX", value); num += ScaleEpicPrefabByName("LevelUpVFX2", value); } if (!flag && EpicMmoScaledObjects.Count == 0) { return 0; } return num; } private static int ScaleGameObjectsFromAssetBundle(object bundle, Type assetBundleType, float multiplier) { try { MethodInfo method = assetBundleType.GetMethod("LoadAllAssets", BindingFlags.Instance | BindingFlags.Public, null, new Type[1] { typeof(Type) }, null); if (method == null) { return 0; } if (!(method.Invoke(bundle, new object[1] { typeof(GameObject) }) is Array array)) { return 0; } int num = 0; foreach (object item in array) { GameObject val = (GameObject)((item is GameObject) ? item : null); if (val != null) { num += ScaleAudioSources(val, multiplier, EpicMmoScaledObjects); } } return num; } catch (Exception ex) { NotYourLootPlugin.LogWarning("Could not inspect an EpicMMO asset bundle for audio: " + ex.Message); return 0; } } private static int ScaleEpicPrefabByName(string prefabName, float multiplier) { try { GameObject prefab = ZNetScene.instance.GetPrefab(prefabName); return ScaleAudioSources(prefab, multiplier, EpicMmoScaledObjects) + AdjustEpicMmoLevelUpEffects(prefabName, prefab); } catch { return 0; } } private static int AdjustEpicMmoLevelUpEffects(string prefabName, GameObject prefab) { if ((Object)(object)prefab == (Object)null) { return 0; } int num = 0; Transform val = prefab.transform.Find("Wings buff cast"); if ((Object)(object)val != (Object)null) { ((Component)val).gameObject.SetActive(false); num++; NotYourLootPlugin.LogInfo("Disabled EpicMMO Wings buff effect on " + prefabName + "."); } if (prefabName == "LevelUpVFX2") { AudioSource[] componentsInChildren = prefab.GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val2 in componentsInChildren) { if (!((Object)(object)val2 == (Object)null) && !((Object)(object)val2.clip == (Object)null) && !(((Object)val2.clip).name != "level_up_wav")) { val2.volume = 0f; val2.playOnAwake = false; val2.mute = true; num++; NotYourLootPlugin.LogInfo("Suppressed EpicMMO custom level-up theme: level_up_wav"); } } } return num; } private static string GetTransformPath(Transform current, Transform root) { if ((Object)(object)current == (Object)null) { return "<null>"; } List<string> list = new List<string>(); while ((Object)(object)current != (Object)null) { list.Add(((Object)current).name); if ((Object)(object)current == (Object)(object)root) { break; } current = current.parent; } list.Reverse(); return string.Join("/", list); } private static void InstallEpicMmoPatches(Harmony harmony) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown //IL_0097: Expected O, but got Unknown Type type = AccessTools.TypeByName("EpicMMOSystem.PlayerFVX"); if (type == null) { NotYourLootPlugin.LogInfo("EpicMMO PlayerFVX not detected; runtime level-up patch skipped."); return; } MethodInfo methodInfo = AccessTools.Method(type, "levelUp", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.Method(typeof(AudioPatches), "EpicMmoLevelUpPrefix", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.Method(typeof(AudioPatches), "EpicMmoLevelUpPostfix", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null) { NotYourLootPlugin.LogWarning("Could not install EpicMMO level-up runtime patch."); return; } harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), new HarmonyMethod(methodInfo3), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); NotYourLootPlugin.LogInfo("EpicMMO level-up prefix/postfix patches installed."); } private static void EpicMmoLevelUpPrefix() { try { if ((Object)(object)ZNetScene.instance == (Object)null) { return; } int num = 0; int num2 = 0; string[] array = new string[2] { "LevelUpVFX", "LevelUpVFX2" }; foreach (string text in array) { GameObject prefab = ZNetScene.instance.GetPrefab(text); if ((Object)(object)prefab == (Object)null) { continue; } Transform[] componentsInChildren = prefab.GetComponentsInChildren<Transform>(true); foreach (Transform val in componentsInChildren) { if ((Object)(object)val == (Object)null) { continue; } if (((Object)val).name == "Wings buff cast") { AudioSource[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { val2.Stop(); val2.volume = 0f; val2.playOnAwake = false; val2.mute = true; num2++; } } ((Component)val).gameObject.SetActive(false); num++; } else if (((Object)val).name == "WindsSpinePivot" || ((Object)val).name == "Wings buff") { ((Component)val).gameObject.SetActive(false); num++; } else { AudioSource component = ((Component)val).GetComponent<AudioSource>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.clip == (Object)null) && ((Object)component.clip).name == "level_up_wav") { component.Stop(); component.volume = 0f; component.playOnAwake = false; component.mute = true; num2++; } } } } NotYourLootPlugin.LogInfo("EpicMMO pre-spawn level-up cleanup: " + $"{num} Wings object(s) disabled, " + $"{num2} AudioSource(s) muted."); } catch (Exception ex) { NotYourLootPlugin.LogWarning("EpicMMO pre-spawn level-up cleanup failed: " + ex.Message); } } private static void EpicMmoLevelUpPostfix() { try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } Transform[] componentsInChildren = ((Component)localPlayer).GetComponentsInChildren<Transform>(true); int num = 0; int num2 = 0; Transform[] array = componentsInChildren; foreach (Transform val in array) { if ((Object)(object)val == (Object)null) { continue; } if (((Object)val).name == "Wings buff cast" && IsEpicMmoLevelUpChild(val)) { AudioSource[] componentsInChildren2 = ((Component)val).GetComponentsInChildren<AudioSource>(true); foreach (AudioSource val2 in componentsInChildren2) { if (!((Object)(object)val2 == (Object)null)) { val2.Stop(); val2.volume = 0f; val2.playOnAwake = false; val2.mute = true; } } ((Component)val).gameObject.SetActive(false); num++; } else { AudioSource component = ((Component)val).GetComponent<AudioSource>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.clip == (Object)null) && ((Object)component.clip).name == "level_up_wav" && IsEpicMmoLevelUpChild(val)) { component.Stop(); component.volume = 0f; component.playOnAwake = false; component.mute = true; num2++; } } } NotYourLootPlugin.LogInfo("EpicMMO live level-up cleanup: " + $"{num} Wings object(s) disabled, " + $"{num2} theme source(s) muted."); } catch (Exception ex) { NotYourLootPlugin.LogWarning("EpicMMO live level-up cleanup failed: " + ex.Message); } } private static bool IsEpicMmoLevelUpChild(Transform transform) { Transform val = transform; while ((Object)(object)val != (Object)null) { if ((((Object)val).name ?? string.Empty).StartsWith("LevelUpVFX", StringComparison.Ordinal)) { return true; } val = val.parent; } return false; } private static IEnumerable<Type> GetLoadableTypes(Assembly assembly) { try { return assembly.GetTypes(); } catch (ReflectionTypeLoadException ex) { return ex.Types.Where((Type type) => type != null); } catch { return Enumerable.Empty<Type>(); } } private static void InstallCaptainPatches(Harmony harmony) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown Type type = AccessTools.TypeByName("CaptainSkillTree.SimpleVFX"); if (type == null) { NotYourLootPlugin.LogInfo("CaptainSkillTree not detected; Captain audio patches skipped."); return; } MethodInfo methodInfo = AccessTools.Method(typeof(AudioPatches), "CaptainGameObjectPostfix", (Type[])null, (Type[])null); string[] source = new string[7] { "InstantiateVFX", "Play", "PlayAtPosition", "PlayFollowing", "PlayOnPlayer", "PlayOnTarget", "PlayWithRotation" }; int num = 0; MethodInfo[] methods = type.GetMethods(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (MethodInfo methodInfo2 in methods) { if (!(methodInfo2.ReturnType != typeof(GameObject)) && source.Contains(methodInfo2.Name)) { harmony.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, new HarmonyMethod(methodInfo), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } } num += PatchSingleFloatEntryPoint(harmony, "CaptainSkillTree.Audio.QuestCompleteSoundManager", "PlayOnce", "QuestCompleteVolumePrefix"); num += PatchSingleFloatEntryPoint(harmony, "CaptainSkillTree.Audio.HeroAwakensSoundManager", "PlayOnce", "SuppressCaptainHeroAwakensPrefix"); num += PatchPoleSwingEntryPoint(harmony); _captainInstalled = num > 0; NotYourLootPlugin.LogInfo(_captainInstalled ? $"CaptainSkillTree audio normalization installed ({num} hook(s))." : "CaptainSkillTree detected, but no supported audio hooks were found."); } private static int PatchSingleFloatEntryPoint(Harmony harmony, string typeName, string methodName, string prefixName) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown Type type = AccessTools.TypeByName(typeName); if (type == null) { return 0; } MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo candidate) { if (candidate.Name != methodName) { return false; } ParameterInfo[] parameters = candidate.GetParameters(); return parameters.Length == 1 && parameters[0].ParameterType == typeof(float); }); if (methodInfo == null) { return 0; } MethodInfo methodInfo2 = AccessTools.Method(typeof(AudioPatches), prefixName, (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return 1; } private static int PatchPoleSwingEntryPoint(Harmony harmony) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown Type type = AccessTools.TypeByName("CaptainSkillTree.Audio.PoleSwingSoundManager"); if (type == null) { return 0; } MethodInfo methodInfo = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).FirstOrDefault(delegate(MethodInfo candidate) { if (candidate.Name != "PlaySwing") { return false; } ParameterInfo[] parameters = candidate.GetParameters(); return parameters.Length == 2 && parameters[0].ParameterType == typeof(int) && parameters[1].ParameterType == typeof(float); }); if (methodInfo == null) { return 0; } MethodInfo methodInfo2 = AccessTools.Method(typeof(AudioPatches), "CaptainVolume1Prefix", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); return 1; } private static void CaptainGameObjectPostfix(GameObject __result) { if (NotYourLootPlugin.AudioCaptainEnabled != null && NotYourLootPlugin.AudioCaptainEnabled.Value) { ScaleAudioSources(__result, NotYourLootPlugin.AudioCaptainVolume.Value, CaptainScaledObjects, routeToGuiMixer: true); } } private static bool SuppressCaptainHeroAwakensPrefix(ref float __0) { //IL_0024: 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_002f: Expected O, but got Unknown try { AudioClip heroAwakensReplacementClip = GetHeroAwakensReplacementClip(); if ((Object)(object)heroAwakensReplacementClip != (Object)null) { if ((Object)(object)_heroAwakensReplacementSource == (Object)null) { GameObject val = new GameObject("NotYourLoot_HeroAwakensReplacement"); Object.DontDestroyOnLoad((Object)val); _heroAwakensReplacementSource = val.AddComponent<AudioSource>(); _heroAwakensReplacementSource.playOnAwake = false; _heroAwakensReplacementSource.loop = false; _heroAwakensReplacementSource.spatialBlend = 0f; RouteToValheimGuiMixer(_heroAwakensReplacementSource); } float num = NotYourLootPlugin.AudioCaptainLevelUpVolume?.Value ?? 0.65f; _heroAwakensReplacementSource.PlayOneShot(heroAwakensReplacementClip, num); NotYourLootPlugin.LogInfo("CaptainSkillTree HeroAwakens replaced with LockChime.wav " + $"(volume {num:0.###})."); } else { NotYourLootPlugin.LogWarning("LockChime.wav could not be loaded; CaptainSkillTree HeroAwakens remains suppressed."); } } catch (Exception ex) { NotYourLootPlugin.LogWarning("HeroAwakens replacement failed: " + ex.Message); } return false; } private static AudioClip GetHeroAwakensReplacementClip() { if ((Object)(object)_heroAwakensReplacementClip != (Object)null) { return _heroAwakensReplacementClip; } _heroAwakensReplacementClip = LoadPcmWav(Path.Combine(Paths.PluginPath, "NotYourFriend-NotYourLoot", "LockChime.wav"), "NotYourLoot_LockChime", "HeroAwakens replacement"); return _heroAwakensReplacementClip; } private static AudioClip GetQuestCompleteReplacementClip() { if ((Object)(object)_questCompleteReplacementClip != (Object)null) { return _questCompleteReplacementClip; } _questCompleteReplacementClip = LoadPcmWav(Path.Combine(Paths.PluginPath, "NotYourFriend-NotYourLoot", "QuestComplete.wav"), "NotYourLoot_QuestComplete", "Quest-complete replacement"); return _questCompleteReplacementClip; } internal static AudioClip LoadPcmWav(string path, string clipName, string logName) { if (!File.Exists(path)) { NotYourLootPlugin.LogWarning(logName + " WAV not found: " + path); return null; } using FileStream fileStream = File.OpenRead(path); using BinaryReader binaryReader = new BinaryReader(fileStream); string text = new string(binaryReader.ReadChars(4)); binaryReader.ReadInt32(); string text2 = new string(binaryReader.ReadChars(4)); if (text != "RIFF" || text2 != "WAVE") { throw new InvalidDataException(Path.GetFileName(path) + " is not a RIFF/WAVE file."); } ushort num = 0; ushort num2 = 0; int num3 = 0; ushort num4 = 0; byte[] array = null; while (fileStream.Position + 8 <= fileStream.Length) { string text3 = new string(binaryReader.ReadChars(4)); int num5 = binaryReader.ReadInt32(); long position = fileStream.Position; if (text3 == "fmt ") { num = binaryReader.ReadUInt16(); num2 = binaryReader.ReadUInt16(); num3 = binaryReader.ReadInt32(); binaryReader.ReadInt32(); binaryReader.ReadUInt16(); num4 = binaryReader.ReadUInt16(); } else if (text3 == "data") { array = binaryReader.ReadBytes(num5); } long num6 = position + num5; if ((num5 & 1) != 0) { num6++; } fileStream.Position = Math.Min(num6, fileStream.Length); } if (num != 1) { throw new InvalidDataException($"Unsupported WAV format {num}; PCM required."); } if (num2 == 0 || num3 <= 0) { throw new InvalidDataException("Invalid WAV channel/sample-rate information."); } if (num4 != 16) { throw new InvalidDataException($"Unsupported WAV bit depth {num4}; 16-bit required."); } if (array == null || array.Length == 0) { throw new InvalidDataException("WAV contains no PCM data."); } int num7 = array.Length / 2; int num8 = num7 / num2; float[] array2 = new float[num7]; for (int i = 0; i < num7; i++) { short num9 = (short)(array[i * 2] | (array[i * 2 + 1] << 8)); array2[i] = (float)num9 / 32768f; } AudioClip val = AudioClip.Create(clipName, num8, (int)num2, num3, false); val.SetData(array2, 0); NotYourLootPlugin.LogInfo("Loaded " + logName + ": " + Path.GetFileName(path) + " " + $"({num2}ch, {num3} Hz, {num4}-bit)."); return val; } private static void CaptainVolume0Prefix(ref float __0) { if (NotYourLootPlugin.AudioCaptainEnabled != null && NotYourLootPlugin.AudioCaptainEnabled.Value) { __0 = Mathf.Max(0f, __0 * NotYourLootPlugin.AudioCaptainVolume.Value); } } private static void CaptainVolume1Prefix(ref float __1) { if (NotYourLootPlugin.AudioCaptainEnabled != null && NotYourLootPlugin.AudioCaptainEnabled.Value) { __1 = Mathf.Max(0f, __1 * NotYourLootPlugin.AudioCaptainVolume.Value); } } private static bool QuestCompleteVolumePrefix(ref float __0) { //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown if (NotYourLootPlugin.AudioCaptainQuestEnabled == null || !NotYourLootPlugin.AudioCaptainQuestEnabled.Value) { return true; } try { AudioClip questCompleteReplacementClip = GetQuestCompleteReplacementClip(); if ((Object)(object)questCompleteReplacementClip != (Object)null) { if ((Object)(object)_questCompleteReplacementSource == (Object)null) { GameObject val = new GameObject("NotYourLoot_QuestCompleteReplacement"); Object.DontDestroyOnLoad((Object)val); _questCompleteReplacementSource = val.AddComponent<AudioSource>(); _questCompleteReplacementSource.playOnAwake = false; _questCompleteReplacementSource.loop = false; _questCompleteReplacementSource.spatialBlend = 0f; RouteToValheimGuiMixer(_questCompleteReplacementSource); } float num = Mathf.Clamp01(NotYourLootPlugin.AudioCaptainQuestVolume.Value); _questCompleteReplacementSource.PlayOneShot(questCompleteReplacementClip, num); NotYourLootPlugin.LogInfo("CaptainSkillTree quest-complete sound replaced with QuestComplete.wav " + $"(volume {num:0.###})."); } else { NotYourLootPlugin.LogWarning("QuestComplete.wav could not be loaded; CaptainSkillTree quest-complete audio remains suppressed."); } } catch (Exception ex) { NotYourLootPlugin.LogWarning("Quest-complete replacement failed: " + ex.Message); } return false; } internal static void RouteToValheimGuiMixer(AudioSource source) { if (!((Object)(object)source == (Object)null) && !((Object)(object)AudioMan.instance == (Object)null) && !((Object)(object)AudioMan.instance.m_guiMixer == (Object)null)) { source.outputAudioMixerGroup = AudioMan.instance.m_guiMixer; } } private static int ScaleAudioSources(GameObject gameObject, float multiplier, HashSet<int> scaledObjects, bool routeToGuiMixer = false) { if ((Object)(object)gameObject == (Object)null) { return 0; } int instanceID = ((Object)gameObject).GetInstanceID(); if (!scaledObjects.Add(instanceID)) { return 0; } AudioSource[] componentsInChildren = gameObject.GetComponentsInChildren<AudioSource>(true); if (componentsInChildren == null || componentsInChildren.Length == 0) { return 0; } int num = 0; AudioSource[] array = componentsInChildren; foreach (AudioSource val in array) { if (!((Object)(object)val == (Object)null)) { val.volume = Mathf.Clamp01(val.volume * multiplier); if (routeToGuiMixer) { RouteToValheimGuiMixer(val); } num++; } } return num; } } [HarmonyPatch(typeof(ZNetScene), "Awake")] internal static class EpicMmoAudioScenePatch { private static void Postfix() { if ((Object)(object)NotYourLootPlugin.Instance != (Object)null) { ((MonoBehaviour)NotYourLootPlugin.Instance).StartCoroutine(AudioPatches.DelayedEpicMmoScan()); } } } internal static class EpicLootChestProvider { private const string ProviderId = "NotYourFriend.NotYourLoot.ValheimPlusCraftFromChests"; private static ManualLogSource _log; private static Assembly _valheimPlusAssembly; private static Type _inventoryAssistantType; private static Type _configurationType; private static MethodInfo _getNearbyChests; private static MethodInfo _removeNearbyItemsByName; private static bool _registered; private static bool _loggedMissingValheimPlus; private static bool _loggedReflectionFailure; private static EnchantUI _enchantUI; private static AugmentUI _augmentUI; private static ConvertUI _convertUI; private static UpgradeTableUI _upgradeUI; private static RuneUI _runeUI; private static SacrificeUI _sacrificeUI; private static readonly Dictionary<string, int> _chestCountCache = new Dictionary<string, int>(StringComparer.Ordinal); private static float _chestCountCacheExpiresAt; private static int _chestCountCacheTargetId; private static float _chestCountCacheRange; private static bool _chestCountCacheCheckWard; private const float ChestCountCacheLifetime = 0.5f; private static float _queryContextExpiresAt; private static bool _queryContextValid; private static float _queryRange; private static bool _queryCheckWard; private static GameObject _queryTarget; private const float QueryContextLifetime = 0.5f; internal static void Initialize(ManualLogSource log) { _log = log; API.UnregisterInventoryProvider("NotYourFriend.NotYourLoot.ValheimPlusCraftFromChests"); _registered = API.RegisterInventoryProvider("NotYourFriend.NotYourLoot.ValheimPlusCraftFromChests", (Func<List<ItemData>>)null, (Func<string, int>)CountChestItems, (Func<string, int, int>)RemoveChestItems, (Func<ItemData, int, int>)null); if (_registered) { ManualLogSource log2 = _log; if (log2 != null) { log2.LogInfo((object)"[EpicLoot/V+] Registered chest-backed material provider."); } } else { ManualLogSource log3 = _log; if (log3 != null) { log3.LogWarning((object)"[EpicLoot/V+] Failed to register inventory provider."); } } } private static int CountChestItems(string itemName) { if (string.IsNullOrEmpty(itemName)) { return 0; } try { if (!TryGetCachedQueryContext(out var target, out var range, out var checkWard)) { return 0; } EnsureChestCountSnapshot(target, range, checkWard); int value; return _chestCountCache.TryGetValue(itemName, out value) ? Math.Max(0, value) : 0; } catch (Exception ex) { LogReflectionFailure("counting nearby chest materials", ex); return 0; } } private static bool TryGetCachedQueryContext(out GameObject target, out float range, out bool checkWard) { float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < _queryContextExpiresAt) { target = _queryTarget; range = _queryRange; checkWard = _queryCheckWard; if (_queryContextValid) { return (Object)(object)target != (Object)null; } return false; } _queryContextExpiresAt = realtimeSinceStartup + 0.5f; _queryContextValid = false; _queryTarget = null; _queryRange = 0f; _queryCheckWard = true; if (!IsChestContextAllowed()) { target = null; range = 0f; checkWard = true; return false; } if (!TryGetValheimPlusSettings(out var range2, out var checkWard2, out var checkFromWorkbench)) { target = null; range = 0f; checkWard = true; return false; } GameObject searchTarget = GetSearchTarget(checkFromWorkbench); if ((Object)(object)searchTarget == (Object)null) { target = null; range = 0f; checkWard = true; return false; } _queryTarget = searchTarget; _queryRange = range2; _queryCheckWard = checkWard2; _queryContextValid = true; target = _queryTarget; range = _queryRange; checkWard = _queryCheckWard; return true; } private static void EnsureChestCountSnapshot(GameObject target, float range, bool checkWard) { int instanceID = ((Object)target).GetInstanceID(); float realtimeSinceStartup = Time.realtimeSinceStartup; if (realtimeSinceStartup < _chestCountCacheExpiresAt && _chestCountCacheTargetId == instanceID && Mathf.Approximately(_chestCountCacheRange, range) && _chestCountCacheCheckWard == checkWard) { return; } _chestCountCache.Clear(); if (_getNearbyChests.Invoke(null, new object[4] { target, range, checkWard, true }) is IEnumerable enumerable) { foreach (object item in enumerable) { Container val = (Container)((item is Container) ? item : null); if ((Object)(object)val == (Object)null) { continue; } Inventory inventory = val.GetInventory(); if (inventory == null) { continue; } List<ItemData> allItems = inventory.GetAllItems(); if (allItems == null) { continue; } foreach (ItemData item2 in allItems) { if (item2 != null && item2.m_shared != null && !string.IsNullOrEmpty(item2.m_shared.m_name) && item2.m_stack > 0) { string name = item2.m_shared.m_name; if (_chestCountCache.TryGetValue(name, out var value)) { _chestCountCache[name] = value + item2.m_stack; } else { _chestCountCache[name] = item2.m_stack; } } } } } _chestCountCacheTargetId = instanceID; _chestCountCacheRange = range; _chestCountCacheCheckWard = checkWard; _chestCountCacheExpiresAt = realtimeSinceStartup + 0.5f; } private static void InvalidateChestCountSnapshot() { _chestCountCacheExpiresAt = 0f; _chestCountCache.Clear(); _queryContextExpiresAt = 0f; _queryContextValid = false; _queryTarget = null; } private static int RemoveChestItems(string itemName, int amount) { if (string.IsNullOrEmpty(itemName) || amount <= 0 || !IsChestContextAllowed()) { return 0; } if (!TryGetValheimPlusSettings(out var range, out var checkWard, out var checkFromWorkbench)) { return 0; } GameObject searchTarget = GetSearchTarget(checkFromWorkbench); if ((Object)(object)searchTarget == (Object)null) { return 0; } try { object obj = _removeNearbyItemsByName.Invoke(null, new object[5] { searchTarget, range, itemName, amount, checkWard }); if (obj == null) { return 0; } int num = Mathf.Clamp(Convert.ToInt32(obj), 0, amount); if (num > 0) { InvalidateChestCountSnapshot(); } return num; } catch (Exception ex) { LogReflectionFailure("removing nearby chest materials", ex); return 0; } } internal static bool IsChestContextAllowed() { if (IsPanelActive<EnchantUI>(ref _enchantUI)) { return true; } if (IsPanelActive<AugmentUI>(ref _augmentUI)) { return true; } if (IsPanelActive<ConvertUI>(ref _convertUI)) { return true; } if (IsPanelActive<UpgradeTableUI>(ref _upgradeUI)) { return true; } if (IsPanelActive<RuneUI>(ref _runeUI)) { return true; } if (IsPanelActive<SacrificeUI>(ref _sacrificeUI)) { if ((Object)(object)_sacrificeUI.IdentifyToggle != (Object)null) { return _sacrificeUI.IdentifyToggle.isOn; } return false; } return false; } private static bool IsPanelActive<T>(ref T cached) where T : MonoBehaviour { if ((Object)(object)cached != (Object)null && ((Behaviour)cached).isActiveAndEnabled && ((Component)cached).gameObject.activeInHierarchy) { return true; } T[] array = Resources.FindObjectsOfTypeAll<T>(); foreach (T val in array) { if (!((Object)(object)val == (Object)null) && ((Behaviour)(object)val).isActiveAndEnabled && ((Component)(object)val).gameObject.activeInHierarchy) { cached = val; return true; } } return false; } private static bool TryResolveValheimPlus() { if (_valheimPlusAssembly != null && _inventoryAssistantType != null && _configurationType != null && _getNearbyChests != null && _removeNearbyItemsByName != null) { return true; } Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (string.Equals(assembly.GetName().Name, "ValheimPlus", StringComparison.OrdinalIgnoreCase)) { _valheimPlusAssembly = assembly; break; } } if (_valheimPlusAssembly == null) { if (!_loggedMissingValheimPlus) { _loggedMissingValheimPlus = true; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)"[EpicLoot/V+] ValheimPlus is not loaded; chest-backed Epic Loot costs are disabled."); } } return false; } try { _inventoryAssistantType = _valheimPlusAssembly.GetType("ValheimPlus.InventoryAssistant", throwOnError: false); _configurationType = _valheimPlusAssembly.GetType("ValheimPlus.Configurations.Configuration", throwOnError: false); if (_inventoryAssistantType == null || _configurationType == null) { return false; } _getNearbyChests = _inventoryAssistantType.GetMethod("GetNearbyChests", BindingFlags.Static | BindingFlags.Public, null, new Type[4] { typeof(GameObject), typeof(float), typeof(bool), typeof(bool) }, null); _removeNearbyItemsByName = _inventoryAssistantType.GetMethod("RemoveItemInAmountFromAllNearbyChests", BindingFlags.Static | BindingFlags.Public, null, new Type[5] { typeof(GameObject), typeof(float), typeof(string), typeof(int), typeof(bool) }, null); return _getNearbyChests != null && _removeNearbyItemsByName != null; } catch (Exception ex) { LogReflectionFailure("resolving ValheimPlus", ex); return false; } } private static bool TryGetValheimPlusSettings(out float range, out bool checkWard, out bool checkFromWorkbench) { range = 0f; checkWard = true; checkFromWorkbench = false; if (!TryResolveValheimPlus()) { return false; } try { object staticMemberValue = GetStaticMemberValue(_configurationType, "Current"); if (staticMemberValue == null) { return false; } object instanceMemberValue = GetInstanceMemberValue(staticMemberValue, "CraftFromChest"); if (instanceMemberValue == null) { return false; } if (!ReadBool(instanceMemberValue, "IsEnabled", fallback: false)) { return false; } range = Mathf.Clamp(ReadFloat(instanceMemberValue, "range", 10f), 1f, 50f); bool flag = ReadBool(instanceMemberValue, "ignorePrivateAreaCheck", fallback: false); checkWard = !flag; checkFromWorkbench = ReadBool(instanceMemberValue, "checkFromWorkbench", fallback: false); return true; } catch (Exception ex) { LogReflectionFailure("reading ValheimPlus CraftFromChest settings", ex); return false; } } private static GameObject GetSearchTarget(bool checkFromWorkbench) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return null; } if (checkFromWorkbench) { CraftingStation currentCraftingStation = localPlayer.GetCurrentCraftingStation(); if ((Object)(object)currentCraftingStation != (Object)null) { return ((Component)currentCraftingStation).gameObject; } } return ((Component)localPlayer).gameObject; } private static object GetStaticMemberValue(Type type, string name) { PropertyInfo property = type.GetProperty(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null) { return property.GetValue(null); } return type.GetField(name, BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)?.GetValue(null); } private static object GetInstanceMemberValue(object instance, string name) { if (instance == null) { return null; } Type type = instance.GetType(); PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy); if (property != null) { return property.GetValue(instance); } return type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy)?.GetValue(instance); } private static bool ReadBool(object instance, string name, bool fallback) { object instanceMemberValue = GetInstanceMemberValue(instance, name); if (instanceMemberValue == null) { return fallback; } try { return Convert.ToBoolean(instanceMemberValue); } catch { return fallback; } } private static float ReadFloat(object instance, string name, float fallback) { object instanceMemberValue = GetInstanceMemberValue(instance, name); if (instanceMemberValue == null) { return fallback; } try { return Convert.ToSingle(instanceMemberValue); } catch { return fallback; } } private static void LogReflectionFailure(string action, Exception ex) { if (!_loggedReflectionFailure) { _loggedReflectionFailure = true; ManualLogSource log = _log; if (log != null) { log.LogWarning((object)$"[EpicLoot/V+] Error while {action}: {ex}"); } } } } [HarmonyPatch(typeof(EnchantingTableUIPanelBase), "LocalPlayerCanAffordCost")] internal static class EpicLootChestAffordabilityPatch { private static void Postfix(List<InventoryItemListElement> cost, ref bool __result) { if (!__result && cost != null && EpicLootChestProvider.IsChestContextAllowed() && CanAffordThroughEpicLootInventory(cost)) { __result = true; } } internal static bool CanAffordThroughEpicLootInventory(List<InventoryItemListElement> cost) { Dictionary<string, int> dictionary = new Dictionary<string, int>(); foreach (InventoryItemListElement item2 in cost) { if (item2 == null) { continue; } ItemData item = item2.GetItem(); if (item != null && item.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name)) { string name = item.m_shared.m_name; if (!dictionary.ContainsKey(name)) { dictionary[name] = 0; } dictionary[name] += Math.Max(0, item.m_stack); } } foreach (KeyValuePair<string, int> item3 in dictionary) { if (InventoryManagement.Instance.CountItem(item3.Key) < item3.Value) { return false; } } return true; } } [HarmonyPatch(typeof(SacrificeUI), "LocalPlayerCanAffordIdentifyCost")] internal static class EpicLootIdentifyChestAffordabilityPatch { private static void Postfix(List<InventoryItemListElement> cost, ref bool __result) { if (!__result && cost != null && EpicLootChestProvider.IsChestContextAllowed() && EpicLootChestAffordabilityPatch.CanAffordThroughEpicLootInventory(cost)) { __result = true; } } } internal static class EpicLootCostDisplay { [HarmonyPatch(typeof(MultiSelectItemListElement), "SetItem")] private static class MultiSelectItemListElement_SetItem_Patch { private static void Postfix(MultiSelectItemListElement __instance, IListElement item) { //IL_00b1: 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) try { if (!((Object)(object)__instance == (Object)null) && item != null && !((Object)(object)__instance.ItemTotalQuantity == (Object)null) && IsCostListElement(__instance)) { ItemData item2 = item.GetItem(); if (item2 != null && item2.m_shared != null && !string.IsNullOrEmpty(item2.m_shared.m_name)) { int num = Math.Max(0, item2.m_stack); int val = InventoryManagement.Instance.CountItem(item2.m_shared.m_name); val = Math.Max(0, val); __instance.ItemTotalQuantity.text = val + "/" + num; ((Graphic)__instance.ItemTotalQuantity).color = ((val < num) ? Color.red : Color.white); } } } catch { } } } private static bool IsCostListElement(MultiSelectItemListElement element) { Transform transform = ((Component)element).transform; MonoBehaviour[] array = Resources.FindObjectsOfTypeAll<MonoBehaviour>(); foreach (MonoBehaviour val in array) { if ((Object)(object)val == (Object)null || !((Behaviour)val).isActiveAndEnabled || !((Component)val).gameObject.activeInHierarchy) { continue; } Type type = ((object)val).GetType(); string text = type.FullName ?? type.Name; if (!text.Contains("EpicLoot") && !text.Contains("EpicLoot_UnityLib")) { continue; } object memberValue = GetMemberValue(val, "CostList"); Component val2 = (Component)((memberValue is Component) ? memberValue : null); if (!((Object)(object)val2 == (Object)null)) { Transform transform2 = val2.transform; if ((Object)(object)transform == (Object)(object)transform2 || transform.IsChildOf(transform2)) { return true; } } } return false; } private static object GetMemberValue(object instance, string name) { if (instance == null) { return null; } Type type = instance.GetType(); while (type != null) { FieldInfo field = type.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (field != null) { return field.GetValue(instance); } PropertyInfo property = type.GetProperty(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); if (property != null && property.GetIndexParameters().Length == 0) { return property.GetValue(instance); } type = type.BaseType; } return null; } } [HarmonyPatch(typeof(SEMan), "AddStatusEffect", new Type[] { typeof(StatusEffect), typeof(bool), typeof(int), typeof(float), typeof(short) })] internal static class EpicMmoOrbAudioPatch { private static AudioClip _bonusClip; private static AudioSource _bonusSource; private static void Postfix(StatusEffect __result) { if (!((Object)(object)__result == (Object)null) && string.Equals(((Object)__result).name, "MMO_XP", StringComparison.Ordinal)) { PlayBonusSound(); } } private static void PlayBonusSound() { //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Expected O, but got Unknown if (NotYourLootPlugin.AudioEpicMmoEnabled == null || !NotYourLootPlugin.AudioEpicMmoEnabled.Value) { return; } try { if ((Object)(object)_bonusClip == (Object)null) { _bonusClip = AudioPatches.LoadPcmWav(Path.Combine(Paths.PluginPath, "NotYourFriend-NotYourLoot", "Bonus.wav"), "NotYourLoot_EpicMmoOrbBonus", "EpicMMO XP-orb replacement"); } if ((Object)(object)_bonusClip == (Object)null) { NotYourLootPlugin.LogWarning("Bonus.wav could not be loaded for EpicMMO XP orbs."); return; } if ((Object)(object)_bonusSource == (Object)null) { GameObject val = new GameObject("NotYourLoot_EpicMmoOrbBonus"); Object.DontDestroyOnLoad((Object)val); _bonusSource = val.AddComponent<AudioSource>(); _bonusSource.playOnAwake = false; _bonusSource.loop = false; _bonusSource.spatialBlend = 0f; AudioPatches.RouteToValheimGuiMixer(_bonusSource); } float num = Mathf.Clamp01(NotYourLootPlugin.AudioEpicMmoVolume.Value); _bonusSource.PlayOneShot(_bonusClip, num); NotYourLootPlugin.LogInfo("EpicMMO MMO_XP applied: played Bonus.wav " + $"at volume {num:0.###}."); } catch (Exception ex) { NotYourLootPlugin.LogWarning("EpicMMO XP-orb replacement sound failed: " + ex.Message); } } } internal static class HerbalistVegetationPatch { private static ConfigEntry<bool> Enabled; private static ConfigEntry<float> SpawnChance; private static ConfigEntry<int> MinGroup; private static ConfigEntry<int> MaxGroup; private static ConfigEntry<bool> CleanNames; private static readonly HashSet<string> HerbalistPlants = new HashSet<string>(StringComparer.Ordinal) { "BH_Pickable_Boswellia", "BH_Pickable_Chamomile", "BH_Pickable_Chicory", "BH_Pickable_Daisy", "BH_Pickable_Echinacea", "BH_Pickable_Lavender", "BH_Pickable_AslaugsHerb", "BH_Pickable_Bjorncap", "BH_Pickable_HelshadeFungus", "BH_Pickable_LokisTrickcap", "BH_Pickable_NordicFirebloom", "BH_Pickable_SeidrBlossoms", "BH_Pickable_SkaldsIvy", "BH_Pickable_ThorsToadstool", "BH_Pickable_Valhallaberry", "BH_Pickable_ValkyrieFern", "BH_Pickable_VikingsBreadcap" }; internal static void BindConfig(ConfigFile config) { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Expected O, but got Unknown //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown Enabled = config.Bind<bool>("Herbalist - Vegetation", "Enabled", true, "Reduce naturally generated Herbalist vegetation."); SpawnChance = config.Bind<float>("Herbalist - Vegetation", "SpawnChance", 0.5f, new ConfigDescription("Probability of one group attempt per eligible zone.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 0.99f), Array.Empty<object>())); MinGroup = config.Bind<int>("Herbalist - Vegetation", "MinimumGroupSize", 1, new ConfigDescription("Minimum plants attempted per group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); MaxGroup = config.Bind<int>("Herbalist - Vegetation", "MaximumGroupSize", 3, new ConfigDescription("Maximum plants attempted per group.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 10), Array.Empty<object>())); CleanNames = config.Bind<bool>("Herbalist - Names", "Enabled", true, "Use localized names for wild Herbalist plants."); } internal static void Install(Harmony harmony) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Expected O, but got Unknown Type type = AccessTools.TypeByName("Herbalist.Functions.VegetationSetup"); if (type == null) { NotYourLootPlugin.LogInfo("[Herbalist] Not installed; scarcity patch skipped."); return; } MethodInfo methodInfo = AccessTools.Method(type, "Init", new Type[1] { typeof(ZoneSystem) }, (Type[])null); if (methodInfo == null) { NotYourLootPlugin.LogWarning("[Herbalist] VegetationSetup.Init not found."); return; } try { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(HerbalistVegetationPatch), "AfterVegetationInit", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); NotYourLootPlugin.LogInfo("[Herbalist] Vegetation scarcity patch installed."); } catch (Exception ex) { NotYourLootPlugin.LogWarning("[Herbalist] Could not install patch: " + ex); } } private static void AfterVegetationInit(ZoneSystem zoneSystem) { if ((Object)(object)zoneSystem == (Object)null) { return; } bool flag = Enabled != null && Enabled.Value; bool flag2 = CleanNames != null && CleanNames.Value; if (!flag && !flag2) { return; } int num = Math.Max(1, MinGroup.Value); int num2 = Math.Max(num, MaxGroup.Value); int num3 = 0; int num4 = 0; foreach (ZoneVegetation item in zoneSystem.m_vegetation) { if ((Object)(object)item?.m_prefab == (Object)null) { continue; } string name = ((Object)item.m_prefab).name; if (!HerbalistPlants.Contains(name)) { continue; } if (flag) { item.m_max = SpawnChance.Value; item.m_groupSizeMin = num; item.m_groupSizeMax = num2; num3++; } if (flag2) { Pickable component = item.m_prefab.GetComponent<Pickable>(); if ((Object)(object)component != (Object)null) { string overrideName = "$bh_" + name.Substring("BH_Pickable_".Length).ToLowerInvariant(); component.m_overrideName = overrideName; num4++; } } } if (flag && num3 != HerbalistPlants.Count) { NotYourLootPlugin.LogWarning($"[Herbalist] Adjusted {num3}/" + $"{HerbalistPlants.Count} expected vegetation entries."); } else if (flag) { NotYourLootPlugin.LogInfo($"[Herbalist] Adjusted {num3} vegetation entries: " + $"chance={SpawnChance.Value:F2}, " + $"group={num}-{num2}."); } if (flag2) { NotYourLootPlugin.LogInfo($"[Herbalist] Localized {num4}/" + $"{HerbalistPlants.Count} wild plant names."); } } } internal static class ModdedContainerCompatibility { private static readonly HashSet<Container> Containers = new HashSet<Container>(); private static bool _installed; private static readonly FieldInfo LastRevisionField = AccessTools.Field(typeof(Container), "m_lastRevision"); private static readonly MethodInfo CheckAccessMethod = AccessTools.Method(typeof(Container), "CheckAccess", new Type[1] { typeof(long) }, (Type[])null); internal static void Install(Harmony harmony) { //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: Expected O, but got Unknown if (_installed || harmony == null) { return; } try { Type type = AccessTools.TypeByName("ValheimPlus.InventoryAssistant"); if (type == null) { NotYourLootPlugin.LogWarning("[Containers] ValheimPlus InventoryAssistant not found."); return; } MethodInfo methodInfo = AccessTools.Method(type, "GetNearbyChests", new Type[4] { typeof(GameObject), typeof(float), typeof(bool), typeof(bool) }, (Type[])null); if (methodInfo == null) { NotYourLootPlugin.LogWarning("[Containers] ValheimPlus GetNearbyChests method not found."); return; } MethodInfo methodInfo2 = AccessTools.Method(typeof(ModdedContainerCompatibility), "GetNearbyChestsPostfix", (Type[])null, (Type[])null); harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); _installed = true; NotYourLootPlugin.LogInfo("[Containers] Installed modded-container compatibility for ValheimPlus Craft From Chest."); } catch (Exception arg) { NotYourLootPlugin.LogWarning($"[Containers] Failed to install ValheimPlus compatibility: {arg}"); } } internal static void Register(Container container) { if ((Object)(object)container != (Object)null) { Containers.Add(container); } } internal static void Unregister(Container container) { if ((Object)(object)container != (Object)null) { Containers.Remove(container); } } private static void GetNearbyChestsPostfix(GameObject target, float range, bool checkWard, bool includeVehicles, ref List<Container> __result) { //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_0111: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_0119: 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) try { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || (Object)(object)target == (Object)null || range <= 0f) { return; } if (__result == null) { __result = new List<Container>(); } long playerID = localPlayer.GetPlayerID(); Vector3 position = target.transform.position; Containers.RemoveWhere((Container container) => (Object)(object)container == (Object)null); Container[] array = (Container[])(object)new Container[Containers.Count]; Containers.CopyTo(array); Container[] array2 = array; foreach (Container val in array2) { if ((Object)(object)val == (Object)null || __result.Contains(val) || (LastRevisionField != null && LastRevisionField.GetValue(val) is uint num2 && num2 == uint.MaxValue) || val.GetInventory() == null) { continue; } Transform transform = ((Component)val).transform; if ((Object)(object)transform == (Object)null) { continue; } Vector3 position2 = transform.position; if (Vector3.Distance(position, position2) >= range) { continue; } if (CheckAccessMethod != null) { object obj = CheckAccessMethod.Invoke(val, new object[1] { playerID }); if (obj is bool && !(bool)obj) { continue; } } if ((!checkWard || PrivateArea.CheckAccess(position2, 0f, false, true)) && !HasVehicleInHierarchy(val)) { Piece val2 = FindAssociatedPiece(val); if (!((Object)(object)val2 == (Object)null) && val2.IsPlacedByPlayer()) { __result.Add(val); } } } } catch (Exception arg) { NotYourLootPlugin.LogWarning($"[Containers] Supplemental nearby-container scan failed: {arg}"); } } private static Piece FindAssociatedPiece(Container container) { if ((Object)(object)container == (Object)null) { return null; } Piece componentInParent = ((Component)container).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent != (Object)null) { return componentInParent; } Transform root = ((Component)container).transform.root; if ((Object)(object)root == (Object)null) { return null; } return ((Component)root).GetComponentInChildren<Piece>(true); } private static bool HasVehicleInHierarchy(Container container) { if ((Object)(object)container == (Object)null) { return false; } if ((Object)(object)((Component)container).GetComponentInParent<Vagon>() != (Object)null || (Object)(object)((Component)container).GetComponentInParent<Ship>() != (Object)null) { return true; } Transform root = ((Component)container).transform.root; if ((Object)(object)root == (Object)null) { return false; } if (!((Object)(object)((Component)root).GetComponentInChildren<Vagon>(true) != (Object)null)) { return (Object)(object)((Component)root).GetComponentInChildren<Ship>(true) != (Object)null; } return true; } } [HarmonyPatch(typeof(Container), "Awake")] internal static class ModdedContainerRegisterPatch { private static void Postfix(Container __instance) { ModdedContainerCompatibility.Register(__instance); } } [BepInPlugin("NotYourFriend.NotYourLoot", "NotYourLoot", "0.7.1")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class NotYourLootPlugin : BaseUnityPlugin { public const string PluginGUID = "NotYourFriend.NotYourLoot"; public const string PluginName = "NotYourLoot"; public const string PluginVersion = "0.7.1"; internal static NotYourLootPlugin Instance; private Harmony _harmony; internal static ConfigEntry<bool> AudioEpicMmoEnabled; internal static ConfigEntry<float> AudioEpicMmoVolume; internal static ConfigEntry<bool> AudioCaptainEnabled; internal static ConfigEntry<float> AudioCaptainVolume; internal static ConfigEntry<bool> AudioCaptainQuestEnabled; internal static ConfigEntry<float> AudioCaptainQuestVolume; internal static ConfigEntry<float> AudioCaptainLevelUpVolume; private void Awake() { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Expected O, but got Unknown Instance = this; BindAudioConfig(); HerbalistVegetationPatch.BindConfig(((BaseUnityPlugin)this).Config); EpicLootChestProvider.Initialize(((BaseUnityPlugin)this).Logger); _harmony = new Harmony("NotYourFriend.NotYourLoot"); _harmony.PatchAll(); ModdedContainerCompatibility.Install(_harmony); AudioPatches.Install(_harmony); HerbalistVegetationPatch.Install(_harmony); ((MonoBehaviour)this).StartCoroutine(AudioPatches.DelayedEpicMmoScan()); ((MonoBehaviour)this).StartCoroutine(AudioPatches.DelayedEpicMmoOrbEffectCleanup()); ((BaseUnityPlugin)this).Logger.LogInfo((object)"NotYourLoot 0.7.1 loaded successfully."); } private void BindAudioConfig() { //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: Expected O, but got Unknown //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Expected O, but got Unknown //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014f: Expected O, but got Unknown AudioEpicMmoEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio - EpicMMO", "Enabled", true, "Normalize audio embedded in EpicMMO GameObject assets."); AudioEpicMmoVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio - EpicMMO", "VolumeMultiplier", 0.5f, new ConfigDescription("Multiplier applied to EpicMMO AudioSource volume. 1.0 leaves the original volume unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); AudioCaptainEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio - CaptainSkillTree", "Enabled", true, "Normalize CaptainSkillTree VFX/SFX audio and supported dedicated sound managers."); AudioCaptainVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio - CaptainSkillTree", "VolumeMultiplier", 0.3f, new ConfigDescription("Multiplier applied to general CaptainSkillTree audio. 1.0 leaves the original volume unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); AudioCaptainQuestEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Audio - CaptainSkillTree Quest Complete", "Enabled", true, "Apply a separate multiplier to CaptainSkillTree quest-complete music."); AudioCaptainQuestVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio - CaptainSkillTree Quest Complete", "VolumeMultiplier", 0.15f, new ConfigDescription("Multiplier applied to quest-complete music before CaptainSkillTree plays it. 1.0 leaves the configured quest volume unchanged.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); AudioCaptainLevelUpVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Audio - CaptainSkillTree Level Up", "Volume", 0.65f, new ConfigDescription("Volume used for the LockChime.wav replacement when CaptainSkillTree levels up.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 2f), Array.Empty<object>())); } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } internal static void LogInfo(string message) { NotYourLootPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogInfo((object)message); } } internal static void LogWarning(string message) { NotYourLootPlugin instance = Instance; if (instance != null) { ((BaseUnityPlugin)instance).Logger.LogWarning((object)message); } } } internal static class TherzieEquipment { private enum TherzieSource { None, Warfare, Wizardry, Armory } private sealed class OwnedItemInfo { internal TherzieSource Source; internal string PrefabName; internal string ArmoryGroup; } private static readonly Dictionary<ItemDrop, OwnedItemInfo> OwnedItems = new Dictionary<ItemDrop, OwnedItemInfo>(); private static bool _cacheBuilt; private static readonly HashSet<ItemType> EquipmentTypes = new HashSet<ItemType> { (ItemType)3, (ItemType)4, (ItemType)5, (ItemType)6, (ItemType)7, (ItemType)11, (ItemType)12, (ItemType)14, (ItemType)17, (ItemType)18, (ItemType)19, (ItemType)22, (ItemType)24 }; private static readonly string[] ArmorySets = new string[10] { "Razorback", "Hunter", "Leather", "Rogue", "Vigorous", "Warrior", "Vidar", "Fenrir", "Bold", "Legion" }; private static readonly string[] ArmoryTiers = new string[5] { "Iron", "Silver", "BM", "Carapace", "Flametal" }; internal static bool IsTargetEquipment(Recipe recipe) { OwnedItemInfo info; return TryGetInfo(recipe, out info); } internal static bool IsUnlocked(Recipe recipe, HashSet<string> knownMaterials) { if (knownMaterials == null || !TryGetInfo(recipe, out var info)) { return false; } if (info.Source != TherzieSource.Armory || string.IsNullOrEmpty(info.ArmoryGroup)) { return knownMaterials.Contains(recipe.m_item.m_itemData.m_shared.m_name); } foreach (KeyValuePair<ItemDrop, OwnedItemInfo> ownedItem in OwnedItems) { ItemDrop key = ownedItem.Key; OwnedItemInfo value = ownedItem.Value; if (value.Source == TherzieSource.Armory && !(value.ArmoryGroup != info.ArmoryGroup) && !((Object)(object)key == (Object)null) && key.m_itemData != null && key.m_itemData.m_shared != null && knownMaterials.Contains(key.m_itemData.m_shared.m_name)) { return true; } } return false; } internal static string GetUnlockDescription(Recipe recipe) { if (!TryGetInfo(recipe, out var info)) { return "unknown"; } if (info.Source == TherzieSource.Armory && !string.IsNullOrEmpty(info.ArmoryGroup)) { return "Armory group " + info.ArmoryGroup; } return $"{info.Source} exact item"; } private static bool TryGetInfo(Recipe recipe, out OwnedItemInfo info) { //IL_006a: Unknown result type (might be due to invalid IL or missing references) info = null; if ((Object)(object)recipe == (Object)null || (Object)(object)recipe.m_item == (Object)null || recipe.m_item.m_itemData == null || recipe.m_item.m_itemData.m_shared == null) { return false; } EnsureCache(); if (!OwnedItems.TryGetValue(recipe.m_item, out info)) { return false; } return EquipmentTypes.Contains(recipe.m_item.m_itemData.m_shared.m_itemType); } private static void EnsureCache() { if (_cacheBuilt && OwnedItems.Count > 0) { return; } OwnedItems.Clear(); AddItemsFromAssembly("Warfare", TherzieSource.Warfare); AddItemsFromAssembly("Wizardry", TherzieSource.Wizardry); AddItemsFromAssembly("Armory", TherzieSource.Armory); if (OwnedItems.Count <= 0) { return; } if (!_cacheBuilt) { int num = OwnedItems.Values.Count((OwnedItemInfo x) => x.Source == TherzieSource.Warfare); int num2 = OwnedItems.Values.Count((OwnedItemInfo x) => x.Source == TherzieSource.Wizardry); int num3 = OwnedItems.Values.Count((OwnedItemInfo x) => x.Source == TherzieSource.Armory); int num4 = OwnedItems.Values.Count((OwnedItemInfo x) => x.Source == TherzieSource.Armory && !string.IsNullOrEmpty(x.ArmoryGroup)); NotYourLootPlugin.LogInfo("Therzie ownership cache built: " + $"{OwnedItems.Count} items " + $"(Warfare {num}, " + $"Wizardry {num2}, " + $"Armory {num3}, " + $"Armory grouped {num4})."); } _cacheBuilt = true; } private static void AddItemsFromAssembly(string assemblyName, TherzieSource source) { try { Assembly assembly = AppDomain.CurrentDomain.GetAssemblies().FirstOrDefault((Assembly a) => string.Equals(a.GetName().Name, assemblyName, StringComparison.OrdinalIgnoreCase)); if (assembly == null) { return; } Type type = assembly.GetType("ItemManager.Item"); if (type == null) { return; } FieldInfo field = type.GetField("itemDropMap", BindingFlags.Static | BindingFlags.NonPublic); if (field == null || !(field.GetValue(null) is IDictionary dictionary)) { return; } foreach (DictionaryEntry item in dictionary) { object key = item.Key; ItemDrop val = (ItemDrop)((key is ItemDrop) ? key : null); if (val != null) { string prefabName = (((Object)(object)((Component)val).gameObject != (Object)null) ? ((Object)((Component)val).gameObject).name : string.Empty); OwnedItems[val] = new OwnedItemInfo { Source = source, PrefabName = prefabName, ArmoryGroup = ((source == TherzieSource.Armory) ? GetArmoryGroup(prefabName) : null) }; } } } catch (Exception ex) { NotYourLootPlugin.LogWarning("Could not inspect " + assemblyName + ": " + ex.Message); } } private static string GetArmoryGroup(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return null; } string text = prefabName; if (text.EndsWith("_TW", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(0, text.Length - 3); } string[] armorySets = ArmorySets; foreach (string text2 in armorySets) { string text3 = "Helmet" + text2; string[] armoryTiers; if (text.StartsWith(text3, StringComparison.OrdinalIgnoreCase)) { string text4 = text.Substring(text3.Length); if (text4.Length == 0) { return text2; } armoryTiers = ArmoryTiers; foreach (string text5 in armoryTiers) { if (string.Equals(text4, text5, StringComparison.OrdinalIgnoreCase)) { return text2 + text5; } } return null; } string text6 = "Armor" + text2; if (!text.StartsWith(text6, StringComparison.OrdinalIgnoreCase)) { continue; } string a = text.Substring(text6.Length); if (string.Equals(a, "Chest", StringComparison.OrdinalIgnoreCase)) { return text2; } armoryTiers = ArmoryTiers; foreach (string text7 in armoryTiers) { if (string.Equals(a, "Chest" + text7, StringComparison.OrdinalIgnoreCase) || string.Equals(a, text7 + "Chest", StringComparison.OrdinalIgnoreCase)) { return text2 + text7; } } if (string.Equals(a, "Legs", StringComparison.OrdinalIgnoreCase)) { return text2; } armoryTiers = ArmoryTiers; foreach (string text8 in armoryTiers) { if (string.Equals(a, "Legs" + text8, StringComparison.OrdinalIgnoreCase) || string.Equals(a, text8 + "Legs", StringComparison.OrdinalIgnoreCase)) { return text2 + text8; } } } return null; } } [HarmonyPatch(typeof(Player), "AddKnownRecipe")] internal static class AddKnownRecipePatch { private static bool Prefix(Recipe recipe, HashSet<string> ___m_knownMaterial) { if (!TherzieEquipment.IsTargetEquipment(recipe)) { return true; } return TherzieEquipment.IsUnlocked(recipe, ___m_knownMaterial); } } [HarmonyPatch(typeof(Player), "UpdateKnownRecipesList")] internal static class UpdateKnownRecipesListPatch { private static readonly MethodInfo AddKnownRecipeMethod = AccessTools.Method(typeof(Player), "AddKnownRecipe", (Type[])null, (Type[])null); private static void Postfix(Player __instance, HashSet<string> ___m_knownMaterial, HashSet<string> ___m_knownRecipes) { if ((Object)(object)ObjectDB.instance == (Object)null || ObjectDB.instance.m_recipes == null || AddKnownRecipeMethod == null) { return; } foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (TherzieEquipment.IsTargetEquipment(recipe) && TherzieEquipment.IsUnlocked(recipe, ___m_knownMaterial)) { string name = recipe.m_item.m_itemData.m_shared.m_name; if (!___m_knownRecipes.Contains(name)) { AddKnownRecipeMethod.Invoke(__instance, new object[1] { recipe }); NotYourLootPlugin.LogInfo("Discovery unlocked recipe: " + name + " [" + TherzieEquipment.GetUnlockDescription(recipe) + "]"); } } } } } [HarmonyPatch(typeof(HotkeyBar), "UpdateIcons")] [HarmonyAfter(new string[] { "randyknapp.mods.equipmentandquickslots" })] internal static class EquipmentAndQuickSlotsQuickBarUIPatch { private const float MinimumLabelWidth = 100f; private static void Postfix(HotkeyBar __instance) { //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || ((Object)((Component)__instance).gameObject).name != "QuickSlotsHotkeyBar") { return; } TMP_Text[] componentsInChildren = ((Component)__instance).GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val in componentsInChildren) { if (!((Object)(object)val == (Object)null) && !(((Object)((Component)val).gameObject).name != "binding")) { val.textWrappingMode = (TextWrappingModes)0; val.overflowMode = (TextOverflowModes)0; RectTransform rectTransform = val.rectTransform; Rect rect = rectTransform.rect; if (((Rect)(ref rect)).width < 100f) { rectTransform.SetSizeWithCurrentAnchors((Axis)0, 100f); } } } } } internal static class WorkerBonusPatches { private enum WorkerBonusKind { None, Woodcutting, Gathering, Mining, Crafting } [HarmonyPatch] private static class ProductionContextPatch { private static IEnumerable<MethodBase> TargetMethods() { Type type = AccessTools.TypeByName("CaptainSkillTree.SkillTree.ProductionEffects"); if (type == null) { yield break; } string[] array = new string[4] { "TryDropExtraWood", "TryDropExtraResource", "TryDropExtraMiningResource", "CheckAndApplyCraftingBonus" }; string[] array2 = array; foreach (string name in array2) { MethodInfo methodInfo = AccessTools.GetDeclaredMethods(type).FirstOrDefault((MethodInfo m) => m.Name == name); if (methodInfo != null) { yield return methodInfo; } } } private static void Prefix(MethodBase __originalMethod, object[] __args) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: 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) //IL_00f4: 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_0118: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) _activeKind = WorkerBonusKind.None; _activePosition = Vector3.zero; _vanillaEffectPlayed = false; switch (__originalMethod.Name) { case "TryDropExtraWood": _activeKind = WorkerBonusKind.Woodcutting; if (__args.Length >= 3 && __args[2] is Vector3 activePosition) { _activePosition = activePosition; } break; case "TryDropExtraResource": if (__args.Length >= 3 && __args[2] is string a && string.Equals(a, "gathering", StringComparison.OrdinalIgnoreCase)) { _activeKind = WorkerBonusKind.Gathering; if (__args[1] is Vector3 activePosition3) { _activePosition = activePosition3; } } break; case "TryDropExtraMiningResource": _activeKind = WorkerBonusKind.Mining; if (__args.Length >= 2 && __args[1] is Vector3 activePosition2) { _activePosition = activePosition2; } break; case "CheckAndApplyCraftingBonus": _activeKind = WorkerBonusKind.Crafting; if ((Object)(object)Player.m_localPlayer != (Object)null) { _activePosition = ((Component)Player.m_localPlayer).transform.position; } break; } } private static Exception Finalizer(Exception __exception) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) _activeKind = WorkerBonusKind.None; _activePosition = Vector3.zero; _vanillaEffectPlayed = false; return __exception; } } [HarmonyPatch] private static class CaptainFloatingTextPatch { private static IEnumerable<MethodBase> TargetMethods() { Type type = AccessTools.TypeByName("CaptainSkillTree.SkillTree.SkillEffect"); if (type == null) { yield break; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (declaredMethod.Name == "DrawFloatingText") { yield return declaredMethod; } } } private static bool Prefix(object[] __args) { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) if (_activeKind != WorkerBonusKind.Woodcutting && _activeKind != WorkerBonusKind.Gathering && _activeKind != WorkerBonusKind.Mining) { return true; } string text = null; for (int i = 0; i < __args.Length; i++) { if (__args[i] is string text2) { text = text2; break; } } if (string.IsNullOrEmpty(text)) { return true; } Vector3 val = _activePosition + Vector3.up * 0.5f; _pendingDamageText = null; _pendingDamageTextColor = null; if (_activeKind == WorkerBonusKind.Gathering) { text = LocalizeGatheringBonus(text); text = (_pendingDamageText = text.Replace("⚒\ufe0f", "\ud83c\udf3f").Replace("⚒", "\ud83c\udf3f")); _pendingDamageTextColor = GatheringColor; } else if (_activeKind == WorkerBonusKind.Mining) { _pendingDamageText = text; _pendingDamageTextColor = MiningColor; } if ((Object)(object)DamageText.instance != (Object)null) { DamageText.instance.ShowText((TextType)7, val, text, true); } PlayVanillaBonusEffect(_activePosition); NotYourLootPlugin.LogInfo("Captain Worker bonus converted to vanilla-style popup: " + $"{_activeKind} / {text}"); return false; } } [HarmonyPatch(typeof(DamageText), "AddInworldText")] private static class DamageTextColorPatch { private static void Postfix(DamageText __instance, string text) { //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_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) if (!_pendingDamageTextColor.HasValue || string.IsNullOrEmpty(_pendingDamageText) || !string.Equals(text, _pendingDamageText, StringComparison.Ordinal)) { return; } try { if (!(AccessTools.Field(typeof(DamageText), "m_worldTexts")?.GetValue(__instance) is IList { Count: not 0 } list)) { return; } object obj = list[list.Count - 1]; if (obj != null) { object? obj2 = AccessTools.Field(obj.GetType(), "m_textField")?.GetValue(obj); TMP_Text val = (TMP_Text)((obj2 is TMP_Text) ? obj2 : null); if (!((Object)(object)val == (Object)null)) { Color value = _pendingDamageTextColor.Value; value.a = ((Graphic)val).color.a; ((Graphic)val).color = value; } } } finally { _pendingDamageText = null; _pendingDamageTextColor = null; } } } [HarmonyPatch] private static class CaptainLootSpawnSoundPatch { private static IEnumerable<MethodBase> TargetMethods() { Type type = AccessTools.TypeByName("CaptainSkillTree.VFX.VFXManager"); if (type == null) { yield break; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (declaredMethod.Name == "PlaySound") { yield return declaredMethod; } } } private static bool Prefix(object[] __args) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (_activeKind != WorkerBonusKind.Woodcutting && _activeKind != WorkerBonusKind.Gathering && _activeKind != WorkerBonusKind.Mining) { return true; } if (!string.Equals(GetFirstString(__args), "sfx_lootspawn", StringComparison.Ordinal)) { return true; } if (!_vanillaEffectPlayed) { PlayVanillaBonusEffect(_activePosition); } return false; } } [HarmonyPatch] private static class CaptainCraftingSoundPatch { private static IEnumerable<MethodBase> TargetMethods() { Type type = AccessTools.TypeByName("CaptainSkillTree.VFX.VFXManager"); if (type == null) { yield break; } foreach (MethodInfo declaredMethod in AccessTools.GetDeclaredMethods(type)) { if (declaredMethod.Name == "PlayVFXAtPosition") { yield return declaredMethod; } } } private static bool Prefix(object[] __args) { //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) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) if (_activeKind != WorkerBonusKind.Crafting) { return true; } if (!string.Equals(GetFirstString(__args), "sfx_fader_bell", StringComparison.Ordinal)) { return true; } Vector3 position = _activePosition; for (int i = 0; i < __args.Length; i++) { if (__args[i] is Vector3 val) { position = val; break; } } PlayVanillaBonusEffect(position); NotYourLootPlugin.LogInfo("Captain Crafting bonus sound replaced with vanilla Farming bonus effect."); return false; } } private static WorkerBonusKind _activeKind = WorkerBonusKind.None; private static Vector3 _activePosition; private static bool _vanillaEffectPlayed; private static EffectList _vanillaBonusEffect; private static bool _searchedForVanillaBonusEffect; private static readonly Color GatheringColor = new Color(0.4f, 0.8f, 0.2f, 1f); private static readonly Color MiningColor = new Color(0.2f, 0.8f, 0.9f, 1f); private static string _pendingDamageText; private static Color? _pendingDamageTextColor; private static readonly HashSet<string> LocalizedGatheringItems = new HashSet<string>(StringComparer.Ordinal) { "BH_AslaugsHerb", "BH_Bjorncap", "BH_Boswellia", "BH_Chamomile", "BH_Chicory", "BH_Daisy", "BH_Echinacea", "BH_HelshadeFungus", "BH_Lavender", "BH_LokisTrickcap", "BH_NordicFirebloom", "BH_SeidrBlossoms", "BH_SkaldsIvy", "BH_ThorsToadstool", "BH_Valhallaberry", "BH_ValkyrieFern", "BH_VikingsBreadcap", "BFP_Clay", "BFP_Straw" }; private static string LocalizeGatheringBonus(string text) { if (string.IsNullOrEmpty(text) || LocalizationManager.Instance == null) { return text; } return Regex.Replace(text, "\\b(BH|BFP)_([A-Za-z]+)\\b", delegate(Match match) { string text2 = "$" + match.Groups[1].Value.ToLowerInvariant() + "_" + match.Groups[2].Value.ToLowerInvariant(); if (!LocalizedGatheringItems.Contains(match.Value)) { return match.Value; } string text3 = LocalizationManager.Instance.TryTranslate(text2); return (!string.IsNullOrEmpty(text3) && !(text3 == text2) && !text3.StartsWith("[")) ? text3 : match.Value; }); } private static void PlayVanillaBonusEffect(Vector3 position) { //IL_002c: 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) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_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 (_vanillaEffectPlayed) { return; } _vanillaEffectPlayed = true; EffectList vanillaBonusEffect = GetVanillaBonusEffect(); if (vanillaBonusEffect == null || !vanillaBonusEffect.HasEffects()) { NotYourLootPlugin.LogWarning("Could not locate a vanilla Pickable bonus effect."); return; } ZDOID val = default(ZDOID); if ((Object)(object)Player.m_localPlayer != (Object)null) { val = ((Character)Player.m_localPlayer).GetZDOID(); } vanillaBonusEffect.Create(position, Quaternion.identity, (Transform)null, 1f, -1, val); } private static EffectList GetVanillaBonusEffect() { if (_vanillaBonusEffect != null) { return _vanillaBonusEffect; } if (_searchedForVanillaBonusEffect) { return null; } _searchedForVanillaBonusEffect = true; try { Pickable[] source = Resources.FindObjectsOfTypeAll<Pickable>(); Pickable val = ((IEnumerable<Pickable>)source).FirstOrDefault((Func<Pickable, bool>)((Pickable p) => (Object)(object)p != (Object)null && p.m_bonusEffect != null && p.m_bonusEffect.HasEffects() && (Object)(object)((Component)p).gameObject != (Object)null && ((Object)((Component)p).gameObject).name.IndexOf("rasp", StringComparison.OrdinalIgnoreCase) >= 0)); if ((Object)(object)val == (Object)null) { val = ((IEnumerable<Pickable>)source).FirstOrDefault((Func<Pickable, bool>)((Pickable p) => (Object)(object)p != (Object)null && p.m_bonusEffect != null && p.m_bonusEffect.HasEffects() && (int)p.m_pickRaiseSkill > 0)); } if ((Object)(object)val != (Object)null) { _vanillaBonusEffect = val.m_bonusEffect; NotYourLootPlugin.LogInfo("Vanilla Farming bonus effect sourced from Pickable '" + ((Object)((Component)val).gameObject).name + "'."); return _vanillaBonusEffect; } NotYourLootPlugin.LogWarning("No loaded Pickable with a vanilla bonus effect was found."); } catch (Exception ex) { NotYourLootPlugin.LogWarning("Failed locating vanilla Farming bonus effect: " + ex.Message); } return null; } private static string GetFirstString(object[] args) { if (args == null) { return null; } for (int i = 0; i < args.Length; i++) { if (args[i] is string result) { return result; } } return null; } }