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 OttoAura v1.5.3
OttoAura.dll
Decompiled a day 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.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using OttoAura.AuraBoost; using OttoAura.AuraDispel; using OttoAura.AuraMove; using OttoAura.AuraTrade; using OttoAura.Config; using ServerSync; using SkillManager; using TMPro; using UnityEngine; using UnityEngine.PostProcessing; using UnityEngine.Rendering; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("OttoAura")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("potto007")] [assembly: AssemblyProduct("OttoAura")] [assembly: AssemblyCopyright("Copyright © 2022-2026 OttoAura contributors")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("E0E2F92E-557C-4A05-9D89-AA92A0BD75C4")] [assembly: AssemblyFileVersion("1.5.3")] [assembly: InternalsVisibleTo("OttoAura.Tests")] [assembly: IgnoresAccessChecksTo("assembly_guiutils")] [assembly: IgnoresAccessChecksTo("assembly_postprocessing")] [assembly: IgnoresAccessChecksTo("assembly_utils")] [assembly: IgnoresAccessChecksTo("assembly_valheim")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.5.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkillManager { [PublicAPI] public class Skill { public static class LocalizationCache { private static readonly Dictionary<string, Localization> localizations = new Dictionary<string, Localization>(); internal static void LocalizationPostfix(Localization __instance, string language) { string key = localizations.FirstOrDefault<KeyValuePair<string, Localization>>((KeyValuePair<string, Localization> l) => l.Value == __instance).Key; if (key != null) { localizations.Remove(key); } if (!localizations.ContainsKey(language)) { localizations.Add(language, __instance); } } public static Localization ForLanguage(string? language = null) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown if (localizations.TryGetValue(language ?? PlayerPrefs.GetString("language", "English"), out Localization value)) { return value; } value = new Localization(); if (language != null) { value.SetupLanguage(language); } return value; } } [PublicAPI] public class LocalizeKey { private static readonly List<LocalizeKey> keys = new List<LocalizeKey>(); public readonly string Key; public readonly Dictionary<string, string> Localizations = new Dictionary<string, string>(); public LocalizeKey(string key) { Key = key.Replace("$", ""); } public void Alias(string alias) { Localizations.Clear(); if (!alias.Contains("$")) { alias = "$" + alias; } Localizations["alias"] = alias; Localization.instance.AddWord(Key, Localization.instance.Localize(alias)); } public LocalizeKey English(string key) { return addForLang("English", key); } public LocalizeKey Swedish(string key) { return addForLang("Swedish", key); } public LocalizeKey French(string key) { return addForLang("French", key); } public LocalizeKey Italian(string key) { return addForLang("Italian", key); } public LocalizeKey German(string key) { return addForLang("German", key); } public LocalizeKey Spanish(string key) { return addForLang("Spanish", key); } public LocalizeKey Russian(string key) { return addForLang("Russian", key); } public LocalizeKey Romanian(string key) { return addForLang("Romanian", key); } public LocalizeKey Bulgarian(string key) { return addForLang("Bulgarian", key); } public LocalizeKey Macedonian(string key) { return addForLang("Macedonian", key); } public LocalizeKey Finnish(string key) { return addForLang("Finnish", key); } public LocalizeKey Danish(string key) { return addForLang("Danish", key); } public LocalizeKey Norwegian(string key) { return addForLang("Norwegian", key); } public LocalizeKey Icelandic(string key) { return addForLang("Icelandic", key); } public LocalizeKey Turkish(string key) { return addForLang("Turkish", key); } public LocalizeKey Lithuanian(string key) { return addForLang("Lithuanian", key); } public LocalizeKey Czech(string key) { return addForLang("Czech", key); } public LocalizeKey Hungarian(string key) { return addForLang("Hungarian", key); } public LocalizeKey Slovak(string key) { return addForLang("Slovak", key); } public LocalizeKey Polish(string key) { return addForLang("Polish", key); } public LocalizeKey Dutch(string key) { return addForLang("Dutch", key); } public LocalizeKey Portuguese_European(string key) { return addForLang("Portuguese_European", key); } public LocalizeKey Portuguese_Brazilian(string key) { return addForLang("Portuguese_Brazilian", key); } public LocalizeKey Chinese(string key) { return addForLang("Chinese", key); } public LocalizeKey Japanese(string key) { return addForLang("Japanese", key); } public LocalizeKey Korean(string key) { return addForLang("Korean", key); } public LocalizeKey Hindi(string key) { return addForLang("Hindi", key); } public LocalizeKey Thai(string key) { return addForLang("Thai", key); } public LocalizeKey Abenaki(string key) { return addForLang("Abenaki", key); } public LocalizeKey Croatian(string key) { return addForLang("Croatian", key); } public LocalizeKey Georgian(string key) { return addForLang("Georgian", key); } public LocalizeKey Greek(string key) { return addForLang("Greek", key); } public LocalizeKey Serbian(string key) { return addForLang("Serbian", key); } public LocalizeKey Ukrainian(string key) { return addForLang("Ukrainian", key); } private LocalizeKey addForLang(string lang, string value) { Localizations[lang] = value; if (Localization.instance.GetSelectedLanguage() == lang) { Localization.instance.AddWord(Key, value); } else if (lang == "English" && !Localization.instance.m_translations.ContainsKey(Key)) { Localization.instance.AddWord(Key, value); } return this; } [HarmonyPriority(300)] internal static void AddLocalizedKeys(Localization __instance, string language) { foreach (LocalizeKey key in keys) { string value2; if (key.Localizations.TryGetValue(language, out string value) || key.Localizations.TryGetValue("English", out value)) { __instance.AddWord(key.Key, value); } else if (key.Localizations.TryGetValue("alias", out value2)) { Localization.instance.AddWord(key.Key, Localization.instance.Localize(value2)); } } } } private class ConfigurationManagerAttributes { [UsedImplicitly] public string? Category; } [HarmonyPatch(typeof(Skills), "IsSkillValid")] private static class Patch_Skills_IsSkillValid { private static void Postfix(SkillType type, ref bool __result) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if (!__result && skills.ContainsKey(type)) { __result = true; } } } private static readonly Dictionary<SkillType, Skill> skills; internal static readonly Dictionary<string, Skill> skillByName; private readonly string skillName; private readonly string internalSkillName; private readonly SkillDef skillDef; public readonly LocalizeKey Name; public readonly LocalizeKey Description; private float skillEffectFactor = 1f; private int skillLoss = 5; public bool Configurable; private static bool InitializedTerminal; private static readonly MethodInfo? LoadImageMethod; private static Localization? _english; private static BaseUnityPlugin? _plugin; private static bool hasConfigSync; private static object? _configSync; public float SkillGainFactor { get { return skillDef.m_increseStep; } set { skillDef.m_increseStep = value; this.SkillGainFactorChanged?.Invoke(value); } } public float SkillEffectFactor { get { return skillEffectFactor; } set { skillEffectFactor = value; this.SkillEffectFactorChanged?.Invoke(value); } } public int SkillLoss { get { return skillLoss; } set { skillLoss = value; this.SkillLossChanged?.Invoke(value); } } private static Localization english => _english ?? (_english = LocalizationCache.ForLanguage("English")); private static BaseUnityPlugin plugin { get { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Expected O, but got Unknown object obj = _plugin; if (obj == null) { BaseUnityPlugin val = (BaseUnityPlugin)Chainloader.ManagerObject.GetComponent((Type)Assembly.GetExecutingAssembly().DefinedTypes.First((TypeInfo t) => t.IsClass && typeof(BaseUnityPlugin).IsAssignableFrom(t))); _plugin = val; obj = (object)val; } return (BaseUnityPlugin)obj; } } private static object? configSync { get { if (_configSync == null && hasConfigSync) { Type type = Assembly.GetExecutingAssembly().GetType("ServerSync.ConfigSync"); if ((object)type != null) { _configSync = Activator.CreateInstance(type, plugin.Info.Metadata.GUID + " SkillManager"); type.GetField("CurrentVersion").SetValue(_configSync, plugin.Info.Metadata.Version.ToString()); type.GetProperty("IsLocked").SetValue(_configSync, true); } else { hasConfigSync = false; } } return _configSync; } } public event Action<float>? SkillGainFactorChanged; public event Action<float>? SkillEffectFactorChanged; public event Action<float>? SkillLossChanged; public Skill(string englishName, string icon) : this(englishName, loadSprite(icon, 64, 64)) { } public unsafe Skill(string englishName, Sprite icon) { //IL_0019: 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_003a: 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_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Expected O, but got Unknown SkillType val = fromName(englishName); string text = new Regex("[^a-zA-Z]").Replace(englishName, "_"); skills[val] = this; skillByName[englishName] = this; skillDef = new SkillDef { m_description = "$skilldesc_" + text, m_icon = icon, m_increseStep = 1f, m_skill = val }; internalSkillName = text; skillName = englishName; Name = new LocalizeKey("skill_" + ((object)(*(SkillType*)(&val))/*cast due to .constrained prefix*/).ToString()).English(englishName); Description = new LocalizeKey("skilldesc_" + text); } public static SkillType fromName(string englishName) { return (SkillType)Math.Abs(StringExtensionMethods.GetStableHashCode(englishName)); } static Skill() { //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: 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_0095: Expected O, but got Unknown //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d1: Expected O, but got Unknown //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0149: Expected O, but got Unknown //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Expected O, but got Unknown //IL_01db: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_020a: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Expected O, but got Unknown //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_026c: Expected O, but got Unknown //IL_026c: Expected O, but got Unknown skills = new Dictionary<SkillType, Skill>(); skillByName = new Dictionary<string, Skill>(); InitializedTerminal = false; LoadImageMethod = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }, (Type[])null); hasConfigSync = true; Harmony val = new Harmony("org.bepinex.helpers.skillmanager"); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(FejdStartup), "Awake", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_FejdStartup", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "GetSkillDef", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_GetSkillDef", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatRaiseSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatRaiseskill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "CheatResetSkill", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_CheatResetSkill", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "LoadCSV", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizeKey), "AddLocalizedKeys", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Terminal), "InitTerminal", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal_Prefix", (Type[])null, (Type[])null)), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Terminal_InitTerminal", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Localization), "SetupLanguage", (Type[])null, (Type[])null), (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(LocalizationCache), "LocalizationPostfix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); val.Patch((MethodBase)AccessTools.DeclaredMethod(typeof(Skills), "OnDeath", (Type[])null, (Type[])null), new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Prefix", (Type[])null, (Type[])null)), (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(AccessTools.DeclaredMethod(typeof(Skill), "Patch_Skills_OnDeath_Finalizer", (Type[])null, (Type[])null)), (HarmonyMethod)null); } private static void Patch_FejdStartup() { //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013e: Expected O, but got Unknown //IL_01a5: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Expected O, but got Unknown foreach (Skill skill in skills.Values) { if (skill.Configurable) { string key = skill.Name.Key; string text = new Regex("['[\"\\]]").Replace(english.Localize(key), "").Trim(); string category = Localization.instance.Localize(key).Trim(); ConfigEntry<float> skillGain = config(text, "Skill gain factor", skill.SkillGainFactor, new ConfigDescription("The rate at which you gain experience for the skill.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.SkillGainFactor = skillGain.Value; skillGain.SettingChanged += delegate { skill.SkillGainFactor = skillGain.Value; }; ConfigEntry<float> skillEffect = config(text, "Skill effect factor", skill.SkillEffectFactor, new ConfigDescription("The power of the skill, based on the default power.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.01f, 5f), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.SkillEffectFactor = skillEffect.Value; skillEffect.SettingChanged += delegate { skill.SkillEffectFactor = skillEffect.Value; }; ConfigEntry<int> skillLoss = config(text, "Skill loss", skill.skillLoss, new ConfigDescription("How much experience to lose on death.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), new object[1] { new ConfigurationManagerAttributes { Category = category } })); skill.skillLoss = skillLoss.Value; skillLoss.SettingChanged += delegate { skill.skillLoss = skillLoss.Value; }; } } } private static void Patch_Skills_GetSkillDef(ref SkillDef? __result, List<SkillDef> ___m_skills, SkillType type) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (__result == null) { SkillDef val = GetSkillDef(type); if (val != null) { ___m_skills.Add(val); __result = val; } } } private unsafe static bool Patch_Skills_CheatRaiseskill(Skills __instance, string name, float value, Player ___m_player) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) foreach (SkillType key in skills.Keys) { Skill skill = skills[key]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { Skill skill2 = __instance.GetSkill(key); skill2.m_level += value; skill2.m_level = Mathf.Clamp(skill2.m_level, 0f, 100f); ((Character)___m_player).Message((MessageType)1, "Skill increased " + Localization.instance.Localize("$skill_" + ((object)(*(SkillType*)(&key))/*cast due to .constrained prefix*/).ToString()) + ": " + (int)skill2.m_level, 0, skill2.m_info.m_icon, false); Console.instance.Print("Skill " + skill.internalSkillName + " = " + skill2.m_level); return false; } } return true; } private static bool Patch_Skills_CheatResetSkill(Skills __instance, string name) { //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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) foreach (SkillType key in skills.Keys) { Skill skill = skills[key]; if (string.Equals(skill.internalSkillName, name, StringComparison.CurrentCultureIgnoreCase)) { __instance.ResetSkill(key); Console.instance.Print("Skill " + skill.internalSkillName + " reset"); return false; } } return true; } private static void Patch_Skills_OnDeath_Prefix(Skills __instance, ref Dictionary<SkillType, Skill>? __state) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0091: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { __state = new Dictionary<SkillType, Skill>(); } foreach (KeyValuePair<SkillType, Skill> skill in skills) { if (__instance.m_skillData.TryGetValue(skill.Key, out var value)) { __state[skill.Key] = value; if (skill.Value.skillLoss > 0) { Skill obj = value; obj.m_level -= value.m_level * (float)skill.Value.SkillLoss / 100f; value.m_accumulator = 0f; } __instance.m_skillData.Remove(skill.Key); } } } private static void Patch_Skills_OnDeath_Finalizer(Skills __instance, ref Dictionary<SkillType, Skill>? __state) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) if (__state == null) { return; } foreach (KeyValuePair<SkillType, Skill> item in __state) { __instance.m_skillData[item.Key] = item.Value; } __state = null; } private static void Patch_Terminal_InitTerminal_Prefix() { InitializedTerminal = Terminal.m_terminalInitialized; } private static void Patch_Terminal_InitTerminal() { if (!InitializedTerminal) { AddSkill(Terminal.commands["raiseskill"]); AddSkill(Terminal.commands["resetskill"]); } static void AddSkill(ConsoleCommand command) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown ConsoleOptionsFetcher fetcher = command.m_tabOptionsFetcher; command.m_tabOptionsFetcher = (ConsoleOptionsFetcher)delegate { List<string> list = fetcher.Invoke(); list.AddRange(skills.Values.Select((Skill skill) => skill.internalSkillName)); return list; }; } } private static SkillDef? GetSkillDef(SkillType skillType) { //IL_0005: 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) if (!skills.ContainsKey(skillType)) { return null; } return skills[skillType].skillDef; } private static byte[] ReadEmbeddedFileBytes(string name) { using MemoryStream memoryStream = new MemoryStream(); Assembly.GetExecutingAssembly().GetManifestResourceStream(Assembly.GetExecutingAssembly().GetName().Name + "." + name).CopyTo(memoryStream); return memoryStream.ToArray(); } private static Texture2D loadTexture(string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Expected O, but got Unknown Texture2D val = new Texture2D(0, 0); if (LoadImageMethod == null) { Debug.LogError((object)"UnityEngine.ImageConversion.LoadImage was not found. Skill icons will not load."); return val; } LoadImageMethod.Invoke(null, new object[2] { val, ReadEmbeddedFileBytes("icons." + name) }); return val; } private static Sprite loadSprite(string name, int width, int height) { //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) return Sprite.Create(loadTexture(name), new Rect(0f, 0f, (float)width, (float)height), Vector2.zero); } private static ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description) { ConfigEntry<T> val = plugin.Config.Bind<T>(group, name, value, description); configSync?.GetType().GetMethod("AddConfigEntry").MakeGenericMethod(typeof(T)) .Invoke(configSync, new object[1] { val }); return val; } private static ConfigEntry<T> config<T>(string group, string name, T value, string description) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>())); } } [PublicAPI] public static class SkillExtensions { public static float GetSkillFactor(this Character character, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return character.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static float GetSkillFactor(this Skills skills, string name) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return skills.GetSkillFactor(Skill.fromName(name)) * Skill.skillByName[name].SkillEffectFactor; } public static void RaiseSkill(this Character character, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) character.RaiseSkill(Skill.fromName(name), value); } public static void RaiseSkill(this Skills skill, string name, float value = 1f) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) skill.RaiseSkill(Skill.fromName(name), value); } public static void LowerSkill(this Character character, string name, float factor = 1f) { character.GetSkills().LowerSkill(name, factor); } public static void LowerSkill(this Skills skills, string name, float factor) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) if (factor > 0f && skills.m_skillData.TryGetValue(Skill.fromName(name), out var value)) { Skill obj = value; obj.m_level -= value.m_level * factor; value.m_accumulator = 0f; } } } } namespace OttoAura { [HarmonyPatch] internal static class CraftingStationPatches { internal static CraftingStation? Workbench; [HarmonyPostfix] [HarmonyPatch(typeof(ZNetScene), "Awake")] private static void ZNetSceneAwakePostfix(ZNetScene __instance) { GameObject prefab = __instance.GetPrefab("piece_workbench"); Workbench = (((Object)(object)prefab == (Object)null) ? null : prefab.GetComponent<CraftingStation>()); } [HarmonyPostfix] [HarmonyPatch(typeof(InventoryGui), "UpdateRepair")] private static void InventoryGuiUpdateRepairPostfix(InventoryGui __instance) { Player localPlayer = Player.m_localPlayer; if (OttoAuraPlugin.PreventCraftingStationRepair.Value != OttoAuraPlugin.Toggle.Off && !((Object)(object)localPlayer == (Object)null) && !((Object)(object)localPlayer.GetCurrentCraftingStation() == (Object)null) && !localPlayer.NoCostCheat()) { ((Component)__instance.m_repairPanel).gameObject.SetActive(false); ((Component)__instance.m_repairPanelSelection).gameObject.SetActive(false); ((Component)__instance.m_repairButton).gameObject.SetActive(false); } } } internal static class DurabilityHold { internal enum State { None, Holding, Expired } internal const string DeadlineKey = "RepairStation"; internal const string UseDurabilityKey = "RepairStationUseDurability"; internal static int MinutesFor(float skillFactor) { if (!(skillFactor >= 0.5f)) { return 0; } return (int)(10f * skillFactor); } internal static void Start(ItemData item, float skillFactor, DateTime now) { item.m_customData["RepairStation"] = now.AddMinutes(MinutesFor(skillFactor)).ToString(CultureInfo.InvariantCulture); item.m_customData["RepairStationUseDurability"] = item.m_shared.m_useDurability.ToString(); } internal static State Refresh(ItemData? item, DateTime now) { if (item?.m_shared == null || !item.m_customData.TryGetValue("RepairStation", out var value) || !TryReadDeadline(value, out var deadline)) { return State.None; } if (now <= deadline) { item.m_shared.m_useDurability = false; return State.Holding; } item.m_customData.Remove("RepairStation"); if (item.m_customData.TryGetValue("RepairStationUseDurability", out var value2) && bool.TryParse(value2, out var result)) { item.m_shared.m_useDurability = result; } item.m_customData.Remove("RepairStationUseDurability"); return State.Expired; } internal static bool TryReadDeadline(string? value, out DateTime deadline) { if (!DateTime.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.None, out deadline)) { return DateTime.TryParse(value, out deadline); } return true; } } [HarmonyPatch] internal static class BlacksmithingPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Humanoid), "GetRightItem")] private static void HumanoidGetRightItemPostfix(Humanoid __instance) { if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Refresh(__instance.m_rightItem, "GetRightItem"); } } [HarmonyPostfix] [HarmonyPatch(typeof(Humanoid), "GetLeftItem")] private static void HumanoidGetLeftItemPostfix(Humanoid __instance) { if ((Object)(object)Player.m_localPlayer != (Object)null && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Refresh(__instance.m_leftItem, "GetLeftItem"); } } [HarmonyPrefix] [HarmonyPatch(typeof(Humanoid), "IsItemEquiped")] private static void HumanoidIsItemEquipedPrefix(Humanoid __instance, ItemData item) { if (((Character)__instance).IsPlayer() && (Object)(object)__instance == (Object)(object)Player.m_localPlayer) { Refresh(item, "IsItemEquiped"); } } private static void Refresh(ItemData? item, string caller) { if (DurabilityHold.Refresh(item, DateTime.Now) == DurabilityHold.State.Expired) { OttoAuraPlugin.OttoAuraLogger.LogDebug((object)("(" + caller + ") The durability hold on " + item.m_shared.m_name + " ran out.")); } } } internal static class OttoPayBridge { private static bool _bound; private static MethodInfo? _isAuraPayEnabled; private static MethodInfo? _tryWithdraw; private static MethodInfo? _registerAuraService; private static MethodInfo? _unregisterAuraService; private static MethodInfo? _tryDeposit; private static MethodInfo? _registerDepositHandler; private static MethodInfo? _unregisterDepositHandler; internal static bool CanDeposit { get { Bind(); if (_tryDeposit != null) { return _registerDepositHandler != null; } return false; } } internal static bool IsAuraPayEnabled() { Bind(); if (_isAuraPayEnabled != null) { return (bool)_isAuraPayEnabled.Invoke(null, null); } return false; } internal static bool TryWithdraw(int amount) { Bind(); if (_tryWithdraw != null) { return (bool)_tryWithdraw.Invoke(null, new object[1] { amount }); } return false; } internal static void RegisterDepositHandler(string name, Func<Inventory, ItemData, int, bool> canDeposit, Func<Inventory, ItemData, int, bool> deposit, Func<Inventory, ItemData, int, string> describe) { Bind(); if (CanDeposit) { _registerDepositHandler.Invoke(null, new object[4] { name, canDeposit, deposit, describe }); } } internal static void UnregisterDepositHandler(string name) { Bind(); _unregisterDepositHandler?.Invoke(null, new object[1] { name }); } internal static bool TryDeposit(int amount) { Bind(); if (_tryDeposit != null) { return (bool)_tryDeposit.Invoke(null, new object[1] { amount }); } return false; } internal static void RegisterAuraService(string name, Func<string> describe) { Bind(); _registerAuraService?.Invoke(null, new object[2] { name, describe }); } internal static void UnregisterAuraService(string name) { Bind(); _unregisterAuraService?.Invoke(null, new object[1] { name }); } private static void Bind() { if (!_bound) { _bound = true; Type type = AccessTools.TypeByName("OttoPay.OttoPayApi"); _isAuraPayEnabled = ((type == null) ? null : AccessTools.Method(type, "IsAuraPayEnabled", (Type[])null, (Type[])null)); _tryWithdraw = ((type == null) ? null : AccessTools.Method(type, "TryWithdraw", (Type[])null, (Type[])null)); if (_isAuraPayEnabled == null || _tryWithdraw == null) { _isAuraPayEnabled = null; _tryWithdraw = null; OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's AuraPay API was not found. Paid aura repairs and AuraBoost are off."); } _registerAuraService = ((type == null) ? null : AccessTools.Method(type, "RegisterAuraService", (Type[])null, (Type[])null)); _unregisterAuraService = ((type == null) ? null : AccessTools.Method(type, "UnregisterAuraService", (Type[])null, (Type[])null)); if (_registerAuraService == null || _unregisterAuraService == null) { _registerAuraService = null; _unregisterAuraService = null; OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's RegisterAuraService API was not found. The AuraPay tooltip will not list OttoAura's services."); } _tryDeposit = ((type == null) ? null : AccessTools.Method(type, "TryDeposit", new Type[1] { typeof(int) }, (Type[])null)); _registerDepositHandler = ((type == null) ? null : AccessTools.Method(type, "RegisterDepositHandler", (Type[])null, (Type[])null)); _unregisterDepositHandler = ((type == null) ? null : AccessTools.Method(type, "UnregisterDepositHandler", (Type[])null, (Type[])null)); if (_tryDeposit == null || _registerDepositHandler == null || _unregisterDepositHandler == null) { _tryDeposit = null; _registerDepositHandler = null; _unregisterDepositHandler = null; OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"OttoPay's deposit API was not found. AuraTrade stays off until OttoPay 1.6.0 is installed."); } } } } [BepInPlugin("potto007.OttoAura", "OttoAura", "1.5.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency("potto007.OttoPay", "1.5.0")] public class OttoAuraPlugin : BaseUnityPlugin { public enum Toggle { On = 1, Off = 0 } private class ConfigurationManagerAttributes { [UsedImplicitly] public int? Order; [UsedImplicitly] public bool? Browsable; [UsedImplicitly] public string? Category; [UsedImplicitly] public Action<ConfigEntryBase>? CustomDrawer; } internal const string ModName = "OttoAura"; internal const string ModVersion = "1.5.3"; internal const string Author = "potto007"; private const string ModGUID = "potto007.OttoAura"; private static string ConfigFileName = "potto007.OttoAura.cfg"; private static string ConfigFileFullPath; private readonly Harmony _harmony = new Harmony("potto007.OttoAura"); public static readonly ManualLogSource OttoAuraLogger; private static readonly ConfigSync ConfigSync; internal static OttoAuraPlugin context; internal static bool BlacksmithingInstalled; private static ConfigEntry<Toggle> _serverConfigLocked; internal static ConfigEntry<Toggle> PreventCraftingStationRepair; internal static ConfigEntry<float> HealPerSecond; internal static ConfigEntry<float> RepairPercentPerTick; internal static ConfigEntry<int> CoinsPerItemTick; internal static ConfigEntry<float> TickSeconds; internal static ConfigEntry<Toggle> ShowHealText; internal static ConfigEntry<Toggle> AuraBoostEnabled; internal static ConfigEntry<float> AuraBoostStaminaTrail; internal static ConfigEntry<float> AuraBoostStaminaRoad; internal static ConfigEntry<Toggle> AuraBoostShowStatusIcon; internal static Sprite? AuraBoostSprite; internal static ConfigEntry<Toggle> AuraMoveEnabled; internal static ConfigEntry<int> AuraMoveCoins; internal static ConfigEntry<float> AuraMoveMaxDistance; internal static ConfigEntry<Toggle> AuraMoveSupportImmovable; internal static ConfigEntry<string> AuraMoveAllowedPrefabs; internal static ConfigEntry<string> AuraMoveDeniedPrefabs; internal static ConfigEntry<float> AuraMoveShimmerSeconds; internal static ConfigEntry<string> AuraMoveGrabEffects; internal static ConfigEntry<string> AuraMoveDepartEffects; internal static ConfigEntry<string> AuraMoveTravelEffect; internal static ConfigEntry<string> AuraMoveArriveEffects; internal static ConfigEntry<string> AuraMoveFinishEffects; internal static ConfigEntry<KeyboardShortcut> AuraMoveKey; internal static ConfigEntry<Toggle> AuraTradeEnabled; internal static ConfigEntry<int> AuraTradeFlatFee; internal static ConfigEntry<float> AuraTradePercentFee; internal static ConfigEntry<string> AuraTradeDeniedItems; internal static ConfigEntry<float> AuraTradeShimmerSeconds; internal static ConfigEntry<string> AuraTradeDepartEffects; internal static ConfigEntry<string> AuraTradeTravelEffect; internal static ConfigEntry<string> AuraTradeArriveEffects; internal static ConfigEntry<Toggle> AuraDispelEnabled; internal static ConfigEntry<float> AuraDispelRadiusScale; public void Awake() { //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Expected O, but got Unknown //IL_010e: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_019b: Unknown result type (might be due to invalid IL or missing references) //IL_01a6: Expected O, but got Unknown //IL_01d4: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Expected O, but got Unknown //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0257: Expected O, but got Unknown //IL_0285: Unknown result type (might be due to invalid IL or missing references) //IL_0290: Expected O, but got Unknown //IL_031a: Unknown result type (might be due to invalid IL or missing references) //IL_0325: Expected O, but got Unknown //IL_03e5: Unknown result type (might be due to invalid IL or missing references) //IL_0437: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Expected O, but got Unknown //IL_0470: Unknown result type (might be due to invalid IL or missing references) //IL_047b: Expected O, but got Unknown //IL_04c9: Unknown result type (might be due to invalid IL or missing references) //IL_04d4: Expected O, but got Unknown //IL_057e: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Expected O, but got Unknown context = this; ConfigNameMigration.Apply(((BaseUnityPlugin)this).Config, OttoAuraLogger); _serverConfigLocked = config("General", "LockConfiguration", Toggle.On, "If on, the configuration is locked and can be changed by server admins only."); ConfigSync.AddLockingConfigEntry<Toggle>(_serverConfigLocked); HealPerSecond = config("Aura", "HealPerSecond", 1f, new ConfigDescription("Health restored each second to a permitted player inside an active ward. 0 turns healing off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); RepairPercentPerTick = config("Aura", "RepairPercentPerTick", 5f, new ConfigDescription("Percent of an item's maximum durability restored each tick, for worn gear carried by a permitted player inside an active ward. 0 turns repair off.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 100f), Array.Empty<object>())); CoinsPerItemTick = config("Aura", "CoinsPerItemTick", 1, new ConfigDescription("Coins charged to the OttoPay Merchant Bank balance for each item repaired in a tick. The player must turn AuraPay on in OttoPay. 0 makes repair free.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>())); TickSeconds = config("Aura", "TickSeconds", 1f, new ConfigDescription("Seconds between aura ticks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 30f), Array.Empty<object>())); ShowHealText = config("Aura", "ShowHealText", Toggle.Off, "If on, each heal tick shows a floating heal number.", synchronizedSetting: false); PreventCraftingStationRepair = config("CraftingStations", "PreventCraftingStationRepair", Toggle.Off, "If on, players cannot repair items at crafting stations and must use a ward aura."); AuraBoostEnabled = config("AuraBoost", "Enabled", Toggle.On, "If on, Merchant Bank members with AuraPay on in OttoPay drain less stamina while running on roads and trails."); AuraBoostStaminaTrail = config("AuraBoost", "StaminaUsageTrail", 0.5f, new ConfigDescription("Run stamina drain on dirt paths, wood and metal, as a fraction of vanilla. 1 is vanilla, 0 is no drain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); AuraBoostStaminaRoad = config("AuraBoost", "StaminaUsageRoad", 0f, new ConfigDescription("Run stamina drain on paved roads and stone, as a fraction of vanilla. 1 is vanilla, 0 is no drain.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); AuraBoostShowStatusIcon = config("AuraBoost", "ShowStatusIcon", Toggle.On, "If on, the AuraBoost icon shows in the status bar while the effect is active."); AuraBoostSprite = LoadSprite("auraboost_icon.png"); AuraMoveEnabled = config("AuraMove", "Enabled", Toggle.On, "If on, the Merchant Guild will move placed objects for a fee while AuraPay is active."); AuraMoveCoins = config("AuraMove", "Coins", 5, new ConfigDescription("Coins charged to the Merchant Bank balance per completed move. 0 makes moving free, but AuraPay must still be on.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>())); AuraMoveMaxDistance = config("AuraMove", "MaxMoveDistance", 15f, new ConfigDescription("How far in metres the destination may sit from where the object stands now.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 64f), Array.Empty<object>())); AuraMoveSupportImmovable = config("AuraMove", "SupportIsImmovable", Toggle.On, "If on, non-furniture pieces that carry structural load cannot be moved."); AuraMoveAllowedPrefabs = config("AuraMove", "AllowedPrefabs", "wood_fine_stack,blackwood_stack,bone_stack,piece_beehive", "Comma-separated prefab names that skip every eligibility restriction and can always be moved."); AuraMoveDeniedPrefabs = config("AuraMove", "DeniedPrefabs", "fire_pit,bonfire,hearth,windmill", "Comma-separated prefab names that can never be moved."); AuraMoveShimmerSeconds = config("AuraMove", "ShimmerSeconds", 1.2f, new ConfigDescription("Total duration of the shrink and grow animation. 0 snaps and only plays the stage effects.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); AuraMoveGrabEffects = config("AuraMove", "GrabEffects", "fx_summon_start,sfx_staffspiritcaller_cast", "Comma-separated vanilla effect prefabs played for you alone when the Guild takes hold of an object."); AuraMoveDepartEffects = config("AuraMove", "DepartEffects", "vfx_Potion_eitr_minor,sfx_OpenPortal", "Comma-separated vanilla effect prefabs played at the old spot as the object leaves it."); AuraMoveTravelEffect = config("AuraMove", "TravelEffect", "vfx_pick_wisp", "One vanilla effect prefab flown along an arc from the old spot to the new one during the shimmer. Blank flies nothing."); AuraMoveArriveEffects = config("AuraMove", "ArriveEffects", "fx_summon_spirit_spawn,sfx_runestone_activate", "Comma-separated vanilla effect prefabs played at the new spot as the object grows back in, alongside the piece's own place effect."); AuraMoveFinishEffects = config("AuraMove", "FinishEffects", "sfx_dverger_heal_finish", "Comma-separated vanilla effect prefabs played at the new spot once the object is whole again."); AuraMoveKey = config<KeyboardShortcut>("AuraMove", "MoveKey", new KeyboardShortcut((KeyCode)109, (KeyCode[])(object)new KeyCode[1] { (KeyCode)308 }), "Keyboard shortcut that takes the hammer out and selects Guild Move, and puts it away again.", synchronizedSetting: false); AuraTradeEnabled = config("AuraTrade", "Enabled", Toggle.On, "If on, Merchant Bank members with AuraPay on can sell valuables to the Merchant Guild by dropping them on the Merchant Bank balance, or all at once at the ward, while inside a ward they may use. Needs OttoPay 1.6.0."); AuraTradeFlatFee = config("AuraTrade", "FlatFee", 5, new ConfigDescription("Coins the AuraPay network keeps from every trade, however large. Charged once per trade, so one big trade keeps more coins than several small ones.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 1000), Array.Empty<object>())); AuraTradePercentFee = config("AuraTrade", "PercentFee", 5f, new ConfigDescription("Percent of a trade's gross worth the AuraPay network keeps on top of FlatFee, rounded up to whole coins.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 50f), Array.Empty<object>())); AuraTradeDeniedItems = config("AuraTrade", "DeniedItems", "", "Comma-separated item prefab names the Merchant Guild will not buy, for example Ruby,AmberPearl. Coins are never bought."); AuraTradeShimmerSeconds = config("AuraTrade", "ShimmerSeconds", 1.2f, new ConfigDescription("How long a sold valuable takes to shrink away into the ward. 0 plays only the effects.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 3f), Array.Empty<object>())); AuraTradeDepartEffects = config("AuraTrade", "DepartEffects", "vfx_Potion_eitr_minor,sfx_OpenPortal", "Comma-separated vanilla effect prefabs played where the sold valuable appears in front of the seller. Every player nearby sees the sale."); AuraTradeTravelEffect = config("AuraTrade", "TravelEffect", "vfx_pick_wisp", "One vanilla effect prefab flown with the sold valuable into the ward. Blank flies nothing."); AuraTradeArriveEffects = config("AuraTrade", "ArriveEffects", "fx_summon_spirit_spawn,sfx_dverger_heal_finish", "Comma-separated vanilla effect prefabs played at the ward as the sold valuable reaches it."); AuraDispelEnabled = config("AuraDispel", "Enabled", Toggle.On, "If on, a lit Wisp Torch also clears the distance fog inside the radius where it clears the Mists. Free, and only changes what players see."); AuraDispelRadiusScale = config("AuraDispel", "RadiusScale", 1f, new ConfigDescription("Size of the fog-free bubble, as a multiple of the radius where the torch clears the Mists.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.25f, 3f), Array.Empty<object>())); BlacksmithingInstalled = Chainloader.PluginInfos.TryGetValue("org.bepinex.plugins.blacksmithing", out var value) && value != null; Assembly executingAssembly = Assembly.GetExecutingAssembly(); _harmony.PatchAll(executingAssembly); SetupWatcher(); OttoPayBridge.RegisterAuraService("AuraBoost", () => (AuraBoostEnabled.Value != Toggle.Off) ? "AuraBoost lightens your feet on roads and trails." : ""); OttoPayBridge.RegisterAuraService("AuraMove", delegate { if (AuraMoveEnabled.Value == Toggle.Off) { return ""; } int value2 = AuraMoveCoins.Value; string text = ((value2 > 0) ? $"for {value2} coins" : "for free"); return "AuraMove: open the hammer's Merchant Guild tab or press " + MoveTargeting.KeyLabel + ", then click a chest or piece of furniture to have the Merchant Guild move it a short way " + text + "."; }); OttoPayBridge.RegisterAuraService("AuraTrade", () => (AuraTradeEnabled.Value == Toggle.Off || !OttoPayBridge.CanDeposit) ? "" : string.Format("AuraTrade: inside a ward you may use, drop a valuable on your Merchant Bank balance to sell it, or press {0} on the ward to sell every valuable you carry. AuraPay keeps {1} coins plus {2:0.##}% of each sale, so fewer, larger sales keep more.", Localization.instance.Localize("$KEY_AltPlace + $KEY_Use"), AuraTradeFlatFee.Value, AuraTradePercentFee.Value)); OttoPayBridge.RegisterAuraService("AuraDispel", () => (AuraDispelEnabled.Value != Toggle.Off) ? "AuraDispel: a lit Wisp Torch dispels the fog around it, not just the Mists." : ""); AuraTradeController.Register(); } public void Start() { AuraBoostEffect.Init(); AuraMoveController.Init(); FogBubbles.Init(); } private void Update() { WardAura.Update(Time.deltaTime); AuraBoostEffect.Tick(); AuraMoveController.Tick(); } private static Sprite? LoadSprite(string name) { //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Expected O, but got Unknown //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) MethodInfo methodInfo = AccessTools.Method("UnityEngine.ImageConversion:LoadImage", new Type[2] { typeof(Texture2D), typeof(byte[]) }, (Type[])null); Assembly executingAssembly = Assembly.GetExecutingAssembly(); using Stream stream = executingAssembly.GetManifestResourceStream(executingAssembly.GetName().Name + ".assets." + name); if (methodInfo == null || stream == null) { OttoAuraLogger.LogError((object)("Could not load the " + name + " icon.")); return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); Texture2D val = new Texture2D(0, 0); methodInfo.Invoke(null, new object[2] { val, memoryStream.ToArray() }); return Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), Vector2.zero); } internal static void AutoDoc() { } private void OnDestroy() { OttoPayBridge.UnregisterAuraService("AuraBoost"); OttoPayBridge.UnregisterAuraService("AuraMove"); OttoPayBridge.UnregisterAuraService("AuraTrade"); OttoPayBridge.UnregisterAuraService("AuraDispel"); AuraTradeController.Unregister(); AuraMoveController.Shutdown(); AuraBoostEffect.Shutdown(); FogBubbles.Shutdown(); ((BaseUnityPlugin)this).Config.Save(); } private void SetupWatcher() { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(Paths.ConfigPath, ConfigFileName); fileSystemWatcher.Changed += ReadConfigValues; fileSystemWatcher.Created += ReadConfigValues; fileSystemWatcher.Renamed += ReadConfigValues; fileSystemWatcher.IncludeSubdirectories = true; fileSystemWatcher.SynchronizingObject = ThreadingHelper.SynchronizingObject; fileSystemWatcher.EnableRaisingEvents = true; } private void ReadConfigValues(object sender, FileSystemEventArgs e) { if (!File.Exists(ConfigFileFullPath)) { return; } try { OttoAuraLogger.LogDebug((object)"ReadConfigValues called"); ((BaseUnityPlugin)this).Config.Reload(); } catch { OttoAuraLogger.LogError((object)("There was an issue loading your " + ConfigFileName)); OttoAuraLogger.LogError((object)"Please check your config entries for spelling and format!"); } } private ConfigEntry<T> config<T>(string group, string name, T value, ConfigDescription description, bool synchronizedSetting = true) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected O, but got Unknown ConfigDescription val = new ConfigDescription(description.Description + (synchronizedSetting ? " [Synced with Server]" : " [Not Synced with Server]"), description.AcceptableValues, description.Tags); ConfigEntry<T> val2 = ((BaseUnityPlugin)this).Config.Bind<T>(ConfigName.Section(group), ConfigName.Key(name), value, val); ConfigSync.AddConfigEntry<T>(val2).SynchronizedConfig = synchronizedSetting; return val2; } private ConfigEntry<T> config<T>(string group, string name, T value, string description, bool synchronizedSetting = true) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Expected O, but got Unknown return config(group, name, value, new ConfigDescription(description, (AcceptableValueBase)null, Array.Empty<object>()), synchronizedSetting); } static OttoAuraPlugin() { string configPath = Paths.ConfigPath; char directorySeparatorChar = Path.DirectorySeparatorChar; ConfigFileFullPath = configPath + directorySeparatorChar + ConfigFileName; OttoAuraLogger = Logger.CreateLogSource("OttoAura"); ConfigSync = new ConfigSync("potto007.OttoAura") { DisplayName = "OttoAura", CurrentVersion = "1.5.3", MinimumRequiredVersion = "1.5.3", ModRequired = false }; context = null; _serverConfigLocked = null; PreventCraftingStationRepair = null; HealPerSecond = null; RepairPercentPerTick = null; CoinsPerItemTick = null; TickSeconds = null; ShowHealText = null; AuraBoostEnabled = null; AuraBoostStaminaTrail = null; AuraBoostStaminaRoad = null; AuraBoostShowStatusIcon = null; AuraMoveEnabled = null; AuraMoveCoins = null; AuraMoveMaxDistance = null; AuraMoveSupportImmovable = null; AuraMoveAllowedPrefabs = null; AuraMoveDeniedPrefabs = null; AuraMoveShimmerSeconds = null; AuraMoveGrabEffects = null; AuraMoveDepartEffects = null; AuraMoveTravelEffect = null; AuraMoveArriveEffects = null; AuraMoveFinishEffects = null; AuraMoveKey = null; AuraTradeEnabled = null; AuraTradeFlatFee = null; AuraTradePercentFee = null; AuraTradeDeniedItems = null; AuraTradeShimmerSeconds = null; AuraTradeDepartEffects = null; AuraTradeTravelEffect = null; AuraTradeArriveEffects = null; AuraDispelEnabled = null; AuraDispelRadiusScale = null; } } internal static class WardAura { private const float EmptyBalanceMessageSeconds = 30f; private static readonly List<ItemData> _wornItems = new List<ItemData>(); private static readonly List<ItemData> _repairedItems = new List<ItemData>(); private static float _elapsed; private static float _lastEmptyBalanceMessage = -1000f; internal static bool IsPaidRepair => OttoAuraPlugin.CoinsPerItemTick.Value > 0; internal static void Update(float deltaTime) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || ((Character)localPlayer).IsDead()) { _elapsed = 0f; return; } _elapsed += deltaTime; if (!(_elapsed < OttoAuraPlugin.TickSeconds.Value)) { float elapsed = _elapsed; _elapsed = 0f; if (!((Object)(object)FindAuraWard(localPlayer) == (Object)null)) { Heal(localPlayer, elapsed); Repair(localPlayer); } } } internal static PrivateArea? FindAuraWard(Player player) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_002b: 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) Vector3 position = ((Component)player).transform.position; foreach (PrivateArea allArea in PrivateArea.m_allAreas) { if (!((Object)(object)allArea == (Object)null) && (int)allArea.m_ownerFaction == 0 && allArea.IsEnabled() && allArea.IsInside(position, 0f) && allArea.HaveLocalAccess()) { return allArea; } } return null; } internal static void CollectRepairable(Inventory inventory, List<ItemData> worn) { worn.Clear(); inventory.GetWornItems(worn); worn.RemoveAll((ItemData item) => !item.m_shared.m_canBeReparied); } internal static void RepairStep(List<ItemData> worn, float percent, List<ItemData> repaired) { repaired.Clear(); foreach (ItemData item in worn) { float maxDurability = item.GetMaxDurability(); item.m_durability = Mathf.Min(maxDurability, item.m_durability + maxDurability * percent / 100f); if (item.m_durability >= maxDurability) { repaired.Add(item); } } } internal static string HoverLine(PrivateArea area) { return HoverLine(OttoAuraPlugin.RepairPercentPerTick.Value, OttoAuraPlugin.HealPerSecond.Value, OttoAuraPlugin.CoinsPerItemTick.Value, area.m_radius); } internal static string HoverLine(float repairPercent, float healPerSecond, int coinsPerItem, float radius) { bool flag = repairPercent > 0f; bool flag2 = healPerSecond > 0f; string arg = ((flag && flag2) ? "heals you and repairs your gear" : (flag ? "repairs your gear" : (flag2 ? "heals you" : "is idle"))); string arg2 = ((flag && coinsPerItem > 0) ? ", paid through AuraPay" : ""); return $"\n<color=#8FD7FF>Aura {arg} within {radius:0} m{arg2}</color>"; } private static void Heal(Player player, float elapsed) { float num = OttoAuraPlugin.HealPerSecond.Value * elapsed; if (!(num <= 0f) && !(((Character)player).GetHealth() >= ((Character)player).GetMaxHealth())) { ((Character)player).Heal(num, OttoAuraPlugin.ShowHealText.Value == OttoAuraPlugin.Toggle.On); } } private static void Repair(Player player) { float value = OttoAuraPlugin.RepairPercentPerTick.Value; if (value <= 0f) { return; } CollectRepairable(((Humanoid)player).GetInventory(), _wornItems); if (_wornItems.Count == 0 || (IsPaidRepair && !TryPay(player, OttoAuraPlugin.CoinsPerItemTick.Value * _wornItems.Count))) { return; } RepairStep(_wornItems, value, _repairedItems); foreach (ItemData repairedItem in _repairedItems) { OnFullyRepaired(player, repairedItem); } } private static void OnFullyRepaired(Player player, ItemData item) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_006a: 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_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) if (OttoAuraPlugin.BlacksmithingInstalled) { DurabilityHold.Start(item, ((Character)player).GetSkillFactor(Skill.fromName("Blacksmithing")), DateTime.Now); } ((Character)player).Message((MessageType)1, Localization.instance.Localize("$msg_repaired", new string[1] { item.m_shared.m_name }), 0, (Sprite)null, false); CraftingStation workbench = CraftingStationPatches.Workbench; if ((Object)(object)workbench != (Object)null) { workbench.m_repairItemDoneEffects.Create(((Component)player).transform.position, Quaternion.identity, (Transform)null, 1f, -1, default(ZDOID)); } } private static bool TryPay(Player player, int cost) { if (!OttoPayBridge.IsAuraPayEnabled()) { return false; } if (OttoPayBridge.TryWithdraw(cost)) { return true; } if (Time.time - _lastEmptyBalanceMessage > 30f) { ((Character)player).Message((MessageType)1, "Your Merchant Bank balance is empty. The aura cannot repair your gear.", 0, (Sprite)null, false); _lastEmptyBalanceMessage = Time.time; } return false; } } [HarmonyPatch] internal static class WardAuraPatches { [HarmonyPostfix] [HarmonyPatch(typeof(PrivateArea), "GetHoverText")] private static void PrivateAreaGetHoverTextPostfix(PrivateArea __instance, ref string __result) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(__result) && !((Object)(object)Player.m_localPlayer == (Object)null) && (int)__instance.m_ownerFaction == 0 && __instance.IsEnabled() && __instance.HaveLocalAccess()) { __result += WardAura.HoverLine(__instance); __result += AuraTradeController.HoverLine(__instance); } } } } namespace OttoAura.Config { public static class ConfigName { public const string DefaultSection = "General"; private static readonly Regex OrdinalPrefix = new Regex("^\\s*\\d+(?:\\.\\d+)*\\s*-\\s*(?=\\S)"); public static string Section(string name) { if (string.IsNullOrWhiteSpace(name)) { return "General"; } string text = Normalize(OrdinalPrefix.Replace(name, string.Empty, 1)); if (text.Length != 0) { return text; } return "General"; } public static string Key(string name) { return Normalize(name); } internal static string Normalize(string name) { if (string.IsNullOrEmpty(name)) { return name; } StringBuilder stringBuilder = new StringBuilder(name.Length); if (name[0] == '_') { stringBuilder.Append('_'); } bool flag = true; foreach (char c in name) { if (!char.IsLetterOrDigit(c)) { flag = true; continue; } stringBuilder.Append(flag ? char.ToUpperInvariant(c) : c); flag = false; } return stringBuilder.ToString(); } } public static class ConfigNameMigration { public static void Apply(ConfigFile file, ManualLogSource? logger) { try { string configFilePath = file.ConfigFilePath; if (string.IsNullOrEmpty(configFilePath) || !File.Exists(configFilePath)) { return; } string[] array = File.ReadAllLines(configFilePath); HashSet<string> present = CollectNormalizedNames(array); HashSet<string> seen = new HashSet<string>(); List<string> list = new List<string>(); string section = string.Empty; bool flag = false; for (int i = 0; i < array.Length; i++) { string text = SectionName(array[i]); if (text != null) { section = ConfigName.Section(text); } string text2 = DuplicateKey(array[i], section, present, seen); if (text2 != null) { if (logger != null) { logger.LogWarning((object)("Dropping the stale duplicate " + text2)); } flag = true; continue; } string text3 = RewriteLine(array[i]); list.Add(text3 ?? array[i]); if (text3 != null) { flag = true; } } array = list.ToArray(); if (!flag) { return; } StringBuilder stringBuilder = new StringBuilder(); string[] array2 = array; foreach (string value in array2) { stringBuilder.Append(value).Append(Environment.NewLine); } string text4 = configFilePath + ".premigration.bak"; File.Copy(configFilePath, text4, overwrite: true); File.WriteAllText(configFilePath, stringBuilder.ToString()); if (logger != null) { logger.LogInfo((object)("Migrated config names to PascalCase: " + configFilePath)); } try { file.Reload(); } catch (Exception arg) { File.Copy(text4, configFilePath, overwrite: true); if (logger != null) { logger.LogWarning((object)$"Config name migration rolled back: {arg}"); } } finally { TryDelete(text4, logger); } } catch (Exception arg2) { if (logger != null) { logger.LogWarning((object)$"Config name migration skipped: {arg2}"); } } } private static string? SectionName(string line) { string text = line.Trim(); if (text.Length >= 2 && text[0] == '[' && text[text.Length - 1] == ']') { return text.Substring(1, text.Length - 2); } return null; } private static string? KeyName(string line) { string text = line.Trim(); if (text.Length == 0 || text[0] == '#' || SectionName(line) != null) { return null; } int num = line.IndexOf('='); if (num < 0) { return null; } string text2 = line.Substring(0, num).Trim(); if (text2.Length != 0) { return text2; } return null; } private static HashSet<string> CollectNormalizedNames(string[] lines) { HashSet<string> hashSet = new HashSet<string>(); string text = string.Empty; foreach (string line in lines) { string text2 = SectionName(line); if (text2 != null) { text = ConfigName.Section(text2); continue; } string text3 = KeyName(line); if (text3 != null && ConfigName.Key(text3) == text3) { hashSet.Add(text + "/" + text3); } } return hashSet; } private static string? DuplicateKey(string line, string section, HashSet<string> present, HashSet<string> seen) { string text = KeyName(line); if (text == null) { return null; } string text2 = ConfigName.Key(text); if (text2.Length == 0) { return null; } string item = section + "/" + text2; if (text2 != text && present.Contains(item)) { return section + "/" + text; } if (!seen.Add(item)) { return section + "/" + text; } return null; } private static void TryDelete(string path, ManualLogSource? logger) { try { File.Delete(path); } catch (Exception ex) { if (logger != null) { logger.LogWarning((object)("Could not remove the migration backup " + path + ": " + ex.Message)); } } } private static string? RewriteLine(string line) { string text = line.Trim(); if (text.Length == 0 || text[0] == '#') { return null; } if (text.Length >= 2 && text[0] == '[' && text[text.Length - 1] == ']') { string text2 = text.Substring(1, text.Length - 2); string text3 = ConfigName.Section(text2); if (text3.Length == 0 || text3 == text2) { return null; } return Indent(line) + "[" + text3 + "]" + TrailingSpace(line); } int num = line.IndexOf('='); if (num < 0) { return null; } string text4 = line.Substring(0, num); string text5 = text4.Trim(); string text6 = ConfigName.Key(text5); if (text5.Length == 0 || text6.Length == 0 || text6 == text5) { return null; } return Indent(text4) + text6 + TrailingSpace(text4) + line.Substring(num); } private static string Indent(string line) { int i; for (i = 0; i < line.Length && char.IsWhiteSpace(line[i]); i++) { } return line.Substring(0, i); } private static string TrailingSpace(string line) { int num = line.Length; while (num > 0 && char.IsWhiteSpace(line[num - 1])) { num--; } return line.Substring(num); } } } namespace OttoAura.AuraTrade { internal static class AuraTradeController { internal const string HandlerName = "Sell to the Merchant Guild"; private static readonly List<TradeLot> _lots = new List<TradeLot>(); internal static void Register() { OttoPayBridge.RegisterDepositHandler("Sell to the Merchant Guild", CanSell, Sell, Describe); } internal static void Unregister() { OttoPayBridge.UnregisterDepositHandler("Sell to the Merchant Guild"); } internal static bool IsAvailable(Player? player) { if ((Object)(object)player != (Object)null && OttoAuraPlugin.AuraTradeEnabled.Value == OttoAuraPlugin.Toggle.On && OttoPayBridge.CanDeposit && OttoPayBridge.IsAuraPayEnabled()) { return (Object)(object)WardAura.FindAuraWard(player) != (Object)null; } return false; } internal static bool IsTradingPost(PrivateArea? area) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)area != (Object)null && (int)area.m_ownerFaction == 0 && area.IsEnabled()) { return area.HaveLocalAccess(); } return false; } private static bool CanSell(Inventory inventory, ItemData item, int amount) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer != (Object)null && amount > 0 && inventory == ((Humanoid)localPlayer).GetInventory() && TradeValuation.IsValuable(item)) { return IsAvailable(localPlayer); } return false; } private static string Describe(Inventory inventory, ItemData item, int amount) { TradeValuation.Quote quote = TradeValuation.QuoteFor(TradeValuation.Worth(item, amount)); string text = WhatFor(item, amount); if (!quote.Tradeable) { return RefusalFor(text, quote); } return "Click to sell " + text + ".\n\n" + $"Worth: {quote.Gross} coins\n" + $"AuraPay fee: {quote.Fee} coins\n" + $"To your balance: {quote.Net} coins\n\n" + $"The fee is {OttoAuraPlugin.AuraTradeFlatFee.Value} coins plus {OttoAuraPlugin.AuraTradePercentFee.Value:0.##}% of each sale, so fewer, larger sales keep more."; } private static bool Sell(Inventory inventory, ItemData item, int amount) { Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null || !CanSell(inventory, item, amount) || amount > item.m_stack || !inventory.ContainsItem(item)) { return false; } PrivateArea val = WardAura.FindAuraWard(localPlayer); if ((Object)(object)val == (Object)null) { return false; } _lots.Clear(); _lots.Add(new TradeLot(item, amount)); return Complete(localPlayer, val, WhatFor(item, amount)); } internal static bool SellAll(Player player, PrivateArea ward) { _lots.Clear(); int num = 0; foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if (TradeValuation.IsValuable(allItem)) { _lots.Add(new TradeLot(allItem, allItem.m_stack)); num += allItem.m_stack; } } if (num == 0) { Tell(player, "You carry nothing the Merchant Guild will buy."); return true; } Complete(player, ward, (num == 1) ? "1 valuable" : $"{num} valuables"); return true; } internal static string HoverLine(PrivateArea ward) { Player localPlayer = Player.m_localPlayer; if (!IsAvailable(localPlayer) || !IsTradingPost(ward)) { return ""; } long num = 0L; foreach (ItemData allItem in ((Humanoid)localPlayer).GetInventory().GetAllItems()) { if (TradeValuation.IsValuable(allItem)) { num += TradeValuation.Worth(allItem, allItem.m_stack); } } if (num == 0L) { return ""; } TradeValuation.Quote quote = TradeValuation.QuoteFor(num); string text = "[<color=yellow><b>$KEY_AltPlace + $KEY_Use</b></color>]"; string text2 = (quote.Tradeable ? $"\n{text} Sell all valuables: {quote.Gross} worth, {quote.Fee} fee, {quote.Net} to your balance" : $"\n{text} Sell all valuables: the {quote.Fee} coin fee would take all {quote.Gross} they are worth"); return Localization.instance.Localize(text2); } private static bool Complete(Player player, PrivateArea ward, string what) { SaleResult saleResult = TradeSale.Complete(((Humanoid)player).GetInventory(), _lots, TradeValuation.CurrentFees(), new PlayerTradeDesk(player)); TradeValuation.Quote quote = saleResult.Quote; switch (saleResult.Outcome) { case SaleOutcome.Sold: TradeEffects.Broadcast(player, ward, saleResult.MostValuable); Tell(player, $"The Merchant Guild bought {what} for {quote.Gross} coins. AuraPay kept {quote.Fee}, and {quote.Net} went to your balance."); return true; case SaleOutcome.Untradeable: Tell(player, RefusalFor(what, quote)); return false; case SaleOutcome.LostTrack: Tell(player, "The Merchant Guild lost track of your valuables. Nothing was sold."); return false; default: Tell(player, "The Merchant Bank refused the deposit. Your valuables are back in your pack."); return false; } } private static string WhatFor(ItemData item, int amount) { string text = Localization.instance.Localize(item.m_shared.m_name); if (amount <= 1) { return text; } return $"{amount} {text}"; } private static string RefusalFor(string what, TradeValuation.Quote quote) { return $"{what} is worth {quote.Gross} coins, and the AuraPay fee of {quote.Fee} would take all of it. Sell more at once."; } private static void Tell(Player player, string message) { ((Character)player).Message((MessageType)1, message, 0, (Sprite)null, false); } } internal sealed class PlayerTradeDesk : ITradeDesk { private readonly Player _player; internal PlayerTradeDesk(Player player) { _player = player; } public bool TryDeposit(int coins) { return OttoPayBridge.TryDeposit(coins); } public void Drop(ItemData item) { //IL_0014: 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_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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) Transform transform = ((Component)_player).transform; ItemDrop.DropItem(item, item.m_stack, transform.position + transform.forward + Vector3.up, transform.rotation); } } [HarmonyPatch] internal static class AuraTradePatches { [HarmonyPrefix] [HarmonyPatch(typeof(PrivateArea), "Interact")] private static bool PrivateAreaInteractPrefix(PrivateArea __instance, Humanoid human, bool hold, bool alt, ref bool __result) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (hold || !alt || (Object)(object)human != (Object)(object)Player.m_localPlayer || !AuraTradeController.IsAvailable(Player.m_localPlayer) || !AuraTradeController.IsTradingPost(__instance)) { return true; } __result = AuraTradeController.SellAll((Player)human, __instance); return false; } } internal static class TradeEffects { internal const string RpcName = "OttoAura_TradeEffect"; private const float ScaleEpsilon = 0.02f; private const float ArcHeight = 1.5f; private const float SpinDegreesPerSecond = 360f; private const float AudibleRange = 100f; internal static void Register() { if (!((Object)(object)ZNet.instance == (Object)null) && !ZNet.instance.IsDedicated() && ZRoutedRpc.instance != null && !ZRoutedRpc.instance.m_functions.ContainsKey(StringExtensionMethods.GetStableHashCode("OttoAura_TradeEffect"))) { ZRoutedRpc.instance.Register<Vector3, Vector3, string>("OttoAura_TradeEffect", (Action<long, Vector3, Vector3, string>)RPC_TradeEffect); } } internal static void Broadcast(Player seller, PrivateArea ward, ItemData item) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_009b: 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) Transform transform = ((Component)seller).transform; Vector3 val = transform.position + Vector3.up * 1.3f + transform.forward * 0.7f; Vector3 val2 = ((Component)ward).transform.position + Vector3.up * 1.5f; string text = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : ""); Play(val, val2, text); if (ZRoutedRpc.instance != null) { ZRoutedRpc.instance.InvokeRoutedRPC(0L, "OttoAura_TradeEffect", new object[3] { val, val2, text }); } } private static void RPC_TradeEffect(long sender, Vector3 from, Vector3 to, string prefab) { //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_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) if (ZRoutedRpc.instance != null && sender != ZRoutedRpc.instance.m_id && !((Object)(object)ZNetScene.instance == (Object)null)) { Player localPlayer = Player.m_localPlayer; if (!((Object)(object)localPlayer == (Object)null) && !(Vector3.Distance(((Component)localPlayer).transform.position, from) > 100f)) { Play(from, to, prefab); } } } private static void Play(Vector3 from, Vector3 to, string prefab) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) MoveEffects.Spawn(OttoAuraPlugin.AuraTradeDepartEffects.Value, from, Quaternion.identity, isGrab: false); float num = Mathf.Max(0f, OttoAuraPlugin.AuraTradeShimmerSeconds.Value); if (num <= 0f) { MoveEffects.Spawn(OttoAuraPlugin.AuraTradeArriveEffects.Value, to, Quaternion.identity, isGrab: false); return; } GameObject val = MoveEffects.SpawnOne(prefab, from, Quaternion.identity, isGrab: false); if ((Object)(object)val != (Object)null) { MakeInert(val); } GameObject wisp = MoveEffects.SpawnOne(MoveEffects.FirstName(OttoAuraPlugin.AuraTradeTravelEffect.Value), from, Quaternion.identity, isGrab: false); ((MonoBehaviour)OttoAuraPlugin.context).StartCoroutine(Carry(val, wisp, from, to, num)); } private static void MakeInert(GameObject visual) { Rigidbody[] componentsInChildren = visual.GetComponentsInChildren<Rigidbody>(); foreach (Rigidbody obj in componentsInChildren) { obj.isKinematic = true; obj.detectCollisions = false; } Collider[] componentsInChildren2 = visual.GetComponentsInChildren<Collider>(); for (int i = 0; i < componentsInChildren2.Length; i++) { componentsInChildren2[i].enabled = false; } MonoBehaviour[] componentsInChildren3 = visual.GetComponentsInChildren<MonoBehaviour>(); foreach (MonoBehaviour val in componentsInChildren3) { if (val is ItemDrop || val is Floating) { ((Behaviour)val).enabled = false; } } } private static IEnumerator Carry(GameObject? visual, GameObject? wisp, Vector3 from, Vector3 to, float seconds) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Unknown result type (might be due to invalid IL or missing references) Vector3 scale = (((Object)(object)visual != (Object)null) ? visual.transform.localScale : Vector3.one); float elapsed = 0f; while (elapsed < seconds) { elapsed += Time.deltaTime; float num = Mathf.Clamp01(elapsed / seconds); Vector3 position = Vector3.Lerp(from, to, num); position.y += 1.5f * Mathf.Sin(num * (float)Math.PI); if ((Object)(object)visual != (Object)null) { visual.transform.position = position; visual.transform.localScale = Vector3.Lerp(scale, scale * 0.02f, num); visual.transform.Rotate(0f, 360f * Time.deltaTime, 0f); } if ((Object)(object)wisp != (Object)null) { wisp.transform.position = position; } yield return null; } MoveEffects.DestroyTracked(visual); MoveEffects.DestroyTracked(wisp); MoveEffects.Spawn(OttoAuraPlugin.AuraTradeArriveEffects.Value, to, Quaternion.identity, isGrab: false); } } [HarmonyPatch] internal static class TradeEffectsPatches { [HarmonyPostfix] [HarmonyPatch(typeof(Game), "Start")] private static void GameStartPostfix() { TradeEffects.Register(); } } internal readonly struct TradeLot { internal readonly ItemData Item; internal readonly int Amount; internal TradeLot(ItemData item, int amount) { Item = item; Amount = amount; } } internal interface ITradeDesk { bool TryDeposit(int coins); void Drop(ItemData item); } internal enum SaleOutcome { Sold, Untradeable, LostTrack, DepositRefused } internal readonly struct SaleResult { internal readonly SaleOutcome Outcome; internal readonly TradeValuation.Quote Quote; internal readonly ItemData? MostValuable; internal SaleResult(SaleOutcome outcome, TradeValuation.Quote quote, ItemData? mostValuable = null) { Outcome = outcome; Quote = quote; MostValuable = mostValuable; } } internal static class TradeSale { internal static SaleResult Complete(Inventory inventory, IReadOnlyList<TradeLot> lots, TradeFees fees, ITradeDesk desk) { long num = 0L; foreach (TradeLot lot in lots) { num += TradeValuation.Worth(lot.Item, lot.Amount); } TradeValuation.Quote quote = TradeValuation.QuoteFor(num, fees); if (!quote.Tradeable) { return new SaleResult(SaleOutcome.Untradeable, quote); } List<TradeLot> list = new List<TradeLot>(lots.Count); foreach (TradeLot lot2 in lots) { if (!((lot2.Amount == lot2.Item.m_stack) ? inventory.RemoveItem(lot2.Item) : inventory.RemoveItem(lot2.Item, lot2.Amount))) { Restore(inventory, list, desk); return new SaleResult(SaleOutcome.LostTrack, quote); } list.Add(lot2); } if (!desk.TryDeposit(quote.Net)) { Restore(inventory, list, desk); return new SaleResult(SaleOutcome.DepositRefused, quote); } return new SaleResult(SaleOutcome.Sold, quote, MostValuable(list)); } private static void Restore(Inventory inventory, List<TradeLot> removed, ITradeDesk desk) { foreach (TradeLot item2 in removed) { if (inventory.ContainsItem(item2.Item)) { ItemData item = item2.Item; item.m_stack += item2.Amount; inventory.Changed(false, false); } else if (!inventory.AddItem(item2.Item)) { desk.Drop(item2.Item); } } } private static ItemData MostValuable(List<TradeLot> lots) { TradeLot tradeLot = lots[0]; foreach (TradeLot lot in lots) { if (TradeValuation.Worth(lot.Item, lot.Amount) > TradeValuation.Worth(tradeLot.Item, tradeLot.Amount)) { tradeLot = lot; } } return tradeLot.Item; } } internal static class TradeTooltip { private const string ValueTag = "\n$item_value:"; internal static string Insert(string tooltip, ItemData item, int stack, TradeFees fees) { StringBuilder stringBuilder = new StringBuilder(); if (stack > 1) { AppendQuote(stringBuilder, "AuraTrade each", TradeValuation.QuoteFor(item.m_shared.m_value, fees)); AppendQuote(stringBuilder, $"AuraTrade stack of {stack}", TradeValuation.QuoteFor(TradeValuation.Worth(item, stack), fees)); } else { AppendQuote(stringBuilder, "AuraTrade", TradeValuation.QuoteFor(item.m_shared.m_value, fees)); } int num = tooltip.IndexOf("\n$item_value:", StringComparison.Ordinal); if (num < 0) { return tooltip + stringBuilder; } int num2 = tooltip.IndexOf('\n', num + 1); if (num2 >= 0) { return tooltip.Insert(num2, stringBuilder.ToString()); } return tooltip + stringBuilder; } private static void AppendQuote(StringBuilder lines, string label, TradeValuation.Quote quote) { lines.Append(quote.Tradeable ? $"\n{label}: <color=orange>{quote.Gross}</color> worth, <color=orange>{quote.Fee}</color> fee, <color=orange>{quote.Net}</color> net" : $"\n{label}: <color=orange>{quote.Gross}</color> worth, the <color=orange>{quote.Fee}</color> fee takes it all"); } } [HarmonyPatch] internal static class TradeTooltipPatches { [HarmonyPostfix] [HarmonyPatch(typeof(ItemData), "GetTooltip", new Type[] { typeof(ItemData), typeof(int), typeof(bool), typeof(float), typeof(int), typeof(bool) })] private static void ItemDataGetTooltipPostfix(ItemData item, bool crafting, int stackOverride, bool appending, ref string __result) { if (!(crafting || appending) && OttoAuraPlugin.AuraTradeEnabled.Value != OttoAuraPlugin.Toggle.Off && OttoPayBridge.CanDeposit && TradeValuation.IsValuable(item)) { __result = TradeTooltip.Insert(__result, item, (stackOverride > 0) ? stackOverride : item.m_stack, TradeValuation.CurrentFees()); } } } internal readonly struct TradeFees { internal readonly int Flat; internal readonly float Percent; internal TradeFees(int flat, float percent) { Flat = flat; Percent = percent; } } internal static class TradeValuation { internal readonly struct Quote { internal readonly int Gross; internal readonly int Fee; internal int Net => Gross - Fee; internal bool Tradeable => Net > 0; internal Quote(int gross, int fee) { Gross = gross; Fee = fee; } } private const string CoinsName = "$item_coins"; internal static TradeFees CurrentFees() { return new TradeFees(OttoAuraPlugin.AuraTradeFlatFee.Value, OttoAuraPlugin.AuraTradePercentFee.Value); } internal static bool IsValuable(ItemData? item) { return IsValuable(item, OttoAuraPlugin.AuraTradeDeniedItems.Value); } internal static bool IsValuable(ItemData? item, string deniedItems) { if (item == null || item.m_shared.m_value <= 0 || item.m_shared.m_name == "$item_coins") { return false; } string prefabName = (((Object)(object)item.m_dropPrefab != (Object)null) ? ((Object)item.m_dropPrefab).name : ""); return !MoveEligibility.IsListed(deniedItems, prefabName); } internal static long Worth(ItemData item, int stack) { return (long)item.m_shared.m_value * (long)stack; } internal static Quote QuoteFor(long gross) { return QuoteFor(gross, CurrentFees()); } internal static Quote QuoteFor(long gross, TradeFees fees) { if (gross <= 0 || gross > int.MaxValue) { return new Quote(0, 0); } long num = (long)Math.Round((double)Math.Max(0f, fees.Percent) * 100.0); long num2 = (gross * num + 9999) / 10000; long val = Math.Max(0, fees.Flat) + num2; return new Quote((int)gross, (int)Math.Min(val, gross)); } } } namespace OttoAura.AuraMove { internal static class AuraMoveController { private static bool _lastAvailable; internal static bool IsAvailable { get { if (OttoAuraPlugin.AuraMoveEnabled.Value == OttoAuraPlugin.Toggle.On) { return OttoPayBridge.IsAuraPayEnabled(); } return false; } } internal static void Init() { MoveCarry.Drop(rebuildGhost: false); _lastAvailable = false; } internal static void Tick() { MoveEffects.Tick(); Player localPlayer = Player.m_localPlayer; if ((Object)(object)localPlayer == (Object)null) { MoveCarry.Drop(rebuildGhost: false); _lastAvailable = false; return; } bool isAvailable = IsAvailable; if (MoveCarry.IsCarrying && !CarryStillValid(localPlayer, isAvailable)) { MoveCarry.Drop(rebuildGhost: true); } if (isAvailable != _lastAvailable) { _lastAvailable = isAvailable; if (((Character)localPlayer).InPlaceMode()) { localPlayer.UpdateAvailablePiecesList(); } } GuildMove.RefreshDescription(); if (((Character)localPlayer).InPlaceMode() && (Object)(object)localPlayer.m_buildPieces == (Object)(object)GuildMove.HammerTable) { GuildMove.EnsureTabs(localPlayer.m_buildPieces); } HandleShortcut(localPlayer, isAvailable); } internal static void Shutdown() { MoveCarry.Drop(rebuildGhost: false); MoveEffects.StopAll(); GuildMove.Shutdown(); _lastAvailable = false; } internal static bool HandlePlaceClick(Player player) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (!IsAvailable) { MoveCarry.Drop(rebuildGhost: true); return false; } if (!MoveCarry.IsCarrying) { TryGrab(player); return false; } player.UpdatePlacementGhost(true); if (MoveCarry.TooFar) { ((Character)player).Message((MessageType)1, "The Guild will not carry it that far.", 0, (Sprite)null, false); return false; } if ((int)player.m_placementStatus != 0) { return true; } ChargeAndCommit(player); return false; } internal static void CancelByPlayer(Player player) { ((Character)player).Message((MessageType)1, "The Merchant Guild lets go.", 0, (Sprite)null, false); MoveCarry.Drop(rebuildGhost: true); } private static void TryGrab(Player player) { Piece hoveringPiece = player.GetHoveringPiece(); if ((Object)(object)hoveringPiece == (Object)null) { return; } MoveDenial moveDenial = MoveEligibility.Evaluate(hoveringPiece, flashWard: true); if (moveDenial != MoveDenial.None) { string text = MoveEligibility.DenialMessage(moveDenial); if (text.Length > 0) { ((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false); } } else if (MoveCarry.Grab(player, hoveringPiece)) { ((Character)player).Message((MessageType)1, "The Merchant Guild takes hold of the " + MoveCarry.CarriedName + ".", 0, (Sprite)null, false); } } private static void ChargeAndCommit(Player player) { //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_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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) Piece source = MoveCarry.Source; GameObject placementGhost = player.m_placementGhost; if ((Object)(object)source == (Object)null || (Object)(object)placementGhost == (Object)null || !MoveRelocation.CanRequest(source)) { MoveCarry.Drop(rebuildGhost: true); return; } MoveDenial moveDenial = MoveEligibility.Evaluate(source, flashWard: true); if (moveDenial != MoveDenial.None) { string text = MoveEligibility.DenialMessage(moveDenial); if (text.Length > 0) { ((Character)player).Message((MessageType)1, text, 0, (Sprite)null, false); } MoveCarry.Drop(rebuildGhost: true); return; } int num = Mathf.Max(0, OttoAuraPlugin.AuraMoveCoins.Value); if (num > 0 && !OttoPayBridge.TryWithdraw(num)) { ((Character)player).Message((MessageType)1, "Your Merchant Bank balance is empty. The Merchant Guild does not work for free.", 0, (Sprite)null, false); return; } Vector3 position = placementGhost.transform.position; Quaternion rotation = placementGhost.transform.rotation; string carriedName = MoveCarry.CarriedName; bool num2 = MoveRelocation.Request(source, position, rotation); MoveCarry.Drop(rebuildGhost: true); if (!num2) { OttoAuraPlugin.OttoAuraLogger.LogWarning((object)"AuraMove: the move RPC could not be sent after the fee was taken."); return; } string text2 = ((num > 0) ? $"The Guild moves the {carriedName} for {num} coins." : ("The Guild moves the " + carriedName + ".")); ((Character)player).Message((MessageType)1, text2, 0, (Sprite)null, false); } private static bool CarryStillValid(Player player, bool available) { //IL_006b: 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) if (!available || ((Character)player).IsDead() || ((Character)player).IsTeleporting() || !((Character)player).InPlaceMode()) { return false; } if ((Object)(object)player.m_buildPieces != (Object)(object)GuildMove.HammerTable || !GuildMove.IsSelectedBy(player)) { return false; } Piece source = MoveCarry.Source; if ((Object)(object)source == (Object)null || (Object)(object)source.m_nview == (Object)null || !source.m_nview.IsValid()) { return false; } return Vector3.Distance(((Component)player).transform.position, ((Component)source).transform.position) <= OttoAuraPlugin.AuraMoveMaxDistance.Value + player.m_maxPlaceDistance; } private static void HandleShortcut(Player player, bool available) { if (!MoveTargeting.ShortcutDown || !available || (Object)(object)GuildMove.PseudoPiece == (Object)null || (Object)(object)GuildMove.HammerTable == (Object)null) { return; } if (GuildMove.IsSelectedBy(player)) { MoveCarry.Drop(rebuildGhost: false); ((Humanoid)player).UnequipItem(((Humanoid)player).GetRightItem(), true); return; } if ((Object)(object)player.m_buildPieces != (Object)(object)GuildMove.HammerTable) { ItemData val = FindHammer(player); if (val == null) { ((Character)player).Message((MessageType)1, "The Merchant Guild works through a hammer, and you have none.", 0, (Sprite)null, false); return; } if (!((Humanoid)player).EquipItem(val, true)) { return; } } player.SetSelectedPiece(GuildMove.PseudoPiece); } private static ItemData? FindHammer(Player player) { foreach (ItemData allItem in ((Humanoid)player).GetInventory().GetAllItems()) { if ((Object)(object)allItem.m_shared.m_buildPieces == (Object)(object)GuildMove.HammerTable) { return allItem; } } return null; } } [HarmonyPatch(typeof(Minimap), "SetMapMode")] internal static class Minimap_SetMapMode_Patch { private static bool Prefix(MapMode mode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 if ((int)mode == 2) { return !MoveTargeting.ShortcutDown; } return true; } } [HarmonyPatch(typeof(Game), "Logout")] internal static class Game_Logout_Patch { private static void Prefix() { MoveCarry.Drop(rebuildGhost: false); MoveEffects.StopAll(); } } internal static class GuildMove { internal const string PrefabName = "OttoAura_GuildMove"; internal const string PieceLabel = "Guild Move"; internal const string CategoryLabel = "Merchant Guild"; internal const PieceCategory Category = (PieceCategory)10; private const int CategoryListCount = 11; private static GameObject? _prefab; private static Piece? _pseudoPiece; private static PieceTable? _hammerTable; private static bool _warnedNoHammer; private static string _describedFor = ""; private static int _describedCoins = -1; private static float _describedDistance = -1f; internal static Piece? PseudoPiece => _pseudoPiece; internal static PieceTable? HammerTable => _hammerTable; internal static bool IsPseudoPiece(Piece? piece) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Invalid comparison between Unknown and I4 if ((Object)(object)piece != (Object)null && (Object)(object)_pseudoPiece != (Object)null && piece.m_name == "Guild Move") { return (int)piece.m_category == 10; } return false; } internal static bool IsSelectedBy(Player? player) { if ((Object)(object)player == (Object)null || (Object)(object)_hammerTable == (Object)null || (Object)(object)player.m_buildPieces != (Object)(object)_hammerTable) { return false; } return IsPseudoPiece(_hammerTable.GetSelectedPiece()); } internal static void Setup(ObjectDB db) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)db == (Object)null) { return; } PieceTable val = ResolveHammerTable(db); if (!((Object)(object)val == (Object)null)) { _hammerTable = val; if (!((Object)(object)_prefab != (Object)null)) { GameObject val2 = new GameObject("OttoAura_GuildMove"); val2.SetActive(false); Object.DontDestroyOnLoad((Object)(object)val2); Piece obj = val2.AddComponent<Piece>(); obj.m_name = "Guild Move"; obj.m_description = BuildDescription(); obj.m_icon = ResolveIcon(db); obj.m_category = (PieceCategory)10; obj.m_usage = (UsageTagFlags)1; obj.m_canBeRemoved = false; obj.m_enabled = true; obj.m_canRotate = true; obj.m_resources = Array.Empty<Requirement>(); _prefab = val2; _pseudoPiece = obj; } } } internal static void Shutdown() { if ((Object)(object)_hammerTable != (Object)null && (Object)(object)_pseudoPiece != (Object)null) { _hammerTable.m_enabledPieces.Remove(_pseudoPiece); _hammerTable.m_availablePieces.Remove(_pseudoPiece); if (_hammerTable.m_availablePiecesByCategory.Count > 10) { _hammerTable.m_availablePiecesByCategory[10].Remove(_pseudoPiece); } SyncCategory(_hammerTable, ava