mirror of
https://github.com/Cardidi/ca2d-unity-toolkit.git
synced 2025-12-20 01:06:03 +08:00
Add some basic features of this toolkit.
feat: Logg was almost done. fix: Some impossible call was fixed in UnityObjectWarp.cs feat: Boxing<T> was force to unbox by explicit cast operator.
This commit is contained in:
parent
91c24b27e8
commit
0315862527
@ -7,28 +7,43 @@ namespace Ca2d.Toolkit
|
||||
|
||||
public static class AsDisposableExtension
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert an <see cref="System.Action"/> to a IDisposable callback.
|
||||
/// </summary>
|
||||
public static AsDisposable AsDisposable(Action callback)
|
||||
{
|
||||
return new AsDisposable(callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an <see cref="System.Action"/> to a IDisposable callback.
|
||||
/// </summary>
|
||||
public static AsAsyncDisposable AsAsyncDisposable(Func<UniTask> callback)
|
||||
{
|
||||
return new AsAsyncDisposable(callback);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert an <see cref="System.Action"/> to a IDisposable callback in chain style.
|
||||
/// </summary>
|
||||
public static AsDisposable<T> AsDisposable<T>(this T target, Action<T> callback)
|
||||
{
|
||||
return new AsDisposable<T>(callback, target);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Convert an <see cref="System.Action"/> to a IDisposable callback in chain style.
|
||||
/// </summary>
|
||||
public static AsAsyncDisposable<T> AsAsyncDisposable<T>(this T target, Func<T, UniTask> callback)
|
||||
{
|
||||
return new AsAsyncDisposable<T>(callback, target);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An operation container for <see cref="IDisposable"/>.
|
||||
/// </summary>
|
||||
public readonly struct AsDisposable : IDisposable
|
||||
{
|
||||
private readonly Action m_callback;
|
||||
@ -49,6 +64,10 @@ namespace Ca2d.Toolkit
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An operation container for <see cref="IDisposable"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TParam">Object select source.</typeparam>
|
||||
public readonly struct AsDisposable<TParam> : IDisposable
|
||||
{
|
||||
private readonly Action<TParam> m_callback;
|
||||
@ -73,6 +92,9 @@ namespace Ca2d.Toolkit
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An operation container for <see cref="IDisposable"/>.
|
||||
/// </summary>
|
||||
public readonly struct AsAsyncDisposable : IAsyncDisposable
|
||||
{
|
||||
private readonly Func<UniTask> m_callback;
|
||||
@ -94,6 +116,10 @@ namespace Ca2d.Toolkit
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An operation container for <see cref="IDisposable"/>.
|
||||
/// </summary>
|
||||
/// <typeparam name="TParam">Object select source.</typeparam>
|
||||
public readonly struct AsAsyncDisposable<TParam> : IAsyncDisposable
|
||||
{
|
||||
private readonly Func<TParam, UniTask> m_callback;
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
@ -18,7 +17,7 @@ namespace Ca2d.Toolkit
|
||||
/// </summary>
|
||||
public Boxing(Boxing<T> source)
|
||||
{
|
||||
m_value = source.Unbox;
|
||||
m_value = source.m_value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -30,24 +29,15 @@ namespace Ca2d.Toolkit
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a empty boxing.
|
||||
/// Create an empty boxing.
|
||||
/// </summary>
|
||||
public Boxing()
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Get a copy of boxing value.
|
||||
/// Access to the boxing value directly in reference mode.
|
||||
/// </summary>
|
||||
public T Unbox
|
||||
{
|
||||
get => m_value;
|
||||
set => m_value = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access to the boxing value directly.
|
||||
/// </summary>
|
||||
public ref T Direct => ref m_value;
|
||||
public ref T Ref => ref m_value;
|
||||
|
||||
/// <summary>
|
||||
/// Clean this boxing container to the default value of boxing target.
|
||||
@ -62,9 +52,9 @@ namespace Ca2d.Toolkit
|
||||
return m_value.ToString();
|
||||
}
|
||||
|
||||
public static implicit operator T(Boxing<T> wrapper)
|
||||
public static explicit operator T(Boxing<T> wrapper)
|
||||
{
|
||||
return wrapper.Unbox;
|
||||
return wrapper.m_value;
|
||||
}
|
||||
|
||||
public static implicit operator Boxing<T>(T value)
|
||||
|
||||
43
Assets/Main/Scripts/ILoggHandler.cs
Normal file
43
Assets/Main/Scripts/ILoggHandler.cs
Normal file
@ -0,0 +1,43 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
public enum LoggType
|
||||
{
|
||||
/// <summary>
|
||||
/// <para>LogType used for Errors.</para>
|
||||
/// </summary>
|
||||
Error,
|
||||
/// <summary>
|
||||
/// <para>LogType used for Asserts. (These could also indicate an error inside Unity itself.)</para>
|
||||
/// </summary>
|
||||
Assert,
|
||||
/// <summary>
|
||||
/// <para>LogType used for Warnings.</para>
|
||||
/// </summary>
|
||||
Warning,
|
||||
/// <summary>
|
||||
/// <para>LogType used for regular log messages.</para>
|
||||
/// </summary>
|
||||
Log,
|
||||
/// <summary>
|
||||
/// <para>LogType used for Exceptions.</para>
|
||||
/// </summary>
|
||||
Exception,
|
||||
/// <summary>
|
||||
/// <para>LogType used for Developers on testing.</para>
|
||||
/// </summary>
|
||||
Debug
|
||||
}
|
||||
|
||||
public interface ILoggHandler : ILogHandler
|
||||
{
|
||||
public ILogHandler InnerLogHandler { get; }
|
||||
|
||||
public void LoggFormat(LoggType logType, Object context, string format, params object[] args);
|
||||
|
||||
public void SetLabel(string label);
|
||||
|
||||
public void ClearLabel();
|
||||
}
|
||||
}
|
||||
3
Assets/Main/Scripts/ILoggHandler.cs.meta
Normal file
3
Assets/Main/Scripts/ILoggHandler.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bfec301646cc46339921f4c1c9170412
|
||||
timeCreated: 1715271270
|
||||
@ -1,497 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
public readonly struct Log : IDisposable
|
||||
{
|
||||
private const string kNoLabelAndContextName = "Anonymous";
|
||||
|
||||
private const string kFallbackLabelName = "Fallback";
|
||||
|
||||
private static HashSet<int> _loopDetector = new();
|
||||
|
||||
private static StringBuilder _sb = new();
|
||||
|
||||
#region ManagedRegionOperations
|
||||
|
||||
private static Core _fallbackCore = new Core
|
||||
{
|
||||
ValidateNumber = 0,
|
||||
ParentIndex = 0,
|
||||
ParentValidateNumber = 0,
|
||||
Context = null,
|
||||
Label = kFallbackLabelName
|
||||
};
|
||||
|
||||
private static List<Core> _core = new()
|
||||
{
|
||||
// This is the first element of AdvDebugCore and also as fallback options.
|
||||
_fallbackCore
|
||||
};
|
||||
|
||||
#region Allocation
|
||||
|
||||
private static List<Vector2Int> m_allocMap = new()
|
||||
{
|
||||
// The first element must be allocated.
|
||||
new Vector2Int(0, 1)
|
||||
};
|
||||
|
||||
private static bool RangeOverlap(Vector2Int a, Vector2Int b)
|
||||
{
|
||||
var offset = a.x - b.x;
|
||||
switch (offset)
|
||||
{
|
||||
case < 0:
|
||||
{
|
||||
var o = -offset;
|
||||
var lenA = a.y - a.x;
|
||||
return o < lenA;
|
||||
}
|
||||
case > 0:
|
||||
{
|
||||
var o = offset;
|
||||
var lenB = b.y - b.x;
|
||||
return o < lenB;
|
||||
}
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static bool IsIdUsed(int id)
|
||||
{
|
||||
return m_allocMap.Exists(range => id >= range.x && id < range.y);
|
||||
}
|
||||
|
||||
private static int GetUnusedId()
|
||||
{
|
||||
var alloc = m_allocMap[0].y;
|
||||
if (alloc == int.MaxValue) throw new IndexOutOfRangeException("No free index can be exposed!");
|
||||
return alloc;
|
||||
}
|
||||
|
||||
public static bool AllocId(int id)
|
||||
{
|
||||
if (id <= 0 || id == int.MaxValue) return false;
|
||||
var range = new Vector2Int(id, id + 1);
|
||||
|
||||
for (var i = 1; i < m_allocMap.Count; i++)
|
||||
{
|
||||
var r = m_allocMap[i];
|
||||
var insert = i + 1;
|
||||
if (m_allocMap.Count != insert && RangeOverlap(r, range)) continue;
|
||||
|
||||
// Get the reaction on merge.
|
||||
var mergePrev = false;
|
||||
var mergeNext = false;
|
||||
|
||||
var before = m_allocMap[insert - 1];
|
||||
if (before.y == range.x) mergePrev = true;
|
||||
|
||||
var after = m_allocMap.Count > insert ? m_allocMap[insert] : default;
|
||||
if (after.y != 0 && after.x == range.y) mergeNext = true;
|
||||
|
||||
if (mergePrev & mergeNext)
|
||||
{
|
||||
m_allocMap[insert - 1] = new Vector2Int(before.x, after.y);
|
||||
m_allocMap.RemoveAt(insert);
|
||||
}
|
||||
else if (mergePrev)
|
||||
{
|
||||
m_allocMap[insert - 1] = new Vector2Int(before.x, range.y);
|
||||
}
|
||||
else if (mergeNext)
|
||||
{
|
||||
m_allocMap[insert] = new Vector2Int(range.x, after.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allocMap.Insert(insert, range);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool FreeId(int id)
|
||||
{
|
||||
if (id <= 0 || id == int.MaxValue) return false;
|
||||
var range = new Vector2Int(id, id + 1);
|
||||
var idx = m_allocMap.FindIndex(r => RangeOverlap(r, range));
|
||||
if (idx < 0) return false;
|
||||
|
||||
// Get reaction on split
|
||||
var insertLeft = true;
|
||||
var insertRight = true;
|
||||
|
||||
var splitTarget = m_allocMap[id];
|
||||
if (splitTarget.x == range.x) insertLeft = false;
|
||||
if (splitTarget.y == range.y) insertRight = false;
|
||||
|
||||
if (insertLeft || insertRight)
|
||||
{
|
||||
if (insertLeft)
|
||||
{
|
||||
m_allocMap[idx] = new Vector2Int(splitTarget.x, range.x);
|
||||
}
|
||||
|
||||
if (insertRight)
|
||||
{
|
||||
m_allocMap.Insert(idx + 1, new Vector2Int(range.y, splitTarget.y));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_allocMap.RemoveAt(idx);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
private struct Capture
|
||||
{
|
||||
public readonly ulong CaptureValidateNumber;
|
||||
|
||||
public readonly int ResourceIndex;
|
||||
|
||||
public object Context
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsValid()) return _core[ResourceIndex].Context;
|
||||
return _fallbackCore.Context;
|
||||
}
|
||||
}
|
||||
|
||||
public string Label
|
||||
{
|
||||
get
|
||||
{
|
||||
if (IsValid()) return _core[ResourceIndex].Label;
|
||||
return _fallbackCore.Label;
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryResolveParent(out Capture capture, bool includeFallback = false)
|
||||
{
|
||||
if (IsValid())
|
||||
{
|
||||
capture = new Capture(_core[ResourceIndex].ParentIndex);
|
||||
if (capture.IsFallback()) return includeFallback;
|
||||
return capture.CaptureValidateNumber == _core[ResourceIndex].ParentValidateNumber;
|
||||
}
|
||||
|
||||
capture = default;
|
||||
return includeFallback;
|
||||
}
|
||||
|
||||
public Capture(int idx)
|
||||
{
|
||||
if (idx >= _core.Count || idx <= 0)
|
||||
{
|
||||
CaptureValidateNumber = default;
|
||||
ResourceIndex = default;
|
||||
return;
|
||||
}
|
||||
|
||||
ResourceIndex = idx;
|
||||
CaptureValidateNumber = _core[idx].ValidateNumber;
|
||||
}
|
||||
|
||||
public bool IsFallback()
|
||||
{
|
||||
return ResourceIndex == 0;
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
var resIdx = ResourceIndex;
|
||||
if (resIdx == 0) return true;
|
||||
if (resIdx >= _core.Count || resIdx < 0) return false;
|
||||
return _core[resIdx].ParentValidateNumber == CaptureValidateNumber && IsIdUsed(resIdx);
|
||||
}
|
||||
}
|
||||
|
||||
private struct Core
|
||||
{
|
||||
public ulong ValidateNumber;
|
||||
|
||||
public ulong ParentValidateNumber;
|
||||
|
||||
public int ParentIndex;
|
||||
|
||||
public object Context;
|
||||
|
||||
public string Label;
|
||||
}
|
||||
|
||||
private static bool RequestCore(out Capture capture, string label, object context, int parentId)
|
||||
{
|
||||
var id = GetUnusedId();
|
||||
if (AllocId(id))
|
||||
{
|
||||
// Make sure there has valid space to allocate.
|
||||
while (_core.Count - 1 < id) _core.Add(default);
|
||||
|
||||
var c = _core[id];
|
||||
|
||||
// Set context of current Debug.
|
||||
c.Context = context;
|
||||
c.Label = label;
|
||||
|
||||
// Check is given parent id is valid and fill result.
|
||||
c.ParentIndex = parentId != 0 && IsIdUsed(parentId) ? parentId : 0;
|
||||
c.ParentValidateNumber = c.ParentIndex == 0 ? 0 : _core[c.ParentIndex].ValidateNumber;
|
||||
|
||||
_core[id] = c;
|
||||
capture = new Capture(id);
|
||||
return true;
|
||||
}
|
||||
|
||||
capture = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool ReturnCore(Capture capture)
|
||||
{
|
||||
if (capture.IsFallback() || !capture.IsValid()) return false;
|
||||
if (!FreeId(capture.ResourceIndex)) return false;
|
||||
|
||||
var core = _core[capture.ResourceIndex];
|
||||
|
||||
core.ValidateNumber += 1;
|
||||
core.ParentValidateNumber = default;
|
||||
core.ParentIndex = default;
|
||||
core.Context = null;
|
||||
core.Label = kFallbackLabelName;
|
||||
|
||||
_core[capture.ResourceIndex] = core;
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ExposeValue
|
||||
|
||||
public bool IsFallback => m_capture.IsFallback();
|
||||
|
||||
public string Label => m_capture.Label;
|
||||
|
||||
public object Context => m_capture.Context;
|
||||
|
||||
public Log? Parent
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_capture.TryResolveParent(out var cap, false))
|
||||
return new Log(cap);
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Lifecircle
|
||||
|
||||
private readonly Capture m_capture;
|
||||
|
||||
private Log(Capture capture)
|
||||
{
|
||||
m_capture = capture;
|
||||
}
|
||||
|
||||
public Log(Log parent = default)
|
||||
{
|
||||
if (!RequestCore(out var capture, kNoLabelAndContextName, null, parent.m_capture.ResourceIndex))
|
||||
{
|
||||
m_capture = default;
|
||||
return;
|
||||
}
|
||||
|
||||
m_capture = capture;
|
||||
}
|
||||
|
||||
public Log(string label, Log parent = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(label)) label = kNoLabelAndContextName;
|
||||
if (!RequestCore(out var capture, label, null, parent.m_capture.ResourceIndex))
|
||||
{
|
||||
m_capture = default;
|
||||
return;
|
||||
}
|
||||
|
||||
m_capture = capture;
|
||||
}
|
||||
|
||||
public Log(object context, Log parent = default)
|
||||
{
|
||||
var label = context == null ? kNoLabelAndContextName : context.GetType().Name;
|
||||
if (!RequestCore(out var capture, label, null, parent.m_capture.ResourceIndex))
|
||||
{
|
||||
m_capture = default;
|
||||
return;
|
||||
}
|
||||
|
||||
m_capture = capture;
|
||||
}
|
||||
|
||||
public Log(string label, object context, Log parent = default)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(label)) label = context == null ? kNoLabelAndContextName : context.GetType().Name;
|
||||
if (!RequestCore(out var capture, label, null, parent.m_capture.ResourceIndex))
|
||||
{
|
||||
m_capture = default;
|
||||
return;
|
||||
}
|
||||
|
||||
m_capture = capture;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!FreeId(m_capture.ResourceIndex) || !ReturnCore(m_capture)) throw new InvalidOperationException(
|
||||
"You can not trying to dispose an outdated or default AdvLogger!");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void Debug(string text)
|
||||
{
|
||||
}
|
||||
|
||||
public void Info(string text)
|
||||
{}
|
||||
|
||||
public void Warning(string text)
|
||||
{}
|
||||
|
||||
public void Error(string text)
|
||||
{}
|
||||
|
||||
public void Error(Exception err)
|
||||
{}
|
||||
}
|
||||
|
||||
public static class QLog
|
||||
{
|
||||
|
||||
#region (string)
|
||||
|
||||
public static void Debug(string text)
|
||||
{
|
||||
default(Log).Debug(text);
|
||||
}
|
||||
|
||||
public static void Info(string text)
|
||||
{
|
||||
default(Log).Info(text);
|
||||
}
|
||||
|
||||
public static void Warning(string text)
|
||||
{
|
||||
default(Log).Warning(text);
|
||||
}
|
||||
|
||||
public static void Error(string text)
|
||||
{
|
||||
default(Log).Error(text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region (string, string)
|
||||
|
||||
public static void Debug(string text, string label)
|
||||
{
|
||||
using var logger = new Log(label);
|
||||
logger.Debug(text);
|
||||
}
|
||||
|
||||
public static void Info(string text, string label)
|
||||
{
|
||||
using var logger = new Log(label);
|
||||
logger.Info(text);
|
||||
}
|
||||
|
||||
public static void Warning(string text, string label)
|
||||
{
|
||||
using var logger = new Log(label);
|
||||
logger.Warning(text);
|
||||
}
|
||||
|
||||
public static void Error(string text, string label)
|
||||
{
|
||||
using var logger = new Log(label);
|
||||
logger.Error(text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region (string, object)
|
||||
|
||||
public static void Debug(string text, object context)
|
||||
{
|
||||
using var logger = new Log(context);
|
||||
logger.Debug(text);
|
||||
}
|
||||
|
||||
public static void Info(string text, object context)
|
||||
{
|
||||
using var logger = new Log(context);
|
||||
logger.Info(text);
|
||||
}
|
||||
|
||||
public static void Warning(string text, object context)
|
||||
{
|
||||
using var logger = new Log(context);
|
||||
logger.Warning(text);
|
||||
}
|
||||
|
||||
public static void Error(string text, object context)
|
||||
{
|
||||
using var logger = new Log(context);
|
||||
logger.Error(text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region (string, string, object)
|
||||
|
||||
public static void Debug(string text, string label, object context)
|
||||
{
|
||||
using var logger = new Log(label, context);
|
||||
logger.Info(text);
|
||||
}
|
||||
|
||||
public static void Info(string text, string label, object context)
|
||||
{
|
||||
using var logger = new Log(label, context);
|
||||
logger.Info(text);
|
||||
}
|
||||
|
||||
public static void Warning(string text, string label, object context)
|
||||
{
|
||||
using var logger = new Log(label, context);
|
||||
logger.Warning(text);
|
||||
}
|
||||
|
||||
public static void Error(string text, string label, object context)
|
||||
{
|
||||
using var logger = new Log(label, context);
|
||||
logger.Error(text);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3b5d1b48628646eebc9e64c30bd93ae8
|
||||
timeCreated: 1713286134
|
||||
282
Assets/Main/Scripts/Logg.cs
Normal file
282
Assets/Main/Scripts/Logg.cs
Normal file
@ -0,0 +1,282 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// Alternatives to the default Unity Logger.
|
||||
/// </summary>
|
||||
public struct Logg
|
||||
{
|
||||
#region BackendConfig
|
||||
|
||||
// ReSharper disable once MemberCanBePrivate.Global
|
||||
public const string kDefaultLoggerLevelSplit = "::";
|
||||
|
||||
private static ILoggHandler _backend;
|
||||
|
||||
/// <summary>
|
||||
/// Which backend will be used for logger?
|
||||
/// </summary>
|
||||
public static ILoggHandler Backend
|
||||
{
|
||||
get => _backend;
|
||||
set => _backend = value ?? throw new NullReferenceException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logger level name spliter sign.
|
||||
/// </summary>
|
||||
public static string LoggerLevelSplit { get; set; } = kDefaultLoggerLevelSplit;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
|
||||
private static readonly StringBuilder kStringBuilder = new();
|
||||
|
||||
private readonly bool m_useLabel;
|
||||
|
||||
private readonly string m_label;
|
||||
|
||||
/// <summary>
|
||||
/// Create a logger with first-level namespace
|
||||
/// </summary>
|
||||
/// <param name="ns">Namespace</param>
|
||||
public Logg(string ns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ns))
|
||||
{
|
||||
m_useLabel = false;
|
||||
m_label = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_useLabel = true;
|
||||
m_label = ns.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a copy of source logger.
|
||||
/// </summary>
|
||||
/// <param name="source">Source logger.</param>
|
||||
public Logg(Logg source)
|
||||
{
|
||||
if (source.m_useLabel)
|
||||
{
|
||||
m_useLabel = true;
|
||||
m_label = source.m_label;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_useLabel = false;
|
||||
m_label = null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a nested logger with given namespace.
|
||||
/// </summary>
|
||||
/// <param name="source">Nest source.</param>
|
||||
/// <param name="ns">Namespace</param>
|
||||
public Logg(Logg source, string ns)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(ns))
|
||||
{
|
||||
if (source.m_useLabel)
|
||||
{
|
||||
m_useLabel = true;
|
||||
m_label = source.m_label;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_useLabel = false;
|
||||
m_label = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_useLabel = true;
|
||||
if (source.m_useLabel)
|
||||
{
|
||||
kStringBuilder.Clear();
|
||||
m_label = kStringBuilder.AppendJoin(LoggerLevelSplit, source.m_label, ns.Trim()).ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_label = ns.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region EnvOverrider
|
||||
|
||||
private static bool _init = false;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[InitializeOnLoadMethod]
|
||||
private static void LoggInitEditor()
|
||||
{
|
||||
LoggInit();
|
||||
}
|
||||
#else
|
||||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void RuntimeLoggInit()
|
||||
{
|
||||
LoggInit();
|
||||
}
|
||||
#endif
|
||||
|
||||
private static void LoggInit()
|
||||
{
|
||||
if (!_init)
|
||||
{
|
||||
var prevLogHandler = UnityEngine.Debug.unityLogger.logHandler;
|
||||
|
||||
if (prevLogHandler is ILoggHandler)
|
||||
{
|
||||
prevLogHandler.LogFormat(
|
||||
LogType.Warning,
|
||||
null,
|
||||
"Logg seems to be inited before initialize?");
|
||||
}
|
||||
else
|
||||
{
|
||||
var l = new LoggHandler(prevLogHandler);
|
||||
_backend = l;
|
||||
UnityEngine.Debug.unityLogger.logHandler = l;
|
||||
prevLogHandler.LogFormat(LogType.Log, null, "##### Debug.unityLogger was taken over by Logg #####");
|
||||
}
|
||||
|
||||
_init = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region LogMethods
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Format(LoggType type, Object context, string format, params object[] args)
|
||||
{
|
||||
if (_backend != null)
|
||||
{
|
||||
if (m_useLabel) _backend.SetLabel(m_label);
|
||||
_backend.LoggFormat(type, context, format, args);
|
||||
_backend.ClearLabel();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use fallback logger if Logg is not ready.
|
||||
UnityEngine.Debug.LogFormat((LogType) type, LogOption.NoStacktrace, context, format, args);
|
||||
}
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Debug(string content, Object context = null)
|
||||
{
|
||||
Format(LoggType.Debug, context, content);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Info(string content, Object context = null)
|
||||
{
|
||||
Format(LoggType.Log, context, content);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Warning(string content, Object context = null)
|
||||
{
|
||||
Format(LoggType.Warning, context, content);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Error(string content, Object context = null)
|
||||
{
|
||||
Format(LoggType.Error, context, content);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void Error(Exception err, Object context = null)
|
||||
{
|
||||
Format(LoggType.Exception, context, err.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Quick log API for <see cref="Logg"/>.
|
||||
/// </summary>
|
||||
public static class DebugLogg
|
||||
{
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Format(LoggType type, Object context, string format, params object[] args)
|
||||
{
|
||||
default(Logg).Format(type, context, format, args);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Debug(string content, Object context = null)
|
||||
{
|
||||
default(Logg).Debug(content, context);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Info(string content, Object context = null)
|
||||
{
|
||||
default(Logg).Info(content, context);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Warning(string content, Object context = null)
|
||||
{
|
||||
default(Logg).Warning(content, context);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Error(string content, Object context = null)
|
||||
{
|
||||
default(Logg).Error(content, context);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public static void Error(Exception err, Object context = null)
|
||||
{
|
||||
default(Logg).Error(err, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Main/Scripts/Logg.cs.meta
Normal file
3
Assets/Main/Scripts/Logg.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 59eb97c7769441599ea2569c2f5402b8
|
||||
timeCreated: 1715264700
|
||||
102
Assets/Main/Scripts/LoggHandler.cs
Normal file
102
Assets/Main/Scripts/LoggHandler.cs
Normal file
@ -0,0 +1,102 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
public class LoggHandler : ILoggHandler
|
||||
{
|
||||
private readonly ILogHandler m_innerHandle;
|
||||
|
||||
private readonly StringBuilder m_sb = new();
|
||||
|
||||
private bool m_useLabel = false;
|
||||
|
||||
private string m_labelText = default;
|
||||
|
||||
#region PassThrough
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void LogFormat(LogType logType, Object context, string format, params object[] args)
|
||||
{
|
||||
LoggFormat((LoggType) logType, context, format, args);
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void LogException(Exception exception, Object context)
|
||||
{
|
||||
LoggFormat(LoggType.Exception, context, exception.ToString());
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void GenerateLabel(StringBuilder sb, LoggType type)
|
||||
{
|
||||
var logTypeText = type switch
|
||||
{
|
||||
LoggType.Assert => "ASSERT",
|
||||
LoggType.Exception => "EXCEPTION",
|
||||
LoggType.Error => "Error",
|
||||
LoggType.Warning => "Warning",
|
||||
LoggType.Log => "Info",
|
||||
_ => "Debug"
|
||||
};
|
||||
|
||||
if (m_useLabel)
|
||||
{
|
||||
sb.AppendFormat("[{0:yyyy-M-d HH:mm:ss}] {1} ({2}) : ", DateTime.Now, logTypeText, m_labelText);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat("[{0:yyyy-M-d HH:mm:ss}] {1} : ", DateTime.Now, logTypeText);
|
||||
}
|
||||
}
|
||||
|
||||
[HideInCallstack]
|
||||
[DebuggerHidden]
|
||||
[DebuggerStepThrough]
|
||||
public void LoggFormat(LoggType logType, Object context, string format, params object[] args)
|
||||
{
|
||||
m_sb.Clear();
|
||||
|
||||
// Write label to the front
|
||||
GenerateLabel(m_sb, logType);
|
||||
|
||||
// Write format text after front
|
||||
m_sb.AppendFormat(format, args);
|
||||
|
||||
// Redirect Debug to Log.
|
||||
LogType finalType;
|
||||
if (logType == LoggType.Debug) finalType = LogType.Log;
|
||||
else finalType = (LogType) logType;
|
||||
|
||||
// Use inner handle to write.
|
||||
m_innerHandle.LogFormat(finalType, context, m_sb.ToString());
|
||||
}
|
||||
|
||||
public ILogHandler InnerLogHandler => m_innerHandle;
|
||||
|
||||
public void SetLabel(string label)
|
||||
{
|
||||
m_labelText = label;
|
||||
m_useLabel = label != null;
|
||||
}
|
||||
|
||||
public void ClearLabel()
|
||||
{
|
||||
m_labelText = null;
|
||||
m_useLabel = false;
|
||||
}
|
||||
|
||||
public LoggHandler(ILogHandler innerHandle)
|
||||
{
|
||||
m_innerHandle = innerHandle ?? throw new ArgumentNullException(nameof(innerHandle));
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Main/Scripts/LoggHandler.cs.meta
Normal file
3
Assets/Main/Scripts/LoggHandler.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f543cfba5cf04258b3ab59b75849e7a9
|
||||
timeCreated: 1715271314
|
||||
@ -2,6 +2,9 @@ using System;
|
||||
|
||||
namespace Ca2d.Toolkit
|
||||
{
|
||||
/// <summary>
|
||||
/// When Unity Requirements did not fit <see cref="Guard"/> wants, throw this.
|
||||
/// </summary>
|
||||
public class LoseRequirementException : Exception
|
||||
{
|
||||
public Type RequiredType { get; }
|
||||
|
||||
@ -11,8 +11,14 @@ namespace Ca2d.Toolkit
|
||||
[Serializable]
|
||||
public struct Option<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Is option set to fill.
|
||||
/// </summary>
|
||||
public bool Enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Value inside of option
|
||||
/// </summary>
|
||||
public T Value;
|
||||
|
||||
public T ValueOrDefault()
|
||||
|
||||
@ -15,16 +15,26 @@ namespace Ca2d.Toolkit
|
||||
/// <summary>
|
||||
/// Is this warp reference to a valid target?
|
||||
/// </summary>
|
||||
public bool Valid => m_referencedObject is T;
|
||||
public bool Is => m_referencedObject is T;
|
||||
|
||||
/// <summary>
|
||||
/// Trying to get the actual object of this reference.
|
||||
/// </summary>
|
||||
public T Object => m_referencedObject as T;
|
||||
public T As => m_referencedObject as T;
|
||||
|
||||
public static implicit operator T(UnityObjectWarp<T> wrapper)
|
||||
/// <summary>
|
||||
/// Is this warp reference to a valid target? If this is valid, give the casting result.
|
||||
/// </summary>
|
||||
public bool IsAs(out T val)
|
||||
{
|
||||
return wrapper.Object;
|
||||
if (m_referencedObject is T referenced)
|
||||
{
|
||||
val = referenced;
|
||||
return true;
|
||||
}
|
||||
|
||||
val = null;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user