using System; 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 CustomTvVideos.Patches; using GameNetcodeStuff; using HarmonyLib; using JetBrains.Annotations; using Microsoft.CodeAnalysis; using Unity.Netcode; using UnityEngine; 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("CustomTvVideos")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Allowes you to set custom videos for the tv")] [assembly: AssemblyFileVersion("0.1.3.0")] [assembly: AssemblyInformationalVersion("0.1.3")] [assembly: AssemblyProduct("CustomTvVideos")] [assembly: AssemblyTitle("CustomTvVideos")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace CustomTvVideos { internal interface ITryGet { bool TryGetValue(out T? value); } public class MyPluginInfo { public const string PLUGIN_GUID = "sakura.custom-tv-videos"; public const string PLUGIN_NAME = "CustomTvVideos"; public const string PLUGIN_VERSION = "0.1.3"; } [BepInPlugin("sakura.custom-tv-videos", "CustomTvVideos", "0.1.3")] public class CustomTvVideos : BaseUnityPlugin { private static string videosDir = Path.Combine(Paths.BepInExRootPath, "CustomTvVideos", "VideoClips"); private static ManualLogSource logger; private Harmony harmony = new Harmony("sakura.custom-tv-videos"); [UsedImplicitly] private void Awake() { try { logger = ((BaseUnityPlugin)this).Logger; CreateDirectoryIfItDoesNotExist(); if (LoadClips()) { harmony.PatchAll(typeof(TvScriptPatch)); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin sakura.custom-tv-videos is loaded!"); } } catch (Exception arg) { ((BaseUnityPlugin)this).Logger.LogError((object)$"Encountered an error in Awake()\n {arg}"); } } private bool LoadClips() { if (new VideoGetter(((BaseUnityPlugin)this).Logger).TryGetValue(out var value)) { List list = new List(); string[] array = value; foreach (string fileName in array) { list.Add(new FileInfo(fileName)); } FileInfo[] array2 = list.ToArray(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Got {value.Length} video files."); if (array2.Length == 0) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"No video clips where loaded, Aborting..."); ((Component)this).gameObject.SetActive(false); return false; } TvScriptPatch.Init(array2, logger); return true; } ((BaseUnityPlugin)this).Logger.LogFatal((object)"Unable to get video clips."); ((Component)this).gameObject.SetActive(false); return false; } private void CreateDirectoryIfItDoesNotExist() { Directory.CreateDirectory(videosDir); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Video Directory: " + videosDir)); } } internal class VideoGetter : ITryGet { [Flags] private enum PlatformFlag { Unknown = 0, Windows = 1, MacOS = 2, Linux = 4 } private struct FileType { public string Extension; public PlatformFlag Platform; public FileType(string extension, PlatformFlag platform) { Extension = extension; Platform = platform; } } private ManualLogSource logger; private static string videosDir = Path.Combine(Paths.BepInExRootPath, "CustomTvVideos", "VideoClips"); private static FileType[] videoFileTypes = new FileType[12] { new FileType(".asf", PlatformFlag.Windows), new FileType(".avi", PlatformFlag.Windows), new FileType(".dv", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".mv4", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".mov", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".mp4", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".mpg", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".mpeg", PlatformFlag.Windows | PlatformFlag.MacOS), new FileType(".ogv", PlatformFlag.Windows | PlatformFlag.MacOS | PlatformFlag.Linux), new FileType(".vp8", PlatformFlag.Windows | PlatformFlag.MacOS | PlatformFlag.Linux), new FileType(".webm", PlatformFlag.Windows | PlatformFlag.MacOS | PlatformFlag.Linux), new FileType(".wmv", PlatformFlag.Windows) }; public VideoGetter(ManualLogSource logger) { this.logger = logger; } private static bool IsSupportedOnCurrentPlatform(string extension, PlatformFlag platform) { return videoFileTypes.Any((FileType x) => string.Compare(x.Extension, extension) == 0 && x.Platform.HasFlag(platform)); } private string[] GetSupportedVideoFiles(string dir, PlatformFlag platform) { List list = new List(); foreach (string item in Directory.EnumerateFiles(dir)) { FileInfo fileInfo = new FileInfo(item); if (fileInfo.Exists) { if (IsSupportedOnCurrentPlatform(fileInfo.Extension, platform)) { list.Add(fileInfo.FullName); } else { logger.LogWarning((object)("File: \"" + fileInfo.Name + "\" Is not supported.")); } } } return list.ToArray(); } public bool TryGetValue(out string[] value) { try { PlatformFlag currentPlatform = GetCurrentPlatform(); string[] supportedVideoFiles = GetSupportedVideoFiles(videosDir, currentPlatform); value = supportedVideoFiles; return true; } catch (Exception ex) { logger.LogError((object)ex); value = null; return false; } } private static PlatformFlag GetCurrentPlatform() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 //IL_0026: Unknown result type (might be due to invalid IL or missing references) RuntimePlatform platform = Application.platform; if ((int)platform != 1) { if ((int)platform != 2) { if ((int)platform == 13) { return PlatformFlag.Linux; } throw new PlatformNotSupportedException($"Platform: \"{platform}\" is not supported."); } return PlatformFlag.Windows; } return PlatformFlag.MacOS; } } public static class PluginInfo { public const string PLUGIN_GUID = "CustomTvVideos"; public const string PLUGIN_NAME = "CustomTvVideos"; public const string PLUGIN_VERSION = "0.1.3"; } } namespace CustomTvVideos.Patches { [HarmonyPatch(typeof(PlayerControllerB))] internal static class PlayerControllerBPatch { } [HarmonyPatch(typeof(TVScript))] internal class TvScriptPatch { private static ManualLogSource logger; private static FileInfo[] videoFiles; private static int currentClip; private static bool setupDone; private static bool wasTvOnLastFrame; private static float currentClipTime; internal static void Init(FileInfo[] videos, ManualLogSource logSource) { videoFiles = videos; logger = logSource; } private static void IncrementCurrentClip() { if (currentClip + 1 >= videoFiles.Length) { currentClip = 0; } else { currentClip++; } } private static void SetVideo(TVScript tv, FileInfo videoFile) { tv.video.clip = null; tv.tvSFX.clip = null; tv.video.url = "file://" + videoFile.FullName; tv.video.source = (VideoSource)1; tv.video.controlledAudioTrackCount = 1; tv.video.audioOutputMode = (VideoAudioOutputMode)1; tv.video.SetTargetAudioSource((ushort)0, tv.tvSFX); tv.video.Prepare(); tv.video.Stop(); tv.tvSFX.Stop(); } [HarmonyPatch(typeof(TVScript), "TVFinishedClip")] [HarmonyPrefix] private static bool TV_TVFinishedClip(TVScript __instance, VideoPlayer source) { logger.LogInfo((object)"TV_TVFinishedClip"); if (__instance.tvOn && !GameNetworkManager.Instance.localPlayerController.isInsideFactory) { IncrementCurrentClip(); FileInfo fileInfo = videoFiles[currentClip]; logger.LogInfo((object)("Playing " + fileInfo.FullName)); SetVideo(__instance, fileInfo); } return false; } [HarmonyPatch(typeof(TVScript), "TurnTVOnOff")] [HarmonyPrefix] private static bool TV_TurnTVOnOff(TVScript __instance, bool on) { logger.LogInfo((object)"TV_TurnTVOnOff"); __instance.tvOn = on; if (!setupDone) { __instance.video.clip = null; __instance.tvSFX.clip = null; IncrementCurrentClip(); FileInfo videoFile = videoFiles[currentClip]; SetVideo(__instance, videoFile); setupDone = true; } if (on) { IncrementCurrentClip(); FileInfo videoFile2 = videoFiles[currentClip]; SetVideo(__instance, videoFile2); SetTVScreenMaterial(__instance, b: true); __instance.video.Play(); __instance.tvSFX.Play(); __instance.tvSFX.PlayOneShot(__instance.switchTVOn); WalkieTalkie.TransmitOneShotAudio(__instance.tvSFX, __instance.switchTVOn, 1f); } else { SetTVScreenMaterial(__instance, b: false); __instance.tvSFX.Stop(); __instance.tvSFX.PlayOneShot(__instance.switchTVOff); __instance.video.Stop(); WalkieTalkie.TransmitOneShotAudio(__instance.tvSFX, __instance.switchTVOff, 1f); } return false; } [HarmonyPatch(typeof(TVScript), "Update")] [HarmonyPrefix] private static bool TV_Update(TVScript __instance) { if (NetworkManager.Singleton.ShutdownInProgress || (Object)(object)GameNetworkManager.Instance.localPlayerController == (Object)null) { return false; } if ((!__instance.tvOn || GameNetworkManager.Instance.localPlayerController.isInsideFactory) && wasTvOnLastFrame) { wasTvOnLastFrame = false; SetTVScreenMaterial(__instance, b: false); currentClipTime = (float)__instance.video.time; __instance.video.Stop(); } return false; } private static void SetTVScreenMaterial(TVScript instance, bool b) { ((object)instance).GetType().GetMethod("SetTVScreenMaterial", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(instance, new object[1] { b }); } } }