using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Mirror;
using Steamworks.Data;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.Localization.Components;
using UnityEngine.UI;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyCompany("HostPauseMod")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("HostPauseMod")]
[assembly: AssemblyTitle("HostPauseMod")]
[assembly: AssemblyVersion("1.0.0.0")]
[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.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace HostPauseMod
{
[BepInPlugin("codex.superbattlegolf.hostpause", "Host Pause", "0.2.1")]
public sealed class HostPausePlugin : BaseUnityPlugin
{
private sealed class RigidbodySnapshot
{
public Rigidbody Body;
public bool IsKinematic;
public bool UseGravity;
public bool DetectCollisions;
public Vector3 LinearVelocity;
public Vector3 AngularVelocity;
}
[HarmonyPatch(typeof(PauseMenu), "Awake")]
private static class PauseMenuAwakePatch
{
private static void Postfix(PauseMenu __instance)
{
instance?.AddPauseButton(__instance);
}
}
[HarmonyPatch(typeof(PauseMenu), "OnEnable")]
private static class PauseMenuOnEnablePatch
{
private static void Postfix(PauseMenu __instance)
{
if ((Object)(object)instance?.pauseButton != (Object)null)
{
RefreshPauseMenuButtonList(__instance);
FitPauseMenuButtonStack(__instance);
instance.RefreshPauseButton();
}
}
}
[HarmonyPatch(typeof(BNetworkManager), "OnStartClient")]
private static class NetworkStartClientPatch
{
private static void Postfix()
{
lastObservedLobbyPauseVersion = string.Empty;
nextLobbyPollTime = 0f;
}
}
[HarmonyPatch(typeof(BNetworkManager), "OnStopServer")]
private static class NetworkStopServerPatch
{
private static void Prefix()
{
pendingRemotePause = false;
PublishSteamLobbyPauseState(paused: false);
ForceLocalResume();
}
}
[HarmonyPatch(typeof(BNetworkManager), "OnStopClient")]
private static class NetworkStopClientPatch
{
private static void Prefix()
{
lastObservedLobbyPauseVersion = string.Empty;
nextLobbyPollTime = 0f;
pendingRemotePause = false;
ForceLocalResume();
}
}
[HarmonyPatch(typeof(PlayerMovement), "Update")]
private static class PlayerMovementUpdatePatch
{
private static bool Prefix()
{
return !isPaused;
}
}
[HarmonyPatch(typeof(PlayerMovement), "FixedUpdate")]
private static class PlayerMovementFixedUpdatePatch
{
private static bool Prefix()
{
return !isPaused;
}
}
[HarmonyPatch(typeof(GolfBall), "UpdatePhysics")]
private static class GolfBallUpdatePhysicsPatch
{
private static bool Prefix()
{
return !isPaused;
}
}
[CompilerGenerated]
private static class <>O
{
public static UnityAction <0>__TogglePauseFromPauseMenu;
}
private const string PluginGuid = "codex.superbattlegolf.hostpause";
private const string PluginName = "Host Pause";
private const string PluginVersion = "0.2.1";
private const string LobbyPauseStateKey = "codex_hostpause_state";
private const string LobbyPauseVersionKey = "codex_hostpause_version";
private static HostPausePlugin instance;
private static bool isPaused;
private static string lastObservedLobbyPauseVersion = string.Empty;
private static float nextLobbyPollTime;
private static bool pendingRemotePause;
private static bool pauseMenuStackAdjusted;
private static Vector3 pauseMenuOriginalScale;
private static Vector2 pauseMenuOriginalAnchoredPosition;
private static bool pauseBannerApplied;
private static bool aheadBannerWasVisibleBeforePause;
private static readonly List<RigidbodySnapshot> frozenRigidbodies = new List<RigidbodySnapshot>();
private static readonly Dictionary<TMP_Text, string> pauseBannerOriginalTexts = new Dictionary<TMP_Text, string>();
private static readonly List<LocalizeStringEvent> pauseBannerDisabledLocalizers = new List<LocalizeStringEvent>();
private Harmony harmony;
private Button pauseButton;
private TMP_Text pauseButtonLabel;
private void Awake()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0016: Expected O, but got Unknown
instance = this;
harmony = new Harmony("codex.superbattlegolf.hostpause");
harmony.PatchAll();
((BaseUnityPlugin)this).Logger.LogInfo((object)"Host Pause 0.2.1 loaded.");
}
private void OnDestroy()
{
ForceLocalResume();
Harmony obj = harmony;
if (obj != null)
{
obj.UnpatchSelf();
}
if (instance == this)
{
instance = null;
}
}
private void Update()
{
if (isPaused)
{
if (!CanApplyPauseState())
{
ForceLocalResume();
return;
}
MaintainFrozenRigidbodies();
ShowPauseBanner();
}
PollSteamLobbyPauseState();
TryApplyPendingRemotePause();
if (isPaused && !NetworkServer.active && !NetworkClient.active)
{
ForceLocalResume();
}
RefreshPauseButton();
}
private static void PollSteamLobbyPauseState()
{
if (NetworkServer.active || !NetworkClient.active || !NetworkClient.isConnected || NetworkClient.connection == null || !((NetworkConnection)NetworkClient.connection).isAuthenticated || !CanApplyPauseState() || Time.unscaledTime < nextLobbyPollTime)
{
return;
}
nextLobbyPollTime = Time.unscaledTime + 0.5f;
Lobby val = default(Lobby);
if (BNetworkManager.TryGetSteamLobby(ref val))
{
string data = ((Lobby)(ref val)).GetData("codex_hostpause_version");
if (!string.IsNullOrEmpty(data) && !(data == lastObservedLobbyPauseVersion))
{
lastObservedLobbyPauseVersion = data;
ApplyRemotePause(((Lobby)(ref val)).GetData("codex_hostpause_state") == "1");
}
}
}
private static void TogglePauseFromPauseMenu()
{
if (!NetworkServer.active)
{
return;
}
bool flag = !isPaused;
if (flag && !CanApplyPauseState())
{
HostPausePlugin hostPausePlugin = instance;
if (hostPausePlugin != null)
{
((BaseUnityPlugin)hostPausePlugin).Logger.LogWarning((object)"Ignoring pause request because the game is not in a playable match state.");
}
}
else
{
PauseMenu.Unpause();
ApplyPauseLocal(flag);
PublishSteamLobbyPauseState(flag);
}
}
private static void PublishSteamLobbyPauseState(bool paused)
{
Lobby val = default(Lobby);
if (NetworkServer.active && BNetworkManager.TryGetSteamLobby(ref val))
{
((Lobby)(ref val)).SetData("codex_hostpause_state", paused ? "1" : "0");
((Lobby)(ref val)).SetData("codex_hostpause_version", Time.unscaledTime.ToString("R"));
}
}
private static void ApplyPauseLocal(bool paused)
{
if (paused)
{
if (!CanApplyPauseState())
{
pendingRemotePause = true;
ForceLocalResume();
return;
}
if (!isPaused)
{
FreezeRigidbodies();
ShowPauseBanner();
}
isPaused = true;
}
else
{
pendingRemotePause = false;
isPaused = false;
RestoreRigidbodies();
RestorePauseBanner();
}
instance?.RefreshPauseButton();
}
private static void ApplyRemotePause(bool paused)
{
if (!paused)
{
pendingRemotePause = false;
ApplyPauseLocal(paused: false);
}
else if (!CanApplyPauseState())
{
pendingRemotePause = true;
ForceLocalResume();
}
else
{
pendingRemotePause = false;
ApplyPauseLocal(paused: true);
}
}
private static void TryApplyPendingRemotePause()
{
if (pendingRemotePause && !isPaused && CanApplyPauseState())
{
pendingRemotePause = false;
ApplyPauseLocal(paused: true);
}
}
private static void ForceLocalResume()
{
isPaused = false;
RestoreRigidbodies();
RestorePauseBanner();
instance?.RefreshPauseButton();
}
private static bool CanApplyPauseState()
{
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_004d: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Invalid comparison between Unknown and I4
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
//IL_0054: Invalid comparison between Unknown and I4
if (!NetworkServer.active && (!NetworkClient.active || NetworkClient.connection == null || !((NetworkConnection)NetworkClient.connection).isAuthenticated))
{
return false;
}
if (!SingletonBehaviour<PauseMenu>.HasInstance)
{
return false;
}
if ((Object)(object)GameManager.LocalPlayerInfo == (Object)null || (Object)(object)GameManager.LocalPlayerMovement == (Object)null)
{
return false;
}
MatchState matchState = CourseManager.MatchState;
if ((int)matchState >= 1)
{
return (int)matchState < 6;
}
return false;
}
private static void ShowPauseBanner()
{
AheadOfBallMessage aheadOfBallMessage = GetAheadOfBallMessage();
if ((Object)(object)aheadOfBallMessage == (Object)null)
{
return;
}
if (!pauseBannerApplied)
{
aheadBannerWasVisibleBeforePause = GetAheadBannerVisible(aheadOfBallMessage);
pauseBannerOriginalTexts.Clear();
pauseBannerDisabledLocalizers.Clear();
LocalizeStringEvent[] componentsInChildren = ((Component)aheadOfBallMessage).GetComponentsInChildren<LocalizeStringEvent>(true);
foreach (LocalizeStringEvent val in componentsInChildren)
{
if (((Behaviour)val).enabled)
{
((Behaviour)val).enabled = false;
pauseBannerDisabledLocalizers.Add(val);
}
}
TMP_Text[] componentsInChildren2 = ((Component)aheadOfBallMessage).GetComponentsInChildren<TMP_Text>(true);
foreach (TMP_Text val2 in componentsInChildren2)
{
pauseBannerOriginalTexts[val2] = val2.text;
val2.text = "Game Paused";
}
pauseBannerApplied = true;
}
else
{
foreach (TMP_Text key in pauseBannerOriginalTexts.Keys)
{
if ((Object)(object)key != (Object)null)
{
key.text = "Game Paused";
}
}
}
AheadOfBallMessage.Show();
}
private static void RestorePauseBanner()
{
if (!pauseBannerApplied)
{
return;
}
foreach (KeyValuePair<TMP_Text, string> pauseBannerOriginalText in pauseBannerOriginalTexts)
{
if ((Object)(object)pauseBannerOriginalText.Key != (Object)null)
{
pauseBannerOriginalText.Key.text = pauseBannerOriginalText.Value;
}
}
foreach (LocalizeStringEvent pauseBannerDisabledLocalizer in pauseBannerDisabledLocalizers)
{
if ((Object)(object)pauseBannerDisabledLocalizer != (Object)null)
{
((Behaviour)pauseBannerDisabledLocalizer).enabled = true;
}
}
pauseBannerOriginalTexts.Clear();
pauseBannerDisabledLocalizers.Clear();
pauseBannerApplied = false;
if (aheadBannerWasVisibleBeforePause)
{
AheadOfBallMessage.Show();
}
else
{
AheadOfBallMessage.Hide();
}
}
private static AheadOfBallMessage GetAheadOfBallMessage()
{
if (SingletonBehaviour<AheadOfBallMessage>.HasInstance)
{
return SingletonBehaviour<AheadOfBallMessage>.Instance;
}
return Object.FindFirstObjectByType<AheadOfBallMessage>((FindObjectsInactive)1);
}
private static bool GetAheadBannerVisible(AheadOfBallMessage banner)
{
object obj = AccessTools.Field(typeof(AheadOfBallMessage), "isVisible")?.GetValue(banner);
bool flag = default(bool);
int num;
if (obj is bool)
{
flag = (bool)obj;
num = 1;
}
else
{
num = 0;
}
return (byte)((uint)num & (flag ? 1u : 0u)) != 0;
}
private static void FreezeRigidbodies()
{
//IL_0059: Unknown result type (might be due to invalid IL or missing references)
//IL_005e: Unknown result type (might be due to invalid IL or missing references)
//IL_0065: 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)
frozenRigidbodies.Clear();
Rigidbody[] array = Object.FindObjectsByType<Rigidbody>((FindObjectsSortMode)0);
foreach (Rigidbody val in array)
{
if (!((Object)(object)val == (Object)null))
{
frozenRigidbodies.Add(new RigidbodySnapshot
{
Body = val,
IsKinematic = val.isKinematic,
UseGravity = val.useGravity,
DetectCollisions = val.detectCollisions,
LinearVelocity = val.linearVelocity,
AngularVelocity = val.angularVelocity
});
FreezeRigidbody(val);
}
}
}
private static void MaintainFrozenRigidbodies()
{
foreach (RigidbodySnapshot frozenRigidbody in frozenRigidbodies)
{
if ((Object)(object)frozenRigidbody.Body != (Object)null)
{
FreezeRigidbody(frozenRigidbody.Body);
}
}
}
private static void FreezeRigidbody(Rigidbody body)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
body.linearVelocity = Vector3.zero;
body.angularVelocity = Vector3.zero;
body.isKinematic = true;
}
private static void RestoreRigidbodies()
{
//IL_0053: 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)
foreach (RigidbodySnapshot frozenRigidbody in frozenRigidbodies)
{
Rigidbody body = frozenRigidbody.Body;
if (!((Object)(object)body == (Object)null))
{
body.useGravity = frozenRigidbody.UseGravity;
body.detectCollisions = frozenRigidbody.DetectCollisions;
body.isKinematic = frozenRigidbody.IsKinematic;
if (!body.isKinematic)
{
body.linearVelocity = frozenRigidbody.LinearVelocity;
body.angularVelocity = frozenRigidbody.AngularVelocity;
}
}
}
frozenRigidbodies.Clear();
}
private void AddPauseButton(PauseMenu pauseMenu)
{
//IL_00b2: Unknown result type (might be due to invalid IL or missing references)
//IL_00bc: Expected O, but got Unknown
//IL_00d7: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Expected O, but got Unknown
if ((Object)(object)pauseMenu == (Object)null || (Object)(object)pauseMenu.menuButtonContainer == (Object)null || (Object)(object)pauseButton != (Object)null)
{
return;
}
Button val = FindPauseButtonTemplate(pauseMenu);
if ((Object)(object)val == (Object)null)
{
((BaseUnityPlugin)this).Logger.LogWarning((object)"Could not find a pause menu button to clone for Host Pause.");
return;
}
GameObject val2 = Object.Instantiate<GameObject>(((Component)val).gameObject, ((Component)val).transform.parent);
((Object)val2).name = "HostPauseButton";
val2.transform.SetSiblingIndex(((Component)val).transform.GetSiblingIndex() + 1);
LocalizeStringEvent[] componentsInChildren = val2.GetComponentsInChildren<LocalizeStringEvent>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
((Behaviour)componentsInChildren[i]).enabled = false;
}
pauseButton = val2.GetComponent<Button>();
pauseButton.onClick = new ButtonClickedEvent();
ButtonClickedEvent onClick = pauseButton.onClick;
object obj = <>O.<0>__TogglePauseFromPauseMenu;
if (obj == null)
{
UnityAction val3 = TogglePauseFromPauseMenu;
<>O.<0>__TogglePauseFromPauseMenu = val3;
obj = (object)val3;
}
((UnityEvent)onClick).AddListener((UnityAction)obj);
pauseButtonLabel = val2.GetComponentInChildren<TMP_Text>(true);
RefreshPauseButton();
RefreshPauseMenuButtonList(pauseMenu);
FitPauseMenuButtonStack(pauseMenu);
}
private static Button FindPauseButtonTemplate(PauseMenu pauseMenu)
{
Button[] componentsInChildren = pauseMenu.menuButtonContainer.GetComponentsInChildren<Button>(true);
Button[] array = componentsInChildren;
foreach (Button val in array)
{
TMP_Text componentInChildren = ((Component)val).GetComponentInChildren<TMP_Text>(true);
if ((Object)(object)componentInChildren != (Object)null && componentInChildren.text.Trim().Equals("Settings", StringComparison.OrdinalIgnoreCase))
{
return val;
}
}
int num = Array.IndexOf(componentsInChildren, pauseMenu.exitGameButton);
if (num > 0)
{
return componentsInChildren[num - 1];
}
if (!((Object)(object)pauseMenu.exitGameButton != (Object)null))
{
return pauseMenu.resumeButton;
}
return pauseMenu.exitGameButton;
}
private static void RefreshPauseMenuButtonList(PauseMenu pauseMenu)
{
Button[] componentsInChildren = pauseMenu.menuButtonContainer.GetComponentsInChildren<Button>(true);
AccessTools.Field(typeof(PauseMenu), "allButtons")?.SetValue(pauseMenu, componentsInChildren);
AccessTools.Method(typeof(PauseMenu), "UpdateButtonOffsets", (Type[])null, (Type[])null)?.Invoke(pauseMenu, null);
}
private static void FitPauseMenuButtonStack(PauseMenu pauseMenu)
{
//IL_0064: 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_007e: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_001e: 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_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
RectTransform component = pauseMenu.menuButtonContainer.GetComponent<RectTransform>();
if (!((Object)(object)component == (Object)null))
{
if (!pauseMenuStackAdjusted)
{
pauseMenuOriginalScale = ((Transform)component).localScale;
pauseMenuOriginalAnchoredPosition = component.anchoredPosition;
pauseMenuStackAdjusted = true;
}
((Transform)component).localScale = new Vector3(pauseMenuOriginalScale.x * 0.88f, pauseMenuOriginalScale.y * 0.88f, pauseMenuOriginalScale.z);
component.anchoredPosition = pauseMenuOriginalAnchoredPosition + new Vector2(0f, 26f);
}
}
private void RefreshPauseButton()
{
if (!((Object)(object)pauseButton == (Object)null))
{
bool active = NetworkServer.active;
((Selectable)pauseButton).interactable = active;
if ((Object)(object)pauseButtonLabel != (Object)null)
{
pauseButtonLabel.text = (active ? GetHostPauseButtonLabel() : "Host Pause Only");
}
}
}
private static string GetHostPauseButtonLabel()
{
if (isPaused)
{
return "Resume Game";
}
return "Pause Game";
}
}
}