From 1b1227fb7c5ff190632f3595f439266ee3688237 Mon Sep 17 00:00:00 2001 From: yhh <359807859@qq.com> Date: Thu, 23 Aug 2018 14:25:28 +0800 Subject: [PATCH] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=BF=AB=E6=8D=B7=E5=AE=B9?= =?UTF-8?q?=E5=99=A8=20=E4=BC=98=E5=8C=96=E6=97=A5=E5=BF=97=E5=BC=95?= =?UTF-8?q?=E6=93=8E=20=E7=BC=96=E8=BE=91=E5=99=A8=E9=A2=84=E7=95=99?= =?UTF-8?q?=E8=B7=A8=E5=B9=B3=E5=8F=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../CLEditor.AssetEngine.csproj | 46 ++ .../Properties/AssemblyInfo.cs | 36 ++ CLEditor.Core/AccessorMetadata.cs | 21 + CLEditor.Core/CLEditor.Core.csproj | 27 +- CLEditor.Core/ComponentBase.cs | 57 +++ CLEditor.Core/DataMemberIgnoreAttribute.cs | 13 + CLEditor.Core/DefaultValueMetadata.cs | 26 ++ .../Diagnostics/ConsoleLogListener.cs | 162 +++++++ CLEditor.Core/Diagnostics/ConsoleLogMode.cs | 22 + CLEditor.Core/Diagnostics/GlobalLogger.cs | 83 ++++ CLEditor.Core/Diagnostics/LogListener.cs | 87 ++++ CLEditor.Core/Diagnostics/Logger.Extension.cs | 133 ++++++ CLEditor.Core/Diagnostics/Logger.cs | 23 +- CLEditor.Core/DisposeBase.cs | 66 +++ CLEditor.Core/ICollectorHolder.cs | 13 + CLEditor.Core/IComponent.cs | 13 + CLEditor.Core/IReferencable.cs | 24 + CLEditor.Core/ObjectCollector.cs | 57 +++ CLEditor.Core/ObjectInvalidationMetadata.cs | 7 + CLEditor.Core/Platform.cs | 70 +++ CLEditor.Core/PlatformType.cs | 47 ++ CLEditor.Core/PropertyContainer.cs | 432 ++++++++++++++++++ CLEditor.Core/PropertyKey.cs | 77 ++++ CLEditor.Core/PropertyKeyMetadata.cs | 7 + .../ReferenceCountingExtensions.cs | 20 + .../Serialization/DataSerializerAttribute.cs | 25 + .../DataSerializerGenericMode.cs | 19 + CLEditor.Core/Utilities.cs | 20 + CLEditor.Core/ValidateValueMetadata.cs | 7 + CLEditor.sln | 31 ++ CLEngine/CGame.cs | 28 ++ CLEngine/CLEngine.csproj | 59 +++ CLEngine/Properties/AssemblyInfo.cs | 36 ++ CLEngine/packages.config | 4 + README.md | 34 ++ 35 files changed, 1830 insertions(+), 2 deletions(-) create mode 100644 CLEditor.AssetEngine/CLEditor.AssetEngine.csproj create mode 100644 CLEditor.AssetEngine/Properties/AssemblyInfo.cs create mode 100644 CLEditor.Core/AccessorMetadata.cs create mode 100644 CLEditor.Core/ComponentBase.cs create mode 100644 CLEditor.Core/DataMemberIgnoreAttribute.cs create mode 100644 CLEditor.Core/DefaultValueMetadata.cs create mode 100644 CLEditor.Core/Diagnostics/ConsoleLogListener.cs create mode 100644 CLEditor.Core/Diagnostics/ConsoleLogMode.cs create mode 100644 CLEditor.Core/Diagnostics/GlobalLogger.cs create mode 100644 CLEditor.Core/Diagnostics/LogListener.cs create mode 100644 CLEditor.Core/Diagnostics/Logger.Extension.cs create mode 100644 CLEditor.Core/DisposeBase.cs create mode 100644 CLEditor.Core/ICollectorHolder.cs create mode 100644 CLEditor.Core/IComponent.cs create mode 100644 CLEditor.Core/IReferencable.cs create mode 100644 CLEditor.Core/ObjectCollector.cs create mode 100644 CLEditor.Core/ObjectInvalidationMetadata.cs create mode 100644 CLEditor.Core/Platform.cs create mode 100644 CLEditor.Core/PlatformType.cs create mode 100644 CLEditor.Core/PropertyContainer.cs create mode 100644 CLEditor.Core/PropertyKey.cs create mode 100644 CLEditor.Core/PropertyKeyMetadata.cs create mode 100644 CLEditor.Core/ReferenceCounting/ReferenceCountingExtensions.cs create mode 100644 CLEditor.Core/Serialization/DataSerializerAttribute.cs create mode 100644 CLEditor.Core/Serialization/DataSerializerGenericMode.cs create mode 100644 CLEditor.Core/Utilities.cs create mode 100644 CLEditor.Core/ValidateValueMetadata.cs create mode 100644 CLEngine/CGame.cs create mode 100644 CLEngine/CLEngine.csproj create mode 100644 CLEngine/Properties/AssemblyInfo.cs create mode 100644 CLEngine/packages.config diff --git a/CLEditor.AssetEngine/CLEditor.AssetEngine.csproj b/CLEditor.AssetEngine/CLEditor.AssetEngine.csproj new file mode 100644 index 0000000..3828d66 --- /dev/null +++ b/CLEditor.AssetEngine/CLEditor.AssetEngine.csproj @@ -0,0 +1,46 @@ + + + + + Debug + AnyCPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5} + Library + Properties + CLEditor.AssetEngine + CLEditor.AssetEngine + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/CLEditor.AssetEngine/Properties/AssemblyInfo.cs b/CLEditor.AssetEngine/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..07cc832 --- /dev/null +++ b/CLEditor.AssetEngine/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("CLEditor.AssetEngine")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CLEditor.AssetEngine")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("fe171bf2-9210-4a24-bce4-bdb95e6202f5")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CLEditor.Core/AccessorMetadata.cs b/CLEditor.Core/AccessorMetadata.cs new file mode 100644 index 0000000..3c228ba --- /dev/null +++ b/CLEditor.Core/AccessorMetadata.cs @@ -0,0 +1,21 @@ +namespace CLEditor.Core +{ + public class AccessorMetadata : PropertyKeyMetadata + { + public delegate object GetterDelegate(ref PropertyContainer propertyContainer); + public delegate void SetterDelegate(ref PropertyContainer propertyContainer, object value); + + private GetterDelegate getter; + private SetterDelegate setter; + + public object GetValue(ref PropertyContainer obj) + { + return getter(ref obj); + } + + public void SetValue(ref PropertyContainer obj, object value) + { + setter(ref obj, value); + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/CLEditor.Core.csproj b/CLEditor.Core/CLEditor.Core.csproj index 409252a..e8f02ab 100644 --- a/CLEditor.Core/CLEditor.Core.csproj +++ b/CLEditor.Core/CLEditor.Core.csproj @@ -18,7 +18,7 @@ full false bin\Debug\ - DEBUG;TRACE + TRACE;DEBUG;C_PLATFORM_WINDOWS_DESKTOP prompt 4 true @@ -61,27 +61,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CLEditor.Core/ComponentBase.cs b/CLEditor.Core/ComponentBase.cs new file mode 100644 index 0000000..393a4fd --- /dev/null +++ b/CLEditor.Core/ComponentBase.cs @@ -0,0 +1,57 @@ +namespace CLEditor.Core +{ + /// + /// 框架组件的基类 + /// + [DataContract] + public abstract class ComponentBase : DisposeBase, IComponent, ICollectorHolder + { + private string name; + private ObjectCollector collector; + + /// + /// 获取或设置此组件的名称 + /// + public virtual string Name + { + get { return name; } + set + { + if (value == name) + { + return; + } + + name = value; + + OnNameChanged(); + } + } + + /// + /// 获取此组件的附加属性 + /// + [DataMemberIgnore] + public PropertyContainer Tags; + + public ComponentBase(string name) + { + collector = new ObjectCollector(); + Tags = new PropertyContainer(this); + Name = name ?? GetType().Name; + } + + public ObjectCollector Collector + { + get + { + collector.EnsureValid(); + return collector; + } + } + + protected virtual void OnNameChanged() + { + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/DataMemberIgnoreAttribute.cs b/CLEditor.Core/DataMemberIgnoreAttribute.cs new file mode 100644 index 0000000..89f5841 --- /dev/null +++ b/CLEditor.Core/DataMemberIgnoreAttribute.cs @@ -0,0 +1,13 @@ +using System; + +namespace CLEditor.Core +{ + /// + /// 在属性或字段上指定时,在序列化/反序列化时不会使用它 + /// + [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, Inherited = false)] + public class DataMemberIgnoreAttribute : Attribute + { + + } +} \ No newline at end of file diff --git a/CLEditor.Core/DefaultValueMetadata.cs b/CLEditor.Core/DefaultValueMetadata.cs new file mode 100644 index 0000000..a9cac5d --- /dev/null +++ b/CLEditor.Core/DefaultValueMetadata.cs @@ -0,0 +1,26 @@ +namespace CLEditor.Core +{ + /// + /// 可以重载的抽象类 + /// + public abstract class DefaultValueMetadata : PropertyKeyMetadata + { + /// + /// 获取外部属性的默认值,并指定是否应保留此默认值 + /// + /// + /// + public abstract object GetDefaultValue(ref PropertyContainer obj); + /// + /// 获取或设置属性更新回调 + /// + public PropertyContainer.PropertyUpdatedDelegate PropertyUpdateCallback { get; set; } + /// + /// 获取一个值,该值指示是否保留此值 + /// + public virtual bool KeepValue + { + get { return false; } + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/ConsoleLogListener.cs b/CLEditor.Core/Diagnostics/ConsoleLogListener.cs new file mode 100644 index 0000000..fa60e4c --- /dev/null +++ b/CLEditor.Core/Diagnostics/ConsoleLogListener.cs @@ -0,0 +1,162 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Runtime.InteropServices; +using CLEditor.Core.Annotations; +using Microsoft.Win32.SafeHandles; + +namespace CLEditor.Core.Diagnostics +{ + /// + /// 实现将其输出重定向到默认的OS控制台 + /// + public class ConsoleLogListener : LogListener + { +#if C_PLATFORM_WINDOWS_DESKTOP + private bool isConsoleActive; +#endif + public static void ShowConsole() + { + var handle = GetConsoleWindow(); + var outputRedirected = IsHandleRedirected((IntPtr)StdOutConsoleHandle); + + if (outputRedirected) + { + var originalStream = Console.OpenStandardOutput(); + + FreeConsole(); + AllocConsole(); + + var outputStream = Console.OpenStandardOutput(); + if (originalStream != null) + { + outputStream = new DualStream(originalStream, outputStream); + } + + TextWriter writer = new StreamWriter(outputStream) { AutoFlush = true }; + Console.SetOut(writer); + } + else if (handle != IntPtr.Zero) + { + const int SW_SHOW = 5; + ShowWindow(handle, SW_SHOW); + } + } + + private static bool IsHandleRedirected(IntPtr ioHandle) + { + if ((GetFileType(new SafeFileHandle(ioHandle, false)) & 2) != 2) + { + return true; + } + + return false; + } + + /// + /// 获取或设置此侦听器处理的最小日志级别 + /// + public LogMessageType LogLevel { get; set; } + /// + /// 获取或设置日志模式 + /// + public ConsoleLogMode LogMode { get; set; } + + protected override void OnLog([NotNull] ILogMessage logMessage) + { + if (!Debugger.IsAttached && (logMessage.Type < LogLevel || LogMode == ConsoleLogMode.None + || !(LogMode == ConsoleLogMode.Auto && + Platform.IsRunningDebugAssembly) && + LogMode != ConsoleLogMode.Always)) + { + return; + } + } + +#if C_PLATFORM_WINDOWS_DESKTOP + private const int StdOutConsoleHandle = -11; + + public static void HideConsole() + { + var handle = GetConsoleWindow(); + const int SW_HIDE = 0; + ShowWindow(handle, SW_HIDE); + } + + private class DualStream : Stream + { + private readonly Stream stream1; + private readonly Stream stream2; + + public DualStream(Stream stream1, Stream stream2) + { + this.stream1 = stream1; + this.stream2 = stream2; + } + + public override void Flush() + { + stream1.Flush(); + stream2.Flush(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + stream1.Write(buffer, offset, count); + stream2.Write(buffer, offset, count); + } + + public override bool CanRead => false; + public override bool CanSeek => false; + public override bool CanWrite => false; + public override long Length { get; } + public override long Position { get; set; } + } + + [DllImport("kernel32.dll")] + private static extern IntPtr GetConsoleWindow(); + [DllImport("kernel32.dll")] + private static extern int GetFileType(SafeFileHandle handle); + [DllImport("user32.dll")] + private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool FreeConsole(); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool AllocConsole(); + [DllImport("kernel32", SetLastError = true)] + private static extern bool AttachConsole(int dwProcessId); + + private void EnsureConsole() + { + if (isConsoleActive || !Platform.IsWindowsDesktop) + { + return; + } + + var attackedToConsole = AttachConsole(-1); + if (!attackedToConsole) + { + ShowConsole(); + } + + isConsoleActive = true; + } +#endif + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/ConsoleLogMode.cs b/CLEditor.Core/Diagnostics/ConsoleLogMode.cs new file mode 100644 index 0000000..b06d113 --- /dev/null +++ b/CLEditor.Core/Diagnostics/ConsoleLogMode.cs @@ -0,0 +1,22 @@ +namespace CLEditor.Core.Diagnostics +{ + /// + /// 定义控制台的打开方式 + /// + public enum ConsoleLogMode + { + /// + /// 控制台应仅在调试中可见,如果有消息,则不可见 + /// + Auto, + Default = Auto, + /// + /// 控制台不可见 + /// + None, + /// + /// 控制台始终可见 + /// + Always, + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/GlobalLogger.cs b/CLEditor.Core/Diagnostics/GlobalLogger.cs new file mode 100644 index 0000000..c303f42 --- /dev/null +++ b/CLEditor.Core/Diagnostics/GlobalLogger.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections.Generic; +using CLEditor.Core.Annotations; + +namespace CLEditor.Core.Diagnostics +{ + /// + /// 一种记录器,它将消息重定向到全局处理程序并处理实例化的MapModuleNameToLogger + /// + public sealed class GlobalLogger : Logger + { + /// + /// 默认情况下,GlobalLogger的最低级别为info + /// + public const LogMessageType MinimumLevel = LogMessageType.Info; + /// + /// 映射所有实例化的记录器 + /// 将模块名称映射到记录器 + /// + private static readonly Dictionary MapModuleNameToLogger = new Dictionary(); + + public delegate void MessageFilterDelegate(ref ILogMessage logMessage); + /// + /// 记录消息时发生 + /// + public static event Action GlobalMessageLogged; + /// + /// 在记录消息之前发生 + /// + public static event MessageFilterDelegate GlobalMessageFilter; + + private GlobalLogger(string module) + { + Module = module; + } + + public static Logger GetLogger([NotNull] string module) + { + if (module == null) + throw new ArgumentNullException(nameof(module)); + + Logger logger; + lock (MapModuleNameToLogger) + { + if (!MapModuleNameToLogger.TryGetValue(module, out logger)) + { + logger = new GlobalLogger(module); + logger.ActivateLog(MinimumLevel); + MapModuleNameToLogger.Add(module, logger); + } + } + return logger; + } + + /// + /// 使用指定的操作激活所有记录器的日志 + /// + /// + public static void ActivateLog([NotNull] Action activator) + { + if (activator == null) + throw new ArgumentNullException(nameof(activator)); + + foreach (var logger in MapModuleNameToLogger.Values) + activator(logger); + } + + protected override void LogRaw(ILogMessage logMessage) + { + var filterHandler = GlobalMessageFilter; + if (filterHandler != null) + { + filterHandler(ref logMessage); + if (logMessage == null) + { + return; + } + } + + GlobalMessageLogged?.Invoke(logMessage); + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/LogListener.cs b/CLEditor.Core/Diagnostics/LogListener.cs new file mode 100644 index 0000000..544c232 --- /dev/null +++ b/CLEditor.Core/Diagnostics/LogListener.cs @@ -0,0 +1,87 @@ +using System; +using CLEditor.Core.Annotations; + +namespace CLEditor.Core.Diagnostics +{ + /// + /// 实现日志侦听器的基类 + /// + public abstract class LogListener : IDisposable + { + /// + /// 获取日志消息计数 + /// + public int LogMessageCount { get; private set; } + + protected LogListener() + { + LogCountFlushLimit = 1; + TextFormatter = msg => msg.ToString(); + } + + public Func TextFormatter { get; set; } + + /// + /// 获取或设置日志计数刷新限制。 每条消息都有默认值 + /// + public int LogCountFlushLimit + { + get { return LogCountFlushLimit; } + set + { + if (value <= 0) + { + throw new ArgumentException("值必须大于0"); + } + + LogCountFlushLimit = value; + } + } + + /// + /// 执行与释放,释放或重置非托管资源相关的应用程序定义的任务 + /// + public virtual void Dispose() + { + } + + /// + /// 发生日志时调用 + /// + /// + protected abstract void OnLog(ILogMessage logMessage); + + [NotNull] + public static implicit operator Action([NotNull] LogListener logListener) + { + return logListener.OnLogInternal; + } + + /// + /// 刷新日志,方法在子类中实现 + /// + protected virtual void Flush() + { + } + + /// + /// 返回一个布尔值,指示是否应刷新日志 + /// + /// + /// + protected virtual bool ShouldFlush([NotNull] ILogMessage logMessage) + { + return (logMessage.Type > LogMessageType.Info) || (LogMessageCount % LogCountFlushLimit) == 0; + } + + private void OnLogInternal([NotNull] ILogMessage logMessage) + { + OnLog(logMessage); + LogMessageCount++; + if (ShouldFlush(logMessage)) + { + Flush(); + } + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/Logger.Extension.cs b/CLEditor.Core/Diagnostics/Logger.Extension.cs new file mode 100644 index 0000000..a5c0af9 --- /dev/null +++ b/CLEditor.Core/Diagnostics/Logger.Extension.cs @@ -0,0 +1,133 @@ +using System; + +namespace CLEditor.Core.Diagnostics +{ + public abstract partial class Logger + { + /// + /// 使用异常记录指定的详细消息 + /// + /// 详细消息 + /// 使用消息记录的异常 + /// 有关Caller的信息。 默认值为null,否则使用 + public void Verbose(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Verbose, message, exception, callerInfo)); + } + + /// + /// 记录指定的详细消息 + /// + /// 详细消息 + /// 有关Caller的信息。 默认值为null,否则使用 + public void Verbose(string message, CallerInfo callerInfo = null) + { + Verbose(message, null, callerInfo); + } + + /// + /// 记录指定的调试消息并发生异常 + /// + /// + /// + /// + public void Debug(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Debug, message, exception, callerInfo)); + } + + /// + /// 记录指定的调试消息 + /// + /// + /// + public void Debug(string message, CallerInfo callerInfo = null) + { + Debug(message, null, callerInfo); + } + + /// + /// 记录指定的信息消息,但有异常 + /// + /// + /// + /// + public void Info(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Info, message, exception, callerInfo)); + } + + /// + /// 记录指定的信息消息 + /// + /// + /// + public void Info(string message, CallerInfo callerInfo = null) + { + Info(message, null, callerInfo); + } + + /// + /// 记录指定的警告消息并发生异常 + /// + /// + /// + /// + public void Warning(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Warning, message, exception, callerInfo)); + } + + /// + /// 记录指定的警告消息 + /// + /// + /// + public void Warning(string message, CallerInfo callerInfo = null) + { + Warning(message, null, callerInfo); + } + + /// + /// 记录指定的错误消息,但有异常 + /// + /// + /// + /// + public void Error(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Error, message, exception, callerInfo)); + } + + /// + /// 记录指定的错误消息 + /// + /// + /// + public void Error(string message, CallerInfo callerInfo = null) + { + Error(message, null, callerInfo); + } + + /// + /// 使用例外记录指定的致命消息 + /// + /// + /// + /// + public void Fatal(string message, Exception exception, CallerInfo callerInfo = null) + { + Log(new LogMessage(Module, LogMessageType.Fatal, message, exception, callerInfo)); + } + + /// + /// 记录指定的致命消息 + /// + /// + /// + public void Fatal(string message, CallerInfo callerInfo = null) + { + Fatal(message, null, callerInfo); + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/Diagnostics/Logger.cs b/CLEditor.Core/Diagnostics/Logger.cs index ec9a075..075dacf 100644 --- a/CLEditor.Core/Diagnostics/Logger.cs +++ b/CLEditor.Core/Diagnostics/Logger.cs @@ -3,7 +3,7 @@ using CLEditor.Core.Annotations; namespace CLEditor.Core.Diagnostics { - public abstract class Logger : ILogger + public abstract partial class Logger : ILogger { /// /// 获取模块名称。 只读 @@ -43,6 +43,27 @@ namespace CLEditor.Core.Diagnostics } } + /// + /// 激活此记录器的日志 + /// 在指定范围之外,将禁用日志消息类型 + /// + /// 要记录的最低包含级别 + /// 要记录的最高包含级别 + /// 如果设置为 true ,则启用日志,否则为false。 默认为true + public void ActivateLog(LogMessageType fromLevel, LogMessageType toLevel = LogMessageType.Fatal, bool enabledFlag = true) + { + // 从低到高 + if (fromLevel > toLevel) + { + var temp = fromLevel; + fromLevel = toLevel; + toLevel = temp; + } + + for (var i = 0; i < EnableTypes.Length; i++) + EnableTypes[i] = (i >= (int)fromLevel && i <= (int)toLevel) ? enabledFlag : !enabledFlag; + } + /// /// 用于记录消息的内部方法。 所有信息,调试,错误......等。 /// 方法正在调用此方法 diff --git a/CLEditor.Core/DisposeBase.cs b/CLEditor.Core/DisposeBase.cs new file mode 100644 index 0000000..699cd46 --- /dev/null +++ b/CLEditor.Core/DisposeBase.cs @@ -0,0 +1,66 @@ +using System; +using System.Threading; +using CLEditor.Core.ReferenceCounting; + +namespace CLEditor.Core +{ + public abstract class DisposeBase : IDisposable, IReferencable + { + private int counter = 1; + /// + /// 组件是否已经处理好 + /// + public bool IsDisposed { get; private set; } + + public void Dispose() + { + if (!IsDisposed) + { + this.ReleaseInternal(); + } + } + + public int ReferenceCount => counter; + + public int AddReference() + { + OnAddReference(); + + var newCounter = Interlocked.Increment(ref counter); + if (newCounter <= 1) throw new InvalidOperationException("无法为已发布的对象添加引用。 AddReference / Release对必须匹配"); + return newCounter; + } + + protected virtual void OnAddReference() + { + } + + public int Release() + { + OnReleaseReference(); + + var newCounter = Interlocked.Decrement(ref counter); + if (newCounter == 0) + { + Destroy(); + IsDisposed = true; + } + else if (newCounter < 0) + { + throw new InvalidOperationException("无法释放没有活动引用的对象。 AddReference / Release对必须匹配"); + } + return newCounter; + } + + protected virtual void OnReleaseReference() + { + } + + /// + /// 处理对象资源 + /// + protected virtual void Destroy() + { + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/ICollectorHolder.cs b/CLEditor.Core/ICollectorHolder.cs new file mode 100644 index 0000000..31e8992 --- /dev/null +++ b/CLEditor.Core/ICollectorHolder.cs @@ -0,0 +1,13 @@ +namespace CLEditor.Core +{ + /// + /// 接口ICollectorHolder用于可以收集其他实例的实例 + /// + public interface ICollectorHolder + { + /// + /// 获取收集器 + /// + ObjectCollector Collector { get; } + } +} \ No newline at end of file diff --git a/CLEditor.Core/IComponent.cs b/CLEditor.Core/IComponent.cs new file mode 100644 index 0000000..8d81a14 --- /dev/null +++ b/CLEditor.Core/IComponent.cs @@ -0,0 +1,13 @@ +namespace CLEditor.Core +{ + /// + /// 所有组件的基本接口 + /// + public interface IComponent : IReferencable + { + /// + /// 获取此组件的名称 + /// + string Name { get; } + } +} \ No newline at end of file diff --git a/CLEditor.Core/IReferencable.cs b/CLEditor.Core/IReferencable.cs new file mode 100644 index 0000000..f608427 --- /dev/null +++ b/CLEditor.Core/IReferencable.cs @@ -0,0 +1,24 @@ +namespace CLEditor.Core +{ + /// + /// 所有可引用对象的基本接口 + /// + public interface IReferencable + { + /// + /// 获取此实例的引用计数 + /// + int ReferenceCount { get; } + /// + /// 增加此实例的引用计数 + /// + /// + int AddReference(); + /// + /// 减少此实例的引用计数 + /// 当引用计数变为0时,组件应释放/配置依赖项对象 + /// + /// + int Release(); + } +} \ No newline at end of file diff --git a/CLEditor.Core/ObjectCollector.cs b/CLEditor.Core/ObjectCollector.cs new file mode 100644 index 0000000..6a438e0 --- /dev/null +++ b/CLEditor.Core/ObjectCollector.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; + +namespace CLEditor.Core +{ + public struct ObjectCollector : IDisposable + { + private List disposables; + + public void Dispose() + { + if (disposables == null) + { + return; + } + + for (var i = disposables.Count - 1; i >= 0; i--) + { + var objectToDispose = disposables[i]; + DisposeObject(objectToDispose); + disposables.RemoveAt(i); + } + disposables.Clear(); + } + + private static void DisposeObject(object objectToDispose) + { + if (objectToDispose == null) + return; + + var referenceableObject = objectToDispose as IReferencable; + if (referenceableObject != null) + { + referenceableObject.Release(); + return; + } + + var disposableObject = objectToDispose as IDisposable; + if (disposableObject != null) + { + disposableObject.Dispose(); + } + else + { + var localData = objectToDispose; + var dataPointer = (IntPtr)localData; + Utilities.FreeMemory(dataPointer); + } + } + + public void EnsureValid() + { + if (disposables == null) + disposables = new List(); + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/ObjectInvalidationMetadata.cs b/CLEditor.Core/ObjectInvalidationMetadata.cs new file mode 100644 index 0000000..019f601 --- /dev/null +++ b/CLEditor.Core/ObjectInvalidationMetadata.cs @@ -0,0 +1,7 @@ +namespace CLEditor.Core +{ + public abstract class ObjectInvalidationMetadata : PropertyKeyMetadata + { + public abstract void Invalidate(object propertyOwner, PropertyKey propertyKey, object propertyOldValue); + } +} \ No newline at end of file diff --git a/CLEditor.Core/Platform.cs b/CLEditor.Core/Platform.cs new file mode 100644 index 0000000..d34fdb3 --- /dev/null +++ b/CLEditor.Core/Platform.cs @@ -0,0 +1,70 @@ +using System.Diagnostics; +using System.Linq; +using System.Reflection; + +namespace CLEditor.Core +{ + /// + /// 特定于平台的查询和功能 + /// + public static class Platform + { +#if C_PLATFORM_WINDOWS_DESKTOP + public static readonly PlatformType Type = PlatformType.Windows; +#endif + + /// + /// 获取一个值,指示正在运行的程序集是否为调试程序集 + /// + public static readonly bool IsRunningDebugAssembly = GetIsRunningDebugAssembly(); + + /// + /// 获取一个值,该值指示正在运行的平台是否为Windows桌面 + /// + public static readonly bool IsWindowsDesktop = Type == PlatformType.Windows; + + /// + /// 检查运行的程序集是否已启用DebuggableAttribute并启用了DisableOptimizations模式 + /// 此函数仅调用一次 + /// + /// + private static bool GetIsRunningDebugAssembly() + { +#if C_PLATFORM_UWP + return false; +#endif + var entryAssembly = Assembly.GetEntryAssembly(); + if (entryAssembly != null) + { + var debuggableAttribute = entryAssembly.GetCustomAttributes().FirstOrDefault(); + if (debuggableAttribute != null) + { +#if !C_RUNTIME_CORECLR + return (debuggableAttribute.DebuggingFlags & + DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0; +#else + // 使用反射的解决方法,因为CoreCLR不在DebuggableAttribute上提供 DebuggingFlags + // 当使用CoreCLR中的mscorlib时,字段m_debuggingModes(如果存在)存储此值,所以我们需要尝试找到它并获取其值 + try + { + foreach (var f in debuggableAttribute.GetType().GetTypeInfo().DeclaredFields) + { + if (f.Name.Equals("m_debuggingModes")) + { + return ((DebuggableAttribute.DebuggingModes)f.GetValue(debuggableAttribute) & DebuggableAttribute.DebuggingModes.DisableOptimizations) != 0; + } + } + } + catch (Exception) + { + } + + return false; +#endif + } + } + + return false; + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/PlatformType.cs b/CLEditor.Core/PlatformType.cs new file mode 100644 index 0000000..0dc36b8 --- /dev/null +++ b/CLEditor.Core/PlatformType.cs @@ -0,0 +1,47 @@ +using System; + +namespace CLEditor.Core +{ + /// + /// 描述平台操作系统 + /// +#if C_ASSEMBLY_PROCESSOR + internal enum PlatformType +#else + [DataContract("PlatformType")] + public enum PlatformType +#endif + { + /// + /// 这是跨平台共享的 + /// + Shared, + /// + /// Windows桌面操作系统 + /// + Windows, + /// + /// Android操作系统 + /// + Android, + /// + /// IOS操作系统 + /// + iOS, + /// + /// 通用Windows平台(UWP) + /// + UWP, + /// + /// Linux操作系统 + /// + Linux, + /// + /// macOS + /// + macOS, + + [Obsolete("Please use UWP instead")] + Windows10 = UWP, + } +} \ No newline at end of file diff --git a/CLEditor.Core/PropertyContainer.cs b/CLEditor.Core/PropertyContainer.cs new file mode 100644 index 0000000..3c4bc1c --- /dev/null +++ b/CLEditor.Core/PropertyContainer.cs @@ -0,0 +1,432 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using CLEditor.Core.Annotations; +using CLEditor.Core.Serialization; + +namespace CLEditor.Core +{ + /// + /// 表示可以保存属性的容器,轻量级嵌入(延迟初始化) + /// 标签属性系统的目的是允许绑定非逻辑上属于一般类的属性 + /// + [DataContract] + public struct PropertyContainer : IDictionary, IReadOnlyDictionary + { + private int _count; + private ICollection _keys; + private ICollection _values; + private int _count1; + private IEnumerable _keys1; + private IEnumerable _values1; + + private Dictionary properties; + + public PropertyContainer(object owner) + { + properties = null; + PropertyUpdated = null; + Owner = owner; + } + + /// + /// 获取此实例中的键 - 属性值对 + /// + /// + public IEnumerator> GetEnumerator() + { + if (properties != null) + { + foreach (var property in properties) + { + yield return new KeyValuePair(property.Key, property.Key.IsValueType ? ((ValueHolder)property.Value).ObjectValue : property.Value); + } + } + } + + internal abstract class ValueHolder + { + public abstract object ObjectValue { get; } + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + public void Add(KeyValuePair item) + { + SetObject(item.Key, item.Value); + } + + public delegate void PropertyUpdatedDelegate(ref PropertyContainer propertyContainer, PropertyKey propertyKey, object newValue, object oldValue); + + /// + /// 设置指定的标记值 + /// + /// + /// + public void SetObject([NotNull] PropertyKey propertyKey, object tagValue) + { + SetObject(propertyKey, tagValue, false); + } + + /// + /// 获取指定的标记值 + /// + /// + /// + public object Get([NotNull] PropertyKey propertyKey) + { + return Get(propertyKey, false); + } + + private object Get([NotNull] PropertyKey propertyKey, bool forceNotToKeep) + { + if (propertyKey.AccessorMetadata != null) + { + return propertyKey.AccessorMetadata.GetValue(ref this); + } + + object value; + + if (properties != null && properties.TryGetValue(propertyKey, out value)) + { + if (propertyKey.IsValueType) + value = ((ValueHolder)value).ObjectValue; + return value; + } + + if (propertyKey.DefaultValueMetadata != null) + { + var defaultValue = propertyKey.DefaultValueMetadata.GetDefaultValue(ref this); + + if (propertyKey.DefaultValueMetadata.KeepValue && !forceNotToKeep) + { + SetObject(propertyKey, defaultValue); + } + return defaultValue; + } + + return null; + } + + [DataMemberIgnore] + public object Owner { get; } + + /// + /// 在修改属性时发生 + /// + public event PropertyUpdatedDelegate PropertyUpdated; + + private void SetObject([NotNull] PropertyKey propertyKey, object tagValue, bool tryToAdd) + { + var oldValue = Get(propertyKey, true); + + propertyKey.ValidateValueMetadata?.Validate(ref tagValue); + + if (propertyKey.AccessorMetadata != null) + { + propertyKey.AccessorMetadata.SetValue(ref this, tagValue); + return; + } + + if (properties == null) + properties = new Dictionary(); + + var valueToSet = propertyKey.IsValueType ? propertyKey.CreateValueHolder(tagValue) : tagValue; + + if (PropertyUpdated != null || propertyKey.PropertyUpdateCallback != null) + { + var previousValue = GetNonRecursive(propertyKey); + + if (tryToAdd) + properties.Add(propertyKey, valueToSet); + else + properties[propertyKey] = valueToSet; + + if (!ArePropertyValuesEqual(propertyKey, tagValue, previousValue)) + { + PropertyUpdated?.Invoke(ref this, propertyKey, tagValue, previousValue); + propertyKey.PropertyUpdateCallback?.Invoke(ref this, propertyKey, tagValue, previousValue); + } + } + else + { + if (tryToAdd) + properties.Add(propertyKey, valueToSet); + else + properties[propertyKey] = valueToSet; + } + + propertyKey.ObjectInvalidationMetadata?.Invalidate(Owner, propertyKey, oldValue); + } + + private static bool ArePropertyValuesEqual([NotNull] PropertyKey propertyKey, object propertyValue1, object propertyValue2) + { + var propertyType = propertyKey.PropertyType; + + if (!propertyType.GetTypeInfo().IsValueType && propertyType != typeof(string)) + { + return object.ReferenceEquals(propertyValue1, propertyValue2); + } + + return object.Equals(propertyValue1, propertyValue2); + } + + private object GetNonRecursive([NotNull] PropertyKey propertyKey) + { + object value; + + if (properties != null && properties.TryGetValue(propertyKey, out value)) + { + return propertyKey.IsValueType ? ((ValueHolder)value).ObjectValue : value; + } + + return propertyKey.DefaultValueMetadata?.GetDefaultValue(ref this); + } + + public void Clear() + { + properties?.Clear(); + } + + public bool Contains(KeyValuePair item) + { + object temp; + return properties.TryGetValue(item.Key, out temp) && Equals(temp, item.Value); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + ((IDictionary)properties).CopyTo(array, arrayIndex); + } + + public bool Remove(KeyValuePair item) + { + return Remove(item.Key); + } + + int ICollection>.Count => _count; + + public bool IsReadOnly => false; + private static readonly Dictionary> AccessorProperties = new Dictionary>(); + bool IDictionary.ContainsKey(PropertyKey key) + { + if (key.AccessorMetadata != null && Owner != null) + { + var currentType = Owner.GetType(); + while (currentType != null) + { + List typeAccessorProperties; + if (AccessorProperties.TryGetValue(currentType, out typeAccessorProperties)) + { + foreach (var accessorProperty in typeAccessorProperties) + { + if (accessorProperty == key) + return true; + } + } + + currentType = currentType.GetTypeInfo().BaseType; + } + + return false; + } + + return properties != null && properties.ContainsKey(key); + } + + /// + /// 尝试获得标签值 + /// + /// + /// + /// + bool IReadOnlyDictionary.TryGetValue(PropertyKey key, out object value) + { + if (ContainsKey(key)) + { + var result = Get(key); + value = result; + return true; + } + + value = null; + return false; + } + + /// + /// 确定指定的实例是否包含此键 + /// + /// + /// + public bool ContainsKey([NotNull] PropertyKey key) + { + if (key.AccessorMetadata != null && Owner != null) + { + var currentType = Owner.GetType(); + while (currentType != null) + { + List typeAccessorProperties; + if (AccessorProperties.TryGetValue(currentType, out typeAccessorProperties)) + { + foreach (var accessorProperty in typeAccessorProperties) + { + if (accessorProperty == key) + return true; + } + } + + currentType = currentType.GetTypeInfo().BaseType; + } + + return false; + } + + return properties != null && properties.ContainsKey(key); + } + + public void Add(PropertyKey key, object value) + { + SetObject(key, value, true); + } + + public bool Remove(PropertyKey propertyKey) + { + var removed = false; + + var previousValue = Get(propertyKey); + if (PropertyUpdated != null || propertyKey.PropertyUpdateCallback != null) + { + + if (properties != null) + removed = properties.Remove(propertyKey); + var tagValue = Get(propertyKey); + + if (!ArePropertyValuesEqual(propertyKey, tagValue, previousValue)) + { + propertyKey.PropertyUpdateCallback?.Invoke(ref this, propertyKey, tagValue, previousValue); + PropertyUpdated?.Invoke(ref this, propertyKey, tagValue, previousValue); + } + } + else + { + if (properties != null) + removed = properties.Remove(propertyKey); + } + + propertyKey.ObjectInvalidationMetadata?.Invalidate(Owner, propertyKey, previousValue); + + return removed; + } + + /// + /// 确定指定的实例是否包含此键 + /// + /// + /// + bool IReadOnlyDictionary.ContainsKey(PropertyKey key) + { + if (key.AccessorMetadata != null && Owner != null) + { + var currentType = Owner.GetType(); + while (currentType != null) + { + List typeAccessorProperties; + if (AccessorProperties.TryGetValue(currentType, out typeAccessorProperties)) + { + foreach (var accessorProperty in typeAccessorProperties) + { + if (accessorProperty == key) + return true; + } + } + + currentType = currentType.GetTypeInfo().BaseType; + } + + return false; + } + + return properties != null && properties.ContainsKey(key); + } + + /// + /// 尝试获得标签值 + /// + /// + /// + /// + bool IDictionary.TryGetValue(PropertyKey propertyKey, out object value) + { + if (ContainsKey(propertyKey)) + { + var result = Get(propertyKey); + value = result; + return true; + } + + value = null; + return false; + } + + public object this[PropertyKey key] + { + get + { + return Get(key); + } + set + { + SetObject(key, value); + } + } + + public ICollection Keys + { + get + { + return this.Select(x => x.Key).ToList(); + } + } + + public ICollection Values + { + get + { + return this.Select(x => x.Value).ToList(); + } + } + + /// + /// 获取此容器中存储的属性数 + /// + public int Count + { + get + { + // TODO: 需要优化 + var count = 0; + using (var enumerator = GetEnumerator()) + { + while (enumerator.MoveNext()) + ++count; + } + return count; + } + } + + IEnumerable IReadOnlyDictionary.Keys => Keys; + + IEnumerable IReadOnlyDictionary.Values => Values; + + ICollection IDictionary.Keys => Keys; + + ICollection IDictionary.Values => Values; + + int IReadOnlyCollection>.Count => Count; + } +} \ No newline at end of file diff --git a/CLEditor.Core/PropertyKey.cs b/CLEditor.Core/PropertyKey.cs new file mode 100644 index 0000000..232f82a --- /dev/null +++ b/CLEditor.Core/PropertyKey.cs @@ -0,0 +1,77 @@ +using System; +using System.Diagnostics; + +namespace CLEditor.Core +{ + /// + /// 表示标记属性的类 + /// + [DataContract] + [DebuggerDisplay("{" + nameof(Name) + "}")] + public abstract class PropertyKey : IComparable + { + private DefaultValueMetadata defaultValueMetadata; + /// + /// 获取此键的名称 + /// + public string Name { get; protected set; } + + public int CompareTo(object obj) + { + var key = obj as PropertyKey; + if (key == null) + { + return 0; + } + + return string.Compare(Name, key.Name, StringComparison.OrdinalIgnoreCase); + } + + public abstract bool IsValueType { get; } + + /// + /// 获取验证值元数据(可以为null) + /// + [DataMemberIgnore] + internal ValidateValueMetadata ValidateValueMetadata { get; private set; } + /// + /// 获取访问者元数据(可以为null) + /// + [DataMemberIgnore] + internal AccessorMetadata AccessorMetadata { get; private set; } + + /// + /// 获取或设置属性更新回调 + /// + [DataMemberIgnore] + internal PropertyContainer.PropertyUpdatedDelegate PropertyUpdateCallback { get; private set; } + + /// + /// 获取此键的名称 + /// + [DataMemberIgnore] + internal DefaultValueMetadata DefaultValueMetadata + { + get { return defaultValueMetadata; } + set + { + defaultValueMetadata = value; + PropertyUpdateCallback = defaultValueMetadata.PropertyUpdateCallback; + } + } + + /// + /// 获取对象失效元数据(可以为null) + /// + [DataMemberIgnore] + internal ObjectInvalidationMetadata ObjectInvalidationMetadata { get; private set; } + + /// + /// 获取属性的类型 + /// + [DataMemberIgnore] + public Type PropertyType { get; protected set; } + + internal abstract PropertyContainer.ValueHolder CreateValueHolder(object value); + } +} \ No newline at end of file diff --git a/CLEditor.Core/PropertyKeyMetadata.cs b/CLEditor.Core/PropertyKeyMetadata.cs new file mode 100644 index 0000000..ed4a36b --- /dev/null +++ b/CLEditor.Core/PropertyKeyMetadata.cs @@ -0,0 +1,7 @@ +namespace CLEditor.Core +{ + public abstract class PropertyKeyMetadata + { + + } +} \ No newline at end of file diff --git a/CLEditor.Core/ReferenceCounting/ReferenceCountingExtensions.cs b/CLEditor.Core/ReferenceCounting/ReferenceCountingExtensions.cs new file mode 100644 index 0000000..d591abd --- /dev/null +++ b/CLEditor.Core/ReferenceCounting/ReferenceCountingExtensions.cs @@ -0,0 +1,20 @@ +using System.Runtime.CompilerServices; +using CLEditor.Core.Annotations; + +namespace CLEditor.Core.ReferenceCounting +{ + public static class ReferenceCountingExtensions + { + /// + /// 减少此实例的引用计数 + /// + /// + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ReleaseInternal([NotNull] this IReferencable referencable) + { + return referencable.Release(); + } + + } +} \ No newline at end of file diff --git a/CLEditor.Core/Serialization/DataSerializerAttribute.cs b/CLEditor.Core/Serialization/DataSerializerAttribute.cs new file mode 100644 index 0000000..4767a07 --- /dev/null +++ b/CLEditor.Core/Serialization/DataSerializerAttribute.cs @@ -0,0 +1,25 @@ +using System; +using CLEditor.Core.Annotations; + +namespace CLEditor.Core.Serialization +{ + /// + /// 在类上使用此属性可指定其数据序列化程序类型 + /// + [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] + public class DataSerializerAttribute : Attribute + { + /// + /// 获取数据序列化程序的类型 + /// + [NotNull] + public Type DataSerializerType; + + public DataSerializerGenericMode Mode; + + public DataSerializerAttribute([NotNull] Type dataSerializerType) + { + DataSerializerType = dataSerializerType; + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/Serialization/DataSerializerGenericMode.cs b/CLEditor.Core/Serialization/DataSerializerGenericMode.cs new file mode 100644 index 0000000..878ee8b --- /dev/null +++ b/CLEditor.Core/Serialization/DataSerializerGenericMode.cs @@ -0,0 +1,19 @@ +namespace CLEditor.Core.Serialization +{ + /// + /// 定义要传递给序列化程序的通用参数 + /// + public enum DataSerializerGenericMode + { + None = 0, + /// + /// 序列化类型的类型将作为序列化程序的通用参数传递 + /// + Type = 1, + /// + /// 序列化类型的泛型参数将作为序列化程序的通用参数传递 + /// + GenericArguments = 2, + TypeAndGenericArguments = 3, + } +} \ No newline at end of file diff --git a/CLEditor.Core/Utilities.cs b/CLEditor.Core/Utilities.cs new file mode 100644 index 0000000..d2429d2 --- /dev/null +++ b/CLEditor.Core/Utilities.cs @@ -0,0 +1,20 @@ +using System; +using System.Runtime.InteropServices; + +namespace CLEditor.Core +{ + /// + /// 实用类 + /// + public static class Utilities + { + /// + /// 分配对齐的内存缓冲区 + /// + /// + public static unsafe void FreeMemory(IntPtr alignedBuffer) + { + Marshal.FreeHGlobal(((IntPtr*) alignedBuffer)[-1]); + } + } +} \ No newline at end of file diff --git a/CLEditor.Core/ValidateValueMetadata.cs b/CLEditor.Core/ValidateValueMetadata.cs new file mode 100644 index 0000000..678b70b --- /dev/null +++ b/CLEditor.Core/ValidateValueMetadata.cs @@ -0,0 +1,7 @@ +namespace CLEditor.Core +{ + public abstract class ValidateValueMetadata : PropertyKeyMetadata + { + public abstract void Validate(ref object obj); + } +} \ No newline at end of file diff --git a/CLEditor.sln b/CLEditor.sln index be1ef8c..d4c7d16 100644 --- a/CLEditor.sln +++ b/CLEditor.sln @@ -17,6 +17,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "BuildEngine", "BuildEngine" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLEditor.BuildEngine.Common", "CLEditor.BuildEngine.Common\CLEditor.BuildEngine.Common.csproj", "{14E96242-DA07-4408-BFD5-CEB6D2FE9CCE}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AssetEngine", "AssetEngine", "{CD40EE54-68B9-47F9-9B40-0D2DD2B18A96}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLEditor.AssetEngine", "CLEditor.AssetEngine\CLEditor.AssetEngine.csproj", "{FE171BF2-9210-4A24-BCE4-BDB95E6202F5}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CLEngine", "CLEngine\CLEngine.csproj", "{64882F3D-F201-43FC-9C9B-F92D7A37F846}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -95,6 +101,30 @@ Global {14E96242-DA07-4408-BFD5-CEB6D2FE9CCE}.Release|x64.Build.0 = Release|Any CPU {14E96242-DA07-4408-BFD5-CEB6D2FE9CCE}.Release|x86.ActiveCfg = Release|Any CPU {14E96242-DA07-4408-BFD5-CEB6D2FE9CCE}.Release|x86.Build.0 = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|Any CPU.Build.0 = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|x64.ActiveCfg = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|x64.Build.0 = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|x86.ActiveCfg = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Debug|x86.Build.0 = Debug|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|Any CPU.ActiveCfg = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|Any CPU.Build.0 = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|x64.ActiveCfg = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|x64.Build.0 = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|x86.ActiveCfg = Release|Any CPU + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5}.Release|x86.Build.0 = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|Any CPU.Build.0 = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|x64.ActiveCfg = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|x64.Build.0 = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|x86.ActiveCfg = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Debug|x86.Build.0 = Debug|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|Any CPU.ActiveCfg = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|Any CPU.Build.0 = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|x64.ActiveCfg = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|x64.Build.0 = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|x86.ActiveCfg = Release|Any CPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -102,6 +132,7 @@ Global GlobalSection(NestedProjects) = preSolution {F49C4C69-3A15-4201-8AA2-29E115A17311} = {C2329FBC-8B03-4A1F-9873-3688D3A0F679} {14E96242-DA07-4408-BFD5-CEB6D2FE9CCE} = {C2329FBC-8B03-4A1F-9873-3688D3A0F679} + {FE171BF2-9210-4A24-BCE4-BDB95E6202F5} = {CD40EE54-68B9-47F9-9B40-0D2DD2B18A96} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {09D24DF9-151B-4065-8E04-AA89C79159C9} diff --git a/CLEngine/CGame.cs b/CLEngine/CGame.cs new file mode 100644 index 0000000..61d934e --- /dev/null +++ b/CLEngine/CGame.cs @@ -0,0 +1,28 @@ +using CLEditor.Core.Diagnostics; +using Microsoft.Xna.Framework; + +namespace CLEngine +{ + /// + /// 主要游戏类系统 + /// + public class CGame : Game + { + private readonly LogListener logListener; + + public CGame() + { + logListener = GetLogListener(); + + if (logListener != null) + { + GlobalLogger.GlobalMessageLogged += logListener; + } + } + + protected virtual LogListener GetLogListener() + { + return new ConsoleLogListener(); + } + } +} \ No newline at end of file diff --git a/CLEngine/CLEngine.csproj b/CLEngine/CLEngine.csproj new file mode 100644 index 0000000..e81297f --- /dev/null +++ b/CLEngine/CLEngine.csproj @@ -0,0 +1,59 @@ + + + + + Debug + AnyCPU + {64882F3D-F201-43FC-9C9B-F92D7A37F846} + Library + Properties + CLEngine + CLEngine + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\packages\MonoGame.Framework.Portable.3.6.0.1625\lib\portable-net45+win8+wpa81\MonoGame.Framework.dll + + + + + + + + + + + + + + + + + + + + {A9459A99-39D8-480B-BF14-A7687ECE7DB1} + CLEditor.Core + + + + \ No newline at end of file diff --git a/CLEngine/Properties/AssemblyInfo.cs b/CLEngine/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..db87347 --- /dev/null +++ b/CLEngine/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// 有关程序集的一般信息由以下 +// 控制。更改这些特性值可修改 +// 与程序集关联的信息。 +[assembly: AssemblyTitle("CLEngine")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CLEngine")] +[assembly: AssemblyCopyright("Copyright © 2018")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// 将 ComVisible 设置为 false 会使此程序集中的类型 +//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型 +//请将此类型的 ComVisible 特性设置为 true。 +[assembly: ComVisible(false)] + +// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID +[assembly: Guid("64882f3d-f201-43fc-9c9b-f92d7a37f846")] + +// 程序集的版本信息由下列四个值组成: +// +// 主版本 +// 次版本 +// 生成号 +// 修订号 +// +// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号 +//通过使用 "*",如下所示: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CLEngine/packages.config b/CLEngine/packages.config new file mode 100644 index 0000000..78caa92 --- /dev/null +++ b/CLEngine/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/README.md b/README.md index ff5f1f3..e031465 100644 --- a/README.md +++ b/README.md @@ -44,6 +44,40 @@ WPF高性能界面 28. 自定义插件 29. 自定义组件 +### 引擎提供 +1. 动画 - Animations +> 使用Textures和Sprites,我们可以导入Sprite Sheets,在同一个文件上maped图像集合,并通过SpriteBatch在屏幕上绘制它们 +2. 位图字体 - BitmapFonts +> 使用BMFont工具生成的位图字体用于代替内置SpriteFont的方法之一 +3. 相机 - Cameras +> 相机的目的是创建一个转换矩阵,改变精灵批处理的渲染方式 +4. 集合 - Collections +> 集合是对C#集合的扩展,更适合游戏使用 +5. 碰撞 - Collisions +> 基于2D网格的碰撞系统 +6. 资源编译 - ContentPipline +7. 资源 - Content +8. 实体 - Entities +> Entities包是一个基于Artemis的现代高性能实体组件系统 +9. 图形 - Graphics +> 包含用于生成动态几何和批处理绘制调用的扩展 +10. 界面 - GUI +11. 输入 - Input +12. 对象池 - ObjectPooling +> 对象池是一种优化模式, 在某些情况下,它通过重用对象而不是按需为它们分配内存来提高性能。 在C / C ++中,对象池提供的是一个避免内存碎片的解决方案。 在C#中,由于垃圾回收,我们不必担心内存碎片。 但是,在CPU速度较慢且垃圾收集器较简单的移动设备上我们还是特别需要对象池。 +13. 粒子 - Particles +> 高性能粒子系统 +14. 场景图 - SceneGraphs +> 含一个场景图(树)系统 +15. 场景 - Screens +> ScreenGameComponent管理各个Screen对象 +16. 序列 - Serialization +> 序列化助手 +17. 地图 - Tiled +> 加载和渲染使用Tiled Map Editor创建的地图 +18. 缓动 - Tweening +> 基于补间的动画的类扩展 + ### 未来实现功能 1. GPU粒子系统 2. LoD渲染器 -- Gitee