Delete the in-tree cache, JsonKnownTypes and vendored MessagePack
Cut 8b, deletes first. The old authorities are removed, not demoted: - ServerShared/CultCache: CultCache.cs, DatabaseEntry.cs (root [Union], DatabaseLink, INamedEntry), RegisterResolver.cs, TypeFormatterResolver.cs, JsonConverters.cs, JsonKnownTypes/**. - Assets/Plugins/MessagePack/** and System.Runtime.CompilerServices.Unsafe.dll (org.gamecult.cultlib ships both). - GalaxyMapLayerData, PlayerData, GlobalSettingsAttribute. - The inspector attributes CultLib already carries or nothing reads. Kept and moved: MathFormatters.cs and MathResolver.cs to ServerShared/Serialization; GetAllChildClasses, SplitCamelCase, FormatTypeName, MaxBy and MinBy to Extensions.cs; Inspectable, PreferredInspectorAttribute and the five Aetheria drawer attributes to ServerShared/Attributes.cs. Aetheria.Shared.csproj drops the vendored MessagePack include and the Unsafe package; the asmdef drops MessagePack. Does not build: the data model moves onto CultLib in the next commit. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
d3db1730ad
commit
b4c06b50cb
266 changed files with 67 additions and 33150 deletions
|
|
@ -2,7 +2,6 @@
|
|||
"name": "Aetheria.Shared.Unity",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"MessagePack",
|
||||
"UniRx",
|
||||
"Ink"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -16,12 +16,26 @@ public class EntityTypeRestrictionAttribute : Attribute
|
|||
}
|
||||
|
||||
public class RuntimeInspectable : Attribute { }
|
||||
// public class CategoryAttribute : Attribute
|
||||
// {
|
||||
// public readonly Type Type;
|
||||
//
|
||||
// public CategoryAttribute(Type type)
|
||||
// {
|
||||
// Type = type;
|
||||
// }
|
||||
// }
|
||||
|
||||
// The runtime PropertiesPanel's opt-in; the Studio does not read it.
|
||||
[AttributeUsage(AttributeTargets.All, Inherited = false)]
|
||||
public class InspectableAttribute : Attribute { }
|
||||
|
||||
// Inspection meaning CultLib's CultInspector attributes do not carry, drawn by Aetheria's Studio drawers.
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public abstract class PreferredInspectorAttribute : InspectableAttribute { }
|
||||
|
||||
public class InspectableTemperatureAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableAnimationCurveAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableColorAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableSchematicShapeAttribute : PreferredInspectorAttribute { }
|
||||
|
||||
public class InspectableTypeAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly Type Type;
|
||||
|
||||
public InspectableTypeAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 49ec0c83548c7084ab0d3f6c2175ee71
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,146 +0,0 @@
|
|||
using System;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class GlobalSettingsAttribute : Attribute { }
|
||||
|
||||
// [AttributeUsage(AttributeTargets.Class)]
|
||||
// public class ExternalEntryAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.All, Inherited = false)]
|
||||
public class InspectableAttribute : Attribute { }
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public abstract class PreferredInspectorAttribute : InspectableAttribute { }
|
||||
|
||||
public class InspectableTextAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectablePrefabAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableTextureAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableTextAssetAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableTemperatureAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableAnimationCurveAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableColorAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableSoundBankAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableAudioParameterAttribute : PreferredInspectorAttribute { }
|
||||
public class InspectableSchematicShapeAttribute : PreferredInspectorAttribute { }
|
||||
|
||||
public class InspectableEnumValuesAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public Type EnumType;
|
||||
|
||||
public InspectableEnumValuesAttribute(Type enumType)
|
||||
{
|
||||
EnumType = enumType;
|
||||
}
|
||||
}
|
||||
|
||||
public class InspectableDatabaseLinkAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly Type EntryType;
|
||||
|
||||
public InspectableDatabaseLinkAttribute(Type entryType)
|
||||
{
|
||||
EntryType = entryType;
|
||||
}
|
||||
}
|
||||
|
||||
public class InspectableRangedFloatAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly float Min, Max;
|
||||
|
||||
public InspectableRangedFloatAttribute(float min, float max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
|
||||
public class InspectableRangedIntAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly int Min, Max;
|
||||
|
||||
public InspectableRangedIntAttribute(int min, int max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
|
||||
public class InspectableTypeAttribute : PreferredInspectorAttribute
|
||||
{
|
||||
public readonly Type Type;
|
||||
|
||||
public InspectableTypeAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field)]
|
||||
public class RangedFloatAttribute : Attribute
|
||||
{
|
||||
public readonly float Min, Max;
|
||||
|
||||
public RangedFloatAttribute(float min, float max)
|
||||
{
|
||||
Min = min;
|
||||
Max = max;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <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 DatabaseCategoryAttribute : Attribute
|
||||
{
|
||||
public string Category;
|
||||
|
||||
public DatabaseCategoryAttribute(string category)
|
||||
{
|
||||
Category = category;
|
||||
}
|
||||
}
|
||||
|
||||
public class NameAttribute : Attribute
|
||||
{
|
||||
public string Name;
|
||||
|
||||
public NameAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class OrderAttribute : Attribute
|
||||
{
|
||||
public int Order;
|
||||
|
||||
public OrderAttribute(int order)
|
||||
{
|
||||
Order = order;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true, Inherited = true)]
|
||||
public class InspectorHeaderAttribute : Attribute
|
||||
{
|
||||
public readonly string header;
|
||||
|
||||
public InspectorHeaderAttribute(string header) => this.header = header;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d078a6b39f8c440fabe8d43881207c5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class CollectionExtensions
|
||||
{
|
||||
// https://stackoverflow.com/a/800469
|
||||
public static string GetHashSHA1(this byte[] data)
|
||||
{
|
||||
using (var sha1 = new System.Security.Cryptography.SHA1CryptoServiceProvider())
|
||||
{
|
||||
return string.Concat(sha1.ComputeHash(data).Select(x => x.ToString("X2")));
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/3188835
|
||||
public static T MaxBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) > 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
|
||||
public static T MinBy<T, U>(this IEnumerable<T> items, Func<T, U> selector)
|
||||
{
|
||||
if (!items.Any())
|
||||
{
|
||||
throw new InvalidOperationException("Empty input sequence");
|
||||
}
|
||||
|
||||
var comparer = Comparer<U>.Default;
|
||||
T maxItem = items.First();
|
||||
U maxValue = selector(maxItem);
|
||||
|
||||
foreach (T item in items.Skip(1))
|
||||
{
|
||||
// Get the value of the item and compare it to the current max.
|
||||
U value = selector(item);
|
||||
if (comparer.Compare(value, maxValue) < 0)
|
||||
{
|
||||
maxValue = value;
|
||||
maxItem = item;
|
||||
}
|
||||
}
|
||||
|
||||
return maxItem;
|
||||
}
|
||||
}
|
||||
|
||||
public static class AsyncAwaitExtensions
|
||||
{
|
||||
public static async void WrapAwait(this Task task)
|
||||
{
|
||||
await task;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: eed05df00a9a6b84292c81be1662a66e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,437 +0,0 @@
|
|||
/* 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.Buffers.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
using UniRx;
|
||||
|
||||
public class CultCache
|
||||
{
|
||||
|
||||
private readonly object addLock = new object();
|
||||
|
||||
//public Action<string> Logger = Console.WriteLine;
|
||||
//private string _filePath;
|
||||
|
||||
public event Action<DatabaseEntry, DatabaseEntry> OnUpdate;
|
||||
|
||||
private List<CacheBackingStore> _backingStores = new List<CacheBackingStore>();
|
||||
|
||||
private readonly Dictionary<Type, CacheBackingStore> _typeStores = new Dictionary<Type, CacheBackingStore>();
|
||||
private readonly Dictionary<CacheBackingStore, Type[]> _storeTypes = new Dictionary<CacheBackingStore, Type[]>();
|
||||
|
||||
private readonly Dictionary<Guid, DatabaseEntry> _entries = new Dictionary<Guid, DatabaseEntry>();
|
||||
|
||||
private readonly Dictionary<Type, DatabaseEntry> _globals = new Dictionary<Type, DatabaseEntry>();
|
||||
private readonly Dictionary<Type, HashSet<DatabaseEntry>> _types = new Dictionary<Type, HashSet<DatabaseEntry>>();
|
||||
|
||||
public IEnumerable<DatabaseEntry> AllEntries => _entries.Values;
|
||||
|
||||
public CultCache()
|
||||
{
|
||||
DatabaseLinkBase.Cache = this;
|
||||
|
||||
foreach (var type in typeof(DatabaseEntry).GetAllChildClasses())
|
||||
{
|
||||
_types[type] = new HashSet<DatabaseEntry>();
|
||||
|
||||
if (type.GetCustomAttribute<GlobalSettingsAttribute>() != null)
|
||||
{
|
||||
_globals[type] = null;
|
||||
Add(Activator.CreateInstance(type) as DatabaseEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddBackingStore(CacheBackingStore store, params Type[] domain)
|
||||
{
|
||||
if (domain.Length > 0)
|
||||
{
|
||||
_storeTypes[store] = domain;
|
||||
foreach (var t in domain) _typeStores[t] = store;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(var existingStore in _backingStores) store.SubscribeTo(existingStore);
|
||||
_backingStores.Add(store);
|
||||
}
|
||||
store.EntryAdded.Subscribe(entry =>
|
||||
{
|
||||
Add(entry, store);
|
||||
OnUpdate?.Invoke(null, entry);
|
||||
});
|
||||
store.EntryUpdated.Subscribe(entry =>
|
||||
{
|
||||
Add(entry, store);
|
||||
OnUpdate?.Invoke(entry, entry);
|
||||
});
|
||||
store.EntryDeleted.Subscribe(entry =>
|
||||
{
|
||||
Remove(entry, store);
|
||||
OnUpdate?.Invoke(entry, null);
|
||||
});
|
||||
}
|
||||
|
||||
public void PullAllBackingStores()
|
||||
{
|
||||
foreach(var store in _backingStores) store.PullAll();
|
||||
foreach(var store in _storeTypes.Keys) store.PullAll();
|
||||
}
|
||||
|
||||
public void Add(DatabaseEntry entry, CacheBackingStore source = null)
|
||||
{
|
||||
lock(addLock)
|
||||
{
|
||||
if (entry != null)
|
||||
{
|
||||
var exists = _entries.ContainsKey(entry.ID);
|
||||
|
||||
var type = entry.GetType();
|
||||
|
||||
if (_globals.ContainsKey(type))
|
||||
{
|
||||
if(_globals[type]!=null)
|
||||
{
|
||||
Remove(_globals[type]);
|
||||
exists = true;
|
||||
}
|
||||
_globals[type] = entry;
|
||||
}
|
||||
|
||||
if(_typeStores.ContainsKey(type))
|
||||
_typeStores[type].Push(entry);
|
||||
else
|
||||
{
|
||||
var masterStore = _backingStores.First();
|
||||
if(masterStore!=source)
|
||||
masterStore.Push(entry);
|
||||
}
|
||||
|
||||
_entries[entry.ID] = entry;
|
||||
_types[type].Add(entry);
|
||||
foreach (var parentType in type.GetParentTypes())
|
||||
{
|
||||
if(_types.ContainsKey(parentType))
|
||||
_types[parentType].Add(entry);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsGlobal(DatabaseEntry entry) => _globals.ContainsKey(entry.GetType());
|
||||
|
||||
public void AddAll(IEnumerable<DatabaseEntry> entries)
|
||||
{
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
Add(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public DatabaseEntry Get(Guid guid)
|
||||
{
|
||||
DatabaseEntry entry;
|
||||
_entries.TryGetValue(guid, out entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public T Get<T>(Guid guid) where T : DatabaseEntry
|
||||
{
|
||||
return Get(guid) as T;
|
||||
}
|
||||
|
||||
public DatabaseEntry GetGlobal(Type type)
|
||||
{
|
||||
if (_globals.ContainsKey(type)) return _globals[type];
|
||||
return null;
|
||||
}
|
||||
|
||||
public T GetGlobal<T>() where T : DatabaseEntry
|
||||
{
|
||||
return GetGlobal(typeof(T)) as T;
|
||||
}
|
||||
|
||||
public IEnumerable<DatabaseEntry> GetAll(Type type)
|
||||
{
|
||||
return !_types.ContainsKey(type) ? Enumerable.Empty<DatabaseEntry>() : _types[type];
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetAll<T>() where T : DatabaseEntry
|
||||
{
|
||||
var type = typeof(T);
|
||||
return !_types.ContainsKey(type) ? Enumerable.Empty<T>() : _types[type].Cast<T>();
|
||||
}
|
||||
|
||||
public void Remove(DatabaseEntry entry, CacheBackingStore source = null)
|
||||
{
|
||||
_entries.Remove(entry.ID);
|
||||
var type = entry.GetType();
|
||||
if(_typeStores.ContainsKey(type))
|
||||
_typeStores[type].Delete(entry);
|
||||
else foreach(var store in _backingStores)
|
||||
{
|
||||
if(store != source)
|
||||
store.Delete(entry);
|
||||
}
|
||||
foreach (var parentType in type.GetParentTypes())
|
||||
{
|
||||
if(_types.ContainsKey(parentType))
|
||||
_types[parentType].Remove(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface RealtimeBackingStore
|
||||
{
|
||||
public void ObserveChanges();
|
||||
}
|
||||
|
||||
public abstract class CacheBackingStore
|
||||
{
|
||||
protected CacheBackingStore()
|
||||
{
|
||||
EntryAdded = new Subject<DatabaseEntry>();
|
||||
EntryDeleted = new Subject<DatabaseEntry>();
|
||||
EntryUpdated = new Subject<DatabaseEntry>();
|
||||
}
|
||||
|
||||
public abstract void PullAll();
|
||||
public abstract void Push(DatabaseEntry entry);
|
||||
public abstract void Delete(DatabaseEntry entry);
|
||||
public abstract void PushAll(bool soft = false);
|
||||
|
||||
public Subject<DatabaseEntry> EntryAdded { get; }
|
||||
public Subject<DatabaseEntry> EntryDeleted { get; }
|
||||
public Subject<DatabaseEntry> EntryUpdated { get; }
|
||||
|
||||
protected Dictionary<Guid, DatabaseEntry> Entries = new Dictionary<Guid, DatabaseEntry>();
|
||||
|
||||
public void SubscribeTo(CacheBackingStore targetStore)
|
||||
{
|
||||
targetStore.EntryAdded.Subscribe(Push);
|
||||
targetStore.EntryDeleted.Subscribe(Delete);
|
||||
targetStore.EntryUpdated.Subscribe(Push);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class MultiFileBackingStore : CacheBackingStore, RealtimeBackingStore
|
||||
{
|
||||
public DirectoryInfo DirectoryInfo { get; }
|
||||
protected Dictionary<Type, DirectoryInfo> _entryTypeDirectories = new Dictionary<Type, DirectoryInfo>();
|
||||
|
||||
public abstract byte[] Serialize(DatabaseEntry entry);
|
||||
public abstract DatabaseEntry Deserialize(byte[] data);
|
||||
public abstract string Extension { get; }
|
||||
|
||||
public MultiFileBackingStore(string path)
|
||||
{
|
||||
DirectoryInfo = new DirectoryInfo(path);
|
||||
foreach (var type in typeof(DatabaseEntry).GetAllChildClasses())
|
||||
{
|
||||
_entryTypeDirectories[type] = DirectoryInfo.CreateSubdirectory(type.Name);
|
||||
}
|
||||
}
|
||||
|
||||
public override void PullAll()
|
||||
{
|
||||
if (!DirectoryInfo.Exists) return;
|
||||
|
||||
foreach (var directory in _entryTypeDirectories.Values)
|
||||
{
|
||||
foreach (var file in directory.EnumerateFiles($"*.{Extension}"))
|
||||
{
|
||||
var entry = Deserialize(File.ReadAllBytes(file.FullName));
|
||||
Entries[entry.ID] = entry;
|
||||
EntryAdded.OnNext(entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string GetFileName(DatabaseEntry entry) =>
|
||||
$"{(entry is INamedEntry namedEntry ? namedEntry.EntryName : entry.ID.ToString())}.{Extension}";
|
||||
|
||||
public override void Push(DatabaseEntry entry)
|
||||
{
|
||||
var type = entry.GetType();
|
||||
Entries[entry.ID] = entry;
|
||||
var directory = _entryTypeDirectories[type];
|
||||
File.WriteAllBytes(Path.Combine(directory.FullName, GetFileName(entry)), Serialize(entry));
|
||||
}
|
||||
|
||||
public override void Delete(DatabaseEntry entry)
|
||||
{
|
||||
if(Entries.ContainsKey(entry.ID))
|
||||
{
|
||||
var type = entry.GetType();
|
||||
Entries.Remove(entry.ID);
|
||||
var directory = _entryTypeDirectories[type];
|
||||
var file = new FileInfo(Path.Combine(directory.FullName, GetFileName(entry)));
|
||||
if (file.Exists)
|
||||
file.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
public override void PushAll(bool soft = false)
|
||||
{
|
||||
foreach(var entry in Entries.Values.ToArray()) Push(entry);
|
||||
}
|
||||
|
||||
public void ObserveChanges()
|
||||
{
|
||||
foreach (var directory in _entryTypeDirectories.Values)
|
||||
{
|
||||
var watcher = new FileSystemWatcher(directory.FullName);
|
||||
watcher.Changed += (sender, args) =>
|
||||
{
|
||||
var entry = Deserialize(File.ReadAllBytes(args.FullPath));
|
||||
Entries[entry.ID] = entry;
|
||||
EntryUpdated.OnNext(entry);
|
||||
};
|
||||
watcher.Created += (sender, args) =>
|
||||
{
|
||||
var entry = Deserialize(File.ReadAllBytes(args.FullPath));
|
||||
Entries[entry.ID] = entry;
|
||||
EntryAdded.OnNext(entry);
|
||||
};
|
||||
watcher.Deleted += (sender, args) =>
|
||||
{
|
||||
var entry = Deserialize(File.ReadAllBytes(args.FullPath));
|
||||
Entries[entry.ID] = entry;
|
||||
EntryDeleted.OnNext(entry);
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MultiFileJsonBackingStore : MultiFileBackingStore
|
||||
{
|
||||
public MultiFileJsonBackingStore(string path) : base(path)
|
||||
{
|
||||
RegisterResolver.Register();
|
||||
}
|
||||
|
||||
public override byte[] Serialize(DatabaseEntry entry)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(entry));
|
||||
}
|
||||
|
||||
public override DatabaseEntry Deserialize(byte[] data)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<DatabaseEntry>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
|
||||
public override string Extension => "json";
|
||||
}
|
||||
|
||||
public class MultiFileMessagePackBackingStore : MultiFileBackingStore
|
||||
{
|
||||
public MultiFileMessagePackBackingStore(string path) : base(path)
|
||||
{
|
||||
RegisterResolver.Register();
|
||||
}
|
||||
|
||||
public override byte[] Serialize(DatabaseEntry entry)
|
||||
{
|
||||
return MessagePackSerializer.Serialize(entry);
|
||||
}
|
||||
|
||||
public override DatabaseEntry Deserialize(byte[] data)
|
||||
{
|
||||
return MessagePackSerializer.Deserialize<DatabaseEntry>(data);
|
||||
}
|
||||
|
||||
public override string Extension => "msgpack";
|
||||
}
|
||||
|
||||
public abstract class SingleFileBackingStore : CacheBackingStore
|
||||
{
|
||||
public FileInfo FileInfo { get; }
|
||||
|
||||
public abstract byte[] Serialize(DatabaseEntry[] entries);
|
||||
public abstract DatabaseEntry[] Deserialize(byte[] data);
|
||||
|
||||
public SingleFileBackingStore(string filePath)
|
||||
{
|
||||
FileInfo = new FileInfo(filePath);
|
||||
}
|
||||
|
||||
public override void PullAll()
|
||||
{
|
||||
if (!FileInfo.Exists) return;
|
||||
|
||||
foreach (var entry in Deserialize(File.ReadAllBytes(FileInfo.FullName)))
|
||||
{
|
||||
Entries[entry.ID] = entry;
|
||||
EntryAdded.OnNext(entry);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Push(DatabaseEntry entry)
|
||||
{
|
||||
var type = entry.GetType();
|
||||
Entries[entry.ID] = entry;
|
||||
PushAll();
|
||||
}
|
||||
|
||||
public override void Delete(DatabaseEntry entry)
|
||||
{
|
||||
if(Entries.ContainsKey(entry.ID))
|
||||
{
|
||||
Entries.Remove(entry.ID);
|
||||
PushAll();
|
||||
}
|
||||
}
|
||||
|
||||
public override void PushAll(bool soft = false)
|
||||
{
|
||||
var entriesArray = Entries.Values.ToArray();
|
||||
File.WriteAllBytes(FileInfo.FullName, Serialize(entriesArray));
|
||||
}
|
||||
}
|
||||
|
||||
public class SingleFileMessagePackBackingStore : SingleFileBackingStore
|
||||
{
|
||||
public SingleFileMessagePackBackingStore(string filePath) : base(filePath)
|
||||
{
|
||||
RegisterResolver.Register();
|
||||
}
|
||||
|
||||
public override byte[] Serialize(DatabaseEntry[] entries)
|
||||
{
|
||||
return MessagePackSerializer.Serialize(entries);
|
||||
}
|
||||
|
||||
public override DatabaseEntry[] Deserialize(byte[] data)
|
||||
{
|
||||
return MessagePackSerializer.Deserialize<DatabaseEntry[]>(data);
|
||||
}
|
||||
}
|
||||
|
||||
public class SingleFileJsonBackingStore : SingleFileBackingStore
|
||||
{
|
||||
public SingleFileJsonBackingStore(string filePath) : base(filePath)
|
||||
{
|
||||
RegisterResolver.Register();
|
||||
}
|
||||
|
||||
public override byte[] Serialize(DatabaseEntry[] entries)
|
||||
{
|
||||
return Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(entries));
|
||||
}
|
||||
|
||||
public override DatabaseEntry[] Deserialize(byte[] data)
|
||||
{
|
||||
return JsonConvert.DeserializeObject<DatabaseEntry[]>(Encoding.UTF8.GetString(data));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a43b39c6991618b43aed4a24ffcdc0ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
/* 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 CultMath;
|
||||
using static CultMath.math;
|
||||
|
||||
public interface INamedEntry
|
||||
{
|
||||
string EntryName { get; set; }
|
||||
}
|
||||
|
||||
[MessagePackObject,
|
||||
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)),
|
||||
Union(32, typeof(FactionProductData))]
|
||||
public abstract class DatabaseEntry
|
||||
{
|
||||
[JsonProperty("id"), Key(0)]
|
||||
public Guid ID = Guid.NewGuid();
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return ID.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj is DatabaseEntry entry) return entry.ID == ID;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class DatabaseLink<T> : DatabaseLinkBase where T : DatabaseEntry
|
||||
{
|
||||
[IgnoreMember]
|
||||
public T Value => Cache.Get<T>(LinkID);
|
||||
}
|
||||
|
||||
[MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class DatabaseLinkBase
|
||||
{
|
||||
[Key(0), JsonProperty("linkID")]
|
||||
public Guid LinkID;
|
||||
|
||||
[IgnoreMember]
|
||||
public static CultCache Cache;
|
||||
}
|
||||
|
||||
public interface ITintInspector
|
||||
{
|
||||
float3 TintColor { get; }
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3bb4780bed7bb544dbf6ea2223dd8f06
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,128 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
public static class ReflectionExtensions
|
||||
{
|
||||
// Every type that can be loaded from every assembly in the domain. An assembly whose dependencies are missing
|
||||
// (a Unity plugin referencing UnityEngine when running outside Unity) still yields the types that do load.
|
||||
private static IEnumerable<Type> LoadableTypes()
|
||||
{
|
||||
return AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly =>
|
||||
{
|
||||
try { return assembly.GetTypes(); }
|
||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); }
|
||||
});
|
||||
}
|
||||
|
||||
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] = LoadableTypes().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] = LoadableTypes().Where(type.IsAssignableFrom).ToArray();
|
||||
}
|
||||
|
||||
private static Dictionary<Type,Type[]> GenericChildClasses = new Dictionary<Type, Type[]>();
|
||||
public static Type[] GetAllGenericChildClasses(this Type genericType)
|
||||
{
|
||||
if (GenericChildClasses.ContainsKey(genericType))
|
||||
return GenericChildClasses[genericType];
|
||||
return GenericChildClasses[genericType] = LoadableTypes().Where(type=>type.IsAssignableToGenericType(genericType)).ToArray();
|
||||
}
|
||||
|
||||
public static bool IsAssignableToGenericType(this Type givenType, Type genericType)
|
||||
{
|
||||
var interfaceTypes = givenType.GetInterfaces();
|
||||
|
||||
foreach (var it in interfaceTypes)
|
||||
{
|
||||
if (it.IsGenericType && it.GetGenericTypeDefinition() == genericType)
|
||||
return true;
|
||||
}
|
||||
|
||||
if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericType)
|
||||
return true;
|
||||
|
||||
Type baseType = givenType.BaseType;
|
||||
if (baseType == null) return false;
|
||||
|
||||
return IsAssignableToGenericType(baseType, genericType);
|
||||
}
|
||||
|
||||
public static string SplitCamelCase( this string str )
|
||||
{
|
||||
return Regex.Replace(
|
||||
Regex.Replace(
|
||||
str,
|
||||
@"(\P{Ll})(\P{Ll}\p{Ll})",
|
||||
"$1 $2"
|
||||
),
|
||||
@"(\p{Ll})(\P{Ll})",
|
||||
"$1 $2"
|
||||
);
|
||||
}
|
||||
|
||||
public static string FormatTypeName(this string typeName)
|
||||
{
|
||||
return (typeName.EndsWith("Data", StringComparison.InvariantCultureIgnoreCase)
|
||||
? typeName.Substring(0, typeName.Length - 4)
|
||||
: typeName).SplitCamelCase();
|
||||
}
|
||||
|
||||
public static string GetFullName(this Type t)
|
||||
{
|
||||
if (!t.IsGenericType)
|
||||
return t.Name.FormatTypeName();
|
||||
|
||||
var name = t.Name.FormatTypeName();
|
||||
return
|
||||
$"{name.Substring(0, name.LastIndexOf("`"))}{t.GetGenericArguments().Aggregate("<", (aggregate, type) => $"{aggregate}{(aggregate == "<" ? "" : ",")}{GetFullName(type)}")}>";
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fd5642f26b80465fb57f3d2610633140
|
||||
timeCreated: 1617055075
|
||||
|
|
@ -1,169 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using CultMath;
|
||||
using static CultMath.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;
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fafad9d553198e942a5501ea1472ec9c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f94c63c8b140fb34bb5d70a8d8a5dbd6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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));
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6036d25d64e90064ca92c91f6d7827b2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 01722fba3f2fd3942bca61d48508ad27
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace JsonKnownTypes.Exceptions
|
||||
{
|
||||
public class JsonKnownTypesException : Exception
|
||||
{
|
||||
public JsonKnownTypesException(string message)
|
||||
: base(message)
|
||||
{ }
|
||||
|
||||
public JsonKnownTypesException(string message, Exception innerException)
|
||||
: base(message, innerException)
|
||||
{ }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 36f9ed87d773cf146bf68e828cefe89c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f7c6582f43e22994ebbaf0e139e63dc5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
namespace JsonKnownTypes
|
||||
{
|
||||
public class JsonDiscriminatorSettings
|
||||
{
|
||||
public string Name { get; set; } = "$type";
|
||||
public bool AutoJsonKnown { get; set; } = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5f09ee78f257904caa3ab939d3edc65
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace JsonKnownTypes
|
||||
{
|
||||
public class JsonKnownThisTypeAttribute : Attribute
|
||||
{
|
||||
public string Discriminator { get; }
|
||||
|
||||
public JsonKnownThisTypeAttribute()
|
||||
{ }
|
||||
|
||||
public JsonKnownThisTypeAttribute(string discriminator)
|
||||
{
|
||||
Discriminator = discriminator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c8dc4cbd1c54167409cf14ec8ec37d70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ecbe3646a4d9ca04eac598b60e5c77ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<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>
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 937d902757d946b47a7bea20ade37beb
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: bce1b7fa2da230447b3614d23394ee9f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
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 ArgumentException($"Json Known Types: Type Unknown {objectType.FullName}!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b0a6c832fc846634789aa691cd2b81d9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 77ce621509349204a87085f089b3daa3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
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>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 99b988650c739094aa3a5ba7040ea379
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a361505c5408b374788cbaeed6fa2f55
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6d6706b0998d8af458321fd5f35906fb
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c30d51fc767627a41b65f5cdd2b22cc3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using MessagePack;
|
||||
using MessagePack.ReactivePropertyExtension;
|
||||
using MessagePack.Resolvers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
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;
|
||||
|
||||
// Add CultMath serialization support to Newtonsoft JSON
|
||||
JsonConvert.DefaultSettings = () => new JsonSerializerSettings
|
||||
{
|
||||
Converters = new List<JsonConverter>
|
||||
{
|
||||
new MathJsonConverter()
|
||||
}
|
||||
};
|
||||
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc638a5fae4350643871d45495a49643
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
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 == null ? "" : value.AssemblyQualifiedName);
|
||||
}
|
||||
|
||||
public Type Deserialize(ref MessagePackReader reader, MessagePackSerializerOptions options)
|
||||
{
|
||||
if (reader.IsNil)
|
||||
{
|
||||
return null; //throw new InvalidOperationException("typecode is null, struct not supported");
|
||||
}
|
||||
|
||||
var assemblyQualifiedName = reader.ReadString();
|
||||
if (string.IsNullOrEmpty(assemblyQualifiedName)) return null;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ede4e7a24e20d134fb02868d010af83d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -23,6 +23,49 @@ public static class Extensions
|
|||
return baseType.GetInterfaces().Any(interfaceType.Equals);
|
||||
}
|
||||
|
||||
// Every loadable type assignable to this one. An assembly whose dependencies are missing (a Unity plugin
|
||||
// referencing UnityEngine outside Unity) still yields the types that do load.
|
||||
private static readonly Dictionary<Type, Type[]> ChildClasses = new Dictionary<Type, Type[]>();
|
||||
public static Type[] GetAllChildClasses(this Type type)
|
||||
{
|
||||
if (ChildClasses.TryGetValue(type, out var children)) return children;
|
||||
return ChildClasses[type] = AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly =>
|
||||
{
|
||||
try { return assembly.GetTypes(); }
|
||||
catch (ReflectionTypeLoadException e) { return e.Types.Where(t => t != null); }
|
||||
}).Where(type.IsAssignableFrom).ToArray();
|
||||
}
|
||||
|
||||
public static string SplitCamelCase(this string str) =>
|
||||
Regex.Replace(Regex.Replace(str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2");
|
||||
|
||||
public static string FormatTypeName(this string typeName) =>
|
||||
(typeName.EndsWith("Data", StringComparison.InvariantCultureIgnoreCase)
|
||||
? typeName.Substring(0, typeName.Length - 4)
|
||||
: typeName).SplitCamelCase();
|
||||
|
||||
public static T MaxBy<T, U>(this IEnumerable<T> items, Func<T, U> selector) => items.Best(selector, 1);
|
||||
public static T MinBy<T, U>(this IEnumerable<T> items, Func<T, U> selector) => items.Best(selector, -1);
|
||||
|
||||
private static T Best<T, U>(this IEnumerable<T> items, Func<T, U> selector, int sign)
|
||||
{
|
||||
using var e = items.GetEnumerator();
|
||||
if (!e.MoveNext()) throw new InvalidOperationException("Empty input sequence");
|
||||
var best = e.Current;
|
||||
var bestValue = selector(best);
|
||||
var comparer = Comparer<U>.Default;
|
||||
while (e.MoveNext())
|
||||
{
|
||||
var value = selector(e.Current);
|
||||
if (comparer.Compare(value, bestValue) * sign > 0)
|
||||
{
|
||||
best = e.Current;
|
||||
bestValue = value;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
public static T[] WeightedRandomElements<T>(this IEnumerable<T> collection, ref Random random, Func<T, float> weightFunction, int count)
|
||||
{
|
||||
var elements = collection as T[] ?? collection.ToArray();
|
||||
|
|
|
|||
|
|
@ -11,73 +11,6 @@ using CultMath;
|
|||
using static CultMath.math;
|
||||
using static NoiseFbm;
|
||||
|
||||
[Inspectable, Serializable, DatabaseCategory("Galaxy"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class GalaxyMapLayerData : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[Inspectable, JsonProperty("coreBoost"), Key(1)]
|
||||
public float CoreBoost = 1.05f;
|
||||
|
||||
[Inspectable, JsonProperty("coreBoostOffset"), Key(2)]
|
||||
public float CoreBoostOffset = .1f;
|
||||
|
||||
[Inspectable, JsonProperty("coreBoostPower"), Key(3)]
|
||||
public float CoreBoostPower = 2.25f;
|
||||
|
||||
[Inspectable, JsonProperty("spokeScale"), Key(4)]
|
||||
public float SpokeScale = 1;
|
||||
|
||||
[Inspectable, JsonProperty("spokeOffset"), Key(5)]
|
||||
public float SpokeOffset = 0;
|
||||
|
||||
[Inspectable, JsonProperty("edgeReduction"), Key(6)]
|
||||
public float EdgeReduction = 3;
|
||||
|
||||
[Inspectable, JsonProperty("noiseOffset"), Key(7)]
|
||||
public float NoiseOffset = 0;
|
||||
|
||||
[Inspectable, JsonProperty("noiseAmplitude"), Key(8)]
|
||||
public float NoiseAmplitude = 1.5f;
|
||||
|
||||
[Inspectable, JsonProperty("noiseGain"), Key(9)]
|
||||
public float NoiseGain = .7f;
|
||||
|
||||
[Inspectable, JsonProperty("noiseLacunarity"), Key(10)]
|
||||
public float NoiseLacunarity = 2;
|
||||
|
||||
[Inspectable, JsonProperty("noiseOctaves"), Key(11)]
|
||||
public int NoiseOctaves = 7;
|
||||
|
||||
[Inspectable, JsonProperty("noiseFrequency"), Key(12)]
|
||||
public float NoiseFrequency = 1;
|
||||
|
||||
[Inspectable, JsonProperty("noisePosition"), Key(13)]
|
||||
public float NoisePosition = 1337;
|
||||
|
||||
[Inspectable, JsonProperty("name"), Key(14)]
|
||||
public string Name;
|
||||
|
||||
public float Evaluate(float2 uv, GalaxyShapeSettings settings)
|
||||
{
|
||||
float2 offset = -float2(.5f, .5f)+uv;
|
||||
float circle = (.5f-length(offset))*2;
|
||||
float angle = pow(length(offset)*2,settings.TwistExponent) * settings.Twist;
|
||||
float2 t = float2(offset.x*cos(angle) - offset.y*sin(angle), offset.x*sin(angle) + offset.y*cos(angle));
|
||||
float atan = atan2(t.y,t.x);
|
||||
float spokes = (sin(atan*settings.Arms) + SpokeOffset) * SpokeScale;
|
||||
float noise = fBm(uv + float2(NoisePosition), NoiseOctaves, NoiseFrequency, NoiseOffset, NoiseAmplitude, NoiseLacunarity, NoiseGain);
|
||||
float shape = lerp(spokes - EdgeReduction * length(offset), 1, pow(circle, CoreBoostPower) * CoreBoost) + CoreBoostOffset;
|
||||
float gal = max(shape - noise * saturate(circle), 0);
|
||||
|
||||
return gal;
|
||||
}
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Name;
|
||||
set => Name = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static class NoiseFbm
|
||||
{
|
||||
public static float3 fBm3(float2 p, int octaves, float frequency, float offset, float amplitude, float lacunarity, float gain)
|
||||
|
|
|
|||
|
|
@ -1,29 +0,0 @@
|
|||
/* 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 MessagePack;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
[DatabaseCategory("Users"), MessagePackObject, JsonObject(MemberSerialization.OptIn)]
|
||||
public class PlayerData : DatabaseEntry, INamedEntry
|
||||
{
|
||||
[JsonProperty("email"), Key(1)]
|
||||
public string Email;
|
||||
|
||||
[JsonProperty("password"), Key(2)]
|
||||
public string Password;
|
||||
|
||||
[JsonProperty("username"), Key(3)]
|
||||
public string Username;
|
||||
|
||||
[JsonProperty("corporation"), Key(4)]
|
||||
public Guid Corporation;
|
||||
|
||||
[IgnoreMember] public string EntryName
|
||||
{
|
||||
get => Username;
|
||||
set => Username = value;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6daac48880264dcc91c928f0dd9c2abb
|
||||
timeCreated: 1591829144
|
||||
Loading…
Reference in a new issue