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 Television v0.1.0
plugins/tech.rethunk.mortar.Television.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using BepInEx; using BepInEx.Logging; using ConfigSync; using GameNetcodeStuff; using Microsoft.CodeAnalysis; using MonoMod.RuntimeDetour; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.Events; using UnityEngine.InputSystem; using UnityEngine.Video; [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("Rethunk Tech")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyCopyright("Copyright (c) 2026 Rethunk Tech")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+ba5778a89cd1d43b0f62d95fa4d90ffd7fc04813")] [assembly: AssemblyProduct("tech.rethunk.mortar.Television")] [assembly: AssemblyTitle("Television")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Rethunk-Tech/mortar-lc-television")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [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 Television { [BepInPlugin("tech.rethunk.mortar.Television", "Television", "0.1.0")] [BepInProcess("Lethal Company.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private sealed class Show(string? url, VideoClip? clip, AudioClip? audio, double length) { public string? Url { get; } = url; public VideoClip? Clip { get; } = clip; public AudioClip? Audio { get; } = audio; public double Length { get; } = length; public string Name { get { if (Url == null) { return ((Object)Clip).name; } return Path.GetFileNameWithoutExtension(Url); } } public string Key { get { if (Url == null) { return "game:" + ((Object)Clip).name; } return Path.GetFileName(Url); } } } private sealed class Measurer : MonoBehaviour { } private sealed class Runner : MonoBehaviour { private float untilSync = 5f; private void Update() { untilSync -= Time.unscaledDeltaTime; if (untilSync > 0f) { return; } untilSync = 5f; NetworkManager singleton = NetworkManager.Singleton; if ((Object)(object)singleton != (Object)null && singleton.IsServer && singleton.CustomMessagingManager != null && singleton.ConnectedClientsIds.Count > 1) { TVScript val = Object.FindObjectOfType<TVScript>(); if (val != null && val.tvOn) { SendStateToAll(); } } } } [CompilerGenerated] private static class <>O { public static Action<IReadOnlyCollection<string>> <0>__Reload; public static Func<string, bool> <1>__Exists; public static Func<string, IEnumerable<string>> <2>__GetFiles; public static Func<string, bool> <3>__IsVideo; public static Action<Action<TVScript>, TVScript> <4>__Update; public static Action<Action<TVScript, bool>, TVScript, bool> <5>__TurnOnOff; public static Action<Action<TVScript, VideoPlayer>, TVScript, VideoPlayer> <6>__Finished; public static Action<Action<StartOfRound>, StartOfRound> <7>__ShipLoaded; public static HandleNamedMessageDelegate <8>__Received; public static Action<CallbackContext> <9>__Pressed; } private const float MeasureTimeout = 10f; private const string Message = "tech.rethunk.mortar.Television"; private const byte Ask = 0; private const byte Skip = 1; private const byte State = 2; private static readonly List<Hook> hooks = new List<Hook>(); private static string[] videos = Array.Empty<string>(); private static double[]? lengths; private static bool measuring; private static readonly Dictionary<string, double> known = new Dictionary<string, double>(); private static int measureRound; private static SyncedEntry<bool> channel = null; private static SyncedEntry<bool> mixGame = null; private static SyncedEntry<bool> shuffle = null; private static readonly Dictionary<TVScript, int> nextShow = new Dictionary<TVScript, int>(); private static double offset; private static bool listening; private static List<(string Key, double Length)>? hostSchedule; private static string? playingKey; private static int darkToken; private static Runner runner = null; private const float SyncEvery = 5f; private const double Drift = 1.5; private static readonly Dictionary<TVScript, InteractTrigger> triggers = new Dictionary<TVScript, InteractTrigger>(); private static readonly Dictionary<InteractTrigger, string> hoverTips = new Dictionary<InteractTrigger, string>(); internal static ManualLogSource Log { get; private set; } = null; private void Awake() { //IL_0101: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; videos = Videos(); Log.LogInfo((object)string.Format("{0} {1} found {2} videos", "Television", "0.1.0", videos.Length)); SyncedConfig val = SyncedConfig.For((BaseUnityPlugin)(object)this); channel = val.Share<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("TV", "Channel", true, "Play the videos as one channel on the lobby's clock, so everyone sees the same moment. Off starts a video from its beginning each time the TV comes on."), (Sync)1); mixGame = val.Share<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("TV", "Include game clips", false, "Keep the TV's own clips in the schedule with the packs' videos."), (Sync)1); shuffle = val.Share<bool>(((BaseUnityPlugin)this).Config.Bind<bool>("TV", "Shuffle", true, "Play the videos in an order picked from the lobby's seed instead of by file name."), (Sync)1); Action action = delegate { TVScript[] array = Object.FindObjectsOfType<TVScript>(); foreach (TVScript val3 in array) { if (val3.wasTvOnLastFrame) { Play(val3); } } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer && NetworkManager.Singleton.CustomMessagingManager != null) { SendStateToAll(); } }; channel.Changed += action; mixGame.Changed += action; shuffle.Changed += action; GameObject val2 = new GameObject("Television"); Object.DontDestroyOnLoad((Object)(object)val2); ((Object)val2).hideFlags = (HideFlags)61; runner = val2.AddComponent<Runner>(); Watch.Start(val2, Reload, Paths.PluginPath); if (videos.Length != 0) { TakeOver(); } } private static string[] Videos() { return (from dir in Directory.GetDirectories(Paths.PluginPath, "mortar", SearchOption.AllDirectories) select Path.Combine(dir, "tv")).Where(Directory.Exists).Concat(Directory.GetDirectories(Paths.PluginPath, "Television Videos", SearchOption.AllDirectories)).SelectMany(Directory.GetFiles) .Where(IsVideo) .Distinct() .OrderBy<string, string>((string f) => Path.GetFileName(f), StringComparer.Ordinal) .ToArray(); } private static bool IsVideo(string file) { if (!file.EndsWith(".mp4", StringComparison.OrdinalIgnoreCase)) { return file.EndsWith(".webm", StringComparison.OrdinalIgnoreCase); } return true; } private static void TakeOver() { //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Expected O, but got Unknown //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_008c: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Expected O, but got Unknown //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Expected O, but got Unknown if (hooks.Count <= 0) { hooks.Add(new Hook((MethodBase)typeof(TVScript).GetMethod("Update", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (Delegate)new Action<Action<TVScript>, TVScript>(Update))); hooks.Add(new Hook((MethodBase)typeof(TVScript).GetMethod("TurnTVOnOff"), (Delegate)new Action<Action<TVScript, bool>, TVScript, bool>(TurnOnOff))); hooks.Add(new Hook((MethodBase)typeof(TVScript).GetMethod("TVFinishedClip", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (Delegate)new Action<Action<TVScript, VideoPlayer>, TVScript, VideoPlayer>(Finished))); hooks.Add(new Hook((MethodBase)typeof(StartOfRound).GetMethod("Start", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic), (Delegate)new Action<Action<StartOfRound>, StartOfRound>(ShipLoaded))); StartMeasure(); } } private static void Reload(IReadOnlyCollection<string> changed) { if (!changed.Any((string f) => IsVideo(f) || Path.GetExtension(f) == "")) { return; } if (lengths != null) { for (int num = 0; num < videos.Length; num++) { if (!changed.Contains(videos[num])) { known[videos[num]] = lengths[num]; } } } foreach (string item in changed) { known.Remove(item); } videos = Videos(); Log.LogInfo((object)$"Found {videos.Length} videos"); lengths = null; measuring = false; measureRound++; if (videos.Length != 0) { TakeOver(); StartMeasure(); } } private static void ShipLoaded(Action<StartOfRound> orig, StartOfRound self) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Expected O, but got Unknown orig(self); offset = 0.0; hostSchedule = null; playingKey = null; nextShow.Clear(); triggers.Clear(); hoverTips.Clear(); NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; object obj = <>O.<8>__Received; if (obj == null) { HandleNamedMessageDelegate val = Received; <>O.<8>__Received = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("tech.rethunk.mortar.Television", (HandleNamedMessageDelegate)obj); if (!singleton.IsServer) { Send(0uL, 0); } if (!listening) { IngamePlayerSettings.Instance.playerInput.actions.FindAction("ItemSecondaryUse", false).performed += Pressed; listening = true; } } } private static void Pressed(CallbackContext context) { PlayerControllerB val = GameNetworkManager.Instance?.localPlayerController; if ((Object)(object)val == (Object)null || val.isTypingChat || val.inTerminalMenu || (Object)(object)val.hoveringOverTrigger == (Object)null) { return; } TVScript val2 = TvOf(val.hoveringOverTrigger); if (!((Object)(object)val2 == (Object)null) && val2.tvOn) { if (NetworkManager.Singleton.IsServer) { SkipAhead(val2); } else { Send(0uL, 1); } } } private static TVScript? TvOf(InteractTrigger trigger) { for (int i = 0; i < ((UnityEventBase)trigger.onInteract).GetPersistentEventCount(); i++) { Object persistentTarget = ((UnityEventBase)trigger.onInteract).GetPersistentTarget(i); TVScript val = (TVScript)(object)((persistentTarget is TVScript) ? persistentTarget : null); if (val != null) { return val; } } return null; } private static void SkipAhead(TVScript tv) { //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) List<Show> list = ((lengths == null) ? new List<Show>() : Schedule(tv)); if (list.Count == 0) { return; } if (channel.Value) { NetworkTime serverTime = NetworkManager.Singleton.ServerTime; double num = (((NetworkTime)(ref serverTime)).Time + offset) % list.Sum((Show show) => show.Length); int num2; for (num2 = 0; num2 < list.Count - 1 && num >= list[num2].Length; num2++) { num -= list[num2].Length; } offset += list[num2].Length - num + 0.05; } SendStateToAll(!channel.Value); if (tv.wasTvOnLastFrame) { Play(tv); } } private unsafe static void Send(ulong to, byte kind, bool advance = false) { //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_002a: 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) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: Unknown result type (might be due to invalid IL or missing references) FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(64, (Allocator)2, 65536); try { ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref kind, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref offset, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<bool>(ref advance, default(ForPrimitives)); TVScript val2 = Object.FindObjectOfType<TVScript>(); List<Show> list = ((kind == 2 && (Object)(object)val2 != (Object)null && lengths != null) ? Schedule(val2) : new List<Show>()); int count = list.Count; ((FastBufferWriter)(ref val)).WriteValueSafe<int>(ref count, default(ForPrimitives)); foreach (Show item in list) { ((FastBufferWriter)(ref val)).WriteValueSafe(item.Key, false); double length = item.Length; ((FastBufferWriter)(ref val)).WriteValueSafe<double>(ref length, default(ForPrimitives)); } NetworkManager.Singleton.CustomMessagingManager.SendNamedMessage("tech.rethunk.mortar.Television", to, val, (NetworkDelivery)4); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private static void SendStateToAll(bool advance = false) { NetworkManager singleton = NetworkManager.Singleton; foreach (ulong connectedClientsId in singleton.ConnectedClientsIds) { if (connectedClientsId != 0L) { Send(connectedClientsId, 2, advance); } } } private static void Received(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_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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_007f: 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) //IL_00aa: 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)); double num = default(double); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref num, default(ForPrimitives)); bool flag = default(bool); ((FastBufferReader)(ref reader)).ReadValueSafe<bool>(ref flag, default(ForPrimitives)); TVScript val = Object.FindObjectOfType<TVScript>(); if (NetworkManager.Singleton.IsServer) { switch (b) { case 0: Send(sender, 2); break; case 1: if ((Object)(object)val != (Object)null && val.tvOn) { SkipAhead(val); } break; } return; } int num2 = default(int); ((FastBufferReader)(ref reader)).ReadValueSafe<int>(ref num2, default(ForPrimitives)); List<(string, double)> list = new List<(string, double)>(num2); string item = default(string); double item2 = default(double); for (int i = 0; i < num2; i++) { ((FastBufferReader)(ref reader)).ReadValueSafe(ref item, false); ((FastBufferReader)(ref reader)).ReadValueSafe<double>(ref item2, default(ForPrimitives)); list.Add((item, item2)); } bool flag2 = num != offset || hostSchedule == null || !hostSchedule.SequenceEqual<(string, double)>(list); offset = num; hostSchedule = ((list.Count > 0) ? list : null); if (!((Object)(object)val == (Object)null) && val.wasTvOnLastFrame && (flag || (channel.Value && (flag2 || OutOfStep(val))))) { Play(val); } } private static bool OutOfStep(TVScript tv) { if (hostSchedule == null) { return false; } var (index, num) = Locate(hostSchedule.Select<(string, double), double>(((string Key, double Length) s) => s.Length).ToList()); if (!(hostSchedule[index].Key != playingKey)) { if (tv.video.isPlaying) { return Math.Abs(tv.video.time - num) > 1.5; } return false; } return true; } private static (int Index, double At) Locate(List<double> lengths) { //IL_0005: 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) NetworkTime serverTime = NetworkManager.Singleton.ServerTime; double num = (((NetworkTime)(ref serverTime)).Time + offset) % lengths.Sum(); int i; for (i = 0; i < lengths.Count - 1 && num >= lengths[i]; i++) { num -= lengths[i]; } return (Index: i, At: num); } private static void Hover(TVScript tv, string? name) { if (!triggers.TryGetValue(tv, out InteractTrigger value)) { value = ((IEnumerable<InteractTrigger>)Object.FindObjectsOfType<InteractTrigger>()).FirstOrDefault((Func<InteractTrigger, bool>)((InteractTrigger t) => (Object)(object)TvOf(t) == (Object)(object)tv)); if ((Object)(object)value == (Object)null) { return; } triggers[tv] = value; hoverTips[value] = value.hoverTip; } string text = hoverTips[value]; value.hoverTip = ((name == null) ? text : (text + "\nNext channel : [Q]\n" + name)); } private static void StartMeasure() { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown if (!measuring && lengths == null) { measuring = true; GameObject val = new GameObject("Television lengths"); Object.DontDestroyOnLoad((Object)(object)val); ((Object)val).hideFlags = (HideFlags)61; ((MonoBehaviour)val.AddComponent<Measurer>()).StartCoroutine(Measure(val, measureRound)); } } private static void Update(Action<TVScript> orig, TVScript self) { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)instance.localPlayerController == (Object)null || (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.ShutdownInProgress) { return; } bool flag = self.tvOn && !instance.localPlayerController.isInsideFactory; if (flag != self.wasTvOnLastFrame) { self.wasTvOnLastFrame = flag; self.SetTVScreenMaterial(flag); if (flag) { Play(self); return; } self.video.Stop(); StopGameAudio(self); Hover(self, null); } } private static void TurnOnOff(Action<TVScript, bool> orig, TVScript self, bool on) { self.tvOn = on; AudioClip val = (on ? self.switchTVOn : self.switchTVOff); self.tvSFX.PlayOneShot(val); WalkieTalkie.TransmitOneShotAudio(self.tvSFX, val, 1f); } private static void Finished(Action<TVScript, VideoPlayer> orig, TVScript self, VideoPlayer source) { if (self.wasTvOnLastFrame) { Play(self); } } private static void Play(TVScript tv) { if (lengths == null) { StartMeasure(); return; } List<Show> list = Schedule(tv); if (channel.Value && hostSchedule != null && !NetworkManager.Singleton.IsServer) { (int Index, double At) tuple = Locate(hostSchedule.Select<(string, double), double>(((string Key, double Length) s) => s.Length).ToList()); int item = tuple.Index; double item2 = tuple.At; (string, double) tuple2 = hostSchedule[item]; string key = tuple2.Item1; double item3 = tuple2.Item2; Show show = AllShows(tv).FirstOrDefault((Show show2) => show2.Key == key); if (show != null) { PlayShow(tv, show, item2); } else { Dark(tv, key, item3 - item2); } } else { if (list.Count == 0) { return; } if (channel.Value) { var (index, at) = Locate(list.Select((Show show2) => show2.Length).ToList()); PlayShow(tv, list[index], at); } else { nextShow.TryGetValue(tv, out var value); value %= list.Count; nextShow[tv] = value + 1; PlayShow(tv, list[value], 0.0); } } } private static void Dark(TVScript tv, string key, double seconds) { tv.video.Stop(); StopGameAudio(tv); tv.SetTVScreenMaterial(false); Hover(tv, null); playingKey = key; ((MonoBehaviour)runner).StartCoroutine(AfterDark(tv, ++darkToken, (float)seconds)); } private static IEnumerator AfterDark(TVScript tv, int token, float seconds) { yield return (object)new WaitForSeconds(seconds); if (token == darkToken && (Object)(object)tv != (Object)null && tv.wasTvOnLastFrame) { Play(tv); } } private static IEnumerable<Show> AllShows(TVScript tv) { for (int i = 0; i < tv.tvClips.Length; i++) { yield return new Show(null, tv.tvClips[i], tv.tvAudioClips[i], tv.tvClips[i].length); } for (int i = 0; i < videos.Length; i++) { if (lengths[i] > 0.0) { yield return new Show(videos[i], null, null, lengths[i]); } } } private static List<Show> Schedule(TVScript tv) { List<Show> list = new List<Show>(); if (mixGame.Value || lengths.All((double length) => length <= 0.0)) { for (int num = 0; num < tv.tvClips.Length; num++) { list.Add(new Show(null, tv.tvClips[num], tv.tvAudioClips[num], tv.tvClips[num].length)); } } for (int num2 = 0; num2 < videos.Length; num2++) { if (lengths[num2] > 0.0) { list.Add(new Show(videos[num2], null, null, lengths[num2])); } } if (shuffle.Value && (Object)(object)StartOfRound.Instance != (Object)null) { Random random = new Random(StartOfRound.Instance.randomMapSeed); list = list.OrderBy((Show _) => random.Next()).ToList(); } return list; } private static void PlayShow(TVScript tv, Show show, double at) { VideoPlayer video = tv.video; darkToken++; playingKey = show.Key; tv.SetTVScreenMaterial(true); video.Stop(); StopGameAudio(tv); if ((Object)(object)show.Clip != (Object)null) { video.source = (VideoSource)0; video.clip = show.Clip; video.audioOutputMode = (VideoAudioOutputMode)0; tv.tvSFX.clip = show.Audio; tv.tvSFX.time = (float)at; tv.tvSFX.Play(); } else { video.audioOutputMode = (VideoAudioOutputMode)1; video.controlledAudioTrackCount = 1; video.EnableAudioTrack((ushort)0, true); video.SetTargetAudioSource((ushort)0, tv.tvSFX); video.source = (VideoSource)1; video.url = new Uri(show.Url).AbsoluteUri; } video.isLooping = false; video.time = at; video.Play(); Hover(tv, show.Name); } private static void StopGameAudio(TVScript tv) { if ((Object)(object)tv.tvSFX.clip != (Object)null) { tv.tvSFX.Stop(); tv.tvSFX.clip = null; } } private static IEnumerator Measure(GameObject holder, int round) { VideoPlayer probe = holder.AddComponent<VideoPlayer>(); probe.playOnAwake = false; probe.audioOutputMode = (VideoAudioOutputMode)0; probe.source = (VideoSource)1; bool failed = false; probe.errorReceived += (ErrorEventHandler)delegate { failed = true; }; string[] list = videos; double[] measured = new double[list.Length]; for (int i = 0; i < list.Length; i++) { if (!known.TryGetValue(list[i], out measured[i])) { failed = false; probe.url = new Uri(list[i]).AbsoluteUri; probe.Prepare(); float waited = 0f; while (!probe.isPrepared && !failed && waited < 10f) { waited += Time.unscaledDeltaTime; yield return null; } measured[i] = (probe.isPrepared ? probe.length : 0.0); if (measured[i] <= 0.0) { Log.LogWarning((object)(list[i] + " can't play here, so it's skipped")); } } } Object.Destroy((Object)(object)holder); if (round == measureRound) { lengths = measured; TVScript val = Object.FindObjectOfType<TVScript>(); if ((Object)(object)val != (Object)null && val.wasTvOnLastFrame) { Play(val); } if ((Object)(object)NetworkManager.Singleton != (Object)null && NetworkManager.Singleton.IsServer && NetworkManager.Singleton.CustomMessagingManager != null) { SendStateToAll(); } } } } internal sealed class Watch : MonoBehaviour { private static readonly TimeSpan quiet = TimeSpan.FromSeconds(1.0); private readonly List<FileSystemWatcher> watchers = new List<FileSystemWatcher>(); private readonly object gate = new object(); private readonly HashSet<string> changed = new HashSet<string>(); private DateTime last; private Action<IReadOnlyCollection<string>> onChange = delegate { }; public static void Start(GameObject host, Action<IReadOnlyCollection<string>> onChange, params string[] dirs) { Watch watch = host.AddComponent<Watch>(); watch.onChange = onChange; foreach (string item in dirs.Where(Directory.Exists)) { try { FileSystemWatcher fileSystemWatcher = new FileSystemWatcher(item) { IncludeSubdirectories = true }; fileSystemWatcher.Created += delegate(object _, FileSystemEventArgs e) { watch.Note(e.FullPath); }; fileSystemWatcher.Changed += delegate(object _, FileSystemEventArgs e) { watch.Note(e.FullPath); }; fileSystemWatcher.Deleted += delegate(object _, FileSystemEventArgs e) { watch.Note(e.FullPath); }; fileSystemWatcher.Renamed += delegate(object _, RenamedEventArgs e) { watch.Note(e.OldFullPath); watch.Note(e.FullPath); }; fileSystemWatcher.EnableRaisingEvents = true; watch.watchers.Add(fileSystemWatcher); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Can't watch " + item + " for new files, so they need a restart: " + ex.Message)); } } } private void Note(string path) { lock (gate) { changed.Add(path); last = DateTime.UtcNow; } } private void Update() { string[] obj; lock (gate) { if (changed.Count == 0 || DateTime.UtcNow - last < quiet) { return; } obj = changed.ToArray(); changed.Clear(); } try { onChange((IReadOnlyCollection<string>)(object)obj); } catch (Exception arg) { Plugin.Log.LogError((object)$"Couldn't pick up changed files: {arg}"); } } private void OnDestroy() { foreach (FileSystemWatcher watcher in watchers) { watcher.Dispose(); } } } internal static class MyPluginInfo { public const string Id = "tech.rethunk.mortar.Television"; public const string Name = "Television"; public const string Version = "0.1.0"; } }