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 EmotePlaylist v1.0.3
EmotePlaylist.dll
Decompiled a month agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using TooManyEmotes; using TooManyEmotes.Patches; using TooManyEmotes.Props; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; 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("EmotePlaylist")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.3.0")] [assembly: AssemblyInformationalVersion("1.0.3")] [assembly: AssemblyProduct("EmotePlaylist")] [assembly: AssemblyTitle("EmotePlaylist")] [assembly: AssemblyVersion("1.0.3.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace EmotePlaylist { internal static class InputUtil { private struct EdgeCache { public int Frame; public bool Result; public bool WasDown; } private static readonly Dictionary<KeyCode, Key> KeyMap = new Dictionary<KeyCode, Key> { { (KeyCode)97, (Key)15 }, { (KeyCode)98, (Key)16 }, { (KeyCode)99, (Key)17 }, { (KeyCode)100, (Key)18 }, { (KeyCode)101, (Key)19 }, { (KeyCode)102, (Key)20 }, { (KeyCode)103, (Key)21 }, { (KeyCode)104, (Key)22 }, { (KeyCode)105, (Key)23 }, { (KeyCode)106, (Key)24 }, { (KeyCode)107, (Key)25 }, { (KeyCode)108, (Key)26 }, { (KeyCode)109, (Key)27 }, { (KeyCode)110, (Key)28 }, { (KeyCode)111, (Key)29 }, { (KeyCode)112, (Key)30 }, { (KeyCode)113, (Key)31 }, { (KeyCode)114, (Key)32 }, { (KeyCode)115, (Key)33 }, { (KeyCode)116, (Key)34 }, { (KeyCode)117, (Key)35 }, { (KeyCode)118, (Key)36 }, { (KeyCode)119, (Key)37 }, { (KeyCode)120, (Key)38 }, { (KeyCode)121, (Key)39 }, { (KeyCode)122, (Key)40 }, { (KeyCode)48, (Key)50 }, { (KeyCode)49, (Key)41 }, { (KeyCode)50, (Key)42 }, { (KeyCode)51, (Key)43 }, { (KeyCode)52, (Key)44 }, { (KeyCode)53, (Key)45 }, { (KeyCode)54, (Key)46 }, { (KeyCode)55, (Key)47 }, { (KeyCode)56, (Key)48 }, { (KeyCode)57, (Key)49 }, { (KeyCode)32, (Key)1 }, { (KeyCode)304, (Key)51 }, { (KeyCode)303, (Key)52 }, { (KeyCode)306, (Key)55 }, { (KeyCode)305, (Key)56 }, { (KeyCode)308, (Key)53 }, { (KeyCode)307, (Key)54 }, { (KeyCode)9, (Key)3 }, { (KeyCode)301, (Key)72 }, { (KeyCode)8, (Key)65 }, { (KeyCode)13, (Key)2 }, { (KeyCode)27, (Key)60 }, { (KeyCode)273, (Key)63 }, { (KeyCode)274, (Key)64 }, { (KeyCode)276, (Key)61 }, { (KeyCode)275, (Key)62 }, { (KeyCode)277, (Key)70 }, { (KeyCode)127, (Key)71 }, { (KeyCode)278, (Key)68 }, { (KeyCode)279, (Key)69 }, { (KeyCode)280, (Key)67 }, { (KeyCode)281, (Key)66 }, { (KeyCode)282, (Key)94 }, { (KeyCode)283, (Key)95 }, { (KeyCode)284, (Key)96 }, { (KeyCode)285, (Key)97 }, { (KeyCode)286, (Key)98 }, { (KeyCode)287, (Key)99 }, { (KeyCode)288, (Key)100 }, { (KeyCode)289, (Key)101 }, { (KeyCode)290, (Key)102 }, { (KeyCode)291, (Key)103 }, { (KeyCode)292, (Key)104 }, { (KeyCode)293, (Key)105 } }; private static readonly Dictionary<KeyCode, EdgeCache> Edges = new Dictionary<KeyCode, EdgeCache>(); public static bool WasPressedThisFrame(KeyCode keyCode) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0079: 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) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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) int frameCount = Time.frameCount; if (Edges.TryGetValue(keyCode, out var value) && value.Frame == frameCount) { return value.Result; } bool wasDown = value.WasDown; bool flag = false; try { Keyboard current = Keyboard.current; if (current != null && KeyMap.TryGetValue(keyCode, out var value2)) { KeyControl val = current[value2]; if (val != null && ((ButtonControl)val).wasPressedThisFrame) { flag = true; } } } catch { } if (!flag) { try { if (Input.GetKeyDown(keyCode)) { flag = true; } } catch { } } bool flag2 = IsDown(keyCode); if (!flag) { flag = flag2 && !wasDown; } Edges[keyCode] = new EdgeCache { Frame = frameCount, Result = flag, WasDown = flag2 }; return flag; } public static bool IsDown(KeyCode keyCode) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) try { Keyboard current = Keyboard.current; if (current != null && KeyMap.TryGetValue(keyCode, out var value)) { KeyControl val = current[value]; if (val != null && ((ButtonControl)val).isPressed) { return true; } } } catch { } try { if (Input.GetKey(keyCode)) { return true; } } catch { } return false; } public unsafe static string TipLabel(KeyCode keyCode) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Expected I4, but got Unknown //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Invalid comparison between Unknown and I4 //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Invalid comparison between Unknown and I4 //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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) KeyCode val = keyCode; if ((int)val != 13) { if ((int)val != 27) { switch (val - 303) { case 0: case 1: return "Shift"; case 2: case 3: return "Ctrl"; case 4: case 5: return "Alt"; default: if ((int)keyCode >= 48 && (int)keyCode <= 57) { return ((char)(48 + (keyCode - 48))).ToString(); } return ((object)(*(KeyCode*)(&keyCode))/*cast due to .constrained prefix*/).ToString(); } } return "Esc"; } return "Enter"; } } internal sealed class PlaylistHud : MonoBehaviour { private static PlaylistHud? _instance; private Canvas? _canvas; private Image? _backdrop; private TextMeshProUGUI? _label; private bool _fontAssigned; private bool _visible; private float _nextRefresh; private string _cachedText = ""; private static readonly Color PanelBg = new Color(0.05f, 0.05f, 0.08f, 0.78f); private static readonly Color TextColor = new Color(0.92f, 0.92f, 0.95f, 1f); private static readonly Color AccentOrange = new Color(0.855f, 0.4f, 0.185f, 1f); internal static PlaylistHud? Instance => _instance; internal static bool IsVisible { get { if ((Object)(object)_instance != (Object)null) { return _instance._visible; } return false; } } internal static void EnsureExists() { //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 if (!((Object)(object)_instance != (Object)null)) { GameObject val = new GameObject("EmotePlaylistHUD"); Object.DontDestroyOnLoad((Object)val); _instance = val.AddComponent<PlaylistHud>(); } } internal static void Toggle() { EnsureExists(); if (!((Object)(object)_instance == (Object)null)) { _instance.SetVisible(!_instance._visible); } } internal static void Show() { EnsureExists(); _instance?.SetVisible(visible: true); } internal static void Hide() { _instance?.SetVisible(visible: false); } private void Awake() { _instance = this; BuildUi(); } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void BuildUi() { //IL_0058: 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_008c: Expected O, but got Unknown //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected O, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_018b: 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_01d7: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)_canvas != (Object)null)) { _canvas = ((Component)this).gameObject.AddComponent<Canvas>(); _canvas.renderMode = (RenderMode)0; _canvas.sortingOrder = 4900; CanvasScaler obj = ((Component)this).gameObject.AddComponent<CanvasScaler>(); obj.uiScaleMode = (ScaleMode)1; obj.referenceResolution = new Vector2(1920f, 1080f); ((Component)this).gameObject.AddComponent<GraphicRaycaster>(); GameObject val = new GameObject("Panel", new Type[1] { typeof(RectTransform) }); val.transform.SetParent(((Component)this).transform, false); RectTransform component = val.GetComponent<RectTransform>(); component.anchorMin = new Vector2(0f, 0.5f); component.anchorMax = new Vector2(0f, 0.5f); component.pivot = new Vector2(0f, 0.5f); component.sizeDelta = new Vector2(360f, 280f); component.anchoredPosition = new Vector2(24f, 40f); _backdrop = val.AddComponent<Image>(); ((Graphic)_backdrop).color = PanelBg; ((Graphic)_backdrop).raycastTarget = false; GameObject val2 = new GameObject("Label", new Type[1] { typeof(RectTransform) }); val2.transform.SetParent(val.transform, false); RectTransform component2 = val2.GetComponent<RectTransform>(); component2.anchorMin = Vector2.zero; component2.anchorMax = Vector2.one; component2.offsetMin = new Vector2(14f, 10f); component2.offsetMax = new Vector2(-14f, -10f); _label = val2.AddComponent<TextMeshProUGUI>(); ((TMP_Text)_label).alignment = (TextAlignmentOptions)257; ((TMP_Text)_label).fontStyle = (FontStyles)0; ((Graphic)_label).color = TextColor; ((TMP_Text)_label).enableWordWrapping = true; ((Graphic)_label).raycastTarget = false; ((TMP_Text)_label).overflowMode = (TextOverflowModes)0; ((TMP_Text)_label).fontSize = 20f; ((TMP_Text)_label).lineSpacing = 4f; ((TMP_Text)_label).text = ""; TryAssignFont(); ((Behaviour)_canvas).enabled = false; if ((Object)(object)_backdrop != (Object)null) { ((Component)_backdrop).gameObject.SetActive(false); } Plugin.Log.LogInfo((object)"EmotePlaylist HUD built."); } } private void TryAssignFont() { if ((Object)(object)_label == (Object)null || _fontAssigned) { return; } try { TMP_FontAsset val = null; HUDManager instance = HUDManager.Instance; if ((Object)(object)instance != (Object)null) { if (instance.controlTipLines != null) { TextMeshProUGUI[] controlTipLines = instance.controlTipLines; foreach (TextMeshProUGUI val2 in controlTipLines) { if ((Object)(object)val2 != (Object)null && (Object)(object)((TMP_Text)val2).font != (Object)null) { val = ((TMP_Text)val2).font; break; } } } if ((Object)(object)val == (Object)null && (Object)(object)instance.clockNumber != (Object)null && (Object)(object)((TMP_Text)instance.clockNumber).font != (Object)null) { val = ((TMP_Text)instance.clockNumber).font; } if ((Object)(object)val == (Object)null && (Object)(object)instance.weightCounter != (Object)null) { val = ((TMP_Text)instance.weightCounter).font; } } if ((Object)(object)val == (Object)null && (Object)(object)TMP_Settings.defaultFontAsset != (Object)null) { val = TMP_Settings.defaultFontAsset; } if ((Object)(object)val != (Object)null) { ((TMP_Text)_label).font = val; _fontAssigned = true; Plugin.Log.LogInfo((object)("EmotePlaylist HUD font: " + ((Object)val).name)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("EmotePlaylist HUD font assign failed: " + ex.Message)); } } private void LateUpdate() { if ((Object)(object)_canvas == (Object)null || (Object)(object)_label == (Object)null) { BuildUi(); } if (_visible) { TryAssignFont(); if (!(Time.unscaledTime < _nextRefresh)) { _nextRefresh = Time.unscaledTime + 0.5f; RefreshText(); } } } private void RefreshText() { //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)_label == (Object)null) { return; } StringBuilder stringBuilder = new StringBuilder(256); stringBuilder.Append("<b><color=#DA662F>Emote Playlist</color></b>\n"); int index; int remainSeconds; int total; bool flag = PlaylistRunner.TryGetStatus(out index, out remainSeconds, out total); string[] overrideNames = GetOverrideNames(); for (int i = 0; i < 8; i++) { string slotName = GetSlotName(i, overrideNames); string text = $"{i + 1}. {slotName}"; if (flag && i == index) { stringBuilder.Append($"<color=#DA662F><b>> {text}</b> ({remainSeconds}s)</color>\n"); } else { stringBuilder.Append(text).Append('\n'); } } string text2 = InputUtil.TipLabel(Plugin.PlaylistKey.Value); string text3 = InputUtil.TipLabel(Plugin.ListKey.Value); if (flag) { stringBuilder.Append($"\n<color=#AAAAAA>{text2} stop · {text3} hide · {index + 1}/{Mathf.Max(total, 1)} ({remainSeconds}s)</color>"); } else { stringBuilder.Append("\n<color=#AAAAAA>" + text2 + " start/stop · " + text3 + " hide</color>"); } _cachedText = stringBuilder.ToString(); ((TMP_Text)_label).text = _cachedText; ((Graphic)_label).color = TextColor; } private static string[]? GetOverrideNames() { string text = Plugin.PlaylistOverride?.Value; if (string.IsNullOrWhiteSpace(text)) { return null; } string[] array = text.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); string[] array2 = new string[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = array[i].Trim(); } return array2; } private static string GetSlotName(int index, string[]? overrideNames) { if (overrideNames != null) { if (index < overrideNames.Length && !string.IsNullOrEmpty(overrideNames[index])) { return overrideNames[index]; } return "(empty)"; } try { UnlockableEmote quickEmote = QuickEmotes.GetQuickEmote(index); if (quickEmote != null && !string.IsNullOrEmpty(quickEmote.emoteName)) { return quickEmote.emoteName; } } catch (Exception ex) { Plugin.Log.LogWarning((object)$"HUD quick slot {index}: {ex.Message}"); } return "(empty)"; } private void SetVisible(bool visible) { _visible = visible; if ((Object)(object)_canvas != (Object)null) { ((Behaviour)_canvas).enabled = visible; } if ((Object)(object)_backdrop != (Object)null && ((Component)_backdrop).gameObject.activeSelf != visible) { ((Component)_backdrop).gameObject.SetActive(visible); } if (visible) { _nextRefresh = 0f; RefreshText(); Plugin.Log.LogInfo((object)"EmotePlaylist HUD shown."); } else { Plugin.Log.LogInfo((object)"EmotePlaylist HUD hidden."); } } } internal static class PlaylistNet { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnMessage; } public const string MessageName = "MrGlim.EmotePlaylist"; private static bool _registered; public static void EnsureRegistered() { //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && !_registered) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<0>__OnMessage; if (obj == null) { HandleNamedMessageDelegate val = OnMessage; <>O.<0>__OnMessage = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("MrGlim.EmotePlaylist", (HandleNamedMessageDelegate)obj); _registered = true; } } public unsafe static void BroadcastStart(PlaylistState state) { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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_0030: Unknown result type (might be due to invalid IL or missing references) EnsureRegistered(); NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return; } FastBufferWriter val = WriteState(1, state); try { if (singleton.IsServer) { singleton.CustomMessagingManager.SendNamedMessageToAll("MrGlim.EmotePlaylist", val, (NetworkDelivery)2); } else { singleton.CustomMessagingManager.SendNamedMessage("MrGlim.EmotePlaylist", 0uL, val, (NetworkDelivery)2); } } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } public static void BroadcastStop(ulong ownerPlayerId) { //IL_0028: 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) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_0059: Unknown result type (might be due to invalid IL or missing references) EnsureRegistered(); NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null)) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); byte b = 0; ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref ownerPlayerId, default(ForPrimitives)); if (singleton.IsServer) { singleton.CustomMessagingManager.SendNamedMessageToAll("MrGlim.EmotePlaylist", val, (NetworkDelivery)2); } else { singleton.CustomMessagingManager.SendNamedMessage("MrGlim.EmotePlaylist", 0uL, val, (NetworkDelivery)2); } ((FastBufferWriter)(ref val)).Dispose(); } } private static FastBufferWriter WriteState(byte op, PlaylistState state) { //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_005c: 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_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0087: Unknown result type (might be due to invalid IL or missing references) string text = string.Join("|", state.EmoteNames); int byteCount = Encoding.UTF8.GetByteCount(text); FastBufferWriter result = default(FastBufferWriter); ((FastBufferWriter)(ref result))..ctor(64 + byteCount, (Allocator)2, -1); ((FastBufferWriter)(ref result)).WriteValueSafe<byte>(ref op, default(ForPrimitives)); ((FastBufferWriter)(ref result)).WriteValueSafe<ulong>(ref state.OwnerPlayerId, default(ForPrimitives)); ((FastBufferWriter)(ref result)).WriteValueSafe<double>(ref state.StartServerTime, default(ForPrimitives)); ((FastBufferWriter)(ref result)).WriteValueSafe<int>(ref state.SecondsPerEmote, default(ForPrimitives)); ((FastBufferWriter)(ref result)).WriteValueSafe(text, false); return result; } private unsafe static void OnMessage(ulong sender, FastBufferReader reader) { //IL_0006: 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) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001f: 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_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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_0060: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) byte b = default(byte); ((FastBufferReader)(ref reader)).ReadValueSafe<byte>(ref b, default(ForPrimitives)); ulong ownerPlayerId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref ownerPlayerId, default(ForPrimitives)); NetworkManager singleton = NetworkManager.Singleton; if (b == 0) { PlaylistRegistry.Clear(ownerPlayerId); if ((Object)(object)singleton != (Object)null && singleton.IsServer) { FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); byte b2 = 0; ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref b2, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref ownerPlayerId, default(ForPrimitives)); singleton.CustomMessagingManager.SendNamedMessageToAll("MrGlim.EmotePlaylist", val, (NetworkDelivery)2); ((FastBufferWriter)(ref val)).Dispose(); } return; } double startServerTime = default(double); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref startServerTime, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num, default(ForPrimitives)); string text = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref text, false); num = Mathf.Clamp(num, 60, 300); string[] emoteNames = (string.IsNullOrEmpty(text) ? Array.Empty<string>() : text.Split('|')); PlaylistState state = new PlaylistState { OwnerPlayerId = ownerPlayerId, StartServerTime = startServerTime, SecondsPerEmote = num, EmoteNames = emoteNames }; PlaylistRegistry.Set(state); if (!((Object)(object)singleton != (Object)null) || !singleton.IsServer || sender == 0L) { return; } FastBufferWriter val2 = WriteState(1, state); try { singleton.CustomMessagingManager.SendNamedMessageToAll("MrGlim.EmotePlaylist", val2, (NetworkDelivery)2); } finally { ((IDisposable)(*(FastBufferWriter*)(&val2))/*cast due to .constrained prefix*/).Dispose(); } } } internal sealed class PlaylistRunner : MonoBehaviour { private static PlaylistRunner? _instance; private ulong _followingOwner; private int _lastIndex = -1; private bool _running; private string _tip = ""; private float _tipUntil; private bool _didShowListOnStart; private bool _hadLocalPlayer; internal static bool IsRunning { get { if ((Object)(object)_instance != (Object)null) { return _instance._running; } return false; } } internal static bool TryGetStatus(out int index, out int remainSeconds, out int total) { index = 0; remainSeconds = 0; total = 0; if ((Object)(object)_instance == (Object)null || !_instance._running) { return false; } if (!PlaylistRegistry.TryGet(_instance._followingOwner, out PlaylistState state) || state.EmoteNames.Length == 0) { return false; } double num = ServerNow(); index = state.IndexAt(num); total = state.EmoteNames.Length; remainSeconds = state.SecondsPerEmote - (int)((num - state.StartServerTime) % (double)state.SecondsPerEmote); if (remainSeconds <= 0) { remainSeconds = state.SecondsPerEmote; } return true; } private void Awake() { _instance = this; } private void OnDestroy() { if ((Object)(object)_instance == (Object)(object)this) { _instance = null; } } private void Update() { //IL_0085: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_0191: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return; } PlaylistNet.EnsureRegistered(); PlaylistHud.EnsureExists(); PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.isPlayerDead) { StopLocal(_running); ClearStatusTip(); _hadLocalPlayer = false; return; } if (!_hadLocalPlayer) { _hadLocalPlayer = true; MaybeShowListOnStart(); } if (!val.isTypingChat && !val.inTerminalMenu) { if (InputUtil.WasPressedThisFrame(Plugin.PlaylistKey.Value)) { ToggleOwnPlaylist(val); } if (InputUtil.WasPressedThisFrame(Plugin.ListKey.Value)) { PlaylistHud.Toggle(); } } if (!_running) { if (Time.unscaledTime < _tipUntil && !string.IsNullOrEmpty(_tip)) { ShowControlTip(_tip); } return; } if (!PlaylistRegistry.TryGet(_followingOwner, out PlaylistState state) || state.EmoteNames.Length == 0) { StopLocal(broadcast: false); ClearStatusTip(); return; } double num = ServerNow(); int num2 = state.IndexAt(num); if (num2 != _lastIndex) { PlayIndex(state, num2); _lastIndex = num2; } int num3 = state.SecondsPerEmote - (int)((num - state.StartServerTime) % (double)state.SecondsPerEmote); if (num3 <= 0) { num3 = state.SecondsPerEmote; } _tip = $"Playlist {num2 + 1}/{state.EmoteNames.Length}: {state.EmoteNames[num2]} ({num3}s) [{InputUtil.TipLabel(Plugin.PlaylistKey.Value)} stop]"; ShowControlTip(_tip); } private void MaybeShowListOnStart() { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) if (_didShowListOnStart || Plugin.ShowListOnStart == null || !Plugin.ShowListOnStart.Value) { return; } _didShowListOnStart = true; PlaylistHud.Show(); string text = InputUtil.TipLabel(Plugin.ListKey.Value); string text2 = InputUtil.TipLabel(Plugin.PlaylistKey.Value); try { HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("Emote Playlist", text + " list · " + text2 + " start after setting TME quick slots", false, false, "LC_Tip1"); } } catch { } Plugin.Log.LogInfo((object)"ShowListOnStart: playlist HUD shown + tip."); } internal void Join(ulong ownerPlayerId) { if (PlaylistRegistry.TryGet(ownerPlayerId, out PlaylistState state) && state.EmoteNames.Length != 0) { _followingOwner = ownerPlayerId; _running = true; _lastIndex = -1; double serverTime = ServerNow(); int num = state.IndexAt(serverTime); PlayIndex(state, num); _lastIndex = num; FlashTip($"Joined playlist ({state.EmoteNames.Length} emotes)", 3f); Plugin.Log.LogInfo((object)$"Joined playlist owner={ownerPlayerId} index={num} duration={state.SecondsPerEmote}s"); } } private void ToggleOwnPlaylist(PlayerControllerB player) { //IL_000f: 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) Plugin.Log.LogInfo((object)$"Playlist key pressed ({Plugin.PlaylistKey.Value})."); if (_running && _followingOwner == player.playerClientId) { StopLocal(broadcast: true); FlashTip("Playlist stopped", 2.5f); return; } List<string> list = BuildPlaylist(); if (list.Count == 0) { Plugin.Log.LogWarning((object)"Playlist empty — assign TooManyEmotes quick slots (wheel remotes 1–8) first."); FlashTip("Playlist empty — set TME quick slots 1–8 first", 4f); try { string text = InputUtil.TipLabel(Plugin.PlaylistKey.Value); HUDManager instance = HUDManager.Instance; if (instance != null) { instance.DisplayTip("Emote Playlist", "Assign TooManyEmotes quick slots (wheel remotes), then press " + text + ".", false, false, "LC_Tip1"); } return; } catch { return; } } PlaylistState playlistState = new PlaylistState { OwnerPlayerId = player.playerClientId, StartServerTime = ServerNow(), SecondsPerEmote = Plugin.ClampedSeconds(), EmoteNames = list.ToArray() }; PlaylistRegistry.Set(playlistState); PlaylistNet.BroadcastStart(playlistState); _followingOwner = player.playerClientId; _running = true; _lastIndex = -1; FlashTip($"Playlist started ({list.Count} emotes)", 2.5f); Plugin.Log.LogInfo((object)$"Started playlist ({list.Count} emotes, {playlistState.SecondsPerEmote}s each)."); } private void StopLocal(bool broadcast) { if (_running) { ulong followingOwner = _followingOwner; _running = false; _lastIndex = -1; if (broadcast) { PlaylistRegistry.Clear(followingOwner); PlaylistNet.BroadcastStop(followingOwner); Plugin.Log.LogInfo((object)"Stopped playlist."); } } } private void FlashTip(string text, float seconds) { _tip = text; _tipUntil = Time.unscaledTime + seconds; ShowControlTip(text); } private void ClearStatusTip() { _tip = ""; _tipUntil = 0f; } private static void ShowControlTip(string text) { try { HUDManager instance = HUDManager.Instance; if (!((Object)(object)instance == (Object)null)) { instance.ChangeControlTip(3, text, false); } } catch { } } private static List<string> BuildPlaylist() { List<string> list = new List<string>(); string value = Plugin.PlaylistOverride.Value; if (!string.IsNullOrWhiteSpace(value)) { string[] array = value.Split(new char[2] { ',', ';' }, StringSplitOptions.RemoveEmptyEntries); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } return list; } for (int j = 0; j < 8; j++) { try { UnlockableEmote quickEmote = QuickEmotes.GetQuickEmote(j); if (quickEmote != null && !string.IsNullOrEmpty(quickEmote.emoteName)) { list.Add(quickEmote.emoteName); } } catch (Exception ex) { Plugin.Log.LogWarning((object)$"Quick slot {j} failed: {ex.Message}"); } } return list; } private static void PlayIndex(PlaylistState state, int index) { EmoteControllerPlayer emoteControllerLocal = EmoteControllerPlayer.emoteControllerLocal; if ((Object)(object)emoteControllerLocal == (Object)null || index < 0 || index >= state.EmoteNames.Length) { return; } string text = state.EmoteNames[index]; if (!EmotesManager.allUnlockableEmotesDict.TryGetValue(text, out var value) || value == null) { Plugin.Log.LogWarning((object)("Playlist emote not found: " + text)); return; } try { emoteControllerLocal.TryPerformingEmoteLocal(value, -1, (GrabbablePropObject)null); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to play " + text + ": " + ex.Message)); } } private static double ServerNow() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return Time.realtimeSinceStartupAsDouble; } NetworkTime serverTime = singleton.ServerTime; return ((NetworkTime)(ref serverTime)).Time; } } [HarmonyPatch(typeof(SyncWithEmoteControllerManager), "SyncWithEmoteController_performed")] internal static class SyncPlaylistPatch { [HarmonyPrefix] [HarmonyPriority(800)] private static bool Prefix(PlayerControllerB __instance) { if (Plugin.Enabled == null || !Plugin.Enabled.Value) { return true; } EmoteController lookingAtSyncableEmoteController = SyncWithEmoteControllerManager.lookingAtSyncableEmoteController; EmoteControllerPlayer val = (EmoteControllerPlayer)(object)((lookingAtSyncableEmoteController is EmoteControllerPlayer) ? lookingAtSyncableEmoteController : null); if (val == null || (Object)(object)val.playerController == (Object)null) { return true; } ulong playerClientId = val.playerController.playerClientId; if (!PlaylistRegistry.TryGet(playerClientId, out PlaylistState _)) { return true; } (((Object)(object)Plugin.Instance != (Object)null) ? ((Component)Plugin.Instance).GetComponent<PlaylistRunner>() : null)?.Join(playerClientId); SyncWithEmoteControllerManager.ResetState(); return false; } } internal sealed class PlaylistState { public ulong OwnerPlayerId; public double StartServerTime; public int SecondsPerEmote; public string[] EmoteNames = Array.Empty<string>(); public int IndexAt(double serverTime) { if (EmoteNames.Length == 0 || SecondsPerEmote <= 0) { return 0; } double num = serverTime - StartServerTime; if (num < 0.0) { num = 0.0; } int num2 = (int)(num / (double)SecondsPerEmote) % EmoteNames.Length; if (num2 >= 0) { return num2; } return num2 + EmoteNames.Length; } } internal static class PlaylistRegistry { private static readonly Dictionary<ulong, PlaylistState> ByOwner = new Dictionary<ulong, PlaylistState>(); public static void Set(PlaylistState state) { ByOwner[state.OwnerPlayerId] = state; } public static void Clear(ulong ownerPlayerId) { ByOwner.Remove(ownerPlayerId); } public static bool TryGet(ulong ownerPlayerId, out PlaylistState state) { return ByOwner.TryGetValue(ownerPlayerId, out state); } public static void ClearAll() { ByOwner.Clear(); } } [BepInPlugin("com.benhough.lethal.EmotePlaylist", "EmotePlaylist", "1.0.3")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string ModGuid = "com.benhough.lethal.EmotePlaylist"; public const string ModName = "EmotePlaylist"; public const string ModVersion = "1.0.3"; internal static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } internal static ConfigEntry<bool> Enabled { get; private set; } internal static ConfigEntry<KeyCode> PlaylistKey { get; private set; } internal static ConfigEntry<KeyCode> ListKey { get; private set; } internal static ConfigEntry<bool> ShowListOnStart { get; private set; } internal static ConfigEntry<int> SecondsPerEmote { get; private set; } internal static ConfigEntry<string> PlaylistOverride { get; private set; } private void Awake() { //IL_00e3: Unknown result type (might be due to invalid IL or missing references) Instance = this; Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Enable emote playlists."); PlaylistKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "PlaylistKey", (KeyCode)290, "Start/stop a looping playlist of your 8 TooManyEmotes quick slots (the wheel remotes)."); ListKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("General", "ListKey", (KeyCode)291, "Toggle the on-screen emote playlist panel."); ShowListOnStart = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ShowListOnStart", true, "Auto-show the playlist panel (and a tip) when your local player first becomes available this session."); SecondsPerEmote = ((BaseUnityPlugin)this).Config.Bind<int>("General", "SecondsPerEmote", 120, "How long each playlist emote plays (clamped 60–300)."); PlaylistOverride = ((BaseUnityPlugin)this).Config.Bind<string>("General", "PlaylistOverride", "", "Optional comma-separated emote names. Empty = use current quick slots 1–8."); try { new Harmony("com.benhough.lethal.EmotePlaylist").PatchAll(typeof(Plugin).Assembly); ((Component)this).gameObject.AddComponent<PlaylistRunner>(); PlaylistHud.EnsureExists(); Log.LogInfo((object)"EmotePlaylist v1.0.3 loaded."); } catch (Exception arg) { Log.LogError((object)$"Failed to start: {arg}"); } } internal static int ClampedSeconds() { return Mathf.Clamp(SecondsPerEmote?.Value ?? 120, 60, 300); } } internal static class PluginInfo { public const string PLUGIN_GUID = "com.benhough.lethal.EmotePlaylist"; public const string PLUGIN_NAME = "EmotePlaylist"; public const string PLUGIN_VERSION = "1.0.3"; } }