Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ConfigurableMoonPreview v1.0.0
BepInEx/plugins/ConfigurableMoonPreview/ConfigurableMoonPreview.dll
Decompiled 13 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using UnityEngine; using UnityEngine.Video; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("ConfigurableMoonPreview")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("ConfigurableMoonPreview")] [assembly: AssemblyTitle("ConfigurableMoonPreview")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace ConfigurableMoonPreview { internal sealed class Manifest { internal const int SupportedFormatVersion = 1; [JsonProperty("formatVersion")] public int FormatVersion = 1; [JsonProperty("packName")] public string PackName; [JsonProperty("author")] public string Author; [JsonProperty("entries")] public List<ManifestEntry> Entries; } internal sealed class ManifestEntry { [JsonProperty("scene")] public string Scene; [JsonProperty("planet")] public string Planet; [JsonProperty("description")] public string Description; [JsonProperty("video")] public string Video; [JsonProperty("image")] public string Image; internal bool HasSelector => !string.IsNullOrEmpty(Scene) || !string.IsNullOrEmpty(Planet); internal bool HasReel => !string.IsNullOrEmpty(Video); internal bool HasPayload => Description != null || HasReel; internal string DescribeSelector => (!string.IsNullOrEmpty(Scene)) ? ("scene '" + Scene + "'") : ((!string.IsNullOrEmpty(Planet)) ? ("planet '" + Planet + "'") : "<no selector>"); } internal static class ManifestLoader { private const string Suffix = "*.moonpreview.json"; private const string BundledManifest = "vanilla.moonpreview.json"; private static int bundledEntries; internal static ReelStore LoadAll(string pluginDirectory) { bundledEntries = 0; ReelStore reelStore = new ReelStore(); string skip = LoadBundled(reelStore, pluginDirectory); (int, int) tuple = LoadFrom(reelStore, Paths.PluginPath, "mod", skip); (int, int) tuple2 = LoadFrom(reelStore, Paths.ConfigPath, "user override", null); Plugin.Log.LogInfo((object)(string.Format("{0} moon entr{1} loaded: ", reelStore.Count, (reelStore.Count == 1) ? "y" : "ies") + $"{bundledEntries} bundled, {tuple.Item2} from {tuple.Item1} mod manifest(s), " + $"{tuple2.Item2} from {tuple2.Item1} user override(s).")); return reelStore; } private static string LoadBundled(ReelStore store, string pluginDirectory) { if (string.IsNullOrEmpty(pluginDirectory)) { return null; } string text = Path.Combine(pluginDirectory, "vanilla.moonpreview.json"); if (!File.Exists(text)) { Plugin.Log.LogWarning((object)("'vanilla.moonpreview.json' is missing from " + pluginDirectory + ". The vanilla moons keep the base game's descriptions. Reinstall if that was not deliberate.")); return text; } bundledEntries = Math.Max(Load(store, text, pluginDirectory), 0); return text; } private static (int manifests, int entries) LoadFrom(ReelStore store, string root, string label, string skip) { if (string.IsNullOrEmpty(root) || !Directory.Exists(root)) { return (manifests: 0, entries: 0); } string[] files; try { files = Directory.GetFiles(root, "*.moonpreview.json", SearchOption.AllDirectories); } catch (Exception arg) { Plugin.Log.LogError((object)$"Scanning '{root}' threw. {arg}"); return (manifests: 0, entries: 0); } if (files.Length == 0) { return (manifests: 0, entries: 0); } Array.Sort(files, (IComparer<string>?)StringComparer.OrdinalIgnoreCase); int num = 0; int num2 = 0; string[] array = files; foreach (string text in array) { if (skip == null || !string.Equals(text, skip, StringComparison.OrdinalIgnoreCase)) { int num3 = Load(store, text, root); if (num3 >= 0) { num++; num2 += num3; } } } return (manifests: num, entries: num2); } private static int Load(ReelStore store, string path, string root) { string text = Shorten(path, root); Manifest manifest; try { manifest = JsonConvert.DeserializeObject<Manifest>(File.ReadAllText(path)); } catch (Exception ex) { Plugin.Log.LogError((object)("'" + text + "' is not valid JSON and was skipped. " + ex.Message)); return -1; } if (manifest == null) { Plugin.Log.LogWarning((object)("'" + text + "' is empty and was skipped.")); return -1; } if (manifest.FormatVersion > 1) { Plugin.Log.LogWarning((object)($"'{text}' declares formatVersion {manifest.FormatVersion}; this build understands " + $"up to {1}. Update Configurable Moon Preview. Skipped rather " + "than half-applied.")); return -1; } if (manifest.Entries == null || manifest.Entries.Count == 0) { Plugin.Log.LogWarning((object)("'" + text + "' has no entries.")); return -1; } string dir = Path.GetDirectoryName(path) ?? string.Empty; string text2 = ((!string.IsNullOrEmpty(manifest.PackName)) ? manifest.PackName : text); if (!string.IsNullOrEmpty(manifest.Author)) { text2 = text2 + " by " + manifest.Author; } int num = 0; for (int i = 0; i < manifest.Entries.Count; i++) { if (AddEntry(store, manifest.Entries[i], i, dir, text2, text)) { num++; } } return num; } private static bool AddEntry(ReelStore store, ManifestEntry entry, int index, string dir, string source, string name) { string text = $"'{name}' entry {index}"; if (entry == null) { Plugin.Log.LogWarning((object)(text + " is null; skipped.")); return false; } if (!entry.HasSelector) { Plugin.Log.LogWarning((object)(text + " names no moon. Give it a \"scene\" or a \"planet\". Skipped — an entry matching everything would repaint every moon in the game.")); return false; } if (!string.IsNullOrEmpty(entry.Image)) { Plugin.Log.LogWarning((object)(text + " sets \"image\", which is not supported — reels are video files. Convert it to an mp4 and use \"video\" instead.")); } if (!entry.HasPayload) { Plugin.Log.LogWarning((object)(text + " (" + entry.DescribeSelector + ") asks for nothing: no \"description\" and no \"video\". Skipped.")); return false; } MoonReel moonReel = new MoonReel { Description = entry.Description }; if (entry.Description != null) { moonReel.DescriptionSource = source; } if (!string.IsNullOrEmpty(entry.Video)) { moonReel.VideoPath = Resolve(dir, entry.Video); moonReel.ReelSource = source; if (!File.Exists(moonReel.VideoPath)) { Plugin.Log.LogWarning((object)(text + " points at '" + entry.Video + "', which does not exist (" + moonReel.VideoPath + "). The moon keeps its own reel.")); moonReel.VideoPath = null; moonReel.ReelSource = null; if (moonReel.Description == null) { return false; } } } store.Add(entry.Scene, entry.Planet, moonReel); return true; } private static string Resolve(string dir, string relative) { return Path.IsPathRooted(relative) ? relative : Path.Combine(dir, relative); } private static string Shorten(string path, string root) { if (!string.IsNullOrEmpty(root) && path.StartsWith(root, StringComparison.OrdinalIgnoreCase)) { return path.Substring(root.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); } return Path.GetFileName(path); } } internal static class Monitor { private static VideoAudioOutputMode? originalAudioMode; internal static void ApplyDescriptions() { SelectableLevel[] array = StartOfRound.Instance?.levels; if (array == null) { return; } int num = 0; SelectableLevel[] array2 = array; foreach (SelectableLevel level in array2) { if (ApplyDescription(level)) { num++; } } Plugin.Log.LogInfo((object)$"Applied {num} description(s) across {array.Length} moon(s)."); } internal static bool ApplyDescription(SelectableLevel level) { if ((Object)(object)level == (Object)null) { return false; } MoonReel moonReel = Plugin.Store.Lookup(level.sceneName, level.PlanetName); if (moonReel?.Description == null) { return false; } level.LevelDescription = moonReel.Description; return true; } internal static void Refresh(StartOfRound start) { if ((Object)(object)start == (Object)null) { return; } VideoPlayer screenLevelVideoReel = start.screenLevelVideoReel; SelectableLevel currentLevel = start.currentLevel; if ((Object)(object)screenLevelVideoReel == (Object)null || (Object)(object)currentLevel == (Object)null) { return; } try { MoonReel moonReel = Plugin.Store.Lookup(currentLevel.sceneName, currentLevel.PlanetName); if (start.isChallengeFile || moonReel?.VideoPath == null) { RestoreClipMode(start, screenLevelVideoReel, currentLevel); } else { Play(screenLevelVideoReel, moonReel.VideoPath); } } catch (Exception arg) { Plugin.Log.LogError((object)$"Updating the monitor for {currentLevel.PlanetName} threw. {arg}"); } } private static void Play(VideoPlayer player, string path) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_003d: Unknown result type (might be due to invalid IL or missing references) if ((int)player.source != 1 || !string.Equals(player.url, path, StringComparison.Ordinal)) { player.Stop(); if (!originalAudioMode.HasValue) { originalAudioMode = player.audioOutputMode; } player.audioOutputMode = (VideoAudioOutputMode)0; player.source = (VideoSource)1; player.clip = null; player.url = path; player.isLooping = true; } ((Behaviour)player).enabled = true; ((Component)player).gameObject.SetActive(true); player.Play(); } private static void RestoreClipMode(StartOfRound start, VideoPlayer player, SelectableLevel level) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 //IL_0052: Unknown result type (might be due to invalid IL or missing references) if ((int)player.source == 1) { player.Stop(); player.source = (VideoSource)0; player.url = string.Empty; player.clip = level.videoReel; if (originalAudioMode.HasValue) { player.audioOutputMode = originalAudioMode.Value; } bool flag = (((Behaviour)player).enabled = (Object)(object)level.videoReel != (Object)null && !start.isChallengeFile); ((Component)player).gameObject.SetActive(flag); if (flag) { player.Play(); } } } } [HarmonyPatch(typeof(StartOfRound))] internal static class Patches { [HarmonyPostfix] [HarmonyPatch("Start")] [HarmonyPriority(200)] private static void Start_Postfix() { try { Monitor.ApplyDescriptions(); } catch (Exception arg) { Plugin.Log.LogError((object)$"Applying descriptions at StartOfRound.Start threw. {arg}"); } } [HarmonyPrefix] [HarmonyPatch("SetMapScreenInfoToCurrentLevel")] private static void SetMapScreenInfoToCurrentLevel_Prefix(StartOfRound __instance) { try { Monitor.ApplyDescription(__instance.currentLevel); } catch (Exception arg) { Plugin.Log.LogError((object)$"Applying a description threw; the screen keeps vanilla text. {arg}"); } } [HarmonyPostfix] [HarmonyPatch("SetMapScreenInfoToCurrentLevel")] private static void SetMapScreenInfoToCurrentLevel_Postfix(StartOfRound __instance) { Monitor.Refresh(__instance); } [HarmonyPostfix] [HarmonyPatch("SwitchMapMonitorPurpose")] private static void SwitchMapMonitorPurpose_Postfix(StartOfRound __instance, bool displayInfo) { if (displayInfo) { Monitor.Refresh(__instance); } } } [BepInPlugin("com.luth.configurablemoonpreview", "ConfigurableMoonPreview", "1.0.0")] [BepInProcess("Lethal Company.exe")] public class Plugin : BaseUnityPlugin { public const string Guid = "com.luth.configurablemoonpreview"; public const string Name = "ConfigurableMoonPreview"; public const string Version = "1.0.0"; internal static ManualLogSource Log { get; private set; } internal static ReelStore Store { get; private set; } = new ReelStore(); private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; string pluginDirectory = Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location) ?? string.Empty; Store = ManifestLoader.LoadAll(pluginDirectory); try { new Harmony("com.luth.configurablemoonpreview").PatchAll(typeof(Plugin).Assembly); } catch (Exception arg) { Log.LogError((object)$"Harmony patching failed; Configurable Moon Preview is inert this session. {arg}"); return; } Log.LogInfo((object)"ConfigurableMoonPreview 1.0.0 loaded."); } } internal sealed class MoonReel { internal string Description; internal string VideoPath; internal string DescriptionSource; internal string ReelSource; internal bool HasReel => VideoPath != null; internal MoonReel Clone() { return new MoonReel { Description = Description, VideoPath = VideoPath, DescriptionSource = DescriptionSource, ReelSource = ReelSource }; } internal void Overlay(MoonReel other) { if (other != null) { if (other.Description != null) { Description = other.Description; DescriptionSource = other.DescriptionSource; } if (other.HasReel) { VideoPath = other.VideoPath; ReelSource = other.ReelSource; } } } } internal sealed class ReelStore { private readonly Dictionary<string, MoonReel> byScene = new Dictionary<string, MoonReel>(StringComparer.OrdinalIgnoreCase); private readonly Dictionary<string, MoonReel> byPlanet = new Dictionary<string, MoonReel>(StringComparer.OrdinalIgnoreCase); internal int Count => byScene.Count + byPlanet.Count; internal void Add(string scene, string planet, MoonReel reel) { if (reel != null) { if (!string.IsNullOrEmpty(scene)) { Merge(byScene, scene, reel); } if (!string.IsNullOrEmpty(planet)) { Merge(byPlanet, Numberless(planet), reel); } } } private static void Merge(Dictionary<string, MoonReel> target, string key, MoonReel reel) { if (target.TryGetValue(key, out var value)) { value.Overlay(reel); } else { target[key] = reel.Clone(); } } internal MoonReel Lookup(string sceneName, string planetName) { MoonReel moonReel = null; if (!string.IsNullOrEmpty(planetName) && byPlanet.TryGetValue(Numberless(planetName), out var value)) { moonReel = value.Clone(); } if (!string.IsNullOrEmpty(sceneName) && byScene.TryGetValue(sceneName, out var value2)) { if (moonReel == null) { moonReel = value2.Clone(); } else { moonReel.Overlay(value2); } } return moonReel; } internal static string Numberless(string planetName) { if (string.IsNullOrEmpty(planetName)) { return string.Empty; } int i; for (i = 0; i < planetName.Length && char.IsDigit(planetName[i]); i++) { } for (; i < planetName.Length && planetName[i] == ' '; i++) { } return (i >= planetName.Length) ? planetName.Trim() : planetName.Substring(i).Trim(); } } }