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();
}
}