Code/Serialisation/Serialisation.cs
using Sandbox.Internal;
using System;
using System.Linq;
using System.Text.Json;
using System.Text.Json.Nodes;
using System.Text.Json.Serialization;
namespace SandbankDatabase;
internal static class Serialisation
{
private static JsonSerializerOptions _jsonOptions = new()
{
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = ConfigController.INDENT_JSON,
Converters = { new GenericSavedDataConverter() }
};
public static string SerialiseClass<T>( T theClass )
{
return JsonSerializer.Serialize( theClass, _jsonOptions );
}
public static T DeserialiseClass<T>( string data )
{
return JsonSerializer.Deserialize<T>( data, _jsonOptions );
}
public static string SerialiseJSONObject( JsonObject obj )
{
return obj.ToJsonString( _jsonOptions );
}
public static string SerialiseClass( object theClass, Type classType )
{
return JsonSerializer.Serialize( theClass, classType, _jsonOptions );
}
public static object DeserialiseClass( string data, Type type )
{
return JsonSerializer.Deserialize( data, type, _jsonOptions );
}
}
internal sealed class GenericSavedDataConverter : JsonConverter<object>
{
public override object Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options )
{
var instance = GlobalGameNamespace.TypeLibrary.Create<object>( typeToConvert );
var properties = GlobalGameNamespace.TypeLibrary.GetPropertyDescriptions( instance, true )
.Where( prop => prop.Attributes.Any( a => a is Saved || a is AutoSaved ) );
if ( reader.TokenType != JsonTokenType.StartObject )
{
throw new SandbankException("unexpected JSON token");
}
while ( reader.Read() )
{
if ( reader.TokenType == JsonTokenType.EndObject )
{
return instance;
}
if ( reader.TokenType != JsonTokenType.PropertyName )
{
throw new SandbankException( "unexpected JSON token");
}
var propertyName = reader.GetString();
var property = properties.FirstOrDefault( prop =>
string.Equals( prop.Name, propertyName, StringComparison.OrdinalIgnoreCase ) );
if ( property != null )
{
reader.Read();
var value = JsonSerializer.Deserialize( ref reader, property.PropertyType );
property.SetValue( instance, value );
}
else
{
reader.Skip();
}
}
throw new SandbankException( "expected end of JSON object" );
}
public override void Write( Utf8JsonWriter writer, object value, JsonSerializerOptions options )
{
writer.WriteStartObject();
var properties = GlobalGameNamespace.TypeLibrary.GetPropertyDescriptions( value )
.Where( prop => prop.Attributes.Any( a => a is Saved || a is AutoSaved ) );
foreach ( var prop in properties )
{
writer.WritePropertyName( prop.Name );
JsonSerializer.Serialize( writer, prop.GetValue( value ), prop.PropertyType );
}
writer.WriteEndObject();
}
/// <summary>
/// Don't delete this as it does actually do something!
/// </summary>
public override bool CanConvert( Type typeToConvert )
{
// Optionally, you can refine this method to return false for types that shouldn't use this converter
return true; // As a simple approach, return true to indicate it can convert any object
}
}