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 CymruSyncLockTV v1.0.0
plugins/CymruSyncLockTV/CymruTVSync.dll
Decompiled 3 weeks agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Logging; using CymruTVSync.NetcodePatcher; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Video; [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: IgnoresAccessChecksTo("Assembly-CSharp")] [assembly: AssemblyCompany("CymruTVSync")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Syncs the TV across all players using TVLoader.")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("CymruTVSync")] [assembly: AssemblyTitle("CymruTVSync")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] [module: NetcodePatchedAssembly] 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 CymruTVSync { internal class HostLockStatusOverlay : MonoBehaviour { private GUIStyle _labelStyle; private GUIStyle _boxStyle; private void OnGUI() { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006c: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008d: Unknown result type (might be due to invalid IL or missing references) if (ShouldShow()) { EnsureStyles(); string text = ((!TVSyncState.LockFeatureEnabled) ? "TV LOCK CTRL: OFF" : (TVSyncState.IsLocked ? "TV LOCK: ON" : "TV LOCK: OFF")); float num = (float)Screen.width - 170f - 16f; Rect val = default(Rect); ((Rect)(ref val))..ctor(num, 16f, 170f, 28f); Color color = GUI.color; GUI.Box(val, string.Empty, _boxStyle); GUI.Label(val, text, _labelStyle); GUI.color = color; } } private static bool ShouldShow() { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer; } private void EnsureStyles() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Expected O, but got Unknown //IL_0054: 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) //IL_0061: 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_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_0088: Expected O, but got Unknown //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) if (_boxStyle == null) { _boxStyle = new GUIStyle(GUI.skin.box); _boxStyle.normal.background = Texture2D.whiteTexture; } if (_labelStyle == null) { GUIStyle val = new GUIStyle(GUI.skin.label) { alignment = (TextAnchor)4, fontStyle = (FontStyle)1, fontSize = 12 }; val.normal.textColor = Color.white; _labelStyle = val; } GUI.color = (TVSyncState.IsLocked ? new Color(0.72f, 0.14f, 0.14f, 0.78f) : new Color(0.12f, 0.42f, 0.18f, 0.78f)); } } public class TVSyncNetworkHandler : MonoBehaviour { private const string RequestChangeMessageName = "CymruTVSync/RequestChange"; private const string RequestSyncMessageName = "CymruTVSync/RequestSync"; private const string ToggleLockMessageName = "CymruTVSync/ToggleLock"; private const string ToggleLockFeatureMessageName = "CymruTVSync/ToggleLockFeature"; private const string BroadcastStateMessageName = "CymruTVSync/BroadcastState"; private const string BroadcastLockStateMessageName = "CymruTVSync/BroadcastLockState"; private const string BroadcastLockFeatureMessageName = "CymruTVSync/BroadcastLockFeature"; private static bool _handlersRegistered; private static NetworkManager _registeredNetworkManager; private static bool _pendingSyncRequest; public static TVSyncNetworkHandler Instance { get; private set; } public static event Action<int, double, bool, string> OnTVStateReceived; public static event Action<bool> OnLockStateReceived; public static event Action<bool> OnLockFeatureStateReceived; public static void EnsureInstance() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Expected O, but got Unknown if (!((Object)(object)Instance != (Object)null)) { GameObject val = new GameObject("TVSyncNetworkHandlerLocal"); Object.DontDestroyOnLoad((Object)(object)val); Instance = val.AddComponent<TVSyncNetworkHandler>(); } } public static void EnsureMessagingReady(string source) { EnsureInstance(); Instance.TryEnsureMessagingReady(source); } private void Awake() { if ((Object)(object)Instance != (Object)null && (Object)(object)Instance != (Object)(object)this) { Object.Destroy((Object)(object)((Component)this).gameObject); return; } Instance = this; Object.DontDestroyOnLoad((Object)(object)((Component)this).gameObject); } private static string LocalRoleTag() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return "NO-NET"; } if (singleton.IsHost) { return "HOST"; } if (singleton.IsServer) { return "SERVER"; } if (singleton.IsClient) { return "CLIENT"; } return "OFFLINE"; } private static string LocalEndpointTag() { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { return "role=NO-NET local=n/a"; } return $"role={LocalRoleTag()} local={singleton.LocalClientId}"; } private bool TryEnsureMessagingReady(string source) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0119: Expected O, but got Unknown //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0136: Expected O, but got Unknown //IL_0149: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Expected O, but got Unknown //IL_0166: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Expected O, but got Unknown NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { TVSyncPlugin.Log.LogWarning((object)("[CymruTVSync][NGO] Messaging not ready during " + source + " because NetworkManager.Singleton is null.")); return false; } if (_handlersRegistered && (Object)(object)_registeredNetworkManager == (Object)(object)singleton) { return true; } if (singleton.CustomMessagingManager == null) { TVSyncPlugin.Log.LogWarning((object)("[CymruTVSync][NGO] Messaging not ready during " + source + " because CustomMessagingManager is null (" + LocalEndpointTag() + ").")); return false; } singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/RequestChange", new HandleNamedMessageDelegate(OnRequestChangeMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/RequestSync", new HandleNamedMessageDelegate(OnRequestSyncMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/ToggleLock", new HandleNamedMessageDelegate(OnToggleLockMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/ToggleLockFeature", new HandleNamedMessageDelegate(OnToggleLockFeatureMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/BroadcastState", new HandleNamedMessageDelegate(OnBroadcastStateMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/BroadcastLockState", new HandleNamedMessageDelegate(OnBroadcastLockStateMessage)); singleton.CustomMessagingManager.RegisterNamedMessageHandler("CymruTVSync/BroadcastLockFeature", new HandleNamedMessageDelegate(OnBroadcastLockFeatureMessage)); _registeredNetworkManager = singleton; _handlersRegistered = true; if (_pendingSyncRequest && singleton.IsClient && !singleton.IsServer) { _pendingSyncRequest = false; TryRequestFullSyncFromServer("PendingSyncRequest"); } return true; } public bool TrySendChangeToServer(string source, int clipIndex, double seekTime, bool tvOn) { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00be: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00d2: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (!TryEnsureMessagingReady(source)) { return false; } string currentMediaId = BestestTV.GetCurrentMediaId(); NetworkManager singleton = NetworkManager.Singleton; if (singleton.IsServer) { if (TVSyncState.LockFeatureEnabled && TVSyncState.IsLocked && string.Equals(source, "TVScript.TurnTVOnOff", StringComparison.Ordinal) && !TVSyncPatches.ConsumeHostControlIntent()) { TVSyncPlugin.Log.LogDebug((object)"[CymruTVSync] Ignoring mirrored TurnTVOnOff while locked because it was not host-initiated."); return false; } HandleRequestChange(singleton.LocalClientId, clipIndex, seekTime, tvOn, currentMediaId); return true; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4096, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref seekTime, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref tvOn, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(currentMediaId ?? string.Empty, false); singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/RequestChange", 0uL, val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public bool TryRequestFullSyncFromServer(string source) { //IL_006d: Unknown result type (might be due to invalid IL or missing references) if (!TryEnsureMessagingReady(source)) { _pendingSyncRequest = true; return false; } NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null) { _pendingSyncRequest = true; return false; } if (singleton.IsServer) { SendCurrentStateToClient(singleton.LocalClientId); return true; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1); try { singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/RequestSync", 0uL, val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public bool TryToggleLockFromHost(string source) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!TryEnsureMessagingReady(source)) { return false; } NetworkManager singleton = NetworkManager.Singleton; if (singleton.IsServer) { HandleToggleLock(singleton.LocalClientId); return true; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1); try { singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/ToggleLock", 0uL, val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } public bool TryToggleLockFeatureFromHost(string source) { //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (!TryEnsureMessagingReady(source)) { return false; } NetworkManager singleton = NetworkManager.Singleton; if (singleton.IsServer) { HandleToggleLockFeature(singleton.LocalClientId); return true; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(1, (Allocator)2, -1); try { singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/ToggleLockFeature", 0uL, val, (NetworkDelivery)3); return true; } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private void OnRequestChangeMessage(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); double seekTime = default(double); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref seekTime, default(ForPrimitives)); bool tvOn = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref tvOn, default(ForPrimitives)); string mediaId = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref mediaId, false); HandleRequestChange(senderClientId, clipIndex, seekTime, tvOn, mediaId); } private void HandleRequestChange(ulong senderClientId, int clipIndex, double seekTime, bool tvOn, string mediaId) { if (mediaId == null) { mediaId = string.Empty; } bool flag = clipIndex == TVSyncState.CurrentClip; bool flag2 = tvOn == TVSyncState.IsTvOn; bool flag3 = Math.Abs(seekTime - TVSyncState.SeekTime) < 0.01; bool flag4 = string.Equals(mediaId, TVSyncState.CurrentMediaId, StringComparison.OrdinalIgnoreCase); if (flag && flag2 && flag3 && flag4) { TVSyncPlugin.Log.LogDebug((object)"[CymruTVSync] Ignoring duplicate TV state request."); return; } if (TVSyncState.LockFeatureEnabled && TVSyncState.IsLocked && senderClientId != NetworkManager.Singleton.LocalClientId) { TVSyncPlugin.Log.LogDebug((object)$"[CymruTVSync] Client {senderClientId} tried to change TV but it is locked. Ignoring."); return; } TVSyncState.CurrentClip = clipIndex; TVSyncState.SeekTime = seekTime; TVSyncState.IsTvOn = tvOn; TVSyncState.CurrentMediaId = mediaId; BroadcastStateToClients(clipIndex, seekTime, tvOn, mediaId); } private void OnRequestSyncMessage(ulong senderClientId, FastBufferReader reader) { SendCurrentStateToClient(senderClientId); } private void SendCurrentStateToClient(ulong targetClientId) { SendStateMessage(targetClientId, TVSyncState.CurrentClip, TVSyncState.SeekTime, TVSyncState.IsTvOn, TVSyncState.CurrentMediaId); SendLockStateMessage(targetClientId, TVSyncState.IsLocked); SendLockFeatureStateMessage(targetClientId, TVSyncState.LockFeatureEnabled); } private void OnToggleLockMessage(ulong senderClientId, FastBufferReader reader) { HandleToggleLock(senderClientId); } private void HandleToggleLock(ulong senderClientId) { if (senderClientId != NetworkManager.Singleton.LocalClientId) { TVSyncPlugin.Log.LogWarning((object)$"[CymruTVSync][NGO-RX S<-C] Non-host client {senderClientId} tried to toggle lock. Ignoring."); return; } if (!TVSyncState.LockFeatureEnabled) { TVSyncPlugin.Log.LogDebug((object)"[CymruTVSync] Host tried to toggle TV lock while lock feature is disabled."); return; } TVSyncState.IsLocked = !TVSyncState.IsLocked; TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync][NGO-RX S<-C] Host toggled TV lock: {TVSyncState.IsLocked}. Broadcasting."); BroadcastLockStateToClients(TVSyncState.IsLocked); BroadcastStateToClients(TVSyncState.CurrentClip, TVSyncState.SeekTime, TVSyncState.IsTvOn, TVSyncState.CurrentMediaId); } private void OnToggleLockFeatureMessage(ulong senderClientId, FastBufferReader reader) { HandleToggleLockFeature(senderClientId); } private void HandleToggleLockFeature(ulong senderClientId) { if (senderClientId != NetworkManager.Singleton.LocalClientId) { TVSyncPlugin.Log.LogWarning((object)$"[CymruTVSync][NGO-RX S<-C] Non-host client {senderClientId} tried to toggle lock feature. Ignoring."); return; } TVSyncState.LockFeatureEnabled = !TVSyncState.LockFeatureEnabled; if (!TVSyncState.LockFeatureEnabled) { TVSyncState.IsLocked = false; } TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync][NGO-RX S<-C] Host toggled lock feature: {TVSyncState.LockFeatureEnabled}. Current lock={TVSyncState.IsLocked}. Broadcasting."); BroadcastLockFeatureStateToClients(TVSyncState.LockFeatureEnabled); BroadcastStateToClients(TVSyncState.CurrentClip, TVSyncState.SeekTime, TVSyncState.IsTvOn, TVSyncState.CurrentMediaId); if (!TVSyncState.LockFeatureEnabled) { BroadcastLockStateToClients(isLocked: false); } } private void BroadcastStateToClients(int clipIndex, double seekTime, bool tvOn, string mediaId) { if (mediaId == null) { mediaId = string.Empty; } ReceiveBroadcastState(clipIndex, seekTime, tvOn, mediaId, "LOCAL-HOST"); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != NetworkManager.Singleton.LocalClientId) { SendStateMessage(connectedClientsId, clipIndex, seekTime, tvOn, mediaId); } } } private void SendStateMessage(ulong targetClientId, int clipIndex, double seekTime, bool tvOn, string mediaId) { //IL_0015: 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) //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_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(4096, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref clipIndex, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref seekTime, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref tvOn, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe(mediaId ?? string.Empty, false); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/BroadcastState", targetClientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private void OnBroadcastStateMessage(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: 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) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_002f: 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) int clipIndex = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref clipIndex, default(ForPrimitives)); double seekTime = default(double); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref seekTime, default(ForPrimitives)); bool tvOn = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref tvOn, default(ForPrimitives)); string mediaId = default(string); ((FastBufferReader)(ref reader)).ReadValueSafe(ref mediaId, false); ReceiveBroadcastState(clipIndex, seekTime, tvOn, mediaId, senderClientId.ToString()); } private void ReceiveBroadcastState(int clipIndex, double seekTime, bool tvOn, string mediaId, string target) { if (mediaId == null) { mediaId = string.Empty; } TVSyncState.CurrentClip = clipIndex; TVSyncState.SeekTime = seekTime; TVSyncState.IsTvOn = tvOn; TVSyncState.CurrentMediaId = mediaId; TVSyncNetworkHandler.OnTVStateReceived?.Invoke(clipIndex, seekTime, tvOn, mediaId); } private void BroadcastLockStateToClients(bool isLocked) { ReceiveBroadcastLockState(isLocked, "LOCAL-HOST"); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != NetworkManager.Singleton.LocalClientId) { SendLockStateMessage(connectedClientsId, isLocked); } } } private void SendLockStateMessage(ulong targetClientId, bool isLocked) { //IL_0012: 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_002f: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref isLocked, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/BroadcastLockState", targetClientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private void OnBroadcastLockStateMessage(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) bool isLocked = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref isLocked, default(ForPrimitives)); ReceiveBroadcastLockState(isLocked, senderClientId.ToString()); } private void ReceiveBroadcastLockState(bool isLocked, string target) { TVSyncState.IsLocked = isLocked; TVSyncNetworkHandler.OnLockStateReceived?.Invoke(isLocked); if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost && (Object)(object)HUDManager.Instance != (Object)null) { string text = (isLocked ? "Host has locked the TV." : "Host has unlocked the TV."); HUDManager.Instance.DisplayTip("CymruTV Sync", text, false, false, "TVLockTip"); } } private void BroadcastLockFeatureStateToClients(bool enabled) { ReceiveBroadcastLockFeatureState(enabled, "LOCAL-HOST"); foreach (ulong connectedClientsId in NetworkManager.Singleton.ConnectedClientsIds) { if (connectedClientsId != NetworkManager.Singleton.LocalClientId) { SendLockFeatureStateMessage(connectedClientsId, enabled); } } } private void SendLockFeatureStateMessage(ulong targetClientId, bool enabled) { //IL_0012: 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_002f: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref enabled, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("CymruTVSync/BroadcastLockFeature", targetClientId, val, (NetworkDelivery)3); } finally { ((IDisposable)(FastBufferWriter)(ref val)).Dispose(); } } private void OnBroadcastLockFeatureMessage(ulong senderClientId, FastBufferReader reader) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) bool enabled = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref enabled, default(ForPrimitives)); ReceiveBroadcastLockFeatureState(enabled, senderClientId.ToString()); } private void ReceiveBroadcastLockFeatureState(bool enabled, string target) { TVSyncState.LockFeatureEnabled = enabled; TVSyncNetworkHandler.OnLockFeatureStateReceived?.Invoke(enabled); if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsHost && (Object)(object)HUDManager.Instance != (Object)null) { string text = (enabled ? "Host enabled TV lock controls (L toggles lock)." : "Host disabled TV lock controls."); HUDManager.Instance.DisplayTip("CymruTV Sync", text, false, false, "TVLockFeatureTip"); } } } public static class TVSyncState { public static int CurrentClip = 0; public static double SeekTime = 0.0; public static bool IsTvOn = false; public static string CurrentMediaId = string.Empty; public static bool LockFeatureEnabled = true; public static bool IsLocked = false; } [HarmonyPatch] public class TVSyncNetworkObjectManager { private static bool _ngoCallbacksRegistered; private static string LocalRole() { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return "NO-NET"; } if (NetworkManager.Singleton.IsHost) { return "HOST"; } if (NetworkManager.Singleton.IsServer) { return "SERVER"; } if (NetworkManager.Singleton.IsClient) { return "CLIENT"; } return "OFFLINE"; } private static void EnsureNgoCallbacks() { if (!_ngoCallbacksRegistered && !((Object)(object)NetworkManager.Singleton == (Object)null)) { NetworkManager.Singleton.OnClientConnectedCallback += delegate(ulong clientId) { TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync][NGO] OnClientConnected callback: client={clientId}, local={NetworkManager.Singleton.LocalClientId}, role={LocalRole()}."); }; NetworkManager.Singleton.OnClientDisconnectCallback += delegate(ulong clientId) { TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync][NGO] OnClientDisconnected callback: client={clientId}, local={NetworkManager.Singleton.LocalClientId}, role={LocalRole()}."); }; _ngoCallbacksRegistered = true; TVSyncPlugin.Log.LogInfo((object)"[CymruTVSync][NGO] Registered connection callbacks."); } } [HarmonyPostfix] [HarmonyPatch(typeof(GameNetworkManager), "Start")] public static void RegisterNetworkPrefab() { TVSyncNetworkHandler.EnsureInstance(); if ((Object)(object)NetworkManager.Singleton == (Object)null) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Could not initialize NGO messaging because NetworkManager.Singleton is null."); return; } EnsureNgoCallbacks(); TVSyncNetworkHandler.EnsureMessagingReady("GameNetworkManager.Start"); TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync] NGO message transport ready (role={LocalRole()}, local={NetworkManager.Singleton.LocalClientId})."); } [HarmonyPostfix] [HarmonyPatch(typeof(StartOfRound), "Awake")] public static void SpawnNetworkHandler() { TVSyncNetworkHandler.EnsureInstance(); if ((Object)(object)NetworkManager.Singleton == (Object)null) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Cannot refresh NGO messaging because NetworkManager.Singleton is null."); return; } TVSyncNetworkHandler.EnsureMessagingReady("StartOfRound.Awake"); TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync] NGO message transport refreshed for round start (role={LocalRole()}, local={NetworkManager.Singleton.LocalClientId})."); } } internal static class TVLockGuard { private static InteractTrigger _cachedTvTrigger; private static string _originalHoverTip; private static string _originalDisabledHoverTip; private static bool _warnedMissingTrigger; public static void ApplyAuthoritativeState() { TVSyncInputPatch.ApplyState(TVSyncState.CurrentClip, TVSyncState.SeekTime, TVSyncState.IsTvOn, TVSyncState.CurrentMediaId); } public static bool ShouldBlockLocalInput() { if (!TVSyncState.LockFeatureEnabled) { return false; } if (!TVSyncState.IsLocked) { return false; } if ((Object)(object)NetworkManager.Singleton == (Object)null) { return false; } return !NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer; } public static void NotifyBlocked(string reason) { } private static string ScenePath(Transform t) { if ((Object)(object)t == (Object)null) { return "(null)"; } StringBuilder stringBuilder = new StringBuilder(); Transform val = t; while ((Object)(object)val != (Object)null) { if (stringBuilder.Length > 0) { stringBuilder.Insert(0, "/"); } stringBuilder.Insert(0, ((Object)val).name); val = val.parent; } return stringBuilder.ToString(); } private static InteractTrigger FindTVInteractTrigger() { if ((Object)(object)_cachedTvTrigger != (Object)null) { return _cachedTvTrigger; } InteractTrigger[] array = Object.FindObjectsOfType<InteractTrigger>(true); string[] array2 = new string[5] { "Switch TV", "Turn on TV", "Turn off TV", "Toggle TV", "TV" }; string[] array3 = array2; foreach (string value in array3) { InteractTrigger[] array4 = array; foreach (InteractTrigger val in array4) { if (val.hoverTip != null && val.hoverTip.IndexOf(value, StringComparison.OrdinalIgnoreCase) >= 0) { _cachedTvTrigger = val; return _cachedTvTrigger; } } } TVScript[] array5 = Object.FindObjectsOfType<TVScript>(true); TVScript[] array6 = array5; foreach (TVScript val2 in array6) { InteractTrigger componentInChildren = ((Component)val2).GetComponentInChildren<InteractTrigger>(true); if ((Object)(object)componentInChildren != (Object)null) { _cachedTvTrigger = componentInChildren; return _cachedTvTrigger; } } InteractTrigger[] array7 = array; foreach (InteractTrigger val3 in array7) { Transform val4 = ((Component)val3).transform; while ((Object)(object)val4 != (Object)null) { if (((Object)val4).name.IndexOf("Television", StringComparison.OrdinalIgnoreCase) >= 0 || ((Object)val4).name.IndexOf("TVSet", StringComparison.OrdinalIgnoreCase) >= 0) { _cachedTvTrigger = val3; return _cachedTvTrigger; } val4 = val4.parent; } } return null; } public static void ApplyTriggerLock() { if ((Object)(object)NetworkManager.Singleton == (Object)null) { return; } bool flag = TVSyncState.LockFeatureEnabled && TVSyncState.IsLocked; bool flag2 = NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer; InteractTrigger val = FindTVInteractTrigger(); if ((Object)(object)val == (Object)null) { if (!_warnedMissingTrigger) { _warnedMissingTrigger = true; TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Could not find TV InteractTrigger to apply lock state."); } return; } _warnedMissingTrigger = false; if (string.IsNullOrEmpty(_originalHoverTip)) { _originalHoverTip = val.hoverTip; } if (string.IsNullOrEmpty(_originalDisabledHoverTip)) { _originalDisabledHoverTip = val.disabledHoverTip; } string text = (string.IsNullOrWhiteSpace(_originalHoverTip) ? "Switch TV" : _originalHoverTip); if (flag2) { val.interactable = true; val.hoverTip = (flag ? (text + "\nTV is locked for clients") : (text + "\nTV is unlocked")); val.disabledHoverTip = _originalDisabledHoverTip; } else if (flag) { val.interactable = false; val.disabledHoverTip = "TV locked"; val.hoverTip = text; } else { val.interactable = true; val.hoverTip = text; val.disabledHoverTip = _originalDisabledHoverTip; } } } internal static class BestestTV { private static Type _patchType; private static Type _videoManagerType; private static Type _configType; public static FieldInfo TVIndexField; public static FieldInfo VideoSourceField; public static FieldInfo AudioSourceField; public static FieldInfo TvIsOnField; public static FieldInfo VideosField; public static FieldInfo EnableChannelsField; public static FieldInfo EnableSeekingField; public static FieldInfo SkipForwardKeyField; public static FieldInfo SkipReverseKeyField; public static FieldInfo SeekForwardKeyField; public static FieldInfo SeekReverseKeyField; public static bool Ready { get; private set; } public static int TVIndex { get { return (TVIndexField != null) ? ((int)TVIndexField.GetValue(null)) : 0; } set { TVIndexField?.SetValue(null, value); } } public static VideoPlayer VideoSource { get { object? obj = VideoSourceField?.GetValue(null); return (VideoPlayer)((obj is VideoPlayer) ? obj : null); } } public static AudioSource AudioSource { get { object? obj = AudioSourceField?.GetValue(null); return (AudioSource)((obj is AudioSource) ? obj : null); } } public static bool TvIsOn { get { return TvIsOnField != null && (bool)TvIsOnField.GetValue(null); } set { TvIsOnField?.SetValue(null, value); } } public static List<string> Videos => VideosField?.GetValue(null) as List<string>; public static bool EnableChannels => EnableChannelsField == null || GetConfigValue<bool>(EnableChannelsField); public static bool EnableSeeking => EnableSeekingField == null || GetConfigValue<bool>(EnableSeekingField); public static void Init() { try { Assembly assembly = FindBestestTVAssembly(); if (assembly == null) { TVSyncPlugin.Log.LogError((object)("[CymruTVSync] Could not find BestestTVMod assembly. Loaded assemblies: " + string.Join(", ", GetLoadedAssemblyNames()))); return; } TVSyncPlugin.Log.LogInfo((object)("[CymruTVSync] Found BestestTVMod assembly: " + assembly.GetName().Name)); Type[] types = assembly.GetTypes(); foreach (Type type in types) { if (_patchType == null && type.GetField("TVIndex", BindingFlags.Static | BindingFlags.Public) != null) { _patchType = type; } if (_videoManagerType == null && type.GetField("Videos", BindingFlags.Static | BindingFlags.Public) != null) { _videoManagerType = type; } if (_configType == null && type.GetField("enableChannels", BindingFlags.Static | BindingFlags.Public) != null) { _configType = type; } } if (_patchType == null) { TVSyncPlugin.Log.LogError((object)"[CymruTVSync] Could not find TVScriptPatches type in BestestTVMod!"); return; } TVSyncPlugin.Log.LogInfo((object)("[CymruTVSync] Found patch type: " + _patchType.FullName)); BindingFlags bindingAttr = BindingFlags.Static | BindingFlags.Public; TVIndexField = _patchType.GetField("TVIndex", bindingAttr); VideoSourceField = _patchType.GetField("videoSource", bindingAttr); AudioSourceField = _patchType.GetField("audioSource", bindingAttr); TvIsOnField = _patchType.GetField("tvIsCurrentlyOn", bindingAttr); if (_videoManagerType != null) { VideosField = _videoManagerType.GetField("Videos", bindingAttr); } if (_configType != null) { EnableChannelsField = _configType.GetField("enableChannels", bindingAttr); EnableSeekingField = _configType.GetField("enableSeeking", bindingAttr); SkipForwardKeyField = _configType.GetField("skipForwardKeyBind", bindingAttr); SkipReverseKeyField = _configType.GetField("skipReverseKeyBind", bindingAttr); SeekForwardKeyField = _configType.GetField("seekForwardKeyBind", bindingAttr); SeekReverseKeyField = _configType.GetField("seekReverseKeyBind", bindingAttr); } Ready = TVIndexField != null && VideoSourceField != null; TVSyncPlugin.Log.LogInfo((object)($"[CymruTVSync] BestestTV reflection ready={Ready}. " + $"TVIndex={TVIndexField != null}, videoSource={VideoSourceField != null}, " + $"Videos={VideosField != null}, Config={_configType != null}")); } catch (Exception arg) { TVSyncPlugin.Log.LogError((object)$"[CymruTVSync] Reflection init failed: {arg}"); } } private static Assembly FindBestestTVAssembly() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); foreach (Assembly assembly in assemblies) { if (IsBestestTVAssemblyName(assembly.GetName().Name)) { return assembly; } } try { string pluginPath = Paths.PluginPath; if (!Directory.Exists(pluginPath)) { return null; } string[] files = Directory.GetFiles(pluginPath, "*.dll", SearchOption.AllDirectories); foreach (string text in files) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(text); if (IsBestestTVAssemblyName(fileNameWithoutExtension)) { TVSyncPlugin.Log.LogInfo((object)("[CymruTVSync] Loading BestestTV assembly from disk: " + text)); return Assembly.LoadFrom(text); } } } catch (Exception ex) { TVSyncPlugin.Log.LogWarning((object)("[CymruTVSync] Failed to load BestestTV assembly from disk: " + ex.Message)); } return null; } private static bool IsBestestTVAssemblyName(string assemblyName) { if (string.IsNullOrWhiteSpace(assemblyName)) { return false; } return assemblyName.IndexOf("BestestTelevisionMod", StringComparison.OrdinalIgnoreCase) >= 0 || assemblyName.IndexOf("BestestTV", StringComparison.OrdinalIgnoreCase) >= 0 || assemblyName.IndexOf("DeathWrench", StringComparison.OrdinalIgnoreCase) >= 0; } private static string[] GetLoadedAssemblyNames() { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); string[] array = new string[assemblies.Length]; for (int i = 0; i < assemblies.Length; i++) { array[i] = assemblies[i].GetName().Name; } return array; } private static T GetConfigValue<T>(FieldInfo fi) { try { object value = fi.GetValue(null); if (value == null) { return default(T); } PropertyInfo property = value.GetType().GetProperty("Value"); if (property == null) { return default(T); } return (T)property.GetValue(value); } catch { return default(T); } } public static Key GetKeyBind(FieldInfo fi, Key fallback) { //IL_004b: 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_004f: 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_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0046: Unknown result type (might be due to invalid IL or missing references) try { object obj = fi?.GetValue(null); if (obj == null) { return fallback; } PropertyInfo property = obj.GetType().GetProperty("Value"); return (property == null) ? fallback : ConvertToInputSystemKey(property.GetValue(obj), fallback); } catch { return fallback; } } private static Key ConvertToInputSystemKey(object value, Key fallback) { //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //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_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_0052: 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_0053: Unknown result type (might be due to invalid IL or missing references) if (value == null) { return fallback; } if (value is Key result) { return result; } string value2 = value.ToString(); if (string.IsNullOrWhiteSpace(value2)) { return fallback; } Key result2; return Enum.TryParse<Key>(value2, ignoreCase: true, out result2) ? result2 : fallback; } public static bool WasPressedThisFrame(Key key) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Keyboard current = Keyboard.current; if (current == null) { return false; } try { return ((ButtonControl)current[key]).wasPressedThisFrame; } catch { return false; } } public static string NormalizeMediaId(string media) { if (string.IsNullOrWhiteSpace(media)) { return string.Empty; } string text = media.Trim(); if (Uri.TryCreate(text, UriKind.Absolute, out Uri result)) { text = ((!result.IsFile) ? result.AbsoluteUri : result.LocalPath); } else if (text.StartsWith("file://", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(7); } string fileName = Path.GetFileName(text); if (!string.IsNullOrWhiteSpace(fileName)) { return fileName.Trim().ToLowerInvariant(); } text = text.Replace('\\', '/').TrimStart('/'); return text.ToLowerInvariant(); } public static string GetCurrentMediaId() { return ((Object)(object)VideoSource == (Object)null) ? string.Empty : NormalizeMediaId(VideoSource.url); } public static int FindVideoIndexByMediaId(string mediaId) { string text = NormalizeMediaId(mediaId); if (string.IsNullOrEmpty(text)) { return -1; } List<string> videos = Videos; if (videos == null) { return -1; } for (int i = 0; i < videos.Count; i++) { if (NormalizeMediaId(videos[i]) == text) { return i; } } return -1; } } [HarmonyPatch] public class TVSyncBestestHooks { [CompilerGenerated] private sealed class <TargetMethods>d__9 : IEnumerable<MethodBase>, IEnumerable, IEnumerator<MethodBase>, IEnumerator, IDisposable { private int <>1__state; private MethodBase <>2__current; private int <>l__initialThreadId; private Type <targetType>5__1; private string[] <methodNames>5__2; private string[] <>s__3; private int <>s__4; private string <methodName>5__5; private MethodInfo <method>5__6; MethodBase IEnumerator<MethodBase>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TargetMethods>d__9(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Environment.CurrentManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <targetType>5__1 = null; <methodNames>5__2 = null; <>s__3 = null; <methodName>5__5 = null; <method>5__6 = null; <>1__state = -2; } private bool MoveNext() { int num = <>1__state; if (num != 0) { if (num != 1) { return false; } <>1__state = -1; <method>5__6 = null; <methodName>5__5 = null; goto IL_012e; } <>1__state = -1; <targetType>5__1 = AccessTools.TypeByName("BestestTVModPlugin.TVScriptPatches"); if (<targetType>5__1 == null) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Could not find BestestTVModPlugin.TVScriptPatches for direct input hooks."); return false; } <methodNames>5__2 = new string[5] { "TVIndexUp", "TVIndexDown", "GetTVInput", "Update", "TurnTVOnOff" }; <>s__3 = <methodNames>5__2; <>s__4 = 0; goto IL_013c; IL_012e: <>s__4++; goto IL_013c; IL_013c: if (<>s__4 < <>s__3.Length) { <methodName>5__5 = <>s__3[<>s__4]; <method>5__6 = AccessTools.DeclaredMethod(<targetType>5__1, <methodName>5__5, (Type[])null, (Type[])null); if (<method>5__6 == null) { TVSyncPlugin.Log.LogWarning((object)("[CymruTVSync] Could not hook BestestTV method " + <methodName>5__5 + ".")); goto IL_012e; } <>2__current = <method>5__6; <>1__state = 1; return true; } <>s__3 = null; return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<MethodBase> IEnumerable<MethodBase>.GetEnumerator() { if (<>1__state == -2 && <>l__initialThreadId == Environment.CurrentManagedThreadId) { <>1__state = 0; return this; } return new <TargetMethods>d__9(0); } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<MethodBase>)this).GetEnumerator(); } } private static int _preInputClip; private static double _preInputTime; private static bool _preInputOn; private static bool _updateSnapshotReady; private static int _lastUpdateClip; private static double _lastUpdateTime; private static bool _lastUpdateOn; private static bool _warnedBestestNotReady; private static bool _warnedHandlerMissing; [IteratorStateMachine(typeof(<TargetMethods>d__9))] public static IEnumerable<MethodBase> TargetMethods() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TargetMethods>d__9(-2); } [HarmonyPrefix] [HarmonyPriority(200)] public static bool Prefix(MethodBase __originalMethod) { if (__originalMethod == null) { return true; } string name = __originalMethod.Name; if (name == "GetTVInput") { _preInputClip = BestestTV.TVIndex; _preInputTime = (((Object)(object)BestestTV.VideoSource != (Object)null) ? BestestTV.VideoSource.time : 0.0); _preInputOn = BestestTV.TvIsOn; } switch (name) { default: if (!(name == "TurnTVOnOff")) { break; } goto case "TVIndexUp"; case "TVIndexUp": case "TVIndexDown": case "GetTVInput": if (TVLockGuard.ShouldBlockLocalInput()) { if (name == "TurnTVOnOff" && TVSyncPatches.SuppressOutboundSync) { return true; } if (name != "GetTVInput") { TVLockGuard.NotifyBlocked(name); } return false; } break; } return true; } [HarmonyPostfix] [HarmonyPriority(200)] public static void Postfix(MethodBase __originalMethod) { //IL_0201: Unknown result type (might be due to invalid IL or missing references) //IL_0206: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0213: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_021d: Unknown result type (might be due to invalid IL or missing references) if (__originalMethod == null || TVSyncPatches.SuppressOutboundSync) { return; } if (!BestestTV.Ready) { BestestTV.Init(); if (!BestestTV.Ready) { if (!_warnedBestestNotReady) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Bestest hooks skipped because BestestTV reflection is not ready on this client."); _warnedBestestNotReady = true; } return; } } _warnedBestestNotReady = false; if ((Object)(object)TVSyncNetworkHandler.Instance == (Object)null) { if (!_warnedHandlerMissing) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] Bestest hooks skipped because TVSyncNetworkHandler.Instance is null on this client."); _warnedHandlerMissing = true; } return; } _warnedHandlerMissing = false; int tVIndex = BestestTV.TVIndex; double num = (((Object)(object)BestestTV.VideoSource != (Object)null) ? BestestTV.VideoSource.time : 0.0); bool tvIsOn = BestestTV.TvIsOn; if (__originalMethod.Name == "TVIndexUp" || __originalMethod.Name == "TVIndexDown") { TVSyncNetworkHandler.Instance.TrySendChangeToServer("Bestest:" + __originalMethod.Name, tVIndex, 0.0, tvIsOn); } else if (__originalMethod.Name == "Update") { if (_updateSnapshotReady) { bool flag = tVIndex == _lastUpdateClip; bool flag2 = tvIsOn == _lastUpdateOn; double num2 = Math.Abs(num - _lastUpdateTime); if (flag && flag2 && tvIsOn && num2 >= 1.0) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("Bestest:UpdateSeekJump", tVIndex, num, tvIsOn); } } _lastUpdateClip = tVIndex; _lastUpdateTime = num; _lastUpdateOn = tvIsOn; _updateSnapshotReady = true; } else { if (__originalMethod.Name != "GetTVInput") { return; } Key keyBind = BestestTV.GetKeyBind(BestestTV.SeekForwardKeyField, (Key)63); Key keyBind2 = BestestTV.GetKeyBind(BestestTV.SeekReverseKeyField, (Key)64); if ((BestestTV.WasPressedThisFrame(keyBind) || BestestTV.WasPressedThisFrame(keyBind2)) && BestestTV.EnableSeeking) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("Bestest:GetTVInputSeekKey", tVIndex, num, tvIsOn); return; } bool flag3 = tVIndex != _preInputClip; bool flag4 = tvIsOn != _preInputOn; bool flag5 = Math.Abs(num - _preInputTime) >= 0.75; if (flag3 || flag4 || flag5) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("Bestest:GetTVInputDelta", tVIndex, num, tvIsOn); } } } } [HarmonyPatch] public class TVSyncPatches { private static float _ignoreOutboundUntilTime; private static bool _skipNextTurnTvOnOffPostfix; private static float _hostControlIntentUntilTime; private static int _lastObservedClip = -1; private static double _lastObservedSeek = 0.0; private static bool _lastObservedOn = false; private static bool _hasObservedState; private static string _lastObservedMediaId = string.Empty; private static float _nextWatchSendTime; private static bool _watcherWarnedBestestNotReady; private static bool _watcherWarnedHandlerMissing; internal static bool SuppressOutboundSync => Time.unscaledTime < _ignoreOutboundUntilTime; internal static void MarkHostControlIntent(float durationSeconds = 0.5f) { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && (NetworkManager.Singleton.IsHost || NetworkManager.Singleton.IsServer)) { _hostControlIntentUntilTime = Mathf.Max(_hostControlIntentUntilTime, Time.unscaledTime + durationSeconds); } } internal static bool ConsumeHostControlIntent() { bool flag = Time.unscaledTime <= _hostControlIntentUntilTime; if (flag) { _hostControlIntentUntilTime = 0f; } return flag; } internal static void BeginSuppressedRemoteApply() { _ignoreOutboundUntilTime = Mathf.Max(_ignoreOutboundUntilTime, Time.unscaledTime + 1f); } internal static void EndSuppressedRemoteApply() { _ignoreOutboundUntilTime = Mathf.Max(_ignoreOutboundUntilTime, Time.unscaledTime + 0.5f); } internal static void UpdateObservedStateSnapshot(int clipIndex, double seekTime, bool tvOn, string mediaId) { _lastObservedClip = clipIndex; _lastObservedSeek = seekTime; _lastObservedOn = tvOn; _lastObservedMediaId = mediaId ?? string.Empty; _hasObservedState = true; _nextWatchSendTime = Mathf.Max(_nextWatchSendTime, Time.unscaledTime + 0.75f); } [HarmonyPostfix] [HarmonyPatch(typeof(TVScript), "Update")] [HarmonyPriority(200)] public static void TVUpdate_Postfix() { if (SuppressOutboundSync) { return; } if (!BestestTV.Ready) { BestestTV.Init(); if (!BestestTV.Ready) { if (!_watcherWarnedBestestNotReady) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] TV watcher skipped because BestestTV reflection is not ready on this client."); _watcherWarnedBestestNotReady = true; } return; } } _watcherWarnedBestestNotReady = false; if ((Object)(object)TVSyncNetworkHandler.Instance == (Object)null) { if (!_watcherWarnedHandlerMissing) { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] TV watcher skipped because TVSyncNetworkHandler.Instance is null on this client."); _watcherWarnedHandlerMissing = true; } return; } _watcherWarnedHandlerMissing = false; if ((Object)(object)NetworkManager.Singleton == (Object)null || !NetworkManager.Singleton.IsClient) { return; } int tVIndex = BestestTV.TVIndex; double num = (((Object)(object)BestestTV.VideoSource != (Object)null) ? BestestTV.VideoSource.time : 0.0); bool tvIsOn = BestestTV.TvIsOn; string currentMediaId = BestestTV.GetCurrentMediaId(); if (!_hasObservedState) { _lastObservedClip = tVIndex; _lastObservedSeek = num; _lastObservedOn = tvIsOn; _lastObservedMediaId = currentMediaId; _hasObservedState = true; return; } bool flag = tVIndex != _lastObservedClip; bool flag2 = tvIsOn != _lastObservedOn; bool flag3 = Math.Abs(num - _lastObservedSeek) >= 1.0; bool flag4 = !string.Equals(currentMediaId, _lastObservedMediaId, StringComparison.OrdinalIgnoreCase); if (flag || flag2 || flag3 || flag4) { if (TVLockGuard.ShouldBlockLocalInput()) { _lastObservedClip = TVSyncState.CurrentClip; _lastObservedSeek = TVSyncState.SeekTime; _lastObservedOn = TVSyncState.IsTvOn; _lastObservedMediaId = TVSyncState.CurrentMediaId; return; } if (Time.unscaledTime >= _nextWatchSendTime) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("TVScript.UpdateWatcher", tVIndex, num, tvIsOn); _nextWatchSendTime = Time.unscaledTime + 0.12f; } } _lastObservedClip = tVIndex; _lastObservedSeek = num; _lastObservedOn = tvIsOn; _lastObservedMediaId = currentMediaId; } [HarmonyPrefix] [HarmonyPatch(typeof(TVScript), "TurnTVOnOff")] [HarmonyPriority(600)] public static bool TurnTVOnOff_Prefix(bool on) { MarkHostControlIntent(0.6f); if (!TVLockGuard.ShouldBlockLocalInput()) { return true; } _skipNextTurnTvOnOffPostfix = true; return true; } [HarmonyPostfix] [HarmonyPatch(typeof(TVScript), "TurnTVOnOff")] [HarmonyPriority(200)] public static void TurnTVOnOff_Postfix(bool on) { if (_skipNextTurnTvOnOffPostfix) { _skipNextTurnTvOnOffPostfix = false; } else if (!SuppressOutboundSync && BestestTV.Ready && !((Object)(object)TVSyncNetworkHandler.Instance == (Object)null)) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("TVScript.TurnTVOnOff", BestestTV.TVIndex, ((Object)(object)BestestTV.VideoSource != (Object)null) ? BestestTV.VideoSource.time : 0.0, on); } } [HarmonyPostfix] [HarmonyPatch(typeof(TVScript), "TVFinishedClip")] [HarmonyPriority(200)] public static void TVFinishedClip_Postfix() { if (!SuppressOutboundSync && BestestTV.Ready && !((Object)(object)TVSyncNetworkHandler.Instance == (Object)null) && BestestTV.TvIsOn) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("TVScript.TVFinishedClip", BestestTV.TVIndex, 0.0, tvOn: true); } } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] public class TVSyncInputPatch { [CompilerGenerated] private static class <>O { public static EventHandler <0>__OnVideoPrepared; } private static VideoPlayer _preparedVideoSource; private static AudioSource _preparedAudioSource; private static double _preparedSeekTime; private static bool _preparedTvOn; private static int _preparedClipIndex; private static string _preparedMediaId; [HarmonyPostfix] [HarmonyPriority(200)] public static void Update_Postfix(PlayerControllerB __instance) { //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d6: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_0111: Unknown result type (might be due to invalid IL or missing references) if (TVSyncPatches.SuppressOutboundSync || !BestestTV.Ready || !((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled || __instance.inTerminalMenu || __instance.isTypingChat || __instance.isPlayerDead || (Object)(object)TVSyncNetworkHandler.Instance == (Object)null) { return; } InteractTrigger hoveringOverTrigger = __instance.hoveringOverTrigger; if ((Object)(object)hoveringOverTrigger == (Object)null) { return; } Transform parent = ((Component)hoveringOverTrigger).transform.parent; if ((Object)(object)parent == (Object)null || !((Object)((Component)parent).gameObject).name.Contains("Television")) { return; } Key keyBind = BestestTV.GetKeyBind(BestestTV.SkipForwardKeyField, (Key)62); Key keyBind2 = BestestTV.GetKeyBind(BestestTV.SkipReverseKeyField, (Key)61); Key keyBind3 = BestestTV.GetKeyBind(BestestTV.SeekForwardKeyField, (Key)63); Key keyBind4 = BestestTV.GetKeyBind(BestestTV.SeekReverseKeyField, (Key)64); bool flag = BestestTV.WasPressedThisFrame(keyBind); bool flag2 = BestestTV.WasPressedThisFrame(keyBind2); bool flag3 = BestestTV.WasPressedThisFrame(keyBind3); bool flag4 = BestestTV.WasPressedThisFrame(keyBind4); bool flag5 = (flag || flag2) && BestestTV.EnableChannels && BestestTV.TvIsOn; bool flag6 = (flag3 || flag4) && BestestTV.EnableSeeking; if (!flag5 && !flag6) { return; } if (TVLockGuard.ShouldBlockLocalInput()) { TVLockGuard.NotifyBlocked("PlayerControllerB.Update input"); return; } double seekTime = (((Object)(object)BestestTV.VideoSource != (Object)null) ? BestestTV.VideoSource.time : 0.0); if (flag5) { TVSyncNetworkHandler.Instance.TrySendChangeToServer("PlayerController.Update:ChannelSkip", BestestTV.TVIndex, 0.0, BestestTV.TvIsOn); } else { TVSyncNetworkHandler.Instance.TrySendChangeToServer("PlayerController.Update:Seek", BestestTV.TVIndex, seekTime, BestestTV.TvIsOn); } } private static void OnVideoPrepared(VideoPlayer source) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown try { if ((Object)(object)_preparedVideoSource != (Object)null) { VideoPlayer preparedVideoSource = _preparedVideoSource; object obj = <>O.<0>__OnVideoPrepared; if (obj == null) { EventHandler val = OnVideoPrepared; <>O.<0>__OnVideoPrepared = val; obj = (object)val; } preparedVideoSource.prepareCompleted -= (EventHandler)obj; } source.time = _preparedSeekTime; if (_preparedTvOn) { if (!source.isPlaying) { source.Play(); } if ((Object)(object)_preparedAudioSource != (Object)null && !_preparedAudioSource.isPlaying) { _preparedAudioSource.Play(); } BestestTV.TvIsOn = true; } else { if (source.isPlaying) { source.Stop(); } if ((Object)(object)_preparedAudioSource != (Object)null && _preparedAudioSource.isPlaying) { _preparedAudioSource.Stop(); } BestestTV.TvIsOn = false; } TVSyncPatches.UpdateObservedStateSnapshot(_preparedClipIndex, _preparedSeekTime, _preparedTvOn, _preparedMediaId); } finally { _preparedVideoSource = null; _preparedAudioSource = null; _preparedMediaId = string.Empty; TVSyncPatches.EndSuppressedRemoteApply(); } } private static void QueuePreparedPlayback(VideoPlayer source, AudioSource audio, int clipIndex, double seekTime, bool tvOn, string mediaId) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Expected O, but got Unknown //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_0089: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Expected O, but got Unknown if ((Object)(object)_preparedVideoSource != (Object)null) { VideoPlayer preparedVideoSource = _preparedVideoSource; object obj = <>O.<0>__OnVideoPrepared; if (obj == null) { EventHandler val = OnVideoPrepared; <>O.<0>__OnVideoPrepared = val; obj = (object)val; } preparedVideoSource.prepareCompleted -= (EventHandler)obj; TVSyncPatches.EndSuppressedRemoteApply(); } _preparedVideoSource = source; _preparedAudioSource = audio; _preparedSeekTime = seekTime; _preparedTvOn = tvOn; _preparedClipIndex = clipIndex; _preparedMediaId = mediaId ?? string.Empty; object obj2 = <>O.<0>__OnVideoPrepared; if (obj2 == null) { EventHandler val2 = OnVideoPrepared; <>O.<0>__OnVideoPrepared = val2; obj2 = (object)val2; } source.prepareCompleted -= (EventHandler)obj2; object obj3 = <>O.<0>__OnVideoPrepared; if (obj3 == null) { EventHandler val3 = OnVideoPrepared; <>O.<0>__OnVideoPrepared = val3; obj3 = (object)val3; } source.prepareCompleted += (EventHandler)obj3; source.Prepare(); } private static void ApplyVisualPowerForClients(bool tvOn) { NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton == (Object)null || !singleton.IsClient || singleton.IsServer) { return; } TVScript[] array = Object.FindObjectsOfType<TVScript>(true); TVScript[] array2 = array; foreach (TVScript val in array2) { if (!((Object)(object)val == (Object)null)) { try { val.TurnTVOnOff(tvOn); } catch (Exception ex) { TVSyncPlugin.Log.LogDebug((object)("[CymruTVSync] Visual power fallback failed on TVScript: " + ex.Message)); } } } } public static void ApplyState(int clipIndex, double seekTime, bool tvOn, string mediaId = "") { if (!BestestTV.Ready || (Object)(object)BestestTV.VideoSource == (Object)null) { return; } TVSyncPatches.BeginSuppressedRemoteApply(); try { bool tvIsOn = BestestTV.TvIsOn; VideoPlayer videoSource = BestestTV.VideoSource; AudioSource audioSource = BestestTV.AudioSource; List<string> videos = BestestTV.Videos; string text = BestestTV.NormalizeMediaId(mediaId); string b = BestestTV.NormalizeMediaId(videoSource.url); int num = clipIndex; if (!string.IsNullOrEmpty(text)) { int num2 = BestestTV.FindVideoIndexByMediaId(text); if (num2 >= 0) { num = num2; } } bool flag = videos != null && num >= 0 && num < videos.Count; bool flag2 = !string.IsNullOrEmpty(text) && !string.Equals(text, b, StringComparison.OrdinalIgnoreCase); bool flag3 = false; if (flag && (BestestTV.TVIndex != num || flag2)) { BestestTV.TVIndex = num; videoSource.Stop(); if ((Object)(object)audioSource != (Object)null && audioSource.isPlaying) { audioSource.Stop(); } videoSource.url = "file://" + videos[num]; videoSource.time = 0.0; flag3 = true; } else if (!flag && flag2) { TVSyncPlugin.Log.LogWarning((object)$"[CymruTVSync] Received media id '{text}' that does not exist in local list. Using incoming clip index {clipIndex} as fallback."); } if (!flag3 && tvOn && !videoSource.isPrepared) { if ((Object)(object)audioSource != (Object)null && audioSource.isPlaying) { audioSource.Stop(); } flag3 = true; } if (flag3) { QueuePreparedPlayback(videoSource, audioSource, num, seekTime, tvOn, mediaId); if (tvIsOn != tvOn) { ApplyVisualPowerForClients(tvOn); } return; } videoSource.time = seekTime; if (tvOn) { if (!BestestTV.TvIsOn) { BestestTV.TvIsOn = true; } if (!videoSource.isPlaying) { videoSource.Play(); } if ((Object)(object)audioSource != (Object)null && !audioSource.isPlaying) { audioSource.Play(); } } else { if (videoSource.isPlaying) { videoSource.Stop(); } if ((Object)(object)audioSource != (Object)null && audioSource.isPlaying) { audioSource.Stop(); } BestestTV.TvIsOn = false; } if (tvIsOn != tvOn) { ApplyVisualPowerForClients(tvOn); } TVSyncPatches.UpdateObservedStateSnapshot(num, seekTime, tvOn, mediaId); } finally { if ((Object)(object)_preparedVideoSource == (Object)null) { TVSyncPatches.EndSuppressedRemoteApply(); } } } } [HarmonyPatch(typeof(TVScript))] public class TVSyncReceiver { private static bool _subscribed; [HarmonyPostfix] [HarmonyPatch("OnEnable")] public static void OnEnable_Postfix(TVScript __instance) { BestestTV.Init(); if (!_subscribed) { TVSyncNetworkHandler.OnTVStateReceived -= OnStateReceived; TVSyncNetworkHandler.OnTVStateReceived += OnStateReceived; TVSyncNetworkHandler.OnLockStateReceived -= OnLockReceived; TVSyncNetworkHandler.OnLockStateReceived += OnLockReceived; TVSyncNetworkHandler.OnLockFeatureStateReceived -= OnLockFeatureReceived; TVSyncNetworkHandler.OnLockFeatureStateReceived += OnLockFeatureReceived; _subscribed = true; } TVLockGuard.ApplyTriggerLock(); if (!NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer) { if ((Object)(object)TVSyncNetworkHandler.Instance != (Object)null) { TVSyncNetworkHandler.Instance.TryRequestFullSyncFromServer("TVScript.OnEnable"); } else { TVSyncPlugin.Log.LogWarning((object)"[CymruTVSync] TV enabled before network handler existed, so no sync request could be sent yet."); } } } [HarmonyPostfix] [HarmonyPatch("OnDisable")] public static void OnDisable_Postfix() { TVSyncNetworkHandler.OnTVStateReceived -= OnStateReceived; TVSyncNetworkHandler.OnLockStateReceived -= OnLockReceived; TVSyncNetworkHandler.OnLockFeatureStateReceived -= OnLockFeatureReceived; _subscribed = false; } private static void OnStateReceived(int clipIndex, double seekTime, bool tvOn, string mediaId) { TVSyncInputPatch.ApplyState(clipIndex, seekTime, tvOn, mediaId); } private static void OnLockReceived(bool isLocked) { TVLockGuard.ApplyTriggerLock(); } private static void OnLockFeatureReceived(bool enabled) { TVLockGuard.ApplyTriggerLock(); if (!enabled) { TVSyncInputPatch.ApplyState(TVSyncState.CurrentClip, TVSyncState.SeekTime, TVSyncState.IsTvOn, TVSyncState.CurrentMediaId); } } } [HarmonyPatch(typeof(InteractTrigger), "Interact")] public class TVSyncInteractTriggerPatch { [HarmonyPrefix] [HarmonyPriority(600)] public static bool Prefix(InteractTrigger __instance) { if (!TVLockGuard.ShouldBlockLocalInput()) { return true; } if (__instance.hoverTip == null || !__instance.hoverTip.Contains("Switch TV")) { return true; } TVLockGuard.NotifyBlocked("InteractTrigger.Interact"); return false; } } [HarmonyPatch(typeof(PlayerControllerB), "Update")] public class TVSyncLockKeyPatch { [HarmonyPostfix] public static void Update_Postfix(PlayerControllerB __instance) { if (!((NetworkBehaviour)__instance).IsOwner || !__instance.isPlayerControlled || __instance.inTerminalMenu || __instance.isTypingChat || __instance.isPlayerDead || (!NetworkManager.Singleton.IsHost && !NetworkManager.Singleton.IsServer) || (Object)(object)TVSyncNetworkHandler.Instance == (Object)null) { return; } if (BestestTV.WasPressedThisFrame((Key)29)) { TVSyncNetworkHandler.Instance.TryToggleLockFeatureFromHost("HostKey:O"); } else { if (!BestestTV.WasPressedThisFrame((Key)26)) { return; } if (!TVSyncState.LockFeatureEnabled) { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("CymruTV Sync", "Lock controls are disabled. Press O to enable.", false, false, "TVLockDisabledTip"); } } else { TVSyncNetworkHandler.Instance.TryToggleLockFromHost("HostKey:L"); } } } } [HarmonyPatch(typeof(ShipBuildModeManager))] public static class TVSyncStorageBlockPatch { private static MethodInfo _returnUnlockableFromStorageClientRpcMethod; private static bool IsTelevision(PlaceableShipObject shipObject) { if ((Object)(object)shipObject == (Object)null) { return false; } if ((Object)(object)((Component)shipObject).GetComponentInChildren<TVScript>(true) != (Object)null) { return true; } StartOfRound instance = StartOfRound.Instance; if (instance?.unlockablesList?.unlockables == null) { return false; } int unlockableID = shipObject.unlockableID; if (unlockableID < 0 || unlockableID >= instance.unlockablesList.unlockables.Count) { return false; } UnlockableItem val = instance.unlockablesList.unlockables[unlockableID]; if (val == null) { return false; } string text = val.unlockableName ?? string.Empty; return text.IndexOf("television", StringComparison.OrdinalIgnoreCase) >= 0 || text.Equals("TV", StringComparison.OrdinalIgnoreCase); } private static void TryReturnUnlockableToClient(int unlockableId, int playerWhoStored) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_005b: 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_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007c: 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) StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null) { return; } if ((object)_returnUnlockableFromStorageClientRpcMethod == null) { _returnUnlockableFromStorageClientRpcMethod = AccessTools.Method(typeof(StartOfRound), "ReturnUnlockableFromStorageClientRpc", (Type[])null, (Type[])null); } if (!(_returnUnlockableFromStorageClientRpcMethod == null)) { ClientRpcParams val = default(ClientRpcParams); val.Send = new ClientRpcSendParams { TargetClientIds = new ulong[1] { (ulong)playerWhoStored } }; ClientRpcParams val2 = val; ParameterInfo[] parameters = _returnUnlockableFromStorageClientRpcMethod.GetParameters(); if (parameters.Length == 1) { _returnUnlockableFromStorageClientRpcMethod.Invoke(instance, new object[1] { unlockableId }); } else if (parameters.Length >= 2) { _returnUnlockableFromStorageClientRpcMethod.Invoke(instance, new object[2] { unlockableId, val2 }); } } } [HarmonyPrefix] [HarmonyPatch("StoreObjectLocalClient")] public static bool PreventStoreHost(ShipBuildModeManager __instance) { if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsServer) { return true; } if (__instance.timeSincePlacingObject <= 0.25f || !__instance.InBuildMode || !Object.op_Implicit((Object)(object)__instance.placingObject)) { return true; } PlaceableShipObject placingObject = __instance.placingObject; if (!IsTelevision(placingObject)) { return true; } TVSyncPlugin.Log.LogInfo((object)"[CymruTVSync] Blocked host from storing the TV."); __instance.CancelBuildMode(false); AudioSource component = ((Component)placingObject).GetComponent<AudioSource>(); if ((Object)(object)component != (Object)null && (Object)(object)placingObject.placeObjectSFX != (Object)null) { component.PlayOneShot(placingObject.placeObjectSFX); } return false; } [HarmonyPrefix] [HarmonyPatch("StoreObjectServerRpc")] public static bool PreventStoreServer(ShipBuildModeManager __instance, NetworkObjectReference objectRef, int playerWhoStored) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)__instance == (Object)null || !((NetworkBehaviour)__instance).IsServer) { return true; } NetworkObjectReference val = objectRef; NetworkObject val2 = default(NetworkObject); if (!((NetworkObjectReference)(ref val)).TryGet(ref val2, (NetworkManager)null) || (Object)(object)val2 == (Object)null) { return true; } PlaceableShipObject componentInChildren = ((Component)val2).GetComponentInChildren<PlaceableShipObject>(); if (!IsTelevision(componentInChildren)) { return true; } TVSyncPlugin.Log.LogInfo((object)$"[CymruTVSync] Blocked client {playerWhoStored} from storing the TV."); if ((Object)(object)componentInChildren != (Object)null) { TryReturnUnlockableToClient(componentInChildren.unlockableID, playerWhoStored); } return false; } } [BepInPlugin("CymruTV.Sync", "CymruTV Sync", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class TVSyncPlugin : BaseUnityPlugin { internal static ManualLogSource Log; private readonly Harmony _harmony = new Harmony("CymruTV.Sync"); private void Awake() { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; if ((Object)(object)Object.FindObjectOfType<HostLockStatusOverlay>() == (Object)null) { GameObject val = new GameObject("CymruTVSyncHostLockOverlay"); Object.DontDestroyOnLoad((Object)(object)val); val.AddComponent<HostLockStatusOverlay>(); } TVSyncNetworkHandler.EnsureInstance(); NetcodePatcher(); _harmony.PatchAll(typeof(TVSyncNetworkObjectManager)); _harmony.PatchAll(typeof(TVSyncPatches)); _harmony.PatchAll(typeof(TVSyncInputPatch)); _harmony.PatchAll(typeof(TVSyncBestestHooks)); _harmony.PatchAll(typeof(TVSyncReceiver)); _harmony.PatchAll(typeof(TVSyncLockKeyPatch)); _harmony.PatchAll(typeof(TVSyncStorageBlockPatch)); Log.LogInfo((object)"[CymruTVSync] Plugin loaded. Host keys: L = lock/unlock TV, O = enable/disable lock controls."); } private static void NetcodePatcher() { Type[] types = Assembly.GetExecutingAssembly().GetTypes(); Type[] array = types; foreach (Type type in array) { MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic); MethodInfo[] array2 = methods; foreach (MethodInfo methodInfo in array2) { object[] customAttributes = methodInfo.GetCustomAttributes(typeof(RuntimeInitializeOnLoadMethodAttribute), inherit: false); if (customAttributes.Length != 0) { methodInfo.Invoke(null, null); } } } } } public static class PluginInfo { public const string PLUGIN_GUID = "CymruTVSync"; public const string PLUGIN_NAME = "CymruTVSync"; public const string PLUGIN_VERSION = "1.0.0"; } } namespace CymruTVSync.Patches { [HarmonyPatch(typeof(TVScript))] public class ExampleTVPatch { [HarmonyPatch("SwitchTVLocalClient")] [HarmonyPrefix] private static void SwitchTVPrefix(TVScript __instance) { StartOfRound.Instance.shipRoomLights.SetShipLightsBoolean(__instance.tvOn); } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true)] internal sealed class IgnoresAccessChecksToAttribute : Attribute { public IgnoresAccessChecksToAttribute(string assemblyName) { } } } namespace __GEN { internal class NetworkVariableSerializationHelper { [RuntimeInitializeOnLoadMethod] internal static void InitializeSerialization() { } } } namespace CymruTVSync.NetcodePatcher { [AttributeUsage(AttributeTargets.Module)] internal class NetcodePatchedAssemblyAttribute : Attribute { } }