Decompiled source of CustomPosters v4.0.2
BepInEx/plugins/CustomPosters/CustomPosters.dll
Decompiled 2 days ago
The result has been truncated due to the large size, download it to view full contents!
using 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 System.Threading.Tasks; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using CustomPosters.Data; using CustomPosters.Data.PosterLayouts; using CustomPosters.Data.PosterLayouts.Legacy; using CustomPosters.Networking; using CustomPosters.Patches; using CustomPosters.Utils; using HarmonyLib; using LethalNetworkAPI; 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("CustomPosters")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Replaces the default posters in the ship with custom posters")] [assembly: AssemblyFileVersion("4.0.2.0")] [assembly: AssemblyInformationalVersion("4.0.2+c3ee4d65edc757e8332a2e464098fe3375173973")] [assembly: AssemblyProduct("CustomPosters")] [assembly: AssemblyTitle("CustomPosters")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.2.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 CustomPosters { internal static class AssetManager { public static AssetBundle? Bundle { get; private set; } public static GameObject? PosterPrefab { get; private set; } public static GameObject? Poster5Prefab { get; private set; } public static GameObject? TipsPrefab { get; private set; } public static void LoadAssets() { Assembly executingAssembly = Assembly.GetExecutingAssembly(); string directoryName = Path.GetDirectoryName(executingAssembly.Location); string text = Path.Combine(directoryName, "customposters"); Bundle = AssetBundle.LoadFromFile(text); if ((Object)(object)Bundle == (Object)null) { Plugin.Log.LogError((object)"Failed to load AssetBundle."); return; } PosterPrefab = Bundle.LoadAsset<GameObject>("CustomPosterPrefab"); Poster5Prefab = Bundle.LoadAsset<GameObject>("Poster5"); TipsPrefab = Bundle.LoadAsset<GameObject>("Tips"); if ((Object)(object)PosterPrefab == (Object)null) { Plugin.Log.LogError((object)"Failed to load prefab from the AssetBundle."); } else { Plugin.Log.LogInfo((object)"Loaded assetbundle."); } if ((Object)(object)Poster5Prefab == (Object)null) { Plugin.Log.LogError((object)"Failed to load Poster5 prefab from the AssetBundle."); } if ((Object)(object)TipsPrefab == (Object)null) { Plugin.Log.LogError((object)"Failed to load Tips prefab from the AssetBundle."); } } } internal static class Constants { public static readonly string[] ValidImageExtensions = new string[4] { ".png", ".jpg", ".jpeg", ".bmp" }; public static readonly string[] ValidVideoExtensions = new string[1] { ".mp4" }; public static readonly string[] AllValidExtensions = new string[5] { ".png", ".jpg", ".jpeg", ".bmp", ".mp4" }; public const string PluginsFolderName = "plugins"; public const int DefaultVideoVolume = 10; public const float DefaultVideoMaxDistance = 3.5f; public static readonly string[] ExcludedModFolderNames = new string[3] { "CustomPosters", "seechela-CustomPosters", "plugins" }; public const string BiggerShipGUID = "BiggerShip"; public const string ShipWindowsGUID = "TestAccount666.ShipWindows"; public const string WiderShipModGUID = "mborsh.WiderShipMod"; public const string TwoStoryShipGUID = "MelanieMelicious.2StoryShip"; public const string PosterNamePoster1 = "Poster1"; public const string PosterNamePoster2 = "Poster2"; public const string PosterNamePoster3 = "Poster3"; public const string PosterNamePoster4 = "Poster4"; public const string PosterNamePoster5 = "Poster5"; public const string PosterNameCustomTips = "CustomTips"; public const string WiderShipSideLeft = "Left"; public const string WiderShipSideRight = "Right"; public const string WiderShipSideBoth = "Both"; public const string SinglePackFolderName = "CustomPosters"; public const string PackSyncIdentifier = "CustomPosters_SyncPack"; public const string VideoRequestIdentifier = "CustomPosters_RequestVideoTime"; public const string VideoSyncIdentifier = "CustomPosters_SyncVideoTime"; public const string Es3SelectedPackKey = "CustomPosters_SelectedPack"; public const int PosterRenderTextureWidth = 512; public const int PosterRenderTextureHeight = 512; public const int PosterRenderTextureDepth = 16; } [BepInPlugin("CustomPosters", "CustomPosters", "4.0.2")] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { private readonly Harmony _harmony = new Harmony("CustomPosters"); public static Plugin Instance { get; private set; } internal static ManualLogSource Log { get; private set; } public static PosterService Service { get; private set; } public static PosterConfig ModConfig { get; private set; } private void Awake() { Instance = this; Log = ((BaseUnityPlugin)this).Logger; Log.LogInfo((object)"Initializing CustomPosters"); AssetManager.LoadAssets(); ModConfig = new PosterConfig(((BaseUnityPlugin)this).Config); Service = new PosterService(); ModConfig.Initialize(); Log.LogInfo((object)"Applying patches"); _harmony.PatchAll(typeof(StartOfRoundPatch)); _harmony.PatchAll(typeof(GameNetworkManagerPatch)); Log.LogInfo((object)"CustomPosters is loaded!"); } } internal class FileConfig { public ConfigEntry<bool> Enabled { get; } public ConfigEntry<int> Chance { get; } public ConfigEntry<int>? Volume { get; set; } public ConfigEntry<float>? MaxDistance { get; set; } public ConfigEntry<PosterConfig.VideoAspectRatio>? AspectRatio { get; set; } public FileConfig(ConfigEntry<bool> enabled, ConfigEntry<int> chance) { Enabled = enabled; Chance = chance; } } public class PosterConfig { [Serializable] public enum RandomizerMode { PerPack, PerPoster } [Serializable] public enum VideoAspectRatio { Stretch, FitInside, FitOutside, NoScaling } [Serializable] public enum KeepFor { Lobby, Session, SaveSlot } [Flags] public enum VanillaModelOption { None = 0, Poster5 = 1, Tips = 2, Both = 3 } private readonly Dictionary<string, ConfigEntry<bool>> _packEnabledEntries = new Dictionary<string, ConfigEntry<bool>>(); private readonly Dictionary<string, ConfigEntry<int>> _packChanceEntries = new Dictionary<string, ConfigEntry<int>>(); private readonly Dictionary<string, FileConfig> _fileConfigs = new Dictionary<string, FileConfig>(); private readonly ConfigFile _configFile; public ConfigEntry<bool> EnableNetworking { get; private set; } public ConfigEntry<RandomizerMode> RandomizerModeSetting { get; private set; } public ConfigEntry<KeepFor> KeepPackFor { get; private set; } public ConfigEntry<bool> EnableTextureCaching { get; private set; } public ConfigEntry<bool> EnableVideoAudio { get; private set; } public ConfigEntry<VanillaModelOption> VanillaModelSelection { get; private set; } public bool UsePoster5VanillaModel => VanillaModelSelection.Value.HasFlag(VanillaModelOption.Poster5); public bool UseTipsVanillaModel => VanillaModelSelection.Value.HasFlag(VanillaModelOption.Tips); public PosterConfig(ConfigFile config) { _configFile = config; } public void Initialize() { //IL_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Expected O, but got Unknown //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_019d: Expected O, but got Unknown //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_027e: Expected O, but got Unknown //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02dc: Expected O, but got Unknown //IL_0321: Unknown result type (might be due to invalid IL or missing references) //IL_032b: Expected O, but got Unknown _configFile.SaveOnConfigSet = false; EnableNetworking = _configFile.Bind<bool>("1. Settings", "Enable Networking", true, "Sync posters with all players (requires all to have the mod); false = client-side, makes compatible with vanilla lobbies."); RandomizerModeSetting = _configFile.Bind<RandomizerMode>("1. Settings", "RandomizerMode", RandomizerMode.PerPack, "Controls randomization: PerPack selects one pack for all posters; PerPoster randomizes each poster from enabled packs."); KeepPackFor = _configFile.Bind<KeepFor>("1. Settings", "Keep pack for", KeepFor.Lobby, "Keeping selection: Lobby = reroll each lobby; Session = until game restart; Save slot = per save file."); VanillaModelSelection = _configFile.Bind<VanillaModelOption>("1. Settings", "Vanilla Model", VanillaModelOption.Both, new ConfigDescription("Choose vanilla LC mesh: None (use quads), Poster5, Tips, or Both.", (AcceptableValueBase)null, Array.Empty<object>())); EnableVideoAudio = _configFile.Bind<bool>("1. Settings", "EnableVideoAudio", false, "Enable audio for .mp4 poster videos; disable to mute."); EnableTextureCaching = _configFile.Bind<bool>("1. Settings", "EnableTextureCaching", false, "Cache textures/videos in memory to improve performance; disable to reduce memory usage."); int num = 2; foreach (string posterFolder in Plugin.Service.PosterFolders) { try { string text = PackName(posterFolder); if (string.IsNullOrEmpty(text)) { continue; } string text2 = $"{num}. {text}"; string text3 = $"{num}. {text} - Chances"; ConfigEntry<bool> value = _configFile.Bind<bool>(text2, "Enabled", true, "Enable or disable the " + text + " pack"); _packEnabledEntries[text] = value; ConfigEntry<int> value2 = _configFile.Bind<int>(text3, "Global chance", 0, new ConfigDescription("Chance of selecting the " + text + " pack in PerPack mode; 0 = equal probability with other packs.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); _packChanceEntries[text] = value2; IEnumerable<string> filesFromPack = GetFilesFromPack(posterFolder); foreach (string item in filesFromPack) { string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(item); string text4 = Path.GetExtension(item).TrimStart('.').ToUpper(); string fileName = Path.GetFileName(item); string text5 = fileNameWithoutExtension + "-" + text4; ConfigEntry<bool> enabled = _configFile.Bind<bool>(text2, text5, true, "Enable or disable poster file '" + fileName + "' in pack '" + text + "'"); ConfigEntry<int> chance = _configFile.Bind<int>(text3, text5 + " Chance", 0, new ConfigDescription("Chance of selecting poster '" + fileName + "' in PerPoster mode; 0 = equal probability with other posters.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); FileConfig fileConfig = new FileConfig(enabled, chance); if (text4 == "MP4") { fileConfig.Volume = _configFile.Bind<int>(text2, text5 + " Volume", 10, new ConfigDescription("Volume for video '" + fileName + "'.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 100), Array.Empty<object>())); fileConfig.MaxDistance = _configFile.Bind<float>(text2, text5 + " MaxDistance", 3.5f, new ConfigDescription("Maximum distance for audio playback of video '" + fileName + "'", (AcceptableValueBase)(object)new AcceptableValueRange<float>(1f, 5f), Array.Empty<object>())); fileConfig.AspectRatio = _configFile.Bind<VideoAspectRatio>(text2, text5 + " AspectRatio", VideoAspectRatio.Stretch, "Aspect ratio for video '" + fileName + "': Stretch (fill), FitInside (no crop), FitOutside (may crop), NoScaling (original size)."); } _fileConfigs[item] = fileConfig; } num++; } catch (Exception ex) { Plugin.Log.LogError((object)("Failed to generate config for pack at " + PathUtils.GetPrettyPath(posterFolder) + ": " + ex.Message)); } } ClearOrphanedEntries(); _configFile.Save(); _configFile.SaveOnConfigSet = true; Plugin.Log.LogInfo((object)$"Found {_packEnabledEntries.Count} packs and {_fileConfigs.Count} poster files"); } public bool IsPackEnabled(string packPath) { string key = PackName(packPath); if (_packEnabledEntries.TryGetValue(key, out ConfigEntry<bool> value)) { return value.Value; } return true; } public int GetPackChance(string packPath) { string key = PackName(packPath); if (_packChanceEntries.TryGetValue(key, out ConfigEntry<int> value)) { return value.Value; } return 0; } public bool IsFileEnabled(string filePath) { if (_fileConfigs.TryGetValue(Path.GetFullPath(filePath), out FileConfig value)) { return value.Enabled.Value; } return true; } public int GetFileChance(string filePath) { if (_fileConfigs.TryGetValue(Path.GetFullPath(filePath), out FileConfig value)) { return value.Chance.Value; } return 0; } public (int volume, float maxDistance, VideoAspectRatio aspectRatio) GetFileAudioSettings(string filePath) { if (_fileConfigs.TryGetValue(Path.GetFullPath(filePath), out FileConfig value)) { int item = value.Volume?.Value ?? 10; float item2 = value.MaxDistance?.Value ?? 3.5f; VideoAspectRatio item3 = value.AspectRatio?.Value ?? VideoAspectRatio.Stretch; return (item, item2, item3); } return (10, 3.5f, VideoAspectRatio.Stretch); } private static string PackName(string packPath) { return PathUtils.GetDisplayPackName(packPath); } private static IEnumerable<string> GetFilesFromPack(string packPath) { List<string> list = new List<string>(); string path = Path.Combine(packPath, "posters"); if (Directory.Exists(path)) { list.AddRange(from f in Directory.GetFiles(path) where Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()) select f); } string path2 = Path.Combine(packPath, "tips"); if (Directory.Exists(path2)) { list.AddRange(from f in Directory.GetFiles(path2) where Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()) select f); } string text = Path.Combine(packPath, "CustomTips.png"); if (File.Exists(text)) { list.Add(text); } list.AddRange(from f in Directory.GetFiles(packPath) where Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()) select f); return from f in list.Distinct<string>(StringComparer.OrdinalIgnoreCase) select Path.GetFullPath(f); } private void ClearOrphanedEntries() { try { PropertyInfo propertyInfo = AccessTools.Property(typeof(ConfigFile), "OrphanedEntries"); if (propertyInfo != null && propertyInfo.GetValue(_configFile) is Dictionary<ConfigDefinition, string> dictionary) { dictionary.Clear(); Plugin.Log.LogDebug((object)"Cleared orphaned config entries"); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Could not clear orphaned config entries: " + ex.Message)); } } } internal static class PosterManager { [CompilerGenerated] private sealed class <>c__DisplayClass26_0 { public string[] validExtensions; public Func<string, bool> <>9__4; internal bool <CreateCustomPostersAsync>b__4(string f) { if (validExtensions.Contains(Path.GetExtension(f).ToLower())) { return Plugin.ModConfig.IsFileEnabled(f); } return false; } } [CompilerGenerated] private sealed class <>c__DisplayClass26_1 { public (Texture2D? texture, string? filePath) textureResult; public Task loadTask; internal void <CreateCustomPostersAsync>b__6((Texture2D? texture, string? filePath) result) { textureResult = result; } internal bool <CreateCustomPostersAsync>b__7() { return loadTask.IsCompleted; } } [CompilerGenerated] private sealed class <CreateCustomPostersAsync>d__26 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; private <>c__DisplayClass26_1 <>8__1; private GameObject <hangarShip>5__2; private GameObject <postersParent>5__3; private GameObject <posterPlane>5__4; private PosterData[] <posterData>5__5; private Dictionary<string, List<(Texture2D texture, string filePath)>> <allTextures>5__6; private Dictionary<string, List<string>> <allVideos>5__7; private Dictionary<string, (Texture2D? texture, string filePath, bool isVideo)> <prioritizedContent>5__8; private bool <anyPosterLoaded>5__9; private List<string>.Enumerator <>7__wrap9; private List<string> <filesToLoad>5__11; private int <i>5__12; private List<string>.Enumerator <>7__wrap12; private string <file>5__14; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <CreateCustomPostersAsync>d__26(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if ((uint)(num - -4) <= 1u || (uint)(num - 1) <= 1u) { try { if (num == -4 || num == 1) { try { } finally { <>m__Finally2(); } } } finally { <>m__Finally1(); } } <>8__1 = null; <hangarShip>5__2 = null; <postersParent>5__3 = null; <posterPlane>5__4 = null; <posterData>5__5 = null; <allTextures>5__6 = null; <allVideos>5__7 = null; <prioritizedContent>5__8 = null; <>7__wrap9 = default(List<string>.Enumerator); <filesToLoad>5__11 = null; <>7__wrap12 = default(List<string>.Enumerator); <file>5__14 = null; <>1__state = -2; } private bool MoveNext() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Expected O, but got Unknown //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_0a4b: Unknown result type (might be due to invalid IL or missing references) //IL_0a6d: Unknown result type (might be due to invalid IL or missing references) //IL_0a72: Unknown result type (might be due to invalid IL or missing references) //IL_0a94: Unknown result type (might be due to invalid IL or missing references) //IL_06b8: Unknown result type (might be due to invalid IL or missing references) //IL_06c2: Expected O, but got Unknown try { switch (<>1__state) { default: return false; case 0: { <>1__state = -1; CleanUpPosters(); <hangarShip>5__2 = GameObject.Find("Environment/HangarShip"); if ((Object)(object)<hangarShip>5__2 == (Object)null) { return false; } <postersParent>5__3 = new GameObject("CustomPosters"); <postersParent>5__3.transform.SetParent(<hangarShip>5__2.transform); <postersParent>5__3.transform.localPosition = Vector3.zero; <posterPlane>5__4 = GameObject.Find("Environment/HangarShip/Plane.001"); <posterData>5__5 = PosterLayoutProvider.GetLayout(); List<string> list3 = Plugin.Service.PosterFolders.Where((string folder) => Plugin.ModConfig.IsPackEnabled(folder)).ToList(); bool flag = Plugin.ModConfig.EnableNetworking.Value && !ShouldActAsHost && !string.IsNullOrEmpty(_selectedPack); if (list3.Count == 0 && !flag) { Plugin.Log.LogWarning((object)"No enabled packs found"); if ((Object)(object)<posterPlane>5__4 != (Object)null) { <posterPlane>5__4.SetActive(true); } return false; } List<string> list4 = list3.Select((string pack) => Path.GetFileName(pack)).ToList(); List<string> list6; if (Plugin.ModConfig.RandomizerModeSetting.Value == PosterConfig.RandomizerMode.PerPack) { if (ShouldActAsHost) { PosterConfig.KeepFor value2 = Plugin.ModConfig.KeepPackFor.Value; if (value2 == PosterConfig.KeepFor.SaveSlot) { string value3 = SavePersistenceManager.TryGetCurrentSaveId(); if (string.IsNullOrEmpty(value3)) { _selectedPack = null; } } if (value2 switch { PosterConfig.KeepFor.Lobby => true, PosterConfig.KeepFor.Session => _selectedPack == null || !list3.Contains(_selectedPack), PosterConfig.KeepFor.SaveSlot => _selectedPack == null || !list3.Contains(_selectedPack), _ => true, }) { List<string> list5 = new List<string>(list3); string selectedPack = null; while (list5.Count > 0) { string text5 = PackSelector.SelectPackByChance(list5); if (PackHasValidFiles(text5)) { selectedPack = text5; break; } list5.Remove(text5); } _selectedPack = selectedPack; if (!string.IsNullOrEmpty(_selectedPack) && value2 == PosterConfig.KeepFor.SaveSlot) { try { string text6 = SavePersistenceManager.TryGetCurrentSaveId(); if (!string.IsNullOrEmpty(text6)) { SavePersistenceManager.SaveSelectedPack(text6, _selectedPack); Plugin.Log.LogInfo((object)("Saved selected pack for save '" + text6 + "'")); } else { Plugin.Log.LogDebug((object)"PerSave: No valid saveId yet; not persisting selection."); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("SaveSlot save skipped: " + ex.Message)); } } } if (!string.IsNullOrEmpty(_selectedPack) && Plugin.ModConfig.EnableNetworking.Value) { PosterSyncManager.SendPacket(_selectedPack); } } if (string.IsNullOrEmpty(_selectedPack)) { Plugin.Log.LogInfo((object)(Plugin.ModConfig.EnableNetworking.Value ? "Client is waiting for host to select a pack..." : "No valid pack found, falling back to vanilla posters")); if ((Object)(object)<posterPlane>5__4 != (Object)null) { <posterPlane>5__4.SetActive(true); } return false; } string displayPackName = PathUtils.GetDisplayPackName(_selectedPack); Plugin.Log.LogInfo((object)("Using pack: " + displayPackName)); list6 = new List<string> { _selectedPack }; } else { list6 = list3; Plugin.Log.LogInfo((object)"PerPoster mode enabled."); } <allTextures>5__6 = new Dictionary<string, List<(Texture2D, string)>>(); <allVideos>5__7 = new Dictionary<string, List<string>>(); <>7__wrap9 = list6.GetEnumerator(); <>1__state = -3; goto IL_080d; } case 1: <>1__state = -4; if ((Object)(object)<>8__1.textureResult.texture != (Object)null && <>8__1.textureResult.filePath != null) { string key = Path.GetFileNameWithoutExtension(<>8__1.textureResult.filePath).ToLower(); if (!<allTextures>5__6.ContainsKey(key)) { <allTextures>5__6[key] = new List<(Texture2D, string)>(); } <allTextures>5__6[key].Add((<>8__1.textureResult.texture, <>8__1.textureResult.filePath)); } else { Plugin.Log.LogWarning((object)("Failed to load texture from " + <file>5__14)); } <>8__1 = null; goto IL_079c; case 2: <>1__state = -3; <i>5__12 += 5; goto IL_07f0; case 3: { <>1__state = -1; goto IL_0b91; } IL_0ba3: if (<i>5__12 < <posterData>5__5.Length) { GameObject val = CreatePoster(<posterData>5__5[<i>5__12].Name); if (!((Object)(object)val == (Object)null)) { ((Object)val).name = <posterData>5__5[<i>5__12].Name; val.transform.SetParent(<postersParent>5__3.transform); val.transform.position = <posterData>5__5[<i>5__12].Position; val.transform.rotation = Quaternion.Euler(<posterData>5__5[<i>5__12].Rotation); val.transform.localScale = <posterData>5__5[<i>5__12].Scale; string key2 = <posterData>5__5[<i>5__12].Name.ToLower(); if (<prioritizedContent>5__8.TryGetValue(key2, out (Texture2D, string, bool) value) && Plugin.ModConfig.IsFileEnabled(value.Item2)) { PosterRenderer posterRenderer = val.AddComponent<PosterRenderer>(); (Texture2D, string, bool) tuple = value; Texture2D item = tuple.Item1; string item2 = tuple.Item2; bool item3 = tuple.Item3; MeshRenderer component = val.GetComponent<MeshRenderer>(); posterRenderer.Initialize(item, item3 ? item2 : null, (component != null) ? ((Renderer)component).material : null); CreatedPosters.Add(val); <anyPosterLoaded>5__9 = true; } else { Plugin.Log.LogWarning((object)("No enabled texture found for " + <posterData>5__5[<i>5__12].Name + ". Destroying the poster")); Object.Destroy((Object)(object)val); } <>2__current = null; <>1__state = 3; return true; } goto IL_0b91; } if (<anyPosterLoaded>5__9) { if ((Object)(object)<posterPlane>5__4 != (Object)null) { Object.Destroy((Object)(object)<posterPlane>5__4); } Transform obj = <hangarShip>5__2.transform.Find("Plane"); GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val2 != (Object)null) { Object.Destroy((Object)(object)val2); } Plugin.Log.LogInfo((object)"Posters created successfully!"); } else if ((Object)(object)<posterPlane>5__4 != (Object)null) { <posterPlane>5__4.SetActive(true); Plugin.Log.LogWarning((object)"Re-enabled vanilla Plane.001 poster due to no textures loaded"); } return false; IL_07f0: if (<i>5__12 < <filesToLoad>5__11.Count) { List<string> list = <filesToLoad>5__11.Skip(<i>5__12).Take(5).ToList(); <>7__wrap12 = list.GetEnumerator(); <>1__state = -4; goto IL_07a3; } <filesToLoad>5__11 = null; goto IL_080d; IL_07a3: if (<>7__wrap12.MoveNext()) { <file>5__14 = <>7__wrap12.Current; if (Path.GetExtension(<file>5__14).ToLower() == ".mp4") { string key3 = Path.GetFileNameWithoutExtension(<file>5__14).ToLower(); if (!<allVideos>5__7.ContainsKey(key3)) { <allVideos>5__7[key3] = new List<string>(); } <allVideos>5__7[key3].Add(<file>5__14); Plugin.Service.CacheVideo(<file>5__14); goto IL_079c; } <>8__1 = new <>c__DisplayClass26_1(); <>8__1.textureResult = (null, null); <>8__1.loadTask = LoadTextureAsync(<file>5__14, delegate((Texture2D? texture, string? filePath) result) { <>8__1.textureResult = result; }); <>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.loadTask.IsCompleted)); <>1__state = 1; return true; } <>m__Finally2(); <>7__wrap12 = default(List<string>.Enumerator); <>2__current = null; <>1__state = 2; return true; IL_080d: if (<>7__wrap9.MoveNext()) { string current = <>7__wrap9.Current; <>c__DisplayClass26_0 CS$<>8__locals0 = new <>c__DisplayClass26_0(); string fileName = Path.GetFileName(current); string text = Path.Combine(current, "posters"); string text2 = Path.Combine(current, "tips"); string text3 = Path.Combine(current, "CustomPosters", "posters"); string text4 = Path.Combine(current, "CustomPosters", "tips"); <filesToLoad>5__11 = new List<string>(); CS$<>8__locals0.validExtensions = new string[5] { ".png", ".jpg", ".jpeg", ".bmp", ".mp4" }; List<string> list2 = (from p in new string[4] { text, text2, text3, text4 } where Directory.Exists(p) select Path.GetFullPath(p).Replace('\\', '/')).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); foreach (string item5 in list2) { List<string> collection = (from f in Directory.GetFiles(item5) where CS$<>8__locals0.validExtensions.Contains(Path.GetExtension(f).ToLower()) && Plugin.ModConfig.IsFileEnabled(f) select Path.GetFullPath(f).Replace('\\', '/')).ToList(); <filesToLoad>5__11.AddRange(collection); } <filesToLoad>5__11 = <filesToLoad>5__11.Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); <i>5__12 = 0; goto IL_07f0; } <>m__Finally1(); <>7__wrap9 = default(List<string>.Enumerator); <prioritizedContent>5__8 = new Dictionary<string, (Texture2D, string, bool)>(); foreach (KeyValuePair<string, List<(Texture2D, string)>> item6 in <allTextures>5__6) { (Texture2D, string) tuple2 = PackSelector.SelectContentByChance<(Texture2D, string)>(item6.Value, ((Texture2D texture, string filePath) t) => Plugin.ModConfig.GetFileChance(t.filePath), ((Texture2D texture, string filePath) t) => Plugin.Service.GetFilePriority(t.filePath)); <prioritizedContent>5__8[item6.Key] = (tuple2.Item1, tuple2.Item2, false); } foreach (KeyValuePair<string, List<string>> item7 in <allVideos>5__7) { string item4 = PackSelector.SelectContentByChance(item7.Value, (string v) => Plugin.ModConfig.GetFileChance(v), (string v) => Plugin.Service.GetFilePriority(v)); <prioritizedContent>5__8[item7.Key] = (null, item4, true); } if (<allTextures>5__6.Count == 0 && <allVideos>5__7.Count == 0) { Plugin.Log.LogWarning((object)"No textures found in enabled packs"); if ((Object)(object)<posterPlane>5__4 != (Object)null) { <posterPlane>5__4.SetActive(true); } return false; } <anyPosterLoaded>5__9 = false; <i>5__12 = 0; goto IL_0ba3; IL_079c: <file>5__14 = null; goto IL_07a3; IL_0b91: <i>5__12++; goto IL_0ba3; } } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; ((IDisposable)<>7__wrap9).Dispose(); } private void <>m__Finally2() { <>1__state = -3; ((IDisposable)<>7__wrap12).Dispose(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } [CompilerGenerated] private sealed class <DelayedUpdateMaterialsAsync>d__28 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public StartOfRound instance; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <DelayedUpdateMaterialsAsync>d__28(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Expected O, but got Unknown switch (<>1__state) { default: return false; case 0: <>1__state = -1; if (_materialsUpdated) { return false; } <>2__current = (object)new WaitForEndOfFrame(); <>1__state = 1; return true; case 1: <>1__state = -1; HideVanillaPosterPlane(); <>2__current = ((MonoBehaviour)instance).StartCoroutine(CreateCustomPostersAsync()); <>1__state = 2; return true; case 2: <>1__state = -1; _materialsUpdated = true; 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(); } } private static bool _materialsUpdated = false; internal static string? _selectedPack = null; private static readonly List<GameObject> CreatedPosters = new List<GameObject>(); private static int _sessionMapSeed = 0; private static bool _sessionSeedInitialized = false; public static string? SelectedPack => _selectedPack; public static bool IsNewLobby { get; set; } = true; private static bool ShouldActAsHost { get { if (Plugin.ModConfig.EnableNetworking.Value) { if ((Object)(object)NetworkManager.Singleton != (Object)null) { return NetworkManager.Singleton.IsHost; } return false; } return true; } } public static void ResetSession() { _sessionSeedInitialized = false; _sessionMapSeed = 0; _selectedPack = null; Plugin.Log.LogDebug((object)"Session randomization reset."); } public static void SetPackForClients(string packName) { if (!Plugin.ModConfig.EnableNetworking.Value || (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsHost) { return; } Plugin.Log.LogDebug((object)("Client received selected pack from host: " + PathUtils.GetPrettyPath(packName))); _selectedPack = LocalPackPath(packName); if (string.IsNullOrEmpty(_selectedPack)) { Plugin.Log.LogWarning((object)"Could not resolve host selected pack on client. Keeping vanilla posters."); return; } _materialsUpdated = false; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.inShipPhase) { ((MonoBehaviour)instance).StartCoroutine(DelayedUpdateMaterialsAsync(instance)); } } private static string? LocalPackPath(string hostPackIdentifier) { try { string displayPackName = PathUtils.GetDisplayPackName(hostPackIdentifier); string fileName = Path.GetFileName(hostPackIdentifier.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar)); foreach (string posterFolder in Plugin.Service.PosterFolders) { if (string.Equals(PathUtils.GetDisplayPackName(posterFolder), displayPackName, StringComparison.OrdinalIgnoreCase)) { return posterFolder; } } foreach (string posterFolder2 in Plugin.Service.PosterFolders) { if (string.Equals(Path.GetFileName(posterFolder2), fileName, StringComparison.OrdinalIgnoreCase)) { return posterFolder2; } } } catch (Exception ex) { Plugin.Log.LogDebug((object)("LocalPackPath error: " + ex.Message)); } return null; } public static void OnRoundStart(StartOfRound instance) { _materialsUpdated = false; if (IsNewLobby && ShouldActAsHost) { InitializeSessionSeedIfNeeded(); int randomSeed = ComputeSeedAndMaybeLoadSavePack(Plugin.ModConfig.KeepPackFor.Value); Plugin.Service.SetRandomSeed(randomSeed); } if (instance.inShipPhase) { ((MonoBehaviour)instance).StartCoroutine(DelayedUpdateMaterialsAsync(instance)); } IsNewLobby = false; } private static void InitializeSessionSeedIfNeeded() { PosterConfig.KeepFor value = Plugin.ModConfig.KeepPackFor.Value; if (!_sessionSeedInitialized) { _sessionMapSeed = ((value == PosterConfig.KeepFor.Session) ? StartOfRound.Instance.randomMapSeed : Environment.TickCount); _sessionSeedInitialized = true; Plugin.Log.LogDebug((object)$"Seed: {_sessionMapSeed}"); } } private static int ComputeSeedAndMaybeLoadSavePack(PosterConfig.KeepFor mode) { switch (mode) { case PosterConfig.KeepFor.Session: return _sessionMapSeed; case PosterConfig.KeepFor.SaveSlot: { string text = null; try { text = SavePersistenceManager.TryGetCurrentSaveId(); } catch { } int result = ((!string.IsNullOrEmpty(text)) ? HashUtils.DeterministicHash(text) : Environment.TickCount); TryLoadSavedPack(); return result; } default: _selectedPack = null; return Environment.TickCount; } } private static void TryLoadSavedPack() { try { string text = SavePersistenceManager.TryGetCurrentSaveId(); string text2 = null; if (!string.IsNullOrEmpty(text)) { text2 = SavePersistenceManager.TryLoadSelectedPack(text); } if (!string.IsNullOrEmpty(text2)) { _selectedPack = text2; Plugin.Log.LogInfo((object)("Loaded saved pack for save '" + text + "': " + PathUtils.GetPrettyPath(_selectedPack))); } else { _selectedPack = null; } } catch (Exception ex) { _selectedPack = null; Plugin.Log.LogDebug((object)("SaveSlot load skipped: " + ex.Message)); } } private static async Task LoadTextureAsync(string filePath, Action<(Texture2D? texture, string? filePath)> onComplete) { try { if (!File.Exists(filePath)) { Plugin.Log.LogError((object)("File not found: " + PathUtils.GetPrettyPath(filePath))); onComplete?.Invoke((null, null)); return; } Texture2D cachedTexture = Plugin.Service.GetCachedTexture(filePath); if ((Object)(object)cachedTexture != (Object)null) { onComplete?.Invoke((cachedTexture, filePath)); return; } byte[] array = await File.ReadAllBytesAsync(filePath); Texture2D val = new Texture2D(2, 2); if (!ImageConversion.LoadImage(val, array)) { Plugin.Log.LogError((object)("Failed to load texture from " + PathUtils.GetPrettyPath(filePath))); onComplete?.Invoke((null, null)); } else { ((Texture)val).filterMode = (FilterMode)0; Plugin.Service.CacheTexture(filePath, val); onComplete?.Invoke((val, filePath)); } } catch (Exception ex) { Plugin.Log.LogError((object)("Error loading file " + PathUtils.GetPrettyPath(filePath) + ": " + ex.Message)); onComplete?.Invoke((null, null)); } } private static void HideVanillaPosterPlane() { GameObject val = GameObject.Find("Environment/HangarShip/Plane.001 (Old)") ?? GameObject.Find("Environment/HangarShip/Plane.001"); if (val != null) { val.SetActive(false); } } private static void CleanUpPosters() { foreach (GameObject createdPoster in CreatedPosters) { if (!((Object)(object)createdPoster == (Object)null)) { PosterRenderer component = createdPoster.GetComponent<PosterRenderer>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } Object.Destroy((Object)(object)createdPoster); } } CreatedPosters.Clear(); } private static GameObject? CreatePoster(string posterName) { GameObject val = null; val = ((posterName == "CustomTips") ? (Plugin.ModConfig.UseTipsVanillaModel ? AssetManager.TipsPrefab : AssetManager.PosterPrefab) : ((!(posterName == "Poster5")) ? AssetManager.PosterPrefab : (Plugin.ModConfig.UsePoster5VanillaModel ? AssetManager.Poster5Prefab : AssetManager.PosterPrefab))); if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)("Failed to find prefab for " + posterName + ". Falling back to default poster prefab.")); val = AssetManager.PosterPrefab; if ((Object)(object)val == (Object)null) { Plugin.Log.LogError((object)"Default poster prefab is also null!"); return null; } } return Object.Instantiate<GameObject>(val); } public static double? GetVideoTimeForPoster(string posterName) { string posterName2 = posterName; GameObject val = ((IEnumerable<GameObject>)CreatedPosters).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => ((Object)p).name == posterName2)); if (val == null) { return null; } return val.GetComponent<PosterRenderer>()?.GetCurrentVideoTime(); } public static void SetVideoTimeForPoster(string posterName, double time) { string posterName2 = posterName; GameObject val = ((IEnumerable<GameObject>)CreatedPosters).FirstOrDefault((Func<GameObject, bool>)((GameObject p) => ((Object)p).name == posterName2)); if (val != null) { val.GetComponent<PosterRenderer>()?.SetVideoTime(time); } } [IteratorStateMachine(typeof(<CreateCustomPostersAsync>d__26))] private static IEnumerator CreateCustomPostersAsync() { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <CreateCustomPostersAsync>d__26(0); } private static bool PackHasValidFiles(string pack) { try { string[] validExtensions = new string[5] { ".png", ".jpg", ".jpeg", ".bmp", ".mp4" }; string text = Path.Combine(pack, "posters"); string text2 = Path.Combine(pack, "tips"); string text3 = Path.Combine(pack, "CustomPosters", "posters"); string text4 = Path.Combine(pack, "CustomPosters", "tips"); List<string> list = new string[4] { text, text2, text3, text4 }.Where((string p) => Directory.Exists(p)).ToList(); foreach (string item in list) { if (Directory.EnumerateFiles(item).Any((string f) => validExtensions.Contains(Path.GetExtension(f).ToLower()))) { return true; } } if (File.Exists(Path.Combine(pack, "CustomTips.png"))) { return true; } } catch (Exception ex) { Plugin.Log.LogDebug((object)("PackHasValidFiles error for " + pack + ": " + ex.Message)); } return false; } [IteratorStateMachine(typeof(<DelayedUpdateMaterialsAsync>d__28))] private static IEnumerator DelayedUpdateMaterialsAsync(StartOfRound instance) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <DelayedUpdateMaterialsAsync>d__28(0) { instance = instance }; } public static void ChangePosterPack(string packName) { if (string.IsNullOrEmpty(packName)) { List<string> enabledPackNames = Plugin.Service.GetEnabledPackNames(); if (enabledPackNames.Count == 0) { return; } int num = enabledPackNames.FindIndex((string p) => p.Equals(_selectedPack, StringComparison.OrdinalIgnoreCase)); _selectedPack = enabledPackNames[(num + 1) % enabledPackNames.Count]; } else { if (!Plugin.Service.GetEnabledPackNames().Contains<string>(packName, StringComparer.OrdinalIgnoreCase)) { Plugin.Log.LogWarning((object)("Attempted to select invalid pack: " + packName)); return; } _selectedPack = packName; } Plugin.Service.SetRandomSeed(Environment.TickCount); Plugin.Log.LogInfo((object)("Changed poster pack to - " + _selectedPack)); _materialsUpdated = false; StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance != (Object)null && instance.inShipPhase) { ((MonoBehaviour)instance).StartCoroutine(DelayedUpdateMaterialsAsync(instance)); } } } public class PosterRenderer : MonoBehaviour { private VideoPlayer? _videoPlayer; private AudioSource? _audioSource; private RenderTexture? _renderTexture; private float _originalVolume; private static VideoAspectRatio ConvertAspectRatio(PosterConfig.VideoAspectRatio aspectRatio) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0025: 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_0029: Unknown result type (might be due to invalid IL or missing references) return (VideoAspectRatio)(aspectRatio switch { PosterConfig.VideoAspectRatio.Stretch => 5, PosterConfig.VideoAspectRatio.FitInside => 3, PosterConfig.VideoAspectRatio.FitOutside => 4, PosterConfig.VideoAspectRatio.NoScaling => 0, _ => 5, }); } public void Initialize(Texture2D? texture, string? videoPath, Material? materialTemplate) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0188: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c5: Unknown result type (might be due to invalid IL or missing references) //IL_01ca: Unknown result type (might be due to invalid IL or missing references) //IL_01db: Unknown result type (might be due to invalid IL or missing references) //IL_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fb: Unknown result type (might be due to invalid IL or missing references) //IL_0202: Expected O, but got Unknown //IL_0235: Unknown result type (might be due to invalid IL or missing references) //IL_023f: Expected O, but got Unknown //IL_024c: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Expected O, but got Unknown string videoPath2 = videoPath; if ((Object)(object)materialTemplate == (Object)null) { Plugin.Log.LogError((object)"Cannot initialize poster, material template is null."); Object.Destroy((Object)(object)((Component)this).gameObject); return; } MeshRenderer component = ((Component)this).GetComponent<MeshRenderer>(); Material val2 = (((Renderer)component).material = new Material(materialTemplate)); if (videoPath2 != null && Path.GetExtension(videoPath2).ToLower() == ".mp4") { _renderTexture = new RenderTexture(512, 512, 16); val2.SetTexture("_BaseColorMap", (Texture)(object)_renderTexture); _videoPlayer = ((Component)this).gameObject.AddComponent<VideoPlayer>(); _videoPlayer.url = "file://" + videoPath2; _videoPlayer.renderMode = (VideoRenderMode)2; _videoPlayer.targetTexture = _renderTexture; var (num, maxDistance, aspectRatio) = Plugin.ModConfig.GetFileAudioSettings(videoPath2); _videoPlayer.aspectRatio = ConvertAspectRatio(aspectRatio); _videoPlayer.isLooping = true; _videoPlayer.playOnAwake = false; _audioSource = ((Component)this).gameObject.AddComponent<AudioSource>(); _audioSource.spatialBlend = 1f; _audioSource.spatialize = false; _audioSource.rolloffMode = (AudioRolloffMode)2; AnimationCurve val3 = new AnimationCurve((Keyframe[])(object)new Keyframe[6] { new Keyframe(0f, 1f), new Keyframe(0.157f, 0.547f), new Keyframe(0.517f, 0.278f), new Keyframe(1.259f, 0.102f), new Keyframe(2.69f, 0.033f), new Keyframe(4f, 0f) }); _audioSource.SetCustomCurve((AudioSourceCurveType)0, val3); _audioSource.maxDistance = maxDistance; _videoPlayer.Stop(); _videoPlayer.errorReceived += (ErrorEventHandler)delegate(VideoPlayer player, string message) { Plugin.Log.LogError((object)("VideoPlayer error for " + PathUtils.GetPrettyPath(videoPath2) + ": " + message)); }; _videoPlayer.prepareCompleted += (EventHandler)delegate(VideoPlayer player) { player.Play(); if (Plugin.ModConfig.EnableNetworking.Value && (Object)(object)NetworkManager.Singleton != (Object)null && !NetworkManager.Singleton.IsHost) { PosterSyncManager.RequestVideoTimeFromServer(((Object)((Component)this).gameObject).name); } }; _originalVolume = (float)num / 100f; if (Plugin.ModConfig.EnableVideoAudio.Value) { _videoPlayer.audioOutputMode = (VideoAudioOutputMode)1; _videoPlayer.SetTargetAudioSource((ushort)0, _audioSource); _audioSource.volume = _originalVolume; } else { _videoPlayer.audioOutputMode = (VideoAudioOutputMode)0; _audioSource.volume = 0f; } _videoPlayer.Prepare(); } else if ((Object)(object)texture != (Object)null) { val2.SetTexture("_BaseColorMap", (Texture)(object)texture); } else { Plugin.Log.LogError((object)("No valid texture for poster: " + ((Object)((Component)this).gameObject).name)); Object.Destroy((Object)(object)((Component)this).gameObject); } } public void SetVideoTime(double time) { if ((Object)(object)_videoPlayer != (Object)null && _videoPlayer.isPrepared) { _videoPlayer.time = time; } } public double? GetCurrentVideoTime() { if ((Object)(object)_videoPlayer != (Object)null && _videoPlayer.isPlaying) { return _videoPlayer.time; } return null; } private void Update() { if ((Object)(object)_audioSource != (Object)null && !Plugin.ModConfig.EnableVideoAudio.Value) { if (_audioSource.isPlaying) { _audioSource.Stop(); } _audioSource.volume = 0f; _audioSource.mute = true; } } private void OnDestroy() { if ((Object)(object)_renderTexture != (Object)null) { _renderTexture.Release(); Object.Destroy((Object)(object)_renderTexture); } if ((Object)(object)_videoPlayer != (Object)null && _videoPlayer.isPlaying) { _videoPlayer.Stop(); } } } public class PosterService { private readonly List<string> _posterFolders = new List<string>(); private readonly Dictionary<string, Texture2D> _textureCache = new Dictionary<string, Texture2D>(); private readonly Dictionary<string, string> _videoCache = new Dictionary<string, string>(); private Random _rand; public IReadOnlyList<string> PosterFolders => _posterFolders.AsReadOnly(); public bool IsBiggerShipInstalled { get; private set; } public bool IsShipWindowsInstalled { get; private set; } public bool IsRightWindowEnabled { get; private set; } public bool IsWiderShipModInstalled { get; private set; } public string WiderShipExtendedSide { get; private set; } = "Both"; public bool Is2StoryShipModInstalled { get; private set; } public bool EnableRightWindows { get; private set; } public bool EnableLeftWindows { get; private set; } public string TwoStoryShipLayout { get; private set; } = "Default"; public Random Rand => _rand; public PosterService() { try { string pluginPath = Paths.PluginPath; HashSet<string> hashSet = new HashSet<string>(Constants.ExcludedModFolderNames, StringComparer.OrdinalIgnoreCase); string[] directories = Directory.GetDirectories(pluginPath); foreach (string text in directories) { string fileName = Path.GetFileName(text); if (hashSet.Contains(fileName)) { continue; } string text2 = Path.Combine(text, "CustomPosters"); if (Directory.Exists(text2) && IsValidPosterPack(text2)) { _posterFolders.Add(text2); Plugin.Log.LogDebug((object)("Added single pack: " + PathUtils.GetPrettyPath(text2))); continue; } string[] directories2 = Directory.GetDirectories(text); bool flag = false; string[] array = directories2; foreach (string text3 in array) { try { if (IsValidPosterPack(text3)) { _posterFolders.Add(text3); Plugin.Log.LogDebug((object)("Added child pack: " + PathUtils.GetPrettyPath(text3))); flag = true; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Error while checking child folder " + text3 + ": " + ex.Message)); } } if (!flag && IsValidPosterPack(text)) { _posterFolders.Add(text); Plugin.Log.LogDebug((object)("Added pack from root folder: " + PathUtils.GetPrettyPath(text))); } } } catch (Exception ex2) { Plugin.Log.LogError((object)("Error scanning for poster packs: " + ex2.Message)); } try { if (_posterFolders.Count > 0) { List<string> list = new List<string>(); foreach (string posterFolder in _posterFolders) { int num = 0; try { string path = Path.Combine(posterFolder, "posters"); if (Directory.Exists(path)) { num += Directory.GetFiles(path).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant())); } string path2 = Path.Combine(posterFolder, "tips"); if (Directory.Exists(path2)) { num += Directory.GetFiles(path2).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant())); } num += Directory.GetFiles(posterFolder).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant())); } catch { } list.Add($"{PathUtils.GetDisplayPackName(posterFolder)}={num}"); } Plugin.Log.LogDebug((object)string.Format("Poster packs discovered: {0}; files per pack: {1}", _posterFolders.Count, string.Join(", ", list))); } } catch { } InitializeBiggerShip(); InitializeShipWindows(); InitializeWiderShipMod(); Initialize2StoryShipMod(); SetRandomSeed(Environment.TickCount); } private bool IsValidPosterPack(string folderPath) { try { string path = Path.Combine(folderPath, "posters"); if (Directory.Exists(path) && Directory.EnumerateFiles(path, "*.*", SearchOption.TopDirectoryOnly).Any((string file) => Constants.ValidImageExtensions.Contains(Path.GetExtension(file).ToLowerInvariant()) || Constants.ValidVideoExtensions.Contains(Path.GetExtension(file).ToLowerInvariant()))) { return true; } string text = Path.Combine(folderPath, "tips"); if (Directory.Exists(text) && File.Exists(Path.Combine(text, "CustomTips.png"))) { return true; } if (File.Exists(Path.Combine(folderPath, "CustomTips.png"))) { return true; } } catch (Exception ex) { Plugin.Log.LogDebug((object)("IsValidPosterPack error for " + PathUtils.GetPrettyPath(folderPath) + ": " + ex.Message)); } return false; } private void InitializeBiggerShip() { IsBiggerShipInstalled = Chainloader.PluginInfos.ContainsKey("BiggerShip"); if (IsBiggerShipInstalled) { Plugin.Log.LogInfo((object)"Detected BiggerShip"); } } private void InitializeShipWindows() { IsShipWindowsInstalled = Chainloader.PluginInfos.ContainsKey("TestAccount666.ShipWindows"); if (IsShipWindowsInstalled) { string configPath = Path.Combine(Paths.ConfigPath, "TestAccount666.ShipWindows.cfg"); IsRightWindowEnabled = ConfigFileReader.ReadBoolFromSection(configPath, "Right Window (SideRight)", "1. Enabled = ", defaultValue: false); Plugin.Log.LogInfo((object)$"Detected ShipWindows, RW - {IsRightWindowEnabled}"); } } private void InitializeWiderShipMod() { IsWiderShipModInstalled = Chainloader.PluginInfos.ContainsKey("mborsh.WiderShipMod"); if (!IsWiderShipModInstalled) { return; } try { FieldInfo fieldInfo = Type.GetType("WiderShipMod")?.GetField("ExtendedSide", BindingFlags.Static | BindingFlags.Public); if (fieldInfo != null) { WiderShipExtendedSide = (string)fieldInfo.GetValue(null); } else { ReadWiderShipConfigFile(); } } catch { ReadWiderShipConfigFile(); } Plugin.Log.LogInfo((object)("Detected WiderShip, ES - " + WiderShipExtendedSide)); } private void ReadWiderShipConfigFile() { string configPath = Path.Combine(Paths.ConfigPath, "mborsh.WiderShipMod.cfg"); WiderShipExtendedSide = ConfigFileReader.ReadStringValue(configPath, "Extended Side = ", "Both"); } private void Initialize2StoryShipMod() { Is2StoryShipModInstalled = Chainloader.PluginInfos.ContainsKey("MelanieMelicious.2StoryShip"); if (!Is2StoryShipModInstalled) { return; } try { Type type = Type.GetType("2StoryShip"); if (type != null) { FieldInfo field = type.GetField("EnableRightWindows", BindingFlags.Static | BindingFlags.Public); FieldInfo field2 = type.GetField("EnableLeftWindows", BindingFlags.Static | BindingFlags.Public); if (field != null && field2 != null) { EnableRightWindows = (bool)field.GetValue(null); EnableLeftWindows = (bool)field2.GetValue(null); } else { Read2StoryShipConfigFile(); } } else { Read2StoryShipConfigFile(); } } catch { Read2StoryShipConfigFile(); } Plugin.Log.LogInfo((object)$"Detected 2StoryShipMod, RW - {EnableRightWindows}, LW - {EnableLeftWindows}"); } private void Read2StoryShipConfigFile() { string configPath = Path.Combine(Paths.ConfigPath, "MelanieMelicious.2StoryShip.cfg"); Dictionary<string, string> dictionary = ConfigFileReader.ReadMultipleValues(configPath, "Enable Right Windows = ", "Enable Left Windows = "); EnableRightWindows = !dictionary.TryGetValue("Enable Right Windows = ", out var value) || bool.Parse(value); EnableLeftWindows = !dictionary.TryGetValue("Enable Left Windows = ", out var value2) || bool.Parse(value2); string text = ConfigFileReader.ReadStringFromSection(configPath, "Wider + 2-Story Exclusive", "Ship Layout = ", "Default"); if (!string.IsNullOrEmpty(text)) { TwoStoryShipLayout = text.Trim(); } } public void SetRandomSeed(int seed) { _rand = new Random(seed); } public Texture2D? GetCachedTexture(string filePath) { if (!Plugin.ModConfig.EnableTextureCaching.Value) { return null; } if (_textureCache.TryGetValue(filePath, out Texture2D value)) { Plugin.Log.LogDebug((object)("Retrieved cached texture: " + PathUtils.GetPrettyPath(filePath))); return value; } return null; } public void CacheTexture(string filePath, Texture2D texture) { if (Plugin.ModConfig.EnableTextureCaching.Value && !_textureCache.ContainsKey(filePath)) { _textureCache[filePath] = texture; } } public string? GetCachedVideo(string filePath) { if (!Plugin.ModConfig.EnableTextureCaching.Value) { return null; } if (_videoCache.TryGetValue(filePath, out string value)) { Plugin.Log.LogDebug((object)("Retrieved cached video: " + PathUtils.GetPrettyPath(filePath))); return value; } return null; } public void CacheVideo(string filePath) { if (Plugin.ModConfig.EnableTextureCaching.Value && !_videoCache.ContainsKey(filePath)) { if (!File.Exists(filePath)) { Plugin.Log.LogError((object)("Cannot cache video, file does not exist: " + PathUtils.GetPrettyPath(filePath))); return; } _videoCache[filePath] = filePath; Plugin.Log.LogDebug((object)("Cached video: " + PathUtils.GetPrettyPath(filePath))); } } public void ClearCache() { foreach (Texture2D value in _textureCache.Values) { if ((Object)(object)value != (Object)null) { Object.Destroy((Object)(object)value); } } _textureCache.Clear(); _videoCache.Clear(); Plugin.Log.LogInfo((object)"Cleared texture and video cache"); } public List<string> GetEnabledPackNames() { List<string> list = (from f in PosterFolders where Plugin.ModConfig.IsPackEnabled(f) select Path.GetFullPath(f).NormalizePath()).Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList(); List<string> values = list.Select(Path.GetFileName).ToList(); Plugin.Log.LogDebug((object)("Enabled pack names: " + string.Join(", ", values))); return list; } public int GetFilePriority(string filePath) { return Path.GetExtension(filePath).ToLower() switch { ".png" => 1, ".jpg" => 2, ".jpeg" => 3, ".bmp" => 4, ".mp4" => 5, _ => int.MaxValue, } * 1000 + Rand.Next(0, 1000); } } public static class MyPluginInfo { public const string PLUGIN_GUID = "CustomPosters"; public const string PLUGIN_NAME = "CustomPosters"; public const string PLUGIN_VERSION = "4.0.2"; } } namespace CustomPosters.Utils { internal static class ConfigFileReader { public static bool ReadBoolValue(string configPath, string key, bool defaultValue = true) { if (!File.Exists(configPath)) { return defaultValue; } try { string[] array = File.ReadAllLines(configPath); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.StartsWith(key, StringComparison.OrdinalIgnoreCase)) { string value = text2.Substring(key.Length).Trim(); if (bool.TryParse(value, out var result)) { return result; } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Error reading config file " + configPath + ": " + ex.Message)); } return defaultValue; } public static string ReadStringValue(string configPath, string key, string defaultValue = "") { if (!File.Exists(configPath)) { return defaultValue; } try { string[] array = File.ReadAllLines(configPath); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.StartsWith(key, StringComparison.OrdinalIgnoreCase)) { return text2.Substring(key.Length).Trim(); } } } catch (Exception ex) { Plugin.Log.LogError((object)("Error reading config file " + configPath + ": " + ex.Message)); } return defaultValue; } public static bool ReadBoolFromSection(string configPath, string sectionHeader, string key, bool defaultValue = true) { if (!File.Exists(configPath)) { return defaultValue; } try { string[] array = File.ReadAllLines(configPath); bool flag = false; string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); if (text2.StartsWith("[") && text2.EndsWith("]")) { flag = text2.Equals("[" + sectionHeader + "]", StringComparison.OrdinalIgnoreCase); } else if (flag && text2.StartsWith(key, StringComparison.OrdinalIgnoreCase)) { string value = text2.Substring(key.Length).Trim(); if (bool.TryParse(value, out var result)) { return result; } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Error reading config file " + configPath + ": " + ex.Message)); } return defaultValue; } public static string ReadStringFromSection(string configPath, string sectionHeader, string key, string defaultValue = "") { if (!File.Exists(configPath)) { return defaultValue; } try { bool flag = false; string[] array = File.ReadAllLines(configPath); foreach (string text in array) { string text2 = text.Trim(); if (string.IsNullOrWhiteSpace(text2)) { continue; } if (text2.StartsWith("[") && text2.EndsWith("]")) { string a = text2.Substring(1, text2.Length - 2).Trim(); flag = string.Equals(a, sectionHeader, StringComparison.OrdinalIgnoreCase); } else if (flag && text2.StartsWith(key, StringComparison.OrdinalIgnoreCase)) { int num = text2.IndexOf('='); if (num >= 0 && num + 1 < text2.Length) { return text2.Substring(num + 1).Trim(); } } } } catch (Exception ex) { try { Plugin.Log.LogDebug((object)("ReadStringFromSection error for '" + sectionHeader + ":" + key + "': " + ex.Message)); } catch { } } return defaultValue; } public static Dictionary<string, string> ReadMultipleValues(string configPath, params string[] keys) { Dictionary<string, string> dictionary = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase); if (!File.Exists(configPath)) { return dictionary; } try { string[] array = File.ReadAllLines(configPath); HashSet<string> hashSet = new HashSet<string>(keys, StringComparer.OrdinalIgnoreCase); string[] array2 = array; foreach (string text in array2) { string text2 = text.Trim(); foreach (string item in hashSet) { if (text2.StartsWith(item, StringComparison.OrdinalIgnoreCase)) { string value = text2.Substring(item.Length).Trim(); dictionary[item] = value; if (dictionary.Count == keys.Length) { return dictionary; } break; } } } } catch (Exception ex) { Plugin.Log.LogError((object)("Error reading config file " + configPath + ": " + ex.Message)); } return dictionary; } } internal static class Extensions { public static bool IsImage(this string filePath) { if (string.IsNullOrEmpty(filePath)) { return false; } string value = Path.GetExtension(filePath).ToLowerInvariant(); return Constants.ValidImageExtensions.Contains(value); } public static bool IsVideo(this string filePath) { if (string.IsNullOrEmpty(filePath)) { return false; } string value = Path.GetExtension(filePath).ToLowerInvariant(); return Constants.ValidVideoExtensions.Contains(value); } public static bool IsValidPosterFile(this string filePath) { if (string.IsNullOrEmpty(filePath)) { return false; } string value = Path.GetExtension(filePath).ToLowerInvariant(); return Constants.AllValidExtensions.Contains(value); } public static string NormalizePath(this string path) { return path?.Replace('\\', '/') ?? string.Empty; } public static string GetPosterName(this string filePath) { return Path.GetFileNameWithoutExtension(filePath)?.ToLower() ?? string.Empty; } public static T GetComponentSafe<T>(this GameObject gameObject) where T : Component { if (!((Object)(object)gameObject != (Object)null)) { return default(T); } return gameObject.GetComponent<T>(); } public static void AddRangeDistinct<T>(this List<T> list, IEnumerable<T> items, IEqualityComparer<T> comparer = null) { if (comparer == null) { comparer = EqualityComparer<T>.Default; } HashSet<T> hashSet = new HashSet<T>(list, comparer); foreach (T item in items) { if (hashSet.Add(item)) { list.Add(item); } } } } internal static class HashUtils { private const int HashSeed = 23; private const int HashMul = 31; [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int DeterministicHash(string input) { int num = 23; for (int i = 0; i < input.Length; i++) { num = num * 31 + input[i]; } return num; } } internal static class PackSelector { public static string SelectPackByChance(List<string> enabledPacks) { if (enabledPacks == null || enabledPacks.Count == 0) { return null; } if (enabledPacks.Count == 1) { return enabledPacks[0]; } List<int> list = enabledPacks.Select((string p) => Plugin.ModConfig.GetPackChance(p)).ToList(); if (list.All((int c) => c == 0)) { return enabledPacks[Plugin.Service.Rand.Next(enabledPacks.Count)]; } return SelectByWeightedChance(enabledPacks, list); } public static T SelectContentByChance<T>(List<T> items, Func<T, int> getChance, Func<T, int> getPriority) { if (items == null || items.Count == 0) { return default(T); } if (items.Count == 1) { return items[0]; } List<int> list = items.Select(getChance).ToList(); if (list.All((int c) => c == 0)) { return items.OrderBy(getPriority).First(); } return SelectByWeightedChance(items, list); } private static T SelectByWeightedChance<T>(List<T> items, List<int> chances) { int num = chances.Sum(); if (num <= 0) { return items[0]; } double num2 = Plugin.Service.Rand.NextDouble() * (double)num; double num3 = 0.0; for (int i = 0; i < items.Count; i++) { num3 += (double)chances[i]; if (num2 <= num3) { return items[i]; } } return items[0]; } } internal static class PathUtils { public static string GetPrettyPath(string fullPath) { if (string.IsNullOrEmpty(fullPath)) { return string.Empty; } int num = fullPath.IndexOf("plugins", StringComparison.OrdinalIgnoreCase); if (num != -1) { return fullPath.Substring(num + "plugins".Length + 1); } return fullPath; } public static string GetPackName(string fullPackName) { if (string.IsNullOrEmpty(fullPackName)) { return string.Empty; } int num = fullPackName.IndexOf('-'); if (num > 0 && num < fullPackName.Length - 1) { return fullPackName.Substring(num + 1); } return fullPackName; } public static string GetDisplayPackName(string packPath) { if (string.IsNullOrEmpty(packPath)) { return string.Empty; } string fileName = Path.GetFileName(packPath); string directoryName = Path.GetDirectoryName(packPath); if (!string.IsNullOrEmpty(directoryName)) { string fileName2 = Path.GetFileName(directoryName); if (string.Equals(fileName, "CustomPosters", StringComparison.OrdinalIgnoreCase)) { return GetPackName(fileName2); } string.IsNullOrEmpty(fileName2); return fileName; } return fileName; } } internal static class SavePersistenceManager { private const string Es3Key = "CustomPosters_SelectedPack"; public static string? TryGetCurrentSaveId() { try { GameNetworkManager instance = GameNetworkManager.Instance; if ((Object)(object)instance != (Object)null) { Type type = ((object)instance).GetType(); FieldInfo field = type.GetField("currentSaveFileName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); PropertyInfo property = type.GetProperty("currentSaveFileName", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); string text = (field?.GetValue(instance) as string) ?? (property?.GetValue(instance) as string); if (!string.IsNullOrEmpty(text)) { return text; } } } catch { } return null; } public static string? TryLoadSelectedPack(string saveId) { try { if (string.IsNullOrEmpty(saveId)) { return null; } if (ES3.KeyExists("CustomPosters_SelectedPack", saveId)) { string text = ES3.Load<string>("CustomPosters_SelectedPack", saveId, ""); return string.IsNullOrEmpty(text) ? null : text; } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Failed to load per save selection from ES3: " + ex.Message)); } return null; } public static void SaveSelectedPack(string saveId, string packPath) { try { if (!string.IsNullOrEmpty(saveId)) { ES3.Save<string>("CustomPosters_SelectedPack", packPath, saveId); } } catch (Exception ex) { Plugin.Log.LogDebug((object)("Failed to save per save selection to ES3: " + ex.Message)); } } } } namespace CustomPosters.Patches { [HarmonyPatch(typeof(GameNetworkManager))] internal class GameNetworkManagerPatch { [HarmonyPostfix] [HarmonyPatch("Start")] private static void OnStartPatch() { PosterManager.ResetSession(); if (Plugin.ModConfig.EnableNetworking.Value) { if ((Object)(object)NetworkManager.Singleton != (Object)null) { Plugin.Log.LogInfo((object)"Networking is enabled."); NetworkManager.Singleton.OnClientConnectedCallback += PosterSyncManager.OnClientConnected; } else { Plugin.Log.LogWarning((object)"NetworkManager.Singleton is null, cannot register callbacks."); } } else { Plugin.Log.LogInfo((object)"Networking is disabled."); } } [HarmonyPostfix] [HarmonyPatch("StartHost")] private static void OnStartHostPatch() { PosterManager.IsNewLobby = true; } [HarmonyPostfix] [HarmonyPatch("JoinLobby")] private static void OnJoinLobbyPatch() { PosterManager.IsNewLobby = true; } } [HarmonyPatch(typeof(StartOfRound))] internal class StartOfRoundPatch { [HarmonyPostfix] [HarmonyPatch("Start")] private static void OnRoundStartPatch(StartOfRound __instance) { PosterManager.OnRoundStart(__instance); } } } namespace CustomPosters.Networking { internal static class PosterSyncManager { private const string PackSyncIdentifier = "CustomPosters_SyncPack"; private static readonly LNetworkMessage<string> SyncPackMessage = LNetworkMessage<string>.Connect("CustomPosters_SyncPack", (Action<string, ulong>)null, (Action<string>)PosterManager.SetPackForClients, (Action<string, ulong>)null); private const string VideoRequestIdentifier = "CustomPosters_RequestVideoTime"; private const string VideoSyncIdentifier = "CustomPosters_SyncVideoTime"; private static readonly LNetworkMessage<string> RequestVideoTimeMessage = LNetworkMessage<string>.Connect("CustomPosters_RequestVideoTime", (Action<string, ulong>)OnVideoTimeRequested, (Action<string>)null, (Action<string, ulong>)null); private static readonly LNetworkMessage<VideoSyncData> SyncVideoTimeMessage = LNetworkMessage<VideoSyncData>.Connect("CustomPosters_SyncVideoTime", (Action<VideoSyncData, ulong>)null, (Action<VideoSyncData>)OnVideoTimeReceived, (Action<VideoSyncData, ulong>)null); public static void SendPacket(string packName) { if (!Plugin.ModConfig.EnableNetworking.Value) { Plugin.Log.LogDebug((object)"Networking disabled."); } else if ((Object)(object)NetworkManager.Singleton == (Object)null) { Plugin.Log.LogWarning((object)"NetworkManager.Singleton is null, cannot send pack sync"); } else if (NetworkManager.Singleton.IsHost) { Plugin.Log.LogDebug((object)("Sending selected pack to all clients: " + PathUtils.GetPrettyPath(packName))); SyncPackMessage.SendClients(packName); } } public static void OnClientConnected(ulong clientId) { if (Plugin.ModConfig.EnableNetworking.Value) { if ((Object)(object)NetworkManager.Singleton == (Object)null) { Plugin.Log.LogWarning((object)"NetworkManager.Singleton is null in OnClientConnected"); } else if (NetworkManager.Singleton.IsHost && clientId != NetworkManager.Singleton.LocalClientId && !string.IsNullOrEmpty(PosterManager.SelectedPack)) { Plugin.Log.LogDebug((object)("New client joined, sending pack: " + PathUtils.GetPrettyPath(PosterManager.SelectedPack))); SyncPackMessage.SendClient(PosterManager.SelectedPack, clientId); } } } public static void RequestVideoTimeFromServer(string posterName) { if (!Plugin.ModConfig.EnableNetworking.Value) { Plugin.Log.LogDebug((object)"Networking disabled, skipping video time sync request"); } else if (!((Object)(object)NetworkManager.Singleton == (Object)null) && !NetworkManager.Singleton.IsHost) { Plugin.Log.LogDebug((object)("Requesting video time for poster: " + posterName)); RequestVideoTimeMessage.SendServer(posterName); } } private static void OnVideoTimeRequested(string posterName, ulong clientId) { double? videoTimeForPoster = PosterManager.GetVideoTimeForPoster(posterName); if (videoTimeForPoster.HasValue) { Plugin.Log.LogDebug((object)$"Host received request for '{posterName}'. Sending time: {videoTimeForPoster.Value} to client {clientId}"); VideoSyncData videoSyncData = default(VideoSyncData); videoSyncData.PosterName = posterName; videoSyncData.VideoTime = videoTimeForPoster.Value; VideoSyncData videoSyncData2 = videoSyncData; SyncVideoTimeMessage.SendClient(videoSyncData2, clientId); } } private static void OnVideoTimeReceived(VideoSyncData syncData) { Plugin.Log.LogDebug((object)$"Client received sync time for '{syncData.PosterName}': {syncData.VideoTime}"); PosterManager.SetVideoTimeForPoster(syncData.PosterName, syncData.VideoTime); } } public struct VideoSyncData { public string PosterName; public double VideoTime; } } namespace CustomPosters.Data { public struct PosterData { public Vector3 Position; public Vector3 Rotation; public Vector3 Scale; public string Name; } internal static class PosterHelper { public static PosterData Poster5Vanilla(Vector3 pos, Vector3 rot, Vector3 scale) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) PosterData result = default(PosterData); result.Position = pos; result.Rotation = rot; result.Scale = scale; result.Name = "Poster5"; return result; } public static PosterData Poster5Quad(Vector3 pos, Vector3 rot, Vector3 scale) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) PosterData result = default(PosterData); result.Position = pos; result.Rotation = rot; result.Scale = scale; result.Name = "Poster5"; return result; } public static PosterData TipsVanilla(Vector3 pos, Vector3 rot, Vector3 scale) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) PosterData result = default(PosterData); result.Position = pos; result.Rotation = rot; result.Scale = scale; result.Name = "CustomTips"; return result; } public static PosterData TipsQuad(Vector3 pos, Vector3 rot, Vector3 scale) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001a: 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) PosterData result = default(PosterData); result.Position = pos; result.Rotation = rot; result.Scale = scale; result.Name = "CustomTips"; return result; } } internal static class PosterLayoutProvider { public static PosterData[] GetLayout() { bool isShipWindowsInstalled = Plugin.Service.IsShipWindowsInstalled; bool isRightWindowEnabled = Plugin.Service.IsRightWindowEnabled; bool isWiderShipModInstalled = Plugin.Service.IsWiderShipModInstalled; string widerShipExtendedSide = Plugin.Service.WiderShipExtendedSide; bool is2StoryShipModInstalled = Plugin.Service.Is2StoryShipModInstalled; bool enableRightWindows = Plugin.Service.EnableRightWindows; bool enableLeftWindows = Plugin.Service.EnableLeftWindows; bool flag = is2StoryShipModInstalled && string.Equals(Plugin.Service.TwoStoryShipLayout, "Legacy", StringComparison.OrdinalIgnoreCase); if (Plugin.Service.IsBiggerShipInstalled) { Plugin.Log.LogInfo((object)"Choosing layout: BiggerShip"); return BiggerShip.Get(); } if (is2StoryShipModInstalled) { if (flag && isWiderShipModInstalled) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (Legacy) + WiderShip"); return CustomPosters.Data.PosterLayouts.Legacy.TwoStoryShip_WiderShip.Get(); } if (isShipWindowsInstalled && isWiderShipModInstalled && !isRightWindowEnabled) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship + ShipWindows + WiderShip (No right window)"); return CustomPosters.Data.PosterLayouts.TwoStoryShip_WiderShip.Get(); } if (isShipWindowsInstalled && isWiderShipModInstalled) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship + ShipWindows + WiderShip"); return CustomPosters.Data.PosterLayouts.TwoStoryShip_WiderShip.Get(); } if (isWiderShipModInstalled && !enableLeftWindows) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship + WiderShip (No left window)"); return CustomPosters.Data.PosterLayouts.TwoStoryShip_WiderShip.Get(); } if (isShipWindowsInstalled) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship + ShipWindows"); return TwoStoryShip.Get(); } if (isWiderShipModInstalled) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship + WiderShip"); return CustomPosters.Data.PosterLayouts.TwoStoryShip_WiderShip.Get(); } if (!enableRightWindows && !enableLeftWindows) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (No both windows)"); return TwoStoryShip.Get(); } if (enableRightWindows && enableLeftWindows) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (All windows)"); return TwoStoryShip.Get(); } if (!enableRightWindows) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (No right window)"); return TwoStoryShip.Get(); } if (!enableLeftWindows) { Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (No left window)"); return TwoStoryShip.Get(); } } if (isShipWindowsInstalled && isRightWindowEnabled && isWiderShipModInstalled && widerShipExtendedSide == "Left") { Plugin.Log.LogInfo((object)"Choosing layout: ShipWindows + WiderShip (Left)"); return ShipWindows_WiderShip_Left.Get(); } if (isWiderShipModInstalled) { Plugin.Log.LogInfo((object)("Choosing layout: WiderShip - " + widerShipExtendedSide)); switch (widerShipExtendedSide) { case "Both": return WiderShip_Both.Get(); case "Right": return WiderShip_Right.Get(); case "Left": return WiderShip_Left.Get(); } } if (isShipWindowsInstalled && isRightWindowEnabled) { Plugin.Log.LogInfo((object)"Choosing layout: ShipWindows"); return ShipWindows.Get(); } Plugin.Log.LogInfo((object)"Choosing layout: Vanilla"); return Vanilla.Get(); } } } namespace CustomPosters.Data.PosterLayouts { internal static class BiggerShip { public static PosterData[] Get() { //IL_0037: 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_0052: 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_006d: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) bool usePoster5VanillaModel = Plugin.ModConfig.UsePoster5VanillaModel; bool useTipsVanillaModel = Plugin.ModConfig.UseTipsVanillaModel; return new PosterData[6] { new PosterData { Position = new Vector3(4.1886f, 2.8918f, -17.8606f), Rotation = new Vector3(0f, 169.6929f, 0f), Scale = new Vector3(0.6391f, 0.4882f, 2f), Name = "Poster1" }, new PosterData { Position = new Vector3(6.4202f, 2.4776f, -10.9064f), Rotation = new Vector3(0f, 0f, 0f), Scale = new Vector3(0.7296f, 0.4896f, 1f), Name = "Poster2" }, new PosterData { Position = new Vector3(9.9186f, 2.8591f, -17.5587f), Rotation = new Vector3(0f, 180f, 356.3345f), Scale = new Vector3(0.7487f, 1.0539f, 1f), Name = "Poster3" }, new PosterData { Position = new Vector3(5.2187f, 2.5963f, -10.782f), Rotation = new Vector3(0f, 10.7715f, 2.68f), Scale = new Vector3(0.7289f, 0.9989f, 1f), Name = "Poster4" }, usePoster5VanillaModel ? PosterHelper.Poster5Vanilla(new Vector3(5.5286f, 2.5882f, -17.6077f), new Vector3(1.3609f, 329.1297f, 182.4321f), new Vector3(0.465f, 0.71f, 1f)) : PosterHelper.Poster5Quad(new Vector3(5.5286f, 2.5882f, -17.6184f), new Vector3(0f, 169.7645f, 359.8f), new Vector3(0.5516f, 0.769f, 1f)), useTipsVanillaModel ? PosterHelper.TipsVanilla(new Vector3(8.147f, 2.399426f, -20.6869f), new Vector3(-270.38f, -321.026f, 219.239f), new Vector3(46.75954f, 100f, 70.89838f)) : PosterHelper.TipsQuad(new Vector3(3.0647f, 2.8174f, -10.4842f), new Vector3(0f, 0f, 0f), new Vector3(0.8596f, 1.2194f, 1f)) }; } } internal static class ShipWindows { public static PosterData[] Get() { //IL_0037: 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_0052: 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_006d: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) bool usePoster5VanillaModel = Plugin.ModConfig.UsePoster5VanillaModel; bool useTipsVanillaModel = Plugin.ModConfig.UseTipsVanillaModel; return new PosterData[6] { new PosterData { Position = new Vector3(4.1886f, 2.9318f, -16.8409f), Rotation = new Vector3(0f, 200.9872f, 0f), Scale = new Vector3(0.6391f, 0.4882f, 2f), Name = "Poster1" }, new PosterData { Position = new Vector3(6.4202f, 2.2577f, -10.822f), Rotation = new Vector3(0f, 0f, 0f), Scale = new Vector3(0.7296f, 0.4896f, 1f), Name = "Poster2" }, new PosterData { Position = new Vector3(9.9186f, 2.8591f, -17.4716f), Rotation = new Vector3(0f, 180f, 356.3345f), Scale = new Vector3(0.7487f, 1.0539f, 1f), Name = "Poster3" }, new PosterData { Position = new Vector3(6.4449f, 3.0961f, -10.8219f), Rotation = new Vector3(0f, 0f, 2.68f), Scale = new Vector3(0.7289f, 0.9989f, 1f), Name = "Poster4" }, usePoster5VanillaModel ? PosterHelper.Poster5Vanilla(new Vector3(5.5286f, 2.5882f, -17.3421f), new Vector3(1.3609f, 0.2388f, 182.4321f), new Vector3(0.465f, 0.71f, 1f)) : PosterHelper.Poster5Quad(new Vector3(5.5286f, 2.5882f, -17.3541f), new Vector3(0f, 201.1556f, 359.8f), new Vector3(0.5516f, 0.769f, 1f)), useTipsVanillaModel ? PosterHelper.TipsVanilla(new Vector3(8.147f, 2.399426f, -21.929f), new Vector3(-270.38f, -321.026f, 219.239f), new Vector3(46.75954f, 100f, 70.89838f)) : PosterHelper.TipsQuad(new Vector3(3.0647f, 2.8174f, -11.7255f), new Vector3(0f, 0f, 358.6752f), new Vector3(0.8596f, 1.2194f, 1f)) }; } } internal static class ShipWindows_WiderShip_Left { public static PosterData[] Get() { //IL_0037: 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_0052: 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_006d: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_0227: Unknown result type (might be due to invalid IL or missing references) //IL_023b: Unknown result type (might be due to invalid IL or missing references) //IL_024f: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_01f8: Unknown result type (might be due to invalid IL or missing references) //IL_020c: Unknown result type (might be due to invalid IL or missing references) //IL_02b5: Unknown result type (might be due to invalid IL or missing references) //IL_02c9: Unknown result type (might be due to invalid IL or missing references) //IL_02dd: Unknown result type (might be due to invalid IL or missing references) //IL_0272: Unknown result type (might be due to invalid IL or missing references) //IL_0286: Unknown result type (might be due to invalid IL or missing references) //IL_029a: Unknown result type (might be due to invalid IL or missing references) bool usePoster5VanillaModel = Plugin.ModConfig.UsePoster5VanillaModel; bool useTipsVanillaModel = Plugin.ModConfig.UseTipsVanillaModel; return new PosterData[6] { new PosterData { Position = new Vector3(4.6777f, 2.9007f, -19.63f), Rotation = new Vector3(0f, 118.2274f, 0f), Scale = new Vector3(0.6391f, 0.4882f, 2f), Name = "Poster1" }, new PosterData { Position = new Vector3(6.4202f, 2.2577f, -10.8226f), Rotation = new Vector3(0f, 0f, 0f), Scale = new Vector3(0.7296f, 0.4896f, 1f), Name = "Poster2" }, new PosterData { Position = new Vector3(9.9186f, 2.8591f, -17.4716f), Rotation = new Vector3(0f, 180f, 356.3345f), Scale = new Vector3(0.7487f, 1.0539f, 1f), Name = "Poster3" }, new PosterData { Position = new Vector3(6.4449f, 3.0961f, -10.8221f), Rotation = new Vector3(0f, 0f, 2.68f), Scale = new Vector3(0.7289f, 0.9989f, 1f), Name = "Poster4" }, usePoster5VanillaModel ? PosterHelper.Poster5Vanilla(new Vector3(5.3602f, 2.5882f, -18.3492f), new Vector3(357.7245f, 277.6282f, 180f), new Vector3(0.465f, 0.71f, 1f)) : PosterHelper.Poster5Quad(new Vector3(5.3602f, 2.5482f, -18.3793f), new Vector3(0f, 118.0114f, 359.8f), new Vector3(0.5516f, 0.769f, 1f)), useTipsVanillaModel ? PosterHelper.TipsVanilla(new Vector3(8.147f, 2.399426f, -21.929f), new Vector3(-270.38f, -321.026f, 219.239f), new Vector3(46.75954f, 100f, 70.89838f)) : PosterHelper.TipsQuad(new Vector3(2.8647f, 2.7774f, -11.7341f), new Vector3(0f, 0f, 358.6752f), new Vector3(0.8596f, 1.2194f, 1f)) }; } } internal static class TwoStoryShip { public static PosterData[] Get() { //IL_0037: 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_0052: 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_006d: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: 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) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_017e: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019e: Unknown result type (might be due to inva