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 ExitGames.Client.Photon; using HarmonyLib; using MenuLib; using MenuLib.MonoBehaviors; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using TMPro; using UnityEngine; using UnityEngine.UI; [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.5.9.0")] [assembly: AssemblyInformationalVersion("1.5.9")] [assembly: AssemblyProduct("CheckoutStatsTW")] [assembly: AssemblyTitle("CheckoutStatsTW")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.5.9.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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] [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] [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.9")] 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__25_0; public static ScrollViewBuilderDelegate <>9__25_1; public static Action <>9__25_4; public static Action <>9__25_5; public static BuilderDelegate <>9__25_2; internal RectTransform b__25_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; ApplyTraditionalChineseFont((TMP_Text)(object)labelTMP); ((TMP_Text)labelTMP).text = "玩家 價值 擊殺 損壞 死"; ((TMP_Text)labelTMP).fontSize = 16f; ((TMP_Text)labelTMP).fontStyle = (FontStyles)1; return ((REPOElement)obj).rectTransform; } internal RectTransform b__25_1(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) REPOLabel obj = MenuAPI.CreateREPOLabel("目前尚無數據錄入...", parent, Vector2.zero); ApplyTraditionalChineseFont((TMP_Text)(object)obj.labelTMP); ((TMP_Text)obj.labelTMP).alignment = (TextAlignmentOptions)514; return ((REPOElement)obj).rectTransform; } internal void b__25_2(Transform parent) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) Component val = (Component)(object)MenuAPI.CreateREPOButton("清除數據", (Action)delegate { ClearAllStats(); Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除"); }, parent, new Vector2(-120f, -180f)); if (val != null) { ApplyTraditionalChineseFont(val.gameObject); } Component val2 = (Component)(object)MenuAPI.CreateREPOButton("關閉視窗", (Action)delegate { ShowStatsUI = false; if ((Object)(object)StatsPopup != (Object)null) { StatsPopup.ClosePage(true); } }, parent, new Vector2(120f, -180f)); if (val2 != null) { ApplyTraditionalChineseFont(val2.gameObject); } } internal void b__25_4() { ClearAllStats(); Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除"); } internal void b__25_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 CurrentStats = new Dictionary(); public static Dictionary EnemyLastHitBy = new Dictionary(); public static HashSet HauledObjects = new HashSet(); public static Dictionary PlayerNames = new Dictionary(); public static bool ShowStatsUI = false; public static REPOPopupPage? StatsPopup; public static StatsSync? SyncComponent; private static TMP_FontAsset? TraditionalChineseFont; public static CheckoutStatsPlugin Instance { get; private set; } = null; public static ManualLogSource Logger { get; private set; } = null; private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Expected O, but got Unknown Instance = this; Logger = ((BaseUnityPlugin)this).Logger; InitializeTraditionalChineseFontSupport(); GameObject val = new GameObject("CheckoutStatsSyncObject"); Object.DontDestroyOnLoad((Object)val); SyncComponent = val.AddComponent(); 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.9 已載入"); } private static void InitializeTraditionalChineseFontSupport() { try { Font val = Font.CreateDynamicFontFromOSFont(new string[7] { "Microsoft JhengHei UI", "Microsoft JhengHei", "Noto Sans CJK TC", "Noto Sans TC", "PingFang TC", "Heiti TC", "Arial Unicode MS" }, 20); if ((Object)(object)val == (Object)null) { Logger.LogWarning((object)"[CheckoutStatsTW] 找不到可用的繁中文字型,將使用遊戲預設字型"); return; } TraditionalChineseFont = TMP_FontAsset.CreateFontAsset(val); ((Object)TraditionalChineseFont).name = "CheckoutStatsTW Traditional Chinese Font"; TraditionalChineseFont.atlasPopulationMode = (AtlasPopulationMode)1; Logger.LogInfo((object)("[CheckoutStatsTW] 已啟用內建繁中字型支援: " + ((Object)val).name)); } catch (Exception ex) { Logger.LogWarning((object)("[CheckoutStatsTW] 繁中字型初始化失敗,將使用遊戲預設字型: " + ex.Message)); } } private static void ApplyTraditionalChineseFont(TMP_Text text) { if (!((Object)(object)text == (Object)null) && !((Object)(object)TraditionalChineseFont == (Object)null)) { text.font = TraditionalChineseFont; ((Graphic)text).SetAllDirty(); } } private static void ApplyTraditionalChineseFont(GameObject root) { if (!((Object)(object)root == (Object)null) && !((Object)(object)TraditionalChineseFont == (Object)null)) { TMP_Text[] componentsInChildren = root.GetComponentsInChildren(true); for (int i = 0; i < componentsInChildren.Length; i++) { ApplyTraditionalChineseFont(componentsInChildren[i]); } } } private static string TrimPlayerName(string playerName) { if (string.IsNullOrWhiteSpace(playerName)) { return "Player"; } if (playerName.Length > 12) { return playerName.Substring(0, 11) + "."; } return playerName; } private static string FormatStatsRow(PlayerStats s) { string text = TrimPlayerName(s.PlayerName); return $"{text,-12} ${s.HaulValue,6} {s.Kills,4} ${s.DamageValue,5} {s.Deaths,3}"; } 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__25_0; if (obj == null) { ScrollViewBuilderDelegate val = delegate(Transform parent) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) REPOLabel obj4 = MenuAPI.CreateREPOLabel("", parent, Vector2.zero); TextMeshProUGUI labelTMP = obj4.labelTMP; ApplyTraditionalChineseFont((TMP_Text)(object)labelTMP); ((TMP_Text)labelTMP).text = "玩家 價值 擊殺 損壞 死"; ((TMP_Text)labelTMP).fontSize = 16f; ((TMP_Text)labelTMP).fontStyle = (FontStyles)1; return ((REPOElement)obj4).rectTransform; }; <>c.<>9__25_0 = val; obj = (object)val; } statsPopup.AddElementToScrollView((ScrollViewBuilderDelegate)obj, 0f, 0f); if (CurrentStats.Count == 0) { REPOPopupPage? statsPopup2 = StatsPopup; object obj2 = <>c.<>9__25_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); ApplyTraditionalChineseFont((TMP_Text)(object)obj4.labelTMP); ((TMP_Text)obj4.labelTMP).alignment = (TextAlignmentOptions)514; return ((REPOElement)obj4).rectTransform; }; <>c.<>9__25_1 = val2; obj2 = (object)val2; } statsPopup2.AddElementToScrollView((ScrollViewBuilderDelegate)obj2, 0f, 0f); } else { foreach (KeyValuePair 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 obj4 = MenuAPI.CreateREPOLabel("", parent, Vector2.zero); TextMeshProUGUI labelTMP = obj4.labelTMP; ApplyTraditionalChineseFont((TMP_Text)(object)labelTMP); ((TMP_Text)labelTMP).text = FormatStatsRow(s); ((TMP_Text)labelTMP).fontSize = 15f; return ((REPOElement)obj4).rectTransform; }, 0f, 0f); } } REPOPopupPage? statsPopup3 = StatsPopup; object obj3 = <>c.<>9__25_2; if (obj3 == null) { BuilderDelegate val3 = delegate(Transform parent) { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) Component val4 = (Component)(object)MenuAPI.CreateREPOButton("清除數據", (Action)delegate { ClearAllStats(); Logger.LogInfo((object)"[CheckoutStatsTW] 統計數據已手動清除"); }, parent, new Vector2(-120f, -180f)); if (val4 != null) { ApplyTraditionalChineseFont(val4.gameObject); } Component val5 = (Component)(object)MenuAPI.CreateREPOButton("關閉視窗", (Action)delegate { ShowStatsUI = false; if ((Object)(object)StatsPopup != (Object)null) { StatsPopup.ClosePage(true); } }, parent, new Vector2(120f, -180f)); if (val5 != null) { ApplyTraditionalChineseFont(val5.gameObject); } }; <>c.<>9__25_2 = val3; obj3 = (object)val3; } statsPopup3.AddElement((BuilderDelegate)obj3); StatsPopup.OpenPage(true); MenuPage component = ((Component)StatsPopup).GetComponent(); 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, IOnEventCallback { private const byte StatDeltaEventCode = 171; private void OnEnable() { PhotonNetwork.AddCallbackTarget((object)this); } private void OnDisable() { PhotonNetwork.RemoveCallbackTarget((object)this); } public void SubmitStatDelta(string steamId, string playerName, string statType, int delta) { if (!string.IsNullOrEmpty(steamId) && delta != 0) { if (!PhotonNetwork.IsConnected) { ApplyDelta(steamId, playerName, statType, delta); } else if (CheckoutStatsPlugin.IsMasterClient()) { ApplyDelta(steamId, playerName, statType, delta); RaiseStatDelta((ReceiverGroup)0, steamId, playerName, statType, delta); } else { RaiseStatDelta((ReceiverGroup)2, steamId, playerName, statType, delta); } } } public void OnEvent(EventData photonEvent) { if (photonEvent.Code != 171 || !(photonEvent.CustomData is object[] array) || array.Length != 4) { return; } string text = (array[0] as string) ?? ""; string playerName = (array[1] as string) ?? "Player"; string statType = (array[2] as string) ?? ""; int num = ((array[3] is int num2) ? num2 : 0); if (!string.IsNullOrEmpty(text) && num != 0) { if (CheckoutStatsPlugin.IsMasterClient()) { ApplyDelta(text, playerName, statType, num); RaiseStatDelta((ReceiverGroup)0, text, playerName, statType, num); } else { ApplyDelta(text, playerName, statType, num); } } } private static void RaiseStatDelta(ReceiverGroup receivers, string steamId, string playerName, string statType, int delta) { //IL_001d: 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) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Expected O, but got Unknown //IL_0031: Unknown result type (might be due to invalid IL or missing references) try { object[] array = new object[4] { steamId, playerName, statType, delta }; RaiseEventOptions val = new RaiseEventOptions { Receivers = receivers }; PhotonNetwork.RaiseEvent((byte)171, (object)array, val, SendOptions.SendReliable); } catch (Exception ex) { CheckoutStatsPlugin.Logger.LogWarning((object)("[CheckoutStatsTW] 統計同步事件送出失敗: " + ex.Message)); } } 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() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } 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) { if (!CheckoutStatsPlugin.IsMasterClient()) { return; } try { string text = SemiFunc.PlayerGetSteamID(__instance); if (!string.IsNullOrEmpty(text)) { string value; string playerName = (CheckoutStatsPlugin.PlayerNames.TryGetValue(text, out value) ? value : "Player"); CheckoutStatsPlugin.SyncComponent?.SubmitStatDelta(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) { if (!CheckoutStatsPlugin.IsMasterClient()) { return; } 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"); CheckoutStatsPlugin.SyncComponent?.SubmitStatDelta(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()); 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 { Count: >0 } list) { 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?.SubmitStatDelta(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) { if (!CheckoutStatsPlugin.IsMasterClient()) { return; } try { if (!_loseValue || valueLost <= 0f) { return; } PhysGrabObject component = ((Component)__instance).GetComponent(); 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 { Count: >0 } list) { val = list[0]?.playerAvatar; } if (!((Object)(object)val == (Object)null)) { 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); CheckoutStatsPlugin.SyncComponent?.SubmitStatDelta(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.9"; } }