diff --git a/Runtime/API/RequestCache.cs b/Runtime/API/RequestCache.cs index ca09b644..cff082f8 100644 --- a/Runtime/API/RequestCache.cs +++ b/Runtime/API/RequestCache.cs @@ -22,7 +22,7 @@ private struct Entry private const int ENTRY_LIFETIME = 120; /// Max cache size. - private static readonly uint MAX_CACHE_SIZE = PluginSettings.CACHE_SIZE*1024; + private static readonly uint MAX_CACHE_SIZE = PluginSettings.CACHE_SIZE_BYTES; // ---------[ Fields ]--------- /// Map of url to saved responses. diff --git a/Runtime/ModIOVersion.cs b/Runtime/ModIOVersion.cs index 3f0cbfe3..f5393543 100644 --- a/Runtime/ModIOVersion.cs +++ b/Runtime/ModIOVersion.cs @@ -6,7 +6,7 @@ public struct ModIOVersion : System.IComparable { // ---------[ Singleton ]--------- /// Singleton instance for current version. - public static readonly ModIOVersion Current = new ModIOVersion(2, 3, 2); + public static readonly ModIOVersion Current = new ModIOVersion(2, 3, 3); // ---------[ Fields ]--------- /// Major version number. diff --git a/Runtime/PluginSettings.cs b/Runtime/PluginSettings.cs index 4906a7d3..f53e67c9 100644 --- a/Runtime/PluginSettings.cs +++ b/Runtime/PluginSettings.cs @@ -9,7 +9,7 @@ namespace ModIO { /// Stores the settings used by various classes that are unique to the game/app. - public class PluginSettings : ScriptableObject + public class PluginSettings : ScriptableObject, ISerializationCallbackReceiver { // ---------[ NESTED CLASSES ]--------- /// Attribute for denoting a field as containing directory variables. @@ -33,46 +33,64 @@ public struct RequestLoggingOptions [System.Serializable] public struct Data { + // ---------[ Versioning ]--------- + internal const int VERSION = 1; + + [HideInInspector] + [VersionedData(VERSION, VERSION)] + public int version; + // ---------[ Fields ]--------- [Header("API Settings")] [Tooltip("API URL to use when making requests")] + [VersionedData(0, "")] public string apiURL; [Tooltip("Game Id assigned to your game profile")] + [VersionedData(0, GameProfile.NULL_ID)] public int gameId; [Tooltip("API Key assigned to your game profile")] + [VersionedData(0, "")] public string gameAPIKey; - [Tooltip("Amount of memory the request cache is permitted to grow to (KB)")] - public uint requestCacheSizeKB; + [Tooltip("Amount of memory the request cache is permitted to grow to (KB)." + + "\nA negative value indicates an unlimited cache size.")] + [VersionedData(1, (int)-1)] + public int requestCacheSizeKB; /// Request logging options. public RequestLoggingOptions requestLogging; [Header("Standalone Directories")] [Tooltip("Directory to use for mod installations")] + [VersionedData(0, @"$DATA_PATH$/mod.io/mods")] [VariableDirectory] public string installationDirectory; [Tooltip("Directory to use for cached server data")] + [VersionedData(0, @"$DATA_PATH$/mod.io/cache")] [VariableDirectory] public string cacheDirectory; [Tooltip("Directory to use for user data")] + [VersionedData(0, @"$PERSISTENT_DATA_PATH$/mod.io-$GAME_ID$")] [VariableDirectory] public string userDirectory; [Header("Editor Directories")] [Tooltip("Directory to use for mod installations")] + [VersionedData(0, @"$CURRENT_DIRECTORY$/mod.io/editor/$GAME_ID$/mods")] [VariableDirectory] public string installationDirectoryEditor; [Tooltip("Directory to use for cached server data")] + [VersionedData(0, @"$CURRENT_DIRECTORY$/mod.io/editor/$GAME_ID$/cache")] [VariableDirectory] public string cacheDirectoryEditor; [Tooltip("Directory to use for user data")] + [VersionedData(0, @"$CURRENT_DIRECTORY$/mod.io/editor/$GAME_ID$/user")] [VariableDirectory] public string userDirectoryEditor; @@ -216,9 +234,19 @@ public static RequestLoggingOptions REQUEST_LOGGING { get { return PluginSettings.data.requestLogging; } } - public static uint CACHE_SIZE + public static uint CACHE_SIZE_BYTES { - get { return PluginSettings.data.requestCacheSizeKB; } + get + { + if(PluginSettings.data.requestCacheSizeKB < 0) + { + return uint.MaxValue; + } + else + { + return (uint)PluginSettings.data.requestCacheSizeKB * 1024; + } + } } // ---------[ FUNCTIONALITY ]--------- @@ -338,6 +366,31 @@ public static string ReplaceDirectoryVariables(string directory, int gameId) return directory; } + /// Creates an updated version of passed PluginSettings.Data. + public static PluginSettings.Data UpdateVersionedValues(int dataVersion, + PluginSettings.Data dataValues) + { + // early out + if(dataVersion >= PluginSettings.Data.VERSION) + { + return dataValues; + } + else + { + return VersionedDataAttribute.UpdateStructFields(dataVersion, dataValues); + } + } + + // ---------[ ISerializationCallbackReceiver ]--------- + /// Implement this method to receive a callback after Unity deserializes your object. + public void OnAfterDeserialize() + { + this.m_data = PluginSettings.UpdateVersionedValues(this.m_data.version, this.m_data); + } + + /// Implement this method to receive a callback before Unity serializes your object. + public void OnBeforeSerialize() {} + // ---------[ EDITOR CODE ]--------- #if UNITY_EDITOR /// Locates the PluginSettings asset used at runtime. @@ -359,26 +412,16 @@ public static void FocusAsset() /// Generates a PluginSettings.Data instance with runtime defaults. public static PluginSettings.Data GenerateDefaultData() { - PluginSettings.Data data = new PluginSettings.Data() + PluginSettings.Data data = new PluginSettings.Data(); + data = PluginSettings.UpdateVersionedValues(-1, data); + + // non-constant defaults + data.apiURL = APIClient.API_URL_PRODUCTIONSERVER + APIClient.API_VERSION; + data.requestLogging = new RequestLoggingOptions() { - apiURL = APIClient.API_URL_PRODUCTIONSERVER + APIClient.API_VERSION, - gameId = GameProfile.NULL_ID, - gameAPIKey = string.Empty, - requestCacheSizeKB = 4*1024, - requestLogging = new RequestLoggingOptions() - { - errorsAsWarnings = true, - logAllResponses = false, - logOnSend = false, - }, - - installationDirectory = IOUtilities.CombinePath("$DATA_PATH$","mod.io","mods"), - cacheDirectory = IOUtilities.CombinePath("$DATA_PATH$","mod.io","cache"), - userDirectory = IOUtilities.CombinePath("$PERSISTENT_DATA_PATH$","mod.io-$GAME_ID$"), - - installationDirectoryEditor = IOUtilities.CombinePath("$CURRENT_DIRECTORY$","mod.io","editor","$GAME_ID$","mods"), - cacheDirectoryEditor = IOUtilities.CombinePath("$CURRENT_DIRECTORY$","mod.io","editor","$GAME_ID$","cache"), - userDirectoryEditor = IOUtilities.CombinePath("$CURRENT_DIRECTORY$","mod.io","editor","$GAME_ID$","user"), + errorsAsWarnings = true, + logAllResponses = false, + logOnSend = false, }; return data; diff --git a/Runtime/Utility/VersionedDataAttribute.cs b/Runtime/Utility/VersionedDataAttribute.cs new file mode 100644 index 00000000..3190fc7a --- /dev/null +++ b/Runtime/Utility/VersionedDataAttribute.cs @@ -0,0 +1,53 @@ +namespace ModIO +{ + /// Attribute for determining the version of and default value for a given field. + public class VersionedDataAttribute : System.Attribute + { + // ---------[ Fields ]--------- + /// Version the field was created. + public int version; + + /// Default value for the field. + public System.Object defaultValue; + + // ---------[ Initialization ]--------- + public VersionedDataAttribute(int version, System.Object defaultValue) + { + this.version = version; + this.defaultValue = defaultValue; + } + + // ---------[ Utility ]--------- + /// Creates an updated version of the data structure passed. + public static T UpdateStructFields(int dataVersion, T dataValues) + where T : struct + { + // set up data + T updatedValues = dataValues; + System.Object boxedData = updatedValues; + + // iterate over the typed fields + var fieldList = typeof(T).GetFields(); + foreach(var field in fieldList) + { + // check for the VersionedDataAttribute attribute + var attributeList = field.GetCustomAttributes(typeof(VersionedDataAttribute), false); + if(attributeList != null + && attributeList.Length == 1) + { + // set the default value if attribute is newer than the dataVersion + VersionedDataAttribute dataAttribute = (VersionedDataAttribute)attributeList[0]; + if(dataAttribute.version > dataVersion) + { + field.SetValue(boxedData, dataAttribute.defaultValue); + } + } + } + + // unbox the updatedValues + updatedValues = (T)boxedData; + + return updatedValues; + } + } +} diff --git a/Runtime/Utility/VersionedDataAttribute.cs.meta b/Runtime/Utility/VersionedDataAttribute.cs.meta new file mode 100644 index 00000000..713cc94c --- /dev/null +++ b/Runtime/Utility/VersionedDataAttribute.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 8e2869d4b03379a48ad42af8aebc8ac0 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: