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 DataManager v1.2.2
Silksong.DataManager.dll
Decompiled 2 months agousing System; using System.Collections.Generic; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.IO; using System.Linq; using System.Reflection; using System.Resources; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using Newtonsoft.Json; using Silksong.DataManager.Data; using Silksong.DataManager.Json; using TeamCherry.Localization; using UnityEngine; using UnityEngine.UI; [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("Silksong.DataManager")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("DataManager is a Silksong mod that saves and loads data - global as well as save slot-specific - on behalf of other mods.")] [assembly: AssemblyFileVersion("1.2.2.0")] [assembly: AssemblyInformationalVersion("1.2.2+e50b69f68ac35635aad8baa693a22fba0cf15f8b")] [assembly: AssemblyProduct("Silksong.DataManager")] [assembly: AssemblyTitle("DataManager")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/silksong-modding/Silksong.DataManager")] [assembly: NeutralResourcesLanguage("en")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.2.2.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace Silksong.DataManager { [BepInDependency(/*Could not decode attribute arguments.*/)] [BepInPlugin("org.silksong-modding.datamanager", "DataManager", "1.2.2")] public class DataManagerPlugin : BaseUnityPlugin, IOnceSaveDataMod<DMOnceSaveData>, IRawOnceSaveDataMod { internal Dictionary<string, ManagedMod> ManagedMods = new Dictionary<string, ManagedMod>(); public const string Id = "org.silksong-modding.datamanager"; internal static DataManagerPlugin Instance { get; private set; } internal static ManualLogSource InstanceLogger => ((BaseUnityPlugin)Instance).Logger; internal ManagedMod ManagedSelf => ManagedMods[((BaseUnityPlugin)this).Info.Metadata.GUID]; internal DMOnceSaveData? OnceSaveData { get; set; } DMOnceSaveData? IOnceSaveDataMod<DMOnceSaveData>.OnceSaveData { get { return OnceSaveData; } set { OnceSaveData = value; } } public static string Name => "DataManager"; public static string Version => "1.2.2"; private void Awake() { //IL_000b: Unknown result type (might be due to invalid IL or missing references) Instance = this; new Harmony("org.silksong-modding.datamanager").PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Mod Loaded"); } private void Start() { foreach (KeyValuePair<string, PluginInfo> pluginInfo in Chainloader.PluginInfos) { pluginInfo.Deconstruct(out var key, out var value); string key2 = key; PluginInfo obj = value; BaseUnityPlugin val = ((obj != null) ? obj.Instance : null); if (val != null && ManagedMod.TryCreate(val, out ManagedMod instance)) { instance.LoadProfileData(); instance.LoadGlobalData(); ManagedMods.Add(key2, instance); } } } internal static void ClearModdedSaveSlot(int saveSlot) { string path = DataPaths.SaveSlotDir(saveSlot); try { Directory.Delete(path, recursive: true); InstanceLogger.LogInfo((object)$"Cleared modded save slot for slot {saveSlot}"); } catch (DirectoryNotFoundException) { InstanceLogger.LogInfo((object)$"No modded save slot to clear for slot {saveSlot}"); } catch (Exception arg) { InstanceLogger.LogError((object)$"Error clearing modded save slot for slot {saveSlot}: {arg}"); } } internal static LocalisedString SetSaveIncompatibleText(SaveSlotButton button, LocalisedString s) { //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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) AutoLocalizeTextUI component = ((Component)((Component)button.saveIncompatibleText).gameObject.transform.Find("Small Desc")).gameObject.GetComponent<AutoLocalizeTextUI>(); LocalisedString text = component.Text; component.Text = s; return text; } internal List<string> MissingMods(int saveSlot) { try { ManagedSelf.LoadOnceSaveData(saveSlot); } catch (IOException) { return new List<string>(); } return (OnceSaveData?.RequiredModGuids ?? new List<string>()).Where((string guid) => !ManagedMods.ContainsKey(guid)).ToList(); } } public static class DataPaths { public static string ProfileDataDir => Paths.ConfigPath; public static string GlobalDataDir => ModdedDir("Global"); private static string ModdedDir(string subdir) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return Path.Combine(((DesktopPlatform)Platform.Current).saveDirPath, "Modded", subdir); } internal static string SaveSlotDir(int saveSlot) { return ModdedDir($"user{saveSlot}"); } public static string SaveDataDir(int saveSlot) { return Path.Combine(SaveSlotDir(saveSlot), "SaveData"); } public static string OnceSaveDataDir(int saveSlot) { return Path.Combine(SaveSlotDir(saveSlot), "OncePerSave"); } } [HarmonyPatch(typeof(GameManager), "OnApplicationQuit")] internal static class OnQuitGameHook { private static void Postfix() { Directory.CreateDirectory(DataPaths.ProfileDataDir); Directory.CreateDirectory(DataPaths.GlobalDataDir); foreach (ManagedMod value in DataManagerPlugin.Instance.ManagedMods.Values) { value.SaveProfileData(); value.SaveGlobalData(); } } } [HarmonyPatch(typeof(GameManager), "SetLoadedGameData", new Type[] { typeof(SaveGameData), typeof(int) })] internal static class SaveDataLoadHook { private static void Postfix(int saveSlot) { Dictionary<string, ManagedMod>.ValueCollection values = DataManagerPlugin.Instance.ManagedMods.Values; if (saveSlot == 0) { return; } foreach (ManagedMod item in values) { item.LoadOnceSaveData(saveSlot); item.LoadSaveData(saveSlot); } } } [HarmonyPatch(typeof(GameManager), "SaveGame", new Type[] { typeof(int), typeof(Action<bool>), typeof(bool), typeof(AutoSaveName) })] [HarmonyPriority(2)] internal static class SaveDataSaveHook { private static void Prefix(int saveSlot, ref Action<bool> ogCallback, bool __runOriginal) { if (!__runOriginal || saveSlot == 0) { return; } Action<bool> ogCallbackCopy = ogCallback; ogCallback = delegate(bool didSave) { ogCallbackCopy?.Invoke(didSave); if (!didSave) { return; } Directory.CreateDirectory(DataPaths.SaveDataDir(saveSlot)); foreach (ManagedMod value in DataManagerPlugin.Instance.ManagedMods.Values) { value.SaveSaveData(saveSlot); } }; } } [HarmonyPatch(typeof(GameManager), "StartNewGame")] internal static class OnceSetupHook { private static void Postfix(GameManager __instance) { int profileID = __instance.profileID; if (profileID == 0) { return; } Dictionary<string, ManagedMod>.ValueCollection values = DataManagerPlugin.Instance.ManagedMods.Values; string path = DataPaths.OnceSaveDataDir(profileID); DataManagerPlugin.ClearModdedSaveSlot(profileID); Directory.CreateDirectory(path); List<string> requiredModGuids = (from x in values where x.IsRequired select x.Guid).ToList(); DataManagerPlugin.Instance.OnceSaveData = new DMOnceSaveData { RequiredModGuids = requiredModGuids }; foreach (ManagedMod item in values) { item.SaveOnceSaveData(profileID); } } } [HarmonyPatch(typeof(GameManager), "ClearSaveFile")] internal static class SaveDataClearHook { private static void Postfix(int saveSlot) { if (saveSlot != 0) { DataManagerPlugin.ClearModdedSaveSlot(saveSlot); } } } [HarmonyPatch(typeof(SaveSlotButton), "ProcessSaveStats")] internal static class ValidationHook { private static LocalisedString? vanillaSaveIncompatibleText; private static bool Prefix(SaveSlotButton __instance, ref bool __result, bool doAnimate, string errorInfo) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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) int saveSlotIndex = __instance.SaveSlotIndex; List<string> list = DataManagerPlugin.Instance.MissingMods(saveSlotIndex); if (list.Count == 0) { LocalisedString? val = vanillaSaveIncompatibleText; if (val.HasValue) { LocalisedString valueOrDefault = val.GetValueOrDefault(); DataManagerPlugin.SetSaveIncompatibleText(__instance, valueOrDefault); vanillaSaveIncompatibleText = null; } return true; } DataManagerPlugin.InstanceLogger.LogInfo((object)$"save slot {saveSlotIndex} has save data for missing mods:"); foreach (string item in list) { DataManagerPlugin.InstanceLogger.LogInfo((object)item); } vanillaSaveIncompatibleText = DataManagerPlugin.SetSaveIncompatibleText(__instance, new LocalisedString("Mods.org.silksong-modding.datamanager", "REQUIRED_MODS_MISSING")); CheatManager.LastErrorText = errorInfo; __instance.ChangeSaveFileState((SaveFileStates)5, doAnimate); __result = true; return false; } } [HarmonyPatch(typeof(SaveSlotButton), "OverrideSaveData")] internal static class OverrideSaveDataHook { private static void Postfix(SaveSlotButton __instance) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Invalid comparison between Unknown and I4 if ((int)__instance.State != 10) { return; } int saveSlotIndex = __instance.SaveSlotIndex; string path = DataPaths.SaveDataDir(saveSlotIndex); try { Directory.Delete(path, recursive: true); } catch (Exception arg) { DataManagerPlugin.InstanceLogger.LogError((object)$"Error overring save data for slot {saveSlotIndex}: {arg}"); } } } [HarmonyPatch(typeof(GameManager), "ReturnToMainMenu")] internal static class SavaDataSetToNullHook { private static void Prefix(ref Action<bool> callback) { Action<bool> callbackCopy = callback; callback = delegate(bool saveCompleteValue) { callbackCopy?.Invoke(saveCompleteValue); DataManagerPlugin.InstanceLogger.LogInfo((object)"Setting mods SaveData to null"); foreach (ManagedMod value in DataManagerPlugin.Instance.ManagedMods.Values) { value.SaveData?.ReadSaveData(null); value.OnceSaveData?.ReadOnceSaveData(null); } }; } } public interface IGlobalDataMod<T> : IRawGlobalDataMod where T : class { T? GlobalData { get; set; } bool IRawGlobalDataMod.HasGlobalData => GlobalData != null; void IRawGlobalDataMod.WriteGlobalData(Stream saveFile) { using StreamWriter s = new StreamWriter(saveFile); JsonUtil.Serialize(s, GlobalData); } void IRawGlobalDataMod.ReadGlobalData(Stream? saveFile) { if (saveFile == null) { GlobalData = null; return; } using StreamReader s = new StreamReader(saveFile); GlobalData = JsonUtil.Deserialize<T>(s); } } internal interface IGlobalDataMod { } public interface IOnceSaveDataMod<T> : IRawOnceSaveDataMod where T : class { T? OnceSaveData { get; set; } bool IRawOnceSaveDataMod.HasOnceSaveData => OnceSaveData != null; void IRawOnceSaveDataMod.WriteOnceSaveData(Stream saveFile) { using StreamWriter s = new StreamWriter(saveFile); JsonUtil.Serialize(s, OnceSaveData); } void IRawOnceSaveDataMod.ReadOnceSaveData(Stream? saveFile) { if (saveFile == null) { OnceSaveData = null; return; } using StreamReader s = new StreamReader(saveFile); OnceSaveData = JsonUtil.Deserialize<T>(s); } } internal interface IOnceSaveDataMod { } public interface IProfileDataMod<T> : IRawProfileDataMod where T : class { T? ProfileData { get; set; } bool IRawProfileDataMod.HasProfileData => ProfileData != null; void IRawProfileDataMod.WriteProfileData(Stream saveFile) { using StreamWriter s = new StreamWriter(saveFile); JsonUtil.Serialize(s, ProfileData); } void IRawProfileDataMod.ReadProfileData(Stream? saveFile) { if (saveFile == null) { ProfileData = null; return; } using StreamReader s = new StreamReader(saveFile); ProfileData = JsonUtil.Deserialize<T>(s); } } internal interface IProfileDataMod { } public interface IRawGlobalDataMod { bool HasGlobalData { get; } void WriteGlobalData(Stream saveFile); void ReadGlobalData(Stream? saveFile); } public interface IRawOnceSaveDataMod { bool HasOnceSaveData { get; } void WriteOnceSaveData(Stream saveFile); void ReadOnceSaveData(Stream? saveFile); } public interface IRawProfileDataMod { bool HasProfileData { get; } void WriteProfileData(Stream saveFile); void ReadProfileData(Stream? saveFile); } public interface IRawSaveDataMod { bool HasSaveData { get; } void WriteSaveData(Stream saveFile); void ReadSaveData(Stream? saveFile); } public interface IRequiredMod { bool IsRequired { get; } } public interface ISaveDataMod<T> : IRawSaveDataMod where T : class { T? SaveData { get; set; } bool IRawSaveDataMod.HasSaveData => SaveData != null; void IRawSaveDataMod.WriteSaveData(Stream saveFile) { using StreamWriter s = new StreamWriter(saveFile); JsonUtil.Serialize(s, SaveData); } void IRawSaveDataMod.ReadSaveData(Stream? saveFile) { if (saveFile == null) { SaveData = null; return; } using StreamReader s = new StreamReader(saveFile); SaveData = JsonUtil.Deserialize<T>(s); } } internal interface ISaveDataMod { } internal record ManagedMod(string Guid, IRawProfileDataMod? ProfileData, IRawGlobalDataMod? GlobalData, IRawSaveDataMod? SaveData, IRawOnceSaveDataMod? OnceSaveData, IRequiredMod? RequiredMod) { public bool HasAnyGlobalData { get { if (ProfileData == null) { return GlobalData != null; } return true; } } public bool HasAnySaveData { get { if (SaveData == null) { return OnceSaveData != null; } return true; } } public bool IsRequired => RequiredMod?.IsRequired ?? false; private string ProfileDataPath => Path.Combine(DataPaths.ProfileDataDir, Guid + ".json"); private string GlobalDataPath => Path.Combine(DataPaths.GlobalDataDir, Guid + ".json.dat"); internal static bool TryCreate(BaseUnityPlugin plugin, [NotNullWhen(true)] out ManagedMod? instance) { instance = null; string gUID = plugin.Info.Metadata.GUID; IRawProfileDataMod rawProfileDataMod = plugin as IRawProfileDataMod; IRawGlobalDataMod rawGlobalDataMod = plugin as IRawGlobalDataMod; IRawSaveDataMod rawSaveDataMod = plugin as IRawSaveDataMod; IRawOnceSaveDataMod rawOnceSaveDataMod = plugin as IRawOnceSaveDataMod; IRequiredMod requiredMod = plugin as IRequiredMod; if (rawProfileDataMod == null && rawGlobalDataMod == null && rawSaveDataMod == null && rawOnceSaveDataMod == null && requiredMod == null) { return false; } instance = new ManagedMod(gUID, rawProfileDataMod, rawGlobalDataMod, rawSaveDataMod, rawOnceSaveDataMod, requiredMod); DataManagerPlugin.InstanceLogger.LogInfo((object)(gUID + " uses data manager")); return true; } internal void LoadProfileData() { if (ProfileData != null) { LoadStreamData(ProfileDataPath, ProfileData.ReadProfileData); } } internal void SaveProfileData() { if (ProfileData != null && ProfileData.HasProfileData) { SaveStreamData(ProfileDataPath, ProfileData.WriteProfileData); } } internal void LoadGlobalData() { if (GlobalData != null) { LoadStreamData(GlobalDataPath, GlobalData.ReadGlobalData); } } internal void SaveGlobalData() { if (GlobalData != null && GlobalData.HasGlobalData) { SaveStreamData(GlobalDataPath, GlobalData.WriteGlobalData); } } internal void LoadSaveData(int saveSlot) { if (SaveData != null) { LoadStreamData(SaveDataPath(saveSlot), SaveData.ReadSaveData); } } internal void SaveSaveData(int saveSlot) { if (SaveData != null && SaveData.HasSaveData) { SaveStreamData(SaveDataPath(saveSlot), SaveData.WriteSaveData); } } internal void LoadOnceSaveData(int saveSlot) { if (OnceSaveData != null) { LoadStreamData(OnceSaveDataPath(saveSlot), OnceSaveData.ReadOnceSaveData); } } internal void SaveOnceSaveData(int saveSlot) { if (OnceSaveData != null && OnceSaveData.HasOnceSaveData) { SaveStreamData(OnceSaveDataPath(saveSlot), OnceSaveData.WriteOnceSaveData); } } private string SaveDataPath(int slot) { return Path.Combine(DataPaths.SaveDataDir(slot), Guid + ".json.dat"); } private string OnceSaveDataPath(int slot) { return Path.Combine(DataPaths.OnceSaveDataDir(slot), Guid + ".json.dat"); } private void LoadStreamData(string path, Action<Stream?> reader) { try { using FileStream obj = File.OpenRead(path); reader(obj); } catch (Exception ex) when (((ex is FileNotFoundException || ex is DirectoryNotFoundException) ? 1 : 0) != 0) { reader(null); } catch (Exception arg) { reader(null); DataManagerPlugin.InstanceLogger.LogError((object)$"Error loading data for mod {Guid}: {arg}"); } } private void SaveStreamData(string path, Action<Stream> writer) { try { using FileStream obj = File.Create(path); writer(obj); } catch (Exception arg) { DataManagerPlugin.InstanceLogger.LogError((object)$"Error saving data for mod {Guid}: {arg}"); } } [CompilerGenerated] protected virtual bool PrintMembers(StringBuilder builder) { RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("Guid = "); builder.Append((object?)Guid); builder.Append(", ProfileData = "); builder.Append(ProfileData); builder.Append(", GlobalData = "); builder.Append(GlobalData); builder.Append(", SaveData = "); builder.Append(SaveData); builder.Append(", OnceSaveData = "); builder.Append(OnceSaveData); builder.Append(", RequiredMod = "); builder.Append(RequiredMod); builder.Append(", HasAnyGlobalData = "); builder.Append(HasAnyGlobalData.ToString()); builder.Append(", HasAnySaveData = "); builder.Append(HasAnySaveData.ToString()); builder.Append(", IsRequired = "); builder.Append(IsRequired.ToString()); return true; } } } namespace Silksong.DataManager.Json { internal static class JsonUtil { private static readonly JsonSerializerSettings _settings = new JsonSerializerSettings { TypeNameHandling = (TypeNameHandling)4, ObjectCreationHandling = (ObjectCreationHandling)2 }; internal static T? Deserialize<T>(StreamReader s) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown JsonTextReader val = new JsonTextReader((TextReader)s); try { return JsonSerializer.CreateDefault(_settings).Deserialize<T>((JsonReader)(object)val); } finally { ((IDisposable)val)?.Dispose(); } } internal static object? Deserialize(string path, Type type) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Expected O, but got Unknown using StreamReader streamReader = File.OpenText(path); JsonTextReader val = new JsonTextReader((TextReader)streamReader); try { return JsonSerializer.CreateDefault(_settings).Deserialize((JsonReader)(object)val, type); } finally { ((IDisposable)val)?.Dispose(); } } internal static void Serialize(StreamWriter s, object value) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Expected O, but got Unknown JsonTextWriter val = new JsonTextWriter((TextWriter)s); try { JsonSerializer.CreateDefault(_settings).Serialize((JsonWriter)(object)val, value); } finally { ((IDisposable)val)?.Dispose(); } } internal static void Serialize(string path, object value) { using StreamWriter s = File.CreateText(path); Serialize(s, value); } } } namespace Silksong.DataManager.Data { internal class DMOnceSaveData { public List<string> RequiredModGuids = new List<string>(); } }