From c20d26dc071f047088b6f50b0e19aa2221e6c281 Mon Sep 17 00:00:00 2001 From: poi-vrc <77053052+poi-vrc@users.noreply.github.com> Date: Wed, 23 Aug 2023 10:33:32 +0800 Subject: [PATCH] refactor: generalize serializer and versioning objects --- .../Editor/DTEditorUtils.cs | 3 +- .../UI/Presenters/WearableConfigPresenter.cs | 2 +- .../AnimationGenerationModuleEditor.cs | 2 +- .../Modules/ArmatureMappingModuleEditor.cs | 2 +- .../Modules/BlendshapeSyncModuleEditor.cs | 2 +- .../UI/Views/Modules/MoveRootModuleEditor.cs | 2 +- .../Lib/Editor/UI/ModuleEditor.cs | 4 +- .../Wearable/Modules/WearableModule.cs | 17 ++- .../Wearable/Providers/ModuleProviderBase.cs | 12 +- ...ableConfigSerializer.cs => ISerializer.cs} | 9 +- ...Serializer.cs.meta => ISerializer.cs.meta} | 0 .../Serializers/Version1Serializer.cs | 19 ++- .../Lib/Runtime/Wearable/WearableConfig.cs | 127 +++--------------- .../Runtime/Wearable/WearableConfigVersion.cs | 113 ++++++++++++++++ .../Wearable/WearableConfigVersion.cs.meta | 11 ++ .../Wearable/WearableConfigVersionedObject.cs | 64 +++++++++ .../WearableConfigVersionedObject.cs.meta | 11 ++ .../Runtime/Cabinet/CabinetApplier.cs | 4 +- .../VRChat/VRChatIntegrationModule.cs | 6 +- .../Modules/AnimationGenerationModule.cs | 6 +- .../Wearable/Modules/ArmatureMappingModule.cs | 8 +- .../Wearable/Modules/BlendshapeSyncModule.cs | 6 +- .../Wearable/Modules/MoveRootModule.cs | 6 +- 23 files changed, 277 insertions(+), 159 deletions(-) rename Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/{IWearableConfigSerializer.cs => ISerializer.cs} (85%) rename Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/{IWearableConfigSerializer.cs.meta => ISerializer.cs.meta} (100%) create mode 100644 Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs create mode 100644 Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs.meta create mode 100644 Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs create mode 100644 Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs.meta diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/DTEditorUtils.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/DTEditorUtils.cs index 8f99d3a6..e766d689 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/DTEditorUtils.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/DTEditorUtils.cs @@ -18,6 +18,7 @@ using Chocopoi.DressingTools.Cabinet; using Chocopoi.DressingTools.Lib.Cabinet; using Chocopoi.DressingTools.Lib.Wearable; +using Newtonsoft.Json; using UnityEditor; using UnityEngine; @@ -96,7 +97,7 @@ public static void AddCabinetWearable(DTCabinet cabinet, WearableConfig config, var cabinetWearable = wearableGameObject.AddComponent(); cabinetWearable.wearableGameObject = wearableGameObject; - cabinetWearable.configJson = config.Serialize(); + cabinetWearable.configJson = config.Serialize().ToString(Formatting.None); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Presenters/WearableConfigPresenter.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Presenters/WearableConfigPresenter.cs index f12345df..cbfae3fe 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Presenters/WearableConfigPresenter.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Presenters/WearableConfigPresenter.cs @@ -190,7 +190,7 @@ private void OnAddModuleButtonClick() UpdateModulesView(); } - private ModuleEditor CreateModuleEditor(ModuleProviderBase provider, ModuleConfig module) + private ModuleEditor CreateModuleEditor(ModuleProviderBase provider, IModuleConfig module) { // prepare cache if not yet if (s_moduleEditorTypesCache == null) diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/AnimationGenerationModuleEditor.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/AnimationGenerationModuleEditor.cs index 5f8e8782..dd321754 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/AnimationGenerationModuleEditor.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/AnimationGenerationModuleEditor.cs @@ -60,7 +60,7 @@ internal class AnimationGenerationModuleEditor : ModuleEditor, IAnimationGenerat private bool _foldoutWearableAnimationPresetToggles; private bool _foldoutWearableAnimationPresetBlendshapes; - public AnimationGenerationModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, ModuleConfig target) : base(parentView, provider, target) + public AnimationGenerationModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, IModuleConfig target) : base(parentView, provider, target) { _parentView = parentView; _presenter = new AnimationGenerationModuleEditorPresenter(this, parentView, (AnimationGenerationModuleConfig)target); diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/ArmatureMappingModuleEditor.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/ArmatureMappingModuleEditor.cs index b5926537..cd9c60cb 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/ArmatureMappingModuleEditor.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/ArmatureMappingModuleEditor.cs @@ -58,7 +58,7 @@ internal class ArmatureMappingModuleEditor : ModuleEditor, IArmatureMappingModul private bool _removeExistingPrefixSuffix; private bool _groupBones; - public ArmatureMappingModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, ModuleConfig target) : base(parentView, provider, target) + public ArmatureMappingModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, IModuleConfig target) : base(parentView, provider, target) { _parentView = parentView; _presenter = new ArmatureMappingModuleEditorPresenter(this, parentView, (ArmatureMappingModuleConfig)target); diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/BlendshapeSyncModuleEditor.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/BlendshapeSyncModuleEditor.cs index b53e2a75..21773409 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/BlendshapeSyncModuleEditor.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/BlendshapeSyncModuleEditor.cs @@ -44,7 +44,7 @@ internal class BlendshapeSyncModuleEditor : ModuleEditor, IBlendshapeSyncModuleE private IModuleEditorViewParent _parentView; private BlendshapeSyncModuleEditorPresenter _presenter; - public BlendshapeSyncModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, ModuleConfig target) : base(parentView, provider, target) + public BlendshapeSyncModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, IModuleConfig target) : base(parentView, provider, target) { _parentView = parentView; _presenter = new BlendshapeSyncModuleEditorPresenter(this, (BlendshapeSyncModuleConfig)target); diff --git a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/MoveRootModuleEditor.cs b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/MoveRootModuleEditor.cs index 16855ec4..12ec8242 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/MoveRootModuleEditor.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Editor/UI/Views/Modules/MoveRootModuleEditor.cs @@ -42,7 +42,7 @@ internal class MoveRootModuleEditor : ModuleEditor, IMoveRootModuleEditorView private IModuleEditorViewParent _parentView; private GameObject _moveToGameObject; - public MoveRootModuleEditor(IModuleEditorViewParent parentView, MoveRootModuleProvider provider, ModuleConfig target) : base(parentView, provider, target) + public MoveRootModuleEditor(IModuleEditorViewParent parentView, MoveRootModuleProvider provider, IModuleConfig target) : base(parentView, provider, target) { _parentView = parentView; _presenter = new MoveRootModuleEditorPresenter(this, parentView, (MoveRootModuleConfig)target); diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Editor/UI/ModuleEditor.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Editor/UI/ModuleEditor.cs index f8d1ed8b..fa68c252 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Editor/UI/ModuleEditor.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Editor/UI/ModuleEditor.cs @@ -31,9 +31,9 @@ public class ModuleEditor : EditorViewBase protected ModuleProviderBase provider; - protected ModuleConfig target; + protected IModuleConfig target; - public ModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, ModuleConfig target) + public ModuleEditor(IModuleEditorViewParent parentView, ModuleProviderBase provider, IModuleConfig target) { this.parentView = parentView; this.provider = provider; diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Modules/WearableModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Modules/WearableModule.cs index 48e736e6..c1197876 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Modules/WearableModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Modules/WearableModule.cs @@ -20,21 +20,18 @@ using Chocopoi.DressingTools.Lib.Cabinet; using Chocopoi.DressingTools.Lib.Logging; using Chocopoi.DressingTools.Lib.Proxy; +using Chocopoi.DressingTools.Lib.Wearable.Serializers; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using UnityEngine; namespace Chocopoi.DressingTools.Lib.Wearable.Modules { - public class WearableModule - { - public string moduleName; - public ModuleConfig config; - } + public interface IModuleConfig { } - public abstract class ModuleConfig { } + public abstract class VersionedModuleConfig : WearableConfigVersionedObject, IModuleConfig { } - public class UnknownModuleConfig : ModuleConfig + public class UnknownModuleConfig : IModuleConfig { public string RawJson { get; private set; } public UnknownModuleConfig(string rawJson) @@ -42,4 +39,10 @@ public UnknownModuleConfig(string rawJson) RawJson = rawJson; } } + + public class WearableModule + { + public string moduleName; + public IModuleConfig config; + } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Providers/ModuleProviderBase.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Providers/ModuleProviderBase.cs index 9db3efcc..9b01628d 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Providers/ModuleProviderBase.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Providers/ModuleProviderBase.cs @@ -28,11 +28,11 @@ public abstract class ModuleProviderBase public abstract int ApplyOrder { get; } public abstract bool AllowMultiple { get; } - public abstract ModuleConfig DeserializeModuleConfig(JObject jObject); - public virtual string SerializeModuleConfig(ModuleConfig moduleConfig) => JsonConvert.SerializeObject(moduleConfig); - public abstract ModuleConfig NewModuleConfig(); - public virtual bool OnBeforeApplyCabinet(ApplyCabinetContext ctx, ModuleConfig moduleConfig) => true; - public virtual bool OnApplyWearable(ApplyCabinetContext cabCtx, ApplyWearableContext wearCtx, ModuleConfig moduleConfig) => true; - public virtual bool OnAfterApplyCabinet(ApplyCabinetContext ctx, ModuleConfig moduleConfig) => true; + public abstract IModuleConfig DeserializeModuleConfig(JObject jObject); + public virtual string SerializeModuleConfig(IModuleConfig moduleConfig) => JsonConvert.SerializeObject(moduleConfig); + public abstract IModuleConfig NewModuleConfig(); + public virtual bool OnBeforeApplyCabinet(ApplyCabinetContext ctx, IModuleConfig moduleConfig) => true; + public virtual bool OnApplyWearable(ApplyCabinetContext cabCtx, ApplyWearableContext wearCtx, IModuleConfig moduleConfig) => true; + public virtual bool OnAfterApplyCabinet(ApplyCabinetContext ctx, IModuleConfig moduleConfig) => true; } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/IWearableConfigSerializer.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/ISerializer.cs similarity index 85% rename from Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/IWearableConfigSerializer.cs rename to Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/ISerializer.cs index b0b38f4f..262d4413 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/IWearableConfigSerializer.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/ISerializer.cs @@ -1,5 +1,5 @@ /* - * File: IWearableConfigSerializer.cs + * File: ISerializer.cs * Project: DressingTools * Created Date: Saturday, Aug 22nd 2023, 16:35:11 pm * Author: chocopoi (poi@chocopoi.com) @@ -20,12 +20,13 @@ using System.Globalization; using Chocopoi.DressingTools.Lib.Wearable.Modules; using Newtonsoft.Json; +using Newtonsoft.Json.Linq; namespace Chocopoi.DressingTools.Lib.Wearable.Serializers { - public interface IWearableConfigSerializer + public interface ISerializer { - string Serialize(WearableConfig config); - WearableConfig Deserialize(string json); + JObject SerializeFrom(object obj); + void DeserializeFrom(object obj, JObject jObject); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/IWearableConfigSerializer.cs.meta b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/ISerializer.cs.meta similarity index 100% rename from Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/IWearableConfigSerializer.cs.meta rename to Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/ISerializer.cs.meta diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/Version1Serializer.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/Version1Serializer.cs index 42a18ed1..5e2d86ae 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/Version1Serializer.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/Serializers/Version1Serializer.cs @@ -25,7 +25,7 @@ namespace Chocopoi.DressingTools.Lib.Wearable.Serializers { - public class Version1Serializer : IWearableConfigSerializer + public class Version1Serializer : ISerializer { private class ModuleConverter : JsonConverter { @@ -35,7 +35,7 @@ private class ModuleConverter : JsonConverter public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { // we do this serialization ourselves - if (objectType == typeof(ModuleConfig)) + if (objectType == typeof(IModuleConfig)) { return null; } @@ -79,7 +79,7 @@ private static WearableModule DeserializeModule(JObject jObject) var moduleName = jObject["moduleName"].Value(); var provider = ModuleProviderLocator.Instance.GetProvider(moduleName); - ModuleConfig moduleConfig = provider == null ? + IModuleConfig moduleConfig = provider == null ? new UnknownModuleConfig(configJObject.ToString(Formatting.None)) : provider.DeserializeModuleConfig(configJObject); @@ -95,12 +95,10 @@ private static WearableModule DeserializeModule(JObject jObject) private const string KeyAvatarConfig = "avatarConfig"; private const string KeyModules = "modules"; - public WearableConfig Deserialize(string json) + public void DeserializeFrom(object obj, JObject jObject) { // TODO: perform schema check here - - var config = new WearableConfig(); - JObject jObject = JObject.Parse(json); + var config = (WearableConfig)obj; if (!jObject.ContainsKey(KeyVersion) || jObject[KeyVersion].Type != JTokenType.String || !jObject.ContainsKey(KeyInfo) || jObject[KeyInfo].Type != JTokenType.Object || @@ -127,12 +125,11 @@ public WearableConfig Deserialize(string json) var module = DeserializeModule((JObject)moduleJtoken); config.Modules.Add(module); } - - return config; } - public string Serialize(WearableConfig config) + public JObject SerializeFrom(object obj) { + var config = (WearableConfig)obj; var jObject = new JObject { [KeyVersion] = config.Version.ToString(), @@ -147,7 +144,7 @@ public string Serialize(WearableConfig config) } jObject[KeyModules] = modulesArray; - return jObject.ToString(Formatting.None); + return jObject; } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfig.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfig.cs index d9224689..3d52c4cb 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfig.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfig.cs @@ -36,101 +36,17 @@ public static bool Migrate(string inputJson, out string outputJson) } } - public class WearableConfigVersion - { - public int Major { get; private set; } - public int Minor { get; private set; } - public int Patch { get; private set; } - public string Extra { get; private set; } - - public WearableConfigVersion(int major, int minor, int patch) - { - Major = major; - Minor = minor; - Patch = patch; - Extra = null; - } - - public WearableConfigVersion(int major, int minor, int patch, string extra) - { - Major = major; - Minor = minor; - Patch = patch; - Extra = extra; - } - - public WearableConfigVersion(string str) - { - var hyphenIndex = str.IndexOf('-'); - string versionStr = null; - if (hyphenIndex != -1) - { - Extra = str.Substring(hyphenIndex + 1); - versionStr = str.Substring(0, hyphenIndex); - } - else - { - versionStr = str; - } - - if (versionStr.Length == 0) - { - throw new ArgumentException("Version part is empty"); - } - - var splits = versionStr.Split('.'); - if (splits.Length < 2) - { - throw new ArgumentException("Version string is not in major, minor or optionally patch format"); - } - - if (!int.TryParse(splits[0], out var major)) - { - throw new ArgumentException("Could not parse major: " + splits[0]); - } - Major = major; - - if (!int.TryParse(splits[1], out var minor)) - { - throw new ArgumentException("Could not parse minor: " + splits[1]); - } - Minor = minor; - - if (splits.Length > 2) - { - if (!int.TryParse(splits[2], out var patch)) - { - throw new ArgumentException("Could not parse patch: " + splits[2]); - } - Patch = patch; - } - else - { - Patch = 0; - } - } - - public override string ToString() - { - var output = string.Format("{0}.{1}.{2}", Major, Minor, Patch); - if (Extra != null) - { - output += "-" + Extra; - } - return output; - } - } - - public class WearableConfig + public class WearableConfig : WearableConfigVersionedObject { public static readonly WearableConfigVersion CurrentConfigVersion = new WearableConfigVersion(1, 0, 0); - private static readonly Dictionary Serializers = new Dictionary() { + private static readonly Dictionary Serializers = new Dictionary() { { 1, new Version1Serializer() }, }; - public WearableConfigVersion Version { get; set; } + public override WearableConfigVersion Version { get; set; } public WearableInfo Info { get; set; } public AvatarConfig AvatarConfig { get; set; } + public List Modules; public WearableConfig() @@ -147,39 +63,38 @@ public WearableConfig() Modules = new List(); } - public string Serialize() + public override ISerializer GetSerializerByVersion(WearableConfigVersion version) { - var serializer = Serializers[CurrentConfigVersion.Major]; - return serializer.Serialize(this); + if (version == null) + { + return null; + } + return Serializers.ContainsKey(version.Major) ? Serializers[version.Major] : null; } public static WearableConfig Deserialize(string json) { - JObject jObject = JObject.Parse(json); - if (!jObject.ContainsKey("version")) - { - throw new JsonException("Config does not contain version"); - } - var configVersion = new WearableConfigVersion(jObject["version"].Value()); - - if (!Serializers.ContainsKey(configVersion.Major)) - { - throw new Exception("Incompatible config version: " + configVersion.Major); - } + // TODO: perform schema check + var jObject = JObject.Parse(json); + return Deserialize(jObject); + } - var serializer = Serializers[configVersion.Major]; - return serializer.Deserialize(json); + public static WearableConfig Deserialize(JObject jObject) + { + var config = new WearableConfig(); + config.DeserializeFrom(jObject); + return config; } public WearableConfig Clone() { - // a tricky and easier way to copy + // a tricky and easier way to copy return Deserialize(Serialize()); } public override string ToString() { - return Serialize(); + return Serialize().ToString(Formatting.None); } } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs new file mode 100644 index 00000000..a376f8c5 --- /dev/null +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs @@ -0,0 +1,113 @@ +/* + * File: WearableConfigVersion.cs + * Project: DressingTools + * Created Date: Saturday, Aug 23th 2023, 09:12:11 am + * Author: chocopoi (poi@chocopoi.com) + * ----- + * Copyright (c) 2023 chocopoi + * + * This file is part of DressingTools. + * + * DressingTools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * DressingTools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DressingTools. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using Chocopoi.DressingTools.Lib.Wearable.Modules; +using Chocopoi.DressingTools.Lib.Wearable.Serializers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SemanticVersioning; + +namespace Chocopoi.DressingTools.Lib.Wearable +{ + public class WearableConfigVersion + { + public int Major { get; private set; } + public int Minor { get; private set; } + public int Patch { get; private set; } + public string Extra { get; private set; } + + public WearableConfigVersion(int major, int minor, int patch) + { + Major = major; + Minor = minor; + Patch = patch; + Extra = null; + } + + public WearableConfigVersion(int major, int minor, int patch, string extra) + { + Major = major; + Minor = minor; + Patch = patch; + Extra = extra; + } + + public WearableConfigVersion(string str) + { + var hyphenIndex = str.IndexOf('-'); + string versionStr = null; + if (hyphenIndex != -1) + { + Extra = str.Substring(hyphenIndex + 1); + versionStr = str.Substring(0, hyphenIndex); + } + else + { + versionStr = str; + } + + if (versionStr.Length == 0) + { + throw new ArgumentException("Version part is empty"); + } + + var splits = versionStr.Split('.'); + if (splits.Length < 2) + { + throw new ArgumentException("Version string is not in major, minor or optionally patch format"); + } + + if (!int.TryParse(splits[0], out var major)) + { + throw new ArgumentException("Could not parse major: " + splits[0]); + } + Major = major; + + if (!int.TryParse(splits[1], out var minor)) + { + throw new ArgumentException("Could not parse minor: " + splits[1]); + } + Minor = minor; + + if (splits.Length > 2) + { + if (!int.TryParse(splits[2], out var patch)) + { + throw new ArgumentException("Could not parse patch: " + splits[2]); + } + Patch = patch; + } + else + { + Patch = 0; + } + } + + public override string ToString() + { + var output = string.Format("{0}.{1}.{2}", Major, Minor, Patch); + if (Extra != null) + { + output += "-" + Extra; + } + return output; + } + } +} diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs.meta b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs.meta new file mode 100644 index 00000000..d2963d37 --- /dev/null +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersion.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ad28c60928a305e468ec38c784978cab +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs new file mode 100644 index 00000000..4e8e9972 --- /dev/null +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs @@ -0,0 +1,64 @@ +/* + * File: WearableConfigVersionedObject.cs + * Project: DressingTools + * Created Date: Saturday, Aug 23th 2023, 09:39:11 am + * Author: chocopoi (poi@chocopoi.com) + * ----- + * Copyright (c) 2023 chocopoi + * + * This file is part of DressingTools. + * + * DressingTools is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + * + * DressingTools is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with DressingTools. If not, see . + */ + +using System; +using System.Collections.Generic; +using System.Globalization; +using Chocopoi.DressingTools.Lib.Wearable.Modules; +using Chocopoi.DressingTools.Lib.Wearable.Serializers; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using SemanticVersioning; + +namespace Chocopoi.DressingTools.Lib.Wearable +{ + public abstract class WearableConfigVersionedObject + { + public abstract WearableConfigVersion Version { get; set; } + + public abstract ISerializer GetSerializerByVersion(WearableConfigVersion version); + + public virtual void DeserializeFrom(JObject jObject) + { + // TODO: do schema check + + var moduleVersion = jObject.ContainsKey("version") ? + new WearableConfigVersion(jObject["version"].Value()) : + null; + var serializer = GetSerializerByVersion(moduleVersion); + + if (serializer == null) + { + throw new Exception("Incompatible object version for deserialization"); + } + + serializer.DeserializeFrom(this, jObject); + } + + public virtual JObject Serialize() + { + var serializer = GetSerializerByVersion(Version); + + if (serializer == null) + { + throw new Exception("Incompatible object version for serialization"); + } + + return serializer.SerializeFrom(this); + } + } +} diff --git a/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs.meta b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs.meta new file mode 100644 index 00000000..3182eb49 --- /dev/null +++ b/Packages/com.chocopoi.vrc.dressingtools/Lib/Runtime/Wearable/WearableConfigVersionedObject.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 3f3e48f264f7212459ce393e12a3b69f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Cabinet/CabinetApplier.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Cabinet/CabinetApplier.cs index b3f6ae2d..2031a24b 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Cabinet/CabinetApplier.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Cabinet/CabinetApplier.cs @@ -24,6 +24,7 @@ using Chocopoi.DressingTools.Lib.Wearable.Modules.Providers; using Chocopoi.DressingTools.Logging; using Chocopoi.DressingTools.Proxy; +using Newtonsoft.Json.Linq; using UnityEngine; namespace Chocopoi.DressingTools.Cabinet @@ -269,7 +270,8 @@ public void Execute() WearableConfig config = null; try { - config = WearableConfig.Deserialize(wearable.configJson); + var jObject = JObject.Parse(wearable.configJson); + config = WearableConfig.Deserialize(jObject); } catch (System.Exception ex) { diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Integrations/VRChat/VRChatIntegrationModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Integrations/VRChat/VRChatIntegrationModule.cs index d93c4ac4..5181e065 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Integrations/VRChat/VRChatIntegrationModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Integrations/VRChat/VRChatIntegrationModule.cs @@ -23,7 +23,7 @@ namespace Chocopoi.DressingTools.Integration.VRChat.Modules { - internal class VRChatIntegrationModuleConfig : ModuleConfig + internal class VRChatIntegrationModuleConfig : IModuleConfig { } @@ -42,8 +42,8 @@ static VRChatIntegrationModuleProvider() ModuleProviderLocator.Instance.Register(new VRChatIntegrationModuleProvider()); } - public override ModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); + public override IModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); - public override ModuleConfig NewModuleConfig() => new VRChatIntegrationModuleConfig(); + public override IModuleConfig NewModuleConfig() => new VRChatIntegrationModuleConfig(); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/AnimationGenerationModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/AnimationGenerationModule.cs index 16a1bc63..003b62ba 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/AnimationGenerationModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/AnimationGenerationModule.cs @@ -29,7 +29,7 @@ namespace Chocopoi.DressingTools.Wearable.Modules { - internal class AnimationGenerationModuleConfig : ModuleConfig + internal class AnimationGenerationModuleConfig : IModuleConfig { public AnimationPreset avatarAnimationOnWear; // execute on wear public AnimationPreset wearableAnimationOnWear; @@ -58,9 +58,9 @@ static AnimationGenerationModuleProvider() ModuleProviderLocator.Instance.Register(new AnimationGenerationModuleProvider()); } - public override ModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); + public override IModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); - public override ModuleConfig NewModuleConfig() => new AnimationGenerationModuleConfig(); + public override IModuleConfig NewModuleConfig() => new AnimationGenerationModuleConfig(); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/ArmatureMappingModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/ArmatureMappingModule.cs index bb89f512..e9b12800 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/ArmatureMappingModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/ArmatureMappingModule.cs @@ -43,7 +43,7 @@ internal enum BoneMappingMode Manual = 2 } - internal class ArmatureMappingModuleConfig : ModuleConfig + internal class ArmatureMappingModuleConfig : IModuleConfig { public string dresserName; @@ -358,7 +358,7 @@ private static string RandomString(int length) .Select(s => s[Random.Next(s.Length)]).ToArray()); } - public override bool OnApplyWearable(ApplyCabinetContext cabCtx, ApplyWearableContext wearCtx, ModuleConfig moduleConfig) + public override bool OnApplyWearable(ApplyCabinetContext cabCtx, ApplyWearableContext wearCtx, IModuleConfig moduleConfig) { var armatureMappingConfig = (ArmatureMappingModuleConfig)moduleConfig; @@ -384,8 +384,8 @@ static ArmatureMappingModuleProvider() ModuleProviderLocator.Instance.Register(new ArmatureMappingModuleProvider()); } - public override ModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); + public override IModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); - public override ModuleConfig NewModuleConfig() => new ArmatureMappingModuleConfig(); + public override IModuleConfig NewModuleConfig() => new ArmatureMappingModuleConfig(); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/BlendshapeSyncModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/BlendshapeSyncModule.cs index e25c141c..67ad336e 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/BlendshapeSyncModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/BlendshapeSyncModule.cs @@ -29,7 +29,7 @@ namespace Chocopoi.DressingTools.Wearable.Modules { - internal class BlendshapeSyncModuleConfig : ModuleConfig + internal class BlendshapeSyncModuleConfig : IModuleConfig { public List blendshapeSyncs; // blendshapes to sync from avatar to wearables @@ -54,8 +54,8 @@ static BlendshapeSyncModuleProvider() ModuleProviderLocator.Instance.Register(new BlendshapeSyncModuleProvider()); } - public override ModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); + public override IModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); - public override ModuleConfig NewModuleConfig() => new BlendshapeSyncModuleConfig(); + public override IModuleConfig NewModuleConfig() => new BlendshapeSyncModuleConfig(); } } diff --git a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/MoveRootModule.cs b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/MoveRootModule.cs index bf0f3efc..f6081417 100644 --- a/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/MoveRootModule.cs +++ b/Packages/com.chocopoi.vrc.dressingtools/Runtime/Wearable/Modules/MoveRootModule.cs @@ -29,7 +29,7 @@ namespace Chocopoi.DressingTools.Wearable.Modules { - internal class MoveRootModuleConfig : ModuleConfig + internal class MoveRootModuleConfig : IModuleConfig { public string avatarPath; } @@ -49,8 +49,8 @@ static MoveRootModuleProvider() ModuleProviderLocator.Instance.Register(new MoveRootModuleProvider()); } - public override ModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); + public override IModuleConfig DeserializeModuleConfig(JObject jObject) => jObject.ToObject(); - public override ModuleConfig NewModuleConfig() => new MoveRootModuleConfig(); + public override IModuleConfig NewModuleConfig() => new MoveRootModuleConfig(); } }