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 Money and XP Multiplier v1.0.0
MoneyAndXpMultiplier.dll
Decompiled 9 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using OffTheClock.Shared; using Rewired; using RoR2; using RoR2.UI; using UnityEngine; using UnityEngine.Networking; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("MoneyAndXpMultiplier")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("MoneyAndXpMultiplier")] [assembly: AssemblyTitle("MoneyAndXpMultiplier")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace MoneyAndXpMultiplier { [BepInPlugin("offtheclock.ror2moneyxp", "Money and XP Multiplier", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigEntry<float> GoldMult; internal static ConfigEntry<float> XpMult; private ConfigEntry<string> _goldStepsText; private ConfigEntry<string> _xpStepsText; private ConfigEntry<KeyCode> _goldKey; private ConfigEntry<KeyCode> _xpKey; private ConfigEntry<bool> _showNotice; private float[] _goldSteps; private float[] _xpSteps; private Notice _notice; private bool _inRunSeen; private bool _keysBroken; private static readonly float[] DefaultGoldSteps = new float[5] { 1f, 2f, 3f, 5f, 10f }; private static readonly float[] DefaultXpSteps = new float[5] { 1f, 2f, 3f, 5f, 10f }; private void Awake() { //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Expected O, but got Unknown //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Expected O, but got Unknown //IL_029b: Unknown result type (might be due to invalid IL or missing references) //IL_02cc: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; _notice = new Notice("Money and XP Multiplier"); GoldMult = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Gold", 2f, new ConfigDescription("Gold from kills, barrels and money pickups is multiplied by this (1 = normal, 10 = ten times). Starting money, Shrine of Blood and item gold (Roll of Pennies, Brittle Crown, Executive Card) stay normal.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); XpMult = ((BaseUnityPlugin)this).Config.Bind<float>("Multipliers", "Experience", 2f, new ConfigDescription("Experience your team earns is multiplied by this (1 = normal, 10 = ten times).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 10f), Array.Empty<object>())); _goldKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "GoldCycleKey", (KeyCode)268, "Cycles the gold multiplier through GoldSteps. None = no key."); _xpKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Keys", "ExperienceCycleKey", (KeyCode)267, "Cycles the experience multiplier through ExperienceSteps. None = no key."); _goldStepsText = ((BaseUnityPlugin)this).Config.Bind<string>("Keys", "GoldSteps", "1, 2, 3, 5, 10", "Values the gold key cycles through (1 to 10, comma-separated)."); _xpStepsText = ((BaseUnityPlugin)this).Config.Bind<string>("Keys", "ExperienceSteps", "1, 2, 3, 5, 10", "Values the experience key cycles through (1 to 10, comma-separated)."); _showNotice = ((BaseUnityPlugin)this).Config.Bind<bool>("Keys", "ShowOnScreenNotice", true, "Show the new value on screen for a moment after a key press (it is always written to the log)."); ParseSteps(); ((BaseUnityPlugin)this).Config.SettingChanged += delegate(object _, SettingChangedEventArgs e) { if ((object)e.ChangedSetting == _goldStepsText || (object)e.ChangedSetting == _xpStepsText) { ParseSteps(); } if ((object)e.ChangedSetting == GoldMult || (object)e.ChangedSetting == XpMult) { Patches.ValueChanged(); } }; Harmony harmony = new Harmony("offtheclock.ror2moneyxp"); Honesty.MarkRunChanging(harmony, Log, "Money and XP Multiplier"); bool flag = PatchGuard.Apply(harmony, Log, "Money and XP Multiplier", "RoR2.TeamManager", "GiveTeamMoney", new Type[2] { typeof(TeamIndex), typeof(uint) }, PatchGuard.Own(typeof(Patches), "GiveTeamMoney_Pre"), null); bool flag2 = PatchGuard.Apply(harmony, Log, "Money and XP Multiplier", "RoR2.TeamManager", "GiveTeamExperience", new Type[2] { typeof(TeamIndex), typeof(ulong) }, PatchGuard.Own(typeof(Patches), "GiveTeamExperience_Pre"), null); string text = (flag ? ("gold x" + Steps.F(GoldMult.Value)) : "gold INACTIVE (game function not found)") + ", " + (flag2 ? ("XP x" + Steps.F(XpMult.Value)) : "XP INACTIVE (game function not found)"); Log.LogInfo((object)("Money and XP Multiplier 1.0.0 loaded - " + text + " in solo and local split-screen runs (never online); " + KeyCheck.KeyName(_goldKey.Value) + " cycles gold (" + Steps.Text(_goldSteps) + "), " + KeyCheck.KeyName(_xpKey.Value) + " cycles XP (" + Steps.Text(_xpSteps) + ").")); } private void ParseSteps() { _goldSteps = Steps.Parse(_goldStepsText.Value, 1f, 10f, DefaultGoldSteps, Log, "Money and XP Multiplier", "GoldSteps"); _xpSteps = Steps.Parse(_xpStepsText.Value, 1f, 10f, DefaultXpSteps, Log, "Money and XP Multiplier", "ExperienceSteps"); } private void Update() { //IL_003b: 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_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) try { bool inRun = Session.InRun; if (inRun && !_inRunSeen) { _inRunSeen = true; Patches.NewRun(); KeyCheck.Check(Log, "Money and XP Multiplier", new List<KeyValuePair<string, KeyCode>> { new KeyValuePair<string, KeyCode>("gold cycle", _goldKey.Value), new KeyValuePair<string, KeyCode>("experience cycle", _xpKey.Value) }); if (!Session.IsOffline) { Log.LogInfo((object)("Money and XP Multiplier: off in this run (" + Session.Describe() + ") - gold and XP stay normal. Works in solo and local split-screen only.")); } } else if (!inRun && _inRunSeen) { _inRunSeen = false; } } catch (Exception ex) { Log.LogDebug((object)("Money and XP Multiplier: run check skipped (" + ex.Message + ").")); } if (_keysBroken) { return; } try { if (KeyCheck.Pressed(_goldKey.Value)) { Cycle(gold: true); } if (KeyCheck.Pressed(_xpKey.Value)) { Cycle(gold: false); } } catch (Exception ex2) { _keysBroken = true; Log.LogWarning((object)("Money and XP Multiplier: key reading stopped (" + ex2.Message + "); the config values still work.")); } } private void Cycle(bool gold) { ConfigEntry<float> val = (gold ? GoldMult : XpMult); float num = (val.Value = Steps.NextCycle(gold ? _goldSteps : _xpSteps, val.Value)); string text = (gold ? "Gold" : "XP"); bool flag = Session.InRun && !Session.IsOffline; Log.LogInfo((object)("Money and XP Multiplier: " + text + " multiplier now x" + Steps.F(num) + " (cycle " + Steps.Text(gold ? _goldSteps : _xpSteps) + ")" + (flag ? " - not applied in online lobbies." : ((num <= 1f) ? " - normal amount." : ".")))); _notice.Show(flag ? (text + " x" + Steps.F(num) + " (offline only)") : (text + " x" + Steps.F(num))); } private void OnGUI() { _notice.Draw(Log, _showNotice.Value); } } internal static class Patches { private static bool _loggedGold; private static bool _loggedXp; private static bool _loggedOnline; internal static void NewRun() { _loggedGold = false; _loggedXp = false; _loggedOnline = false; } internal static void ValueChanged() { _loggedGold = false; _loggedXp = false; } internal static void GiveTeamMoney_Pre(TeamIndex teamIndex, ref uint money) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 try { if ((int)teamIndex != 1 || money == 0) { return; } float value = Plugin.GoldMult.Value; if (value <= 1f) { return; } if (!Session.IsOffline) { LogOnlineOnce(); return; } uint num = money; double num2 = Math.Round((double)num * (double)value); money = ((num2 >= 4294967295.0) ? uint.MaxValue : ((uint)num2)); if (!_loggedGold) { _loggedGold = true; Plugin.Log.LogInfo((object)string.Format("{0}: gold x{1} active ({2} -> {3}).", "Money and XP Multiplier", Steps.F(value), num, money)); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Money and XP Multiplier: gold multiplier skipped once (" + ex.Message + ").")); } } internal static void GiveTeamExperience_Pre(TeamIndex teamIndex, ref ulong experience) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 try { if ((int)teamIndex != 1 || experience == 0L) { return; } float value = Plugin.XpMult.Value; if (value <= 1f) { return; } if (!Session.IsOffline) { LogOnlineOnce(); return; } ulong num = experience; double num2 = Math.Round((double)num * (double)value); experience = ((num2 >= 1.8446744073709552E+19) ? ulong.MaxValue : ((ulong)num2)); if (!_loggedXp) { _loggedXp = true; Plugin.Log.LogInfo((object)string.Format("{0}: XP x{1} active ({2} -> {3}).", "Money and XP Multiplier", Steps.F(value), num, experience)); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Money and XP Multiplier: XP multiplier skipped once (" + ex.Message + ").")); } } private static void LogOnlineOnce() { if (!_loggedOnline) { _loggedOnline = true; Plugin.Log.LogInfo((object)"Money and XP Multiplier: online lobby - gold and XP left unchanged."); } } } internal static class PluginInfo { public const string PLUGIN_GUID = "offtheclock.ror2moneyxp"; public const string PLUGIN_NAME = "Money and XP Multiplier"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace OffTheClock.Shared { internal static class Honesty { private static ManualLogSource _log; private static string _feature; private static bool _loggedBlock; internal static void MarkRunChanging(Harmony harmony, ManualLogSource log, string feature) { _log = log; _feature = feature; bool flag = false; bool flag2 = false; try { RoR2Application.isModded = true; flag = true; } catch (Exception ex) { log.LogWarning((object)(feature + ": could not set the game's modded flag: " + ex.Message)); } try { MethodInfo methodInfo = AccessTools.PropertySetter(typeof(Console), "sessionCheatsEnabled"); if (methodInfo != null) { methodInfo.Invoke(null, new object[1] { true }); flag2 = Console.sessionCheatsEnabled; } if (!flag2) { log.LogWarning((object)(feature + ": the game's cheat flag (Console.sessionCheatsEnabled) could not be set; the leaderboard lock below still applies.")); } } catch (Exception ex2) { log.LogWarning((object)(feature + ": could not set the game's cheat flag: " + ex2.Message)); } bool flag3 = PatchGuard.Apply(harmony, log, feature, "RoR2.WeeklyRun", "GetLeaderboardName", new Type[2] { typeof(int), typeof(uint) }, null, PatchGuard.Own(typeof(Honesty), "GetLeaderboardName_Post")); log.LogInfo((object)(feature + ": Prismatic Trials leaderboard blocked for this session (modded flag " + (flag ? "set" : "NOT set") + ", cheat flag " + (flag2 ? "set" : "NOT set") + ", leaderboard lock " + (flag3 ? "on" : "NOT on") + ").")); } private static void GetLeaderboardName_Post(ref string __result) { try { __result = null; if (!_loggedBlock) { _loggedBlock = true; ManualLogSource log = _log; if (log != null) { log.LogInfo((object)(_feature + ": Prismatic Trials leaderboard name refused (modded session: no score is submitted and the leaderboard view stays empty).")); } } } catch { } } } internal static class KeyCheck { internal static void Check(ManualLogSource log, string feature, IList<KeyValuePair<string, KeyCode>> keys) { //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) try { if (!ReInput.isReady) { return; } List<string> list = new List<string>(); foreach (LocalUser readOnlyLocalUsers in LocalUserManager.readOnlyLocalUsersList) { Player val = ((readOnlyLocalUsers != null) ? readOnlyLocalUsers.inputPlayer : null); if (val == null) { continue; } foreach (ControllerMap allMap in val.controllers.maps.GetAllMaps((ControllerType)0)) { if (allMap == null || !allMap.enabled) { continue; } foreach (ActionElementMap allMap2 in allMap.AllMaps) { if (allMap2 == null || (int)allMap2.keyCode == 0) { continue; } foreach (KeyValuePair<string, KeyCode> key in keys) { if ((int)key.Value != 0 && allMap2.keyCode == key.Value) { string text = "action " + allMap2.actionId; try { InputAction action = ReInput.mapping.GetAction(allMap2.actionId); text = ((action != null) ? action.name : null) ?? text; } catch { } list.Add(KeyName(key.Value) + " (" + key.Key + ") is also bound to the game's '" + text + "'"); } } } } } if (list.Count == 0) { log.LogInfo((object)(feature + ": key check - " + List(keys) + " not used by your game key bindings.")); } else { log.LogWarning((object)(feature + ": key clash - " + string.Join("; ", list) + ". Change the key in the config or in the game's Settings > Keyboard.")); } } catch (Exception ex) { log.LogInfo((object)(feature + ": key check skipped (" + ex.Message + ").")); } } internal static string List(IList<KeyValuePair<string, KeyCode>> keys) { //IL_0018: 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) List<string> list = new List<string>(); foreach (KeyValuePair<string, KeyCode> key in keys) { if ((int)key.Value != 0) { list.Add(KeyName(key.Value)); } } if (list.Count != 0) { return string.Join(", ", list); } return "(no keys)"; } internal unsafe static string KeyName(KeyCode k) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected I4, but got Unknown //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Invalid comparison between Unknown and I4 //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Invalid comparison between Unknown and I4 //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected I4, but got Unknown if ((int)k != 0) { switch (k - 266) { case 2: return "Numpad *"; case 1: return "Numpad /"; case 4: return "Numpad +"; case 3: return "Numpad -"; case 0: return "Numpad ."; case 5: return "Numpad Enter"; default: if ((int)k >= 256 && (int)k <= 265) { return "Numpad " + (k - 256); } return ((object)(*(KeyCode*)(&k))/*cast due to .constrained prefix*/).ToString(); } } return "(no key)"; } internal static bool Pressed(KeyCode k) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) if ((int)k != 0 && Input.GetKeyDown(k)) { return !Session.IsTyping; } return false; } } internal sealed class Notice { private const float Seconds = 2.5f; private readonly string _feature; private string _text; private float _until; private bool _broken; internal Notice(string feature) { _feature = feature; } internal void Show(string text) { _text = text; _until = Time.unscaledTime + 2.5f; } internal void Draw(ManualLogSource log, bool enabled) { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00b9: Unknown result type (might be due to invalid IL or missing references) if (_broken || !enabled || _text == null || Time.unscaledTime > _until) { return; } try { float num = Mathf.Max(320f, 14f * (float)_text.Length); float num2 = 44f; Rect val = new Rect(((float)Screen.width - num) / 2f, (float)Screen.height * 0.12f, num, num2); GUI.Box(val, ""); GUI.Box(val, ""); GUIStyle label = GUI.skin.label; int fontSize = label.fontSize; TextAnchor alignment = label.alignment; label.fontSize = 24; label.alignment = (TextAnchor)4; GUI.Label(val, _text, label); label.fontSize = fontSize; label.alignment = alignment; } catch (Exception ex) { _broken = true; log.LogWarning((object)(_feature + ": on-screen notice unavailable (" + ex.Message + "); new values are shown in the log only.")); } } } internal static class PatchGuard { internal static bool Apply(Harmony harmony, ManualLogSource log, string feature, string typeName, string methodName, Type[] parameters, MethodInfo prefix, MethodInfo postfix) { //IL_009e: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) try { Type type = AccessTools.TypeByName(typeName); if (type == null) { log.LogWarning((object)(feature + ": game class " + typeName + " not found - this part is skipped (game update?).")); return false; } MethodInfo methodInfo = ((parameters == null) ? AccessTools.Method(type, methodName, (Type[])null, (Type[])null) : AccessTools.Method(type, methodName, parameters, (Type[])null)); if (methodInfo == null) { log.LogWarning((object)(feature + ": game method " + typeName + "." + methodName + " not found - this part is skipped (game update?).")); return false; } harmony.Patch((MethodBase)methodInfo, (prefix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix), (postfix == null) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); log.LogInfo((object)(feature + ": patched " + typeName + "." + methodName + ".")); return true; } catch (Exception ex) { log.LogWarning((object)(feature + ": could not patch " + typeName + "." + methodName + " - this part is skipped (game update?): " + ex.Message)); return false; } } internal static MethodInfo Own(Type patchClass, string name) { return AccessTools.Method(patchClass, name, (Type[])null, (Type[])null); } } internal static class Session { internal static bool InRun { get { try { return Object.op_Implicit((Object)(object)Run.instance); } catch { return false; } } } internal static bool IsSolo { get { try { return RoR2Application.isInSinglePlayer; } catch { return false; } } } internal static bool IsOffline { get { try { return NetworkServer.active && NetworkServer.dontListen; } catch { return false; } } } internal static bool IsTyping { get { try { return Object.op_Implicit((Object)(object)ConsoleWindow.instance) || ChatBox.IsActive; } catch { return false; } } } internal static string Describe() { try { if (!InRun) { return "not in a run"; } if (IsSolo) { return "solo"; } if (IsOffline) { return "local split-screen"; } return "online lobby"; } catch (Exception) { return "unknown"; } } } internal static class Steps { internal static float[] Parse(string text, float min, float max, float[] fallback, ManualLogSource log, string feature, string name) { List<float> list = new List<float>(); string[] array = (text ?? "").Split(new char[3] { ',', ';', ' ' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { if (float.TryParse(array[i].Trim().TrimStart('x', 'X'), NumberStyles.Float, CultureInfo.InvariantCulture, out var result) && result >= min && result <= max && !list.Contains(result)) { list.Add(result); } } if (list.Count == 0) { log.LogWarning((object)(feature + ": " + name + " has no valid values (" + F(min) + " to " + F(max) + "), using " + Text(fallback) + ".")); return fallback; } list.Sort(); return list.ToArray(); } internal static string F(float v) { return v.ToString("0.##", CultureInfo.InvariantCulture); } internal static string Text(float[] steps) { List<string> list = new List<string>(); foreach (float v in steps) { list.Add("x" + F(v)); } return string.Join("/", list); } internal static float NextCycle(float[] steps, float current) { foreach (float num in steps) { if (num > current + 0.001f) { return num; } } return steps[0]; } internal static float Up(float[] steps, float current) { foreach (float num in steps) { if (num > current + 0.001f) { return num; } } return steps[^1]; } internal static float Down(float[] steps, float current) { for (int num = steps.Length - 1; num >= 0; num--) { if (steps[num] < current - 0.001f) { return steps[num]; } } return steps[0]; } } }