mirror of
https://github.com/DCFApixels/DragonECS.git
synced 2025-09-19 10:34:37 +08:00
Docs Stash
This commit is contained in:
parent
8aac055712
commit
716328741c
289
src/Debug/DragonDocs/DragonDocs.cs
Normal file
289
src/Debug/DragonDocs/DragonDocs.cs
Normal file
@ -0,0 +1,289 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.PoolsCore;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Docs
|
||||||
|
{
|
||||||
|
[Serializable]
|
||||||
|
[DataContract]
|
||||||
|
public class DragonDocs : ISerializable
|
||||||
|
{
|
||||||
|
[NonSerialized]
|
||||||
|
private List<DragonDocsMeta> _metas = new List<DragonDocsMeta>();
|
||||||
|
[DataMember]
|
||||||
|
private SortedDictionary<string, List<DragonDocsMeta>> _groups = new SortedDictionary<string, List<DragonDocsMeta>>();
|
||||||
|
|
||||||
|
protected DragonDocs(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
public void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
private DragonDocs() { }
|
||||||
|
private DragonDocs(List<DragonDocsMeta> metaList)
|
||||||
|
{
|
||||||
|
_metas = metaList;
|
||||||
|
foreach (var docsMeta in _metas)
|
||||||
|
{
|
||||||
|
string group = docsMeta.Group;
|
||||||
|
if (_groups.TryGetValue(group, out List<DragonDocsMeta> groupMetas) == false)
|
||||||
|
{
|
||||||
|
groupMetas = new List<DragonDocsMeta>();
|
||||||
|
_groups.Add(group, groupMetas);
|
||||||
|
}
|
||||||
|
groupMetas.Add(docsMeta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static DragonDocs Generate()
|
||||||
|
{
|
||||||
|
DragonDocs result = new DragonDocs();
|
||||||
|
List<Type> types = GetTypes();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
TypeMeta meta = type.ToMeta();
|
||||||
|
DragonDocsMeta docsMeta = new DragonDocsMeta(meta);
|
||||||
|
result._metas.Add(docsMeta);
|
||||||
|
string group = meta.Group.Name;
|
||||||
|
|
||||||
|
if (result._groups.TryGetValue(group, out List<DragonDocsMeta> groupMetas) == false)
|
||||||
|
{
|
||||||
|
groupMetas = new List<DragonDocsMeta>();
|
||||||
|
result._groups.Add(group, groupMetas);
|
||||||
|
}
|
||||||
|
|
||||||
|
groupMetas.Add(docsMeta);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private static List<Type> GetTypes()
|
||||||
|
{
|
||||||
|
Type ecsMetaAttributeType = typeof(EcsMetaAttribute);
|
||||||
|
List<Type> result = new List<Type>();
|
||||||
|
Type memberType = typeof(IEcsMember);
|
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
{
|
||||||
|
var types = assembly.GetTypes();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (memberType.IsAssignableFrom(type) || Attribute.GetCustomAttributes(type, ecsMetaAttributeType, false).Length > 1)
|
||||||
|
{
|
||||||
|
result.Add(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#region Serialization
|
||||||
|
public string SerializeToJson()
|
||||||
|
{
|
||||||
|
StringBuilder json = new StringBuilder();
|
||||||
|
json.Append("{ \"data\": [\r");
|
||||||
|
foreach (var group in _groups)
|
||||||
|
{
|
||||||
|
//json.Append($"\"{group.Key}\": ");
|
||||||
|
json.Append($"{{ \"key\": \"{group.Key}\",\r\"values\": [");
|
||||||
|
foreach (var meta in group.Value)
|
||||||
|
{
|
||||||
|
meta.SerializeToJson(json);
|
||||||
|
}
|
||||||
|
json.Append("] }, \r");
|
||||||
|
}
|
||||||
|
json.Append(" ] }");
|
||||||
|
return json.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static DragonDocs CreateDocs(ref JsonIterator reader)
|
||||||
|
{
|
||||||
|
JsonNode node;
|
||||||
|
List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
|
||||||
|
while (reader.Next())
|
||||||
|
{
|
||||||
|
node = reader.Next();
|
||||||
|
if (node.IsKey && node.EqualsString("data") && reader.Next().IsEnter)
|
||||||
|
{
|
||||||
|
while (reader.Next().IsEnter && (node = reader.Next()).IsKey && node.EqualsString("key"))
|
||||||
|
{
|
||||||
|
node = reader.Next();
|
||||||
|
string group = node.ToString();
|
||||||
|
node = reader.Next();
|
||||||
|
if (node.IsKey && node.EqualsString("values") && reader.Next().IsEnter)
|
||||||
|
{
|
||||||
|
while (reader.Next().IsEnter)
|
||||||
|
{
|
||||||
|
metas.Add(DragonDocsMeta.DeserializeFromJson(ref reader, group));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(reader.Next().IsExit == false)
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new DragonDocs(metas);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception();
|
||||||
|
}
|
||||||
|
public unsafe static DragonDocs DeserializeFromJson(string jsonString)
|
||||||
|
{
|
||||||
|
CB.Set(jsonString);
|
||||||
|
fixed (char* ptr = jsonString)
|
||||||
|
{
|
||||||
|
JsonIterator reader = new JsonIterator(ptr, jsonString.Length);
|
||||||
|
return CreateDocs(ref reader);
|
||||||
|
}
|
||||||
|
throw new Exception();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//fixed (char* ptr = jsonString)
|
||||||
|
//{
|
||||||
|
// //var result = DragonDocsJsonReader.ReadJson(ptr, jsonString.Length);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
//
|
||||||
|
//throw new NotImplementedException();
|
||||||
|
|
||||||
|
//jsonString = jsonString.Replace("{", "").Replace("}", "").Replace("\"", "");
|
||||||
|
|
||||||
|
// Разбиваем JSON строку на пары ключ-значение
|
||||||
|
//string[] parts = jsonString.Split(new string[] { "key:", "values:[" }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//string[] parts = jsonString.Split("\"key\":", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
//List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//for (int i = 1; i < parts.Length; i += 2)
|
||||||
|
//{
|
||||||
|
// string key = parts[i];
|
||||||
|
// int indexOf = key.IndexOf('"');
|
||||||
|
// key = key.Substring(indexOf + 1, key.IndexOf('"', indexOf + 1) - indexOf - 1);
|
||||||
|
// string values = parts[i + 1];
|
||||||
|
//
|
||||||
|
// Match match = Regex.Match(values, @"""values"": \[(.*?)\].*");
|
||||||
|
// if (match.Success)
|
||||||
|
// {
|
||||||
|
// values = match.Groups[1].Value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CB.Set(values);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// string[] metaValues = values.Split(new string[] { "},{" }, StringSplitOptions.None);
|
||||||
|
//
|
||||||
|
// foreach (string metaValue in metaValues)
|
||||||
|
// {
|
||||||
|
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
|
||||||
|
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", key);
|
||||||
|
// metas.Add(meta);
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//return new DragonDocs(metas);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Удаляем лишние символы из JSON строки
|
||||||
|
//json = json.Replace("{", "").Replace("}", "").Replace("\"", "");
|
||||||
|
//
|
||||||
|
//// Разбиваем JSON строку на пары ключ-значение
|
||||||
|
//string[] pairs = json.Split(',');
|
||||||
|
//
|
||||||
|
//// Создаем переменные для хранения текущих значений
|
||||||
|
//string currentKey = "";
|
||||||
|
//List<DragonDocsMeta> currentMetas = new List<DragonDocsMeta>();
|
||||||
|
//
|
||||||
|
//foreach (string pair in pairs)
|
||||||
|
//{
|
||||||
|
// string[] keyValue = pair.Split(':');
|
||||||
|
//
|
||||||
|
// if (keyValue.Length == 2)
|
||||||
|
// {
|
||||||
|
// string key = keyValue[0].Trim();
|
||||||
|
// string value = keyValue[1].Trim();
|
||||||
|
//
|
||||||
|
// if (key == "key")
|
||||||
|
// {
|
||||||
|
// currentKey = value;
|
||||||
|
// }
|
||||||
|
// else if (key == "values")
|
||||||
|
// {
|
||||||
|
// // Очищаем список метаданных перед добавлением новых
|
||||||
|
// currentMetas.Clear();
|
||||||
|
//
|
||||||
|
// // Разбиваем значение на отдельные метаданные и десериализуем каждое из них
|
||||||
|
// string[] metaValues = value.Split(new string[] { "},{" }, StringSplitOptions.None);
|
||||||
|
// foreach (string metaValue in metaValues)
|
||||||
|
// {
|
||||||
|
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
|
||||||
|
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", currentKey);
|
||||||
|
// currentMetas.Add(meta);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//return new DragonDocs(currentMetas);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//public static DragonDocs DeserializeFromJson(string jsonString)
|
||||||
|
//{
|
||||||
|
// //jsonString = jsonString.Replace("{", "").Replace("}", "").Replace("\"", "");
|
||||||
|
//
|
||||||
|
// // Разбиваем JSON строку на пары ключ-значение
|
||||||
|
// //string[] parts = jsonString.Split(new string[] { "key:", "values:[" }, StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
// string[] parts = jsonString.Split("\"key\":", StringSplitOptions.RemoveEmptyEntries);
|
||||||
|
// List<DragonDocsMeta> metas = new List<DragonDocsMeta>();
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// for (int i = 1; i < parts.Length; i += 2)
|
||||||
|
// {
|
||||||
|
// string key = parts[i];
|
||||||
|
// int indexOf = key.IndexOf('"');
|
||||||
|
// key = key.Substring(indexOf + 1, key.IndexOf('"', indexOf + 1) - indexOf - 1);
|
||||||
|
// string values = parts[i + 1];
|
||||||
|
//
|
||||||
|
// Match match = Regex.Match(values, @"""values"": \[(.*?)\].*");
|
||||||
|
// if (match.Success)
|
||||||
|
// {
|
||||||
|
// values = match.Groups[1].Value;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// CB.Set(values);
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// string[] metaValues = values.Split(new string[] { "},{" }, StringSplitOptions.None);
|
||||||
|
//
|
||||||
|
// foreach (string metaValue in metaValues)
|
||||||
|
// {
|
||||||
|
// // Десериализация отдельного метаданных (нужно реализовать метод DeserializeFromJson в DragonDocsMeta)
|
||||||
|
// DragonDocsMeta meta = DragonDocsMeta.DeserializeFromJson("{" + metaValue + "}", key);
|
||||||
|
// metas.Add(meta);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return new DragonDocs(metas);
|
||||||
|
//
|
||||||
|
//}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
214
src/Debug/DragonDocs/DragonDocsMeta.cs
Normal file
214
src/Debug/DragonDocs/DragonDocsMeta.cs
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Docs
|
||||||
|
{
|
||||||
|
public class DragonDocsMeta
|
||||||
|
{
|
||||||
|
private Type _sourceType;
|
||||||
|
private bool _isInitSourceType = false;
|
||||||
|
public readonly string AssemblyQualifiedName = string.Empty;
|
||||||
|
|
||||||
|
public readonly string Name = string.Empty;
|
||||||
|
public readonly bool IsCustomName = false;
|
||||||
|
public readonly MetaColor Color = MetaColor.BlackColor;
|
||||||
|
public readonly bool IsCustomColor = false;
|
||||||
|
public readonly string Autor = string.Empty;
|
||||||
|
public readonly string Description = string.Empty;
|
||||||
|
|
||||||
|
public readonly string Group = string.Empty;
|
||||||
|
public readonly string Tags = string.Empty;
|
||||||
|
|
||||||
|
public DragonDocsMeta(TypeMeta meta)
|
||||||
|
{
|
||||||
|
_sourceType = meta.Type;
|
||||||
|
AssemblyQualifiedName = meta.Type.AssemblyQualifiedName;
|
||||||
|
|
||||||
|
Name = meta.Name;
|
||||||
|
IsCustomName = meta.IsCustomName;
|
||||||
|
Color = meta.Color;
|
||||||
|
IsCustomColor = meta.IsCustomColor;
|
||||||
|
Autor = meta.Description.Author;
|
||||||
|
Description = meta.Description.Text;
|
||||||
|
|
||||||
|
Group = meta.Group.Name;
|
||||||
|
Tags = string.Join(", ", meta.Tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool TryGetSourceType(out Type type)
|
||||||
|
{
|
||||||
|
type = GetSourceType();
|
||||||
|
return type != null;
|
||||||
|
}
|
||||||
|
private Type GetSourceType()
|
||||||
|
{
|
||||||
|
if (_isInitSourceType) { return _sourceType; }
|
||||||
|
_isInitSourceType = true;
|
||||||
|
_sourceType = Type.GetType(AssemblyQualifiedName);
|
||||||
|
return _sourceType;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Serialization
|
||||||
|
public void SerializeToJson(StringBuilder json)
|
||||||
|
{
|
||||||
|
json.Append("{");
|
||||||
|
|
||||||
|
SerializeFieldToJson(json, nameof(AssemblyQualifiedName), AssemblyQualifiedName, true, true);
|
||||||
|
SerializeFieldToJson(json, nameof(Name), Name, true, true);
|
||||||
|
SerializeFieldToJson(json, nameof(IsCustomName), IsCustomName.ToString().ToLower(), false, true);
|
||||||
|
SerializeFieldToJson(json, nameof(Color), Color.ToString(), true, true);
|
||||||
|
SerializeFieldToJson(json, nameof(IsCustomColor), IsCustomColor.ToString().ToLower(), false, true);
|
||||||
|
|
||||||
|
SerializeFieldToJson(json, nameof(Autor), Autor, true, false);
|
||||||
|
SerializeFieldToJson(json, nameof(Description), Description, true, false);
|
||||||
|
//SerializeFieldToJson(json, nameof(Group), Group, false);
|
||||||
|
SerializeFieldToJson(json, nameof(Tags), Tags, true, false);
|
||||||
|
|
||||||
|
json.Remove(json.Length - 1, 1);
|
||||||
|
json.Append("}");
|
||||||
|
}
|
||||||
|
private void SerializeFieldToJson(StringBuilder json, string fieldName, string value, bool isString, bool alwaysSerialize)
|
||||||
|
{
|
||||||
|
if (alwaysSerialize || !string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
json.Append($"\"{fieldName}\":");
|
||||||
|
if (isString)
|
||||||
|
{
|
||||||
|
json.Append($"\"{value}\"");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
json.Append($"{value}");
|
||||||
|
}
|
||||||
|
json.Append(",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal static DragonDocsMeta DeserializeFromJson(ref JsonIterator reader, string group)
|
||||||
|
{
|
||||||
|
return new DragonDocsMeta(ref reader, group);
|
||||||
|
}
|
||||||
|
private unsafe DragonDocsMeta(ref JsonIterator reader, string group)
|
||||||
|
{
|
||||||
|
Group = group;
|
||||||
|
JsonNode node;
|
||||||
|
int depth = reader.Depth;
|
||||||
|
while ((node = reader.Next()).Depth >= depth)
|
||||||
|
{
|
||||||
|
//TODO тут можно сделать систему которая бы учитывала что порядок полей может меняться по мере разработки.
|
||||||
|
//Есть идея через рефлекшн разбирать состояние типа, после создавать массив индексов,
|
||||||
|
//а эти индексы потом могли бы применяться в switch-е в котором кейсы на каждый индекс по порядку
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(AssemblyQualifiedName)))
|
||||||
|
{
|
||||||
|
AssemblyQualifiedName = reader.Next().ToString();
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(Name)))
|
||||||
|
{
|
||||||
|
Name = reader.Next().ToString();
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(IsCustomName)))
|
||||||
|
{
|
||||||
|
IsCustomName = UnsafeBoolParse(reader.Next().Ptr);
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(Color)))
|
||||||
|
{
|
||||||
|
node = reader.Next();
|
||||||
|
Color = MetaColor.Parse(node.Ptr, node.Length);
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(IsCustomColor)))
|
||||||
|
{
|
||||||
|
IsCustomColor = UnsafeBoolParse(reader.Next().Ptr);
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(Autor)))
|
||||||
|
{
|
||||||
|
Autor = reader.Next().ToString();
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(Description)))
|
||||||
|
{
|
||||||
|
Description = reader.Next().ToString();
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
//if (node.IsKey && node.EqualsString(nameof(Group)))
|
||||||
|
//{
|
||||||
|
// Group = reader.Next().ToString();
|
||||||
|
// if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
//}
|
||||||
|
if (node.IsKey && node.EqualsString(nameof(Tags)))
|
||||||
|
{
|
||||||
|
Tags = reader.Next().ToString();
|
||||||
|
if ((node = reader.Next()).Depth < depth) { break; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private static unsafe bool UnsafeBoolParse(char* ptr)
|
||||||
|
{
|
||||||
|
return char.ToLower(ptr[0]) == 't';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static DragonDocsMeta DeserializeFromJson(string json, string currentGroup)
|
||||||
|
{
|
||||||
|
return new DragonDocsMeta(json, currentGroup);
|
||||||
|
}
|
||||||
|
/// <summary> DeserializeFromJson constructor. </summary>
|
||||||
|
private DragonDocsMeta(string json, string currentGroup)
|
||||||
|
{
|
||||||
|
// Удаляем лишние символы из JSON строки
|
||||||
|
json = json.Replace("{", "").Replace("}", "").Replace("\"", "");
|
||||||
|
// Разбиваем JSON строку на пары ключ-значение
|
||||||
|
string[] pairs = json.Split(',');
|
||||||
|
|
||||||
|
foreach (string pair in pairs)
|
||||||
|
{
|
||||||
|
string[] keyValue = pair.Split(':');
|
||||||
|
|
||||||
|
if (keyValue.Length == 2)
|
||||||
|
{
|
||||||
|
string key = keyValue[0].Trim();
|
||||||
|
string value = keyValue[1].Trim();
|
||||||
|
|
||||||
|
switch (key)
|
||||||
|
{
|
||||||
|
case nameof(AssemblyQualifiedName):
|
||||||
|
AssemblyQualifiedName = value;
|
||||||
|
break;
|
||||||
|
case nameof(Name):
|
||||||
|
Name = value;
|
||||||
|
break;
|
||||||
|
case nameof(IsCustomName):
|
||||||
|
IsCustomName = bool.Parse(value);
|
||||||
|
break;
|
||||||
|
case nameof(Color):
|
||||||
|
Color = MetaColor.Parse(value);
|
||||||
|
break;
|
||||||
|
case nameof(IsCustomColor):
|
||||||
|
IsCustomColor = bool.Parse(value);
|
||||||
|
break;
|
||||||
|
case nameof(Autor):
|
||||||
|
Autor = value;
|
||||||
|
break;
|
||||||
|
case nameof(Description):
|
||||||
|
Description = value;
|
||||||
|
break;
|
||||||
|
case nameof(Tags):
|
||||||
|
Tags = value;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Group = currentGroup;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
215
src/Debug/DragonDocs/JsonIterator.cs
Normal file
215
src/Debug/DragonDocs/JsonIterator.cs
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Internal
|
||||||
|
{
|
||||||
|
internal unsafe ref struct JsonIterator
|
||||||
|
{
|
||||||
|
private char* _jsonPtr;
|
||||||
|
private int _jsonLength;
|
||||||
|
private int _depth;
|
||||||
|
private JsonNode _currentNode;
|
||||||
|
private char _currentChar;
|
||||||
|
public int Depth
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _depth; }
|
||||||
|
}
|
||||||
|
public char Char
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _jsonPtr[0]; }
|
||||||
|
}
|
||||||
|
public JsonNode Current
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return _currentNode; }
|
||||||
|
}
|
||||||
|
public JsonIterator(char* jsonPtr, int jsonLength)
|
||||||
|
{
|
||||||
|
_jsonPtr = jsonPtr - 1;
|
||||||
|
_jsonLength = jsonLength + 1;
|
||||||
|
_depth = 0;
|
||||||
|
_currentChar = '\0';
|
||||||
|
_currentNode = default;
|
||||||
|
}
|
||||||
|
public JsonNode Next()
|
||||||
|
{
|
||||||
|
_currentNode = NextInternal();
|
||||||
|
return _currentNode;
|
||||||
|
}
|
||||||
|
public override string ToString() { return new string(_jsonPtr, 0, _jsonLength); }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private JsonNode NextInternal()
|
||||||
|
{
|
||||||
|
if (NextSymbol() == false)
|
||||||
|
{
|
||||||
|
return new JsonNode(JsonNodeType.NA, null, 0, _depth); ;
|
||||||
|
}
|
||||||
|
if (IsEnterChar(_currentChar))
|
||||||
|
{
|
||||||
|
_depth++;
|
||||||
|
return new JsonNode(JsonNodeType.Enter, _jsonPtr, 1, _depth);
|
||||||
|
}
|
||||||
|
if (IsExitChar(_currentChar))
|
||||||
|
{
|
||||||
|
_depth--;
|
||||||
|
return new JsonNode(JsonNodeType.Exit, _jsonPtr, 1, _depth);
|
||||||
|
}
|
||||||
|
if (_currentChar == '"')
|
||||||
|
{
|
||||||
|
return ReadString();
|
||||||
|
}
|
||||||
|
if (char.IsLetter(_currentChar))
|
||||||
|
{
|
||||||
|
return ReadValue();
|
||||||
|
}
|
||||||
|
throw new FormatException("JSON format error.");
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private JsonNode ReadString()
|
||||||
|
{
|
||||||
|
JsonSpan span = new JsonSpan(_jsonPtr);
|
||||||
|
bool isEscape = false;
|
||||||
|
while (Increment())
|
||||||
|
{
|
||||||
|
if (_currentChar == '"' && isEscape == false)
|
||||||
|
{
|
||||||
|
JsonNodeType type = JsonNodeType.Value;
|
||||||
|
bool x = NextSymbol();
|
||||||
|
if (x && _currentChar == ':')
|
||||||
|
{
|
||||||
|
type = JsonNodeType.Key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Deincrement();
|
||||||
|
}
|
||||||
|
return new JsonNode(type, span.ptr + 1, span.length, _depth);
|
||||||
|
}
|
||||||
|
isEscape = isEscape == false && _currentChar == '\\';
|
||||||
|
span.length++;
|
||||||
|
}
|
||||||
|
throw new FormatException("JSON format error.");
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private JsonNode ReadValue()
|
||||||
|
{
|
||||||
|
JsonSpan span = new JsonSpan(_jsonPtr);
|
||||||
|
while (Increment() && (char.IsWhiteSpace(_currentChar) || _currentChar == ',' || _currentChar == ':' || _currentChar == '}' || _currentChar == ']') == false)
|
||||||
|
{
|
||||||
|
span.length++;
|
||||||
|
}
|
||||||
|
JsonNodeType type = JsonNodeType.Value;
|
||||||
|
Deincrement();
|
||||||
|
if (NextSymbol() && _currentChar == ':')
|
||||||
|
{
|
||||||
|
type = JsonNodeType.Key;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Deincrement();
|
||||||
|
}
|
||||||
|
return new JsonNode(type, span.ptr, span.length + 1, _depth);
|
||||||
|
}
|
||||||
|
private ref struct JsonSpan
|
||||||
|
{
|
||||||
|
public char* ptr;
|
||||||
|
public int length;
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public JsonSpan(char* ptr)
|
||||||
|
{
|
||||||
|
this.ptr = ptr;
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
public override string ToString() { return new string(ptr, 0, length); }
|
||||||
|
}
|
||||||
|
private bool NextSymbol()
|
||||||
|
{
|
||||||
|
bool isNotEnd;
|
||||||
|
while ((isNotEnd = Increment()) && (char.IsWhiteSpace(_currentChar) || _currentChar == ',')) { }
|
||||||
|
return isNotEnd;
|
||||||
|
}
|
||||||
|
private bool Increment()
|
||||||
|
{
|
||||||
|
if (_jsonLength > 1)
|
||||||
|
{
|
||||||
|
_jsonPtr++;
|
||||||
|
_jsonLength--;
|
||||||
|
_currentChar = _jsonPtr[0];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
private void Deincrement()
|
||||||
|
{
|
||||||
|
_jsonPtr--;
|
||||||
|
_jsonLength++;
|
||||||
|
_currentChar = _jsonPtr[0];
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool IsEnterChar(char chr) { return chr == '{' || chr == '['; }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private bool IsExitChar(char chr) { return chr == '}' || chr == ']'; }
|
||||||
|
}
|
||||||
|
internal readonly unsafe ref struct JsonNode
|
||||||
|
{
|
||||||
|
public readonly JsonNodeType Type;
|
||||||
|
public readonly char* Ptr;
|
||||||
|
public readonly int Length;
|
||||||
|
public readonly int Depth;
|
||||||
|
public bool IsEnter
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return Type == JsonNodeType.Enter; }
|
||||||
|
}
|
||||||
|
public bool IsExit
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return Type == JsonNodeType.Exit; }
|
||||||
|
}
|
||||||
|
public bool IsKey
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return Type == JsonNodeType.Key; }
|
||||||
|
}
|
||||||
|
public bool IsValue
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return Type == JsonNodeType.Value; }
|
||||||
|
}
|
||||||
|
public bool IsNotBreak
|
||||||
|
{
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
get { return Type != JsonNodeType.NA; }
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public JsonNode(JsonNodeType type, char* ptr, int length, int depth)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Ptr = ptr;
|
||||||
|
Length = length;
|
||||||
|
Depth = depth;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public override string ToString() { return new string(Ptr, 0, Length); }
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public bool EqualsString(string str)
|
||||||
|
{
|
||||||
|
if (str.Length != Length) { return false; }
|
||||||
|
for (int i = 0; i < str.Length; i++)
|
||||||
|
{
|
||||||
|
if (str[i] != Ptr[i]) { return false; }
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public static implicit operator bool(JsonNode node) { return node.IsNotBreak; }
|
||||||
|
}
|
||||||
|
internal enum JsonNodeType : byte
|
||||||
|
{
|
||||||
|
NA = 0,
|
||||||
|
Key = 1, Value = 2,
|
||||||
|
Enter = 3, Exit = 4,
|
||||||
|
}
|
||||||
|
}
|
14
src/Debug/DragonDocs/JsonStreamReader.cs
Normal file
14
src/Debug/DragonDocs/JsonStreamReader.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS.Internal
|
||||||
|
{
|
||||||
|
internal struct JsonStreamReader
|
||||||
|
{
|
||||||
|
public StreamReader _stream;
|
||||||
|
private static char[] _chars;
|
||||||
|
public void Next()
|
||||||
|
{
|
||||||
|
_stream.Read(_chars, 0, 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,5 @@
|
|||||||
using DCFApixels.DragonECS.Internal;
|
using System;
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
@ -10,7 +7,6 @@ namespace DCFApixels.DragonECS
|
|||||||
public static class EcsDebugUtility
|
public static class EcsDebugUtility
|
||||||
{
|
{
|
||||||
private const BindingFlags RFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
private const BindingFlags RFL_FLAGS = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
|
||||||
private static readonly Dictionary<Type, TypeMeta> _metaCache = new Dictionary<Type, TypeMeta>();
|
|
||||||
|
|
||||||
#region GetGenericTypeName
|
#region GetGenericTypeName
|
||||||
public static string GetGenericTypeFullName<T>(int maxDepth = 2)
|
public static string GetGenericTypeFullName<T>(int maxDepth = 2)
|
||||||
@ -275,20 +271,15 @@ namespace DCFApixels.DragonECS
|
|||||||
#region GetTypeMeta
|
#region GetTypeMeta
|
||||||
public static TypeMeta GetTypeMeta(object obj)
|
public static TypeMeta GetTypeMeta(object obj)
|
||||||
{
|
{
|
||||||
return GetTypeMeta(GetTypeMetaSource(obj).GetType());
|
return TypeMeta.Get(GetTypeMetaSource(obj).GetType());
|
||||||
}
|
}
|
||||||
public static TypeMeta GetTypeMeta<T>()
|
public static TypeMeta GetTypeMeta<T>()
|
||||||
{
|
{
|
||||||
return GetTypeMeta(typeof(T));
|
return TypeMeta.Get(typeof(T));
|
||||||
}
|
}
|
||||||
public static TypeMeta GetTypeMeta(Type type)
|
public static TypeMeta GetTypeMeta(Type type)
|
||||||
{
|
{
|
||||||
if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
|
return TypeMeta.Get(type);
|
||||||
{
|
|
||||||
result = new TypeMeta(type);
|
|
||||||
_metaCache.Add(type, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@ -304,312 +295,6 @@ namespace DCFApixels.DragonECS
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ITypeMeta
|
|
||||||
{
|
|
||||||
Type Type { get; }
|
|
||||||
string Name { get; }
|
|
||||||
MetaColor Color { get; }
|
|
||||||
MetaDescription Description { get; }
|
|
||||||
MetaGroup Group { get; }
|
|
||||||
IReadOnlyCollection<string> Tags { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
|
||||||
public sealed class TypeMeta : ITypeMeta
|
|
||||||
{
|
|
||||||
internal readonly Type _type;
|
|
||||||
|
|
||||||
private bool _isCustomName;
|
|
||||||
private bool _isCustomColor;
|
|
||||||
private bool _isHidden;
|
|
||||||
|
|
||||||
private string _name;
|
|
||||||
private MetaColor _color;
|
|
||||||
private MetaDescription _description;
|
|
||||||
private MetaGroup _group;
|
|
||||||
private IReadOnlyCollection<string> _tags;
|
|
||||||
private int _typeCode;
|
|
||||||
|
|
||||||
private InitFlag _initFlags = InitFlag.None;
|
|
||||||
|
|
||||||
#region Constructors
|
|
||||||
public TypeMeta(Type type)
|
|
||||||
{
|
|
||||||
_type = type;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Type
|
|
||||||
public Type Type
|
|
||||||
{
|
|
||||||
get { return _type; }
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Name
|
|
||||||
private void InitName()
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.Name) == false)
|
|
||||||
{
|
|
||||||
(_name, _isCustomName) = MetaGenerator.GetMetaName(_type);
|
|
||||||
_initFlags |= InitFlag.Name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool IsCustomName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitName();
|
|
||||||
return _isCustomName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitName();
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Color
|
|
||||||
private void InitColor()
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.Color) == false)
|
|
||||||
{
|
|
||||||
(_color, _isCustomColor) = MetaGenerator.GetColor(_type);
|
|
||||||
_initFlags |= InitFlag.Color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool IsCustomColor
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitColor();
|
|
||||||
return _isCustomColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public MetaColor Color
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitColor();
|
|
||||||
return _color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Description
|
|
||||||
public MetaDescription Description
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.Description) == false)
|
|
||||||
{
|
|
||||||
_description = MetaGenerator.GetDescription(_type);
|
|
||||||
_initFlags |= InitFlag.Description;
|
|
||||||
}
|
|
||||||
return _description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Group
|
|
||||||
public MetaGroup Group
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.Group) == false)
|
|
||||||
{
|
|
||||||
_group = MetaGenerator.GetGroup(_type);
|
|
||||||
_initFlags |= InitFlag.Group;
|
|
||||||
}
|
|
||||||
return _group;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Tags
|
|
||||||
private void InitTags()
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.Tags) == false)
|
|
||||||
{
|
|
||||||
_tags = MetaGenerator.GetTags(_type);
|
|
||||||
_initFlags |= InitFlag.Tags;
|
|
||||||
_isHidden = _tags.Contains(MetaTags.HIDDEN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public IReadOnlyCollection<string> Tags
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitTags();
|
|
||||||
return _tags;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public bool IsHidden
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
InitTags();
|
|
||||||
return _isHidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region TypeCode
|
|
||||||
public int TypeCode
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_initFlags.HasFlag(InitFlag.TypeCode) == false)
|
|
||||||
{
|
|
||||||
_typeCode = EcsTypeCode.Get(_type);
|
|
||||||
_initFlags |= InitFlag.TypeCode;
|
|
||||||
}
|
|
||||||
return _typeCode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region InitializeAll
|
|
||||||
public void InitializeAll()
|
|
||||||
{
|
|
||||||
if (_initFlags == InitFlag.All)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_ = Name;
|
|
||||||
_ = Group;
|
|
||||||
_ = Color;
|
|
||||||
_ = Description;
|
|
||||||
_ = Tags;
|
|
||||||
_ = TypeCode;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region InitFlag
|
|
||||||
[Flags]
|
|
||||||
private enum InitFlag : byte
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
Name = 1 << 0,
|
|
||||||
Group = 1 << 1,
|
|
||||||
Color = 1 << 2,
|
|
||||||
Description = 1 << 3,
|
|
||||||
Tags = 1 << 4,
|
|
||||||
TypeCode = 1 << 5,
|
|
||||||
|
|
||||||
All = Name | Group | Color | Description | Tags | TypeCode
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Other
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
return Name;
|
|
||||||
}
|
|
||||||
private class DebuggerProxy : ITypeMeta
|
|
||||||
{
|
|
||||||
private readonly TypeMeta _meta;
|
|
||||||
public Type Type
|
|
||||||
{
|
|
||||||
get { return _meta.Type; }
|
|
||||||
}
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get { return _meta.Name; }
|
|
||||||
}
|
|
||||||
public MetaColor Color
|
|
||||||
{
|
|
||||||
get { return _meta.Color; }
|
|
||||||
}
|
|
||||||
public MetaDescription Description
|
|
||||||
{
|
|
||||||
get { return _meta.Description; }
|
|
||||||
}
|
|
||||||
public MetaGroup Group
|
|
||||||
{
|
|
||||||
get { return _meta.Group; }
|
|
||||||
}
|
|
||||||
public IReadOnlyCollection<string> Tags
|
|
||||||
{
|
|
||||||
get { return _meta.Tags; }
|
|
||||||
}
|
|
||||||
public DebuggerProxy(TypeMeta meta)
|
|
||||||
{
|
|
||||||
_meta = meta;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region MetaGenerator
|
|
||||||
private static class MetaGenerator
|
|
||||||
{
|
|
||||||
private const int GENERIC_NAME_DEPTH = 3;
|
|
||||||
|
|
||||||
#region GetMetaName
|
|
||||||
public static (string, bool) GetMetaName(Type type)
|
|
||||||
{
|
|
||||||
bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false;
|
|
||||||
if (isCustom)
|
|
||||||
{
|
|
||||||
if ((type.IsGenericType && atr.isHideGeneric == false) == false)
|
|
||||||
{
|
|
||||||
return (atr.name, isCustom);
|
|
||||||
}
|
|
||||||
string genericParams = "";
|
|
||||||
Type[] typeParameters = type.GetGenericArguments();
|
|
||||||
for (int i = 0; i < typeParameters.Length; ++i)
|
|
||||||
{
|
|
||||||
string paramTypeName = EcsDebugUtility.GetGenericTypeName(typeParameters[i], GENERIC_NAME_DEPTH);
|
|
||||||
genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}");
|
|
||||||
}
|
|
||||||
return ($"{atr.name}<{genericParams}>", isCustom);
|
|
||||||
}
|
|
||||||
return (EcsDebugUtility.GetGenericTypeName(type, GENERIC_NAME_DEPTH), isCustom);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetColor
|
|
||||||
private static MetaColor AutoColor(Type type)
|
|
||||||
{
|
|
||||||
return new MetaColor(type.Name).UpContrast();//.Desaturate(0.48f) / 1.18f;
|
|
||||||
}
|
|
||||||
public static (MetaColor, bool) GetColor(Type type)
|
|
||||||
{
|
|
||||||
bool isCustom = type.TryGetCustomAttribute(out MetaColorAttribute atr);
|
|
||||||
return (isCustom ? atr.color : AutoColor(type), isCustom);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetGroup
|
|
||||||
public static MetaGroup GetGroup(Type type)
|
|
||||||
{
|
|
||||||
return type.TryGetCustomAttribute(out MetaGroupAttribute atr) ? atr.Data : MetaGroup.Empty;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetDescription
|
|
||||||
public static MetaDescription GetDescription(Type type)
|
|
||||||
{
|
|
||||||
bool isCustom = type.TryGetCustomAttribute(out MetaDescriptionAttribute atr);
|
|
||||||
return isCustom ? atr.Data : MetaDescription.Empty;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region GetTags
|
|
||||||
public static IReadOnlyCollection<string> GetTags(Type type)
|
|
||||||
{
|
|
||||||
var atr = type.GetCustomAttribute<MetaTagsAttribute>();
|
|
||||||
return atr != null ? atr.Tags : Array.Empty<string>();
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class TypeMetaDataCachedExtensions
|
public static class TypeMetaDataCachedExtensions
|
||||||
{
|
{
|
||||||
public static TypeMeta GetMeta(this object self)
|
public static TypeMeta GetMeta(this object self)
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
using System;
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
@ -339,7 +340,61 @@ namespace DCFApixels.DragonECS
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public override string ToString() { return $"({r}, {g}, {b})"; }
|
public override string ToString() { return $"({r}, {g}, {b}, {a})"; }
|
||||||
|
public unsafe static MetaColor Parse(string input)
|
||||||
|
{
|
||||||
|
if (input == null) { throw new ArgumentNullException(nameof(input)); }
|
||||||
|
int length = input.Length;
|
||||||
|
fixed (char* f = input)
|
||||||
|
{
|
||||||
|
return Parse(f, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public unsafe static MetaColor Parse(char* ptr, int length)
|
||||||
|
{
|
||||||
|
if (ptr == null) { throw new ArgumentNullException(nameof(ptr)); }
|
||||||
|
byte r, g, b, a;
|
||||||
|
Trim(ref ptr, ref length);
|
||||||
|
r = ParseByte(ref ptr, ref length);
|
||||||
|
g = ParseByte(ref ptr, ref length);
|
||||||
|
b = ParseByte(ref ptr, ref length);
|
||||||
|
a = ParseByte(ref ptr, ref length, true);
|
||||||
|
return new MetaColor(r, g, b, a);
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private unsafe static void Trim(ref char* span, ref int length)
|
||||||
|
{
|
||||||
|
if (!char.IsWhiteSpace(span[0]) && !char.IsWhiteSpace(span[length - 1])) { return; }
|
||||||
|
while (char.IsWhiteSpace(span[0])) { span++; length--; }
|
||||||
|
while (char.IsWhiteSpace(span[--length])) { }
|
||||||
|
length++;
|
||||||
|
}
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private unsafe static byte ParseByte(ref char* ptr, ref int length, bool isAplha = false)
|
||||||
|
{
|
||||||
|
if (length <= 0) { return isAplha ? byte.MaxValue : byte.MinValue; }
|
||||||
|
while (char.IsDigit(*ptr) == false)
|
||||||
|
{
|
||||||
|
ptr++; length--;
|
||||||
|
if (length <= 0) { return isAplha ? byte.MaxValue : byte.MinValue; }
|
||||||
|
}
|
||||||
|
|
||||||
|
int value = 0;
|
||||||
|
while (char.IsDigit(*ptr))
|
||||||
|
{
|
||||||
|
value = value * 10 + (*ptr - '0');
|
||||||
|
ptr++; length--;
|
||||||
|
if (length <= 0) { break; }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value < 0 || value > 255)
|
||||||
|
{
|
||||||
|
throw new FormatException("Color component value should be between 0 and 255.");
|
||||||
|
}
|
||||||
|
return (byte)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public bool Equals(MetaColor other) { return colorCode == other.colorCode; }
|
public bool Equals(MetaColor other) { return colorCode == other.colorCode; }
|
||||||
public override bool Equals(object obj) { return obj is MetaColor other && Equals(other); }
|
public override bool Equals(object obj) { return obj is MetaColor other && Equals(other); }
|
||||||
public override int GetHashCode() { return colorCode; }
|
public override int GetHashCode() { return colorCode; }
|
||||||
|
326
src/Debug/TypeMeta.cs
Normal file
326
src/Debug/TypeMeta.cs
Normal file
@ -0,0 +1,326 @@
|
|||||||
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace DCFApixels.DragonECS
|
||||||
|
{
|
||||||
|
public interface ITypeMeta
|
||||||
|
{
|
||||||
|
Type Type { get; }
|
||||||
|
string Name { get; }
|
||||||
|
MetaColor Color { get; }
|
||||||
|
MetaDescription Description { get; }
|
||||||
|
MetaGroup Group { get; }
|
||||||
|
IReadOnlyCollection<string> Tags { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
|
public sealed class TypeMeta : ITypeMeta
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, TypeMeta> _metaCache = new Dictionary<Type, TypeMeta>();
|
||||||
|
|
||||||
|
internal readonly Type _type;
|
||||||
|
|
||||||
|
private bool _isCustomName;
|
||||||
|
private bool _isCustomColor;
|
||||||
|
private bool _isHidden;
|
||||||
|
|
||||||
|
private string _name;
|
||||||
|
private MetaColor _color;
|
||||||
|
private MetaDescription _description;
|
||||||
|
private MetaGroup _group;
|
||||||
|
private IReadOnlyCollection<string> _tags;
|
||||||
|
private int _typeCode;
|
||||||
|
|
||||||
|
private InitFlag _initFlags = InitFlag.None;
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
public static TypeMeta Get(Type type)
|
||||||
|
{
|
||||||
|
if (_metaCache.TryGetValue(type, out TypeMeta result) == false)
|
||||||
|
{
|
||||||
|
result = new TypeMeta(type);
|
||||||
|
_metaCache.Add(type, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
private TypeMeta(Type type)
|
||||||
|
{
|
||||||
|
_type = type;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Type
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get { return _type; }
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Name
|
||||||
|
private void InitName()
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.Name) == false)
|
||||||
|
{
|
||||||
|
(_name, _isCustomName) = MetaGenerator.GetMetaName(_type);
|
||||||
|
_initFlags |= InitFlag.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool IsCustomName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitName();
|
||||||
|
return _isCustomName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitName();
|
||||||
|
return _name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Color
|
||||||
|
private void InitColor()
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.Color) == false)
|
||||||
|
{
|
||||||
|
(_color, _isCustomColor) = MetaGenerator.GetColor(_type);
|
||||||
|
_initFlags |= InitFlag.Color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool IsCustomColor
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitColor();
|
||||||
|
return _isCustomColor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public MetaColor Color
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitColor();
|
||||||
|
return _color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Description
|
||||||
|
public MetaDescription Description
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.Description) == false)
|
||||||
|
{
|
||||||
|
_description = MetaGenerator.GetDescription(_type);
|
||||||
|
_initFlags |= InitFlag.Description;
|
||||||
|
}
|
||||||
|
return _description;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Group
|
||||||
|
public MetaGroup Group
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.Group) == false)
|
||||||
|
{
|
||||||
|
_group = MetaGenerator.GetGroup(_type);
|
||||||
|
_initFlags |= InitFlag.Group;
|
||||||
|
}
|
||||||
|
return _group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Tags
|
||||||
|
private void InitTags()
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.Tags) == false)
|
||||||
|
{
|
||||||
|
_tags = MetaGenerator.GetTags(_type);
|
||||||
|
_initFlags |= InitFlag.Tags;
|
||||||
|
_isHidden = _tags.Contains(MetaTags.HIDDEN);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IReadOnlyCollection<string> Tags
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitTags();
|
||||||
|
return _tags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool IsHidden
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
InitTags();
|
||||||
|
return _isHidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region TypeCode
|
||||||
|
public int TypeCode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_initFlags.HasFlag(InitFlag.TypeCode) == false)
|
||||||
|
{
|
||||||
|
_typeCode = EcsTypeCode.Get(_type);
|
||||||
|
_initFlags |= InitFlag.TypeCode;
|
||||||
|
}
|
||||||
|
return _typeCode;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InitializeAll
|
||||||
|
public TypeMeta InitializeAll()
|
||||||
|
{
|
||||||
|
if (_initFlags != InitFlag.All)
|
||||||
|
{
|
||||||
|
_ = Name;
|
||||||
|
_ = Group;
|
||||||
|
_ = Color;
|
||||||
|
_ = Description;
|
||||||
|
_ = Tags;
|
||||||
|
_ = TypeCode;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region InitFlag
|
||||||
|
[Flags]
|
||||||
|
private enum InitFlag : byte
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Name = 1 << 0,
|
||||||
|
Group = 1 << 1,
|
||||||
|
Color = 1 << 2,
|
||||||
|
Description = 1 << 3,
|
||||||
|
Tags = 1 << 4,
|
||||||
|
TypeCode = 1 << 5,
|
||||||
|
|
||||||
|
All = Name | Group | Color | Description | Tags | TypeCode
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Other
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
private class DebuggerProxy : ITypeMeta
|
||||||
|
{
|
||||||
|
private readonly TypeMeta _meta;
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get { return _meta.Type; }
|
||||||
|
}
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return _meta.Name; }
|
||||||
|
}
|
||||||
|
public MetaColor Color
|
||||||
|
{
|
||||||
|
get { return _meta.Color; }
|
||||||
|
}
|
||||||
|
public MetaDescription Description
|
||||||
|
{
|
||||||
|
get { return _meta.Description; }
|
||||||
|
}
|
||||||
|
public MetaGroup Group
|
||||||
|
{
|
||||||
|
get { return _meta.Group; }
|
||||||
|
}
|
||||||
|
public IReadOnlyCollection<string> Tags
|
||||||
|
{
|
||||||
|
get { return _meta.Tags; }
|
||||||
|
}
|
||||||
|
public DebuggerProxy(TypeMeta meta)
|
||||||
|
{
|
||||||
|
_meta = meta;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region MetaGenerator
|
||||||
|
private static class MetaGenerator
|
||||||
|
{
|
||||||
|
private const int GENERIC_NAME_DEPTH = 3;
|
||||||
|
|
||||||
|
#region GetMetaName
|
||||||
|
public static (string, bool) GetMetaName(Type type)
|
||||||
|
{
|
||||||
|
bool isCustom = type.TryGetCustomAttribute(out MetaNameAttribute atr) && string.IsNullOrEmpty(atr.name) == false;
|
||||||
|
if (isCustom)
|
||||||
|
{
|
||||||
|
if ((type.IsGenericType && atr.isHideGeneric == false) == false)
|
||||||
|
{
|
||||||
|
return (atr.name, isCustom);
|
||||||
|
}
|
||||||
|
string genericParams = "";
|
||||||
|
Type[] typeParameters = type.GetGenericArguments();
|
||||||
|
for (int i = 0; i < typeParameters.Length; ++i)
|
||||||
|
{
|
||||||
|
string paramTypeName = EcsDebugUtility.GetGenericTypeName(typeParameters[i], GENERIC_NAME_DEPTH);
|
||||||
|
genericParams += (i == 0 ? paramTypeName : $", {paramTypeName}");
|
||||||
|
}
|
||||||
|
return ($"{atr.name}<{genericParams}>", isCustom);
|
||||||
|
}
|
||||||
|
return (EcsDebugUtility.GetGenericTypeName(type, GENERIC_NAME_DEPTH), isCustom);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetColor
|
||||||
|
private static MetaColor AutoColor(Type type)
|
||||||
|
{
|
||||||
|
return new MetaColor(type.Name).UpContrast();//.Desaturate(0.48f) / 1.18f;
|
||||||
|
}
|
||||||
|
public static (MetaColor, bool) GetColor(Type type)
|
||||||
|
{
|
||||||
|
bool isCustom = type.TryGetCustomAttribute(out MetaColorAttribute atr);
|
||||||
|
return (isCustom ? atr.color : AutoColor(type), isCustom);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetGroup
|
||||||
|
public static MetaGroup GetGroup(Type type)
|
||||||
|
{
|
||||||
|
return type.TryGetCustomAttribute(out MetaGroupAttribute atr) ? atr.Data : MetaGroup.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetDescription
|
||||||
|
public static MetaDescription GetDescription(Type type)
|
||||||
|
{
|
||||||
|
bool isCustom = type.TryGetCustomAttribute(out MetaDescriptionAttribute atr);
|
||||||
|
return isCustom ? atr.Data : MetaDescription.Empty;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region GetTags
|
||||||
|
public static IReadOnlyCollection<string> GetTags(Type type)
|
||||||
|
{
|
||||||
|
var atr = type.GetCustomAttribute<MetaTagsAttribute>();
|
||||||
|
return atr != null ? atr.Tags : Array.Empty<string>();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
using DCFApixels.DragonECS.Internal;
|
using DCFApixels.DragonECS.Internal;
|
||||||
|
using DCFApixels.DragonECS.PoolsCore;
|
||||||
using DCFApixels.DragonECS.RunnersCore;
|
using DCFApixels.DragonECS.RunnersCore;
|
||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -6,7 +7,7 @@ using static DCFApixels.DragonECS.EcsDebugUtility;
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
public interface IEcsProcess { }
|
public interface IEcsProcess : IEcsMember { }
|
||||||
|
|
||||||
namespace RunnersCore
|
namespace RunnersCore
|
||||||
{
|
{
|
||||||
|
@ -36,7 +36,7 @@ namespace DCFApixels.DragonECS
|
|||||||
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||||
#endif
|
#endif
|
||||||
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
[DebuggerTypeProxy(typeof(DebuggerProxy))]
|
||||||
public partial class EcsWorld : IEntityStorage
|
public partial class EcsWorld : IEntityStorage, IEcsMember
|
||||||
{
|
{
|
||||||
public readonly short id;
|
public readonly short id;
|
||||||
private IConfigContainer _configs;
|
private IConfigContainer _configs;
|
||||||
|
@ -11,7 +11,7 @@ using Unity.IL2CPP.CompilerServices;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
/// <summary>Standard component</summary>
|
/// <summary>Standard component</summary>
|
||||||
public interface IEcsComponent : IEcsComponentType { }
|
public interface IEcsComponent : IEcsMember { }
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
#if ENABLE_IL2CPP
|
||||||
[Il2CppSetOption (Option.NullChecks, false)]
|
[Il2CppSetOption (Option.NullChecks, false)]
|
||||||
|
@ -6,7 +6,7 @@ using System.Runtime.CompilerServices;
|
|||||||
|
|
||||||
namespace DCFApixels.DragonECS.PoolsCore
|
namespace DCFApixels.DragonECS.PoolsCore
|
||||||
{
|
{
|
||||||
public interface IEcsComponentType { }
|
public interface IEcsMember { }
|
||||||
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
|
/// <summary>Only used to implement a custom pool. In other contexts use IEcsPool or IEcsPool<T>.</summary>
|
||||||
public interface IEcsPoolImplementation : IEcsPool
|
public interface IEcsPoolImplementation : IEcsPool
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ using Unity.IL2CPP.CompilerServices;
|
|||||||
namespace DCFApixels.DragonECS
|
namespace DCFApixels.DragonECS
|
||||||
{
|
{
|
||||||
/// <summary>Component without data</summary>
|
/// <summary>Component without data</summary>
|
||||||
public interface IEcsTagComponent : IEcsComponentType { }
|
public interface IEcsTagComponent : IEcsMember { }
|
||||||
|
|
||||||
#if ENABLE_IL2CPP
|
#if ENABLE_IL2CPP
|
||||||
[Il2CppSetOption (Option.NullChecks, false)]
|
[Il2CppSetOption (Option.NullChecks, false)]
|
||||||
|
Loading…
Reference in New Issue
Block a user