添加对 Core 的直接引用

This commit is contained in:
OLDREDSTONE
2025-03-25 15:49:57 +08:00
parent 24907abedb
commit 06c19bf10a
296 changed files with 24961 additions and 2 deletions
@@ -0,0 +1,51 @@
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Events;
using System.Text.RegularExpressions;
namespace RhythmBase.Converters
{
internal partial class AnchorStyleConverter : JsonConverter<FloatingText.AnchorStyle>
{
public override void WriteJson(JsonWriter writer, FloatingText.AnchorStyle value, JsonSerializer serializer)
{
var horizontal = value & (FloatingText.AnchorStyle.Left | FloatingText.AnchorStyle.Right);
var vertical = value & (FloatingText.AnchorStyle.Upper | FloatingText.AnchorStyle.Lower);
writer.WriteValue(
(vertical == 0 ?
"Middle"
: vertical.ToString())
+ horizontal.ToString()
);
}
public override FloatingText.AnchorStyle ReadJson(JsonReader reader, Type objectType, FloatingText.AnchorStyle existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JToken token = JToken.ReadFrom(reader);
string JString = token.ToObject<string>() ?? throw new Exceptions.ConvertingException("Cannot read the anchor.");
Match match = AnchorStyleRegex().Match(JString);
if (!match.Success)
throw new Exceptions.ConvertingException(token, $"Illegal Anchor: {JString}");
FloatingText.AnchorStyle result = FloatingText.AnchorStyle.Center;
result |= match.Groups[1].Value switch
{
"Upper" => FloatingText.AnchorStyle.Upper,
"Lower" => FloatingText.AnchorStyle.Lower,
_ => 0,
};
result |= match.Groups[2].Value switch
{
"Left" => FloatingText.AnchorStyle.Left,
"Right" => FloatingText.AnchorStyle.Right,
_ => 0,
};
return result;
}
[GeneratedRegex("(Upper|Middle|Lower)(Left|Center|Right)")]
private static partial Regex AnchorStyleRegex();
}
}
@@ -0,0 +1,3 @@
namespace RhythmBase.Converters
{
}
@@ -0,0 +1,3 @@
namespace RhythmBase.Converters
{
}
@@ -0,0 +1,35 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Settings;
using System.Diagnostics;
namespace RhythmBase.Converters
{
internal class BaseDecorationActionConverter<TEvent>(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseEventConverter<TEvent>(level, inputSettings) where TEvent : BaseDecorationAction
{
public override TEvent? GetDeserializedObject(JObject jobj, Type objectType, TEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
TEvent? obj = base.GetDeserializedObject(jobj, objectType, existingValue, hasExistingValue, serializer);
if (obj is null) return obj;
string decoId = jobj["target"]?.ToObject<string>()!;
DecorationEventCollection? Parent = level.ModifiableDecorations.FirstOrDefault(i => i.Id == decoId);
if (Parent == null && obj.Type != EventType.Comment)
switch (settings.UnreadableEventsHandling)
{
case UnreadableEventHandling.Store:
settings.UnreadableEvents.Add((jobj,$"Cannot find the decoration with id {decoId}."));
return default;
case UnreadableEventHandling.ThrowException:
#if DEBUG
Debugger.Log(2, "cate", "");
return default;
#else
throw new ConvertingException(string.Format("Cannot find the decoration \"{0}\" at {1}", jobj["target"], obj));
#endif
}
obj._parent = Parent!;
return obj;
}
}
}
@@ -0,0 +1,66 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Exceptions;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class BaseEventConverter<TEvent>(RDLevel level, LevelReadOrWriteSettings inputSettings) : JsonConverter<TEvent> where TEvent : IBaseEvent
{
public override bool CanRead => _canread;
public override bool CanWrite => _canwrite;
public override void WriteJson(JsonWriter writer, TEvent? value, JsonSerializer serializer)
{
if (value == null)
throw new ConvertingException(($"Event is null"));
serializer.Formatting = Formatting.None;
writer.WriteRawValue(JsonConvert.SerializeObject(SetSerializedObject(value, serializer)));
serializer.Formatting = Formatting.Indented;
}
public override TEvent? ReadJson(JsonReader reader, Type objectType, TEvent? existingValue, bool hasExistingValue, JsonSerializer serializer) => GetDeserializedObject((JObject)JToken.ReadFrom(reader), objectType, existingValue, hasExistingValue, serializer);
public virtual TEvent? GetDeserializedObject(JObject jobj, Type objectType, TEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JToken? typeToken = (jobj["type"])
?? throw new Exceptions.ConvertingException(jobj, new Exception($"Missing property \"{jobj["type"]}\". path \"{jobj.Path}\""));
Type SubClassType = Utils.EventTypeUtils.ToType(typeToken.ToObject<string>()
?? throw new Exceptions.ConvertingException(jobj, new Exception($"Missing property \"{typeToken}\". path \"{jobj.Path}\"")));
if (SubClassType == null)
if (jobj["target"] != null)
SubClassType = typeof(CustomDecorationEvent);
else if (jobj["row"] != null)
SubClassType = typeof(CustomRowEvent);
else
SubClassType = typeof(CustomEvent);
_canread = false;
existingValue = (TEvent?)jobj.ToObject(SubClassType, serializer)
?? throw new ConvertingException(jobj, new Exception($"Cannot convert this event: \"{jobj}\". path \"{jobj.Path}\""));
_canread = true;
((BaseEvent)(object)existingValue)._beat = level.Calculator.BeatOf(
uint.Parse(((string?)jobj["bar"])
?? throw new Exception($"Missing property \"{jobj["bar"]}\".path \"{jobj.Path}\"")),
float.Parse((string?)jobj["beat"] ?? 1.ToString()));
return existingValue;
}
public virtual JObject SetSerializedObject(TEvent value, JsonSerializer serializer)
{
_canwrite = false;
JObject JObj = JObject.FromObject(value, serializer);
_canwrite = true;
JObj.Remove("type");
ValueTuple<uint, float> b = value.Beat.BarBeat;
JToken s = JObj.First ?? throw new ConvertingException($"Internal error: Missing properties. path \"{JObj.Path}\"");
s.AddBeforeSelf(new JProperty("bar", b.Item1));
if (value is not IBarBeginningEvent)
s.AddBeforeSelf(new JProperty("beat", b.Item2));
s.AddBeforeSelf(new JProperty("type", value.Type.ToString()));
if (JObj.Value<string>("tag") is string str && string.IsNullOrEmpty(str))
JObj.Property("tag")?.Remove();
return JObj;
}
protected readonly RDLevel level = level;
protected readonly LevelReadOrWriteSettings settings = inputSettings;
private bool _canread = true;
private bool _canwrite = true;
}
}
@@ -0,0 +1,49 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Exceptions;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class BaseRowActionConverter<TEvent>(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseEventConverter<TEvent>(level, inputSettings) where TEvent : BaseRowAction
{
public override TEvent? GetDeserializedObject(JObject jobj, Type objectType, TEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
TEvent? obj = base.GetDeserializedObject(jobj, objectType, existingValue, hasExistingValue, serializer);
if (obj is null) return obj;
short rowId = jobj["row"]?.ToObject<short>() ?? throw new ConvertingException("Cannot read the property row.");
if (rowId == -1)
{
if (obj.Type != EventType.TintRows)
{
switch (settings.UnreadableEventsHandling)
{
case UnreadableEventHandling.Store:
settings.UnreadableEvents.Add((jobj, $"Cannot find the row with id {rowId}."));
return default;
case UnreadableEventHandling.ThrowException:
throw new ConvertingException($"Cannot find the row \"{jobj["target"]}\" at {obj}");
}
}
}
else if (rowId >= level.Rows.Count)
{
switch (settings.UnreadableEventsHandling)
{
case UnreadableEventHandling.Store:
settings.UnreadableEvents.Add((jobj, $"The row id {rowId} out of range."));
return default;
case UnreadableEventHandling.ThrowException:
throw new ConvertingException($"The row id {rowId} out of range.");
}
}
else
{
RowEventCollection Parent = level.ModifiableRows[(int)rowId];
obj._parent = Parent;
}
return obj;
}
}
}
@@ -0,0 +1,34 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Utils;
namespace RhythmBase.Converters
{
internal class BookmarkConverter(BeatCalculator calculator) : JsonConverter<Bookmark>
{
public override void WriteJson(JsonWriter writer, Bookmark? value, JsonSerializer serializer)
{
var beat = value?.Beat.BarBeat ??throw new RhythmBase.Exceptions.ConvertingException("Cannot write the bookmark.");
writer.WriteStartObject();
writer.WritePropertyName("bar");
writer.WriteValue(beat.bar);
writer.WritePropertyName("beat");
writer.WriteValue(beat.beat);
writer.WritePropertyName("color");
writer.WriteValue((int)value.Color);
writer.WriteEndObject();
}
public override Bookmark ReadJson(JsonReader reader, Type objectType, Bookmark? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JToken jobj = JToken.ReadFrom(reader);
return new Bookmark
{
Beat = calculator.BeatOf(jobj["bar"]!.ToObject<uint>(), jobj["beat"]!.ToObject<float>()),
Color = Enum.Parse<Bookmark.BookmarkColors>((string)jobj["color"]!)
};
}
private readonly BeatCalculator calculator = calculator;
}
}
@@ -0,0 +1,34 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
namespace RhythmBase.Converters
{
internal class CharacterConverter : JsonConverter<RDCharacter>
{
public override void WriteJson(JsonWriter writer, RDCharacter value, JsonSerializer serializer)
{
writer.WriteValue(
value.IsCustom
? value.CustomCharacter == null
? ""
: $"custom:{value.CustomCharacter}"
: value.Character.ToString());
}
public override RDCharacter ReadJson(JsonReader reader, Type objectType, RDCharacter existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string value = JToken.ReadFrom(reader).ToObject<string>()!;
RDCharacter ReadJson;
if (value.StartsWith("custom:"))
{
string name = value[7..];
ReadJson = name;
}
else
{
ReadJson = Enum.Parse<RDCharacters>(value);
}
return ReadJson;
}
}
}
@@ -0,0 +1,18 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using System.Text.RegularExpressions;
namespace RhythmBase.Converters
{
internal class ColorConverter : JsonConverter<RDColor>
{
public override void WriteJson(JsonWriter writer, RDColor value, JsonSerializer serializer) => writer.WriteValue(value.ToString("rrggbbaa"));
public override RDColor ReadJson(JsonReader reader, Type objectType, RDColor existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string JString = JToken.Load(reader).Value<string>() ?? throw new RhythmBase.Exceptions.ConvertingException("Cannot read the color.");
return RDColor.FromRgba(JString);
}
}
}
@@ -0,0 +1,85 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using System.Text.RegularExpressions;
namespace RhythmBase.Converters
{
internal partial class ConditionConverter(List<BaseConditional> Conditionals) : JsonConverter<Condition>
{
public override void WriteJson(JsonWriter writer, Condition? value, JsonSerializer serializer) => writer.WriteValue(value!.Serialize());
public override Condition ReadJson(JsonReader reader, Type objectType, Condition? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string s = JToken.Load(reader).ToObject<string>()!;
Condition Value = new();
//MatchCollection ConditionIds = ConditionsRegex().Matches(J);
//foreach (Match match in ConditionIds)
//{
// BaseConditional Parent = (from i in conditionals
// where i.Id == int.Parse(ConditionIndexRegex().Match(match.Value).Value)
// select i).First();
// Value.ConditionLists.Add(new ValueTuple<bool, BaseConditional>(match.Value[0] != '~', Parent));
//}
//Value.Duration = float.Parse (ConditionDurationRegex().Match(J).Value);
int p = 0;
do
{
bool active = ReadActive(s, ref p);
int index = ReadInt(s, ref p) - 1;
if (index < conditionals.Count)
{
Value.ConditionLists.Add((active, conditionals[index]));
}
}
while (!ReadIsEndList(s, ref p));
Value.Duration = ReadFloat(s, ref p);
return Value;
}
private static int ReadInt(string s, ref int p)
{
int r = 0;
while (p < s.Length && char.IsAsciiDigit(s[p]))
{
r *= 10;
r += s[p] - '0';
p++;
}
return r;
}
private static float ReadFloat(string s, ref int p)
{
float r = ReadInt(s, ref p);
if (p < s.Length && s[p] == '.')
{
p++;
float f = 0.1f;
while (p < s.Length && char.IsAsciiDigit(s[p]))
{
r += f * (s[p] - '0');
f *= 0.1f;
p++;
}
}
return r;
}
private static bool ReadActive(string s, ref int p)
{
if (p >= s.Length || s[p] == '~')
{
p++;
return false;
}
return true;
}
private static bool ReadIsEndList(string s, ref int p) => p < s.Length && s[p++] == 'd';
private readonly List<BaseConditional> conditionals = Conditionals;
[GeneratedRegex("~?\\d+(?=[&d])")]
private static partial Regex ConditionsRegex();
[GeneratedRegex("\\d+")]
private static partial Regex ConditionIndexRegex();
[GeneratedRegex("(?<=d)[\\d\\.]+")]
private static partial Regex ConditionDurationRegex();
}
}
@@ -0,0 +1,25 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using RhythmBase.Components;
namespace RhythmBase.Converters
{
internal class ConditionalConverter : JsonConverter<BaseConditional>
{
public override void WriteJson(JsonWriter writer, BaseConditional? value, JsonSerializer serializer) => writer.WriteRawValue(JsonConvert.SerializeObject(value, new JsonSerializerSettings
{
Converters = { new StringEnumConverter() },
ContractResolver = new CamelCasePropertyNamesContractResolver()
}));
public override BaseConditional ReadJson(JsonReader reader, Type objectType, BaseConditional? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JObject J = JObject.Load(reader);
Type? SubClassType = Type.GetType($"{typeof(BaseConditional).Namespace}.Conditions.{J["type"]}Condition");
return SubClassType == null
? throw new Exceptions.ConvertingException(J, new Exception($"Unreadable condition: \"{J["type"]}\". path \"{reader.Path}\""))
: (BaseConditional)J.ToObject(SubClassType)!;
}
}
}
@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class CustomDecorationEventConverter(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseDecorationActionConverter<CustomDecorationEvent>(level, inputSettings)
{
public override CustomDecorationEvent? GetDeserializedObject(JObject jobj, Type objectType, CustomDecorationEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
CustomDecorationEvent? result = base.GetDeserializedObject(jobj, objectType, existingValue, hasExistingValue, serializer);
if (result != null)
result.Data = jobj;
return result;
}
public override JObject SetSerializedObject(CustomDecorationEvent value, JsonSerializer serializer)
{
JObject jobj = base.SetSerializedObject(value, serializer);
JToken data = value.Data.DeepClone();
foreach (KeyValuePair<string, JToken?> item in jobj)
{
data[item.Key] = item.Value;
}
return (JObject)data;
}
}
}
@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class CustomEventConverter(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseEventConverter<CustomEvent>(level, inputSettings)
{
public override CustomEvent? GetDeserializedObject(JObject jobj, Type objectType, CustomEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
CustomEvent? result = base.GetDeserializedObject(jobj, objectType, existingValue, hasExistingValue, serializer);
if(result == null) return null;
result.Data = jobj;
return result;
}
public override JObject SetSerializedObject(CustomEvent value, JsonSerializer serializer)
{
JObject jobj = base.SetSerializedObject(value, serializer);
JObject data = (JObject)value.Data.DeepClone();
foreach (KeyValuePair<string, JToken?> item in data)
{
jobj[item.Key] = item.Value;
}
return jobj;
}
}
}
@@ -0,0 +1,29 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class CustomRowEventConverter(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseRowActionConverter<CustomRowEvent>(level, inputSettings)
{
public override CustomRowEvent? GetDeserializedObject(JObject jobj, Type objectType, CustomRowEvent? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
CustomRowEvent? result = base.GetDeserializedObject(jobj, objectType, existingValue, hasExistingValue, serializer);
if (result == null) return null;
result.Data = jobj;
return result;
}
public override JObject SetSerializedObject(CustomRowEvent value, JsonSerializer serializer)
{
JObject jobj = base.SetSerializedObject(value, serializer);
JToken data = value.Data.DeepClone();
foreach (KeyValuePair<string, JToken?> item in jobj)
{
data[item.Key] = item.Value;
}
return (JObject)data;
}
}
}
@@ -0,0 +1,20 @@
using RhythmBase.Components.RichText;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Newtonsoft.Json;
using System.Threading.Tasks;
namespace RhythmBase.Converters
{
internal class DialogueListConverter : JsonConverter<RDDialogueExchange>
{
public override RDDialogueExchange? ReadJson(JsonReader reader, Type objectType, RDDialogueExchange? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, RDDialogueExchange? value, JsonSerializer serializer) => writer.WriteRawValue(value?.Serialize());
}
}
@@ -0,0 +1,36 @@
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Extensions;
namespace RhythmBase.Converters
{
internal class ExpressionConverter : JsonConverter<RDExpression>
{
public override void WriteJson(JsonWriter writer, RDExpression value, JsonSerializer serializer)
{
if (value.IsNumeric)
{
writer.WriteRawValue(value.NumericValue.ToString());
}
else
{
if (value.ExpressionValue.IsNullOrEmpty())
{
writer.WriteNull();
}
else
{
writer.WriteValue(string.Format("{{{0}}}", value.ExpressionValue));
}
}
}
public override RDExpression ReadJson(JsonReader reader, Type objectType, RDExpression existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string js = JToken.ReadFrom(reader).ToObject<string>() ?? throw new RhythmBase.Exceptions.ConvertingException("Cannot read the expression.");
RDExpression ReadJson = new(js.TrimStart('{').TrimEnd('}'));
return ReadJson;
}
}
}
@@ -0,0 +1,3 @@
namespace RhythmBase.Converters
{
}
@@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RhythmBase.Converters
{
internal class MilliSecondConverter : TimeConverter
{
public MilliSecondConverter() : base(TimeType.MiliSecond)
{
}
}
}
@@ -0,0 +1,78 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Extensions;
using System.Text.RegularExpressions;
namespace RhythmBase.Converters
{
internal partial class PanelColorConverter : JsonConverter<PaletteColor>
{
internal PanelColorConverter(RDColor[] list)
{
parent = list;
}
public override void WriteJson(JsonWriter writer, PaletteColor? value, JsonSerializer serializer)
{
if (value?.EnablePanel ?? throw new NotImplementedException())
{
writer.WriteValue(string.Format("pal{0}", value.PaletteIndex));
}
else
{
string s = value.Value.ToString().Replace("#", "");
string alpha = s[..2];
string rgb = s[2..];
if (value.EnableAlpha)
{
writer.WriteValue(rgb + alpha);
}
else
{
writer.WriteValue(rgb);
}
}
}
public override PaletteColor ReadJson(JsonReader reader, Type objectType, PaletteColor? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
JToken token = JToken.Load(reader);
string? JString = token.Value<string>();
if (JString.IsNullOrEmpty())
{
throw new Exceptions.ConvertingException(token, new Exception($"Unreadable color: \"{token}\". path \"{reader.Path}\""));
}
Match reg = PaletteColorRegex().Match(JString);
existingValue!.parent = parent;
if (reg.Success)
{
existingValue.PaletteIndex = int.Parse(reg.Groups[1].Value);
}
else
{
string s = JString.Replace("#", "");
string alpha = "";
if (s.Length > 6)
{
alpha = s[6..];
}
string rgb = s[..6];
if (s.Length > 6)
{
existingValue.Color = new RDColor?(RDColor.FromArgb(alpha + rgb));
}
else
{
existingValue.Color = new RDColor?(RDColor.FromRgba(rgb));
}
}
return existingValue;
}
private readonly RDColor[] parent;
[GeneratedRegex("pal(\\d+)")]
private static partial Regex PaletteColorRegex();
}
}
@@ -0,0 +1,32 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Events;
namespace RhythmBase.Converters
{
internal class PatternConverter : JsonConverter<Patterns[]>
{
public override void WriteJson(JsonWriter writer, Patterns[]? value, JsonSerializer serializer) => writer.WriteValue(Utils.Utils.GetPatternString(value ?? throw new RhythmBase.Exceptions.ConvertingException($"Pattern cannot be null.")));
public override Patterns[] ReadJson(JsonReader reader, Type objectType, Patterns[]? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string? pattern = JToken.ReadFrom(reader).ToObject<string>();
if (pattern == null || pattern.Length != 6)
throw new Exceptions.ConvertingException($"Invalid pattern: {pattern}");
existingValue ??= new Patterns[6];
for (int i = 0; i < 6; i++)
{
existingValue[i] = pattern[i] switch
{
'x' => Patterns.X,
'u' => Patterns.Up,
'd' => Patterns.Down,
'b' => Patterns.Banana,
'r' => Patterns.Return,
'-' => Patterns.None,
_ => throw new Exceptions.ConvertingException($"Invalid pattern character: {pattern[i]}")
};
}
return existingValue;
}
}
}
@@ -0,0 +1,148 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Extensions;
using System.Reflection;
namespace RhythmBase.Converters
{
internal class RDContractResolver : DefaultContractResolver
{
public static RDContractResolver Instance { get; } = new RDContractResolver();
public RDContractResolver() : base()
{
NamingStrategy = new CamelCaseNamingStrategy();
}
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty p = base.CreateProperty(member, memberSerialization);
Predicate<object>? f = null;
if (p.DeclaringType == typeof(RowEventCollection))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(RowEventCollection.RowToMimic) => i => ((RowEventCollection)i).RowToMimic >= 0,
_ => null
};
if (p.DeclaringType?.IsAssignableTo(typeof(BaseEvent)) == true)
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(BaseEvent.Active) => i => !((BaseEvent)i).Active,
_ => null
};
if (p.DeclaringType == typeof(MoveRow))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(MoveRow.CustomPosition) => i => ((MoveRow)i).Target == MoveRow.Targets.WholeRow,
_ => null
};
if (p.DeclaringType == typeof(SetVFXPreset))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(SetVFXPreset.Enable) => i => (i is SetVFXPreset e) && e.Preset is not SetVFXPreset.Presets.DisableAll,
nameof(SetVFXPreset.Threshold) => i => (i is SetVFXPreset e) && e.Enable && e.Preset == SetVFXPreset.Presets.Bloom,
nameof(SetVFXPreset.Intensity) => i => (i is SetVFXPreset e) && e.Enable && durationPresets.Contains(e.Preset) && e.Preset is not (SetVFXPreset.Presets.TileN or SetVFXPreset.Presets.CustomScreenScroll),
nameof(SetVFXPreset.Color) => i => (i is SetVFXPreset e) && e.Enable && (e.Preset is SetVFXPreset.Presets.Bloom or SetVFXPreset.Presets.Tutorial),
nameof(SetVFXPreset.FloatX) or
nameof(SetVFXPreset.FloatY) => i => (i is SetVFXPreset e) && e.Enable && (e.Preset is SetVFXPreset.Presets.TileN or SetVFXPreset.Presets.CustomScreenScroll),
nameof(SetVFXPreset.Ease) => i => (i is SetVFXPreset e) && e.Enable && durationPresets.Contains(e.Preset),
nameof(SetVFXPreset.Duration) => i => (i is SetVFXPreset e) && e.Enable && durationPresets.Contains(e.Preset),
_ => null
};
if (p.DeclaringType == typeof(TintRows))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(TintRows.Ease) or nameof(TintRows.Duration) => i => (i is TintRows e) && e.Duration != 0f,
_ => null
};
if (p.DeclaringType == typeof(Tint))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(Tint.Ease) or nameof(Tint.Duration) => i => (i is Tint e) && e.Duration != 0f,
_ => null
};
if (p.DeclaringType == typeof(Tile))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(Tile.TilingType) => i => (i is Tile e) && e.Speed is not null,
nameof(Tile.Interval) => i => (i is Tile e) && e.TilingType == Tile.TilingTypes.Pulse,
_ => null
};
if (p.DeclaringType == typeof(SoundSubType))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(SoundSubType.Filename) or
nameof(SoundSubType.Pan) or
nameof(SoundSubType.Offset) => i => (i is SoundSubType e) && e.Used,
nameof(SoundSubType.Volume) => i => (i is SoundSubType e) && e.Used && e.Volume != 100,
nameof(SoundSubType.Pitch) => i => (i is SoundSubType e) && e.Used && e.Pitch != 100,
_ => null
};
if (p.DeclaringType == typeof(SetGameSound))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(SetGameSound.Filename) or
nameof(SetGameSound.Pan) or
nameof(SetGameSound.Offset) => i => (i is SetGameSound e) &&
e.SoundType is not (
SoundTypes.ClapSoundHold or
SoundTypes.FreezeshotSound or
SoundTypes.BurnshotSound),
nameof(SetGameSound.Volume) => i => (i is SetGameSound e) &&
e.SoundType is not (
SoundTypes.ClapSoundHold or
SoundTypes.FreezeshotSound or
SoundTypes.BurnshotSound) && e.Volume != 100,
nameof(SetGameSound.Pitch) => i => (i is SetGameSound e) &&
e.SoundType is not (
SoundTypes.ClapSoundHold or
SoundTypes.FreezeshotSound or
SoundTypes.BurnshotSound) && e.Pitch != 100,
_ => null
};
if (p.DeclaringType == typeof(SetCountingSound))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(SetCountingSound.VoiceSource) => i => (i is SetCountingSound e) && e.VoiceSource == SetCountingSound.VoiceSources.Custom,
_ => null
};
if (p.DeclaringType == typeof(AddOneshotBeat))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(AddOneshotBeat.Skipshot) => i => (i is AddOneshotBeat e) && e.Skipshot,
nameof(AddOneshotBeat.FreezeBurnMode) => i => (i is AddOneshotBeat e) && e.FreezeBurnMode != null,
_ => null
};
if (p.DeclaringType == typeof(Comment))
f = p.PropertyName!.ToUpperCamelCase() switch
{
nameof(Comment.Target) => i => (i is Comment e) && e.Tab == Tabs.Decorations,
_ => null
};
if (f != null)
p.ShouldSerialize = f;
return p;
}
private static readonly SetVFXPreset.Presets[] durationPresets =
[
SetVFXPreset.Presets.HueShift,
SetVFXPreset.Presets.Brightness,
SetVFXPreset.Presets.Contrast,
SetVFXPreset.Presets.Saturation,
SetVFXPreset.Presets.Rain,
SetVFXPreset.Presets.Bloom,
SetVFXPreset.Presets.TileN,
SetVFXPreset.Presets.CustomScreenScroll,
SetVFXPreset.Presets.JPEG,
SetVFXPreset.Presets.Mosaic,
SetVFXPreset.Presets.ScreenWaves,
SetVFXPreset.Presets.Grain,
SetVFXPreset.Presets.Blizzard,
SetVFXPreset.Presets.Drawing,
SetVFXPreset.Presets.Aberration,
SetVFXPreset.Presets.Blur,
SetVFXPreset.Presets.RadialBlur,
SetVFXPreset.Presets.Dots,
SetVFXPreset.Presets.Tutorial,
];
}
}
@@ -0,0 +1,196 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Exceptions;
using RhythmBase.Extensions;
using RhythmBase.Settings;
using RhythmBase.Utils;
namespace RhythmBase.Converters
{
internal class RDLevelConverter : JsonConverter<RDLevel>
{
public RDLevelConverter(string location, LevelReadOrWriteSettings settings)
{
fileLocation = location;
this.settings = settings;
}
public RDLevelConverter(LevelReadOrWriteSettings settings)
{
this.settings = settings;
this.settings.PreloadAssets = false;
}
public override void WriteJson(JsonWriter writer, RDLevel? value, JsonSerializer serializer)
{
JsonSerializerSettings AllInOneSerializer = value!.GetSerializer(settings);
writer.Formatting = settings.Indented ? Formatting.Indented : Formatting.None;
writer.WriteStartObject();
writer.WritePropertyName("settings");
writer.WriteRawValue(JsonConvert.SerializeObject(value!.Settings, Formatting.Indented, AllInOneSerializer));
writer.WritePropertyName("rows");
writer.WriteStartArray();
foreach (RowEventCollection item in value.Rows)
writer.WriteRawValue(JsonConvert.SerializeObject(item, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WritePropertyName("decorations");
writer.WriteStartArray();
foreach (DecorationEventCollection item2 in value.Decorations)
writer.WriteRawValue(JsonConvert.SerializeObject(item2, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WritePropertyName("events");
writer.WriteStartArray();
foreach (IBaseEvent item3 in ((settings.InactiveEventsHandling == InactiveEventsHandling.Retain) ? value.Where(i => i.Active) : value.AsEnumerable()))
writer.WriteRawValue(JsonConvert.SerializeObject(item3, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WritePropertyName("conditionals");
writer.WriteStartArray();
foreach (BaseConditional item4 in value.Conditionals)
writer.WriteRawValue(JsonConvert.SerializeObject(item4, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WritePropertyName("bookmarks");
writer.WriteStartArray();
foreach (Bookmark item5 in value.Bookmarks)
writer.WriteRawValue(JsonConvert.SerializeObject(item5, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WritePropertyName("colorPalette");
writer.WriteStartArray();
foreach (RDColor item6 in value.ColorPalette)
writer.WriteRawValue(JsonConvert.SerializeObject(item6, Formatting.None, AllInOneSerializer));
writer.WriteEndArray();
writer.WriteEndObject();
writer.Close();
}
public override RDLevel ReadJson(JsonReader reader, Type objectType, RDLevel? existingValue, bool hasExistingValue, JsonSerializer serializer)
{
RDLevel outLevel = new()
{
_path = fileLocation
};
JsonSerializer AllInOneSerializer = JsonSerializer.Create(outLevel.GetSerializer(settings));
JArray JEvents = [];
JArray JBookmarks = [];
while (reader.Read())
{
string name = (string)reader.Value!;
reader.Read();
switch (name)
{
case "settings":
JObject jobj = JObject.Load(reader);
JToken? Mods = jobj["mods"];
if (Mods?.Type == JTokenType.String)
jobj["mods"] = new JArray(Mods);
outLevel.Settings = jobj.ToObject<Components.Settings>(AllInOneSerializer)!;
break;
case "rows":
JArray jarr1 = JArray.Load(reader);
outLevel.ModifiableRows.AddRange(jarr1.ToObject<List<RowEventCollection>>(AllInOneSerializer)!);
foreach (RowEventCollection row in outLevel.ModifiableRows)
{
row.Parent = outLevel;
}
break;
case "decorations":
JArray jarr2 = JArray.Load(reader);
outLevel.ModifiableDecorations.AddRange(jarr2.ToObject<List<DecorationEventCollection>>(AllInOneSerializer)!);
foreach (DecorationEventCollection deco in outLevel.ModifiableDecorations)
{
deco.Parent = outLevel;
}
break;
case "conditionals":
JArray jarr3 = JArray.Load(reader);
outLevel.Conditionals.AddRange(jarr3.ToObject<List<BaseConditional>>(AllInOneSerializer)!);
foreach (BaseConditional condi in outLevel.Conditionals)
condi.ParentCollection = outLevel.Conditionals;
break;
case "colorPalette":
JArray jarr4 = JArray.Load(reader);
RDColor[] array = jarr4.ToObject<RDColor[]>(AllInOneSerializer) ?? throw new ConvertingException("Cannot read the color palette.");
if (array.Length == 21)
for (int i = 0; i < array.Length; i++)
outLevel.ColorPalette[i] = array[i];
break;
case "events":
JEvents = JArray.Load(reader);
break;
case "bookmarks":
JBookmarks = JArray.Load(reader);
break;
default:
break;
}
}
reader.Close();
RDLevel ReadJson;
try
{
List<(FloatingText @event, int id)> FloatingTextCollection = [];
List<(AdvanceText @event, int id)> AdvanceTextCollection = [];
foreach (JToken item in JEvents)
{
if (!(settings.InactiveEventsHandling > InactiveEventsHandling.Retain && (item["active"]?.Value<bool>() ?? false)))
{
Type eventType = Utils.EventTypeUtils.ToType((string)item["type"]!);
if (eventType == null)
{
BaseEvent TempEvent;
if (item["target"] != null)
TempEvent = item.ToObject<CustomDecorationEvent>(AllInOneSerializer)!;
else if (item["row"] != null)
TempEvent = item.ToObject<CustomRowEvent>(AllInOneSerializer)!;
else
TempEvent = item.ToObject<CustomEvent>(AllInOneSerializer)!;
if (settings.InactiveEventsHandling == InactiveEventsHandling.Store && !TempEvent.Active)
settings.InactiveEvents.Add(TempEvent);
else
outLevel.Add(TempEvent);
}
else
{
BaseEvent TempEvent2 = (BaseEvent)item.ToObject(eventType, AllInOneSerializer)!;
if (TempEvent2 != null)
{
if (TempEvent2.Type != EventType.CustomEvent)
{
EventType type = TempEvent2.Type;
switch (type)
{
case EventType.FloatingText:
FloatingTextCollection.Add(((FloatingText)TempEvent2, (int)item["id"]!));
break;
case EventType.AdvanceText:
AdvanceTextCollection.Add(((AdvanceText)TempEvent2, (int)item["id"]!));
break;
}
}
if (settings.InactiveEventsHandling == InactiveEventsHandling.Store && !TempEvent2.Active)
settings.InactiveEvents.Add(TempEvent2);
else
outLevel.Add(TempEvent2);
}
}
}
}
foreach (var (@event, id) in AdvanceTextCollection)
{
FloatingText Parent = FloatingTextCollection.First(((FloatingText @event, int id) i) => i.id == id).@event;
Parent.Children.Add(@event);
@event.Parent = Parent;
}
outLevel.Bookmarks.AddRange(JBookmarks.ToObject<List<Bookmark>>(AllInOneSerializer)!);
ReadJson = outLevel;
}
catch (Exception ex)
{
if (outLevel.Settings.Version < 55)
throw new VersionTooLowException(outLevel.Settings.Version, ex);
throw new ConvertingException(ex);
}
return ReadJson;
}
private readonly string fileLocation = "";
private readonly LevelReadOrWriteSettings settings;
}
}
@@ -0,0 +1,118 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Extensions;
using System.Diagnostics.CodeAnalysis;
namespace RhythmBase.Converters
{
internal class RDPointsConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
writer.WriteStartArray();
if (value is RDPointNI v1)
{
writer.WriteValue(v1.X);
writer.WriteValue(v1.Y);
}
else if (value is RDPointN v2)
{
writer.WriteValue(v2.X);
writer.WriteValue(v2.Y);
}
else if (value is RDPointI v3)
{
writer.WriteValue(v3.X);
writer.WriteValue(v3.Y);
}
else if (value is RDPoint v4)
{
writer.WriteValue(v4.X);
writer.WriteValue(v4.Y);
}
else if (value is RDPointE v5)
{
if (v5.X != null)
writer.WriteValue(v5.X.Value.IsNumeric ? v5.X.Value.NumericValue : v5.X.Value.ExpressionValue);
else
writer.WriteNull();
if (v5.Y != null)
writer.WriteValue(v5.Y.Value.IsNumeric ? v5.Y.Value.NumericValue : v5.Y.Value.ExpressionValue);
else
writer.WriteNull();
}
else if (value is RDSizeNI v6)
{
writer.WriteValue(v6.Width);
writer.WriteValue(v6.Height);
}
else if (value is RDSizeN v7)
{
writer.WriteValue(v7.Width);
writer.WriteValue(v7.Height);
}
else if (value is RDSizeI v8)
{
writer.WriteValue(v8.Width);
writer.WriteValue(v8.Height);
}
else if (value is RDSize v9)
{
writer.WriteValue(v9.Width);
writer.WriteValue(v9.Height);
}
else if (value is RDSizeE v10)
{
RDSizeE temp2 = (value != null) ? v10 : default;
if (temp2.Width != null)
writer.WriteValue(temp2.Width.Value.IsNumeric ? temp2.Width.Value.NumericValue : temp2.Width.Value.ExpressionValue);
else
writer.WriteNull();
if (temp2.Height != null)
writer.WriteValue(temp2.Height.Value.IsNumeric ? temp2.Height.Value.NumericValue : temp2.Height.Value.ExpressionValue);
else
writer.WriteNull();
}
else
throw new NotImplementedException();
writer.WriteEndArray();
}
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
JToken ja = JToken.ReadFrom(reader);
object ReadJson;
if (objectType == typeof(RDPointNI) || objectType == typeof(RDPointNI?))
ReadJson = new RDPointNI(ja[0]!.ToObject<int>(), ja[1]!.ToObject<int>());
else if (objectType == typeof(RDPointN) || objectType == typeof(RDPointN?))
ReadJson = new RDPointN(ja[0]!.ToObject<float>(), ja[1]!.ToObject<float>());
else if (objectType == typeof(RDPointI) || objectType == typeof(RDPointI?))
ReadJson = new RDPointI(ja[0]?.ToObject<int?>(), ja[1]?.ToObject<int?>());
else if (objectType == typeof(RDPoint) || objectType == typeof(RDPoint?))
ReadJson = new RDPoint(ja[0]?.ToObject<float?>(), ja[1]?.ToObject<float?>());
else if (objectType == typeof(RDPointE) || objectType == typeof(RDPointE?))
ReadJson = new RDPointE(new RDExpression?(ja[0]!.ToString().IsNullOrEmpty()
? default
: ja[0]!.ToObject<RDExpression>()), new RDExpression?(ja[1]!.ToString().IsNullOrEmpty()
? default
: ja[1]!.ToObject<RDExpression>()));
else if (objectType == typeof(RDSizeNI) || objectType == typeof(RDSizeNI?))
ReadJson = new RDSizeNI(ja[0]!.ToObject<int>(), ja[1]!.ToObject<int>());
else if (objectType == typeof(RDSizeN) || objectType == typeof(RDSizeN?))
ReadJson = new RDSizeN(ja[0]!.ToObject<float>(), ja[1]!.ToObject<float>());
else if (objectType == typeof(RDSizeI) || objectType == typeof(RDSizeI?))
ReadJson = new RDSizeI(ja[0]?.ToObject<int?>(), ja[1]?.ToObject<int?>());
else if (objectType == typeof(RDSize) || objectType == typeof(RDSize?))
ReadJson = new RDSize(ja[0]?.ToObject<float?>(), ja[1]?.ToObject<float?>());
else if (objectType == typeof(RDSizeE) || objectType == typeof(RDSizeE?))
ReadJson = new RDSizeE(new RDExpression?(ja[0]!.ToString().IsNullOrEmpty()
? default
: ja[0]!.ToObject<RDExpression>()), new RDExpression?(ja[1]!.ToString().IsNullOrEmpty()
? default
: ja[1]!.ToObject<RDExpression>()));
else
throw new NotImplementedException();
return ReadJson;
}
public override bool CanConvert(Type objectType) => throw new NotImplementedException();
}
}
@@ -0,0 +1,74 @@
using Microsoft.VisualBasic.CompilerServices;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
namespace RhythmBase.Converters
{
internal class RoomConverter : JsonConverter
{
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
Type type = value!.GetType();
if (type == typeof(RDRoom))
{
writer.WriteStartArray();
foreach (int item in (((RDRoom?)value) ?? default).Rooms)
writer.WriteValue(item);
writer.WriteEndArray();
}
else if (type == typeof(RDSingleRoom))
{
writer.WriteStartArray();
writer.WriteValue((((RDSingleRoom?)value) ?? default).Value);
writer.WriteEndArray();
}
else
throw new NotImplementedException();
}
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
JToken token = JArray.Load(reader);
byte[]? J = token.ToObject<byte[]>();
if (J == null)
throw new Exceptions.ConvertingException(token, new Exception($"Unreadable room: \"{J}\". path \"{reader.Path}\""));
bool flag = objectType == typeof(RDRoom);
object ReadJson;
if (flag)
{
bool enableTop;
if (existingValue != null)
{
object obj = existingValue;
enableTop = ((obj != null) ? ((RDRoom)obj) : default).EnableTop;
}
else
{
enableTop = true;
}
existingValue = new RDRoom(enableTop);
foreach (byte item in J)
{
NewLateBinding.LateIndexSet(existingValue,
[
item,
true
], null);
}
ReadJson = existingValue;
}
else
{
flag = objectType == typeof(RDSingleRoom);
if (!flag)
{
throw new NotImplementedException();
}
ReadJson = new RDSingleRoom(J.Single());
}
return ReadJson;
}
public override bool CanConvert(Type objectType) => objectType == typeof(RDRoom) || objectType == typeof(RDSingleRoom);
}
}
@@ -0,0 +1,9 @@
namespace RhythmBase.Converters
{
internal class SecondConverter : TimeConverter
{
public SecondConverter() : base(TimeType.Second)
{
}
}
}
@@ -0,0 +1,36 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Events;
namespace RhythmBase.Converters
{
internal class TabsConverter : JsonConverter<Tabs>
{
public override void WriteJson(JsonWriter writer, Tabs value, JsonSerializer serializer) => writer.WriteValue(TabNames[(int)value]);
public override Tabs ReadJson(JsonReader reader, Type objectType, Tabs existingValue, bool hasExistingValue, JsonSerializer serializer)
{
string value = JToken.Load(reader).ToObject<string>()??throw new RhythmBase.Exceptions.ConvertingException("Cannot read the tab.");
int t = TabNames.ToList().IndexOf(value);
bool flag = t >= 0;
Tabs ReadJson;
if (flag)
{
ReadJson = (Tabs)t;
}
else
{
ReadJson = Tabs.Unknown;
}
return ReadJson;
}
private static readonly string[] TabNames =
[
"Song",
"Rows",
"Actions",
"Sprites",
"Rooms"
];
}
}
@@ -0,0 +1,25 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using RhythmBase.Components;
using RhythmBase.Events;
using RhythmBase.Settings;
namespace RhythmBase.Converters
{
internal class TagActionConverter(RDLevel level, LevelReadOrWriteSettings inputSettings) : BaseEventConverter<TagAction>(level, inputSettings)
{
public override JObject SetSerializedObject(TagAction value, JsonSerializer serializer)
{
JObject jobj = base.SetSerializedObject(value, serializer);
if (value.Tag == null)
{
jobj.Remove("tag");
}
else
{
jobj["tag"] = value.Tag;
}
jobj["Tag"] = value.ActionTag;
return jobj;
}
}
}
@@ -0,0 +1,66 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace RhythmBase.Converters
{
internal abstract class TimeConverter : JsonConverter<TimeSpan>
{
public TimeConverter()
{
_timeType = TimeType.MiliSecond;
}
public TimeConverter(TimeType type)
{
_timeType = type;
}
public override void WriteJson(JsonWriter writer, TimeSpan value, JsonSerializer serializer)
{
switch (_timeType)
{
case TimeType.Hour:
writer.WriteValue(value.TotalHours);
break;
case TimeType.Minute:
writer.WriteValue(value.TotalMinutes);
break;
case TimeType.Second:
writer.WriteValue(value.TotalSeconds);
break;
case TimeType.MiliSecond:
writer.WriteValue((int)value.TotalMilliseconds);
break;
case TimeType.Microsecond:
writer.WriteValue((int)value.TotalMicroseconds);
break;
default:
break;
}
}
public override TimeSpan ReadJson(JsonReader reader, Type objectType, TimeSpan existingValue, bool hasExistingValue, JsonSerializer serializer)
{
float value = JToken.ReadFrom(reader).ToObject<float>();
return _timeType switch
{
TimeType.Hour => TimeSpan.FromHours((double)value),
TimeType.Minute => TimeSpan.FromMinutes((double)value),
TimeType.Second => TimeSpan.FromSeconds((double)value),
TimeType.MiliSecond => TimeSpan.FromMilliseconds((int)value),
TimeType.Microsecond => TimeSpan.FromMicroseconds((int)value),
_ => throw new NotImplementedException()
};
}
private readonly TimeType _timeType;
public enum TimeType
{
Hour,
Minute,
Second,
MiliSecond,
Microsecond
}
}
}