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 Combat and Loot v1.0.5
DigiCombat.dll
Decompiled an hour ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using ArrowEffects; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using BossStarsAfterDefeat; using BreedingStatus; using CharmScaling; using DigiCore; using FloatingLoot; using GrappleAim; using HarmonyLib; using HitEffects; using InstantLoot; using Jotunn.Utils; using KeepLoaded; using LegendsToggle; using Microsoft.CodeAnalysis; using PassivePowers; using UnityEngine; using UnityEngine.UI; using ValheimLegends; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")] [assembly: AssemblyCompany("DigiCombat")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("DigiCombat")] [assembly: AssemblyTitle("DigiCombat")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } internal static class SettingOrder { internal sealed class ConfigurationManagerAttributes { public int? Order; } internal static void Apply(ConfigFile config) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Expected O, but got Unknown FieldInfo fieldInfo = AccessTools.Field(typeof(ConfigEntryBase), "<Description>k__BackingField"); if (fieldInfo == null) { return; } int num = 1000; foreach (ConfigDefinition item in config.Keys.ToList()) { ConfigEntryBase val = config[item]; ConfigDescription description = val.Description; object[] array = ((description != null) ? description.Tags : null) ?? new object[0]; object obj = array.FirstOrDefault((object t) => t != null && t.GetType().Name == "ConfigurationManagerAttributes"); if (obj != null) { FieldInfo fieldInfo2 = AccessTools.Field(obj.GetType(), "Order"); if (fieldInfo2 != null && fieldInfo2.GetValue(obj) == null) { fieldInfo2.SetValue(obj, num); } } else { fieldInfo.SetValue(val, (object?)new ConfigDescription(((description != null) ? description.Description : null) ?? "", (description != null) ? description.AcceptableValues : null, array.Concat(new object[1] { new ConfigurationManagerAttributes { Order = num } }).ToArray())); } num--; } } } namespace DigiCore { public static class ChestFlags { public const string NoStore = "digi_nostore"; public static bool StoreBlocked(Container chest) { if ((Object)(object)chest == (Object)null) { return false; } ZNetView component = ((Component)chest).GetComponent<ZNetView>(); if ((Object)(object)component != (Object)null && component.IsValid()) { return component.GetZDO().GetBool("digi_nostore", false); } return false; } } public sealed class ModuleInfo { public readonly Type Type; public readonly string Title; public readonly string OldGuid; public readonly string Description; public readonly string[] Requires; public readonly bool DefaultOn; public ModuleInfo(Type type, string title, string oldGuid, string description, string[] requires = null, bool defaultOn = true) { Type = type; Title = title; OldGuid = oldGuid; Description = description; Requires = requires ?? new string[0]; DefaultOn = defaultOn; } } public abstract class DigiPlugin : BaseUnityPlugin { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static Func<string, string> <>9__11_0; public static Func<string, bool> <>9__11_1; public static Func<string, bool> <>9__11_2; public static Func<string, string> <>9__11_3; public static Func<string, string[]> <>9__19_0; public static Func<string[], string> <>9__19_1; public static Func<string[], string> <>9__19_4; public static Func<IGrouping<string, string[]>, string> <>9__19_2; public static PopupButtonCallback <>9__19_3; public static Func<string, bool> <>9__23_0; internal string <Awake>b__11_0(string l) { return l.Trim(); } internal bool <Awake>b__11_1(string l) { return l.Length > 0; } internal bool <Awake>b__11_2(string r) { return !Chainloader.PluginInfos.ContainsKey(r); } internal string <Awake>b__11_3(string r) { if (!RequirementNames.TryGetValue(r, out var value)) { return r; } return value; } internal string[] <ShowDuplicates>b__19_0(string d) { return d.Split(new char[1] { '|' }); } internal string <ShowDuplicates>b__19_1(string[] d) { return d[0]; } internal string <ShowDuplicates>b__19_2(IGrouping<string, string[]> g) { return "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1])); } internal string <ShowDuplicates>b__19_4(string[] d) { return d[1]; } internal void <ShowDuplicates>b__19_3() { UnifiedPopup.Pop(); } internal bool <Apply>b__23_0(string r) { return !Chainloader.PluginInfos.ContainsKey(r); } } public const string ModulesSection = "0 - Sub-mods"; internal static DigiPlugin StartingHost; internal static ModuleInfo StartingModule; private static readonly Dictionary<string, string> RequirementNames = new Dictionary<string, string> { { "randyknapp.mods.epicloot", "Epic Loot" }, { "com.jotunn.jotunn", "Jotunn" }, { "ValheimLegends", "Valheim Legends" }, { "vapok.mods.adventurebackpacks", "Adventure Backpacks" }, { "MidnightsFX.StarLevelSystem", "Star Level System" }, { "sosal.nordicrugs", "Nordic Rugs" }, { "LuminairPrime.valheim.localcraftfromstorageprime", "Local Craft From Storage Prime" } }; private readonly Dictionary<ModuleInfo, DigiModule> _running = new Dictionary<ModuleInfo, DigiModule>(); private readonly Dictionary<ModuleInfo, ConfigEntry<bool>> _switches = new Dictionary<ModuleInfo, ConfigEntry<bool>>(); private HashSet<string> _migrated; private const string DuplicatesKey = "digi.valheim.duplicates"; private const string DuplicatesShownKey = "digi.valheim.duplicates.shown"; protected abstract ModuleInfo[] Modules { get; } private string MigratedFile => Path.Combine(Paths.ConfigPath, ((BaseUnityPlugin)this).Info.Metadata.GUID + ".migrated.txt"); private static List<string> Duplicates { get { List<string> list = AppDomain.CurrentDomain.GetData("digi.valheim.duplicates") as List<string>; if (list == null) { list = new List<string>(); AppDomain.CurrentDomain.SetData("digi.valheim.duplicates", list); } return list; } } protected virtual void Awake() { ((BaseUnityPlugin)this).Config.SaveOnConfigSet = true; ((BaseUnityPlugin)this).Config.Save(); _migrated = (File.Exists(MigratedFile) ? new HashSet<string>(from l in File.ReadAllLines(MigratedFile) select l.Trim() into l where l.Length > 0 select l) : new HashSet<string>()); bool flag = !_migrated.Contains("#switches"); ModuleInfo[] modules = Modules; foreach (ModuleInfo moduleInfo in modules) { List<string> list = moduleInfo.Requires.Where((string r) => !Chainloader.PluginInfos.ContainsKey(r)).ToList(); string value; string text = ((moduleInfo.Requires.Length == 0) ? "" : (" Needs " + string.Join(" and ", moduleInfo.Requires.Select((string r) => (!RequirementNames.TryGetValue(r, out value)) ? r : value)) + ".")); ConfigEntry<bool> val = ((BaseUnityPlugin)this).Config.Bind<bool>("0 - Sub-mods", moduleInfo.Title, moduleInfo.DefaultOn, moduleInfo.Description + text); if (flag && !moduleInfo.DefaultOn && File.Exists(OldConfigPath(moduleInfo))) { val.Value = true; } _switches[moduleInfo] = val; ModuleInfo captured = moduleInfo; val.SettingChanged += delegate { Apply(captured); }; if (list.Count > 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(moduleInfo.Title + ": off, needs " + string.Join(", ", list) + ".")); } } if (flag) { Remember("#switches"); } modules = Modules; foreach (ModuleInfo module in modules) { Apply(module); } } private void Start() { foreach (KeyValuePair<ModuleInfo, DigiModule> item in _running.ToList()) { if (!((Object)(object)item.Value == (Object)null) && Chainloader.PluginInfos.ContainsKey(item.Key.OldGuid)) { item.Value.Teardown(); _running.Remove(item.Key); Forget(item.Key.OldGuid); ReportDuplicate(item.Key); } } SettingOrder.Apply(((BaseUnityPlugin)this).Config); if (!Application.isBatchMode) { ((MonoBehaviour)this).StartCoroutine(ShowDuplicates()); } } private void ReportDuplicate(ModuleInfo module) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": not started, because the separate mod (" + module.OldGuid + ") is installed too. Remove that one.")); string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + module.Title; if (!Duplicates.Contains(item)) { Duplicates.Add(item); } } internal void ReportReplaced(string what) { string item = ((BaseUnityPlugin)this).Info.Metadata.Name.Replace("Digi's ", "") + "|" + what; if (!Duplicates.Contains(item)) { Duplicates.Add(item); } } private IEnumerator ShowDuplicates() { while ((Object)(object)FejdStartup.instance == (Object)null || !UnifiedPopup.IsAvailable()) { yield return (object)new WaitForSeconds(0.5f); } yield return (object)new WaitForSeconds(1f); if (Duplicates.Count == 0 || AppDomain.CurrentDomain.GetData("digi.valheim.duplicates.shown") != null) { yield break; } AppDomain.CurrentDomain.SetData("digi.valheim.duplicates.shown", true); IEnumerable<string> values = from d in Duplicates select d.Split(new char[1] { '|' }) into d group d by d[0] into g select "<b>" + g.Key + ":</b> " + string.Join(", ", g.Select((string[] d) => d[1])); string text = "These mods are installed twice: on their own and inside one of our combined mods.\n\n" + string.Join("\n", values) + "\n\nThe copy in the combined mod stays off until you remove the separate ones in your mod manager (or make a new profile with Digi Modpack). Your settings are copied over."; object obj = <>c.<>9__19_3; if (obj == null) { PopupButtonCallback val = delegate { UnifiedPopup.Pop(); }; <>c.<>9__19_3 = val; obj = (object)val; } UnifiedPopup.Push((PopupBase)new WarningPopup("Mods installed twice", text, (PopupButtonCallback)obj, false)); } private static string OldConfigPath(ModuleInfo module) { return Path.Combine(Paths.ConfigPath, module.OldGuid + ".cfg"); } private void Remember(string key) { if (!_migrated.Add(key)) { return; } try { File.AppendAllText(MigratedFile, key + Environment.NewLine); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message)); } } private void Forget(string key) { if (!_migrated.Remove(key)) { return; } try { File.WriteAllLines(MigratedFile, _migrated.ToArray()); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Could not write " + MigratedFile + ": " + ex.Message)); } } private void Apply(ModuleInfo module) { bool value = _switches[module].Value; _running.TryGetValue(module, out var value2); if (value && (Object)(object)value2 == (Object)null) { if (!module.Requires.Any((string r) => !Chainloader.PluginInfos.ContainsKey(r))) { if (Chainloader.PluginInfos.ContainsKey(module.OldGuid)) { ReportDuplicate(module); } else { StartModule(module); } } } else if (!value && (Object)(object)value2 != (Object)null) { value2.Teardown(); _running.Remove(module); ((BaseUnityPlugin)this).Logger.LogInfo((object)(module.Title + ": switched off.")); } } private void StartModule(ModuleInfo module) { StartingHost = this; StartingModule = module; try { DigiModule digiModule = (DigiModule)(object)((Component)this).gameObject.AddComponent(module.Type); digiModule.Host = this; digiModule.Info2 = module; _running[module] = digiModule; MigrateOldSettings(module, digiModule); } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"{module.Title} could not start: {arg}"); } finally { StartingHost = null; StartingModule = null; } SettingOrder.Apply(((BaseUnityPlugin)this).Config); } private void MigrateOldSettings(ModuleInfo module, DigiModule component) { if (_migrated.Contains(module.OldGuid)) { return; } string path = OldConfigPath(module); if (File.Exists(path) && component.ConfigOrNull != null) { Dictionary<string, string> dictionary = ReadCfg(path); int num = 0; foreach (ModuleConfig.Bound entry in component.ConfigOrNull.Entries) { if (dictionary.TryGetValue(entry.Section + "\n" + entry.Key, out var value)) { try { entry.Entry.SetSerializedValue(value); num++; } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)(module.Title + ": could not copy '" + entry.Key + "': " + ex.Message)); } } } ((BaseUnityPlugin)this).Logger.LogInfo((object)$"{module.Title}: copied {num} setting(s) from {Path.GetFileName(path)}."); } Remember(module.OldGuid); } private static Dictionary<string, string> ReadCfg(string path) { Dictionary<string, string> dictionary = new Dictionary<string, string>(); string text = ""; string[] array = File.ReadAllLines(path); for (int i = 0; i < array.Length; i++) { string text2 = array[i].Trim(); if (text2.Length == 0 || text2.StartsWith("#")) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { text = text2.Substring(1, text2.Length - 2); continue; } int num = text2.IndexOf(" = ", StringComparison.Ordinal); if (num > 0) { dictionary[text + "\n" + text2.Substring(0, num).Trim()] = text2.Substring(num + 3); } } return dictionary; } protected virtual void OnDestroy() { foreach (DigiModule item in _running.Values.ToList()) { item?.Teardown(); } _running.Clear(); } public bool IsRunning(Type moduleType) { return _running.Any((KeyValuePair<ModuleInfo, DigiModule> p) => p.Key.Type == moduleType && (Object)(object)p.Value != (Object)null); } } public abstract class DigiModule : MonoBehaviour { internal DigiPlugin Host; internal ModuleInfo Info2; private ModuleConfig _config; private ManualLogSource _logger; private Harmony _harmony; internal ModuleConfig ConfigOrNull => _config; protected ModuleConfig Config => _config ?? (_config = new ModuleConfig(((BaseUnityPlugin)(Host ?? DigiPlugin.StartingHost)).Config, (Info2 ?? DigiPlugin.StartingModule).Title)); protected ManualLogSource Logger => _logger ?? (_logger = Logger.CreateLogSource("Digi's " + (Info2 ?? DigiPlugin.StartingModule)?.Title)); protected Harmony ModuleHarmony { get { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Expected O, but got Unknown //IL_004a: Expected O, but got Unknown Harmony obj = _harmony; if (obj == null) { Harmony val = new Harmony(((object)this).GetType().Namespace?.ToLowerInvariant() + "." + Guid.NewGuid().ToString("N")); Harmony val2 = val; _harmony = val; obj = val2; } return obj; } } protected void ReportReplacedMod(string what) { (Host ?? DigiPlugin.StartingHost)?.ReportReplaced(what); } protected Harmony PatchModule(Type type) { ModuleHarmony.PatchAll(type); return ModuleHarmony; } protected Harmony PatchModuleNamespace() { string text = ((object)this).GetType().Namespace; Type[] typesFromAssembly = AccessTools.GetTypesFromAssembly(((object)this).GetType().Assembly); foreach (Type type in typesFromAssembly) { if (type.Namespace == text || (type.Namespace != null && text != null && type.Namespace.StartsWith(text + "."))) { ModuleHarmony.CreateClassProcessor(type).Patch(); } } return ModuleHarmony; } internal void Teardown() { try { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } catch (Exception ex) { Logger.LogWarning((object)("Unpatch: " + ex.Message)); } Object.Destroy((Object)(object)this); } } public sealed class ModuleConfig { public sealed class Bound { public string Section; public string Key; public ConfigEntryBase Entry; } private readonly ConfigFile _file; private readonly string _prefix; internal readonly List<Bound> Entries = new List<Bound>(); public ConfigFile File => _file; public string ConfigFilePath => _file.ConfigFilePath; internal ModuleConfig(ConfigFile file, string title) { _file = file; _prefix = title + " - "; } public void Reload() { } public void Save() { _file.Save(); } public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, ConfigDescription configDescription = null) { ConfigEntry<T> val = _file.Bind<T>(_prefix + section, key, defaultValue, configDescription); if (!Entries.Any((Bound b) => b.Section == section && b.Key == key)) { Entries.Add(new Bound { Section = section, Key = key, Entry = (ConfigEntryBase)(object)val }); } return val; } public ConfigEntry<T> Bind<T>(string section, string key, T defaultValue, string description) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Expected O, but got Unknown return Bind(section, key, defaultValue, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } public ConfigEntry<T> Bind<T>(ConfigDefinition definition, T defaultValue, ConfigDescription configDescription = null) { return Bind(definition.Section, definition.Key, defaultValue, configDescription); } public bool TryGetEntry<T>(ConfigDefinition definition, out ConfigEntry<T> entry) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown return _file.TryGetEntry<T>(new ConfigDefinition(_prefix + definition.Section, definition.Key), ref entry); } } } namespace DigiCombat { [BepInPlugin("digi.valheim.combat", "Digi's Combat and Loot", "1.0.5")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [NetworkCompatibility(/*Could not decode attribute arguments.*/)] public class Plugin : DigiPlugin { public const string Guid = "digi.valheim.combat"; public const string Name = "Digi's Combat and Loot"; public const string Version = "1.0.5"; protected override ModuleInfo[] Modules { get; } = new ModuleInfo[11] { new ModuleInfo(typeof(InstantLoot.Plugin), "Instant Loot", "digi.valheim.instantloot", "Monsters drop their loot the moment they die, shown in a stacked pickup list."), new ModuleInfo(typeof(BossStarsAfterDefeat.Plugin), "Boss Stars After Defeat", "digi.valheim.bossstarsafterdefeat", "Every boss you beat allows more stars on creatures, with more trophies from starred ones.", new string[1] { "MidnightsFX.StarLevelSystem" }), new ModuleInfo(typeof(KeepLoaded.Plugin), "Keep Loaded", "digi.valheim.keeploaded", "Crossbows and the grappling hook stay loaded when you switch weapons."), new ModuleInfo(typeof(GrappleAim.Plugin), "Grapple Aim", "digi.valheim.grappleaim", "The crosshair turns red when the grappling hook would not catch where you aim."), new ModuleInfo(typeof(ArrowEffects.Plugin), "Arrow Effects", "digi.valheim.arroweffects", "Tone down the effects of fire, poison and frost arrows."), new ModuleInfo(typeof(FloatingLoot.Plugin), "Floating Loot", "digi.valheim.floatingloot", "Dropped items float on water instead of sinking."), new ModuleInfo(typeof(BreedingStatus.Plugin), "Breeding Status", "digi.valheim.breedingstatus", "Hover a tame animal to see why it is or isn't breeding."), new ModuleInfo(typeof(LegendsToggle.Plugin), "Legends Toggle", "digi.valheim.legendstoggle", "The host turns Valheim Legends on or off for everyone, live.", new string[1] { "com.jotunn.jotunn" }), new ModuleInfo(typeof(CharmScaling.Plugin), "Charm Scaling", "digi.valheim.charmscaling", "The Enchanter's Charm lasts longer as your Alteration skill grows.", new string[1] { "ValheimLegends" }), new ModuleInfo(typeof(HitEffects.Plugin), "Hit Effects", "wheeze.valheim.dimmercombatparticleeffects", "Fades the effects that cover creatures in combat (burning, frost, poison, hit bursts), so you see their attacks coming."), new ModuleInfo(typeof(PassivePowers.Plugin), "Passive Forsaken Powers", "digitalroot.mods.passiveforsakenpowers.jvl", "Forsaken powers are always on: the one you chose at a boss stone, or every power you unlocked.") }; } } namespace PassivePowers { public class Plugin : DigiModule { public enum PowerChoice { Selected, AllUnlocked } public enum UnlockSource { ActivatedStones, DefeatedBosses, PickedUpTrophies } private const string PowerPrefix = "GP_"; private const float CheckInterval = 5f; private static readonly Dictionary<string, string[]> Bosses = new Dictionary<string, string[]> { { "GP_Eikthyr", new string[2] { "TrophyEikthyr", "defeated_eikthyr" } }, { "GP_TheElder", new string[2] { "TrophyTheElder", "defeated_gdking" } }, { "GP_Bonemass", new string[2] { "TrophyBonemass", "defeated_bonemass" } }, { "GP_Moder", new string[2] { "TrophyDragonQueen", "defeated_dragon" } }, { "GP_Yagluth", new string[2] { "TrophyGoblinKing", "defeated_goblinking" } }, { "GP_Queen", new string[2] { "TrophySeekerQueen", "defeated_queen" } }, { "GP_Fader", new string[2] { "TrophyFader", "defeated_fader" } } }; private static ConfigEntry<PowerChoice> _powers; private static ConfigEntry<UnlockSource> _unlockedBy; private static ConfigEntry<bool> _showOnHud; private static bool _running; private static ObjectDB _powersOf; private static readonly List<StatusEffect> AllPowers = new List<StatusEffect>(); private static readonly HashSet<int> Wanted = new HashSet<int>(); private static readonly List<int> ToRemove = new List<int>(); private float _timer; private void Awake() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Expected O, but got Unknown //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown ConfigurationManagerAttributes val = new ConfigurationManagerAttributes { IsAdminOnly = true }; _powers = base.Config.Bind("General", "Powers", PowerChoice.Selected, new ConfigDescription("Selected: the power you chose at a boss stone is always on. AllUnlocked: every power you have unlocked is always on (see Unlocked by). Set by the host, the same for everyone.", (AcceptableValueBase)null, new object[1] { val })); _unlockedBy = base.Config.Bind("General", "Unlocked by", UnlockSource.ActivatedStones, new ConfigDescription("With AllUnlocked, which powers count. ActivatedStones: the boss stones this character has used. DefeatedBosses: the bosses defeated in this world. PickedUpTrophies: the boss trophies this character has picked up. Set by the host, the same for everyone.", (AcceptableValueBase)null, new object[1] { val })); _showOnHud = base.Config.Bind("General", "Show power on HUD", defaultValue: true, "With Selected: keep showing the chosen power in its HUD slot, always ready. Off = the slot stays empty, as with AllUnlocked."); _powers.SettingChanged += OnSettingChanged; _unlockedBy.SettingChanged += OnSettingChanged; _running = true; PatchModule(typeof(Plugin)); Refresh(); } private void Update() { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { _timer -= Time.deltaTime; if (!(_timer > 0f)) { _timer = 5f; Refresh(); } } } private static void OnSettingChanged(object sender, EventArgs e) { Refresh(); } private void OnDestroy() { _running = false; _powers.SettingChanged -= OnSettingChanged; _unlockedBy.SettingChanged -= OnSettingChanged; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { return; } ToRemove.Clear(); foreach (StatusEffect statusEffect in ((Character)localPlayer).GetSEMan().GetStatusEffects()) { if (IsEndlessPower(statusEffect)) { ToRemove.Add(statusEffect.NameHash()); } } foreach (int item in ToRemove) { ((Character)localPlayer).GetSEMan().RemoveStatusEffect(item, true); } } private static void Refresh() { Player localPlayer = Player.m_localPlayer; if (!_running || (Object)(object)localPlayer == (Object)null || (Object)(object)ObjectDB.instance == (Object)null) { return; } CollectWanted(localPlayer); SEMan sEMan = ((Character)localPlayer).GetSEMan(); ToRemove.Clear(); foreach (StatusEffect statusEffect in sEMan.GetStatusEffects()) { if (IsEndlessPower(statusEffect) && !Wanted.Contains(statusEffect.NameHash())) { ToRemove.Add(statusEffect.NameHash()); } } foreach (int item in ToRemove) { sEMan.RemoveStatusEffect(item, true); } foreach (int item2 in Wanted) { StatusEffect val = sEMan.GetStatusEffect(item2) ?? sEMan.AddStatusEffect(item2, false, 0, 0f, (short)(-1)); if ((Object)(object)val != (Object)null) { val.m_ttl = 0f; } } } private static bool IsEndlessPower(StatusEffect se) { if ((Object)(object)se != (Object)null && se.m_ttl <= 0f) { return ((Object)se).name.StartsWith("GP_", StringComparison.Ordinal); } return false; } private static void CollectWanted(Player player) { Wanted.Clear(); string guardianPowerName = player.GetGuardianPowerName(); if (!string.IsNullOrEmpty(guardianPowerName)) { Wanted.Add(StringExtensionMethods.GetStableHashCode(guardianPowerName)); } if (_powers.Value != PowerChoice.AllUnlocked) { return; } UpdatePowerList(); List<string> trophies = null; foreach (StatusEffect allPower in AllPowers) { if (IsUnlocked(player, ((Object)allPower).name, ref trophies)) { Wanted.Add(allPower.NameHash()); } } } private static void UpdatePowerList() { if ((Object)(object)_powersOf == (Object)(object)ObjectDB.instance) { return; } _powersOf = ObjectDB.instance; AllPowers.Clear(); foreach (StatusEffect statusEffect in _powersOf.m_StatusEffects) { if ((Object)(object)statusEffect != (Object)null && ((Object)statusEffect).name.StartsWith("GP_", StringComparison.Ordinal)) { AllPowers.Add(statusEffect); } } } private static bool IsUnlocked(Player player, string power, ref List<string> trophies) { switch (_unlockedBy.Value) { case UnlockSource.DefeatedBosses: { if (Bosses.TryGetValue(power, out var value2) && (Object)(object)ZoneSystem.instance != (Object)null) { return ZoneSystem.instance.GetGlobalKey(value2[1]); } return false; } case UnlockSource.PickedUpTrophies: { if (!Bosses.TryGetValue(power, out var value)) { return false; } if (trophies == null) { trophies = player.GetTrophies(); } return trophies.Contains(value[0]); } default: return ((Humanoid)player).HaveUniqueKey(power); } } [HarmonyPatch(typeof(ItemStand), "DelayedPowerActivation")] [HarmonyPostfix] private static void PowerChosen() { Refresh(); } [HarmonyPatch(typeof(Player), "OnSpawned")] [HarmonyPostfix] private static void Spawned(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Refresh(); } } [HarmonyPatch(typeof(Player), "StartGuardianPower")] [HarmonyPrefix] private static bool StartPower(Player __instance, ref bool __result) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ((Character)__instance).Message((MessageType)1, "Your forsaken power is always on.", 0, (Sprite)null, false); } __result = false; return false; } [HarmonyPatch(typeof(Player), "ActivateGuardianPower")] [HarmonyPrefix] private static bool ActivatePower(ref bool __result) { __result = false; return false; } [HarmonyPatch(typeof(Player), "GetGuardianPowerHUD")] [HarmonyPostfix] private static void PowerHud(ref StatusEffect se, ref float cooldown) { if (_powers.Value == PowerChoice.Selected && _showOnHud.Value) { cooldown = 0f; } else { se = null; } } } } namespace LegendsToggle { [SynchronizationMode(/*Could not decode attribute arguments.*/)] public class Plugin : DigiModule { private static class KeepSkills { private sealed class KeptSkill { public int Type; public float Level; public float Acc; } private sealed class Kept { public readonly List<KeptSkill> Skills = new List<KeptSkill>(); } private static readonly ConditionalWeakTable<Skills, Kept> KeptSkills = new ConditionalWeakTable<Skills, Kept>(); private static readonly Func<SkillType, bool> IsSkillValid = AccessTools.MethodDelegate<Func<SkillType, bool>>(AccessTools.Method(typeof(Skills), "IsSkillValid", (Type[])null, (Type[])null), (object)null, true); [HarmonyPatch(typeof(Skills), "Load")] [HarmonyPrefix] private static void Load(Skills __instance, ZPackage pkg) { Kept orCreateValue = KeptSkills.GetOrCreateValue(__instance); orCreateValue.Skills.Clear(); int pos = pkg.GetPos(); try { int num = pkg.ReadInt(); int num2 = pkg.ReadInt(); for (int i = 0; i < num2; i++) { int num3 = pkg.ReadInt(); float level = pkg.ReadSingle(); float acc = ((num >= 2) ? pkg.ReadSingle() : 0f); if (!IsSkillValid((SkillType)num3)) { orCreateValue.Skills.Add(new KeptSkill { Type = num3, Level = level, Acc = acc }); } } } finally { pkg.SetPos(pos); } } [HarmonyPatch(typeof(Skills), "Save")] [HarmonyPrefix] private static bool Save(Skills __instance, ZPackage pkg, Dictionary<SkillType, Skill> ___m_skillData) { //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected I4, but got Unknown if (!KeptSkills.TryGetValue(__instance, out var value) || value.Skills.Count == 0) { return true; } List<KeptSkill> list = value.Skills.FindAll((KeptSkill s) => !___m_skillData.ContainsKey((SkillType)s.Type)); pkg.Write(2); pkg.Write(___m_skillData.Count + list.Count); foreach (Skill value2 in ___m_skillData.Values) { pkg.Write((int)value2.m_info.m_skill); pkg.Write(value2.m_level); pkg.Write(value2.m_accumulator); } foreach (KeptSkill item in list) { pkg.Write(item.Type); pkg.Write(item.Level); pkg.Write(item.Acc); } return false; } } public const string Guid = "digi.valheim.legendstoggle"; public const string Name = "Digi's Legends Toggle"; public const string Version = "2.0.3"; private const string LegendsGuid = "ValheimLegends"; private const string LegendsHarmonyId = "valheim.torann.valheimlegends"; private static readonly HashSet<string> AlwaysOn = new HashSet<string> { "ZNet.Awake", "ZNet.RPC_PeerInfo", "ZNet.OnDestroy", "ZNetScene.Awake", "ObjectDB.Awake", "ObjectDB.CopyOtherDB", "ObjectDB.GetStatusEffect", "Hud.Awake", "PlayerProfile.SavePlayerToDisk", "PlayerProfile.LoadPlayerFromDisk", "PlayerProfile.LoadPlayerData", "Skills.IsSkillValid", "Skills.GetSkillDef", "Skills.CheatRaiseSkill", "Player.RaiseSkill", "Player.OnSpawned", "Player.OnRespawn", "Menu.OnQuit", "Menu.OnLogout", "Terminal.TryRunCommand" }; private static ConfigEntry<bool> _enabled; private static Assembly _legends; private static ManualLogSource _log; private float _sweepTimer; private void MigrateConfig() { string text = Path.Combine(Paths.ConfigPath, "digi.valheim.legendstoggle".Replace("digi.valheim.", "pieter.valheim.") + ".cfg"); if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text)) { File.Copy(text, base.Config.ConfigFilePath); base.Config.Reload(); } } private void Awake() { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown MigrateConfig(); _log = base.Logger; _enabled = base.Config.Bind("Valheim Legends", "Enabled", defaultValue: true, new ConfigDescription("Valheim Legends on or off for everyone, right away (no restart). Only the host can change it. Your class and Legends skills are kept while it is off.", (AcceptableValueBase)null, new object[1] { (object)new ConfigurationManagerAttributes { IsAdminOnly = true } })); _enabled.SettingChanged += delegate { OnSwitched(); }; Harmony moduleHarmony = base.ModuleHarmony; moduleHarmony.PatchAll(typeof(KeepSkills)); if (Chainloader.PluginInfos.TryGetValue("ValheimLegends", out var value) && (Object)(object)value.Instance != (Object)null) { _legends = ((object)value.Instance).GetType().Assembly; GateLegends(moduleHarmony); GuardDamageHook(moduleHarmony); } else { base.Logger.LogWarning((object)"Valheim Legends is not installed; the switch does nothing."); } } private void GuardDamageHook(Harmony harmony) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown Type type = _legends.GetType("ValheimLegends.ValheimLegends+VL_Damage_Patch"); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null); if (!(methodInfo == null) && !(methodInfo.ReturnType != typeof(bool))) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(Plugin), "DamageHookFailed", (Type[])null), (HarmonyMethod)null); } } private static Exception DamageHookFailed(Exception __exception, ref bool __result, ref HitData hit) { if (!(__exception is NullReferenceException) || hit == null || (Object)(object)hit.GetAttacker() != (Object)null) { return __exception; } __result = true; return null; } private void GateLegends(Harmony harmony) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Expected O, but got Unknown HarmonyMethod val = new HarmonyMethod(AccessTools.Method(typeof(Plugin), "GateBool", (Type[])null, (Type[])null)); HarmonyMethod val2 = new HarmonyMethod(AccessTools.Method(typeof(Plugin), "GateVoid", (Type[])null, (Type[])null)); int num = 0; int num2 = 0; foreach (MethodBase item in Harmony.GetAllPatchedMethods().ToList()) { Patches patchInfo = Harmony.GetPatchInfo(item); if (patchInfo == null) { continue; } string text = item.DeclaringType?.Name + "." + item.Name; foreach (Patch item2 in from p in patchInfo.Prefixes.Concat(patchInfo.Postfixes) where p.owner == "valheim.torann.valheimlegends" select p) { if (AlwaysOn.Contains(text)) { num2++; continue; } try { harmony.Patch((MethodBase)item2.PatchMethod, (item2.PatchMethod.ReturnType == typeof(bool)) ? val : val2, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); num++; } catch (Exception ex) { base.Logger.LogWarning((object)("Could not gate Legends hook on " + text + ": " + ex.Message)); } } } base.Logger.LogInfo((object)string.Format("Legends switch ready: {0} gameplay hooks gated, {1} data hooks always on. Legends is {2}.", num, num2, _enabled.Value ? "ON" : "OFF")); } private static bool GateBool(ref bool __result) { if (_enabled.Value) { return true; } __result = true; return false; } private static bool GateVoid() { return _enabled.Value; } private void OnSwitched() { _log.LogInfo((object)("Valheim Legends switched " + (_enabled.Value ? "ON" : "OFF"))); Player localPlayer = Player.m_localPlayer; if (localPlayer != null) { ((Character)localPlayer).Message((MessageType)2, "Valheim Legends " + (_enabled.Value ? "ON" : "OFF"), 0, (Sprite)null, false); } if (!_enabled.Value) { RemoveAbilityBar(); } _sweepTimer = 0f; } private static void RemoveAbilityBar() { FieldInfo fieldInfo = _legends?.GetType("ValheimLegends.ValheimLegends")?.GetField("abilitiesStatus", BindingFlags.Static | BindingFlags.Public); if (!(fieldInfo?.GetValue(null) is List<RectTransform> list)) { return; } foreach (RectTransform item in list) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)((Component)item).gameObject); } } fieldInfo.SetValue(null, null); } private void Update() { if (_legends == null || _enabled.Value || (Object)(object)Player.m_localPlayer == (Object)null) { return; } _sweepTimer -= Time.deltaTime; if (_sweepTimer > 0f) { return; } _sweepTimer = 0.5f; SEMan sEMan = ((Character)Player.m_localPlayer).GetSEMan(); foreach (StatusEffect item in sEMan.GetStatusEffects().ToList()) { if ((Object)(object)item != (Object)null && ((object)item).GetType().Assembly == _legends) { sEMan.RemoveStatusEffect(item.NameHash(), true); } } } } } namespace KeepLoaded { public class Plugin : DigiModule { public const string Guid = "digi.valheim.keeploaded"; public const string Name = "Digi's Keep Loaded"; public const string Version = "1.0.2"; private const string LoadedKey = "pieter_keeploaded"; private static ConfigEntry<bool> _crossbows; private static ConfigEntry<bool> _grapplingHook; private static readonly FieldRef<Player, ItemData> WeaponLoaded = AccessTools.FieldRefAccess<Player, ItemData>("m_weaponLoaded"); private static readonly Action<Player, ItemData> SetWeaponLoaded = AccessTools.MethodDelegate<Action<Player, ItemData>>(AccessTools.Method(typeof(Player), "SetWeaponLoaded", (Type[])null, (Type[])null), (object)null, true); private void MigrateConfig() { string text = Path.Combine(Paths.ConfigPath, "digi.valheim.keeploaded".Replace("digi.valheim.", "pieter.valheim.") + ".cfg"); if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text)) { File.Copy(text, base.Config.ConfigFilePath); base.Config.Reload(); } } private void Awake() { MigrateConfig(); _crossbows = base.Config.Bind("General", "Crossbows stay loaded", defaultValue: true, "A loaded crossbow stays loaded when you switch to another weapon and back."); _grapplingHook = base.Config.Bind("General", "Grappling hook stays loaded", defaultValue: true, "A loaded grappling hook stays loaded when you switch to another item and back."); PatchModule(typeof(Plugin)); } private static bool Applies(ItemData item) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Invalid comparison between Unknown and I4 if (item?.m_shared == null || !item.m_shared.m_attack.m_requiresReload) { return false; } if ((int)item.m_shared.m_skillType == 14) { return _crossbows.Value; } if ((((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : "").Contains("Grappling") || item.m_shared.m_name.ToLowerInvariant().Contains("grappl")) { return _grapplingHook.Value; } return false; } [HarmonyPatch(typeof(Humanoid), "UnequipItem")] [HarmonyPrefix] private static void Unequip(Humanoid __instance, ItemData item) { Player val = (Player)(object)((__instance is Player) ? __instance : null); if (val != null && !((Object)(object)val != (Object)(object)Player.m_localPlayer) && item != null && WeaponLoaded.Invoke(val) == item && Applies(item) && ((Humanoid)val).IsItemEquiped(item)) { item.m_customData["pieter_keeploaded"] = "1"; } } [HarmonyPatch(typeof(Player), "UpdateWeaponLoading")] [HarmonyPrefix] private static void UpdateWeaponLoading(Player __instance, ItemData weapon) { if (weapon != null && WeaponLoaded.Invoke(__instance) != weapon && weapon.m_customData.ContainsKey("pieter_keeploaded")) { weapon.m_customData.Remove("pieter_keeploaded"); if (Applies(weapon)) { SetWeaponLoaded(__instance, weapon); } } } } } namespace InstantLoot { public class Plugin : DigiModule { public const string Guid = "digi.valheim.instantloot"; public const string Name = "Digi's Instant Loot"; public const string Version = "1.0.2"; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<bool> FeedEnabled; internal static ConfigEntry<bool> FeedOutline; private static ConfigEntry<float> _dropDelay; private static ConfigEntry<float> _corpseTime; private static ConfigEntry<float> _pickupDelay; private static ConfigEntry<float> _pickupRange; internal static ConfigEntry<PickupFeed.Corner> FeedCorner; internal static ConfigEntry<int> FeedX; internal static ConfigEntry<int> FeedY; internal static ConfigEntry<int> FeedWidth; internal static ConfigEntry<int> FeedLines; internal static ConfigEntry<int> FeedFontSize; internal static ConfigEntry<float> FeedOpacity; internal static ConfigEntry<float> FeedLinger; internal static ConfigEntry<Color> FeedTextColor; internal static ConfigEntry<Color> FeedAmountColor; internal static ConfigEntry<Color> FeedOutlineColor; private static readonly Action<Ragdoll, Vector3> SpawnLoot = AccessTools.MethodDelegate<Action<Ragdoll, Vector3>>(AccessTools.Method(typeof(Ragdoll), "SpawnLoot", (Type[])null, (Type[])null), (object)null, true); private static readonly FieldRef<Ragdoll, ZNetView> RagdollView = AccessTools.FieldRefAccess<Ragdoll, ZNetView>("m_nview"); private static bool _spawningLoot; private static readonly List<ItemDrop> Waiting = new List<ItemDrop>(); private static readonly List<float> WaitUntil = new List<float>(); private static float _vanillaRange = -1f; private const string EpicLootName = "characterName"; private const string EpicLootLuckyRolls = "el-lky-rolls"; private void MigrateConfig() { string text = Path.Combine(Paths.ConfigPath, "digi.valheim.instantloot".Replace("digi.valheim.", "pieter.valheim.") + ".cfg"); if (!File.Exists(base.Config.ConfigFilePath) && File.Exists(text)) { File.Copy(text, base.Config.ConfigFilePath); base.Config.Reload(); } } private void Awake() { //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Expected O, but got Unknown //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Expected O, but got Unknown //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d1: Expected O, but got Unknown //IL_01f9: Unknown result type (might be due to invalid IL or missing references) //IL_0203: Expected O, but got Unknown //IL_022c: Unknown result type (might be due to invalid IL or missing references) //IL_0236: Expected O, but got Unknown //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Expected O, but got Unknown //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02b0: Expected O, but got Unknown //IL_02e5: Unknown result type (might be due to invalid IL or missing references) //IL_0318: Unknown result type (might be due to invalid IL or missing references) //IL_033c: Unknown result type (might be due to invalid IL or missing references) MigrateConfig(); Enabled = base.Config.Bind("1 - Loot", "Enabled", defaultValue: true, "Monsters drop their loot the moment they die, instead of when the body fades."); _dropDelay = base.Config.Bind("1 - Loot", "Drop delay (s)", 0.05f, new ConfigDescription("Seconds between a creature's death and its loot dropping.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>())); _corpseTime = base.Config.Bind("1 - Loot", "Corpse time (s)", 60f, new ConfigDescription("How long dead creatures stay before they fade, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 600f), Array.Empty<object>())); _pickupDelay = base.Config.Bind("2 - Pickup", "Auto-pickup delay (s)", 1f, new ConfigDescription("Seconds before monster loot can be picked up automatically (lets it land first). 0 = right away.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); _pickupRange = base.Config.Bind("2 - Pickup", "Auto-pickup range (m)", 2.5f, new ConfigDescription("How close items must be to be picked up automatically, in meters. Normal is 2.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); FeedEnabled = base.Config.Bind("3 - Pickup list", "Enabled", defaultValue: true, "Show pickups stacked in a small list (e.g. \"Leather scraps x7\") instead of one message per item."); FeedCorner = base.Config.Bind("3 - Pickup list", "Corner", PickupFeed.Corner.BottomRight, "Which corner of the screen the list is in."); FeedX = base.Config.Bind("3 - Pickup list", "Offset X", 20, "Distance from the left or right edge of the screen, in pixels."); FeedY = base.Config.Bind("3 - Pickup list", "Offset Y", 20, "Distance from the top or bottom edge of the screen, in pixels."); FeedWidth = base.Config.Bind("3 - Pickup list", "Width", 250, new ConfigDescription("Width of the list, in pixels.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 800), Array.Empty<object>())); FeedLines = base.Config.Bind("3 - Pickup list", "Max lines", 5, new ConfigDescription("How many pickups are shown at once.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 20), Array.Empty<object>())); FeedFontSize = base.Config.Bind("3 - Pickup list", "Font size", 15, new ConfigDescription("Text size.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(8, 40), Array.Empty<object>())); FeedOpacity = base.Config.Bind("3 - Pickup list", "Background opacity", 0f, new ConfigDescription("Background behind the list: 0 = none, 1 = solid black.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); FeedLinger = base.Config.Bind("3 - Pickup list", "Seconds shown", 8f, new ConfigDescription("How long each pickup stays in the list, in seconds.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 30f), Array.Empty<object>())); FeedOutline = base.Config.Bind("3 - Pickup list", "Text outline", defaultValue: true, "Dark edge around the text so it stays readable on bright backgrounds."); FeedTextColor = base.Config.Bind<Color>("3 - Pickup list", "Text color", Color.white, "Color of the item names."); FeedAmountColor = base.Config.Bind<Color>("3 - Pickup list", "Amount color", new Color(0.95f, 0.9f, 0.75f), "Color of the amounts (x7)."); FeedOutlineColor = base.Config.Bind<Color>("3 - Pickup list", "Outline color", Color.black, "Color of the text edge (fully transparent = no edge)."); _pickupRange.SettingChanged += delegate { ApplyRange(Player.m_localPlayer); }; Enabled.SettingChanged += delegate { ApplyRange(Player.m_localPlayer); }; if ((Object)(object)((Component)this).gameObject.GetComponent<PickupFeed>() == (Object)null) { ((Component)this).gameObject.AddComponent<PickupFeed>(); } PatchModule(typeof(Plugin)); } [HarmonyPatch(typeof(Ragdoll), "Awake")] [HarmonyPostfix] private static void RagdollAwake(Ragdoll __instance) { if (Enabled.Value) { ((MonoBehaviour)__instance).CancelInvoke("DestroyNow"); ((MonoBehaviour)__instance).InvokeRepeating("DestroyNow", _corpseTime.Value, 1f); ((MonoBehaviour)__instance).StartCoroutine(DropLoot(__instance)); } } private static IEnumerator DropLoot(Ragdoll ragdoll) { if (_dropDelay.Value > 0f) { yield return (object)new WaitForSeconds(_dropDelay.Value); } else { yield return null; } ZNetView val = RagdollView.Invoke(ragdoll); if ((Object)(object)val == (Object)null || !val.IsValid() || !val.IsOwner()) { yield break; } ZDO zDO = val.GetZDO(); bool flag = !string.IsNullOrEmpty(zDO.GetString("characterName", "")); if (zDO.GetInt(ZDOVars.s_drops, 0) > 0 || flag) { Vector3 arg = (((Object)(object)ragdoll.m_lootSpawnJoint != (Object)null) ? ragdoll.m_lootSpawnJoint.transform.position : ragdoll.GetAverageBodyPosition()); _spawningLoot = true; try { SpawnLoot(ragdoll, arg); } finally { _spawningLoot = false; } zDO.Set(ZDOVars.s_drops, 0, false); if (flag) { zDO.Set("characterName", ""); zDO.Set("el-lky-rolls", 0); } } } [HarmonyPatch(typeof(ItemDrop), "Awake")] [HarmonyPostfix] private static void ItemAwake(ItemDrop __instance) { if (_spawningLoot && !(_pickupDelay.Value <= 0f) && __instance.m_autoPickup) { __instance.m_autoPickup = false; Waiting.Add(__instance); WaitUntil.Add(Time.time + _pickupDelay.Value); } } private void Update() { for (int num = Waiting.Count - 1; num >= 0; num--) { if (!((Object)(object)Waiting[num] != (Object)null) || !(Time.time < WaitUntil[num])) { if ((Object)(object)Waiting[num] != (Object)null) { Waiting[num].m_autoPickup = true; } Waiting.RemoveAt(num); WaitUntil.RemoveAt(num); } } } [HarmonyPatch(typeof(Player), "OnSpawned")] [HarmonyPostfix] private static void Spawned(Player __instance) { if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { ApplyRange(__instance); } } private static void ApplyRange(Player player) { if (!((Object)(object)player == (Object)null)) { if (_vanillaRange < 0f) { _vanillaRange = player.m_autoPickupRange; } player.m_autoPickupRange = (Enabled.Value ? _pickupRange.Value : _vanillaRange); } } [HarmonyPatch(typeof(Character), "ShowPickupMessage")] [HarmonyPrefix] private static bool PickupMessage(Character __instance, ItemData item, int amount) { if (!FeedEnabled.Value || (Object)(object)__instance != (Object)(object)Player.m_localPlayer || (Object)(object)PickupFeed.Instance == (Object)null) { return true; } PickupFeed.Instance.Add(item, amount); return false; } } public class PickupFeed : MonoBehaviour { public enum Corner { BottomRight, BottomLeft, TopRight, TopLeft } private class Line { public string Name; public string AmountText; public int Amount; public Sprite Icon; public float Age; } private readonly List<Line> _lines = new List<Line>(); private GUIStyle _name; private GUIStyle _amount; private int _styleSize = -1; private Texture2D _pixel; public static PickupFeed Instance { get; private set; } private void Awake() { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Expected O, but got Unknown //IL_001b: Unknown result type (might be due to invalid IL or missing references) Instance = this; _pixel = new Texture2D(1, 1); _pixel.SetPixel(0, 0, Color.white); _pixel.Apply(); } public void Add(ItemData item, int amount) { if (item?.m_shared == null || amount <= 0) { return; } string text = ((Localization.instance != null) ? Localization.instance.Localize(item.m_shared.m_name) : item.m_shared.m_name); foreach (Line line in _lines) { if (!(line.Name != text)) { line.Amount += amount; line.AmountText = "x" + line.Amount; line.Age = 0f; _lines.Remove(line); _lines.Add(line); return; } } Sprite[] icons = item.m_shared.m_icons; _lines.Add(new Line { Name = text, Amount = amount, AmountText = "x" + amount, Icon = ((icons != null && icons.Length != 0) ? icons[Mathf.Clamp(item.m_variant, 0, icons.Length - 1)] : null) }); while (_lines.Count > Plugin.FeedLines.Value) { _lines.RemoveAt(0); } } private void Update() { if (_lines.Count == 0) { return; } float value = Plugin.FeedLinger.Value; for (int num = _lines.Count - 1; num >= 0; num--) { _lines[num].Age += Time.unscaledDeltaTime; if (_lines[num].Age >= value) { _lines.RemoveAt(num); } } } private void OnGUI() { //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_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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_0089: Expected O, but got Unknown //IL_0090: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a8: Expected O, but got Unknown //IL_0143: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0368: Unknown result type (might be due to invalid IL or missing references) //IL_02f4: Unknown result type (might be due to invalid IL or missing references) //IL_030b: Unknown result type (might be due to invalid IL or missing references) //IL_0329: Unknown result type (might be due to invalid IL or missing references) //IL_0340: Unknown result type (might be due to invalid IL or missing references) //IL_023e: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Unknown result type (might be due to invalid IL or missing references) //IL_0278: Unknown result type (might be due to invalid IL or missing references) //IL_02bf: Unknown result type (might be due to invalid IL or missing references) if (_lines.Count == 0 || !Plugin.FeedEnabled.Value || (Object)(object)Player.m_localPlayer == (Object)null || Hud.IsUserHidden()) { return; } int value = Plugin.FeedFontSize.Value; if (_name == null || _styleSize != value) { _styleSize = value; _name = new GUIStyle(GUI.skin.label) { fontSize = value, fontStyle = (FontStyle)1, alignment = (TextAnchor)3, clipping = (TextClipping)1, wordWrap = false }; _amount = new GUIStyle(_name) { alignment = (TextAnchor)5, clipping = (TextClipping)0 }; } float num = (float)value + 9f; float num2 = Plugin.FeedWidth.Value; float num3 = (float)Plugin.FeedLines.Value * num + 8f; Corner value2 = Plugin.FeedCorner.Value; bool num4 = value2 == Corner.BottomRight || value2 == Corner.TopRight; bool flag = value2 == Corner.BottomRight || value2 == Corner.BottomLeft; float num5 = (num4 ? ((float)Screen.width - num2 - (float)Plugin.FeedX.Value) : ((float)Plugin.FeedX.Value)); float num6 = (flag ? ((float)Screen.height - num3 - (float)Plugin.FeedY.Value) : ((float)Plugin.FeedY.Value)); Color color = GUI.color; if (Plugin.FeedOpacity.Value > 0f) { GUI.color = new Color(0.04f, 0.05f, 0.06f, Plugin.FeedOpacity.Value); GUI.DrawTexture(new Rect(num5, num6, num2, num3), (Texture)(object)_pixel); } float value3 = Plugin.FeedLinger.Value; float num7 = (flag ? (num6 + num3 - 4f - num) : (num6 + 4f)); for (int num8 = _lines.Count - 1; num8 >= 0; num8--) { Line line = _lines[num8]; float num9 = Mathf.Clamp01((value3 - line.Age) / 0.8f); float num10 = num5 + 6f; if ((Object)(object)line.Icon != (Object)null && (Object)(object)line.Icon.texture != (Object)null) { Texture2D texture = line.Icon.texture; Rect textureRect = line.Icon.textureRect; GUI.color = new Color(1f, 1f, 1f, num9); GUI.DrawTextureWithTexCoords(new Rect(num10, num7 + 3f, num - 6f, num - 6f), (Texture)(object)texture, new Rect(((Rect)(ref textureRect)).x / (float)((Texture)texture).width, ((Rect)(ref textureRect)).y / (float)((Texture)texture).height, ((Rect)(ref textureRect)).width / (float)((Texture)texture).width, ((Rect)(ref textureRect)).height / (float)((Texture)texture).height)); num10 += num; } float num11 = (float)value * 3.4f + 16f; Label(new Rect(num10, num7, num5 + num2 - num10 - num11 - 6f, num), line.Name, _name, Plugin.FeedTextColor.Value, num9); Label(new Rect(num5 + num2 - num11 - 6f, num7, num11, num), line.AmountText, _amount, Plugin.FeedAmountColor.Value, num9); num7 += (flag ? (0f - num) : num); } GUI.color = color; } private static void Label(Rect rect, string text, GUIStyle style, Color color, float fade) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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) GUI.color = Color.white; if (Plugin.FeedOutline.Value) { Color value = Plugin.FeedOutlineColor.Value; value.a *= fade; style.normal.textColor = value; GUI.Label(new Rect(((Rect)(ref rect)).x + 1f, ((Rect)(ref rect)).y + 1f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, style); GUI.Label(new Rect(((Rect)(ref rect)).x - 1f, ((Rect)(ref rect)).y - 1f, ((Rect)(ref rect)).width, ((Rect)(ref rect)).height), text, style); } color.a *= fade; style.normal.textColor = color; GUI.Label(rect, text, style); } } } namespace HitEffects { public class Plugin : DigiModule { [Flags] private enum Kind { None = 0, Status = 1, CreatureHit = 2, Weapon = 4, Projectile = 8, Area = 0x10 } private sealed class Faded { public int Version; public int Count; public MinMaxGradient[] Colors; public MinMaxCurve[] Size; public MinMaxCurve[] SizeX; public MinMaxCurve[] SizeY; public MinMaxCurve[] SizeZ; } private static ConfigEntry<int> _opacity; private static ConfigEntry<int> _brightness; private static ConfigEntry<int> _size; private static ConfigEntry<bool> _status; private static ConfigEntry<bool> _creatureHits; private static ConfigEntry<bool> _weapons; private static ConfigEntry<bool> _projectiles; private static ConfigEntry<bool> _areas; private static ConfigEntry<bool> _players; private static ConfigEntry<bool> _log; private static Plugin _instance; private static ObjectDB _listsOf; private static readonly HashSet<EffectList> StatusLists = new HashSet<EffectList>(); private static readonly HashSet<EffectList> WeaponLists = new HashSet<EffectList>(); private static ZNetScene _networkOf; private static readonly Dictionary<int, Kind> NetworkEffects = new Dictionary<int, Kind>(); private static readonly List<EffectList> Impacts = new List<EffectList>(4); private static readonly List<Kind> ImpactKinds = new List<Kind>(4); private static readonly Dictionary<string, Faded> Cache = new Dictionary<string, Faded>(); private static readonly List<ParticleSystem> Systems = new List<ParticleSystem>(16); private static int _version; private static bool Fades { get { if (_opacity.Value >= 100 && _brightness.Value >= 100) { return _size.Value < 100; } return true; } } private void Awake() { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Expected O, but got Unknown //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Expected O, but got Unknown _instance = this; _opacity = base.Config.Bind("1 - Strength", "Opacity (%)", 35, new ConfigDescription("How visible the faded effects stay: 100 = normal, 35 = faint (default), 0 = invisible. This is the main setting: lower it until you can see an enemy's attack wind-up through the effects. Applies from the next effect on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); _brightness = base.Config.Bind("1 - Strength", "Brightness (%)", 100, new ConfigDescription("Also darkens the colours: 100 = normal. Leave it at 100 unless an effect still looks bright after lowering Opacity (glowing effects add light on top of the picture and partly ignore Opacity). Real lights are never changed, so hits still light up dark places.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); _size = base.Config.Bind("1 - Strength", "Size (%)", 100, new ConfigDescription("Shrinks the effects so they cover less of the creature, instead of (or as well as) fading them: 100 = normal, 50 = half as big.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(10, 100), Array.Empty<object>())); _status = base.Config.Bind("2 - Which effects", "Status effects on creatures", defaultValue: true, "The flames on a burning creature, the frost shell, the poison cloud and other status effect visuals, and the small burst they repeat on every damage tick. They last as long as the effect does, so they hide a creature the longest: this is most of what this mod does."); _creatureHits = base.Config.Bind("2 - Which effects", "Hit bursts on creatures", defaultValue: true, "Blood, sparks and the extra burst of a critical hit or sneak attack that a creature throws off when it is hit."); _weapons = base.Config.Bind("2 - Which effects", "Weapon impacts", defaultValue: true, "The burst a weapon makes where it hits, including the fire, frost, lightning, poison and spirit bursts of elemental weapons."); _projectiles = base.Config.Bind("2 - Which effects", "Projectile impacts", defaultValue: true, "Where an arrow, bolt or staff projectile hits. Water splashes are not changed."); _areas = base.Config.Bind("2 - Which effects", "Area attacks", defaultValue: true, "The burst an area attack (atgeir sweep, bomb, ground slam, staff blast) makes on everything it hits."); _players = base.Config.Bind("2 - Which effects", "Also on players", defaultValue: false, "Also fade these effects when they are on a player: when you or a friend is hit, burning, poisoned, and so on. Off by default, so you still clearly see when you take damage."); _log = base.Config.Bind("3 - Troubleshooting", "Log faded effects", defaultValue: false, "Write the name of every effect this fades to the BepInEx log (LogOutput.log). Use it to check whether an effect that still bothers you is covered."); _opacity.SettingChanged += OnStrengthChanged; _brightness.SettingChanged += OnStrengthChanged; _size.SettingChanged += OnStrengthChanged; PatchModule(typeof(Plugin)); } private static void OnStrengthChanged(object sender, EventArgs e) { _version++; } private void OnDestroy() { _opacity.SettingChanged -= OnStrengthChanged; _brightness.SettingChanged -= OnStrengthChanged; _size.SettingChanged -= OnStrengthChanged; Impacts.Clear(); ImpactKinds.Clear(); if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } [HarmonyPatch(typeof(EffectList), "Create")] [HarmonyPostfix] private static void Created(EffectList __instance, GameObject[] __result, Vector3 basePos, Transform baseParent, ZDOID gamepadEffectsExclusiveToPlayer) { //IL_0010: 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) if (__result == null || __result.Length == 0 || !Fades) { return; } Kind kind = Classify(__instance, basePos, baseParent, gamepadEffectsExclusiveToPlayer); if (kind != Kind.None) { for (int i = 0; i < __result.Length; i++) { Fade(__result[i], kind); } } } private static Kind Classify(EffectList list, Vector3 pos, Transform parent, ZDOID owner) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) for (int num = Impacts.Count - 1; num >= 0; num--) { if (Impacts[num] == list) { return ImpactKinds[num]; } } UpdateLists(); if (WeaponLists.Contains(list)) { if (!_weapons.Value) { return Kind.None; } Character val = Find(owner); if (!((Object)(object)val != (Object)null) || val.IsPlayer() || val.IsTamed() || _players.Value) { return Kind.Weapon; } return Kind.None; } if (StatusLists.Contains(list)) { if (!_status.Value) { return Kind.None; } Character val2 = (((Object)(object)parent != (Object)null) ? ((Component)parent).GetComponentInParent<Character>() : (Find(owner) ?? Nearest(pos))); if (!((Object)(object)val2 != (Object)null) || !val2.IsPlayer() || _players.Value) { return Kind.Status; } return Kind.None; } if ((Object)(object)parent != (Object)null && _creatureHits.Value) { Character component = ((Component)parent).GetComponent<Character>(); if ((Object)(object)component != (Object)null && (list == component.m_hitEffects || list == component.m_critHitEffects || list == component.m_backstabHitEffects)) { if (!component.IsPlayer() || _players.Value) { return Kind.CreatureHit; } return Kind.None; } } return Kind.None; } private static Character Find(ZDOID id) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) if (((ZDOID)(ref id)).IsNone() || (Object)(object)ZNetScene.instance == (Object)null) { return null; } GameObject val = ZNetScene.instance.FindInstance(id); if (!((Object)(object)val != (Object)null)) { return null; } return val.GetComponent<Character>(); } private static Character Nearest(Vector3 pos) { //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_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) foreach (Character allCharacter in Character.GetAllCharacters()) { if ((Object)(object)allCharacter != (Object)null) { Vector3 val = ((Component)allCharacter).transform.position - pos; if (((Vector3)(ref val)).sqrMagnitude < 0.01f) { return allCharacter; } } } return null; } private static void UpdateLists() { ObjectDB instance = ObjectDB.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_listsOf) { return; } _listsOf = instance; StatusLists.Clear(); WeaponLists.Clear(); foreach (StatusEffect statusEffect in instance.m_StatusEffects) { if ((Object)(object)statusEffect == (Object)null) { continue; } Add(StatusLists, statusEffect.m_startEffects); SE_Stats val = (SE_Stats)(object)((statusEffect is SE_Stats) ? statusEffect : null); if (val != null) { Add(StatusLists, val.m_tickEffect); continue; } SE_Burning val2 = (SE_Burning)(object)((statusEffect is SE_Burning) ? statusEffect : null); if (val2 != null) { Add(StatusLists, val2.m_tickEffect); continue; } SE_Poison val3 = (SE_Poison)(object)((statusEffect is SE_Poison) ? statusEffect : null); if (val3 != null) { Add(StatusLists, val3.m_tickEffect); } } foreach (GameObject item in instance.m_items) { SharedData val4 = ((!((Object)(object)item != (Object)null)) ? null : item.GetComponent<ItemDrop>()?.m_itemData?.m_shared); if (val4 != null) { Add(WeaponLists, val4.m_hitEffect); Add(WeaponLists, val4.m_attack?.m_hitEffect); Add(WeaponLists, val4.m_secondaryAttack?.m_hitEffect); } } } private static void Add(HashSet<EffectList> set, EffectList list) { if (list?.m_effectPrefabs != null && list.m_effectPrefabs.Length != 0) { set.Add(list); } } [HarmonyPatch(typeof(Projectile), "OnHit")] [HarmonyPrefix] private static void ProjectileHit(Projectile __instance, out int __state) { __state = Arm(_projectiles.Value ? __instance.m_hitEffects : null, Kind.Projectile); } [HarmonyPatch(typeof(Projectile), "OnHit")] [HarmonyFinalizer] private static void ProjectileHitDone(int __state) { Disarm(__state); } [HarmonyPatch(typeof(Aoe), "OnHit")] [HarmonyPrefix] private static void AreaHit(Aoe __instance, out int __state) { __state = Arm(_areas.Value ? __instance.m_hitEffects : null, Kind.Area); } [HarmonyPatch(typeof(Aoe), "OnHit")] [HarmonyFinalizer] private static void AreaHitDone(int __state) { Disarm(__state); } private static int Arm(EffectList list, Kind kind) { int count = Impacts.Count; if (list != null && Fades) { Impacts.Add(list); ImpactKinds.Add(kind); } return count; } private static void Disarm(int depth) { if (Impacts.Count > depth) { Impacts.RemoveRange(depth, Impacts.Count - depth); ImpactKinds.RemoveRange(depth, ImpactKinds.Count - depth); } } [HarmonyPatch(typeof(ZNetScene), "CreateObject", new Type[] { typeof(ZDO) })] [HarmonyPostfix] private static void NetworkObject(ZDO zdo, GameObject __result) { if ((Object)(object)__result == (Object)null || zdo == null || !Fades) { return; } UpdateNetworkEffects(); if (NetworkEffects.TryGetValue(zdo.GetPrefab(), out var value)) { Kind kind = value & Enabled(); if (kind != Kind.None) { Fade(__result, kind); } } } private static Kind Enabled() { return (Kind)((_status.Value ? 1 : 0) | (_creatureHits.Value ? 2 : 0) | (_weapons.Value ? 4 : 0) | (_projectiles.Value ? 8 : 0) | (_areas.Value ? 16 : 0)); } private static void UpdateNetworkEffects() { ZNetScene instance = ZNetScene.instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance == (Object)(object)_networkOf || (Object)(object)ObjectDB.instance == (Object)null) { return; } _networkOf = instance; NetworkEffects.Clear(); foreach (GameObject prefab in instance.m_prefabs) { if (!((Object)(object)prefab == (Object)null)) { Character component = prefab.GetComponent<Character>(); if ((Object)(object)component != (Object)null) { Note(component.m_hitEffects, Kind.CreatureHit); Note(component.m_critHitEffects, Kind.CreatureHit); Note(component.m_backstabHitEffects, Kind.CreatureHit); } Projectile component2 = prefab.GetComponent<Projectile>(); if ((Object)(object)component2 != (Object)null) { Note(component2.m_hitEffects, Kind.Projectile); } Aoe component3 = prefab.GetComponent<Aoe>(); if ((Object)(object)component3 != (Object)null) { Note(component3.m_hitEffects, Kind.Area); } } } UpdateLists(); foreach (EffectList weaponList in WeaponLists) { Note(weaponList, Kind.Weapon); } foreach (EffectList statusList in StatusLists) { Note(statusList, Kind.Status); } } private static void Note(EffectList list, Kind kind) { if (list?.m_effectPrefabs == null) { return; } EffectData[] effectPrefabs = list.m_effectPrefabs; for (int i = 0; i < effectPrefabs.Length; i++) { GameObject val = effectPrefabs[i]?.m_prefab; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.GetComponent<ZNetView>() == (Object)null)) { int stableHashCode = StringExtensionMethods.GetStableHashCode(((Object)val).name); NetworkEffects.TryGetValue(stableHashCode, out var value); NetworkEffects[stableHashCode] = value | kind; } } } private static void Fade(GameObject effect, Kind kind) { //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b7: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_0124: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)effect == (Object)null) { return; } effect.GetComponentsInChildren<ParticleSystem>(true, Systems); if (Systems.Count == 0) { return; } string name = ((Object)effect).name; if (!Cache.TryGetValue(name, out var value) || value.Version != _version || value.Count != Systems.Count) { value = (Cache[name] = Work(Systems)); } bool flag = _opacity.Value < 100 || _brightness.Value < 100; bool flag2 = _size.Value < 100; for (int i = 0; i < Systems.Count; i++) { MainModule main = Systems[i].main; if (flag) { ((MainModule)(ref main)).startColor = value.Colors[i]; } if (flag2) { if (((MainModule)(ref main)).startSize3D) { ((MainModule)(ref main)).startSizeX = value.SizeX[i]; ((MainModule)(ref main)).startSizeY = value.SizeY[i]; ((MainModule)(ref main)).startSizeZ = value.SizeZ[i]; } else { ((MainModule)(ref main)).startSize = value.Size[i]; } } } Systems.Clear(); if (_log.Value) { Plugin instance = _instance; if (instance != null) { instance.Logger.LogInfo((object)$"Faded {name} ({kind})"); } } } private static Faded Work(List<ParticleSystem> systems) { //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: 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_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: 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_010c: 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_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) float alpha = (float)_opacity.Value / 100f; float light = (float)_brightness.Value / 100f; float factor = (float)_size.Value / 100f; int count = systems.Count; Faded faded = new Faded { Version = _version, Count = count, Colors = (MinMaxGradient[])(object)new MinMaxGradient[count], Size = (MinMaxCurve[])(object)new MinMaxCurve[count], SizeX = (MinMaxCurve[])(object)new MinMaxCurve[count], SizeY = (MinMaxCurve[])(object)new MinMaxCurve[count], SizeZ = (MinMaxCurve[])(object)new MinMaxCurve[count] }; for (int i = 0; i < count; i++) { MainModule main = systems[i].main; faded.Colors[i] = Dim(((MainModule)(ref main)).startColor, alpha, light); faded.Size[i] = Scale(((MainModule)(ref main)).startSize, factor); faded.SizeX[i] = Scale(((MainModule)(ref main)).startSizeX, factor); faded.SizeY[i] = Scale(((MainModule)(ref main)).startSizeY, factor); faded.SizeZ[i] = Scale(((MainModule)(ref main)).startSizeZ, factor); } return faded; } private static MinMaxGradient Dim(MinMaxGradient g, float alpha, float light) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) ParticleSystemGradientMode mode = ((MinMaxGradient)(ref g)).mode; switch ((int)mode) { case 0: return new MinMaxGradient(Dim(((MinMaxGradient)(ref g)).color, alpha, light)); case 2: return new MinMaxGradient(Dim(((MinMaxGradient)(ref g)).colorMin, alpha, light), Dim(((MinMaxGradient)(ref g)).colorMax, alpha, light)); case 3: return new MinMaxGradient(Dim(((MinMaxGradient)(ref g)).gradientMin, alpha, light), Dim(((MinMaxGradient)(ref g)).gradientMax, alpha, light)); case 1: case 4: { MinMaxGradient result = default(MinMaxGradient); ((MinMaxGradient)(ref result))..ctor(Dim(((MinMaxGradient)(ref g)).gradient, alpha, light)); ((MinMaxGradient)(ref result)).mode = ((MinMaxGradient)(ref g)).mode; return result; } default: return g; } } private static Color Dim(Color c, float alpha, float light) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) return new Color(c.r * light, c.g * light, c.b * light, c.a * alpha); } private static Gradient Dim(Gradient source, float alpha, float light) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0088: 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_009b: Expected O, but got Unknown if (source == null) { return null; } GradientColorKey[] colorKeys = source.colorKeys; GradientAlphaKey[] alphaKeys = source.alphaKeys; for (int i = 0; i < colorKeys.Length; i++) { Color color = colorKeys[i].color; colorKeys[i].color = new Color(color.r * light, color.g * light, color.b * light, color.a); } for (int j = 0; j < alphaKeys.Length; j++) { alphaKeys[j].alpha *= alpha; } Gradient val = new Gradient { mode = source.mode }; val.SetKeys(colorKeys, alphaKeys); return val; } private static MinMaxCurve Scale(MinMaxCurve curve, float factor) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) ((MinMaxCurve)(ref curve)).constantMin = ((MinMaxCurve)(ref curve)).constantMin * factor; ((MinMaxCurve)(ref curve)).constantMax = ((MinMaxCurve)(ref curve)).constantMax * factor; ((MinMaxCurve)(ref curve)).curveMultiplier = ((MinMaxCurve)(ref curve)).curveMultiplier * factor; return curve; } } } namespace GrappleAim { public class Plugin : DigiModule { private sealed class Shot { public Projectile Projectile; public Vector3 Start; public float Time; public float PredictedDistance; public bool Predicted; public bool Done; public bool AtClick; public bool HaveClick; public float AtClickDistance; } public const string Guid = "digi.valheim.grappleaim"; public const string Name = "Digi's Grapple Aim"; public const string Version = "1.2.1"; private static ConfigEntry<bool> _enabled; private static ConfigEntry<bool> _onlyWhenLoaded; private static ConfigEntry<bool> _colorInRange; private static ConfigEntry<bool> _tooltipRange; private static ConfigEntry<bool> _logShots; private static ConfigEntry<bool> _noFreeAmmo; internal static ManualLogSource Log; private Harmony _harmony; private static ConfigEntry<Color> _outOfRangeColor; private static ConfigEntry<Color> _inRangeColor; private static int _mask; private static readonly RaycastHit[] Hits = (RaycastHit[])(object)new RaycastHit[32]; private static readonly Color VanillaCrosshair = new Color(1f, 1f, 1f, 0.5f); private static bool _colored; private static bool _predicted; private static float _predictedDistance; private static Vector3 _simSpawn; private static Vector3 _simVelocity; private static float _simGravity; private static string _measuredItem; private static float _measuredFactor = 1f; private static Vector3 _handOffset; private static bool _haveHandOffset; private static readonly FieldRef<Humanoid, VisEquipment> VisEquipment = AccessTools.FieldRefAccess<Humanoid, VisEquipment>("m_visEquipment"); private static readonly FieldRef<Humanoid, Attack> CurrentAttack = AccessTools.FieldRefAccess<Humanoid, Attack>("m_currentAttack"); private static readonly FieldRef<Humanoid, ItemData> LeftItem = AccessTools.FieldRefAccess<Humanoid, ItemData>("m_leftItem"); private static ConfigEntry<bool> _archeryEnabled; private static ConfigEntry<float> _archeryVelocity; private static ConfigEntry<Vector3> _archeryAim; private static bool _archeryLooked; private static readonly List<Shot> Shots = new List<Shot>(); private static bool _predictedAtClick; private static bool _haveClick; private static float _predictedDistanceAtClick; private static int Mask { get { if (_mask == 0) { return _mask = LayerMask.GetMask(new string[12] { "Default", "static_solid", "Default_small", "piece", "piece_nonsolid", "terrain", "character", "character_net", "character_ghost", "hitbox", "character_noenv", "vehicle" }); } return _mask; } } private void Awake() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Expected O, but got Unknown _enabled = base.Config.Bind("Crosshair", "Enabled", defaultValue: true, "Turn the crosshair red when the grappling hook would not catch where you aim."); _outOfRangeColor = base.Config.Bind<Color>("Crosshair", "Out of range color", new Color(1f, 0.15f, 0.15f, 0.8f), "Crosshair color when the hook would miss: too far away, or a surface it can't hold on to."); _colorInRange = base.Config.Bind("Crosshair", "Color when in range", defaultValue: false, "Also give the crosshair its own color when the hook would catch. Off = the normal crosshair."); _inRangeColor = base.Config.Bind<Color>("Crosshair", "In range color", new Color(0.4f, 1f, 0.4f, 0.8f), "Crosshair color when the hook would catch (if turned on above)."); _onlyWhenLoaded = base.Config.Bind("Crosshair", "Only when loaded", defaultValue: false, "Only color the crosshair while the hook is loaded and ready to fire."); _tooltipRange = base.Config.Bind("Tooltip", "Show range", defaultValue: true, "Show the hook's range (how far it reaches when aimed straight ahead) in its tooltip."); _noFreeAmmo = base.Config.Bind("Better Archery", "No free ammo from the hook", defaultValue: true, "Better Archery counts the grappling hook as a bow, so its retrievable arrows drop your equipped arrow or bolt where the hook lands, although the hook used none (free ammo). On: Better Archery leaves hook shots alone; arrows and bolts work as before."); _logShots = base.Config.Bind("Testing", "Log shots", defaultValue: false, "Write every hook shot to the log: what the crosshair said, and where the hook really caught (or that it missed)."); Log = base.Logger; _harmony = PatchModule(typeof(Plugin)); Type type = (Chainloader.PluginInfos.ContainsKey("ishid4.mods.betterarchery") ? AccessTools.TypeByName("BetterArchery.RetrieveArrows") : null); MethodInfo methodInfo = ((type != null) ? AccessTools.Method(type, "Prefix", (Type[])null, (Type[])null) : null); if (methodInfo != null) { _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(typeof(Plugin), "NoArrowForHooks", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private void OnDestroy() { Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } private void LateUpdate() { //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_010b: 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_0127: Unknown result type (might be due to invalid IL or missing references) Hud instance = Hud.instance; Player localPlayer = Player.m_localPlayer; if ((Object)(object)instance == (Object)null || (Object)(object)instance.m_crosshair == (Object)null) { return; } Attack val = ((localPlayer == null) ? null : ((Humanoid)localPlayer).GetCurrentWeapon()?.m_shared?.m_attack); Projectile val2 = ((_enabled.Value && (Object)(object)localPlayer != (Object)null) ? HookProjectile(val) : null); if ((Object)(object)val2 == (Object)null || (_onlyWhenLoaded.Value && val.m_requiresReload && !((Humanoid)localPlayer).IsWeaponLoaded())) { if (_colored) { ((Graphic)instance.m_crosshair).color = VanillaCrosshair; } _colored = false; return; } _predicted = WouldCatch(localPlayer, val, val2, out _predictedDistance); if (!_predicted) { ((Graphic)instance.m_crosshair).color = _outOfRangeColor.Value; } else if (_colorInRange.Value) { ((Graphic)instance.m_crosshair).color = _inRangeColor.Value; } else if (_colored && ((Graphic)instance.m_crosshair).color == _outOfRangeColor.Value) { ((Graphic)instance.m_crosshair).color = VanillaCrosshair; } _colored = !_predicted || _colorInRange.Value; } private static Projectile HookProjectile(Attack attack) { Projectile val = (((Object)(object)attack?.m_attackProjectile != (Object)null) ? attack.m_attackProjectile.GetComponent<Projectile>() : null); if (!((Object)(object)val != (Object)null) || !((Object)(object)val.m_spawnOnHit != (Object)null) || !((Object)(object)val.m_spawnOnHit.GetComponent<GrapplingPoint>() != (Object)null)) { return null; } return val; } private static bool NoArrowForHooks(ref Projectile __0, ref bool __result) { if (!_noFreeAmmo.Value || (Object)(object)__0 == (Object)null || (Object)(object)__0.m_spawnOnHit == (Object)null || (Object)(object)__0.m_spawnOnHit.GetComponent<GrapplingPoint>() == (Object)null) { return true; } __result = true; return false; } [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] [HarmonyPostfix] private static void Tooltip(ItemData item, ref string __result) { if (_tooltipRange.Value && item?.m_shared != null && __result != null) { Attack attack = item.m_shared.m_attack; Projectile val = HookProjectile(attack); if (!((Object)(object)val == (Object)null)) { __result += $"\nRange: <color=orange>{Range(item, attack, val):0} m</color>"; } } } private static float Range(ItemData item, Attack attack, Projectile projectile) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_0028: Invalid comparison between Unknown and I4 //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: 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_00cf: 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_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Unknown result type (might be due to invalid IL or missing references) //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_00f9: 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_0115: Unknown result type (might be due to invalid IL or missing references) //IL_011a: 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) Vector3 val = Vector3.zero; float num = attack.m_projectileVel; Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && (int)item.m_shared.m_itemType == 4 && ((Humanoid)localPlayer).GetAmmoItem() != null) { BetterArcheryApplies(localPlayer); if (_archeryEnabled != null && _archeryVelocity != null && _archeryEnabled.Value) { num = _archeryVelocity.Value; } } if ((Object)(object)localPlayer != (Object)null && _measuredItem == item.m_shared.m_name && _measuredFactor > 0.2f && _measuredFactor < 5f) { num *= _measuredFactor; } Vector3 val2 = Vector3.forward * num; float num2 = ((projectile.m_ttl > 0f) ? projectile.m_ttl : 4f); for (float num3 = 0f; num3 < num2; num3 += 0.02f) { val2 += Vector3.down * (projectile.m_gravity * 0.02f); if (projectile.m_drag > 0f) { val2 -= ((Vector3)(ref val2)).normalized * (((Vector3)(ref val2)).sqrMagnitude * projectile.m_drag * 0.02f); } val += val2 * 0.02f; } GrapplingPoint val3 = (((Object)(object)projectile.m_spawnOnHit != (Object)null) ? projectile.m_spawnOnHit.GetComponent<GrapplingPoint>() : null); if (!((Object)(object)val3 != (Object)null) || !(val3.m_maxLength > 0f)) { return ((Vector3)(ref val)).magnitude; } return Mathf.Min(((Vector3)(ref val)).magnitude, val3.m_maxLength); } private static bool WouldCatch(Player player, Attack attack, Projectile projectile, out float hitDistance) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_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_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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: 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_0101: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_01bf: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) hitDistance = 0f; Launch(player, attack, measured: true, out var spawn, out var velocity); _simSpawn = spawn; _simVelocity = velocity; _simGravity = projectile.m_gravity; float num = ((Time.fixedDeltaTime > 0f) ? Time.fixedDeltaTime : 0.02f); float num2 = projectile.m_ttl; Vector3 val = spawn; bool flag = projectile.m_doOwnerRaytest; Vector3 centerPoint = ((Character)player).GetCenterPoint(); centerPoint.y = spawn.y; for (int i = 0; i < 2000; i++) { Vector3 val2 = (flag ? centerPoint : val); velocity += Vector3.down * (projectile.m_gravity * num); if (projectile.m_drag > 0f) { velocity -= ((Vector3)(ref velocity)).normalized * (((Vector3)(ref velocity)).sqrMagnitude * projectile.m_drag * num); } val += velocity * num; Vector3 val3 = val - val2; if (!flag) { val2 -= ((Vector3)(ref val3)).normalized * (((Vector3)(ref val3)).magnitude * 0.5f); } flag = false; float num3 = ((Vector3)(ref val3)).magnitude * 1.5f; if (num3 > 0.0001f) { int num4 = Physics.RaycastNonAlloc(val2, ((Vector3)(ref val3)).normalized, Hits, num3, Mask); int num5 = -1;