using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using JetBrains.Annotations; using LitJson2; using Microsoft.CodeAnalysis; using ServerSync; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.UI; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("BalrondReviveSoul")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("BalrondReviveSoul")] [assembly: AssemblyCopyright("Copyright © 2022")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("cde312a0-cf19-4264-8616-e1c74774beed")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace BalrondReviveSoul { public class BalrondTranslator { public static Dictionary> translations = new Dictionary>(); public static Dictionary getLanguage(string language) { if (string.IsNullOrEmpty(language)) { return null; } if (translations.TryGetValue(language, out var value)) { return value; } return null; } } internal static class BRSConfig { internal static ConfigEntry LockConfiguration; internal static ConfigEntry DownedSeconds; internal static ConfigEntry AutoReleaseWhenTimerEnds; internal static ConfigEntry AllowSelfPotionRevive; internal static ConfigEntry RequireItemForSelfRevive; internal static ConfigEntry RequirePotionForFriendRevive; internal static ConfigEntry ResurrectionPotionPrefabName; internal static ConfigEntry ResurrectionItemAmount; internal static ConfigEntry ResurrectionCooldownMinutes; internal static ConfigEntry ReviveHealthPercent; internal static ConfigEntry ReviveDistance; internal static ConfigEntry DownedPresentationMode; internal static void Init(Launch plugin) { LockConfiguration = plugin.config("0 General", "Lock Configuration", value: true, "If on, server values are enforced."); DownedSeconds = plugin.config("0 General", "Downed Seconds", 120f, "How long player stays downed."); AutoReleaseWhenTimerEnds = plugin.config("0 General", "Auto Release When Timer Ends", value: true, "Auto death after timer."); ResurrectionCooldownMinutes = plugin.config("0 General", "Cooldown Minutes", 10f, "Cooldown after revive."); ReviveHealthPercent = plugin.config("0 General", "Revive Health Percent", 0.25f, "Health after revive."); ReviveDistance = plugin.config("0 General", "Revive Distance", 3f, "Max revive distance."); DownedPresentationMode = plugin.config("0 General", "Downed Presentation Mode", "Sit", "Sit or Bed."); AllowSelfPotionRevive = plugin.config("1 Self Revive", "Allow Self Revive", value: true, "Allow self revive."); RequireItemForSelfRevive = plugin.config("1 Self Revive", "Require Item For Self Revive", value: true, "Require item for self revive."); RequirePotionForFriendRevive = plugin.config("2 Friend Revive", "Require Item For Friend Revive", value: true, "Require item for reviving others."); ResurrectionPotionPrefabName = plugin.config("3 Items", "Resurrection Item Prefab", "MeadHealthMinor", "Item prefab name."); ResurrectionItemAmount = plugin.config("3 Items", "Resurrection Item Amount", 1, "Amount required."); } } [HarmonyPatch(typeof(Player), "Awake")] internal static class BRSPlayerAwakePatch { private static void Postfix(Player __instance) { if (!((Object)(object)__instance == (Object)null) && (Object)(object)((Component)__instance).GetComponent() == (Object)null) { ((Component)__instance).gameObject.AddComponent(); } } } [HarmonyPatch(typeof(Player), "OnDeath")] internal static class BRSPlayerOnDeathPatch { private static bool Prefix(Player __instance) { if ((Object)(object)__instance == (Object)null) { return true; } if (Launch.AllowOriginalDeath) { return true; } if ((Object)(object)((Character)__instance).m_nview == (Object)null || !((Character)__instance).m_nview.IsValid()) { return true; } if (!((Character)__instance).IsOwner()) { return true; } if (__instance.IsDowned()) { return false; } if (BRSReviveRules.IsPotionReviveOnCooldown(__instance, out var _)) { return true; } float num = Mathf.Max(1f, BRSConfig.DownedSeconds.Value); float until = Time.time + num; float health = Mathf.Max(1f, ((Character)__instance).GetMaxHealth() * 0.01f); __instance.SetDowned(value: true, until); __instance.ClearReleaseRequest(); ((Character)__instance).SetHealth(health); BRSPlayerPresentation.SetDownedPresentation(__instance, downed: true); if ((Object)(object)__instance == (Object)(object)Player.m_localPlayer) { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, "$tag_brs_death_wait_message_bal", 0, (Sprite)null, false); } } return false; } } [HarmonyPatch(typeof(Game), "UpdateRespawn")] internal static class BRSGameUpdateRespawnPatch { private static bool Prefix() { Player localPlayer = Player.m_localPlayer; return (Object)(object)localPlayer == (Object)null || !localPlayer.IsDowned(); } } [HarmonyPatch(typeof(Player), "CreateTombStone")] internal static class BRSCreateTombStonePatch { private static bool Prefix(Player __instance) { return (Object)(object)__instance == (Object)null || !__instance.IsDowned(); } } internal static class BRSAIIgnoreDownedPlayers { internal static bool IsDownedPlayer(Character character) { Player val = (Player)(object)((character is Player) ? character : null); return (Object)(object)val != (Object)null && val.IsDowned(); } internal static void ClearTargetIfDowned(MonsterAI ai) { if (!((Object)(object)ai == (Object)null) && IsDownedPlayer(((BaseAI)ai).GetTargetCreature())) { ai.SetTarget((Character)null); ((BaseAI)ai).SetAlerted(false); } } } [HarmonyPatch(typeof(MonsterAI), "SetTarget")] internal static class BRSMonsterAISetTargetPatch { private static bool Prefix(MonsterAI __instance, Character __0) { if (!BRSAIIgnoreDownedPlayers.IsDownedPlayer(__0)) { return true; } if ((Object)(object)__instance != (Object)null) { ((BaseAI)__instance).SetAlerted(false); } return false; } } [HarmonyPatch(typeof(MonsterAI), "UpdateAI")] internal static class BRSMonsterAIUpdateAIPatch { private static void Prefix(MonsterAI __instance) { BRSAIIgnoreDownedPlayers.ClearTargetIfDowned(__instance); } private static void Postfix(MonsterAI __instance) { BRSAIIgnoreDownedPlayers.ClearTargetIfDowned(__instance); } } [HarmonyPatch(typeof(Character), "Damage")] internal static class BRSDownedPlayerDamagePatch { private static bool Prefix(Character __instance) { return !BRSAIIgnoreDownedPlayers.IsDownedPlayer(__instance); } } [HarmonyPatch] internal static class BRSBaseAIIsEnemyCharacterPatch { private static IEnumerable TargetMethods() { MethodInfo method = AccessTools.Method(typeof(BaseAI), "IsEnemy", new Type[2] { typeof(Character), typeof(Character) }, (Type[])null); if (method != null) { yield return method; } } private static void Postfix(Character __0, Character __1, ref bool __result) { if (__result && (BRSAIIgnoreDownedPlayers.IsDownedPlayer(__0) || BRSAIIgnoreDownedPlayers.IsDownedPlayer(__1))) { __result = false; } } } internal sealed class BRSDownedBehaviour : MonoBehaviour, Hoverable, Interactable { private const string RpcReviveRequest = "BRS_ReviveRequest"; private const string RpcSelfReviveRequest = "BRS_SelfReviveRequest"; private Player _player; private ZNetView _nview; private float _nextOwnerTick; private bool _registered; private void Awake() { _player = ((Component)this).GetComponent(); _nview = ((Component)this).GetComponent(); TryRegisterRpc(); } private void OnEnable() { TryRegisterRpc(); } private void Update() { if (!((Object)(object)_player == (Object)null) && !((Object)(object)_nview == (Object)null) && _nview.IsValid() && _player.IsDowned() && ((Character)_player).IsOwner() && !(Time.time < _nextOwnerTick)) { _nextOwnerTick = Time.time + 0.1f; MaintainDownedOwnerState(); if (_player.ReleaseRequested()) { PerformRealDeath(); } else if (BRSConfig.AutoReleaseWhenTimerEnds.Value && Time.time >= _player.GetDownedUntil()) { PerformRealDeath(); } } } public string GetHoverName() { return ((Object)(object)_player != (Object)null) ? _player.GetPlayerName() : string.Empty; } public string GetHoverText() { if ((Object)(object)_player == (Object)null || !_player.IsDowned()) { return string.Empty; } Player localPlayer = Player.m_localPlayer; float remainingDownedSeconds = _player.GetRemainingDownedSeconds(); string playerName = _player.GetPlayerName(); string text = "$tag_brs_release_in_bal " + remainingDownedSeconds.ToString("0") + "s"; string reason; bool flag = BRSReviveRules.CanFriendRevive(localPlayer, _player, out reason); if (BRSConfig.RequirePotionForFriendRevive.Value) { string value = BRSConfig.ResurrectionPotionPrefabName.Value; int num = Mathf.Max(1, BRSConfig.ResurrectionItemAmount.Value); if (flag) { return Localization.instance.Localize(playerName + "\n$tag_brs_hover_use_revive_bal\n" + num + "x " + value + "\n" + text); } return Localization.instance.Localize(playerName + "\n" + text + "\n" + reason); } if (flag) { return Localization.instance.Localize(playerName + "\n$tag_brs_hover_use_revive_bal\n" + text); } return Localization.instance.Localize(playerName + "\n" + text + "\n" + reason); } public bool Interact(Humanoid user, bool repeat, bool alt) { if (repeat || alt) { return false; } Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || (Object)(object)_player == (Object)null || !_player.IsDowned()) { return false; } return TryReviveFromActor(val, null, fromUseItem: false); } public bool UseItem(Humanoid user, ItemData item) { Player val = (Player)(object)((user is Player) ? user : null); if ((Object)(object)val == (Object)null || item == null || (Object)(object)_player == (Object)null || !_player.IsDowned()) { return false; } if (!IsResurrectionPotion(item)) { return false; } return TryReviveFromActor(val, item, fromUseItem: true); } internal void TrySelfReviveLocal() { if (!((Object)(object)_player == (Object)null) && ((Character)_player).IsOwner() && _player.IsDowned() && BRSReviveRules.CanSelfRevive(_player, out var _) && (!BRSConfig.RequireItemForSelfRevive.Value || BRSItemUtils.ConsumeResurrectionPotion(_player))) { _nview.InvokeRPC("BRS_SelfReviveRequest", Array.Empty()); } } private bool TryReviveFromActor(Player reviver, ItemData directItem, bool fromUseItem) { if (!BRSReviveRules.CanFriendRevive(reviver, _player, out var reason)) { ((Character)reviver).Message((MessageType)2, reason, 0, (Sprite)null); return true; } if (BRSConfig.RequirePotionForFriendRevive.Value && !(fromUseItem ? BRSItemUtils.ConsumeSpecificItem(reviver, directItem, Mathf.Max(1, BRSConfig.ResurrectionItemAmount.Value)) : BRSItemUtils.ConsumeResurrectionPotion(reviver))) { string text = "$tag_brs_need_item_bal " + Mathf.Max(1, BRSConfig.ResurrectionItemAmount.Value) + "x " + BRSConfig.ResurrectionPotionPrefabName.Value + "."; ((Character)reviver).Message((MessageType)2, text, 0, (Sprite)null); return true; } _nview.InvokeRPC("BRS_ReviveRequest", Array.Empty()); return true; } private bool IsResurrectionPotion(ItemData item) { if (item == null) { return false; } string value = BRSConfig.ResurrectionPotionPrefabName.Value; if ((Object)(object)item.m_dropPrefab != (Object)null && string.Equals(((Object)item.m_dropPrefab).name, value, StringComparison.OrdinalIgnoreCase)) { return true; } if (item.m_shared != null && !string.IsNullOrEmpty(item.m_shared.m_name) && string.Equals(item.m_shared.m_name, value, StringComparison.OrdinalIgnoreCase)) { return true; } return false; } private void TryRegisterRpc() { if (!_registered && !((Object)(object)_nview == (Object)null) && _nview.IsValid()) { _registered = true; _nview.Register("BRS_ReviveRequest", (Action)RPC_ReviveRequest); _nview.Register("BRS_SelfReviveRequest", (Action)RPC_SelfReviveRequest); } } private void RPC_ReviveRequest(long sender) { if (!((Object)(object)_player == (Object)null) && ((Character)_player).IsOwner() && _player.IsDowned()) { ReviveHere(usedPotion: true, selfRevive: false); } } private void RPC_SelfReviveRequest(long sender) { if (!((Object)(object)_player == (Object)null) && ((Character)_player).IsOwner() && _player.IsDowned()) { ReviveHere(usedPotion: true, selfRevive: true); } } private void MaintainDownedOwnerState() { float num = Mathf.Max(1f, ((Character)_player).GetMaxHealth() * 0.01f); if (((Character)_player).GetHealth() > num) { ((Character)_player).SetHealth(num); } BRSPlayerPresentation.SetDownedPresentation(_player, downed: true); } private void ReviveHere(bool usedPotion, bool selfRevive) { float health = Mathf.Max(1f, ((Character)_player).GetMaxHealth() * Mathf.Clamp01(BRSConfig.ReviveHealthPercent.Value)); _player.SetDowned(value: false, 0f); _player.ClearReleaseRequest(); ((Character)_player).SetHealth(health); BRSPlayerPresentation.SetDownedPresentation(_player, downed: false); if (usedPotion) { BRSReviveRules.MarkPotionReviveUsed(_player); } if ((Object)(object)_player == (Object)(object)Player.m_localPlayer) { MessageHud instance = MessageHud.instance; if (instance != null) { instance.ShowMessage((MessageType)2, selfRevive ? "$tag_brs_self_revived_bal" : "$tag_brs_revived_by_player_bal", 0, (Sprite)null, false); } } } private void PerformRealDeath() { _player.SetDowned(value: false, 0f); _player.ClearReleaseRequest(); BRSPlayerPresentation.SetDownedPresentation(_player, downed: false); Launch.AllowOriginalDeath = true; try { ((Character)_player).SetHealth(0f); ((Character)_player).OnDeath(); } finally { Launch.AllowOriginalDeath = false; } } } internal sealed class BRSHudController : MonoBehaviour { private const string UnifiedPopupPath = "_GameMain/LoadingGUI/PixelFix/IngameGui/UnifiedPopup"; private static BRSHudController _instance; private static string _cachedItemDisplayName; private GameObject _downedPopupRoot; private bool _isSetup; private bool _isBinding; private float _nextRefreshTime; private bool _suppressReleaseUntilEscapeUp; private bool _wantPopupCursor; private GameObject _popupBackground; private GameObject _popupPanel; private GameObject _popupBkg; private Component _headerText; private Component _bodyText; private Button _buttonYes; private Button _buttonOk; private Button _buttonNo; private Component _buttonYesText; private Component _buttonOkText; private Component _buttonNoText; internal static BRSHudController Instance => EnsureInstance(); internal static bool HasInstance => (Object)(object)_instance != (Object)null; internal static BRSHudController EnsureInstance() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown if ((Object)(object)_instance != (Object)null) { return _instance; } GameObject val = new GameObject("BRS_HudController"); Object.DontDestroyOnLoad((Object)(object)val); _instance = val.AddComponent(); return _instance; } internal static void ClearCachedItemDisplayName() { _cachedItemDisplayName = null; } internal bool ShouldForceMouseActive() { return _wantPopupCursor; } internal void BindHud(Hud hud) { if (!((Object)(object)hud == (Object)null) && !_isBinding && !_isSetup) { ((MonoBehaviour)this).StartCoroutine(SetupPopupWhenReady()); } } internal void UnbindHud(Hud hud) { _isBinding = false; _isSetup = false; ReleaseInputCapture(); if ((Object)(object)_downedPopupRoot != (Object)null) { Object.Destroy((Object)(object)_downedPopupRoot); _downedPopupRoot = null; } _popupBackground = null; _popupPanel = null; _popupBkg = null; _headerText = null; _bodyText = null; _buttonYes = null; _buttonOk = null; _buttonNo = null; _buttonYesText = null; _buttonOkText = null; _buttonNoText = null; } private IEnumerator SetupPopupWhenReady() { _isBinding = true; while (!_isSetup && !TrySetupPopup()) { yield return (object)new WaitForSeconds(0.5f); } _isBinding = false; } private bool TrySetupPopup() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00c7: Unknown result type (might be due to invalid IL or missing references) Transform val = FindUnifiedPopupTransform(); if ((Object)(object)val == (Object)null) { return false; } Transform val2 = val.Find("PopupBlockingBackground"); if ((Object)(object)val2 == (Object)null) { return false; } if ((Object)(object)_downedPopupRoot == (Object)null) { _downedPopupRoot = new GameObject("BRS_DownedUnifiedPopup"); _downedPopupRoot.transform.SetParent(val, false); _downedPopupRoot.transform.SetAsLastSibling(); RectTransform val3 = _downedPopupRoot.AddComponent(); val3.anchorMin = Vector2.zero; val3.anchorMax = Vector2.one; val3.offsetMin = Vector2.zero; val3.offsetMax = Vector2.zero; ((Transform)val3).localScale = Vector3.one; GameObject val4 = Object.Instantiate(((Component)val2).gameObject, _downedPopupRoot.transform, false); ((Object)val4).name = "PopupBlockingBackground"; } if (!CachePopupRefs(_downedPopupRoot.transform)) { return false; } PrepareCloneForDownedUsage(); WireButtons(); _isSetup = true; HidePopup(); return true; } private Transform FindUnifiedPopupTransform() { Transform[] array = Resources.FindObjectsOfTypeAll(); foreach (Transform val in array) { if (!((Object)(object)val == (Object)null) && !(((Object)val).name != "UnifiedPopup")) { string hierarchyPath = GetHierarchyPath(val); if (hierarchyPath.Contains("_GameMain/LoadingGUI/PixelFix/IngameGui/UnifiedPopup")) { return val; } } } return null; } private static string GetHierarchyPath(Transform t) { if ((Object)(object)t == (Object)null) { return string.Empty; } string text = ((Object)t).name; Transform parent = t.parent; while ((Object)(object)parent != (Object)null) { text = ((Object)parent).name + "/" + text; parent = parent.parent; } return text; } private bool CachePopupRefs(Transform root) { Transform val = root.Find("PopupBlockingBackground"); if ((Object)(object)val == (Object)null) { return false; } Transform val2 = val.Find("Popup"); if ((Object)(object)val2 == (Object)null) { return false; } Transform val3 = val2.Find("bkg"); Transform val4 = val2.Find("HeaderText"); Transform val5 = val2.Find("BodyText"); Transform val6 = val2.Find("ButtonYes"); Transform val7 = val2.Find("ButtonOk"); Transform val8 = val2.Find("ButtonNo"); if ((Object)(object)val4 == (Object)null || (Object)(object)val5 == (Object)null || (Object)(object)val6 == (Object)null || (Object)(object)val7 == (Object)null || (Object)(object)val8 == (Object)null) { return false; } _popupBackground = ((Component)val).gameObject; _popupPanel = ((Component)val2).gameObject; _popupBkg = (((Object)(object)val3 != (Object)null) ? ((Component)val3).gameObject : null); _headerText = GetTextComponent(val4); _bodyText = GetTextComponent(val5); _buttonYes = ((Component)val6).GetComponent