Decompiled source of AutoRechargeHelper v1.0.0

plugins/AutoRechargeHelper.dll

Decompiled a week ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
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: IgnoresAccessChecksTo("")]
[assembly: AssemblyCompany("Kai")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0+affca2df2734f3c3721110c096a78cef5520d739")]
[assembly: AssemblyProduct("AutoRechargeHelper")]
[assembly: AssemblyTitle("AutoRechargeHelper")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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]
	[Microsoft.CodeAnalysis.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 AutoRechargeHelper
{
	[BepInPlugin("Kai.AutoRechargeHelper", "AutoRechargeHelper", "1.0.0")]
	public sealed class AutoRechargeHelper : BaseUnityPlugin
	{
		public static ConfigEntry<bool> EnableMod;

		public static ConfigEntry<bool> FirstTimeOnly;

		public static ConfigEntry<string> BlacklistItems;

		public static ConfigEntry<bool> EnableLogging;

		public static ConfigEntry<bool> RunIsMainLevel;

		public static ConfigEntry<bool> ChargeInTruck;

		internal static AutoRechargeHelper Instance { get; private set; }

		internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger;

		internal Harmony? Harmony { get; private set; }

		private void Awake()
		{
			//IL_0022: Unknown result type (might be due to invalid IL or missing references)
			//IL_002c: Expected O, but got Unknown
			Instance = this;
			LoadConfig();
			AutoRechargeRuntime.ReloadBlacklist();
			Harmony = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID);
			Harmony.PatchAll();
			Log.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded.");
		}

		private void OnDestroy()
		{
			Harmony? harmony = Harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		private void LoadConfig()
		{
			EnableMod = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableMod", true, "Mod全体の有効化 / Enable or disable this mod.");
			FirstTimeOnly = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "FirstTimeOnly", true, "初回のみマークし、満充電後は再充電しない / Mark batteries only once; disable recharging after fully charged.");
			BlacklistItems = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Blacklist", "Rubber Duck", "自動充電対象から除外するアイテム名(部分一致、カンマ区切り) / Exclude specific items from auto-recharge (partial match, comma-separated).");
			EnableLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableLogging", false, "ログ出力を有効化 / Enable detailed log output.");
			RunIsMainLevel = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RunIsMainLevel", true, "通常ステージでも自動充電対象の管理を有効化する / Enable auto recharge in main levels.");
			ChargeInTruck = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ChargeInTruck", true, "アイテムがTruck内にある時だけ自動充電する / Only auto charge items while they are inside the truck.");
			BlacklistItems.SettingChanged += delegate
			{
				AutoRechargeRuntime.ReloadBlacklist();
			};
		}

		internal static void LogInfo(string message)
		{
			if (EnableLogging.Value)
			{
				Log.LogInfo((object)message);
			}
		}

		internal static void LogWarning(string message)
		{
			if (EnableLogging.Value)
			{
				Log.LogWarning((object)message);
			}
		}
	}
	internal static class AutoRechargeRuntime
	{
		private static readonly HashSet<ItemBattery> Marked = new HashSet<ItemBattery>();

		private static readonly HashSet<ItemBattery> Finished = new HashSet<ItemBattery>();

		private static HashSet<string> _blacklistSet = new HashSet<string>();

		private static float scanIntervalSeconds = 10f;

		private static float _nextScanTime;

		internal static void ReloadBlacklist()
		{
			_blacklistSet = (from x in AutoRechargeHelper.BlacklistItems.Value.Split(',')
				select x.Trim().ToLowerInvariant() into x
				where !string.IsNullOrWhiteSpace(x)
				select x).ToHashSet();
		}

		internal static bool CanRunInCurrentScene()
		{
			if (SemiFunc.RunIsLobby())
			{
				return true;
			}
			if (AutoRechargeHelper.RunIsMainLevel.Value && SemiFunc.RunIsLevel())
			{
				return true;
			}
			return false;
		}

		internal static bool IsBatteryInTruck(ItemBattery battery)
		{
			//IL_001a: Unknown result type (might be due to invalid IL or missing references)
			if ((Object)(object)battery == (Object)null)
			{
				return false;
			}
			if (SemiFunc.RunIsLobby())
			{
				return true;
			}
			RoomVolume val = default(RoomVolume);
			Vector3 val2 = default(Vector3);
			if (SemiFunc.GetRoomVolumeAtPosition(((Component)battery).transform.position, ref val, ref val2) && (Object)(object)val != (Object)null && val.Truck)
			{
				return true;
			}
			if (TryGetBatteryOwnerAvatar(battery, out PlayerAvatar ownerAvatar))
			{
				if ((Object)(object)ownerAvatar != (Object)null && (Object)(object)ownerAvatar.RoomVolumeCheck != (Object)null)
				{
					return ownerAvatar.RoomVolumeCheck.inTruck;
				}
				return false;
			}
			return false;
		}

		internal static bool TryGetBatteryOwnerAvatar(ItemBattery battery, out PlayerAvatar ownerAvatar)
		{
			ownerAvatar = null;
			if ((Object)(object)battery == (Object)null || (Object)(object)StatsManager.instance == (Object)null || (Object)(object)GameDirector.instance == (Object)null)
			{
				return false;
			}
			ItemAttributes component = ((Component)battery).GetComponent<ItemAttributes>();
			if ((Object)(object)component == (Object)null || string.IsNullOrEmpty(component.instanceName))
			{
				return false;
			}
			int hashCode = component.instanceName.GetHashCode();
			foreach (PlayerAvatar player in GameDirector.instance.PlayerList)
			{
				if (!((Object)(object)player == (Object)null) && !string.IsNullOrEmpty(player.steamID))
				{
					string steamID = player.steamID;
					if (StatsManager.instance.playerInventorySpot1Taken.TryGetValue(steamID, out var value) && value == 1 && StatsManager.instance.playerInventorySpot1.TryGetValue(steamID, out var value2) && value2 == hashCode)
					{
						ownerAvatar = player;
						return true;
					}
					if (StatsManager.instance.playerInventorySpot2Taken.TryGetValue(steamID, out var value3) && value3 == 1 && StatsManager.instance.playerInventorySpot2.TryGetValue(steamID, out var value4) && value4 == hashCode)
					{
						ownerAvatar = player;
						return true;
					}
					if (StatsManager.instance.playerInventorySpot3Taken.TryGetValue(steamID, out var value5) && value5 == 1 && StatsManager.instance.playerInventorySpot3.TryGetValue(steamID, out var value6) && value6 == hashCode)
					{
						ownerAvatar = player;
						return true;
					}
				}
			}
			return false;
		}

		internal static bool IsBlacklisted(string itemName)
		{
			if (string.IsNullOrWhiteSpace(itemName))
			{
				return false;
			}
			string normalized = itemName.Replace("(Clone)", string.Empty).Trim().ToLowerInvariant();
			return _blacklistSet.Any((string bad) => normalized.Contains(bad));
		}

		internal static bool IsMarked(ItemBattery battery)
		{
			if ((Object)(object)battery != (Object)null)
			{
				return Marked.Contains(battery);
			}
			return false;
		}

		internal static bool IsFinished(ItemBattery battery)
		{
			if ((Object)(object)battery != (Object)null)
			{
				return Finished.Contains(battery);
			}
			return false;
		}

		internal static void ClearMarks()
		{
			Marked.Clear();
			Finished.Clear();
			AutoRechargeHelper.LogInfo("[ARH] Cleared all battery marks.");
		}

		internal static void CleanupInvalidEntries()
		{
			Marked.RemoveWhere((ItemBattery b) => (Object)(object)b == (Object)null);
			Finished.RemoveWhere((ItemBattery b) => (Object)(object)b == (Object)null);
		}

		internal static void ScanAndMarkAll()
		{
			if (!SemiFunc.IsMasterClientOrSingleplayer())
			{
				return;
			}
			CleanupInvalidEntries();
			ItemBattery[] array = Object.FindObjectsByType<ItemBattery>((FindObjectsSortMode)0);
			int num = 0;
			ItemBattery[] array2 = array;
			foreach (ItemBattery battery in array2)
			{
				if (CanMark(battery) && MarkBattery(battery))
				{
					num++;
				}
			}
			AutoRechargeHelper.LogInfo($"[ARH] Scan complete. Marked batteries: {num}");
		}

		internal static bool MarkBattery(ItemBattery battery)
		{
			if (!CanMark(battery))
			{
				return false;
			}
			if (Marked.Add(battery))
			{
				AutoRechargeHelper.LogInfo("[ARH] Marked: " + ((Object)battery).name);
				return true;
			}
			return false;
		}

		internal static void UnmarkBattery(ItemBattery battery)
		{
			if (!((Object)(object)battery == (Object)null) && Marked.Remove(battery))
			{
				if (AutoRechargeHelper.FirstTimeOnly.Value)
				{
					Finished.Add(battery);
				}
				AutoRechargeHelper.LogInfo("[ARH] Unmarked: " + ((Object)battery).name);
			}
		}

		public static float SetNextScanTime()
		{
			return _nextScanTime = Time.time + scanIntervalSeconds;
		}

		internal static void Tick()
		{
			if (!AutoRechargeHelper.EnableMod.Value)
			{
				return;
			}
			CleanupInvalidEntries();
			if (Time.time >= _nextScanTime)
			{
				_nextScanTime = SetNextScanTime();
				ScanAndMarkAll();
			}
			if (!AutoRechargeHelper.FirstTimeOnly.Value)
			{
				return;
			}
			foreach (ItemBattery item in Marked.ToList())
			{
				if (!((Object)(object)item == (Object)null) && item.batteryLifeInt >= item.batteryBars)
				{
					UnmarkBattery(item);
				}
			}
		}

		internal static void AddMarkedBatteriesToStation(ChargingStation station)
		{
			if ((Object)(object)station == (Object)null)
			{
				return;
			}
			foreach (ItemBattery item in Marked)
			{
				if (!((Object)(object)item == (Object)null) && (!IsFinished(item) || !AutoRechargeHelper.FirstTimeOnly.Value) && item.batteryLifeInt < item.batteryBars && (!AutoRechargeHelper.ChargeInTruck.Value || IsBatteryInTruck(item)) && !station.itemsCharging.Contains(item))
				{
					station.itemsCharging.Add(item);
				}
			}
		}

		private static bool CanMark(ItemBattery battery)
		{
			if (!AutoRechargeHelper.EnableMod.Value)
			{
				return false;
			}
			if ((Object)(object)battery == (Object)null)
			{
				return false;
			}
			if (IsBlacklisted(((Object)battery).name))
			{
				return false;
			}
			if (AutoRechargeHelper.FirstTimeOnly.Value && Finished.Contains(battery))
			{
				return false;
			}
			if (AutoRechargeHelper.FirstTimeOnly.Value && battery.batteryLifeInt >= battery.batteryBars)
			{
				return false;
			}
			return true;
		}
	}
}
namespace AutoRechargeHelper.Patches
{
	[HarmonyPatch(typeof(ChargingStation))]
	internal static class ChargingStationPatch
	{
		[HarmonyPatch("ChargeAreaCheck")]
		[HarmonyPostfix]
		private static void ChargeAreaCheckPostfix(ChargingStation __instance)
		{
			if (AutoRechargeHelper.EnableMod.Value && SemiFunc.IsMasterClientOrSingleplayer() && AutoRechargeRuntime.CanRunInCurrentScene() && !((Object)(object)__instance == (Object)null) && !(__instance.chargeFloat <= 0f))
			{
				AutoRechargeRuntime.AddMarkedBatteriesToStation(__instance);
			}
		}

		[HarmonyPatch("Update")]
		[HarmonyPostfix]
		private static void UpdatePostfix(ChargingStation __instance)
		{
			if (AutoRechargeHelper.EnableMod.Value && SemiFunc.IsMasterClientOrSingleplayer() && AutoRechargeRuntime.CanRunInCurrentScene() && !((Object)(object)__instance == (Object)null))
			{
				AutoRechargeRuntime.Tick();
			}
		}
	}
	[HarmonyPatch(typeof(SemiFunc), "OnLevelGenDone")]
	internal static class SemiFuncPatch
	{
		[CompilerGenerated]
		private sealed class <DelayedScan>d__1 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <DelayedScan>d__1(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_001d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0027: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>2__current = (object)new WaitForSeconds(1f);
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					if (!AutoRechargeHelper.EnableMod.Value)
					{
						return false;
					}
					if (!SemiFunc.IsMasterClientOrSingleplayer())
					{
						return false;
					}
					AutoRechargeRuntime.ClearMarks();
					AutoRechargeRuntime.ScanAndMarkAll();
					AutoRechargeRuntime.SetNextScanTime();
					return false;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[HarmonyPostfix]
		private static void Postfix()
		{
			if (AutoRechargeHelper.EnableMod.Value && SemiFunc.IsMasterClientOrSingleplayer() && AutoRechargeRuntime.CanRunInCurrentScene())
			{
				((MonoBehaviour)AutoRechargeHelper.Instance).StartCoroutine(DelayedScan());
			}
		}

		[IteratorStateMachine(typeof(<DelayedScan>d__1))]
		private static IEnumerator DelayedScan()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedScan>d__1(0);
		}
	}
}