Decompiled source of CheckoutStatsTW v1.5.6

CheckoutStatsTW.dll

Decompiled 4 hours ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Logging;
using HarmonyLib;
using MenuLib;
using MenuLib.MonoBehaviors;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using TMPro;
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("CheckoutStatsTW")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("在結帳時顯示所有玩家的詳細表現統計。")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0")]
[assembly: AssemblyProduct("CheckoutStatsTW")]
[assembly: AssemblyTitle("CheckoutStatsTW")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.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 CheckoutStatsTW
{
	[BepInPlugin("com.wuzuan.repo.checkoutstatstw", "CheckoutStatsTW", "1.5.6")]
	public class CheckoutStatsPlugin : BaseUnityPlugin
	{
		public class PlayerStats
		{
			public string PlayerName = "Player";

			public int HaulValue;

			public int Kills;

			public int DamageValue;

			public int Deaths;
		}

		[Serializable]
		[CompilerGenerated]
		private sealed class <>c
		{
			public static readonly <>c <>9 = new <>c();

			public static ScrollViewBuilderDelegate <>9__19_0;

			public static ScrollViewBuilderDelegate <>9__19_1;

			public static Action <>9__19_4;

			public static Action <>9__19_5;

			public static BuilderDelegate <>9__19_2;

			internal RectTransform <OpenMenuLibPopup>b__19_0(Transform parent)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				REPOLabel obj = MenuAPI.CreateREPOLabel("", parent, Vector2.zero);
				TextMeshProUGUI labelTMP = obj.labelTMP;
				((TMP_Text)labelTMP).text = "<color=#A347FF>玩家</color> | <color=#47FF47>價值</color> | <color=#FFFF47>擊殺</color> | <color=#FF4747>損壞</color> | <color=#FF8C47>死亡</color>";
				((TMP_Text)labelTMP).fontSize = 18f;
				((TMP_Text)labelTMP).fontStyle = (FontStyles)1;
				return ((REPOElement)obj).rectTransform;
			}

			internal RectTransform <OpenMenuLibPopup>b__19_1(Transform parent)
			{
				//IL_0006: Unknown result type (might be due to invalid IL or missing references)
				REPOLabel obj = MenuAPI.CreateREPOLabel("目前尚無數據錄入...", parent, Vector2.zero);
				((TMP_Text)obj.labelTMP).alignment = (TextAlignmentOptions)514;
				return ((REPOElement)obj).rectTransform;
			}

			internal void <OpenMenuLibPopup>b__19_2(Transform parent)
			{
				//IL_002f: Unknown result type (might be due to invalid IL or missing references)
				//IL_0069: Unknown result type (might be due to invalid IL or missing references)
				MenuAPI.CreateREPOButton("清除數據", (Action)delegate
				{
					ClearAllStats();
					Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除");
				}, parent, new Vector2(-120f, -180f));
				MenuAPI.CreateREPOButton("關閉視窗", (Action)delegate
				{
					ShowStatsUI = false;
					if ((Object)(object)StatsPopup != (Object)null)
					{
						StatsPopup.ClosePage(true);
					}
				}, parent, new Vector2(120f, -180f));
			}

			internal void <OpenMenuLibPopup>b__19_4()
			{
				ClearAllStats();
				Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除");
			}

			internal void <OpenMenuLibPopup>b__19_5()
			{
				ShowStatsUI = false;
				if ((Object)(object)StatsPopup != (Object)null)
				{
					StatsPopup.ClosePage(true);
				}
			}
		}

		private readonly Harmony _harmony = new Harmony("com.wuzuan.repo.checkoutstatstw");

		public static Dictionary<string, PlayerStats> CurrentStats = new Dictionary<string, PlayerStats>();

		public static Dictionary<int, string> EnemyLastHitBy = new Dictionary<int, string>();

		public static HashSet<int> HauledObjects = new HashSet<int>();

		public static Dictionary<string, string> PlayerNames = new Dictionary<string, string>();

		public static bool ShowStatsUI = false;

		public static REPOPopupPage? StatsPopup;

		public static StatsSync? SyncComponent;

		public static CheckoutStatsPlugin Instance { get; private set; } = null;


		public static ManualLogSource Logger { get; private set; } = null;


		private void Awake()
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001b: Unknown result type (might be due to invalid IL or missing references)
			//IL_0021: Expected O, but got Unknown
			Instance = this;
			Logger = ((BaseUnityPlugin)this).Logger;
			GameObject val = new GameObject("CheckoutStatsSyncObject");
			Object.DontDestroyOnLoad((Object)val);
			SyncComponent = val.AddComponent<StatsSync>();
			SafePatch(typeof(Patch_PlayerAvatar_Register));
			SafePatch(typeof(Patch_PlayerAvatar_Death));
			SafePatch(typeof(Patch_EnemyHealth_HurtRPC));
			SafePatch(typeof(Patch_EnemyHealth_Death));
			SafePatch(typeof(Patch_ValuableObject_AddToHaulList));
			SafePatch(typeof(Patch_PhysGrabObject_BreakRPC));
			SafePatch(typeof(Patch_RunManager_ChangeLevel));
			SafePatch(typeof(Patch_RunManager_LeaveToMainMenu));
			SafePatch(typeof(Patch_RunManager_RestartRun));
			SafePatch(typeof(Patch_GameDirector_InputHook));
			Logger.LogInfo((object)"[CheckoutStatsTW] v1.5.6 已載入");
		}

		public static void ClearAllStats()
		{
			CurrentStats.Clear();
			EnemyLastHitBy.Clear();
			HauledObjects.Clear();
			PlayerNames.Clear();
			if ((Object)(object)StatsPopup != (Object)null)
			{
				StatsPopup.ClosePage(true);
				StatsPopup = null;
			}
			ShowStatsUI = false;
		}

		public static void OpenMenuLibPopup()
		{
			//IL_0034: Unknown result type (might be due to invalid IL or missing references)
			//IL_0073: 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_007e: Expected O, but got Unknown
			//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
			//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
			//IL_00bd: Expected O, but got Unknown
			//IL_0102: Unknown result type (might be due to invalid IL or missing references)
			//IL_0116: Expected O, but got Unknown
			//IL_0148: Unknown result type (might be due to invalid IL or missing references)
			//IL_014d: Unknown result type (might be due to invalid IL or missing references)
			//IL_0153: Expected O, but got Unknown
			try
			{
				if ((Object)(object)StatsPopup != (Object)null && ((Component)StatsPopup).gameObject.activeSelf)
				{
					return;
				}
				MenuAPI.CloseAllPagesAddedOnTop();
				StatsPopup = MenuAPI.CreateREPOPopupPage("本局結算統計", true, true, 0f, (Vector2?)Vector2.zero);
				if ((Object)(object)StatsPopup == (Object)null)
				{
					return;
				}
				REPOPopupPage? statsPopup = StatsPopup;
				object obj = <>c.<>9__19_0;
				if (obj == null)
				{
					ScrollViewBuilderDelegate val = delegate(Transform parent)
					{
						//IL_0006: Unknown result type (might be due to invalid IL or missing references)
						REPOLabel obj5 = MenuAPI.CreateREPOLabel("", parent, Vector2.zero);
						TextMeshProUGUI labelTMP2 = obj5.labelTMP;
						((TMP_Text)labelTMP2).text = "<color=#A347FF>玩家</color> | <color=#47FF47>價值</color> | <color=#FFFF47>擊殺</color> | <color=#FF4747>損壞</color> | <color=#FF8C47>死亡</color>";
						((TMP_Text)labelTMP2).fontSize = 18f;
						((TMP_Text)labelTMP2).fontStyle = (FontStyles)1;
						return ((REPOElement)obj5).rectTransform;
					};
					<>c.<>9__19_0 = val;
					obj = (object)val;
				}
				statsPopup.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 0f);
				if (CurrentStats.Count == 0)
				{
					REPOPopupPage? statsPopup2 = StatsPopup;
					object obj2 = <>c.<>9__19_1;
					if (obj2 == null)
					{
						ScrollViewBuilderDelegate val2 = delegate(Transform parent)
						{
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							REPOLabel obj4 = MenuAPI.CreateREPOLabel("目前尚無數據錄入...", parent, Vector2.zero);
							((TMP_Text)obj4.labelTMP).alignment = (TextAlignmentOptions)514;
							return ((REPOElement)obj4).rectTransform;
						};
						<>c.<>9__19_1 = val2;
						obj2 = (object)val2;
					}
					statsPopup2.AddElementToScrollView((ScrollViewBuilderDelegate)obj2, 0f, 0f);
				}
				else
				{
					foreach (KeyValuePair<string, PlayerStats> currentStat in CurrentStats)
					{
						PlayerStats s = currentStat.Value;
						StatsPopup.AddElementToScrollView((ScrollViewBuilderDelegate)delegate(Transform parent)
						{
							//IL_0006: Unknown result type (might be due to invalid IL or missing references)
							REPOLabel val4 = MenuAPI.CreateREPOLabel("", parent, Vector2.zero);
							TMP_Text labelTMP = (TMP_Text)(object)val4.labelTMP;
							labelTMP.text = $"{s.PlayerName,-10} | <color=#47FF47>${s.HaulValue,5}</color> | <color=#FFFF47>{s.Kills,3}</color> | <color=#FF4747>${s.DamageValue,4}</color> | <color=#FF8C47>{s.Deaths,2}</color>";
							labelTMP.fontSize = 16f;
							return ((REPOElement)val4).rectTransform;
						}, 0f, 0f);
					}
				}
				REPOPopupPage? statsPopup3 = StatsPopup;
				object obj3 = <>c.<>9__19_2;
				if (obj3 == null)
				{
					BuilderDelegate val3 = delegate(Transform parent)
					{
						//IL_002f: Unknown result type (might be due to invalid IL or missing references)
						//IL_0069: Unknown result type (might be due to invalid IL or missing references)
						MenuAPI.CreateREPOButton("清除數據", (Action)delegate
						{
							ClearAllStats();
							Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除");
						}, parent, new Vector2(-120f, -180f));
						MenuAPI.CreateREPOButton("關閉視窗", (Action)delegate
						{
							ShowStatsUI = false;
							if ((Object)(object)StatsPopup != (Object)null)
							{
								StatsPopup.ClosePage(true);
							}
						}, parent, new Vector2(120f, -180f));
					};
					<>c.<>9__19_2 = val3;
					obj3 = (object)val3;
				}
				statsPopup3.AddElement((BuilderDelegate)obj3);
				StatsPopup.OpenPage(true);
				MenuPage component = ((Component)StatsPopup).GetComponent<MenuPage>();
				if ((Object)(object)component != (Object)null)
				{
					component.PageStateSet((PageState)1);
				}
			}
			catch (Exception arg)
			{
				Logger.LogError((object)$"[CheckoutStatsTW] UI 建立失敗: {arg}");
			}
		}

		private void SafePatch(Type patchClass)
		{
			try
			{
				_harmony.PatchAll(patchClass);
				Logger.LogInfo((object)("[CheckoutStatsTW] Patch 成功: " + patchClass.Name));
			}
			catch (Exception ex)
			{
				Logger.LogWarning((object)("[CheckoutStatsTW] Patch 失敗: " + patchClass.Name + " -> " + ex.Message));
			}
		}

		public static PlayerStats GetOrCreate(string steamId)
		{
			if (!CurrentStats.TryGetValue(steamId, out PlayerStats value))
			{
				value = new PlayerStats();
				if (PlayerNames.TryGetValue(steamId, out string value2))
				{
					value.PlayerName = value2;
				}
				CurrentStats[steamId] = value;
			}
			return value;
		}

		public static bool IsMasterClient()
		{
			try
			{
				return PhotonNetwork.IsMasterClient;
			}
			catch
			{
				return true;
			}
		}
	}
	public class StatsSync : MonoBehaviour
	{
		public void BroadcastStatDelta(string steamId, string playerName, string statType, int delta)
		{
			if (!CheckoutStatsPlugin.IsMasterClient())
			{
				return;
			}
			ApplyDelta(steamId, playerName, statType, delta);
			try
			{
				PhotonView component = ((Component)this).GetComponent<PhotonView>();
				if ((Object)(object)component != (Object)null && PhotonNetwork.IsConnected)
				{
					component.RPC("ReceiveStatDelta", (RpcTarget)1, new object[4] { steamId, playerName, statType, delta });
				}
			}
			catch
			{
			}
		}

		[PunRPC]
		public void ReceiveStatDelta(string steamId, string playerName, string statType, int delta)
		{
			ApplyDelta(steamId, playerName, statType, delta);
		}

		public static void ApplyDelta(string steamId, string playerName, string statType, int delta)
		{
			CheckoutStatsPlugin.PlayerStats orCreate = CheckoutStatsPlugin.GetOrCreate(steamId);
			if (!string.IsNullOrEmpty(playerName))
			{
				orCreate.PlayerName = playerName;
			}
			switch (statType)
			{
			case "haul":
				orCreate.HaulValue += delta;
				break;
			case "kill":
				orCreate.Kills += delta;
				break;
			case "damage":
				orCreate.DamageValue += delta;
				break;
			case "death":
				orCreate.Deaths += delta;
				break;
			}
		}
	}
	[HarmonyPatch(typeof(GameDirector), "Update")]
	public static class Patch_GameDirector_InputHook
	{
		[HarmonyPostfix]
		private static void Postfix(GameDirector __instance)
		{
			if ((Object)(object)((Component)__instance).GetComponent<InputDebugger>() == (Object)null)
			{
				((Component)__instance).gameObject.AddComponent<InputDebugger>();
			}
		}
	}
	public class InputDebugger : MonoBehaviour
	{
		private void Update()
		{
			if (Input.GetKeyDown((KeyCode)292))
			{
				ExecuteToggle();
			}
		}

		private void ExecuteToggle()
		{
			CheckoutStatsPlugin.ShowStatsUI = !CheckoutStatsPlugin.ShowStatsUI;
			if (CheckoutStatsPlugin.ShowStatsUI)
			{
				CheckoutStatsPlugin.OpenMenuLibPopup();
			}
			else if ((Object)(object)CheckoutStatsPlugin.StatsPopup != (Object)null)
			{
				CheckoutStatsPlugin.StatsPopup.ClosePage(true);
				CheckoutStatsPlugin.StatsPopup = null;
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "AddToStatsManagerRPC")]
	public static class Patch_PlayerAvatar_Register
	{
		[HarmonyPostfix]
		private static void Postfix(string _playerName, string _steamID)
		{
			if (!string.IsNullOrEmpty(_steamID))
			{
				CheckoutStatsPlugin.PlayerNames[_steamID] = _playerName;
				if (CheckoutStatsPlugin.CurrentStats.TryGetValue(_steamID, out CheckoutStatsPlugin.PlayerStats value))
				{
					value.PlayerName = _playerName;
				}
			}
		}
	}
	[HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")]
	public static class Patch_PlayerAvatar_Death
	{
		[HarmonyPostfix]
		private static void Postfix(PlayerAvatar __instance)
		{
			try
			{
				string text = SemiFunc.PlayerGetSteamID(__instance);
				if (!string.IsNullOrEmpty(text))
				{
					string value;
					string playerName = (CheckoutStatsPlugin.PlayerNames.TryGetValue(text, out value) ? value : "Player");
					if (CheckoutStatsPlugin.IsMasterClient())
					{
						CheckoutStatsPlugin.SyncComponent?.BroadcastStatDelta(text, playerName, "death", 1);
					}
					else
					{
						StatsSync.ApplyDelta(text, playerName, "death", 1);
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(EnemyHealth), "HurtRPC")]
	public static class Patch_EnemyHealth_HurtRPC
	{
		[HarmonyPostfix]
		private static void Postfix(EnemyHealth __instance)
		{
			try
			{
				PlayerAvatar val = TryGetAttacker(__instance);
				if (!((Object)(object)val == (Object)null))
				{
					string value = SemiFunc.PlayerGetSteamID(val);
					if (!string.IsNullOrEmpty(value))
					{
						CheckoutStatsPlugin.EnemyLastHitBy[((Object)__instance).GetInstanceID()] = value;
					}
				}
			}
			catch
			{
			}
		}

		private static PlayerAvatar? TryGetAttacker(EnemyHealth health)
		{
			string[] array = new string[6] { "killedByPlayer", "lastHurtByPlayer", "culpritPlayer", "CulpritPlayer", "lastAttacker", "hurtByPlayer" };
			foreach (string name in array)
			{
				object? obj = typeof(EnemyHealth).GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(health);
				PlayerAvatar val = (PlayerAvatar)((obj is PlayerAvatar) ? obj : null);
				if (val != null)
				{
					return val;
				}
			}
			object? obj2 = typeof(EnemyHealth).GetField("enemy", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(health);
			Enemy val2 = (Enemy)((obj2 is Enemy) ? obj2 : null);
			if (val2 != null)
			{
				array = new string[4] { "CulpritPlayer", "culpritPlayer", "lastAttacker", "hurtByPlayer" };
				foreach (string name2 in array)
				{
					object? obj3 = typeof(Enemy).GetField(name2, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val2);
					PlayerAvatar val3 = (PlayerAvatar)((obj3 is PlayerAvatar) ? obj3 : null);
					if (val3 != null)
					{
						return val3;
					}
				}
			}
			return null;
		}
	}
	[HarmonyPatch(typeof(EnemyHealth), "Death")]
	public static class Patch_EnemyHealth_Death
	{
		[HarmonyPostfix]
		private static void Postfix(EnemyHealth __instance)
		{
			try
			{
				int instanceID = ((Object)__instance).GetInstanceID();
				if (CheckoutStatsPlugin.EnemyLastHitBy.TryGetValue(instanceID, out string value))
				{
					string value2;
					string playerName = (CheckoutStatsPlugin.PlayerNames.TryGetValue(value, out value2) ? value2 : "Player");
					if (CheckoutStatsPlugin.IsMasterClient())
					{
						CheckoutStatsPlugin.SyncComponent?.BroadcastStatDelta(value, playerName, "kill", 1);
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(ValuableObject), "AddToDollarHaulList")]
	public static class Patch_ValuableObject_AddToHaulList
	{
		private static readonly string[] ExcludeKeywords = new string[1] { "surplus valuable" };

		[HarmonyPostfix]
		private static void Postfix(ValuableObject __instance)
		{
			if (!CheckoutStatsPlugin.IsMasterClient())
			{
				return;
			}
			try
			{
				int num = Mathf.RoundToInt(Traverse.Create((object)__instance).Field("dollarValueCurrent").GetValue<float>());
				if (num <= 0)
				{
					return;
				}
				string text = ((Object)((Component)__instance).gameObject).name.ToLower().Replace("(clone)", "").Trim();
				string[] excludeKeywords = ExcludeKeywords;
				foreach (string value in excludeKeywords)
				{
					if (text.Contains(value))
					{
						CheckoutStatsPlugin.Logger.LogInfo((object)$"[CheckoutStatsTW] 跳過錢袋: '{((Object)((Component)__instance).gameObject).name}' (${num})");
						return;
					}
				}
				int instanceID = ((Object)__instance).GetInstanceID();
				if (CheckoutStatsPlugin.HauledObjects.Contains(instanceID))
				{
					return;
				}
				CheckoutStatsPlugin.HauledObjects.Add(instanceID);
				PlayerAvatar val = null;
				object? obj = typeof(ValuableObject).GetField("physGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(__instance);
				PhysGrabObject val2 = (PhysGrabObject)((obj is PhysGrabObject) ? obj : null);
				if (val2 != null && typeof(PhysGrabObject).GetField("playerGrabbing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(val2) is List<PhysGrabber> list && list.Count > 0)
				{
					val = list[0]?.playerAvatar;
				}
				if ((Object)(object)val == (Object)null)
				{
					val = PlayerAvatar.instance;
				}
				if (!((Object)(object)val == (Object)null))
				{
					string text2 = SemiFunc.PlayerGetSteamID(val);
					if (!string.IsNullOrEmpty(text2))
					{
						string value2;
						string playerName = (CheckoutStatsPlugin.PlayerNames.TryGetValue(text2, out value2) ? value2 : "Player");
						CheckoutStatsPlugin.SyncComponent?.BroadcastStatDelta(text2, playerName, "haul", num);
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "BreakRPC")]
	public static class Patch_PhysGrabObject_BreakRPC
	{
		[HarmonyPostfix]
		private static void Postfix(PhysGrabObjectImpactDetector __instance, float valueLost, bool _loseValue)
		{
			try
			{
				if (!_loseValue || valueLost <= 0f)
				{
					return;
				}
				PhysGrabObject component = ((Component)__instance).GetComponent<PhysGrabObject>();
				if ((Object)(object)component == (Object)null)
				{
					return;
				}
				PlayerAvatar val = null;
				if (typeof(PhysGrabObject).GetField("playerGrabbing", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(component) is List<PhysGrabber> list && list.Count > 0)
				{
					val = list[0]?.playerAvatar;
				}
				if ((Object)(object)val == (Object)null)
				{
					return;
				}
				string text = SemiFunc.PlayerGetSteamID(val);
				if (!string.IsNullOrEmpty(text))
				{
					string value;
					string playerName = (CheckoutStatsPlugin.PlayerNames.TryGetValue(text, out value) ? value : "Player");
					int delta = Mathf.RoundToInt(valueLost);
					if (CheckoutStatsPlugin.IsMasterClient())
					{
						CheckoutStatsPlugin.SyncComponent?.BroadcastStatDelta(text, playerName, "damage", delta);
					}
					else
					{
						StatsSync.ApplyDelta(text, playerName, "damage", delta);
					}
				}
			}
			catch
			{
			}
		}
	}
	[HarmonyPatch(typeof(RunManager), "ChangeLevel")]
	public static class Patch_RunManager_ChangeLevel
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			if (SemiFunc.RunIsShop())
			{
				CheckoutStatsPlugin.OpenMenuLibPopup();
			}
		}
	}
	[HarmonyPatch(typeof(RunManager), "LeaveToMainMenu")]
	public static class Patch_RunManager_LeaveToMainMenu
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			CheckoutStatsPlugin.Logger.LogInfo((object)"[CheckoutStatsTW] 回主選單,清空所有統計資料");
			CheckoutStatsPlugin.ClearAllStats();
		}
	}
	[HarmonyPatch(typeof(RunManager), "RestartRun")]
	public static class Patch_RunManager_RestartRun
	{
		[HarmonyPrefix]
		private static void Prefix()
		{
			CheckoutStatsPlugin.Logger.LogInfo((object)"[CheckoutStatsTW] RestartRun,清空所有統計資料");
			CheckoutStatsPlugin.ClearAllStats();
		}
	}
	public class PluginInfo
	{
		public const string PLUGIN_GUID = "com.wuzuan.repo.checkoutstatstw";

		public const string PLUGIN_NAME = "CheckoutStatsTW";

		public const string PLUGIN_VERSION = "1.5.6";
	}
}