using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using FishNet; using FishNet.Managing.Timing; using FishNet.Object; using FishNet.Object.Delegating; using FishNet.Object.Synchronizing; using FishNet.Object.Synchronizing.Internal; using FishNet.Serializing; using FishNet.Transporting; using HarmonyLib; using Newtonsoft.Json; 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("BetterCorpses")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("更好的尸体:玩家尸体可卖钱/赌博/抽奖,复活强制等待 + 拍活吃尸体")] [assembly: AssemblyFileVersion("1.2.4.0")] [assembly: AssemblyInformationalVersion("1.2.4")] [assembly: AssemblyProduct("BetterCorpses")] [assembly: AssemblyTitle("BetterCorpses")] [assembly: AssemblyVersion("1.2.4.0")] namespace BetterCorpses; public static class Config { public static ConfigEntry Master; public static ConfigEntry RespawnTime; public static ConfigEntry CorpseDrop; public static ConfigEntry Sell; public static ConfigEntry Gamble; public static ConfigEntry Lottery; public static ConfigEntry Cannibal; public static ConfigEntry CannibalChance; public static ConfigEntry ForcedWaitSeconds; public static ConfigEntry GiveUpHoldSeconds; public static ConfigEntry PriceMin; public static ConfigEntry PriceMax; public static bool RespawnOn { get { if (Master.Value) { return RespawnTime.Value; } return false; } } public static bool EconomyOn { get { if (Master.Value) { return CorpseDrop.Value; } return false; } } public static bool SellOn { get { if (EconomyOn) { return Sell.Value; } return false; } } public static bool GambleOn { get { if (EconomyOn) { return Gamble.Value; } return false; } } public static bool LotteryOn { get { if (EconomyOn) { return Lottery.Value; } return false; } } public static bool CannibalOn { get { if (Master.Value) { return Cannibal.Value; } return false; } } public static void Init(BaseUnityPlugin plugin) { //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_016e: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Expected O, but got Unknown //IL_01b0: Unknown result type (might be due to invalid IL or missing references) //IL_01ba: Expected O, but got Unknown //IL_01ef: Unknown result type (might be due to invalid IL or missing references) //IL_01f9: Expected O, but got Unknown //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_0238: Expected O, but got Unknown Master = plugin.Config.Bind("General", "Master", true, Loc.Get("cfg.Master")); RespawnTime = plugin.Config.Bind("General", "RespawnTime", true, Loc.Get("cfg.RespawnTime")); CorpseDrop = plugin.Config.Bind("General", "CorpseDrop", true, Loc.Get("cfg.CorpseDrop")); Sell = plugin.Config.Bind("General", "Sell", true, Loc.Get("cfg.Sell")); Gamble = plugin.Config.Bind("General", "Gamble", true, Loc.Get("cfg.Gamble")); Lottery = plugin.Config.Bind("General", "Lottery", true, Loc.Get("cfg.Lottery")); Cannibal = plugin.Config.Bind("General", "Cannibal", true, Loc.Get("cfg.Cannibal")); CannibalChance = plugin.Config.Bind("General", "CannibalChance", 50, new ConfigDescription(Loc.Get("cfg.CannibalChance"), (AcceptableValueBase)(object)new AcceptableValueRange(0, 100), Array.Empty())); ForcedWaitSeconds = plugin.Config.Bind("Respawn", "ForcedWaitSeconds", 5f, new ConfigDescription(Loc.Get("cfg.ForcedWaitSeconds"), (AcceptableValueBase)(object)new AcceptableValueRange(0f, 600f), Array.Empty())); GiveUpHoldSeconds = plugin.Config.Bind("Respawn", "GiveUpHoldSeconds", 1f, new ConfigDescription(Loc.Get("cfg.GiveUpHoldSeconds"), (AcceptableValueBase)(object)new AcceptableValueRange(0f, 60f), Array.Empty())); PriceMin = plugin.Config.Bind("Economy", "PriceMin", -50, new ConfigDescription(Loc.Get("cfg.PriceMin"), (AcceptableValueBase)(object)new AcceptableValueRange(-10000, 10000), Array.Empty())); PriceMax = plugin.Config.Bind("Economy", "PriceMax", 50, new ConfigDescription(Loc.Get("cfg.PriceMax"), (AcceptableValueBase)(object)new AcceptableValueRange(-10000, 10000), Array.Empty())); } } internal static class AutoRespawn { private class Pending { public Player Player; public float FireTime; public Vector3 Pos; public Quaternion Rot; } private const float DelaySeconds = 1f; private static readonly List _pending = new List(); public static void Schedule(Player player, Vector3 pos, Quaternion rot) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: 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) try { if ((Object)(object)player == (Object)null || ((NetworkBehaviour)player).IsDeinitializing || (Object)(object)player.Vitals == (Object)null) { return; } float num = Time.time + 1f; if (Config.RespawnOn) { float serverDeathTime = DeathTimer.GetServerDeathTime(player); if (serverDeathTime >= 0f) { num = Mathf.Max(num, serverDeathTime + Config.ForcedWaitSeconds.Value); } } _pending.Add(new Pending { Player = player, FireTime = num, Pos = pos, Rot = rot }); } catch (Exception ex) { Plugin.LogWarn("AutoRespawn.Schedule: " + ex.Message); } } public static void Tick() { try { if (_pending.Count == 0) { return; } for (int num = _pending.Count - 1; num >= 0; num--) { Pending pending = _pending[num]; if (!(Time.time < pending.FireTime)) { _pending.RemoveAt(num); Fire(pending); } } } catch (Exception ex) { Plugin.LogWarn("AutoRespawn.Tick: " + ex.Message); } } private static void Fire(Pending p) { //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) try { Player player = p.Player; if (!((Object)(object)player == (Object)null) && !((NetworkBehaviour)player).IsDeinitializing && !((Object)(object)player.Vitals == (Object)null) && player.Vitals.Health <= 0 && !((Object)(object)Server.Instance == (Object)null) && ((NetworkBehaviour)Server.Instance).IsServerInitialized && !DeathTimer.ServerInWait(player)) { Server.Instance.RespawnPlayer(player, p.Pos, p.Rot); } } catch (Exception ex) { Plugin.LogWarn("AutoRespawn.Fire: " + ex.Message); } } } internal static class CorpseCannibal { private const int ReviverHealAmount = 12; public static void TryCannibalize(Player revived, DeadPlayer corpse) { try { if (!Config.CannibalOn || (Object)(object)revived == (Object)null || (Object)(object)corpse == (Object)null || (Object)(object)revived.Vitals == (Object)null || revived.Vitals.Health <= 0) { return; } Player val = ((Item)corpse).Holder ?? ((Item)corpse).LastHolder; if (!((Object)(object)val == (Object)null) && !((Object)(object)val.Vitals == (Object)null) && !((Object)(object)revived == (Object)(object)val) && Random.Range(0, 100) < Config.CannibalChance.Value) { int num = HalfOfVanillaRevive(revived); revived.Vitals._syncedHealth.Value = Mathf.Clamp(num, 0, 100); val.Vitals.Heal(12); CannibalFx component = ((Component)val).GetComponent(); if ((Object)(object)component != (Object)null) { component.PlayEatEffects(); } Plugin.LogInfo("[BetterCorpses] Cannibalism: " + val.SteamName + " ate " + revived.SteamName + "'s corpse (revived at " + num + " HP, reviver healed " + 12 + ")"); } } catch (Exception ex) { Plugin.LogWarn("CorpseCannibal: " + ex.Message); } } private static int HalfOfVanillaRevive(Player revived) { try { if (AccessTools.Field(typeof(PlayerVitals), "_healthOnRes").GetValue(revived.Vitals) is int num) { return Mathf.FloorToInt((float)num * 0.5f); } } catch (Exception ex) { Plugin.LogWarn("HalfOfVanillaRevive: " + ex.Message); } return 12; } } internal static class DeathTimer { private static float _localDeathTime = -1f; private static readonly Dictionary _serverDeath = new Dictionary(); public static bool LocalInWait { get { if (_localDeathTime < 0f) { return false; } return Time.time - _localDeathTime < Config.ForcedWaitSeconds.Value; } } public static float LocalRemaining { get { if (_localDeathTime < 0f) { return 0f; } return Mathf.Max(0f, Config.ForcedWaitSeconds.Value - (Time.time - _localDeathTime)); } } internal static float NetworkTime() { try { if ((Object)(object)InstanceFinder.TimeManager != (Object)null) { return (float)InstanceFinder.TimeManager.TicksToTime((TickType)0); } } catch (Exception ex) { Plugin.LogWarn("DeathTimer.NetworkTime: " + ex.Message); } return Time.time; } public static void RecordLocalDeath() { _localDeathTime = Time.time; } public static void ClearLocal() { _localDeathTime = -1f; } public static void RecordServerDeath(Player p) { if (!((Object)(object)p == (Object)null)) { _serverDeath[p] = Time.time; } } public static void ClearServer(Player p) { if (!((Object)(object)p == (Object)null)) { _serverDeath.Remove(p); } } public static bool ServerInWait(Player p) { if ((Object)(object)p == (Object)null) { return false; } if (_serverDeath.TryGetValue(p, out var value)) { return Time.time - value < Config.ForcedWaitSeconds.Value; } return false; } public static float GetServerDeathTime(Player p) { if ((Object)(object)p == (Object)null) { return -1f; } if (!_serverDeath.TryGetValue(p, out var value)) { return -1f; } return value; } internal static float GetCorpseDeathTime(DeadPlayer corpse) { try { if ((Object)(object)corpse == (Object)null) { return -1f; } Player player = corpse.Player; if ((Object)(object)player != (Object)null) { CannibalFx component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null && component.DeathTime >= 0f) { return component.DeathTime; } } CorpseEconomy component2 = ((Component)corpse).GetComponent(); if ((Object)(object)component2 != (Object)null) { return component2.DeathTime; } } catch (Exception ex) { Plugin.LogWarn("GetCorpseDeathTime: " + ex.Message); } return -1f; } public static bool CorpseInWait(DeadPlayer corpse) { float corpseDeathTime = GetCorpseDeathTime(corpse); if (corpseDeathTime < 0f) { return false; } return NetworkTime() - corpseDeathTime < Config.ForcedWaitSeconds.Value; } public static float CorpseRemaining(DeadPlayer corpse) { float corpseDeathTime = GetCorpseDeathTime(corpse); if (corpseDeathTime < 0f) { return 0f; } return Mathf.Max(0f, Config.ForcedWaitSeconds.Value - (NetworkTime() - corpseDeathTime)); } } public static class Loc { public enum Lang { Chinese, English } private static Dictionary _zh; private static Dictionary _en; private static bool _loaded; public static Lang Current { get; private set; } public static void Init() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 SystemLanguage systemLanguage = Application.systemLanguage; if (systemLanguage - 40 <= 1) { Current = Lang.Chinese; } else { Current = Lang.English; } } private static string FileName(Lang lang) { if (lang != Lang.Chinese) { return "en-US.json"; } return "zh-CN.json"; } private static void EnsureLoaded() { if (_loaded) { return; } _loaded = true; try { _zh = LoadTable(Lang.Chinese); } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogError((object)("zh-CN 加载失败: " + ex.Message)); } } try { _en = LoadTable(Lang.English); } catch (Exception ex2) { if (Plugin.Log != null) { Plugin.Log.LogError((object)("en-US 加载失败: " + ex2.Message)); } } if (_zh == null) { _zh = new Dictionary(); } if (_en == null) { _en = new Dictionary(); } } private static Dictionary LoadTable(Lang lang) { string text = FileName(lang); string embeddedText = GetEmbeddedText(text); if (embeddedText == null) { if (Plugin.Log != null) { Plugin.Log.LogWarning((object)("未找到内嵌本地化资源: " + text)); } return null; } try { return JsonConvert.DeserializeObject>(embeddedText); } catch (Exception ex) { if (Plugin.Log != null) { Plugin.Log.LogError((object)("JSON 解析失败: " + text + " -> " + ex.Message)); } return null; } } private static string GetEmbeddedText(string fileName) { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string[] manifestResourceNames = executingAssembly.GetManifestResourceNames(); foreach (string text in manifestResourceNames) { if (!text.EndsWith("." + fileName, StringComparison.OrdinalIgnoreCase)) { continue; } using Stream stream = executingAssembly.GetManifestResourceStream(text); if (stream == null) { return null; } using StreamReader streamReader = new StreamReader(stream); return streamReader.ReadToEnd(); } return null; } public static string Get(string key) { EnsureLoaded(); Dictionary dictionary = ((Current == Lang.Chinese) ? _zh : _en); if (dictionary != null && dictionary.TryGetValue(key, out var value) && value != null) { return value; } Dictionary dictionary2 = ((Current == Lang.Chinese) ? _en : _zh); if (dictionary2 != null && dictionary2.TryGetValue(key, out var value2) && value2 != null) { return value2; } return "[" + key + "]"; } public static string Get(string key, params object[] args) { try { return string.Format(Get(key), args); } catch (Exception) { return Get(key); } } } public class CannibalFx : NetworkBehaviour { public readonly SyncVar _deathTime = new SyncVar(-1f, default(SyncTypeSettings)); private float _pendingDeathTime = -1f; private bool _hasPendingDeathTime; private bool _nwEarlyExcuted; private bool _nwLateExcuted; public float DeathTime => _deathTime.Value; public virtual void Awake() { ((NetworkBehaviour)this).NetworkInitialize___Early(); ((NetworkBehaviour)this).NetworkInitialize___Late(); } public override void OnStartServer() { ((NetworkBehaviour)this).OnStartServer(); Plugin.LogInfo("[BetterCorpses] CannibalFx OnStartServer, IsServerInitialized=" + ((NetworkBehaviour)this).IsServerInitialized); } private void Update() { try { if (((NetworkBehaviour)this).IsServerInitialized && _hasPendingDeathTime) { _deathTime.Value = _pendingDeathTime; _hasPendingDeathTime = false; Plugin.LogInfo("[BetterCorpses] CannibalFx._deathTime flushed on server: " + _pendingDeathTime.ToString("0.0")); } } catch (Exception ex) { Plugin.LogWarn("CannibalFx.Update: " + ex.Message); } } public void SetDeathTime(float t) { try { if (((NetworkBehaviour)this).IsServerInitialized) { _deathTime.Value = t; Plugin.LogInfo("[BetterCorpses] CannibalFx.SetDeathTime direct: " + t.ToString("0.0") + ", init=" + ((NetworkBehaviour)this).IsServerInitialized); } else { _pendingDeathTime = t; _hasPendingDeathTime = true; Plugin.LogInfo("[BetterCorpses] CannibalFx.SetDeathTime stashed: " + t.ToString("0.0") + ", init=" + ((NetworkBehaviour)this).IsServerInitialized); } } catch (Exception ex) { Plugin.LogWarn("CannibalFx.SetDeathTime: " + ex.Message); } } public void PlayEatEffects() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) try { if (((NetworkBehaviour)this).IsServerInitialized) { Channel val = (Channel)0; PooledWriter val2 = WriterPool.Retrieve(); ((NetworkBehaviour)this).SendObserversRpc(0u, val2, val, (DataOrderType)0, false, false, false); val2.Store(); } } catch (Exception ex) { Plugin.LogWarn("CannibalFx.PlayEatEffects: " + ex.Message); } } private void RpcLogic___PlayEatEffects() { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) try { Player component = ((Component)this).GetComponent(); if (!((Object)(object)component == (Object)null)) { AudioManager.PlayPlayerClip("Swallow", component, true, (AudioDistance)1, 1f, 0.1f); ParticleManager.Play("Smoke", component.Transform.position, Vector3.up); } } catch (Exception ex) { Plugin.LogWarn("CannibalFx RpcLogic: " + ex.Message); } } private void RpcReader___PlayEatEffects(PooledReader r, Channel channel) { if (((NetworkBehaviour)this).IsClientInitialized) { RpcLogic___PlayEatEffects(); } } public override void NetworkInitialize___Early() { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown if (!_nwEarlyExcuted) { _nwEarlyExcuted = true; ((NetworkBehaviour)this).NetworkInitialize___Early(); ((SyncBase)_deathTime).InitializeEarly((NetworkBehaviour)(object)this, 0u, false); ((NetworkBehaviour)this).RegisterObserversRpc(0u, new ClientRpcDelegate(RpcReader___PlayEatEffects)); } } public override void NetworkInitialize___Late() { if (!_nwLateExcuted) { _nwLateExcuted = true; ((NetworkBehaviour)this).NetworkInitialize___Late(); ((SyncBase)_deathTime).InitializeLate(); } } public override void NetworkInitializeIfDisabled() { ((NetworkBehaviour)this).NetworkInitialize___Early(); ((NetworkBehaviour)this).NetworkInitialize___Late(); } } public class CorpseEconomy : NetworkBehaviour { public readonly SyncVar _price = new SyncVar(0, default(SyncTypeSettings)); public readonly SyncVar _deathTime = new SyncVar(-1f, default(SyncTypeSettings)); private float _pendingDeathTime = -1f; private bool _hasPendingDeathTime; private int _pendingPrice; private bool _hasPendingPrice; private bool _nwEarlyExcuted; private bool _nwLateExcuted; public int Price => _price.Value; public float DeathTime => _deathTime.Value; public virtual void Awake() { ((NetworkBehaviour)this).NetworkInitialize___Early(); ((NetworkBehaviour)this).NetworkInitialize___Late(); } private void Update() { try { if (((NetworkBehaviour)this).IsServerInitialized) { if (_hasPendingDeathTime) { _deathTime.Value = _pendingDeathTime; _hasPendingDeathTime = false; } if (_hasPendingPrice) { _price.Value = _pendingPrice; _hasPendingPrice = false; } } } catch { } } public void SetDeathTime(float t) { try { if (((NetworkBehaviour)this).IsServerInitialized) { _deathTime.Value = t; return; } _pendingDeathTime = t; _hasPendingDeathTime = true; } catch { } } public void SetPrice(int price) { try { if (((NetworkBehaviour)this).IsServerInitialized) { _price.Value = price; return; } _pendingPrice = price; _hasPendingPrice = true; } catch { } } public override void NetworkInitialize___Early() { if (!_nwEarlyExcuted) { _nwEarlyExcuted = true; ((NetworkBehaviour)this).NetworkInitialize___Early(); ((SyncBase)_price).InitializeEarly((NetworkBehaviour)(object)this, 0u, false); ((SyncBase)_deathTime).InitializeEarly((NetworkBehaviour)(object)this, 1u, false); } } public override void NetworkInitialize___Late() { if (!_nwLateExcuted) { _nwLateExcuted = true; ((NetworkBehaviour)this).NetworkInitialize___Late(); ((SyncBase)_price).InitializeLate(); ((SyncBase)_deathTime).InitializeLate(); } } public override void NetworkInitializeIfDisabled() { ((NetworkBehaviour)this).NetworkInitialize___Early(); ((NetworkBehaviour)this).NetworkInitialize___Late(); } } [HarmonyPatch(typeof(PlayerDying), "ServerDie")] internal static class Patch_ServerDie { private static void Postfix(PlayerDying __instance) { try { DeadPlayer deadPlayer = __instance.DeadPlayer; if ((Object)(object)deadPlayer == (Object)null) { return; } Player player = deadPlayer.Player; float deathTime = DeathTimer.NetworkTime(); if ((Object)(object)player != (Object)null) { DeathTimer.RecordServerDeath(player); CannibalFx component = ((Component)player).GetComponent(); if ((Object)(object)component != (Object)null) { component.SetDeathTime(deathTime); } } CorpseEconomy component2 = ((Component)deadPlayer).GetComponent(); if ((Object)(object)component2 != (Object)null) { component2.SetDeathTime(deathTime); } Plugin.LogInfo("[BetterCorpses] death recorded owner=" + (((Object)(object)player != (Object)null) ? player.SteamName : "?") + " netTime=" + deathTime.ToString("0.0")); if (Config.EconomyOn) { int num = Random.Range(Config.PriceMin.Value, Config.PriceMax.Value + 1); try { AccessTools.Field(typeof(Item), "_worth").SetValue(deadPlayer, num); } catch (Exception ex) { Plugin.LogWarn("Patch_ServerDie _worth: " + ex.Message); } if ((Object)(object)component2 != (Object)null) { component2.SetPrice(num); } } } catch (Exception ex2) { Plugin.LogWarn("Patch_ServerDie: " + ex2.Message); } } } [HarmonyPatch(typeof(PlayerDying), "DeathEffects")] internal static class Patch_DeathEffects { private static void Postfix(PlayerDying __instance) { try { if (!((NetworkBehaviour)__instance).Owner.IsLocalClient) { return; } DeathTimer.RecordLocalDeath(); if (!Config.RespawnOn) { return; } try { AccessTools.Field(typeof(PlayerDying), "_totalGiveUpTime").SetValue(__instance, Config.GiveUpHoldSeconds.Value); } catch (Exception ex) { Plugin.LogWarn("GiveUpHoldSeconds: " + ex.Message); } } catch (Exception ex2) { Plugin.LogWarn("Patch_DeathEffects: " + ex2.Message); } } } [HarmonyPatch(typeof(PlayerDying), "ResurrectEffect")] internal static class Patch_ResurrectEffect { private static void Postfix(PlayerDying __instance) { try { DeathTimer.ClearLocal(); Player component = ((Component)__instance).GetComponent(); if ((Object)(object)component != (Object)null) { DeathTimer.ClearServer(component); } } catch (Exception ex) { Plugin.LogWarn("Patch_ResurrectEffect: " + ex.Message); } } } [HarmonyPatch(typeof(PlayerDying), "LocalResurrect")] internal static class Patch_LocalResurrect { private static void Prefix(PlayerDying __instance) { try { if (Config.Master.Value && (Object)(object)__instance.DeadPlayer == (Object)null) { AccessTools.Field(typeof(PlayerDying), "_waitingForTpOnRespawn").SetValue(__instance, true); } } catch (Exception ex) { Plugin.LogWarn("Patch_LocalResurrect: " + ex.Message); } } } [HarmonyPatch(typeof(PlayerDying), "MouseClick")] internal static class Patch_MouseClick { private static bool Prefix() { if (!Config.RespawnOn) { return true; } return !DeathTimer.LocalInWait; } } [HarmonyPatch(typeof(DeadPlayer), "PrimaryInput")] internal static class Patch_DeadPlayerPrimaryInput { private static bool Prefix(DeadPlayer __instance) { if (!Config.RespawnOn) { return true; } return !DeathTimer.CorpseInWait(__instance); } } [HarmonyPatch(typeof(Server), "RpcLogic___ResurrectPlayer___2247010027")] internal static class Patch_ResurrectPlayer { private static bool Prefix(object[] __args, out bool __state) { Player val = (Player)((__args != null && __args.Length != 0) ? /*isinst with value type is only supported in some contexts*/: null); DeadPlayer val2 = (DeadPlayer)((__args != null && __args.Length > 1) ? /*isinst with value type is only supported in some contexts*/: null); if (!((Object)(object)val != (Object)null) || ((NetworkBehaviour)val).IsDeinitializing || !((Object)(object)val.Vitals != (Object)null) || val.Vitals.Health > 0 || !((Object)(object)val2 != (Object)null) || ((NetworkBehaviour)val2).IsDeinitializing) { __state = false; return true; } if (Config.RespawnOn && (DeathTimer.ServerInWait(val) || DeathTimer.CorpseInWait(val2))) { __state = false; return false; } __state = true; return true; } private static void Postfix(object[] __args, bool __state) { if (__state && __args != null && __args.Length >= 2) { object obj = __args[0]; Player val = (Player)((obj is Player) ? obj : null); object obj2 = __args[1]; DeadPlayer corpse = (DeadPlayer)((obj2 is DeadPlayer) ? obj2 : null); if ((Object)(object)val != (Object)null) { DeathTimer.ClearServer(val); } CorpseCannibal.TryCannibalize(val, corpse); } } } [HarmonyPatch(typeof(Server), "RpcLogic___RespawnPlayer___2210451296")] internal static class Patch_RespawnPlayer { private static bool Prefix(object[] __args, out bool __state) { __state = true; if (!Config.RespawnOn) { return true; } Player val = (Player)((__args != null && __args.Length != 0) ? /*isinst with value type is only supported in some contexts*/: null); if ((Object)(object)val != (Object)null && DeathTimer.ServerInWait(val)) { __state = false; return false; } return true; } private static void Postfix(object[] __args, bool __state) { if (__state && __args != null && __args.Length != 0) { object obj = __args[0]; Player val = (Player)((obj is Player) ? obj : null); if ((Object)(object)val != (Object)null) { DeathTimer.ClearServer(val); } } } } [HarmonyPatch(typeof(NPC), "EatItem")] internal static class Patch_NpcEatCorpse { private static bool Prefix(NPC __instance, NPCQuest quest, byte questIndex, Item item) { //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Invalid comparison between Unknown and I4 //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (!Config.SellOn) { return true; } if ((Object)(object)item == (Object)null || (Object)(object)item.DeadPlayer == (Object)null) { return true; } if ((Object)(object)quest == (Object)null || (int)quest.Type != 1) { return true; } if ((Object)(object)Server.Instance == (Object)null || !((NetworkBehaviour)Server.Instance).IsServerInitialized) { return true; } if (item.IsDestroying || ((NetworkBehaviour)item).IsDeinitializing) { return false; } try { Vector3 position = ((Component)item).transform.position; Quaternion rotation = ((Component)item).transform.rotation; Player player = item.DeadPlayer.Player; MoneyManager.SellItem(item); byte b = (byte)AccessTools.Field(typeof(NPC), "_id").GetValue(__instance); item.DestroyItem((byte)2, b); try { NPCManager.Instance.SendEatEffects(b); } catch (Exception ex) { Plugin.LogWarn("SendEatEffects: " + ex.Message); } try { AccessTools.Method(typeof(NPC), "OnQuestProgression", (Type[])null, (Type[])null).Invoke(__instance, new object[1] { questIndex }); } catch (Exception ex2) { Plugin.LogWarn("OnQuestProgression: " + ex2.Message); } if ((Object)(object)player != (Object)null) { AutoRespawn.Schedule(player, position, rotation); } } catch (Exception ex3) { Plugin.LogWarn("Patch_NpcEatCorpse: " + ex3.Message); } return false; } } [HarmonyPatch(typeof(CasinoBox), "FixedUpdate")] internal static class Patch_CasinoBoxCorpses { private static bool Prefix(CasinoBox __instance) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) if (!Config.GambleOn) { return true; } if ((Object)(object)Server.Instance == (Object)null || !((NetworkBehaviour)Server.Instance).IsServerInitialized || ((Object)(object)CasinoManager.Instance != (Object)null && CasinoManager.IsBetting)) { return true; } try { object? value = AccessTools.Field(typeof(CasinoBox), "_col").GetValue(__instance); BoxCollider val = (BoxCollider)((value is BoxCollider) ? value : null); if ((Object)(object)val == (Object)null) { return true; } Vector3 val2 = ((Component)val).transform.TransformPoint(val.center); Vector3 val3 = Vector3.Scale(val.size * 0.5f, ((Component)__instance).transform.localScale); Collider[] array = Physics.OverlapBox(val2, val3, ((Component)__instance).transform.rotation, LayerMask.op_Implicit(GameInfo.ItemLayer)); List list = new List(); Collider[] array2 = array; foreach (Collider val4 in array2) { if (((Component)((Component)val4).transform).CompareTag("Item")) { Item val5 = ItemManager.Get(val4); if ((Object)(object)val5 != (Object)null && !list.Contains(val5) && (!Object.op_Implicit((Object)(object)val5.Creature) || val5.Creature.IsDead)) { list.Add(val5); } } } CasinoManager.SetBetItems(list); return false; } catch (Exception ex) { Plugin.LogWarn("Patch_CasinoBoxCorpses: " + ex.Message); return true; } } } [HarmonyPatch(typeof(BetButton), "ToggleAll")] internal static class Patch_BetButtonToggleAll { internal static bool SuppressModEnable; private static bool Prefix(ref bool to) { try { if (!Config.GambleOn) { return true; } if (to || SuppressModEnable) { return true; } CasinoManager instance = CasinoManager.Instance; if ((Object)(object)instance == (Object)null) { return true; } if (instance.TotalWorth != 0) { to = true; } } catch (Exception ex) { Plugin.LogWarn("Patch_BetButtonToggleAll: " + ex.Message); } return true; } } [HarmonyPatch(typeof(CasinoManager), "get_HasPlacedBet")] internal static class Patch_HasPlacedBet { private static void Postfix(ref bool __result) { try { if (Config.GambleOn) { CasinoManager instance = CasinoManager.Instance; if (!((Object)(object)instance == (Object)null) && instance.TotalWorth != 0) { __result = true; } } } catch (Exception ex) { Plugin.LogWarn("Patch_HasPlacedBet: " + ex.Message); } } } [HarmonyPatch(typeof(CasinoManager), "RpcLogic___BetResultEffects___2774100791")] internal static class Patch_BetResultEffects { private static void Prefix() { Patch_BetButtonToggleAll.SuppressModEnable = true; } private static void Postfix() { Patch_BetButtonToggleAll.SuppressModEnable = false; } } [HarmonyPatch(typeof(SlotMachine), "OnTriggerStay")] internal static class Patch_SlotMachineCorpses { private static bool Prefix(Collider other) { //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) if (!Config.LotteryOn) { return true; } if ((Object)(object)Server.Instance == (Object)null || !((NetworkBehaviour)Server.Instance).IsServerInitialized || SlotMachine.IsRolling) { return true; } try { Item val = ItemManager.Get(other); if ((Object)(object)val == (Object)null || (Object)(object)val.DeadPlayer == (Object)null) { return true; } if (Object.op_Implicit((Object)(object)val.Holder)) { return true; } Player lastHolder = val.LastHolder; if ((Object)(object)lastHolder == (Object)null) { return true; } Vector3 position = ((Component)val).transform.position; Quaternion rotation = ((Component)val).transform.rotation; Player player = val.DeadPlayer.Player; val.DestroyItem((byte)4, byte.MaxValue); SlotMachineManager.RollRandom(lastHolder); if ((Object)(object)player != (Object)null) { AutoRespawn.Schedule(player, position, rotation); } return false; } catch (Exception ex) { Plugin.LogWarn("Patch_SlotMachineCorpses: " + ex.Message); return true; } } } [HarmonyPatch(typeof(MoneyManager), "Update")] internal static class Patch_DriveTick { private static void Postfix() { Plugin.RuntimeTick(); } } [BepInPlugin("top.yw.bettercorpses", "更好的尸体", "1.2.4")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log; public static bool ComponentsAttached; internal static void LogInfo(string msg) { try { Log.LogInfo((object)msg); } catch { } } internal static void LogWarn(string msg) { try { Log.LogWarning((object)msg); } catch { } } private void Awake() { //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Expected O, but got Unknown //IL_0061: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Loc.Init(); Config.Init((BaseUnityPlugin)(object)this); Harmony val = new Harmony("top.yw.bettercorpses"); int num = 0; int num2 = 0; Type[] types = typeof(Plugin).Assembly.GetTypes(); foreach (Type type in types) { if (type.GetCustomAttributes(typeof(HarmonyPatch), inherit: false).Length != 0) { try { new PatchClassProcessor(val, type).Patch(); num++; } catch (Exception ex) { num2++; LogWarn("补丁应用失败:" + type.Name + " => " + ex.GetType().Name + ": " + ex.Message); } } } LogInfo("[BetterCorpses] Harmony 补丁应用完成(成功 " + num + " 失败 " + num2 + ")"); } private void Update() { RuntimeTick(); } public static void RuntimeTick() { try { EnsureAttached(); } catch { } try { AutoRespawn.Tick(); } catch { } try { HudUI.Tick(); } catch { } } private static void EnsureAttached() { if (!ComponentsAttached) { AttachComponents(); } } public static void AttachComponents() { if (ComponentsAttached) { return; } try { if (!((Object)(object)GameInfo.DeadPlayerPrefab == (Object)null) && !((Object)(object)GameInfo.PlayerPrefab == (Object)null)) { GameObject gameObject = ((Component)GameInfo.DeadPlayerPrefab).gameObject; if ((Object)(object)gameObject.GetComponent() == (Object)null) { gameObject.AddComponent(); } GameObject gameObject2 = ((Component)GameInfo.PlayerPrefab).gameObject; if ((Object)(object)gameObject2.GetComponent() == (Object)null) { gameObject2.AddComponent(); } ComponentsAttached = true; LogInfo("[BetterCorpses] CorpseEconomy/CannibalFx 已挂载(DeadPlayerPrefab/PlayerPrefab)"); } } catch (Exception ex) { LogWarn("AttachComponents 失败(稍后重试): " + ex.Message); } } } internal static class HudUI { private static Canvas _canvas; private static Text _waitText; private static Text _corpseWaitText; private static float _refreshTimer; private static DeadPlayer _diagCorpse; private static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvas != (Object)null)) { GameObject val = new GameObject("BetterCorpses_UI"); Object.DontDestroyOnLoad((Object)val); _canvas = val.AddComponent(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 30000; CanvasScaler obj = val.AddComponent(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); val.AddComponent(); _waitText = CreateText(val.transform, new Vector2(0.5f, 0.2f), new Vector2(800f, 80f), 44); ((Component)_waitText).gameObject.SetActive(false); _corpseWaitText = CreateText(val.transform, new Vector2(0.5f, 0.92f), new Vector2(1000f, 90f), 48); ((Component)_corpseWaitText).gameObject.SetActive(false); } } private static Text CreateText(Transform parent, Vector2 anchor, Vector2 size, int fontSize) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Expected O, but got Unknown //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("WrText", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(parent, false); RectTransform component = val.GetComponent(); component.anchorMin = anchor; component.anchorMax = anchor; component.pivot = new Vector2(0.5f, 0.5f); component.anchoredPosition = Vector2.zero; component.sizeDelta = size; Text obj = val.AddComponent(); obj.font = UiFonts.Cjk; obj.fontSize = fontSize; ((Graphic)obj).color = Color.white; obj.alignment = (TextAnchor)4; obj.horizontalOverflow = (HorizontalWrapMode)1; obj.verticalOverflow = (VerticalWrapMode)1; Outline obj2 = val.AddComponent(); ((Shadow)obj2).effectColor = new Color(0f, 0f, 0f, 0.8f); ((Shadow)obj2).effectDistance = new Vector2(1f, -1f); return obj; } public static void Tick() { try { Ensure(); } catch { return; } _refreshTimer -= Time.unscaledDeltaTime; if (_refreshTimer > 0f) { return; } _refreshTimer = 0.25f; try { RefreshWaitText(); } catch { } } private static void RefreshWaitText() { Player localPlayer = Player.LocalPlayer; if ((Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Dying != (Object)null && localPlayer.Dying.IsDead && Config.RespawnOn && DeathTimer.LocalInWait) { ((Component)_waitText).gameObject.SetActive(true); _waitText.text = Loc.Get("hud.respawnWait", Mathf.CeilToInt(DeathTimer.LocalRemaining)); ((Component)_corpseWaitText).gameObject.SetActive(false); return; } if (Config.RespawnOn && (Object)(object)localPlayer != (Object)null && (Object)(object)localPlayer.Holding != (Object)null) { Item heldItem = localPlayer.Holding.HeldItem; DeadPlayer val = (DeadPlayer)(object)((heldItem is DeadPlayer) ? heldItem : null); if ((Object)(object)val != (Object)null) { if (DeathTimer.CorpseInWait(val)) { ((Component)_corpseWaitText).gameObject.SetActive(true); _corpseWaitText.text = Loc.Get("hud.corpseWait", Mathf.CeilToInt(DeathTimer.CorpseRemaining(val))); ((Component)_waitText).gameObject.SetActive(false); return; } DiagnoseHeldCorpse(val); } } ((Component)_waitText).gameObject.SetActive(false); ((Component)_corpseWaitText).gameObject.SetActive(false); } private static void DiagnoseHeldCorpse(DeadPlayer held) { try { if (!((Object)(object)_diagCorpse == (Object)(object)held)) { _diagCorpse = held; Player player = held.Player; CannibalFx cannibalFx = (((Object)(object)player != (Object)null) ? ((Component)player).GetComponent() : null); CorpseEconomy component = ((Component)held).GetComponent(); string text = (((Object)(object)player == (Object)null) ? "owner null" : (((Object)(object)cannibalFx == (Object)null) ? "owner has no CannibalFx" : ((cannibalFx.DeathTime < 0f) ? string.Format("fx.deathTime not synced (-1); eco={0}", ((Object)(object)component != (Object)null) ? component.DeathTime.ToString("0.0") : "none") : $"fx.deathTime {cannibalFx.DeathTime:0.0} vs netTime {DeathTimer.NetworkTime():0.0}, wait {Config.ForcedWaitSeconds.Value}"))); Plugin.LogWarn("[BetterCorpses] held corpse not in wait: " + text); } } catch (Exception ex) { Plugin.LogWarn("DiagnoseHeldCorpse: " + ex.Message); } } } internal static class UiFonts { private static Font _cjk; public static Font Cjk { get { if ((Object)(object)_cjk == (Object)null) { string[] array = new string[6] { "Microsoft YaHei", "SimHei", "Microsoft JhengHei", "Noto Sans CJK SC", "Noto Sans SC", "Arial" }; foreach (string text in array) { try { Font val = Font.CreateDynamicFontFromOSFont(text, 24); if ((Object)(object)val != (Object)null) { _cjk = val; break; } } catch { } } if ((Object)(object)_cjk == (Object)null) { try { _cjk = Resources.GetBuiltinResource("LegacyRuntime.ttf"); } catch { } } if ((Object)(object)_cjk == (Object)null) { try { _cjk = Resources.GetBuiltinResource("Arial.ttf"); } catch { } } } return _cjk; } } }