mirror of
https://github.com/aelurum/AssetStudio.git
synced 2026-11-14 11:18:47 -05:00
Migrate to System.Text.Json in Live2D exporter
- [exp3.json] Fixed format of Blend values (there should be strings according to the official specification) - Fixed BlendType enum
This commit is contained in:
@@ -9,7 +9,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Mono.Cecil" Version="0.11.6" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup Condition=" !$(TargetFramework.Contains('windows')) ">
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
{
|
||||
public enum BlendType
|
||||
{
|
||||
Overwrite,
|
||||
Add,
|
||||
Multiply,
|
||||
Overwrite,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace CubismLive2DExtractor.CubismJsonConverters
|
||||
{
|
||||
public sealed class MyJsonConverterBool : JsonConverter<bool>
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<float>
|
||||
{
|
||||
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<float>(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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+43
@@ -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<List<float>>
|
||||
{
|
||||
public override List<float> Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
|
||||
{
|
||||
return JsonSerializer.Deserialize<List<float>>(ref reader, new JsonSerializerOptions
|
||||
{
|
||||
NumberHandling = options.NumberHandling
|
||||
});
|
||||
}
|
||||
|
||||
public override void Write(Utf8JsonWriter writer, List<float> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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<float> Segments;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<CubismPhysics>(JsonConvert.SerializeObject(physicsDict)).Rig;
|
||||
var cubismPhysicsRig = JsonSerializer.Deserialize<CubismPhysics>(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)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
using System;
|
||||
using AssetStudio;
|
||||
using AssetStudio;
|
||||
using System;
|
||||
|
||||
namespace CubismLive2DExtractor.CubismUnityClasses
|
||||
{
|
||||
|
||||
@@ -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; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<string, JArray>();
|
||||
var motions = new SortedDictionary<string, JsonNode>();
|
||||
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<CubismFadeMotionList>(JsonConvert.SerializeObject(fadeMotionLstDict));
|
||||
var cubismFadeList = JsonSerializer.Deserialize<CubismFadeMotionList>(JsonSerializer.SerializeToUtf8Bytes(fadeMotionLstDict, CubismJsonOptions), CubismJsonOptions);
|
||||
var fadeMotionAssetSet = new HashSet<MonoBehaviour>();
|
||||
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<CubismExpressionList>(JsonConvert.SerializeObject(expLstDict));
|
||||
var cubismExpList = JsonSerializer.Deserialize<CubismExpressionList>(JsonSerializer.SerializeToUtf8Bytes(expLstDict, CubismJsonOptions), CubismJsonOptions);
|
||||
var expAssetSet = new HashSet<MonoBehaviour>();
|
||||
foreach (var expPPtr in cubismExpList.CubismExpressionObjects)
|
||||
{
|
||||
@@ -427,14 +427,14 @@ namespace CubismLive2DExtractor
|
||||
if (expressionDict == null)
|
||||
continue;
|
||||
|
||||
var expression = JsonConvert.DeserializeObject<CubismExpression3Json>(JsonConvert.SerializeObject(expressionDict));
|
||||
var expression = JsonSerializer.Deserialize<CubismExpression3Json>(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<string, JArray> motions, ref float fps)
|
||||
private void ExportFadeMotions(string destMotionPath, SortedDictionary<string, JsonNode> 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<CubismFadeMotionData>(JsonConvert.SerializeObject(fadeMotionDict));
|
||||
|
||||
var fadeMotion = JsonSerializer.Deserialize<CubismFadeMotionData>(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<string, JArray> motions, ref float fps)
|
||||
private void ExportClipMotions(string destMotionPath, CubismMotion3Converter converter, SortedDictionary<string, JsonNode> 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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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<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)
|
||||
{
|
||||
writer.WriteStartArray();
|
||||
Convert(writer, (List<float>)value);
|
||||
writer.WriteEndArray();
|
||||
}
|
||||
|
||||
private void Convert(JsonWriter writer, List<float> array)
|
||||
{
|
||||
foreach (var n in array)
|
||||
{
|
||||
var v = n.ToString("0.###", System.Globalization.CultureInfo.InvariantCulture);
|
||||
writer.WriteRawValue(v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user