diff --git a/AssetStudioUtility/AssetStudioUtility.csproj b/AssetStudioUtility/AssetStudioUtility.csproj index c56d460..a3bb459 100644 --- a/AssetStudioUtility/AssetStudioUtility.csproj +++ b/AssetStudioUtility/AssetStudioUtility.csproj @@ -9,7 +9,6 @@ - diff --git a/AssetStudioUtility/CubismLive2DExtractor/BlendType.cs b/AssetStudioUtility/CubismLive2DExtractor/BlendType.cs index f43daeb..5b00627 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/BlendType.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/BlendType.cs @@ -2,8 +2,8 @@ { public enum BlendType { + Overwrite, Add, Multiply, - Overwrite, } } diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismExpression3Json.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismExpression3Json.cs index 3927131..572aa91 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismExpression3Json.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismExpression3Json.cs @@ -1,4 +1,6 @@ -namespace CubismLive2DExtractor +using System.Text.Json.Serialization; + +namespace CubismLive2DExtractor { public class CubismExpression3Json { @@ -11,6 +13,7 @@ { public string Id { get; set; } public float Value { get; set; } + [JsonConverter(typeof(JsonStringEnumConverter))] public BlendType Blend { get; set; } } } diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterBool.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterBool.cs new file mode 100644 index 0000000..f41c601 --- /dev/null +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterBool.cs @@ -0,0 +1,25 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CubismLive2DExtractor.CubismJsonConverters +{ + public sealed class MyJsonConverterBool : JsonConverter + { + public override bool Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + switch(reader.TokenType) + { + case JsonTokenType.True: return true; + case JsonTokenType.False: return false; + case JsonTokenType.Number: return reader.GetByte() == 1; + default: throw new JsonException($"Unable to convert \"{reader.TokenType}\" token to boolean."); + } + } + + public override void Write(Utf8JsonWriter writer, bool value, JsonSerializerOptions options) + { + writer.WriteBooleanValue(value); + } + } +} diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloat.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloat.cs new file mode 100644 index 0000000..6cf056d --- /dev/null +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloat.cs @@ -0,0 +1,51 @@ +using System; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CubismLive2DExtractor.CubismJsonConverters +{ + public class MyJsonConverterFloat : JsonConverter + { + private readonly bool _asDecimal; + + public MyJsonConverterFloat(bool asDecimal = false) + { + _asDecimal = asDecimal; + } + + public override float Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize(ref reader, new JsonSerializerOptions + { + NumberHandling = options.NumberHandling + }); + } + + public override void Write(Utf8JsonWriter writer, float value, JsonSerializerOptions options) + { + if (float.IsNaN(value) || float.IsInfinity(value)) + { + if (options.NumberHandling == JsonNumberHandling.AllowNamedFloatingPointLiterals) + { + writer.WriteStringValue($"{value.ToString(CultureInfo.InvariantCulture)}"); + } + else + { + writer.WriteStringValue(JsonSerializer.Serialize(value)); + } + } + else + { + if (_asDecimal && value.Equals((int)value)) + { + writer.WriteNumberValue((decimal)value + 0.0m); + } + else + { + writer.WriteNumberValue(MathF.Round(value, 3)); + } + } + } + } +} diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloatList.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloatList.cs new file mode 100644 index 0000000..bd3ee81 --- /dev/null +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismJsonConverters/MyJsonConverterFloatList.cs @@ -0,0 +1,43 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace CubismLive2DExtractor.CubismJsonConverters +{ + public class MyJsonConverterFloatList : JsonConverter> + { + public override List Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + return JsonSerializer.Deserialize>(ref reader, new JsonSerializerOptions + { + NumberHandling = options.NumberHandling + }); + } + + public override void Write(Utf8JsonWriter writer, List value, JsonSerializerOptions options) + { + writer.WriteStartArray(); + foreach (var n in value) + { + if (float.IsNaN(n) || float.IsInfinity(n)) + { + if (options.NumberHandling == JsonNumberHandling.AllowNamedFloatingPointLiterals) + { + writer.WriteStringValue($"{n.ToString(CultureInfo.InvariantCulture)}"); + } + else + { + writer.WriteStringValue(JsonSerializer.Serialize(value)); + } + } + else + { + writer.WriteNumberValue(MathF.Round(n, 3)); + } + } + writer.WriteEndArray(); + } + } +} diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismModel3Json.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismModel3Json.cs index 95a1115..3ec0b67 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismModel3Json.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismModel3Json.cs @@ -1,4 +1,4 @@ -using Newtonsoft.Json.Linq; +using System.Text.Json.Nodes; namespace CubismLive2DExtractor { @@ -16,8 +16,8 @@ namespace CubismLive2DExtractor public string Physics; public string Pose; public string DisplayInfo; - public JObject Motions; - public JArray Expressions; + public JsonObject Motions; + public JsonArray Expressions; } public class SerializableGroup diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Json.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Json.cs index 36fe956..c3c9927 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Json.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismMotion3Json.cs @@ -1,10 +1,12 @@ // File Format Specifications // https://github.com/Live2D/CubismSpecs/blob/master/FileFormats/motion3.json.md +using AssetStudio; +using CubismLive2DExtractor.CubismJsonConverters; using System; using System.Collections.Generic; using System.Linq; -using AssetStudio; +using System.Text.Json.Serialization; namespace CubismLive2DExtractor { @@ -36,6 +38,7 @@ namespace CubismLive2DExtractor public string Id; public float FadeInTime; public float FadeOutTime; + [JsonConverter(typeof(MyJsonConverterFloatList))] public List Segments; } diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs index d75b083..cc2dc3a 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismParsers.cs @@ -1,14 +1,18 @@ -using System; +using AssetStudio; +using CubismLive2DExtractor.CubismJsonConverters; +using CubismLive2DExtractor.CubismUnityClasses; +using System; using System.Collections.Specialized; using System.Linq; -using AssetStudio; -using CubismLive2DExtractor.CubismUnityClasses; -using Newtonsoft.Json; +using System.Text.Json; +using System.Text.Json.Serialization; namespace CubismLive2DExtractor { public static class CubismParsers { + public static readonly JsonSerializerOptions CubismJsonOptions; + public enum CubismMonoBehaviourType { FadeController, @@ -24,9 +28,21 @@ namespace CubismLive2DExtractor RenderTexture, } + static CubismParsers() + { + CubismJsonOptions = new JsonSerializerOptions + { + Converters = { new MyJsonConverterFloat(asDecimal: true) }, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + PropertyNameCaseInsensitive = true, + IncludeFields = true, + WriteIndented = true, + }; + } + public static string ParsePhysics(OrderedDictionary physicsDict, float motionFps) { - var cubismPhysicsRig = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(physicsDict)).Rig; + var cubismPhysicsRig = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(physicsDict, CubismJsonOptions), CubismJsonOptions).Rig; var physicsSettings = new CubismPhysics3Json.SerializablePhysicsSettings[cubismPhysicsRig.SubRigs.Length]; for (var i = 0; i < physicsSettings.Length; i++) @@ -129,7 +145,10 @@ namespace CubismLive2DExtractor }, PhysicsSettings = physicsSettings }; - return JsonConvert.SerializeObject(physicsJson, Formatting.Indented, new MyJsonConverter2()); + var physicsOptions = new JsonSerializerOptions(CubismJsonOptions); + physicsOptions.Converters.Clear(); + physicsOptions.Converters.Add(new MyJsonConverterFloat()); + return JsonSerializer.Serialize(physicsJson, physicsOptions); } public static OrderedDictionary ParseMonoBehaviour(MonoBehaviour m_MonoBehaviour, CubismMonoBehaviourType cubismMonoBehaviourType, AssemblyLoader assemblyLoader) diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismFadeMotionData.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismFadeMotionData.cs index f5e6272..d00541f 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismFadeMotionData.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismFadeMotionData.cs @@ -1,5 +1,5 @@ -using System; -using AssetStudio; +using AssetStudio; +using System; namespace CubismLive2DExtractor.CubismUnityClasses { diff --git a/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismPhysics.cs b/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismPhysics.cs index 210c705..6f54afd 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismPhysics.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/CubismUnityClasses/CubismPhysics.cs @@ -1,5 +1,6 @@ using AssetStudio; -using Newtonsoft.Json; +using CubismLive2DExtractor.CubismJsonConverters; +using System.Text.Json.Serialization; namespace CubismLive2DExtractor.CubismUnityClasses { @@ -33,6 +34,7 @@ namespace CubismLive2DExtractor.CubismUnityClasses public float AngleScale { get; set; } public float Weight { get; set; } public CubismPhysicsSourceComponent SourceComponent { get; set; } + [JsonConverter(typeof(MyJsonConverterBool))] public bool IsInverted { get; set; } } @@ -50,6 +52,7 @@ namespace CubismLive2DExtractor.CubismUnityClasses public float AngleScale { get; set; } public float Weight { get; set; } public CubismPhysicsSourceComponent SourceComponent { get; set; } + [JsonConverter(typeof(MyJsonConverterBool))] public bool IsInverted { get; set; } } @@ -71,7 +74,7 @@ namespace CubismLive2DExtractor.CubismUnityClasses public sealed class CubismPhysics : MonoBehaviour { - [JsonProperty("_rig")] + [JsonPropertyName("_rig")] public CubismPhysicsRig Rig { get; set; } } } diff --git a/AssetStudioUtility/CubismLive2DExtractor/Live2DExtractor.cs b/AssetStudioUtility/CubismLive2DExtractor/Live2DExtractor.cs index 732c961..28db231 100644 --- a/AssetStudioUtility/CubismLive2DExtractor/Live2DExtractor.cs +++ b/AssetStudioUtility/CubismLive2DExtractor/Live2DExtractor.cs @@ -6,8 +6,6 @@ using AssetStudio; using AssetStudio.Addons.CubismLive2D; using CubismLive2DExtractor.CubismUnityClasses; -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using System; using System.Collections.Concurrent; using System.Collections.Generic; @@ -15,6 +13,8 @@ using System.Collections.Specialized; using System.IO; using System.Linq; using System.Text; +using System.Text.Json; +using System.Text.Json.Nodes; using System.Threading.Tasks; using static CubismLive2DExtractor.CubismParsers; using Object = AssetStudio.Object; @@ -315,7 +315,7 @@ namespace CubismLive2DExtractor #endregion #region motion3.json - var motions = new SortedDictionary(); + var motions = new SortedDictionary(); var destMotionPath = Path.Combine(destPath, "motions") + Path.DirectorySeparatorChar; var motionFps = 0f; @@ -327,7 +327,7 @@ namespace CubismLive2DExtractor var fadeMotionLstDict = ParseMonoBehaviour(FadeMotionLst, CubismMonoBehaviourType.FadeMotionList, Assembly); if (fadeMotionLstDict != null) { - var cubismFadeList = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(fadeMotionLstDict)); + var cubismFadeList = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(fadeMotionLstDict, CubismJsonOptions), CubismJsonOptions); var fadeMotionAssetSet = new HashSet(); foreach (var motionPPtr in cubismFadeList.CubismFadeMotionObjects) { @@ -389,7 +389,7 @@ namespace CubismLive2DExtractor #endregion #region exp3.json - var expressions = new JArray(); + var expressions = new JsonArray(); var destExpressionPath = Path.Combine(destPath, "expressions") + Path.DirectorySeparatorChar; if (ExpressionLst != null) //Expressions from Expression List @@ -398,7 +398,7 @@ namespace CubismLive2DExtractor var expLstDict = ParseMonoBehaviour(ExpressionLst, CubismMonoBehaviourType.ExpressionList, Assembly); if (expLstDict != null) { - var cubismExpList = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(expLstDict)); + var cubismExpList = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(expLstDict, CubismJsonOptions), CubismJsonOptions); var expAssetSet = new HashSet(); foreach (var expPPtr in cubismExpList.CubismExpressionObjects) { @@ -427,14 +427,14 @@ namespace CubismLive2DExtractor if (expressionDict == null) continue; - var expression = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(expressionDict)); + var expression = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(expressionDict, CubismJsonOptions), CubismJsonOptions); - expressions.Add(new JObject + expressions.Add(new JsonObject { - { "Name", expressionName }, - { "File", $"expressions/{expressionName}.exp3.json" } + ["Name"] = expressionName, + ["File"] = $"expressions/{expressionName}.exp3.json", }); - File.WriteAllText($"{destExpressionPath}{expressionName}.exp3.json", JsonConvert.SerializeObject(expression, Formatting.Indented)); + File.WriteAllBytes($"{destExpressionPath}{expressionName}.exp3.json", JsonSerializer.SerializeToUtf8Bytes(expression, CubismJsonOptions)); } #endregion @@ -519,16 +519,16 @@ namespace CubismLive2DExtractor Physics = isPhysicsExported ? $"{modelName}.physics3.json" : null, Pose = isPoseExported ? $"{modelName}.pose3.json" : null, DisplayInfo = isCdiExported ? $"{modelName}.cdi3.json" : null, - Motions = JObject.FromObject(motions), + Motions = new JsonObject(motions), Expressions = expressions, }, Groups = groups.ToArray() }; - File.WriteAllText($"{destPath}{modelName}.model3.json", JsonConvert.SerializeObject(model3, Formatting.Indented)); + File.WriteAllBytes($"{destPath}{modelName}.model3.json", JsonSerializer.SerializeToUtf8Bytes(model3, CubismJsonOptions)); #endregion } - private void ExportFadeMotions(string destMotionPath, SortedDictionary motions, ref float fps) + private void ExportFadeMotions(string destMotionPath, SortedDictionary motions, ref float fps) { Directory.CreateDirectory(destMotionPath); foreach (var fadeMotionMono in FadeMotions) @@ -536,8 +536,8 @@ namespace CubismLive2DExtractor var fadeMotionDict = ParseMonoBehaviour(fadeMotionMono, CubismMonoBehaviourType.FadeMotion, Assembly); if (fadeMotionDict == null) continue; - - var fadeMotion = JsonConvert.DeserializeObject(JsonConvert.SerializeObject(fadeMotionDict)); + + var fadeMotion = JsonSerializer.Deserialize(JsonSerializer.SerializeToUtf8Bytes(fadeMotionDict, CubismJsonOptions), CubismJsonOptions); if (fadeMotion.ParameterIds.Length == 0) continue; @@ -551,13 +551,13 @@ namespace CubismLive2DExtractor if (motions.ContainsKey(animName)) continue; } - var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json")); - motions.Add(animName, new JArray(motionPath)); - File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter())); + var motionPath = new JsonObject { ["File"] = $"motions/{animName}.motion3.json" }; + motions.Add(animName, new JsonArray(motionPath)); + File.WriteAllBytes($"{destMotionPath}{animName}.motion3.json", JsonSerializer.SerializeToUtf8Bytes(motionJson, CubismJsonOptions)); } } - private void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, SortedDictionary motions, ref float fps) + private void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, SortedDictionary motions, ref float fps) { if (converter == null) return; @@ -584,9 +584,9 @@ namespace CubismLive2DExtractor if (motions.ContainsKey(animName)) continue; } - var motionPath = new JObject(new JProperty("File", $"motions/{animName}.motion3.json")); - motions.Add(animName, new JArray(motionPath)); - File.WriteAllText($"{destMotionPath}{animName}.motion3.json", JsonConvert.SerializeObject(motionJson, Formatting.Indented, new MyJsonConverter())); + var motionPath = new JsonObject { ["File"] = $"motions/{animName}.motion3.json" }; + motions.Add(animName, new JsonArray(motionPath)); + File.WriteAllBytes($"{destMotionPath}{animName}.motion3.json", JsonSerializer.SerializeToUtf8Bytes(motionJson, CubismJsonOptions)); } } @@ -631,7 +631,7 @@ namespace CubismLive2DExtractor { poseJson.Groups[i++] = nodeList.ToArray(); } - File.WriteAllText($"{destPath}{modelName}.pose3.json", JsonConvert.SerializeObject(poseJson, Formatting.Indented)); + File.WriteAllBytes($"{destPath}{modelName}.pose3.json", JsonSerializer.SerializeToUtf8Bytes(poseJson, CubismJsonOptions)); return true; } @@ -681,7 +681,7 @@ namespace CubismLive2DExtractor if (parts.Count == 0 && parameters.Count == 0) return false; - File.WriteAllText($"{destPath}{modelName}.cdi3.json", JsonConvert.SerializeObject(cdiJson, Formatting.Indented)); + File.WriteAllBytes($"{destPath}{modelName}.cdi3.json", JsonSerializer.SerializeToUtf8Bytes(cdiJson, CubismJsonOptions)); return true; } diff --git a/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter.cs b/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter.cs deleted file mode 100644 index c8056e9..0000000 --- a/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter.cs +++ /dev/null @@ -1,35 +0,0 @@ -using Newtonsoft.Json; -using System; -using System.Collections.Generic; - -namespace CubismLive2DExtractor -{ - public class MyJsonConverter : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return objectType == typeof(List); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - writer.WriteStartArray(); - Convert(writer, (List)value); - writer.WriteEndArray(); - } - - private void Convert(JsonWriter writer, List array) - { - foreach (var n in array) - { - var v = n.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture); - writer.WriteRawValue(v); - } - } - } -} \ No newline at end of file diff --git a/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter2.cs b/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter2.cs deleted file mode 100644 index 89e4256..0000000 --- a/AssetStudioUtility/CubismLive2DExtractor/MyJsonConverter2.cs +++ /dev/null @@ -1,28 +0,0 @@ -using System; -using Newtonsoft.Json; - -namespace CubismLive2DExtractor -{ - public class MyJsonConverter2 : JsonConverter - { - public override bool CanConvert(Type objectType) - { - return objectType == typeof(float); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - throw new NotImplementedException(); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - Convert(writer, (float)value); - } - - private void Convert(JsonWriter writer, float value) - { - writer.WriteRawValue(value.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture)); - } - } -}