Decompiled source of ReduceRecycler v1.3.1

plugins/ReduceRecycler/ReduceRecycler.dll

Decompiled 2 months ago
using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using IL.RoR2;
using Mono.Cecil.Cil;
using MonoMod.Cil;
using On.RoR2;
using R2API.Utils;
using RiskOfOptions;
using RiskOfOptions.Options;
using RoR2;
using UnityEngine;

[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("ReduceRecycler")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+29106a95702b1c19675a0f56ea218e07d1016b45")]
[assembly: AssemblyProduct("ReduceRecycler")]
[assembly: AssemblyTitle("ReduceRecycler")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ReduceRecycler;

internal static class ConfigManager
{
	private static ConfigFile OptionsConfig { get; set; }

	internal static ConfigEntry<bool> IsModEnabled { get; set; }

	internal static ConfigEntry<bool> EnableOnlyAfterTeleporter { get; set; }

	internal static ConfigEntry<ReduceRecycler.CooldownReset> CooldownReset { get; set; }

	internal static void Init()
	{
		//IL_0010: Unknown result type (might be due to invalid IL or missing references)
		//IL_001a: Expected O, but got Unknown
		//IL_0048: Unknown result type (might be due to invalid IL or missing references)
		//IL_0052: Expected O, but got Unknown
		//IL_0076: Unknown result type (might be due to invalid IL or missing references)
		//IL_0080: Expected O, but got Unknown
		//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00ae: Expected O, but got Unknown
		OptionsConfig = new ConfigFile(Paths.ConfigPath + "\\ReduceRecycler.cfg", true);
		ModSettingsManager.SetModDescription("Customize the behavior of the recycler equipment to shorten the time between uses.");
		IsModEnabled = OptionsConfig.Bind<bool>("Behavior", "Enable Mod", true, "Dynamically enable or disable the mod. If this is unchecked, the mod will not function until re-enabled.");
		ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(IsModEnabled));
		EnableOnlyAfterTeleporter = OptionsConfig.Bind<bool>("Behavior", "Enable Only After Teleporter", false, "Enable no-cooldown only after the teleporter for the stage has been completed. For stage without a teleporter (Hidden Realms, Void Fields, Commencement), this just makes the Recycler behave as normal.");
		ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(EnableOnlyAfterTeleporter));
		CooldownReset = OptionsConfig.Bind<ReduceRecycler.CooldownReset>("Behavior", "Cooldown Reset", ReduceRecycler.CooldownReset.AfterUse, "When to reset the cooldown of Recycler. AfterUse will reset immediately after use. OnDemand will reset on button press.");
		ModSettingsManager.AddOption((BaseOption)new ChoiceOption((ConfigEntryBase)(object)CooldownReset));
	}
}
internal static class Log
{
	private static ManualLogSource Logger { get; set; }

	internal static void Init(ManualLogSource logger)
	{
		Logger = logger;
	}

	[Conditional("DEBUG")]
	internal static void Debug(object data)
	{
		Logger.LogDebug(data);
	}

	internal static void Info(object data)
	{
		Logger.LogInfo(data);
	}

	internal static void Message(object data)
	{
		Logger.LogMessage(data);
	}

	internal static void Warning(object data)
	{
		Logger.LogWarning(data);
	}

	internal static void Error(object data)
	{
		Logger.LogError(data);
	}

	internal static void Fatal(object data)
	{
		Logger.LogFatal(data);
	}
}
[BepInDependency(/*Could not decode attribute arguments.*/)]
[NetworkCompatibility(/*Could not decode attribute arguments.*/)]
[BepInPlugin("quasikyo.ReduceRecycler", "ReduceRecycler", "1.3.1")]
public class ReduceRecycler : BaseUnityPlugin
{
	internal enum CooldownReset
	{
		AfterUse,
		OnDemand
	}

	public const string PluginGUID = "quasikyo.ReduceRecycler";

	public const string PluginAuthor = "quasikyo";

	public const string PluginName = "ReduceRecycler";

	public const string PluginVersion = "1.3.1";

	private const string finalStageSceneName = "moon2";

	private const string voidFieldsStageSceneName = "arena";

	public void Awake()
	{
		//IL_0021: Unknown result type (might be due to invalid IL or missing references)
		//IL_002b: Expected O, but got Unknown
		//IL_0032: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0043: Unknown result type (might be due to invalid IL or missing references)
		//IL_004d: Expected O, but got Unknown
		Log.Init(((BaseUnityPlugin)this).Logger);
		Log.Info("Performing setup for ReduceRecycler");
		ConfigManager.Init();
		EquipmentSlot.FireRecycle += new hook_FireRecycle(ResetAfterUse);
		EquipmentSlot.MyFixedUpdate += new Manipulator(EquipmentActivationAllowedIfRecycler);
		EquipmentSlot.ExecuteIfReady += new Manipulator(ResetOnDemand);
	}

	private void EquipmentActivationAllowedIfRecycler(ILContext context)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		ILCursor val = new ILCursor(context);
		val.GotoNext(new Func<Instruction, bool>[4]
		{
			(Instruction x) => ILPatternMatchingExt.MatchLdarg(x, 0),
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<EquipmentSlot>(x, "get_characterBody"),
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<CharacterBody>(x, "get_isEquipmentActivationAllowed"),
			(Instruction x) => ILPatternMatchingExt.MatchStloc(x, 0)
		});
		val.Index += 2;
		val.Remove();
		val.EmitDelegate<Func<CharacterBody, bool>>((Func<CharacterBody, bool>)delegate(CharacterBody body)
		{
			VehicleSeat currentVehicle = body.currentVehicle;
			bool flag = !Object.op_Implicit((Object)(object)currentVehicle) || currentVehicle.isEquipmentActivationAllowed;
			return IsRecycler(body.equipmentSlot) || flag;
		});
	}

	private void ResetOnDemand(ILContext context)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Expected O, but got Unknown
		ILCursor val = new ILCursor(context);
		val.GotoNext(new Func<Instruction, bool>[1]
		{
			(Instruction x) => ILPatternMatchingExt.MatchCallOrCallvirt<EquipmentSlot>(x, "get_stock")
		});
		val.Remove();
		val.EmitDelegate<Func<EquipmentSlot, int>>((Func<EquipmentSlot, int>)delegate(EquipmentSlot slot)
		{
			if (ConfigManager.CooldownReset.Value == CooldownReset.OnDemand)
			{
				Log.Info("Resetting before use");
				ResetRecyclerCooldown(slot);
			}
			return slot.stock;
		});
	}

	private bool ResetAfterUse(orig_FireRecycle original, EquipmentSlot slot)
	{
		bool flag = original.Invoke(slot);
		if (ConfigManager.CooldownReset.Value == CooldownReset.AfterUse && flag)
		{
			Log.Info("Resetting after use");
			((MonoBehaviour)this).StartCoroutine(ExecuteWithDelay(delegate
			{
				ResetRecyclerCooldown(slot);
			}, TimeSpan.FromSeconds(0.5)));
		}
		return flag;
	}

	private void ResetRecyclerCooldown(EquipmentSlot slot)
	{
		if (!ConfigManager.IsModEnabled.Value)
		{
			Log.Info("Skipping reset as mod is disabled");
			return;
		}
		if (!IsRecycler(slot))
		{
			Log.Info("Skipping reset as equipment is not the Recycler");
			return;
		}
		float cooldownTimer = slot.cooldownTimer;
		if (float.IsInfinity(cooldownTimer))
		{
			Log.Info("Skipping reset as cooldownTimer is infinity");
			return;
		}
		float runStopwatch = Run.instance.GetRunStopwatch();
		bool flag = StageHasTeleporter(Stage.instance.sceneDef) && TeleporterInteraction.instance.isCharged;
		bool flag2 = !ConfigManager.EnableOnlyAfterTeleporter.Value || flag;
		if (!(GetEquipmentCharges(slot) == 0 && flag2))
		{
			Log.Info("Skipping reset due to failing criteria evaluation");
			return;
		}
		slot.characterBody.inventory.DeductActiveEquipmentCooldown(cooldownTimer);
		if (!Run.instance.isRunStopwatchPaused)
		{
			Run.instance.SetRunStopwatch(runStopwatch + cooldownTimer);
		}
	}

	private bool StageHasTeleporter(SceneDef scene)
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0007: Invalid comparison between Unknown and I4
		bool num = (int)scene.sceneType == 1;
		bool flag = scene.baseSceneName.Equals("moon2");
		bool flag2 = scene.baseSceneName.Equals("arena");
		if (num && !flag)
		{
			return !flag2;
		}
		return false;
	}

	private bool IsRecycler(EquipmentSlot slot)
	{
		//IL_0007: Unknown result type (might be due to invalid IL or missing references)
		return (Object)(object)EquipmentCatalog.GetEquipmentDef((EquipmentIndex)((slot == null) ? (-1) : ((int)slot.equipmentIndex))) == (Object)(object)Equipment.Recycle;
	}

	private int GetEquipmentCharges(EquipmentSlot equipmentSlot)
	{
		//IL_0013: Unknown result type (might be due to invalid IL or missing references)
		Inventory inventory = equipmentSlot.characterBody.inventory;
		uint activeEquipmentSlot = inventory.activeEquipmentSlot;
		return inventory.GetEquipment(activeEquipmentSlot).charges;
	}

	private IEnumerator ExecuteWithDelay(Action action, TimeSpan delay)
	{
		yield return (object)new WaitForSeconds((float)delay.TotalSeconds);
		action();
	}
}