Decompiled source of CustomPosters v4.0.4

BepInEx/plugins/CustomPosters/CustomPosters.dll

Decompiled 2 weeks ago
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.4.0")]
[assembly: AssemblyInformationalVersion("4.0.4+779ef258841132444bf56259880ed810a1832f15")]
[assembly: AssemblyProduct("CustomPosters")]
[assembly: AssemblyTitle("CustomPosters")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("4.0.4.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 SeedSyncIdentifier = "CustomPosters_SyncSeed";

		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.4")]
	[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__DisplayClass33_0
		{
			public bool anyPosterLoaded;

			internal void <CreateCustomPostersAsync>b__0(bool loaded)
			{
				anyPosterLoaded = loaded;
			}
		}

		[CompilerGenerated]
		private sealed class <>c__DisplayClass43_0
		{
			public (Texture2D? texture, string? filePath) result;

			public Task loadTask;

			internal void <LoadTextureToDictionary>b__0((Texture2D? texture, string? filePath) r)
			{
				result = r;
			}

			internal bool <LoadTextureToDictionary>b__1()
			{
				return loadTask.IsCompleted;
			}
		}

		[CompilerGenerated]
		private sealed class <CreateCustomPostersAsync>d__33 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			private <>c__DisplayClass33_0 <>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;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <CreateCustomPostersAsync>d__33(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>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;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0058: Unknown result type (might be due to invalid IL or missing references)
				//IL_0062: Expected O, but got Unknown
				//IL_0088: Unknown result type (might be due to invalid IL or missing references)
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
				{
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass33_0();
					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();
					if (!TryResolvePacksToUse(<posterPlane>5__4, out List<string> packsToUse))
					{
						return false;
					}
					<allTextures>5__6 = new Dictionary<string, List<(Texture2D, string)>>();
					<allVideos>5__7 = new Dictionary<string, List<string>>();
					<>2__current = LoadContentFromPacks(packsToUse, <allTextures>5__6, <allVideos>5__7);
					<>1__state = 1;
					return true;
				}
				case 1:
				{
					<>1__state = -1;
					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;
					}
					Dictionary<string, (Texture2D, string, bool)> prioritizedContent = BuildPrioritizedContent(<allTextures>5__6, <allVideos>5__7);
					<>8__1.anyPosterLoaded = false;
					<>2__current = SpawnPostersFromLayout(<posterData>5__5, <postersParent>5__3, prioritizedContent, delegate(bool loaded)
					{
						<>8__1.anyPosterLoaded = loaded;
					});
					<>1__state = 2;
					return true;
				}
				case 2:
					<>1__state = -1;
					FinalizeRender(<>8__1.anyPosterLoaded, <hangarShip>5__2, <posterPlane>5__4);
					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();
			}
		}

		[CompilerGenerated]
		private sealed class <DelayedUpdateMaterialsAsync>d__50 : 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__50(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_0032: Unknown result type (might be due to invalid IL or missing references)
				//IL_003c: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					if (_isUpdating)
					{
						return false;
					}
					_isUpdating = true;
					<>2__current = (object)new WaitForEndOfFrame();
					<>1__state = 1;
					return true;
				case 1:
					<>1__state = -1;
					goto IL_004c;
				case 2:
					{
						<>1__state = -1;
						if (!_needsReUpdate)
						{
							_isUpdating = false;
							return false;
						}
						goto IL_004c;
					}
					IL_004c:
					_needsReUpdate = false;
					HideVanillaPosterPlane();
					<>2__current = ((MonoBehaviour)instance).StartCoroutine(CreateCustomPostersAsync());
					<>1__state = 2;
					return true;
				}
			}

			bool IEnumerator.MoveNext()
			{
				//ILSpy generated this explicit interface implementation from .override directive in MoveNext
				return this.MoveNext();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadContentFromPacks>d__40 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public List<string> packsToUse;

			public Dictionary<string, List<string>> allVideos;

			public Dictionary<string, List<(Texture2D texture, string filePath)>> allTextures;

			private List<string>.Enumerator <>7__wrap1;

			private List<string> <filesToLoad>5__3;

			private int <i>5__4;

			private List<string>.Enumerator <>7__wrap4;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadContentFromPacks>d__40(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();
					}
				}
				<>7__wrap1 = default(List<string>.Enumerator);
				<filesToLoad>5__3 = null;
				<>7__wrap4 = default(List<string>.Enumerator);
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				try
				{
					switch (<>1__state)
					{
					default:
						return false;
					case 0:
						<>1__state = -1;
						<>7__wrap1 = packsToUse.GetEnumerator();
						<>1__state = -3;
						goto IL_014e;
					case 1:
						<>1__state = -4;
						goto IL_00ea;
					case 2:
						{
							<>1__state = -3;
							<i>5__4 += 5;
							goto IL_0131;
						}
						IL_014e:
						if (<>7__wrap1.MoveNext())
						{
							string current = <>7__wrap1.Current;
							<filesToLoad>5__3 = GatherValidFilesForPack(current);
							<i>5__4 = 0;
							goto IL_0131;
						}
						<>m__Finally1();
						<>7__wrap1 = default(List<string>.Enumerator);
						return false;
						IL_00ea:
						while (<>7__wrap4.MoveNext())
						{
							string current2 = <>7__wrap4.Current;
							if (current2.IsVideo())
							{
								RegisterVideo(current2, allVideos);
								continue;
							}
							<>2__current = LoadTextureToDictionary(current2, allTextures);
							<>1__state = 1;
							return true;
						}
						<>m__Finally2();
						<>7__wrap4 = default(List<string>.Enumerator);
						<>2__current = null;
						<>1__state = 2;
						return true;
						IL_0131:
						if (<i>5__4 < <filesToLoad>5__3.Count)
						{
							List<string> list = <filesToLoad>5__3.Skip(<i>5__4).Take(5).ToList();
							<>7__wrap4 = list.GetEnumerator();
							<>1__state = -4;
							goto IL_00ea;
						}
						<filesToLoad>5__3 = null;
						goto IL_014e;
					}
				}
				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__wrap1).Dispose();
			}

			private void <>m__Finally2()
			{
				<>1__state = -3;
				((IDisposable)<>7__wrap4).Dispose();
			}

			[DebuggerHidden]
			void IEnumerator.Reset()
			{
				throw new NotSupportedException();
			}
		}

		[CompilerGenerated]
		private sealed class <LoadTextureToDictionary>d__43 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public string file;

			private <>c__DisplayClass43_0 <>8__1;

			public Dictionary<string, List<(Texture2D texture, string filePath)>> allTextures;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <LoadTextureToDictionary>d__43(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>8__1 = null;
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				//IL_006d: Unknown result type (might be due to invalid IL or missing references)
				//IL_0077: Expected O, but got Unknown
				switch (<>1__state)
				{
				default:
					return false;
				case 0:
					<>1__state = -1;
					<>8__1 = new <>c__DisplayClass43_0();
					<>8__1.result = (null, null);
					<>8__1.loadTask = LoadTextureAsync(file, delegate((Texture2D? texture, string? filePath) r)
					{
						<>8__1.result = r;
					});
					<>2__current = (object)new WaitUntil((Func<bool>)(() => <>8__1.loadTask.IsCompleted));
					<>1__state = 1;
					return true;
				case 1:
				{
					<>1__state = -1;
					if ((Object)(object)<>8__1.result.texture == (Object)null || <>8__1.result.filePath == null)
					{
						Plugin.Log.LogWarning((object)("Failed to load texture from " + file));
						return false;
					}
					string posterName = <>8__1.result.filePath.GetPosterName();
					if (!allTextures.ContainsKey(posterName))
					{
						allTextures[posterName] = new List<(Texture2D, string)>();
					}
					allTextures[posterName].Add((<>8__1.result.texture, <>8__1.result.filePath));
					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();
			}
		}

		[CompilerGenerated]
		private sealed class <SpawnPostersFromLayout>d__45 : IEnumerator<object>, IEnumerator, IDisposable
		{
			private int <>1__state;

			private object <>2__current;

			public PosterData[] posterData;

			public GameObject postersParent;

			public Dictionary<string, (Texture2D? texture, string filePath, bool isVideo)> prioritizedContent;

			public Action<bool> onCompleted;

			private bool <anyPosterLoaded>5__2;

			private int <i>5__3;

			object IEnumerator<object>.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			object IEnumerator.Current
			{
				[DebuggerHidden]
				get
				{
					return <>2__current;
				}
			}

			[DebuggerHidden]
			public <SpawnPostersFromLayout>d__45(int <>1__state)
			{
				this.<>1__state = <>1__state;
			}

			[DebuggerHidden]
			void IDisposable.Dispose()
			{
				<>1__state = -2;
			}

			private bool MoveNext()
			{
				int num = <>1__state;
				if (num != 0)
				{
					if (num != 1)
					{
						return false;
					}
					<>1__state = -1;
					goto IL_00b6;
				}
				<>1__state = -1;
				<anyPosterLoaded>5__2 = false;
				<i>5__3 = 0;
				goto IL_00c6;
				IL_00b6:
				<i>5__3++;
				goto IL_00c6;
				IL_00c6:
				if (<i>5__3 < posterData.Length)
				{
					GameObject val = CreatePoster(posterData[<i>5__3].Name);
					if (!((Object)(object)val == (Object)null))
					{
						ApplyPosterTransform(val, posterData[<i>5__3], postersParent.transform);
						if (TryAssignPosterContent(val, posterData[<i>5__3].Name, prioritizedContent))
						{
							<anyPosterLoaded>5__2 = true;
						}
						<>2__current = null;
						<>1__state = 1;
						return true;
					}
					goto IL_00b6;
				}
				onCompleted(<anyPosterLoaded>5__2);
				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 _isUpdating = false;

		private static bool _needsReUpdate = false;

		internal static string? _selectedPack = null;

		private static bool _clientSeedReceived = false;

		private static int _currentHostSeed = 0;

		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 int CurrentHostSeed => _currentHostSeed;

		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;
			_clientSeedReceived = false;
			_currentHostSeed = 0;
			_isUpdating = false;
			_needsReUpdate = false;
			Plugin.Log.LogDebug((object)"Session randomization reset.");
		}

		public static void OnSceneAwake()
		{
			_isUpdating = false;
			_needsReUpdate = false;
			if (Plugin.ModConfig.EnableNetworking.Value && !((Object)(object)NetworkManager.Singleton == (Object)null))
			{
				if (NetworkManager.Singleton.IsHost)
				{
					_currentHostSeed = 0;
					return;
				}
				_clientSeedReceived = false;
				_selectedPack = null;
				_currentHostSeed = 0;
				Plugin.Log.LogDebug((object)"Client per lobby state reset, waiting for host seed.");
			}
		}

		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;
			}
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && instance.inShipPhase)
			{
				if (_isUpdating)
				{
					_needsReUpdate = true;
				}
				else
				{
					((MonoBehaviour)instance).StartCoroutine(DelayedUpdateMaterialsAsync(instance));
				}
			}
		}

		public static void SetSeedForClients(int seed)
		{
			if (!Plugin.ModConfig.EnableNetworking.Value || (Object)(object)NetworkManager.Singleton == (Object)null || NetworkManager.Singleton.IsHost)
			{
				return;
			}
			Plugin.Log.LogDebug((object)$"Client received seed from host: {seed}");
			Plugin.Service.SetRandomSeed(seed);
			_clientSeedReceived = true;
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && instance.inShipPhase)
			{
				if (_isUpdating)
				{
					_needsReUpdate = true;
				}
				else
				{
					((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)
		{
			_isUpdating = false;
			_needsReUpdate = false;
			if (IsNewLobby && ShouldActAsHost)
			{
				InitializeSessionSeedIfNeeded();
				int num = ComputeSeedAndMaybeLoadSavePack(Plugin.ModConfig.KeepPackFor.Value);
				Plugin.Service.SetRandomSeed(num);
				_currentHostSeed = num;
				PosterSyncManager.SendSeed(num);
			}
			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 (Exception)
				{
				}
				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__33))]
		private static IEnumerator CreateCustomPostersAsync()
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <CreateCustomPostersAsync>d__33(0);
		}

		private static bool TryResolvePacksToUse(GameObject? posterPlane, out List<string> packsToUse)
		{
			packsToUse = new List<string>();
			List<string> list = Plugin.Service.PosterFolders.Where((string folder) => Plugin.ModConfig.IsPackEnabled(folder)).ToList();
			bool flag = Plugin.ModConfig.EnableNetworking.Value && !ShouldActAsHost && !string.IsNullOrEmpty(_selectedPack);
			if (list.Count == 0 && !flag)
			{
				Plugin.Log.LogWarning((object)"No enabled packs found");
				if ((Object)(object)posterPlane != (Object)null)
				{
					posterPlane.SetActive(true);
				}
				return false;
			}
			if (Plugin.ModConfig.RandomizerModeSetting.Value == PosterConfig.RandomizerMode.PerPack)
			{
				return TryResolvePerPackSelection(list, posterPlane, out packsToUse);
			}
			if (Plugin.ModConfig.EnableNetworking.Value && !ShouldActAsHost && !_clientSeedReceived)
			{
				Plugin.Log.LogInfo((object)"Client is waiting for host to send seed...");
				if ((Object)(object)posterPlane != (Object)null)
				{
					posterPlane.SetActive(true);
				}
				return false;
			}
			Plugin.Log.LogInfo((object)"PerPoster mode enabled.");
			packsToUse = list;
			return true;
		}

		private static bool TryResolvePerPackSelection(List<string> enabledPacks, GameObject? posterPlane, out List<string> packsToUse)
		{
			packsToUse = new List<string>();
			if (ShouldActAsHost)
			{
				SelectHostPack(enabledPacks);
				BroadcastSelectedPackIfNeeded();
			}
			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 != (Object)null)
				{
					posterPlane.SetActive(true);
				}
				return false;
			}
			Plugin.Log.LogInfo((object)("Using pack: " + PathUtils.GetDisplayPackName(_selectedPack)));
			packsToUse = new List<string> { _selectedPack };
			return true;
		}

		private static void SelectHostPack(List<string> enabledPacks)
		{
			PosterConfig.KeepFor value = Plugin.ModConfig.KeepPackFor.Value;
			if (value == PosterConfig.KeepFor.SaveSlot && string.IsNullOrEmpty(SavePersistenceManager.TryGetCurrentSaveId()))
			{
				_selectedPack = null;
			}
			if (value switch
			{
				PosterConfig.KeepFor.Lobby => true, 
				PosterConfig.KeepFor.Session => _selectedPack == null || !enabledPacks.Contains(_selectedPack), 
				PosterConfig.KeepFor.SaveSlot => _selectedPack == null || !enabledPacks.Contains(_selectedPack), 
				_ => true, 
			})
			{
				_selectedPack = PickFirstValidPack(enabledPacks);
				if (!string.IsNullOrEmpty(_selectedPack) && value == PosterConfig.KeepFor.SaveSlot)
				{
					PersistSelectionForSaveSlot(_selectedPack);
				}
			}
		}

		private static string? PickFirstValidPack(List<string> candidates)
		{
			List<string> list = new List<string>(candidates);
			while (list.Count > 0)
			{
				string text = PackSelector.SelectPackByChance(list);
				if (PackHasValidFiles(text))
				{
					return text;
				}
				list.Remove(text);
			}
			return null;
		}

		private static void PersistSelectionForSaveSlot(string selectedPack)
		{
			try
			{
				string text = SavePersistenceManager.TryGetCurrentSaveId();
				if (!string.IsNullOrEmpty(text))
				{
					SavePersistenceManager.SaveSelectedPack(text, selectedPack);
					Plugin.Log.LogInfo((object)("Saved selected pack for save '" + text + "'"));
				}
				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));
			}
		}

		private static void BroadcastSelectedPackIfNeeded()
		{
			if (!string.IsNullOrEmpty(_selectedPack) && Plugin.ModConfig.EnableNetworking.Value)
			{
				PosterSyncManager.SendPacket(_selectedPack);
			}
		}

		[IteratorStateMachine(typeof(<LoadContentFromPacks>d__40))]
		private static IEnumerator LoadContentFromPacks(List<string> packsToUse, Dictionary<string, List<(Texture2D texture, string filePath)>> allTextures, Dictionary<string, List<string>> allVideos)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadContentFromPacks>d__40(0)
			{
				packsToUse = packsToUse,
				allTextures = allTextures,
				allVideos = allVideos
			};
		}

		private static List<string> GatherValidFilesForPack(string pack)
		{
			string[] source = new string[4]
			{
				Path.Combine(pack, "posters"),
				Path.Combine(pack, "tips"),
				Path.Combine(pack, "CustomPosters", "posters"),
				Path.Combine(pack, "CustomPosters", "tips")
			};
			IEnumerable<string> enumerable = (from p in source.Where(Directory.Exists)
				select Path.GetFullPath(p).NormalizePath()).Distinct<string>(StringComparer.OrdinalIgnoreCase);
			List<string> list = new List<string>();
			foreach (string item in enumerable)
			{
				list.AddRange(from f in Directory.GetFiles(item)
					where f.IsValidPosterFile() && Plugin.ModConfig.IsFileEnabled(f)
					select Path.GetFullPath(f).NormalizePath());
			}
			return list.Distinct<string>(StringComparer.OrdinalIgnoreCase).ToList();
		}

		private static void RegisterVideo(string file, Dictionary<string, List<string>> allVideos)
		{
			string posterName = file.GetPosterName();
			if (!allVideos.ContainsKey(posterName))
			{
				allVideos[posterName] = new List<string>();
			}
			allVideos[posterName].Add(file);
			Plugin.Service.CacheVideo(file);
		}

		[IteratorStateMachine(typeof(<LoadTextureToDictionary>d__43))]
		private static IEnumerator LoadTextureToDictionary(string file, Dictionary<string, List<(Texture2D texture, string filePath)>> allTextures)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <LoadTextureToDictionary>d__43(0)
			{
				file = file,
				allTextures = allTextures
			};
		}

		private static Dictionary<string, (Texture2D? texture, string filePath, bool isVideo)> BuildPrioritizedContent(Dictionary<string, List<(Texture2D texture, string filePath)>> allTextures, Dictionary<string, List<string>> allVideos)
		{
			Dictionary<string, (Texture2D, string, bool)> dictionary = new Dictionary<string, (Texture2D, string, bool)>();
			IEnumerable<string> enumerable = allTextures.Keys.Union(allVideos.Keys);
			foreach (string item in enumerable)
			{
				List<(Texture2D, string, bool)> list = new List<(Texture2D, string, bool)>();
				if (allTextures.TryGetValue(item, out List<(Texture2D, string)> value))
				{
					list.AddRange(value.Select<(Texture2D, string), (Texture2D, string, bool)>(((Texture2D texture, string filePath) t) => (t.texture, t.filePath, false)));
				}
				if (allVideos.TryGetValue(item, out List<string> value2))
				{
					list.AddRange(((IEnumerable<string>)value2).Select((Func<string, (Texture2D, string, bool)>)((string v) => (null, v, true))));
				}
				if (list.Count != 0)
				{
					dictionary[item] = PackSelector.SelectContentByChance<(Texture2D, string, bool)>(list, ((Texture2D texture, string filePath, bool isVideo) item) => Plugin.ModConfig.GetFileChance(item.filePath), ((Texture2D texture, string filePath, bool isVideo) item) => Plugin.Service.GetFilePriority(item.filePath));
				}
			}
			return dictionary;
		}

		[IteratorStateMachine(typeof(<SpawnPostersFromLayout>d__45))]
		private static IEnumerator SpawnPostersFromLayout(PosterData[] posterData, GameObject postersParent, Dictionary<string, (Texture2D? texture, string filePath, bool isVideo)> prioritizedContent, Action<bool> onCompleted)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <SpawnPostersFromLayout>d__45(0)
			{
				posterData = posterData,
				postersParent = postersParent,
				prioritizedContent = prioritizedContent,
				onCompleted = onCompleted
			};
		}

		private static void ApplyPosterTransform(GameObject poster, PosterData data, Transform parent)
		{
			//IL_001f: Unknown result type (might be due to invalid IL or missing references)
			//IL_0030: Unknown result type (might be due to invalid IL or missing references)
			//IL_0035: Unknown result type (might be due to invalid IL or missing references)
			//IL_0046: Unknown result type (might be due to invalid IL or missing references)
			((Object)poster).name = data.Name;
			poster.transform.SetParent(parent);
			poster.transform.position = data.Position;
			poster.transform.rotation = Quaternion.Euler(data.Rotation);
			poster.transform.localScale = data.Scale;
		}

		private static bool TryAssignPosterContent(GameObject poster, string posterName, Dictionary<string, (Texture2D? texture, string filePath, bool isVideo)> prioritizedContent)
		{
			string key = posterName.ToLower();
			if (!prioritizedContent.TryGetValue(key, out (Texture2D, string, bool) value) || !Plugin.ModConfig.IsFileEnabled(value.Item2))
			{
				Plugin.Log.LogWarning((object)("No enabled texture found for " + posterName + ". Destroying the poster"));
				Object.Destroy((Object)(object)poster);
				return false;
			}
			PosterRenderer posterRenderer = poster.AddComponent<PosterRenderer>();
			MeshRenderer component = poster.GetComponent<MeshRenderer>();
			posterRenderer.Initialize(value.Item1, value.Item3 ? value.Item2 : null, (component != null) ? ((Renderer)component).material : null);
			CreatedPosters.Add(poster);
			return true;
		}

		private static void FinalizeRender(bool anyPosterLoaded, GameObject hangarShip, GameObject? posterPlane)
		{
			if (anyPosterLoaded)
			{
				if ((Object)(object)posterPlane != (Object)null)
				{
					Object.Destroy((Object)(object)posterPlane);
				}
				Transform obj = hangarShip.transform.Find("Plane");
				GameObject val = ((obj != null) ? ((Component)obj).gameObject : null);
				if ((Object)(object)val != (Object)null)
				{
					Object.Destroy((Object)(object)val);
				}
				Plugin.Log.LogInfo((object)"Posters created successfully!");
			}
			else if ((Object)(object)posterPlane != (Object)null)
			{
				posterPlane.SetActive(true);
				Plugin.Log.LogWarning((object)"Re-enabled vanilla Plane.001 poster due to no textures loaded");
			}
		}

		private static bool PackHasValidFiles(string pack)
		{
			try
			{
				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) => f.IsValidPosterFile()))
					{
						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__50))]
		private static IEnumerator DelayedUpdateMaterialsAsync(StartOfRound instance)
		{
			//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
			return new <DelayedUpdateMaterialsAsync>d__50(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));
			StartOfRound instance = StartOfRound.Instance;
			if ((Object)(object)instance != (Object)null && instance.inShipPhase)
			{
				if (_isUpdating)
				{
					_needsReUpdate = true;
				}
				else
				{
					((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()
		{
			DiscoverPosterPacks();
			LogDiscoveredPacks();
			InitializeBiggerShip();
			InitializeShipWindows();
			InitializeWiderShipMod();
			Initialize2StoryShipMod();
			SetRandomSeed(Environment.TickCount);
		}

		private void DiscoverPosterPacks()
		{
			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));
			}
		}

		private void LogDiscoveredPacks()
		{
			try
			{
				if (_posterFolders.Count != 0)
				{
					List<string> values = _posterFolders.Select((string pack) => $"{PathUtils.GetDisplayPackName(pack)}={CountValidFiles(pack)}").ToList();
					Plugin.Log.LogDebug((object)string.Format("Poster packs discovered: {0}; files per pack: {1}", _posterFolders.Count, string.Join(", ", values)));
				}
			}
			catch
			{
			}
		}

		private static int CountValidFiles(string pack)
		{
			try
			{
				int num = 0;
				string path = Path.Combine(pack, "posters");
				if (Directory.Exists(path))
				{
					num += Directory.GetFiles(path).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()));
				}
				string path2 = Path.Combine(pack, "tips");
				if (Directory.Exists(path2))
				{
					num += Directory.GetFiles(path2).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()));
				}
				return num + Directory.GetFiles(pack).Count((string f) => Constants.AllValidExtensions.Contains(Path.GetExtension(f).ToLowerInvariant()));
			}
			catch
			{
				return 0;
			}
		}

		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.4";
	}
}
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 (Exception)
			{
			}
			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.ResetSession();
			PosterManager.IsNewLobby = true;
		}
	}
	[HarmonyPatch(typeof(StartOfRound))]
	internal class StartOfRoundPatch
	{
		[HarmonyPostfix]
		[HarmonyPatch("Awake")]
		private static void OnAwakePatch()
		{
			PosterManager.OnSceneAwake();
		}

		[HarmonyPostfix]
		[HarmonyPatch("Start")]
		private static void OnRoundStartPatch(StartOfRound __instance)
		{
			PosterManager.OnRoundStart(__instance);
		}
	}
}
namespace CustomPosters.Networking
{
	internal static class PosterSyncManager
	{
		private static readonly LNetworkMessage<string> SyncPackMessage = LNetworkMessage<string>.Connect("CustomPosters_SyncPack", (Action<string, ulong>)null, (Action<string>)PosterManager.SetPackForClients, (Action<string, ulong>)null);

		private static readonly LNetworkMessage<int> SyncSeedMessage = LNetworkMessage<int>.Connect("CustomPosters_SyncSeed", (Action<int, ulong>)null, (Action<int>)PosterManager.SetSeedForClients, (Action<int, ulong>)null);

		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 SendSeed(int seed)
		{
			if (Plugin.ModConfig.EnableNetworking.Value && !((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsHost)
			{
				Plugin.Log.LogDebug((object)$"Sending seed to all clients - {seed}");
				SyncSeedMessage.SendClients(seed);
			}
		}

		public static void OnClientConnected(ulong clientId)
		{
			if (!Plugin.ModConfig.EnableNetworking.Value)
			{
				return;
			}
			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)
			{
				if (!string.IsNullOrEmpty(PosterManager.SelectedPack))
				{
					Plugin.Log.LogDebug((object)("New client joined, sending pack: " + PathUtils.GetPrettyPath(PosterManager.SelectedPack)));
					SyncPackMessage.SendClient(PosterManager.SelectedPack, clientId);
				}
				if (PosterManager.CurrentHostSeed != 0)
				{
					Plugin.Log.LogDebug((object)$"New client joined, sending seed - {PosterManager.CurrentHostSeed}");
					SyncSeedMessage.SendClient(PosterManager.CurrentHostSeed, 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 legacy = 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)
			{
				return GetTwoStoryLayout(legacy, isWiderShipModInstalled, isShipWindowsInstalled, isRightWindowEnabled, enableRightWindows, enableLeftWindows);
			}
			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();
		}

		private static PosterData[] GetTwoStoryLayout(bool legacy, bool widerShip, bool shipWindows, bool rightWindow, bool enableRightWindows, bool enableLeftWindows)
		{
			if (legacy && widerShip)
			{
				Plugin.Log.LogInfo((object)"Choosing layout: 2 Story Ship (Legacy) + WiderShip");
				return CustomPosters.Data.PosterLayouts.Legacy.TwoStoryShip_WiderShip.Get();
			}
			if (widerShip)
			{
				Plugin.Log.LogInfo((object)("Choosing layout: 2 Story Ship + WiderShip" + GetWiderShipDetail(shipWindows, rightWindow, enableLeftWindows)));
				return CustomPosters.Data.PosterLayouts.TwoStoryShip_WiderShip.Get();
			}
			Plugin.Log.LogInfo((object)("Choosing layout: 2 Story Ship" + GetTwoStorySuffix(shipWindows, enableRightWindows, enableLeftWindows)));
			return TwoStoryShip.Get();
		}

		private static string GetWiderShipDetail(bool shipWindows, bool rightWindow, bool enableLeftWindows)
		{
			if (shipWindows && rightWindow)
			{
				return " + ShipWindows";
			}
			if (shipWindows)
			{
				return " + ShipWindows (No right window)";
			}
			if (!enableLeftWindows)
			{
				return " (No left window)";
			}
			return "";
		}

		private static string GetTwoStorySuffix(bool shipWindows, bool enableRightWindows, bool enableLeftWindows)
		{
			if (shipWindows)
			{
				return " + ShipWindows";
			}
			if (!enableRightWindows && !enableLeftWindows)
			{
				return " (No both windows)";
			}
			if (enableRightWindows && enableLeftWindows)
			{
				return " (All windows)";
			}
			if (!enableRightWindows)
			{
				return " (No right window)";
			}
			return " (No left window)";
		}
	}
}
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