Slime Stuff & DB Prep

Put the finishing touches on the microfauna
Prepared the repository for database extraction
This commit is contained in:
Reinier Vens 2021-03-30 01:17:58 +01:00
commit 48759380c5
773 changed files with 5278 additions and 805 deletions

View file

@ -0,0 +1,140 @@
using System;
[AttributeUsage(AttributeTargets.Class)]
public class InspectableAttribute : Attribute { }
public abstract class PreferredInspectorAttribute : InspectableAttribute
{
public Type TargetType;
public PreferredInspectorAttribute(Type targetType)
{
TargetType = targetType;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class ExternalEntryAttribute : Attribute { }
public class InspectableFieldAttribute : Attribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableTextAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableUnityObjectAttribute : InspectableFieldAttribute
{
public Type ObjectType;
public InspectableUnityObjectAttribute(Type type)
{
ObjectType = type;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class InspectablePrefabAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableTextureAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableTextAssetAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableTemperatureAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableAnimationCurveAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableColorAttribute : InspectableFieldAttribute { }
[AttributeUsage(AttributeTargets.Field)]
public class InspectableDatabaseLinkAttribute : InspectableFieldAttribute
{
public readonly Type EntryType;
public InspectableDatabaseLinkAttribute(Type entryType)
{
EntryType = entryType;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class RangedFloatInspectableAttribute : InspectableFieldAttribute
{
public readonly float Min, Max;
public RangedFloatInspectableAttribute(float min, float max)
{
Min = min;
Max = max;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class RangedFloatAttribute : Attribute
{
public readonly float Min, Max;
public RangedFloatAttribute(float min, float max)
{
Min = min;
Max = max;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class RangedIntInspectableAttribute : InspectableFieldAttribute
{
public readonly int Min, Max;
public RangedIntInspectableAttribute(int min, int max)
{
Min = min;
Max = max;
}
}
public class InspectableTypeAttribute : InspectableFieldAttribute
{
public readonly Type Type;
public InspectableTypeAttribute(Type type)
{
Type = type;
}
}
[AttributeUsage(AttributeTargets.Field)]
public class SimplePerformanceStatAttribute : Attribute { }
/// <summary>
/// <para>Specify a tooltip for a field in the Inspector window.</para>
/// </summary>
[AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class TooltipAttribute : Attribute
{
/// <summary>
/// <para>The tooltip text.</para>
/// </summary>
public readonly string tooltip;
/// <summary>
/// <para>Specify a tooltip for a field.</para>
/// </summary>
/// <param name="tooltip">The tooltip text.</param>
public TooltipAttribute(string tooltip) => this.tooltip = tooltip;
}
[AttributeUsage(AttributeTargets.Class)]
public class RethinkTableAttribute : Attribute
{
public string TableName;
public RethinkTableAttribute(string tableName)
{
TableName = tableName;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d078a6b39f8c440fabe8d43881207c5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,215 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using MessagePack;
public class DatabaseCache
{
public event Action<DatabaseEntry> OnDataInsertLocal;
public event Action<DatabaseEntry> OnDataUpdateLocal;
public event Action<DatabaseEntry> OnDataDeleteLocal;
public event Action<DatabaseEntry> OnDataInsertRemote;
public event Action<DatabaseEntry> OnDataUpdateRemote;
public event Action<DatabaseEntry> OnDataDeleteRemote;
private readonly object addLock = new object();
//public Action<string> Logger = Console.WriteLine;
private string _filePath;
private readonly Dictionary<Guid, DatabaseEntry> _entries = new Dictionary<Guid, DatabaseEntry>();
private readonly Dictionary<Type, HashSet<DatabaseEntry>> _types = new Dictionary<Type, HashSet<DatabaseEntry>>();
private readonly Dictionary<Type, (DirectoryInfo directory, List<Guid> entries)> _externalTypes = new Dictionary<Type, (DirectoryInfo directory, List<Guid> entries)>();
private class ExternalEntry
{
public string FilePath;
public DatabaseEntry Entry;
public ExternalEntry(string filePath, DatabaseEntry entry)
{
FilePath = filePath;
Entry = entry;
}
}
private readonly Dictionary<Guid, ExternalEntry> _externalEntries = new Dictionary<Guid, ExternalEntry>();
public IEnumerable<DatabaseEntry> AllEntries => _entries.Values;
public DatabaseCache(string filePath)
{
RegisterResolver.Register();
_filePath = filePath;
var fileInfo = new FileInfo(filePath);
var dataDirectory = fileInfo.Directory;
// Entry types can be marked external
// External entries are stored individually and loaded on demand
// This is mainly to accomodate large files like datasets
foreach (var type in typeof(DatabaseEntry).GetAllChildClasses())
{
if (type.GetCustomAttribute<ExternalEntryAttribute>() != null)
{
var typeDirectory = dataDirectory.CreateSubdirectory(type.Name);
_externalTypes[type] = (typeDirectory, new List<Guid>());
// Cache the GUIDs for all available external entries for querying
// Initially set values to null to indicate they haven't been loaded yet
foreach (var file in typeDirectory.EnumerateFiles("*.msgpack"))
{
Guid id;
if (Guid.TryParse(file.Name.Substring(0, file.Name.IndexOf('.')), out id))
{
_externalEntries.Add(id, new ExternalEntry(file.FullName, null));
_externalTypes[type].entries.Add(id);
}
}
}
else _types[type] = new HashSet<DatabaseEntry>();
}
}
public void Add(DatabaseEntry entry, bool remote = false)
{
lock(addLock)
{
if (entry != null)
{
var exists = _entries.ContainsKey(entry.ID);
// If an external entry is added, store it separately
var type = entry.GetType();
if (_externalTypes.ContainsKey(type))
{
if (_externalEntries.ContainsKey(entry.ID))
{
_externalEntries[entry.ID].Entry = entry;
}
else
{
_externalTypes[type].entries.Add(entry.ID);
_externalEntries[entry.ID] = new ExternalEntry(
Path.Combine(_externalTypes[type].directory.FullName, $"{entry.ID.ToString()}.msgpack"),
entry);
}
}
else
{
_entries[entry.ID] = entry;
_types[type].Add(entry);
foreach (var parentType in type.GetParentTypes())
{
if(_types.ContainsKey(parentType))
_types[parentType].Add(entry);
}
if (remote)
{
if (exists)
OnDataUpdateRemote?.Invoke(entry);
else
OnDataInsertRemote?.Invoke(entry);
}
else
{
if (exists)
OnDataUpdateLocal?.Invoke(entry);
else
OnDataInsertLocal?.Invoke(entry);
}
}
}
}
}
public void AddAll(IEnumerable<DatabaseEntry> entries, bool remote = false)
{
foreach (var entry in entries)
{
Add(entry, remote);
}
}
public DatabaseEntry Get(Guid guid)
{
if (_externalEntries.ContainsKey(guid))
{
if(_externalEntries[guid].Entry == null)
{
var bytes = File.ReadAllBytes(_externalEntries[guid].FilePath);
var e = MessagePackSerializer.Deserialize<DatabaseEntry>(bytes);
_externalEntries[guid].Entry = e;
}
return _externalEntries[guid].Entry;
}
DatabaseEntry entry;
_entries.TryGetValue(guid, out entry);
return entry;
}
public T Get<T>(Guid guid) where T : DatabaseEntry
{
return Get(guid) as T;
}
public IEnumerable<DatabaseEntry> GetAll(Type type)
{
if (_externalTypes.ContainsKey(type))
{
return _externalTypes[type].entries.Select(Get);
}
return !_types.ContainsKey(type) ? Enumerable.Empty<DatabaseEntry>() : _types[type];
}
public IEnumerable<T> GetAll<T>() where T : DatabaseEntry
{
var type = typeof(T);
if (_externalTypes.ContainsKey(type))
{
return _externalTypes[type].entries.Select(Get<T>);
}
return !_types.ContainsKey(type) ? Enumerable.Empty<T>() : _types[type].Cast<T>();
}
public void Delete(DatabaseEntry entry, bool remote = false)
{
_entries.Remove(entry.ID);
if (remote)
OnDataDeleteRemote?.Invoke(entry);
else
OnDataDeleteLocal?.Invoke(entry);
}
public void Load()
{
var bytes = File.ReadAllBytes(_filePath);
var entries = MessagePackSerializer.Deserialize<DatabaseEntry[]>(bytes);
AddAll(entries);
}
public void Save()
{
var entries = AllEntries.ToArray();
File.WriteAllBytes(_filePath, MessagePackSerializer.Serialize(entries));
foreach (var external in _externalEntries.Values)
{
if (external.Entry != null)
{
File.WriteAllBytes(external.FilePath, MessagePackSerializer.Serialize(external.Entry));
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a43b39c6991618b43aed4a24ffcdc0ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,62 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
using System;
using System.Linq;
using JsonKnownTypes;
using MessagePack;
using MessagePack.Formatters;
using Newtonsoft.Json;
// TODO: USE THIS EVERYWHERE
using Unity.Mathematics;
using static Unity.Mathematics.math;
public interface INamedEntry
{
string EntryName { get; set; }
}
[InspectableField,
MessagePackObject,
//MessagePackFormatter(typeof(TypelessFormatter)),
JsonObject(MemberSerialization.OptIn),
JsonConverter(typeof(JsonKnownTypesConverter<DatabaseEntry>)),
Union(0, typeof(SimpleCommodityData)),
Union(1, typeof(CompoundCommodityData)),
Union(2, typeof(GearData)),
Union(3, typeof(HullData)),
Union(4, typeof(SimpleCommodity)),
Union(5, typeof(CompoundCommodity)),
Union(6, typeof(EquippableItem)),
Union(8, typeof(GalaxyMapLayerData)),
Union(9, typeof(NameFile)),
//Union(10, typeof(ZoneData)),
Union(11, typeof(PlayerData)),
Union(12, typeof(Corporation)),
Union(13, typeof(Faction)),
Union(14, typeof(OrbitalEntity)),
Union(15, typeof(OrbitData)),
Union(16, typeof(BodyData)),
Union(17, typeof(PersonalityAttribute)),
Union(18, typeof(AgentTask)),
// Union(19, typeof(LoadoutData)),
Union(20, typeof(Ship)),
Union(21, typeof(Mining)),
Union(22, typeof(StationTowing)),
Union(23, typeof(Survey)),
Union(24, typeof(HaulingTask)),
Union(25, typeof(AsteroidBeltData)),
Union(26, typeof(GasGiantData)),
Union(27, typeof(SunData)),
Union(28, typeof(PlanetData)),
Union(29, typeof(CargoBayData)),
Union(30, typeof(DockingBayData)),
Union(31, typeof(WeaponItemData))]
public abstract class DatabaseEntry
{
[JsonProperty("id"), Key(0)]
public Guid ID = Guid.NewGuid();
public DatabaseEntry(){}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3bb4780bed7bb544dbf6ea2223dd8f06
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
public static class CultCacheExtensions
{
private static Dictionary<Type,Type[]> InterfaceClasses = new Dictionary<Type, Type[]>();
public static Type[] GetAllInterfaceClasses(this Type type)
{
if (InterfaceClasses.ContainsKey(type))
return InterfaceClasses[type];
return InterfaceClasses[type] = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(ass => ass.GetTypes()).Where(t => t.IsClass && t.GetInterfaces().Contains(type)).ToArray();
}
private static Dictionary<Type,Type[]> ParentTypes = new Dictionary<Type, Type[]>();
public static Type[] GetParentTypes(this Type type)
{
if (ParentTypes.ContainsKey(type))
return ParentTypes[type];
return ParentTypes[type] = type.GetParents().ToArray();
}
private static IEnumerable<Type> GetParents(this Type type)
{
// is there any base type?
if (type == null)
{
yield break;
}
yield return type;
// return all implemented or inherited interfaces
foreach (var i in type.GetInterfaces())
{
yield return i;
}
// return all inherited types
var currentBaseType = type.BaseType;
while (currentBaseType != null)
{
yield return currentBaseType;
currentBaseType= currentBaseType.BaseType;
}
}
private static Dictionary<Type,Type[]> ChildClasses = new Dictionary<Type, Type[]>();
public static Type[] GetAllChildClasses(this Type type)
{
if (ChildClasses.ContainsKey(type))
return ChildClasses[type];
return ChildClasses[type] = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(ass => ass.GetTypes()).Where(type.IsAssignableFrom).ToArray();
}
public static async void WrapAwait(this Task task)
{
await task;
}
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fd5642f26b80465fb57f3d2610633140
timeCreated: 1617055075

View file

@ -0,0 +1,4 @@
public static class MathExtensions
{
}

View file

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5effe288f2074414930e040d4531709f
timeCreated: 1617057296

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8035c545a12367f419eb4a2fe1c917b6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,169 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Unity.Mathematics;
using static Unity.Mathematics.math;
public class MathJsonConverter : JsonConverter
{
private readonly Dictionary<Type, Action<JsonWriter, object>> _writers;
private readonly Dictionary<Type, Func<JArray, object>> _readers;
public MathJsonConverter()
{
_writers = GenerateWriters();
_readers = GenerateReaders();
}
private Dictionary<Type, Action<JsonWriter, object>> GenerateWriters()
{
var writers = new Dictionary<Type, Action<JsonWriter, object>>();
writers[typeof(float2)] = (writer, o) =>
{
if (!(o is float2 v))
throw new JsonReaderException();
writer.WriteStartArray();
writer.WriteValue(v.x);
writer.WriteValue(v.y);
writer.WriteEndArray();
};
writers[typeof(int2)] = (writer, o) =>
{
if (!(o is int2 v))
throw new JsonReaderException();
writer.WriteStartArray();
writer.WriteValue(v.x);
writer.WriteValue(v.y);
writer.WriteEndArray();
};
writers[typeof(float3)] = (writer, o) =>
{
if (!(o is float3 v))
throw new JsonReaderException();
writer.WriteStartArray();
writer.WriteValue(v.x);
writer.WriteValue(v.y);
writer.WriteValue(v.z);
writer.WriteEndArray();
};
writers[typeof(float4)] = (writer, o) =>
{
if (!(o is float4 v))
throw new JsonReaderException();
writer.WriteStartArray();
writer.WriteValue(v.x);
writer.WriteValue(v.y);
writer.WriteValue(v.z);
writer.WriteValue(v.w);
writer.WriteEndArray();
};
return writers;
}
private Dictionary<Type, Func<JArray, object>> GenerateReaders()
{
var readers = new Dictionary<Type, Func<JArray, object>>();
readers[typeof(float2)] = array =>
{
if (array.Count < 2)
{
throw new JsonReaderException(
$"Could not read {typeof(float2)} from json, expected a json array with 2 elements");
}
return float2(
array[0].ToObject<float>(),
array[1].ToObject<float>());
};
readers[typeof(int2)] = array =>
{
if (array.Count < 2)
{
throw new JsonReaderException(
$"Could not read {typeof(float2)} from json, expected a json array with 2 elements");
}
return int2(
array[0].ToObject<int>(),
array[1].ToObject<int>());
};
readers[typeof(float3)] = array =>
{
if (array.Count < 3)
{
throw new JsonReaderException(
$"Could not read {typeof(float3)} from json, expected a json array with 3 elements");
}
return float3(
array[0].ToObject<float>(),
array[1].ToObject<float>(),
array[2].ToObject<float>());
};
readers[typeof(float4)] = array =>
{
if (array.Count < 4)
{
throw new JsonReaderException(
$"Could not read {typeof(float4)} from json, expected a json array with 4 elements");
}
return float4(
array[0].ToObject<float>(),
array[1].ToObject<float>(),
array[2].ToObject<float>(),
array[3].ToObject<float>());
};
return readers;
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (_writers.TryGetValue(value.GetType(), out var serializeAction))
serializeAction(writer, value);
else
throw new JsonReaderException($"Invalid type for ValueConverter:{value.GetType()}");
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (_readers.TryGetValue(objectType, out var deserializeFunc))
{
// Convert token from reader to array for deserialize function
var token = JToken.ReadFrom(reader);
if (!(token is JArray asArray))
throw new JsonReaderException(
$"Could not read {objectType} from json, expected a json array but got {token.Type}");
return deserializeFunc(asArray);
}
throw new JsonReaderException($"Invalid type for ValueConverter:{objectType}");
}
public override bool CanConvert(Type objectType)
{
//If the dictionary contains the key, the type can be handled by this class
return _writers.ContainsKey(objectType);
}
//Enable this JSON Converter for reading as well as writing values
public override bool CanRead => true;
public override bool CanWrite => true;
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fafad9d553198e942a5501ea1472ec9c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f94c63c8b140fb34bb5d70a8d8a5dbd6
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,16 @@
using System;
namespace JsonKnownTypes
{
public static class AttributesManager
{
public static JsonKnownTypeAttribute[] GetJsonKnownAttributes(Type type) =>
(JsonKnownTypeAttribute[])Attribute.GetCustomAttributes(type, typeof(JsonKnownTypeAttribute));
public static JsonKnownThisTypeAttribute GetJsonKnownThisAttribute(Type type) =>
(JsonKnownThisTypeAttribute)Attribute.GetCustomAttribute(type, typeof(JsonKnownThisTypeAttribute));
public static JsonDiscriminatorAttribute GetJsonDiscriminatorAttribute(Type type) =>
(JsonDiscriminatorAttribute)Attribute.GetCustomAttribute(type, typeof(JsonDiscriminatorAttribute));
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6036d25d64e90064ca92c91f6d7827b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 01722fba3f2fd3942bca61d48508ad27
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,15 @@
using System;
namespace JsonKnownTypes.Exceptions
{
public class JsonKnownTypesException : Exception
{
public JsonKnownTypesException(string message)
: base(message)
{ }
public JsonKnownTypesException(string message, Exception innerException)
: base(message, innerException)
{ }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 36f9ed87d773cf146bf68e828cefe89c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,18 @@
using System;
namespace JsonKnownTypes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface)]
public class JsonDiscriminatorAttribute : Attribute
{
public string Name { get; set; }
internal bool? _autoJson;
public bool AutoJson
{
get => _autoJson != null && (bool) _autoJson;
set => _autoJson = value;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7c6582f43e22994ebbaf0e139e63dc5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
namespace JsonKnownTypes
{
public class JsonDiscriminatorSettings
{
public string Name { get; set; } = "$type";
public bool AutoJsonKnown { get; set; } = true;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b5f09ee78f257904caa3ab939d3edc65
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,17 @@
using System;
namespace JsonKnownTypes
{
public class JsonKnownThisTypeAttribute : Attribute
{
public string Discriminator { get; }
public JsonKnownThisTypeAttribute()
{ }
public JsonKnownThisTypeAttribute(string discriminator)
{
Discriminator = discriminator;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8dc4cbd1c54167409cf14ec8ec37d70
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
using System;
namespace JsonKnownTypes
{
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Interface, AllowMultiple = true)]
public class JsonKnownTypeAttribute : Attribute
{
public Type Type { get; }
public string Discriminator { get; }
public JsonKnownTypeAttribute(Type type)
{
Type = type;
}
public JsonKnownTypeAttribute(Type type, string discriminator)
{
Type = type;
Discriminator = discriminator;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ecbe3646a4d9ca04eac598b60e5c77ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
</ItemGroup>
<PropertyGroup>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>0.2.0</Version>
<Authors>Dmitry Kaznacheev</Authors>
<PackageProjectUrl>https://github.com/dmitry-bym/JsonKnownTypes</PackageProjectUrl>
<PackageLicenseUrl>https://github.com/dmitry-bym/JsonKnownTypes/blob/master/LICENSE</PackageLicenseUrl>
<Copyright>Dmitry Kaznacheev</Copyright>
<RepositoryUrl>https://github.com/dmitry-bym/JsonKnownTypes</RepositoryUrl>
<PackageTags>json known polymorphic types</PackageTags>
</PropertyGroup>
</Project>

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 937d902757d946b47a7bea20ade37beb
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,16 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
namespace JsonKnownTypes
{
public class JsonKnownTypesContractResolver<T> : DefaultContractResolver
{
protected override JsonConverter ResolveContractConverter(Type objectType)
{
if (typeof(T).IsAssignableFrom(objectType) && !objectType.IsAbstract)
return null;
return base.ResolveContractConverter(objectType);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bce1b7fa2da230447b3614d23394ee9f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,57 @@
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace JsonKnownTypes
{
public class JsonKnownTypesConverter<T> : JsonConverter
{
private readonly JsonKnownTypesSettings _typesSettings
= JsonKnownTypesSettingsManager.GetSettings<T>();
private JsonSerializerSettings SpecifiedSubclassConversion
{
get =>
new JsonSerializerSettings
{
ContractResolver = new JsonKnownTypesContractResolver<T>()
};
}
public override bool CanConvert(Type objectType)
=> _typesSettings.TypeToDiscriminator.ContainsKey(objectType);
public override bool CanWrite { get => true; }
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null) return null;
var jo = JObject.Load(reader);
var discriminator = jo[_typesSettings.Name].ToString();
if(_typesSettings.DiscriminatorToType.TryGetValue(discriminator, out var typeForObject))
return JsonConvert.DeserializeObject(jo.ToString(), typeForObject, SpecifiedSubclassConversion);
return null;
//throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var objectType = value.GetType();
if (_typesSettings.TypeToDiscriminator.TryGetValue(objectType, out var discriminator))
{
var json = JsonConvert.SerializeObject(value, SpecifiedSubclassConversion);
var jo = JObject.Parse(json);
jo.Add(_typesSettings.Name, new JValue(discriminator));
jo.WriteTo(writer);
}
else
{
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b0a6c832fc846634789aa691cd2b81d9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using System.Linq;
using JsonKnownTypes.Exceptions;
namespace JsonKnownTypes
{
internal static class JsonKnownTypesDictionaryManager
{
public static void AddJsonKnown<T>(this Dictionary<Type, string> dictionary)
{
var attrs = AttributesManager.GetJsonKnownAttributes(typeof(T));
foreach (var attr in attrs)
{
var discriminator = attr.Discriminator ?? attr.Type.Name;
dictionary.TryAdd(attr.Type, discriminator);
}
}
public static void AddJsonKnownThis(this Dictionary<Type, string> dictionary, Type[] inherited)
{
foreach (var type in inherited)
{
var attr = AttributesManager.GetJsonKnownThisAttribute(type);
if (attr != null)
{
var discriminator = attr.Discriminator ?? type.Name;
dictionary.TryAdd(type, discriminator);
}
}
}
public static void AddAutoGenerated(this Dictionary<Type, string> dictionary, Type[] inherited)
{
foreach (var type in inherited.Except(dictionary.Keys))
{
dictionary.TryAdd(type, type.Name);
}
}
public static void TryAdd(this Dictionary<Type, string> dictionary, Type key, string discriminator)
{
if (dictionary.ContainsKey(key))
throw new JsonKnownTypesException($"Dictionary already contains the key {key.Name}");//todo
if (dictionary.ContainsValue(discriminator))
throw new JsonKnownTypesException($"Dictionary already contains the value {discriminator}");//todo
dictionary.Add(key, discriminator);
}
public static Dictionary<string, Type> Revert(this Dictionary<Type, string> dictionary)
{
try
{
return dictionary.ToDictionary(x => x.Value, x => x.Key);
}
catch (ArgumentException e)
{
throw new JsonKnownTypesException("Dictionary has a repeated value", e);
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 77ce621509349204a87085f089b3daa3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
namespace JsonKnownTypes
{
public class JsonKnownTypesSettings
{
public string Name { get; set; }
public Dictionary<string, Type> DiscriminatorToType { get; set; } = new Dictionary<string, Type>();
public Dictionary<Type, string> TypeToDiscriminator { get; set; } = new Dictionary<Type, string>();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 99b988650c739094aa3a5ba7040ea379
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using JsonKnownTypes.Exceptions;
using JsonKnownTypes.Utils;
namespace JsonKnownTypes
{
public static class JsonKnownTypesSettingsManager
{
public static JsonDiscriminatorSettings DefaultDiscriminatorSettings { get; set; } = new JsonDiscriminatorSettings();
private static HashSet<Assembly> RegisteredAssemblies = new HashSet<Assembly>();
public static void RegisterTypeAssembly<T>()
{
var type = typeof(T);
RegisteredAssemblies.Add(type.Assembly);
}
public static JsonKnownTypesSettings GetSettings<T>()
{
var discriminatorAttribute = AttributesManager.GetJsonDiscriminatorAttribute(typeof(T));
var discriminatorSettings = discriminatorAttribute == null ? DefaultDiscriminatorSettings : Mapper.Map(discriminatorAttribute);
var typeSettings = new JsonKnownTypesSettings
{
Name = discriminatorSettings.Name
};
var allTypes = GetAllInheritance<T>();
typeSettings.TypeToDiscriminator.AddJsonKnown<T>();
typeSettings.TypeToDiscriminator.AddJsonKnownThis(allTypes);
if (discriminatorSettings.AutoJsonKnown)
{
typeSettings.TypeToDiscriminator.AddAutoGenerated(allTypes);
}
else if(!allTypes.All(typeSettings.TypeToDiscriminator.ContainsKey))
{
throw new JsonKnownTypesException("Dictionary contains not all types of hierarchy, enable AutoJsonKnow or add attributes for all classes"); //todo
}
typeSettings.DiscriminatorToType = typeSettings.TypeToDiscriminator.Revert();
return typeSettings;
}
private static Type[] GetAllInheritance<T>()
{
RegisterTypeAssembly<T>();
var type = typeof(T);
return RegisteredAssemblies.SelectMany(a=>a.GetTypes())
.Where(x => type.IsAssignableFrom(x) && !x.IsInterface && !x.IsAbstract)
.ToArray();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a361505c5408b374788cbaeed6fa2f55
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6d6706b0998d8af458321fd5f35906fb
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,15 @@
namespace JsonKnownTypes.Utils
{
internal static class Mapper
{
public static JsonDiscriminatorSettings Map(JsonDiscriminatorAttribute entity)
{
var settings = new JsonDiscriminatorSettings();
settings.Name = entity.Name ?? settings.Name;
settings.AutoJsonKnown = entity._autoJson ?? settings.AutoJsonKnown;
return settings;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c30d51fc767627a41b65f5cdd2b22cc3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,226 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MessagePack;
using Unity.Mathematics;
using static Unity.Mathematics.math;
public class Float2Formatter : MessagePack.Formatters.IMessagePackFormatter<float2>
{
public void Serialize(ref MessagePackWriter writer, float2 value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(2);
writer.Write(value.x);
writer.Write(value.y);
}
public float2 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var length = reader.ReadArrayHeader();
var x = default(float);
var y = default(float);
for (int i = 0; i < length; i++)
{
var key = i;
switch (key)
{
case 0:
x = reader.ReadSingle();
break;
case 1:
y = reader.ReadSingle();
break;
default:
reader.Skip();
break;
}
}
var result = float2(x, y);
return result;
}
}
public class Int2Formatter : MessagePack.Formatters.IMessagePackFormatter<int2>
{
public void Serialize(ref MessagePackWriter writer, int2 value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(2);
writer.Write(value.x);
writer.Write(value.y);
}
public int2 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var length = reader.ReadArrayHeader();
var x = default(int);
var y = default(int);
for (int i = 0; i < length; i++)
{
var key = i;
switch (key)
{
case 0:
x = reader.ReadInt32();
break;
case 1:
y = reader.ReadInt32();
break;
default:
reader.Skip();
break;
}
}
var result = int2(x, y);
return result;
}
}
public class Bool2Formatter : MessagePack.Formatters.IMessagePackFormatter<bool2>
{
public void Serialize(ref MessagePackWriter writer, bool2 value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(2);
writer.Write(value.x);
writer.Write(value.y);
}
public bool2 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var length = reader.ReadArrayHeader();
var x = default(bool);
var y = default(bool);
for (int i = 0; i < length; i++)
{
var key = i;
switch (key)
{
case 0:
x = reader.ReadBoolean();
break;
case 1:
y = reader.ReadBoolean();
break;
default:
reader.Skip();
break;
}
}
var result = bool2(x, y);
return result;
}
}
public class Float3Formatter : MessagePack.Formatters.IMessagePackFormatter<float3>
{
public void Serialize(ref MessagePackWriter writer, float3 value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(3);
writer.Write(value.x);
writer.Write(value.y);
writer.Write(value.z);
}
public float3 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var length = reader.ReadArrayHeader();
var x = default(float);
var y = default(float);
var z = default(float);
for (int i = 0; i < length; i++)
{
var key = i;
switch (key)
{
case 0:
x = reader.ReadSingle();
break;
case 1:
y = reader.ReadSingle();
break;
case 2:
z = reader.ReadSingle();
break;
default:
reader.Skip();
break;
}
}
var result = float3(x, y, z);
return result;
}
}
public class Float4Formatter : MessagePack.Formatters.IMessagePackFormatter<float4>
{
public void Serialize(ref MessagePackWriter writer, float4 value, MessagePackSerializerOptions options)
{
writer.WriteArrayHeader(4);
writer.Write(value.x);
writer.Write(value.y);
writer.Write(value.z);
writer.Write(value.w);
}
public float4 Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var length = reader.ReadArrayHeader();
var x = default(float);
var y = default(float);
var z = default(float);
var w = default(float);
for (int i = 0; i < length; i++)
{
var key = i;
switch (key)
{
case 0:
x = reader.ReadSingle();
break;
case 1:
y = reader.ReadSingle();
break;
case 2:
z = reader.ReadSingle();
break;
case 3:
w = reader.ReadSingle();
break;
default:
reader.Skip();
break;
}
}
var result = float4(x, y, z, w);
return result;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 02bc8e83a7f1cf54d94ebebcd3272a0d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,80 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MessagePack;
using MessagePack.Formatters;
using Unity.Mathematics;
using static Unity.Mathematics.math;
public class MathResolver : IFormatterResolver
{
public static readonly MathResolver Instance = new MathResolver();
private MathResolver()
{
}
public IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.Formatter;
}
private static class FormatterCache<T>
{
public static readonly IMessagePackFormatter<T> Formatter;
static FormatterCache()
{
Formatter = (IMessagePackFormatter<T>)MathResolverResolverGetFormatterHelper.GetFormatter(typeof(T));
}
}
}
internal static class MathResolverResolverGetFormatterHelper
{
private static readonly Dictionary<Type, object> FormatterMap = new Dictionary<Type, object>()
{
// standard
{ typeof(float2), new Float2Formatter() },
{ typeof(int2), new Int2Formatter() },
{ typeof(bool2), new Bool2Formatter() },
{ typeof(float3), new Float3Formatter() },
{ typeof(float4), new Float4Formatter() },
{ typeof(float2?), new StaticNullableFormatter<float2>(new Float2Formatter()) },
{ typeof(int2?), new StaticNullableFormatter<int2>(new Int2Formatter()) },
{ typeof(float3?), new StaticNullableFormatter<float3>(new Float3Formatter()) },
{ typeof(float4?), new StaticNullableFormatter<float4>(new Float4Formatter()) },
// standard + array
{ typeof(float2[]), new ArrayFormatter<float2>() },
{ typeof(int2[]), new ArrayFormatter<int2>() },
{ typeof(float3[]), new ArrayFormatter<float3>() },
{ typeof(float4[]), new ArrayFormatter<float4>() },
{ typeof(float2?[]), new ArrayFormatter<float2?>() },
{ typeof(int2?[]), new ArrayFormatter<float2?>() },
{ typeof(float3?[]), new ArrayFormatter<float3?>() },
{ typeof(float4?[]), new ArrayFormatter<float4?>() },
// standard + list
{ typeof(List<float2>), new ListFormatter<float2>() },
{ typeof(List<int2>), new ListFormatter<int2>() },
{ typeof(List<float3>), new ListFormatter<float3>() },
{ typeof(List<float4>), new ListFormatter<float4>() },
{ typeof(List<float2?>), new ListFormatter<float2?>() },
{ typeof(List<int2?>), new ListFormatter<int2?>() },
{ typeof(List<float3?>), new ListFormatter<float3?>() },
{ typeof(List<float4?>), new ListFormatter<float4?>() },
};
internal static object GetFormatter(Type t)
{
object formatter;
if (FormatterMap.TryGetValue(t, out formatter))
{
return formatter;
}
return null;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 80366c67f842eaf4dba339ed553e447c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,27 @@
using System.Collections;
using System.Collections.Generic;
using MessagePack;
using MessagePack.ReactivePropertyExtension;
using MessagePack.Resolvers;
public static class RegisterResolver
{
private static bool registered = false;
public static void Register()
{
if (registered) return;
// Set extensions to default resolver.
var resolver = CompositeResolver.Create(
MathResolver.Instance,
TypeResolver.Instance,
NativeGuidResolver.Instance,
StandardResolver.Instance,
ReactivePropertyResolver.Instance
);
var options = MessagePackSerializerOptions.Standard.WithResolver(resolver);
MessagePackSerializer.DefaultOptions = options;
registered = true;
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc638a5fae4350643871d45495a49643
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,65 @@
using System;
using System.Collections;
using System.Collections.Generic;
using MessagePack;
using MessagePack.Formatters;
public class TypeFormatter : MessagePack.Formatters.IMessagePackFormatter<Type>
{
public static readonly IMessagePackFormatter<Type> Instance = new TypeFormatter();
private TypeFormatter()
{
}
public void Serialize(ref MessagePackWriter writer, Type value, MessagePackSerializerOptions options)
{
writer.Write(value.AssemblyQualifiedName);
}
public Type Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
{
if (reader.IsNil)
{
throw new InvalidOperationException("typecode is null, struct not supported");
}
var assemblyQualifiedName = reader.ReadString();
return Type.GetType(assemblyQualifiedName);
}
}
public class TypeResolver : IFormatterResolver
{
public static readonly TypeResolver Instance = new TypeResolver();
private TypeResolver()
{
}
public IMessagePackFormatter<T> GetFormatter<T>()
{
return FormatterCache<T>.Formatter;
}
private static object GetFormatterHelper(Type t)
{
if (t == typeof(Type))
{
return TypeFormatter.Instance;
}
return null;
}
private static class FormatterCache<T>
{
public static readonly IMessagePackFormatter<T> Formatter;
static FormatterCache()
{
Formatter = (IMessagePackFormatter<T>)GetFormatterHelper(typeof(T));
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ede4e7a24e20d134fb02868d010af83d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: