using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using SeasonalContentUnlocked.Config; using SeasonalContentUnlocked.Definitions; using SeasonalContentUnlocked.Managers; using SeasonalContentUnlocked.Registry; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyVersion("0.0.0.0")] namespace SeasonalContentUnlocked { [BepInPlugin("NoxiousVex.SeasonalContentUnlocked", "Seasonal Content Unlocked", "1.0.0")] public class Plugin : BaseUnityPlugin { private const string ModGUID = "NoxiousVex.SeasonalContentUnlocked"; private const string ModName = "Seasonal Content Unlocked"; private const string ModAuthor = "Noxious Vex"; private const string ModVersion = "1.0.0"; private void Awake() { LogManager.Initialize(((BaseUnityPlugin)this).Logger); ConfigManager.Initialize(((BaseUnityPlugin)this).Config); LogManager.SetLogLevel(ConfigManager.Current.Advanced.Logging); LogManager.LogLoad("========================================"); LogManager.LogLoad("Seasonal Content Unlocked: Version 1.0.0 by Noxious Vex has successfully loaded."); LogManager.LogLoad("========================================"); ((MonoBehaviour)this).StartCoroutine(InitializeRestoration()); } private IEnumerator InitializeRestoration() { yield return (object)new WaitUntil((Func)(() => (Object)(object)ZNetScene.instance != (Object)null)); PieceRegistry.Initialize(); PieceManager.Initialize(); ItemRegistry.Initialize(); ItemManager.Initialize(); } } } namespace SeasonalContentUnlocked.Registry { public static class PieceRegistry { private static readonly List Pieces = new List(); public static void Initialize() { Pieces.Clear(); RegisterPieces(); } private static void RegisterPieces() { RegisterPiece(new PieceDefinition { PrefabName = "piece_maypole", DisplayName = "Maypole", RestoreEnabled = ConfigManager.Current.Midsummer.EnableMaypole }); RegisterPiece(new PieceDefinition { PrefabName = "piece_jackoturnip", DisplayName = "Jack-o-Turnip", RestoreEnabled = ConfigManager.Current.Halloween.EnableJackOTurnip }); RegisterPiece(new PieceDefinition { PrefabName = "piece_xmastree", DisplayName = "Christmas Tree", RestoreEnabled = ConfigManager.Current.Yule.EnableXmasTree }); RegisterPiece(new PieceDefinition { PrefabName = "piece_xmascrown", DisplayName = "Christmas Crown", RestoreEnabled = ConfigManager.Current.Yule.EnableXmasCrown }); RegisterPiece(new PieceDefinition { PrefabName = "piece_xmasgarland", DisplayName = "Christmas Garland", RestoreEnabled = ConfigManager.Current.Yule.EnableXmasGarland }); RegisterPiece(new PieceDefinition { PrefabName = "piece_mistletoe", DisplayName = "Mistletoe", RestoreEnabled = ConfigManager.Current.Yule.EnableMistletoe }); RegisterPiece(new PieceDefinition { PrefabName = "piece_gift1", DisplayName = "Small Christmas Gift", RestoreEnabled = ConfigManager.Current.Yule.EnableGiftSmall }); RegisterPiece(new PieceDefinition { PrefabName = "piece_gift2", DisplayName = "Medium Christmas Gift", RestoreEnabled = ConfigManager.Current.Yule.EnableGiftMedium }); RegisterPiece(new PieceDefinition { PrefabName = "piece_gift3", DisplayName = "Large Christmas Gift", RestoreEnabled = ConfigManager.Current.Yule.EnableGiftLarge }); } private static void RegisterPiece(PieceDefinition definition) { Pieces.Add(definition); } public static List GetPieces() { return Pieces; } } public static class ItemRegistry { private static readonly List Recipes = new List(); public static void Initialize() { Recipes.Clear(); RegisterRecipes(); } private static void RegisterRecipes() { RegisterRecipe(new ItemDefinition { ItemName = "HelmetMidsummerCrown", DisplayName = "Midsummer Crown", RestoreEnabled = ConfigManager.Current.Midsummer.EnableMidsummerCrown }); RegisterRecipe(new ItemDefinition { ItemName = "HelmetPointyHat", DisplayName = "Pointy Hat", RestoreEnabled = ConfigManager.Current.Halloween.EnablePointyHat }); } private static void RegisterRecipe(ItemDefinition definition) { Recipes.Add(definition); } public static List GetRecipes() { return Recipes; } } } namespace SeasonalContentUnlocked.Managers { public static class ConfigManager { public static ConfigLayout Current { get; private set; } = new ConfigLayout(); public static void Initialize(ConfigFile config) { Current.ConfigPath = config.ConfigFilePath; Current.Advanced.EnableExperimentalFeatures = config.Bind("Advanced Features", "Enable Experimental Features", false, "Enables experimental features that are not considered stable.").Value; Current.Advanced.Logging = config.Bind("Advanced Features", "Logging", ConfigLogOptions.Standard, "Console Logging verbosity level.").Value; Current.Yule.EnableXmasCrown = config.Bind("Yule Seasonal Objects", "Enable Christmas Crown", true, "Restores the Christmas Crown Prefab as a permanently available build piece.").Value; Current.Yule.EnableXmasGarland = config.Bind("Yule Seasonal Objects", "Enable Christmas Garland", true, "Restores the Christmas Garland Prefab as a permanently available build piece.").Value; Current.Yule.EnableMistletoe = config.Bind("Yule Seasonal Objects", "Enable Mistletoe", true, "Restores the Mistletoe Prefab as a permanently available build piece.").Value; Current.Yule.EnableGiftSmall = config.Bind("Yule Seasonal Objects", "Enable Small Gift", true, "Restores the small Christmas Gift Prefab as a permanently available build piece.").Value; Current.Yule.EnableGiftMedium = config.Bind("Yule Seasonal Objects", "Enable Medium Gift", true, "Restores the medium Christmas Gift Prefab as a permanently available build piece.").Value; Current.Yule.EnableGiftLarge = config.Bind("Yule Seasonal Objects", "Enable Large Gift", true, "Restores the large Christmas Gift Prefab as a permanently available build piece.").Value; Current.Yule.EnableXmasTree = config.Bind("Yule Seasonal Objects", "Enable Christmas Tree", true, "Restores the Christmas Tree Prefab as a permanently available build piece.").Value; Current.Halloween.EnableJackOTurnip = config.Bind("Halloween Seasonal Objects", "Enable Jack-O-Turnip", true, "Restores the Jack-O-Turnip Prefab as a permanently available build piece.").Value; Current.Midsummer.EnableMaypole = config.Bind("Midsummer Seasonal Objects", "Enable Maypole", true, "Restores the Maypole Prefab as a permanently available build piece.").Value; } } public static class LogManager { private static ManualLogSource Logger; private static ConfigLogOptions CurrentLevel = ConfigLogOptions.Standard; public static void Initialize(ManualLogSource logger) { Logger = logger; } public static void SetLogLevel(ConfigLogOptions level) { CurrentLevel = level; } public static void LogLoad(string message) { Logger.LogInfo((object)("[LOAD] " + message)); } public static void LogInfo(string message) { if (ShouldLog(ConfigLogOptions.Standard)) { Logger.LogInfo((object)("[INFO] " + message)); } } public static void LogWarn(string message) { if (ShouldLog(ConfigLogOptions.Warnings)) { Logger.LogWarning((object)("[WARNING] " + message)); } } public static void LogError(string message) { Logger.LogError((object)("[ERROR] " + message)); } public static void LogDebug(string message) { if (ShouldLog(ConfigLogOptions.Debug)) { Logger.LogInfo((object)("[DEBUG] " + message)); } } private static bool ShouldLog(ConfigLogOptions messageLevel) { switch (CurrentLevel) { case ConfigLogOptions.Minimal: return messageLevel == ConfigLogOptions.Minimal; case ConfigLogOptions.Warnings: if (messageLevel != ConfigLogOptions.Minimal) { return messageLevel == ConfigLogOptions.Warnings; } return true; case ConfigLogOptions.Standard: return messageLevel != ConfigLogOptions.Debug; case ConfigLogOptions.Debug: return true; default: return false; } } } public static class PieceManager { private static FieldInfo EnabledField; private static int PiecesAttempted; private static int PiecesRestored; private static int PiecesAlreadyEnabled; private static int PiecesFailed; public static void Initialize() { ResetStatistics(); RestorePieces(); LogSummary(); } private static void ResetStatistics() { PiecesAttempted = 0; PiecesRestored = 0; PiecesAlreadyEnabled = 0; PiecesFailed = 0; } private static void RestorePieces() { if ((Object)(object)ZNetScene.instance == (Object)null) { LogManager.LogError("ZNetScene instance unavailable. Cannot restore pieces."); return; } foreach (PieceDefinition piece in PieceRegistry.GetPieces()) { if (piece.RestoreEnabled) { PiecesAttempted++; RestorePiece(piece); } } } private static void RestorePiece(PieceDefinition definition) { GameObject prefab = ZNetScene.instance.GetPrefab(definition.PrefabName); if ((Object)(object)prefab == (Object)null) { PiecesFailed++; LogManager.LogWarn("Could not find prefab: " + definition.PrefabName); return; } Piece component = prefab.GetComponent(); if ((Object)(object)component == (Object)null) { PiecesFailed++; LogManager.LogWarn("Prefab " + definition.PrefabName + " has no Piece component."); return; } if (EnabledField == null) { EnabledField = ((object)component).GetType().GetField("m_enabled", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); } if (EnabledField == null) { PiecesFailed++; LogManager.LogError("Could not locate Piece.m_enabled field."); return; } if ((bool)EnabledField.GetValue(component)) { PiecesAlreadyEnabled++; LogManager.LogDebug("Piece already enabled: " + definition.DisplayName); return; } EnabledField.SetValue(component, true); PiecesRestored++; LogManager.LogDebug("Restored piece: " + definition.DisplayName + " (" + definition.PrefabName + ")"); } private static void LogSummary() { LogManager.LogDebug("========================================"); LogManager.LogDebug("Piece Restoration Summary:"); LogManager.LogDebug($"Attempted: {PiecesAttempted}"); LogManager.LogDebug($"Restored: {PiecesRestored}"); LogManager.LogDebug($"Already Enabled: {PiecesAlreadyEnabled}"); LogManager.LogDebug($"Failed: {PiecesFailed}"); LogManager.LogDebug("========================================"); } } public static class ItemManager { private static int RecipesAttempted; private static int RecipesRestored; private static int RecipesAlreadyEnabled; private static int RecipesFailed; public static void Initialize() { ResetStatistics(); RestoreItems(); LogSummary(); } private static void ResetStatistics() { RecipesAttempted = 0; RecipesRestored = 0; RecipesAlreadyEnabled = 0; RecipesFailed = 0; } private static void RestoreItems() { if ((Object)(object)ObjectDB.instance == (Object)null) { LogManager.LogError("ObjectDB instance unavailable. Cannot restore items."); return; } foreach (ItemDefinition recipe in ItemRegistry.GetRecipes()) { if (recipe.RestoreEnabled) { RecipesAttempted++; RestoreItem(recipe); } } } private static void RestoreItem(ItemDefinition definition) { foreach (Recipe recipe in ObjectDB.instance.m_recipes) { if (!((Object)(object)recipe == (Object)null) && !((Object)(object)recipe.m_item == (Object)null) && !(((Object)recipe.m_item).name != definition.ItemName)) { if (recipe.m_enabled) { RecipesAlreadyEnabled++; LogManager.LogDebug("Recipe already enabled: " + definition.DisplayName); return; } recipe.m_enabled = true; RecipesRestored++; LogManager.LogDebug("Restored recipe: " + definition.DisplayName + " (" + definition.ItemName + ")"); return; } } RecipesFailed++; LogManager.LogWarn("Could not find recipe: " + definition.ItemName); } private static void LogSummary() { LogManager.LogDebug("========================================"); LogManager.LogDebug("Recipe Restoration Summary:"); LogManager.LogDebug($"Attempted: {RecipesAttempted}"); LogManager.LogDebug($"Restored: {RecipesRestored}"); LogManager.LogDebug($"Already Enabled: {RecipesAlreadyEnabled}"); LogManager.LogDebug($"Failed: {RecipesFailed}"); LogManager.LogDebug("========================================"); } } } namespace SeasonalContentUnlocked.Definitions { public enum ConfigLogOptions { Minimal, Warnings, Standard, Debug } public enum LogLevel { Load, Info, Warn, Error, Debug } public class PieceDefinition { public bool RestoreEnabled { get; set; } = true; public string PrefabName { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; } public class ItemDefinition { public bool RestoreEnabled { get; set; } = true; public string ItemName { get; set; } = string.Empty; public string DisplayName { get; set; } = string.Empty; } } namespace SeasonalContentUnlocked.Config { public class ConfigAdvancedOptions { public bool EnableExperimentalFeatures { get; set; } public ConfigLogOptions Logging { get; set; } = ConfigLogOptions.Standard; } public class ConfigHalloweenOptions { public bool EnableJackOTurnip { get; set; } = true; public bool EnablePointyHat { get; set; } = true; } public class ConfigLayout { public string ConfigPath { get; set; } = string.Empty; public ConfigAdvancedOptions Advanced { get; set; } = new ConfigAdvancedOptions(); public ConfigYuleOptions Yule { get; set; } = new ConfigYuleOptions(); public ConfigHalloweenOptions Halloween { get; set; } = new ConfigHalloweenOptions(); public ConfigMidsummerOptions Midsummer { get; set; } = new ConfigMidsummerOptions(); } public class ConfigMidsummerOptions { public bool EnableMaypole { get; set; } = true; public bool EnableMidsummerCrown { get; set; } = true; } public class ConfigYuleOptions { public bool EnableXmasTree { get; set; } = true; public bool EnableXmasCrown { get; set; } = true; public bool EnableXmasGarland { get; set; } = true; public bool EnableMistletoe { get; set; } = true; public bool EnableGiftSmall { get; set; } = true; public bool EnableGiftMedium { get; set; } = true; public bool EnableGiftLarge { get; set; } = true; } }