Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SpectatorPLUS v1.0.0
SpectatorPlus.dll
Decompiled 4 months agousing 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 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.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("Omniscye")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("SpectatorPlus")] [assembly: AssemblyTitle("SpectatorPlus")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmpressSpectate { [BepInPlugin("Omniscye.EmpressSpectate", "EmpressSpectate", "1.2.1")] public class EmpressSpectatePlugin : BaseUnityPlugin { internal static EmpressSpectatePlugin Instance { get; private set; } internal static ManualLogSource Logger => Instance._logger; private ManualLogSource _logger => ((BaseUnityPlugin)this).Logger; internal Harmony? Harmony { get; set; } private void Awake() { //IL_005f: 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_006e: Expected O, but got Unknown //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Expected O, but got Unknown //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Expected O, but got Unknown //IL_004d: Expected O, but got Unknown Instance = this; ((Component)this).gameObject.transform.parent = null; ((Object)((Component)this).gameObject).hideFlags = (HideFlags)61; if (Harmony == null) { Harmony val = new Harmony(((BaseUnityPlugin)this).Info.Metadata.GUID); Harmony val2 = val; Harmony = val; } Harmony.PatchAll(); GameObject val3 = new GameObject("EmpressSpectateUI") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val3); val3.AddComponent<EmpressSpectateUI>(); GameObject val4 = new GameObject("EmpressSpectateEventSync") { hideFlags = (HideFlags)61 }; Object.DontDestroyOnLoad((Object)(object)val4); val4.AddComponent<EmpressSpectateEventSync>(); Logger.LogInfo((object)$"{((BaseUnityPlugin)this).Info.Metadata.GUID} v{((BaseUnityPlugin)this).Info.Metadata.Version} loaded"); } private void OnDestroy() { Harmony? harmony = Harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal static class EmpressSpectateStamina { private struct StaminaData { public float Current; public float Max; public double Time; } internal const byte EventCode = 151; private static readonly Dictionary<int, StaminaData> Data = new Dictionary<int, StaminaData>(); internal static void HandleEvent(EventData photonEvent) { if (photonEvent.Code == 151 && photonEvent.CustomData is object[] array && array.Length >= 3) { int num; float current; float max; try { num = Convert.ToInt32(array[0]); current = Convert.ToSingle(array[1]); max = Convert.ToSingle(array[2]); } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("Stamina event parse failed: " + ex.Message)); return; } if (num > 0) { Data[num] = new StaminaData { Current = current, Max = max, Time = PhotonNetwork.Time }; } } } internal static void SetLocal(int actorNumber, float current, float max) { if (actorNumber > 0) { Data[actorNumber] = new StaminaData { Current = current, Max = max, Time = PhotonNetwork.Time }; } } internal static bool TryGet(int actorNumber, out float current, out float max) { if (Data.TryGetValue(actorNumber, out var value)) { current = value.Current; max = value.Max; return true; } current = 0f; max = 0f; return false; } } internal static class EmpressSpectateItem { internal const byte EventCode = 152; private static readonly Dictionary<int, string> Data = new Dictionary<int, string>(); internal static void HandleEvent(EventData photonEvent) { if (photonEvent.Code == 152 && photonEvent.CustomData is object[] array && array.Length >= 2) { int num; string value; try { num = Convert.ToInt32(array[0]); value = array[1]?.ToString() ?? string.Empty; } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("Item event parse failed: " + ex.Message)); return; } if (num > 0) { Data[num] = value; } } } internal static void SetLocal(int actorNumber, string name) { if (actorNumber > 0) { Data[actorNumber] = name ?? string.Empty; } } internal static bool TryGet(int actorNumber, out string name) { if (Data.TryGetValue(actorNumber, out name)) { return true; } name = string.Empty; return false; } internal static void Broadcast(int actorNumber, string name) { //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0055: Unknown result type (might be due to invalid IL or missing references) if (PhotonNetwork.IsConnected && PhotonNetwork.InRoom && !SemiFunc.MenuLevel()) { object[] array = new object[2] { actorNumber, name ?? string.Empty }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)152, (object)array, val, SendOptions.SendReliable); SetLocal(actorNumber, name); } } } internal class EmpressSpectateEventSync : MonoBehaviour { private float sendInterval = 0.2f; private float lastSendTime; private bool subscribed; private void Awake() { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private void OnEnable() { } private void OnDisable() { Unsubscribe(); } private void OnDestroy() { Unsubscribe(); } private void Update() { if (!ShouldBeActive()) { Unsubscribe(); return; } TrySubscribe(); if (Time.unscaledTime - lastSendTime >= sendInterval && CanSendStamina()) { lastSendTime = Time.unscaledTime; SendLocalStamina(); } } private bool ShouldBeActive() { if (!PhotonNetwork.IsConnected || !PhotonNetwork.InRoom) { return false; } if (SemiFunc.MenuLevel()) { return false; } if (!Object.op_Implicit((Object)(object)PlayerAvatar.instance) || !Object.op_Implicit((Object)(object)PlayerController.instance)) { return false; } return true; } private void TrySubscribe() { if (!subscribed && PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived += OnEvent; subscribed = true; } } private void Unsubscribe() { if (subscribed) { if (PhotonNetwork.NetworkingClient != null) { PhotonNetwork.NetworkingClient.EventReceived -= OnEvent; } subscribed = false; } } private bool CanSendStamina() { PlayerAvatar instance = PlayerAvatar.instance; if (!Object.op_Implicit((Object)(object)instance)) { return false; } PhotonView photonView = instance.photonView; if (!Object.op_Implicit((Object)(object)photonView)) { return false; } return photonView.IsMine; } private void SendLocalStamina() { //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Expected O, but got Unknown //IL_00b3: Unknown result type (might be due to invalid IL or missing references) PlayerController instance = PlayerController.instance; PlayerAvatar instance2 = PlayerAvatar.instance; if (Object.op_Implicit((Object)(object)instance) && Object.op_Implicit((Object)(object)instance2) && Object.op_Implicit((Object)(object)instance2.photonView)) { float num = instance.EnergyStart; float energyCurrent = instance.EnergyCurrent; if (num <= 0f) { num = 100f; } energyCurrent = Mathf.Clamp(energyCurrent, 0f, num); int ownerActorNr = instance2.photonView.OwnerActorNr; object[] array = new object[3] { ownerActorNr, energyCurrent, num }; RaiseEventOptions val = new RaiseEventOptions { Receivers = (ReceiverGroup)1 }; PhotonNetwork.RaiseEvent((byte)151, (object)array, val, SendOptions.SendUnreliable); EmpressSpectateStamina.SetLocal(ownerActorNr, energyCurrent, num); } } private void OnEvent(EventData photonEvent) { try { EmpressSpectateStamina.HandleEvent(photonEvent); EmpressSpectateItem.HandleEvent(photonEvent); } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("Event router exception: " + ex.Message)); } } } [HarmonyPatch] internal static class InventorySpotPatches { [HarmonyPostfix] [HarmonyPatch(typeof(InventorySpot), "EquipItem")] private static void Post_EquipItem(InventorySpot __instance) { try { PhotonView val = Inventory.instance?.physGrabber?.photonView; if (Object.op_Implicit((Object)(object)val)) { object obj; if (__instance == null) { obj = null; } else { ItemEquippable currentItem = __instance.CurrentItem; obj = ((currentItem == null) ? null : ((Component)currentItem).GetComponent<ItemAttributes>()?.item?.itemName); } if (obj == null) { obj = string.Empty; } string name = (string)obj; EmpressSpectateItem.Broadcast(val.OwnerActorNr, name); } } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("EquipItem patch failed: " + ex.Message)); } } [HarmonyPostfix] [HarmonyPatch(typeof(InventorySpot), "UnequipItem")] private static void Post_UnequipItem(InventorySpot __instance) { try { PhotonView val = Inventory.instance?.physGrabber?.photonView; if (Object.op_Implicit((Object)(object)val)) { EmpressSpectateItem.Broadcast(val.OwnerActorNr, string.Empty); } } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("UnequipItem patch failed: " + ex.Message)); } } } internal class EmpressSpectateUI : MonoBehaviour { private Canvas canvas; private RectTransform panelRoot; private TextMeshProUGUI headerText; private TextMeshProUGUI healthText; private TextMeshProUGUI staminaText; private TextMeshProUGUI itemText; private static FieldInfo spectatePlayerField; private static FieldInfo playerHealthValueField; private static FieldInfo playerMaxHealthField; private static FieldInfo grabbedPhysObjectField; private void Awake() { Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); SetupReflection(); BuildUI(); } private void SetupReflection() { Type typeFromHandle = typeof(SpectateCamera); spectatePlayerField = typeFromHandle.GetField("player", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Type typeFromHandle2 = typeof(PlayerHealth); playerHealthValueField = typeFromHandle2.GetField("health", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); playerMaxHealthField = typeFromHandle2.GetField("maxHealth", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); Type typeFromHandle3 = typeof(PhysGrabber); grabbedPhysObjectField = typeFromHandle3.GetField("grabbedPhysGrabObject", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } private void BuildUI() { //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Expected O, but got Unknown //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_0189: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01c1: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) //IL_01ee: Unknown result type (might be due to invalid IL or missing references) //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022d: Unknown result type (might be due to invalid IL or missing references) //IL_023c: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_028a: Unknown result type (might be due to invalid IL or missing references) //IL_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02a8: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Unknown result type (might be due to invalid IL or missing references) //IL_02e7: Unknown result type (might be due to invalid IL or missing references) //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0305: Unknown result type (might be due to invalid IL or missing references) canvas = ((Component)this).gameObject.AddComponent<Canvas>(); canvas.renderMode = (RenderMode)0; canvas.sortingOrder = 500; CanvasScaler val = ((Component)this).gameObject.AddComponent<CanvasScaler>(); val.uiScaleMode = (ScaleMode)1; val.referenceResolution = new Vector2(1920f, 1080f); val.screenMatchMode = (ScreenMatchMode)0; val.matchWidthOrHeight = 0.5f; ((Component)this).gameObject.AddComponent<GraphicRaycaster>(); GameObject val2 = new GameObject("Panel", new Type[2] { typeof(RectTransform), typeof(Image) }); val2.transform.SetParent(((Component)canvas).transform, false); panelRoot = val2.GetComponent<RectTransform>(); panelRoot.anchorMin = new Vector2(0.5f, 0.1f); panelRoot.anchorMax = new Vector2(0.5f, 0.1f); panelRoot.pivot = new Vector2(0.5f, 0.5f); panelRoot.anchoredPosition = Vector2.zero; panelRoot.sizeDelta = new Vector2(460f, 160f); Image component = val2.GetComponent<Image>(); ((Graphic)component).color = new Color(0.1f, 0f, 0f, 0.9f); Shadow val3 = val2.AddComponent<Shadow>(); val3.effectColor = new Color(1f, 0f, 0f, 0.5f); val3.effectDistance = new Vector2(5f, -5f); headerText = CreateText(panelRoot, "Header", new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0.5f, 1f), new Vector2(0f, -10f), 28f, (TextAlignmentOptions)514); healthText = CreateText(panelRoot, "Health", new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(20f, 30f), 20f, (TextAlignmentOptions)513); staminaText = CreateText(panelRoot, "Stamina", new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(0f, 0.5f), new Vector2(20f, 0f), 20f, (TextAlignmentOptions)513); itemText = CreateText(panelRoot, "Item", new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(0f, 0f), new Vector2(20f, -50f), 20f, (TextAlignmentOptions)513); ((Behaviour)canvas).enabled = false; } private TextMeshProUGUI CreateText(RectTransform parent, string name, Vector2 anchorMin, Vector2 anchorMax, Vector2 pivot, Vector2 offset, float fontSize, TextAlignmentOptions alignment) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0062: 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) //IL_0093: 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) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_0105: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject(name, new Type[2] { typeof(RectTransform), typeof(TextMeshProUGUI) }); val.transform.SetParent((Transform)(object)parent, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = anchorMin; component.anchorMax = anchorMax; component.pivot = pivot; component.anchoredPosition = offset; component.sizeDelta = new Vector2(parent.sizeDelta.x - 40f, 24f); TextMeshProUGUI component2 = val.GetComponent<TextMeshProUGUI>(); ((TMP_Text)component2).fontSize = fontSize; ((TMP_Text)component2).alignment = alignment; ((TMP_Text)component2).enableWordWrapping = false; ((Graphic)component2).raycastTarget = false; ((Graphic)component2).color = new Color(1f, 1f, 1f, 1f); ((TMP_Text)component2).fontStyle = (FontStyles)1; Outline val2 = val.AddComponent<Outline>(); ((Shadow)val2).effectColor = new Color(1f, 0f, 0f, 1f); ((Shadow)val2).effectDistance = new Vector2(3f, 3f); return component2; } private void Update() { if (!ShouldShow()) { if (((Behaviour)canvas).enabled) { ((Behaviour)canvas).enabled = false; } return; } PlayerAvatar spectatedAvatar = GetSpectatedAvatar(); if (!Object.op_Implicit((Object)(object)spectatedAvatar)) { if (((Behaviour)canvas).enabled) { ((Behaviour)canvas).enabled = false; } return; } ((Behaviour)canvas).enabled = true; string text = SemiFunc.PlayerGetName(spectatedAvatar); ((TMP_Text)headerText).text = "Spectating: " + text; PlayerHealth playerHealth = spectatedAvatar.playerHealth; string text2 = "Health: ?"; if (Object.op_Implicit((Object)(object)playerHealth) && playerHealthValueField != null && playerMaxHealthField != null) { try { object value = playerHealthValueField.GetValue(playerHealth); object value2 = playerMaxHealthField.GetValue(playerHealth); int num2 = ((value is int num) ? num : 0); int num4 = ((value2 is int num3) ? num3 : 0); num2 = Mathf.Max(0, num2); num4 = Mathf.Max(0, num4); text2 = ((num4 > 0) ? $"Health: {num2} / {num4}" : $"Health: {num2}"); } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("Health reflection failed: " + ex.Message)); } } ((TMP_Text)healthText).text = text2; string text3 = "Stamina: N/A"; PhotonView photonView = spectatedAvatar.photonView; if (Object.op_Implicit((Object)(object)photonView) && EmpressSpectateStamina.TryGet(photonView.OwnerActorNr, out var current, out var max) && max > 0f) { int num5 = Mathf.RoundToInt(current); int num6 = Mathf.RoundToInt(max); text3 = $"Stamina: {num5} / {num6}"; } ((TMP_Text)staminaText).text = text3; string text4 = "Item: None"; if (Object.op_Implicit((Object)(object)photonView) && EmpressSpectateItem.TryGet(photonView.OwnerActorNr, out string name) && !string.IsNullOrEmpty(name)) { text4 = "Item: " + name; } else { PhysGrabber physGrabber = spectatedAvatar.physGrabber; if (Object.op_Implicit((Object)(object)physGrabber) && grabbedPhysObjectField != null) { try { object? value3 = grabbedPhysObjectField.GetValue(physGrabber); PhysGrabObject val = (PhysGrabObject)((value3 is PhysGrabObject) ? value3 : null); if (Object.op_Implicit((Object)(object)val)) { ItemAttributes component = ((Component)val).GetComponent<ItemAttributes>(); if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.item)) { string itemName = component.item.itemName; if (!string.IsNullOrEmpty(itemName)) { text4 = "Item: " + itemName; } } } } catch (Exception ex2) { EmpressSpectatePlugin.Logger.LogWarning((object)("Item reflection failed: " + ex2.Message)); } } } ((TMP_Text)itemText).text = text4; } private bool ShouldShow() { if (!Object.op_Implicit((Object)(object)SpectateCamera.instance)) { return false; } if (!Object.op_Implicit((Object)(object)PlayerAvatar.instance)) { return false; } if (!PlayerAvatar.instance.spectating) { return false; } return true; } private PlayerAvatar GetSpectatedAvatar() { if (!Object.op_Implicit((Object)(object)SpectateCamera.instance) || spectatePlayerField == null) { return null; } try { object? value = spectatePlayerField.GetValue(SpectateCamera.instance); return (PlayerAvatar)((value is PlayerAvatar) ? value : null); } catch (Exception ex) { EmpressSpectatePlugin.Logger.LogWarning((object)("Spectated player reflection failed: " + ex.Message)); return null; } } } }