Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Lilacassette CustomPosters v1.0.0
CustomPosters/CustomPosters.dll
Decompiled 3 months 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.3.0")] [assembly: AssemblyInformationalVersion("4.0.3+dcb660f57e8ccba28e2eaa41ee6d192a7411a23b")] [assembly: AssemblyProduct("CustomPosters")] [assembly: AssemblyTitle("CustomPosters")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("4.0.3.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace 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.3")] [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_0a70: Unknown result type (might be due to invalid IL or missing references) //IL_0a92: Unknown result type (might be due to invalid IL or missing references) //IL_0a97: Unknown result type (might be due to invalid IL or missing references) //IL_0ab9: 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 { HashSet<string> hashSet; 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> list4 = Plugin.Service.PosterFolders.Where((string folder) => Plugin.ModConfig.IsPackEnabled(folder)).ToList(); bool flag = Plugin.ModConfig.EnableNetworking.Value && !ShouldActAsHost && !string.IsNullOrEmpty(_selectedPack); if (list4.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> list5 = list4.Select((string pack) => Path.GetFileName(pack)).ToList(); List<string> list7; if (Plugin.ModConfig.RandomizerModeSetting.Value == PosterConfig.RandomizerMode.PerPack) { if (ShouldActAsHost) { PosterConfig.KeepFor value5 = Plugin.ModConfig.KeepPackFor.Value; if (value5 == PosterConfig.KeepFor.SaveSlot) { string value6 = SavePersistenceManager.TryGetCurrentSaveId(); if (string.IsNullOrEmpty(value6)) { _selectedPack = null; } } if (value5 switch { PosterConfig.KeepFor.Lobby => true, PosterConfig.KeepFor.Session => _selectedPack == null || !list4.Contains(_selectedPack), PosterConfig.KeepFor.SaveSlot => _selectedPack == null || !list4.Contains(_selectedPack), _ => true, }) { List<string> list6 = new List<string>(list4); string selectedPack = null; while (list6.Count > 0) { string text5 = PackSelector.SelectPackByChance(list6); if (PackHasValidFiles(text5)) { selectedPack = text5; break; } list6.Remove(text5); } _selectedPack = selectedPack; if (!string.IsNullOrEmpty(_selectedPack) && value5 == 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)); list7 = new List<string> { _selectedPack }; } else { list7 = list4; 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 = list7.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_0bb6; } IL_0bb6: <i>5__12++; goto IL_0bc8; IL_0bc8: 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 item2 = tuple.Item1; string item3 = tuple.Item2; bool item4 = tuple.Item3; MeshRenderer component = val.GetComponent<MeshRenderer>(); posterRenderer.Initialize(item2, item4 ? item3 : 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_0bb6; } 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_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> list = (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 list) { 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)>(); hashSet = <allTextures>5__6.Keys.Union(<allVideos>5__7.Keys).ToHashSet(); foreach (string item6 in hashSet) { List<(Texture2D, string, bool)> list2 = new List<(Texture2D, string, bool)>(); if (<allTextures>5__6.TryGetValue(item6, out List<(Texture2D, string)> value2)) { foreach (var item7 in value2) { list2.Add((item7.Item1, item7.Item2, false)); } } if (<allVideos>5__7.TryGetValue(item6, out List<string> value3)) { foreach (string item8 in value3) { list2.Add((null, item8, true)); } } if (list2.Count > 0) { (Texture2D, string, bool) value4 = PackSelector.SelectContentByChance<(Texture2D, string, bool)>(list2, ((Texture2D texture, string filePath, bool isVideo) item) => Plugin.ModConfig.GetFileChance(item.filePath), ((Texture2D texture, string filePath, bool isVideo) item) => Plugin.Service.GetFilePriority(item.filePath)); <prioritizedContent>5__8[item6] = value4; } } 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_0bc8; 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_07f0: if (<i>5__12 < <filesToLoad>5__11.Count) { List<string> list3 = <filesToLoad>5__11.Skip(<i>5__12).Take(5).ToList(); <>7__wrap12 = list3.GetEnumerator(); <>1__state = -4; goto IL_07a3; } <filesToLoad>5__11 = null; goto IL_080d; IL_079c: <file>5__14 = null; goto IL_07a3; } } 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.3"; } } 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: Unkno