修改合并
This commit is contained in:
parent
8f5a88e1f5
commit
8fe1167292
@ -2,11 +2,9 @@
|
|||||||
"name": "AlicizaX.Framework.Editor",
|
"name": "AlicizaX.Framework.Editor",
|
||||||
"rootNamespace": "AlicizaX.Framework.Editor",
|
"rootNamespace": "AlicizaX.Framework.Editor",
|
||||||
"references": [
|
"references": [
|
||||||
"GUID:acfef7cabed3b0a42b25edb1cd4fa259",
|
|
||||||
"GUID:1619e00706139ce488ff80c0daeea8e7",
|
"GUID:1619e00706139ce488ff80c0daeea8e7",
|
||||||
"GUID:e34a5702dd353724aa315fb8011f08c3",
|
"GUID:e34a5702dd353724aa315fb8011f08c3",
|
||||||
"GUID:4d1926c9df5b052469a1c63448b7609a",
|
"GUID:4d1926c9df5b052469a1c63448b7609a"
|
||||||
"GUID:75b6f2078d190f14dbda4a5b747d709c"
|
|
||||||
],
|
],
|
||||||
"includePlatforms": [
|
"includePlatforms": [
|
||||||
"Editor"
|
"Editor"
|
||||||
|
|||||||
3
Editor/Inspector.meta
Normal file
3
Editor/Inspector.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6a6566b690eb46c3acc8685a8ccabfeb
|
||||||
|
timeCreated: 1737362727
|
||||||
58
Editor/Inspector/GameFrameworkInspector.cs
Normal file
58
Editor/Inspector/GameFrameworkInspector.cs
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架 Inspector 抽象类。
|
||||||
|
/// </summary>
|
||||||
|
public abstract class GameFrameworkInspector : UnityEditor.Editor
|
||||||
|
{
|
||||||
|
protected const string NoneOptionName = "<None>";
|
||||||
|
private bool m_IsCompiling = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 绘制事件。
|
||||||
|
/// </summary>
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
if (m_IsCompiling && !EditorApplication.isCompiling)
|
||||||
|
{
|
||||||
|
m_IsCompiling = false;
|
||||||
|
OnCompileComplete();
|
||||||
|
}
|
||||||
|
else if (!m_IsCompiling && EditorApplication.isCompiling)
|
||||||
|
{
|
||||||
|
m_IsCompiling = true;
|
||||||
|
OnCompileStart();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编译开始事件。
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCompileStart()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 编译完成事件。
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnCompileComplete()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool IsPrefabInHierarchy(UnityEngine.Object obj)
|
||||||
|
{
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
return PrefabUtility.GetPrefabAssetType(obj) != PrefabAssetType.Regular;
|
||||||
|
#else
|
||||||
|
return PrefabUtility.GetPrefabType(obj) != PrefabType.Prefab;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Inspector/GameFrameworkInspector.cs.meta
Normal file
11
Editor/Inspector/GameFrameworkInspector.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b5bb373d9bcd4bd45861670fa5208e05
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
27
Editor/Inspector/InspectorEditor.cs
Normal file
27
Editor/Inspector/InspectorEditor.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
public class InspectorEditor<T> : UnityEditor.Editor where T : Object
|
||||||
|
{
|
||||||
|
public T Target { get; private set; }
|
||||||
|
public PropertyCollection Properties { get; private set; }
|
||||||
|
|
||||||
|
public virtual void OnEnable()
|
||||||
|
{
|
||||||
|
Target = target as T;
|
||||||
|
Properties = EditorDrawing.GetAllProperties(serializedObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
string name = Target.GetType().Name;
|
||||||
|
string spacedName = Regex.Replace(name, "(\\B[A-Z])", " $1");
|
||||||
|
EditorDrawing.DrawInspectorHeader(new GUIContent(spacedName), Target);
|
||||||
|
EditorGUILayout.Space();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Editor/Inspector/InspectorEditor.cs.meta
Normal file
3
Editor/Inspector/InspectorEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ecc870911d5f4da592d757183a315b49
|
||||||
|
timeCreated: 1758265131
|
||||||
150
Editor/Inspector/MemoryPoolComponentInspector.cs
Normal file
150
Editor/Inspector/MemoryPoolComponentInspector.cs
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
using AlicizaX;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(MemoryPoolSetting))]
|
||||||
|
internal sealed class MemoryPoolComponentInspector : GameFrameworkInspector
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, List<MemoryPoolInfo>> m_ReferencePoolInfos = new Dictionary<string, List<MemoryPoolInfo>>(StringComparer.Ordinal);
|
||||||
|
private readonly HashSet<string> m_OpenedItems = new HashSet<string>();
|
||||||
|
|
||||||
|
private SerializedProperty m_EnableStrictCheck = null;
|
||||||
|
|
||||||
|
private bool m_ShowFullClassName = false;
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
|
||||||
|
MemoryPoolSetting t = (MemoryPoolSetting)target;
|
||||||
|
|
||||||
|
if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject))
|
||||||
|
{
|
||||||
|
bool enableStrictCheck = EditorGUILayout.Toggle("Enable Strict Check", t.EnableStrictCheck);
|
||||||
|
if (enableStrictCheck != t.EnableStrictCheck)
|
||||||
|
{
|
||||||
|
t.EnableStrictCheck = enableStrictCheck;
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField("Reference Pool Count", MemoryPool.Count.ToString());
|
||||||
|
m_ShowFullClassName = EditorGUILayout.Toggle("Show Full Class Name", m_ShowFullClassName);
|
||||||
|
m_ReferencePoolInfos.Clear();
|
||||||
|
MemoryPoolInfo[] referencePoolInfos = MemoryPool.GetAllMemoryPoolInfos();
|
||||||
|
foreach (MemoryPoolInfo referencePoolInfo in referencePoolInfos)
|
||||||
|
{
|
||||||
|
string assemblyName = referencePoolInfo.Type.Assembly.GetName().Name;
|
||||||
|
List<MemoryPoolInfo> results = null;
|
||||||
|
if (!m_ReferencePoolInfos.TryGetValue(assemblyName, out results))
|
||||||
|
{
|
||||||
|
results = new List<MemoryPoolInfo>();
|
||||||
|
m_ReferencePoolInfos.Add(assemblyName, results);
|
||||||
|
}
|
||||||
|
|
||||||
|
results.Add(referencePoolInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (KeyValuePair<string, List<MemoryPoolInfo>> assemblyReferencePoolInfo in m_ReferencePoolInfos)
|
||||||
|
{
|
||||||
|
bool lastState = m_OpenedItems.Contains(assemblyReferencePoolInfo.Key);
|
||||||
|
bool currentState = EditorGUILayout.Foldout(lastState, assemblyReferencePoolInfo.Key);
|
||||||
|
if (currentState != lastState)
|
||||||
|
{
|
||||||
|
if (currentState)
|
||||||
|
{
|
||||||
|
m_OpenedItems.Add(assemblyReferencePoolInfo.Key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_OpenedItems.Remove(assemblyReferencePoolInfo.Key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentState)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginVertical("box");
|
||||||
|
{
|
||||||
|
var label = "Unused\tUsing.\tAcquire\tRelease\tAdd\tRemove";
|
||||||
|
EditorGUILayout.LabelField(m_ShowFullClassName ? "Full Class Name" : "Class Name", label);
|
||||||
|
assemblyReferencePoolInfo.Value.Sort(Comparison);
|
||||||
|
foreach (MemoryPoolInfo referencePoolInfo in assemblyReferencePoolInfo.Value)
|
||||||
|
{
|
||||||
|
DrawReferencePoolInfo(referencePoolInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Export CSV Data"))
|
||||||
|
{
|
||||||
|
string exportFileName = EditorUtility.SaveFilePanel("Export CSV Data", string.Empty, Utility.Text.Format("Reference Pool Data - {0}.csv", assemblyReferencePoolInfo.Key), string.Empty);
|
||||||
|
if (!string.IsNullOrEmpty(exportFileName))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
string[] data = new string[assemblyReferencePoolInfo.Value.Count + 1];
|
||||||
|
data[index++] = "Class Name,Full Class Name,Unused,Using,Acquire,Release,Add,Remove";
|
||||||
|
foreach (MemoryPoolInfo referencePoolInfo in assemblyReferencePoolInfo.Value)
|
||||||
|
{
|
||||||
|
data[index++] = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7}", referencePoolInfo.Type.Name, referencePoolInfo.Type.FullName, referencePoolInfo.UnusedMemoryCount, referencePoolInfo.UsingMemoryCount, referencePoolInfo.AcquireMemoryCount, referencePoolInfo.ReleaseMemoryCount, referencePoolInfo.AddMemoryCount, referencePoolInfo.RemoveMemoryCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllLines(exportFileName, data, Encoding.UTF8);
|
||||||
|
Debug.Log(Utility.Text.Format("Export reference pool CSV data to '{0}' success.", exportFileName));
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogError(Utility.Text.Format("Export reference pool CSV data to '{0}' failure, exception is '{1}'.", exportFileName, exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
EditorGUILayout.Separator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(m_EnableStrictCheck);
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
m_EnableStrictCheck = serializedObject.FindProperty("m_EnableStrictCheck");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawReferencePoolInfo(MemoryPoolInfo referencePoolInfo)
|
||||||
|
{
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
EditorGUILayout.LabelField(m_ShowFullClassName ? referencePoolInfo.Type.FullName : referencePoolInfo.Type.Name, Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}\t{4}\t{5}", referencePoolInfo.UnusedMemoryCount, referencePoolInfo.UsingMemoryCount, referencePoolInfo.AcquireMemoryCount, referencePoolInfo.ReleaseMemoryCount, referencePoolInfo.AddMemoryCount, referencePoolInfo.RemoveMemoryCount));
|
||||||
|
#else
|
||||||
|
EditorGUILayout.LabelField(m_ShowFullClassName ? referencePoolInfo.Type.FullName :
|
||||||
|
referencePoolInfo.Type.Name, Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}",referencePoolInfo.UnusedMemoryCount, referencePoolInfo.UsingMemoryCount, referencePoolInfo.AcquireMemoryCount, referencePoolInfo.ReleaseMemoryCount, referencePoolInfo.AddMemoryCount, referencePoolInfo.RemoveMemoryCount));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private int Comparison(MemoryPoolInfo a, MemoryPoolInfo b)
|
||||||
|
{
|
||||||
|
if (m_ShowFullClassName)
|
||||||
|
{
|
||||||
|
return a.Type.FullName.CompareTo(b.Type.FullName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return a.Type.Name.CompareTo(b.Type.Name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Inspector/MemoryPoolComponentInspector.cs.meta
Normal file
11
Editor/Inspector/MemoryPoolComponentInspector.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 705a7441224da3d4cbc6593bdc58f167
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
135
Editor/Inspector/RootModuleInspector.cs
Normal file
135
Editor/Inspector/RootModuleInspector.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using AlicizaX;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(RootModule))]
|
||||||
|
internal sealed class RootModuleInspector : GameFrameworkInspector
|
||||||
|
{
|
||||||
|
private static readonly float[] GameSpeed = new float[] { 0f, 0.01f, 0.1f, 0.25f, 0.5f, 1f, 1.5f, 2f, 4f, 8f };
|
||||||
|
private static readonly string[] GameSpeedForDisplay = new string[] { "0x", "0.01x", "0.1x", "0.25x", "0.5x", "1x", "1.5x", "2x", "4x", "8x" };
|
||||||
|
|
||||||
|
private SerializedProperty _frameRate = null;
|
||||||
|
private SerializedProperty _gameSpeed = null;
|
||||||
|
private SerializedProperty _runInBackground = null;
|
||||||
|
private SerializedProperty _neverSleep = null;
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
|
||||||
|
serializedObject.Update();
|
||||||
|
|
||||||
|
RootModule t = (RootModule)target;
|
||||||
|
|
||||||
|
|
||||||
|
EditorGUILayout.BeginVertical("box");
|
||||||
|
{
|
||||||
|
int frameRate = EditorGUILayout.IntSlider("Frame Rate", _frameRate.intValue, 1, 120);
|
||||||
|
if (frameRate != _frameRate.intValue)
|
||||||
|
{
|
||||||
|
if (EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
t.FrameRate = frameRate;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_frameRate.intValue = frameRate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
|
||||||
|
EditorGUILayout.BeginVertical("box");
|
||||||
|
{
|
||||||
|
float gameSpeed = EditorGUILayout.Slider("Game Speed", _gameSpeed.floatValue, 0f, 8f);
|
||||||
|
int selectedGameSpeed = GUILayout.SelectionGrid(GetSelectedGameSpeed(gameSpeed), GameSpeedForDisplay, 5);
|
||||||
|
if (selectedGameSpeed >= 0)
|
||||||
|
{
|
||||||
|
gameSpeed = GetGameSpeed(selectedGameSpeed);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Math.Abs(gameSpeed - _gameSpeed.floatValue) > 0.01f)
|
||||||
|
{
|
||||||
|
if (EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
t.GameSpeed = gameSpeed;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_gameSpeed.floatValue = gameSpeed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
bool runInBackground = EditorGUILayout.Toggle("Run in Background", _runInBackground.boolValue);
|
||||||
|
if (runInBackground != _runInBackground.boolValue)
|
||||||
|
{
|
||||||
|
if (EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
t.RunInBackground = runInBackground;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_runInBackground.boolValue = runInBackground;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool neverSleep = EditorGUILayout.Toggle("Never Sleep", _neverSleep.boolValue);
|
||||||
|
if (neverSleep != _neverSleep.boolValue)
|
||||||
|
{
|
||||||
|
if (EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
t.NeverSleep = neverSleep;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_neverSleep.boolValue = neverSleep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
_frameRate = serializedObject.FindProperty("frameRate");
|
||||||
|
_gameSpeed = serializedObject.FindProperty("gameSpeed");
|
||||||
|
_runInBackground = serializedObject.FindProperty("runInBackground");
|
||||||
|
_neverSleep = serializedObject.FindProperty("neverSleep");
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetGameSpeed(int selectedGameSpeed)
|
||||||
|
{
|
||||||
|
if (selectedGameSpeed < 0)
|
||||||
|
{
|
||||||
|
return GameSpeed[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectedGameSpeed >= GameSpeed.Length)
|
||||||
|
{
|
||||||
|
return GameSpeed[GameSpeed.Length - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
return GameSpeed[selectedGameSpeed];
|
||||||
|
}
|
||||||
|
|
||||||
|
private int GetSelectedGameSpeed(float gameSpeed)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < GameSpeed.Length; i++)
|
||||||
|
{
|
||||||
|
if (Mathf.Approximately(gameSpeed, GameSpeed[i]))
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Inspector/RootModuleInspector.cs.meta
Normal file
11
Editor/Inspector/RootModuleInspector.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 55195676d06c1cd418e6f3201eae7176
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
52
Editor/Localization/LocalizationComponentInspector.cs
Normal file
52
Editor/Localization/LocalizationComponentInspector.cs
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using AlicizaX.Editor;
|
||||||
|
using AlicizaX.Localization.Runtime;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace AlicizaX.Localization.Editor
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(LocalizationComponent))]
|
||||||
|
internal sealed class LocalizationComponentInspector : GameFrameworkInspector
|
||||||
|
{
|
||||||
|
private string[] _languageNames = new[] { "None" };
|
||||||
|
private SerializedProperty _language;
|
||||||
|
private int languageIndex = -1;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
_language = serializedObject.FindProperty("_language");
|
||||||
|
_languageNames = LocalizationConfiguration.Instance.LanguageTypeNames.ToArray();
|
||||||
|
var languageName = EditorPrefs.GetString(LocalizationComponent.PrefsKey, "None");
|
||||||
|
_language.stringValue = languageName;
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
languageIndex = _languageNames.ToList().FindIndex(t => t.Equals(languageName));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
serializedObject.Update();
|
||||||
|
LocalizationComponent t = (LocalizationComponent)target;
|
||||||
|
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
|
||||||
|
{
|
||||||
|
if (EditorApplication.isPlaying && IsPrefabInHierarchy(t.gameObject))
|
||||||
|
{
|
||||||
|
int index = UnityEditor.EditorPrefs.GetInt(LocalizationComponent.PrefsKey, 0);
|
||||||
|
int selectedIndex = EditorGUILayout.Popup("Language", index, _languageNames);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int selectedIndex = EditorGUILayout.Popup("Play Mode", languageIndex, _languageNames);
|
||||||
|
if (selectedIndex != languageIndex)
|
||||||
|
{
|
||||||
|
languageIndex = selectedIndex;
|
||||||
|
_language.stringValue = _languageNames[languageIndex];
|
||||||
|
EditorPrefs.SetString(LocalizationComponent.PrefsKey, _language.stringValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serializedObject.ApplyModifiedProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 93a2512d8bf54c0a8032fe6f4a7eb52b
|
||||||
|
timeCreated: 1760164418
|
||||||
3
Editor/Misc.meta
Normal file
3
Editor/Misc.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c6d5d730968b49849be897d89a8b9049
|
||||||
|
timeCreated: 1736410513
|
||||||
46
Editor/Misc/EventScriptingDefineSymbols.cs
Normal file
46
Editor/Misc/EventScriptingDefineSymbols.cs
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
using AlicizaX.Editor;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
internal static class EventScriptingDefineSymbols
|
||||||
|
{
|
||||||
|
private const string MenuPath = "Tools/AlicizaX/Event/Strict Check";
|
||||||
|
private const string DefineSymbol = "Event_StrictCheck";
|
||||||
|
|
||||||
|
[MenuItem(MenuPath)]
|
||||||
|
private static void ToggleStrictCheck()
|
||||||
|
{
|
||||||
|
bool enabled = IsEnabled();
|
||||||
|
SetEnabled(!enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
[MenuItem(MenuPath, true)]
|
||||||
|
private static bool ToggleStrictCheckValidate()
|
||||||
|
{
|
||||||
|
Menu.SetChecked(MenuPath, IsEnabled());
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool IsEnabled()
|
||||||
|
{
|
||||||
|
return ScriptingDefineSymbols.HasScriptingDefineSymbol(EditorUserBuildSettings.selectedBuildTargetGroup, DefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void SetEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
var targetGroup = EditorUserBuildSettings.selectedBuildTargetGroup;
|
||||||
|
if (enabled)
|
||||||
|
{
|
||||||
|
ScriptingDefineSymbols.AddScriptingDefineSymbol(targetGroup, DefineSymbol);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(targetGroup, DefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
Debug.Log($"[EventKit] Strict Check {(enabled ? "Enabled" : "Disabled")}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Editor/Misc/EventScriptingDefineSymbols.cs.meta
Normal file
3
Editor/Misc/EventScriptingDefineSymbols.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a0f666b24d9c41c4a355f9a9a643928b
|
||||||
|
timeCreated: 1756782190
|
||||||
172
Editor/Misc/LogScriptingDefineSymbols.cs
Normal file
172
Editor/Misc/LogScriptingDefineSymbols.cs
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
public static class LogScriptingDefineSymbols
|
||||||
|
{
|
||||||
|
private const string EnableLogScriptingDefineSymbol = "ENABLE_LOG";
|
||||||
|
private const string EnableDebugAndAboveLogScriptingDefineSymbol = "ENABLE_DEBUG_AND_ABOVE_LOG";
|
||||||
|
private const string EnableInfoAndAboveLogScriptingDefineSymbol = "ENABLE_INFO_AND_ABOVE_LOG";
|
||||||
|
private const string EnableWarningAndAboveLogScriptingDefineSymbol = "ENABLE_WARNING_AND_ABOVE_LOG";
|
||||||
|
private const string EnableErrorAndAboveLogScriptingDefineSymbol = "ENABLE_ERROR_AND_ABOVE_LOG";
|
||||||
|
private const string EnableFatalAndAboveLogScriptingDefineSymbol = "ENABLE_FATAL_AND_ABOVE_LOG";
|
||||||
|
private const string EnableDebugLogScriptingDefineSymbol = "ENABLE_DEBUG_LOG";
|
||||||
|
private const string EnableInfoLogScriptingDefineSymbol = "ENABLE_INFO_LOG";
|
||||||
|
private const string EnableWarningLogScriptingDefineSymbol = "ENABLE_WARNING_LOG";
|
||||||
|
private const string EnableErrorLogScriptingDefineSymbol = "ENABLE_ERROR_LOG";
|
||||||
|
private const string EnableFatalLogScriptingDefineSymbol = "ENABLE_FATAL_LOG";
|
||||||
|
|
||||||
|
private static readonly string[] AboveLogScriptingDefineSymbols = new string[]
|
||||||
|
{
|
||||||
|
EnableDebugAndAboveLogScriptingDefineSymbol,
|
||||||
|
EnableInfoAndAboveLogScriptingDefineSymbol,
|
||||||
|
EnableWarningAndAboveLogScriptingDefineSymbol,
|
||||||
|
EnableErrorAndAboveLogScriptingDefineSymbol,
|
||||||
|
EnableFatalAndAboveLogScriptingDefineSymbol
|
||||||
|
};
|
||||||
|
|
||||||
|
private static readonly string[] SpecifyLogScriptingDefineSymbols = new string[]
|
||||||
|
{
|
||||||
|
EnableDebugLogScriptingDefineSymbol,
|
||||||
|
EnableInfoLogScriptingDefineSymbol,
|
||||||
|
EnableWarningLogScriptingDefineSymbol,
|
||||||
|
EnableErrorLogScriptingDefineSymbol,
|
||||||
|
EnableFatalLogScriptingDefineSymbol
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 禁用所有日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Disable All Logs", false, 30)]
|
||||||
|
public static void DisableAllLogs()
|
||||||
|
{
|
||||||
|
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
|
||||||
|
|
||||||
|
foreach (string specifyLogScriptingDefineSymbol in SpecifyLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(specifyLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string aboveLogScriptingDefineSymbol in AboveLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启所有日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable All Logs", false, 31)]
|
||||||
|
public static void EnableAllLogs()
|
||||||
|
{
|
||||||
|
DisableAllLogs();
|
||||||
|
ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启调试及以上级别的日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable Debug And Above Logs", false, 32)]
|
||||||
|
public static void EnableDebugAndAboveLogs()
|
||||||
|
{
|
||||||
|
SetAboveLogScriptingDefineSymbol(EnableDebugAndAboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启信息及以上级别的日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable Info And Above Logs", false, 33)]
|
||||||
|
public static void EnableInfoAndAboveLogs()
|
||||||
|
{
|
||||||
|
SetAboveLogScriptingDefineSymbol(EnableInfoAndAboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启警告及以上级别的日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable Warning And Above Logs", false, 34)]
|
||||||
|
public static void EnableWarningAndAboveLogs()
|
||||||
|
{
|
||||||
|
SetAboveLogScriptingDefineSymbol(EnableWarningAndAboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启错误及以上级别的日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable Error And Above Logs", false, 35)]
|
||||||
|
public static void EnableErrorAndAboveLogs()
|
||||||
|
{
|
||||||
|
SetAboveLogScriptingDefineSymbol(EnableErrorAndAboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 开启严重错误及以上级别的日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Scripting Define Symbols/Enable Fatal And Above Logs", false, 36)]
|
||||||
|
public static void EnableFatalAndAboveLogs()
|
||||||
|
{
|
||||||
|
SetAboveLogScriptingDefineSymbol(EnableFatalAndAboveLogScriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="aboveLogScriptingDefineSymbol">要设置的日志脚本宏定义。</param>
|
||||||
|
public static void SetAboveLogScriptingDefineSymbol(string aboveLogScriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(aboveLogScriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string i in AboveLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
if (i == aboveLogScriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
DisableAllLogs();
|
||||||
|
ScriptingDefineSymbols.AddScriptingDefineSymbol(aboveLogScriptingDefineSymbol);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置日志脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="specifyLogScriptingDefineSymbols">要设置的日志脚本宏定义。</param>
|
||||||
|
public static void SetSpecifyLogScriptingDefineSymbols(string[] specifyLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
if (specifyLogScriptingDefineSymbols == null || specifyLogScriptingDefineSymbols.Length <= 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool removed = false;
|
||||||
|
foreach (string specifyLogScriptingDefineSymbol in specifyLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(specifyLogScriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string i in SpecifyLogScriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
if (i == specifyLogScriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (!removed)
|
||||||
|
{
|
||||||
|
removed = true;
|
||||||
|
DisableAllLogs();
|
||||||
|
}
|
||||||
|
|
||||||
|
ScriptingDefineSymbols.AddScriptingDefineSymbol(specifyLogScriptingDefineSymbol);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Misc/LogScriptingDefineSymbols.cs.meta
Normal file
11
Editor/Misc/LogScriptingDefineSymbols.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0b5eed5f56efa7e4cb245bee9b064c21
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
108
Editor/Misc/OpenAssetLogLine.cs
Normal file
108
Editor/Misc/OpenAssetLogLine.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using UnityEditor.Callbacks;
|
||||||
|
using UnityEditorInternal;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
public static class OpenAssetLogLine
|
||||||
|
{
|
||||||
|
[OnOpenAsset(0)]
|
||||||
|
private static bool OnOpenAsset(int instanceID, int line)
|
||||||
|
{
|
||||||
|
if (line <= 0)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// 获取资源路径
|
||||||
|
string assetPath = AssetDatabase.GetAssetPath(instanceID);
|
||||||
|
|
||||||
|
// 判断资源类型
|
||||||
|
if (!assetPath.EndsWith(".cs"))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool autoFirstMatch = assetPath.Contains("Log.cs");
|
||||||
|
|
||||||
|
var stackTrace = GetStackTrace();
|
||||||
|
if (!string.IsNullOrEmpty(stackTrace) && stackTrace.Contains("Log.cs"))
|
||||||
|
|
||||||
|
{
|
||||||
|
if (!autoFirstMatch)
|
||||||
|
{
|
||||||
|
var fullPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal));
|
||||||
|
fullPath = $"{fullPath}{assetPath}";
|
||||||
|
// 跳转到目标代码的特定行
|
||||||
|
InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 使用正则表达式匹配at的哪个脚本的哪一行
|
||||||
|
var matches = Regex.Match(stackTrace, @"\(at (.+)\)",
|
||||||
|
RegexOptions.IgnoreCase);
|
||||||
|
while (matches.Success)
|
||||||
|
{
|
||||||
|
var pathLine = matches.Groups[1].Value;
|
||||||
|
|
||||||
|
if (!pathLine.Contains("Log.cs"))
|
||||||
|
{
|
||||||
|
var splitIndex = pathLine.LastIndexOf(":", StringComparison.Ordinal);
|
||||||
|
// 脚本路径
|
||||||
|
var path = pathLine.Substring(0, splitIndex);
|
||||||
|
// 行号
|
||||||
|
line = Convert.ToInt32(pathLine.Substring(splitIndex + 1));
|
||||||
|
var fullPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("Assets", StringComparison.Ordinal));
|
||||||
|
fullPath = $"{fullPath}{path}";
|
||||||
|
// 跳转到目标代码的特定行
|
||||||
|
InternalEditorUtility.OpenFileAtLineExternal(fullPath.Replace('/', '\\'), line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches = matches.NextMatch();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前日志窗口选中的日志的堆栈信息。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>选中日志的堆栈信息实例。</returns>
|
||||||
|
private static string GetStackTrace()
|
||||||
|
{
|
||||||
|
// 通过反射获取ConsoleWindow类
|
||||||
|
var consoleWindowType = typeof(EditorWindow).Assembly.GetType("UnityEditor.ConsoleWindow");
|
||||||
|
// 获取窗口实例
|
||||||
|
var fieldInfo = consoleWindowType.GetField("ms_ConsoleWindow",
|
||||||
|
BindingFlags.Static |
|
||||||
|
BindingFlags.NonPublic);
|
||||||
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
|
var consoleInstance = fieldInfo.GetValue(null);
|
||||||
|
if (consoleInstance != null)
|
||||||
|
if (EditorWindow.focusedWindow == (EditorWindow)consoleInstance)
|
||||||
|
{
|
||||||
|
// 获取m_ActiveText成员
|
||||||
|
fieldInfo = consoleWindowType.GetField("m_ActiveText",
|
||||||
|
BindingFlags.Instance |
|
||||||
|
BindingFlags.NonPublic);
|
||||||
|
// 获取m_ActiveText的值
|
||||||
|
if (fieldInfo != null)
|
||||||
|
{
|
||||||
|
var activeText = fieldInfo.GetValue(consoleInstance).ToString();
|
||||||
|
return activeText;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Misc/OpenAssetLogLine.cs.meta
Normal file
11
Editor/Misc/OpenAssetLogLine.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bb8c486fbd51ec64fab3749895432f7d
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
84
Editor/Misc/OpenFolder.cs
Normal file
84
Editor/Misc/OpenFolder.cs
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
using AlicizaX;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 打开文件夹相关的实用函数。
|
||||||
|
/// </summary>
|
||||||
|
public static class OpenFolder
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 打开 Data Path 文件夹。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Open Folder/Data Path", false, 10)]
|
||||||
|
public static void OpenFolderDataPath()
|
||||||
|
{
|
||||||
|
Execute(Application.dataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开 Persistent Data Path 文件夹。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Open Folder/Persistent Data Path", false, 11)]
|
||||||
|
public static void OpenFolderPersistentDataPath()
|
||||||
|
{
|
||||||
|
Execute(Application.persistentDataPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开 Streaming Assets Path 文件夹。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Open Folder/Streaming Assets Path", false, 12)]
|
||||||
|
public static void OpenFolderStreamingAssetsPath()
|
||||||
|
{
|
||||||
|
Execute(Application.streamingAssetsPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开 Temporary Cache Path 文件夹。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Open Folder/Temporary Cache Path", false, 13)]
|
||||||
|
public static void OpenFolderTemporaryCachePath()
|
||||||
|
{
|
||||||
|
Execute(Application.temporaryCachePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_2018_3_OR_NEWER
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开 Console Log Path 文件夹。
|
||||||
|
/// </summary>
|
||||||
|
[MenuItem("Tools/AlicizaX/Open Folder/Console Log Path", false, 14)]
|
||||||
|
public static void OpenFolderConsoleLogPath()
|
||||||
|
{
|
||||||
|
Execute(System.IO.Path.GetDirectoryName(Application.consoleLogPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 打开指定路径的文件夹。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="folder">要打开的文件夹的路径。</param>
|
||||||
|
public static void Execute(string folder)
|
||||||
|
{
|
||||||
|
folder = Utility.Text.Format("\"{0}\"", folder);
|
||||||
|
switch (Application.platform)
|
||||||
|
{
|
||||||
|
case RuntimePlatform.WindowsEditor:
|
||||||
|
Process.Start("Explorer.exe", folder.Replace('/', '\\'));
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RuntimePlatform.OSXEditor:
|
||||||
|
Process.Start("open", folder);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("Not support open folder on '{0}' platform.", Application.platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Misc/OpenFolder.cs.meta
Normal file
11
Editor/Misc/OpenFolder.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 62e84f6e8237ea540b348d07a13891c7
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
98
Editor/Misc/ScriptableSingleton.cs
Normal file
98
Editor/Misc/ScriptableSingleton.cs
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using UnityEditorInternal;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor.Setting
|
||||||
|
{
|
||||||
|
public class ScriptableSingleton<T> : ScriptableObject where T : ScriptableObject
|
||||||
|
{
|
||||||
|
private static T s_Instance;
|
||||||
|
|
||||||
|
public static T Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
LoadOrCreate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T LoadOrCreate()
|
||||||
|
{
|
||||||
|
string filePath = GetFilePath();
|
||||||
|
if (!string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
var arr = InternalEditorUtility.LoadSerializedFileAndForget(filePath);
|
||||||
|
s_Instance = arr.Length > 0 ? arr[0] as T : s_Instance ?? CreateInstance<T>();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError($"save location of {nameof(ScriptableSingleton<T>)} is invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Save(bool saveAsText = true)
|
||||||
|
{
|
||||||
|
if (!s_Instance)
|
||||||
|
{
|
||||||
|
Debug.LogError("Cannot save ScriptableSingleton: no instance!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string filePath = GetFilePath();
|
||||||
|
if (!string.IsNullOrEmpty(filePath))
|
||||||
|
{
|
||||||
|
string directoryName = Path.GetDirectoryName(filePath);
|
||||||
|
if (!Directory.Exists(directoryName))
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(directoryName);
|
||||||
|
}
|
||||||
|
|
||||||
|
UnityEngine.Object[] obj = new T[1] { s_Instance };
|
||||||
|
InternalEditorUtility.SaveToSerializedFileAndForget(obj, filePath, saveAsText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static string GetFilePath()
|
||||||
|
{
|
||||||
|
return typeof(T).GetCustomAttributes(inherit: true)
|
||||||
|
.Where(v => v is FilePathAttribute)
|
||||||
|
.Cast<FilePathAttribute>()
|
||||||
|
.FirstOrDefault()
|
||||||
|
?.filepath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Class)]
|
||||||
|
public class FilePathAttribute : Attribute
|
||||||
|
{
|
||||||
|
internal string filepath;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 单例存放路径
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">相对 Project 路径</param>
|
||||||
|
public FilePathAttribute(string path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(path))
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Invalid relative path (it is empty)");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (path[0] == '/')
|
||||||
|
{
|
||||||
|
path = path.Substring(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
filepath = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Editor/Misc/ScriptableSingleton.cs.meta
Normal file
3
Editor/Misc/ScriptableSingleton.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9da8cbe84b4045d093d326334bbf4c7f
|
||||||
|
timeCreated: 1739529382
|
||||||
159
Editor/Misc/ScriptingDefineSymbols.cs
Normal file
159
Editor/Misc/ScriptingDefineSymbols.cs
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Build;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
public static class ScriptingDefineSymbols
|
||||||
|
{
|
||||||
|
private static readonly BuildTargetGroup[] BuildTargetGroups = new BuildTargetGroup[]
|
||||||
|
{
|
||||||
|
BuildTargetGroup.Standalone,
|
||||||
|
BuildTargetGroup.iOS,
|
||||||
|
BuildTargetGroup.Android,
|
||||||
|
BuildTargetGroup.WSA,
|
||||||
|
BuildTargetGroup.WebGL
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查指定平台是否存在指定的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildTargetGroup">要检查脚本宏定义的平台。</param>
|
||||||
|
/// <param name="scriptingDefineSymbol">要检查的脚本宏定义。</param>
|
||||||
|
/// <returns>指定平台是否存在指定的脚本宏定义。</returns>
|
||||||
|
public static bool HasScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] scriptingDefineSymbols = GetScriptingDefineSymbols(buildTargetGroup);
|
||||||
|
foreach (string i in scriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
if (i == scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为指定平台增加指定的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildTargetGroup">要增加脚本宏定义的平台。</param>
|
||||||
|
/// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
|
||||||
|
public static void AddScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup))
|
||||||
|
{
|
||||||
|
scriptingDefineSymbol
|
||||||
|
};
|
||||||
|
|
||||||
|
SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为指定平台移除指定的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildTargetGroup">要移除脚本宏定义的平台。</param>
|
||||||
|
/// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
|
||||||
|
public static void RemoveScriptingDefineSymbol(BuildTargetGroup buildTargetGroup, string scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!HasScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
List<string> scriptingDefineSymbols = new List<string>(GetScriptingDefineSymbols(buildTargetGroup));
|
||||||
|
while (scriptingDefineSymbols.Contains(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
scriptingDefineSymbols.Remove(scriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetScriptingDefineSymbols(buildTargetGroup, scriptingDefineSymbols.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为所有平台增加指定的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scriptingDefineSymbol">要增加的脚本宏定义。</param>
|
||||||
|
public static void AddScriptingDefineSymbol(string scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
|
||||||
|
{
|
||||||
|
AddScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 为所有平台移除指定的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scriptingDefineSymbol">要移除的脚本宏定义。</param>
|
||||||
|
public static void RemoveScriptingDefineSymbol(string scriptingDefineSymbol)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(scriptingDefineSymbol))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (BuildTargetGroup buildTargetGroup in BuildTargetGroups)
|
||||||
|
{
|
||||||
|
RemoveScriptingDefineSymbol(buildTargetGroup, scriptingDefineSymbol);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取指定平台的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildTargetGroup">要获取脚本宏定义的平台。</param>
|
||||||
|
/// <returns>平台的脚本宏定义。</returns>
|
||||||
|
public static string[] GetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup)
|
||||||
|
{
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
return PlayerSettings.GetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup)).Split(';');
|
||||||
|
#else
|
||||||
|
return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';');
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 设置指定平台的脚本宏定义。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buildTargetGroup">要设置脚本宏定义的平台。</param>
|
||||||
|
/// <param name="scriptingDefineSymbols">要设置的脚本宏定义。</param>
|
||||||
|
public static void SetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup, string[] scriptingDefineSymbols)
|
||||||
|
{
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
PlayerSettings.SetScriptingDefineSymbols(NamedBuildTarget.FromBuildTargetGroup(buildTargetGroup), string.Join(";", scriptingDefineSymbols));
|
||||||
|
#else
|
||||||
|
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", scriptingDefineSymbols));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Misc/ScriptingDefineSymbols.cs.meta
Normal file
11
Editor/Misc/ScriptingDefineSymbols.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 99eaa7f830bac2c469f9aab52406b8ed
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
71
Editor/Misc/TypeUtil.cs
Normal file
71
Editor/Misc/TypeUtil.cs
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using AlicizaX;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型相关的实用函数。
|
||||||
|
/// </summary>
|
||||||
|
public static class TypeUtil
|
||||||
|
{
|
||||||
|
private static readonly string[] RuntimeAssemblyNames = Utility.Assembly.GetAssemblies().Where(m => !m.FullName.Contains("Editor")).Select(m => m.FullName).ToArray();
|
||||||
|
|
||||||
|
private static readonly string[] RuntimeOrEditorAssemblyNames = Utility.Assembly.GetAssemblies().Select(m => m.FullName).ToArray();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在运行时程序集中获取指定基类的所有子类的名称。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeBase">基类类型。</param>
|
||||||
|
/// <returns>指定基类的所有子类的名称。</returns>
|
||||||
|
public static string[] GetRuntimeTypeNames(System.Type typeBase)
|
||||||
|
{
|
||||||
|
return GetTypeNames(typeBase, RuntimeAssemblyNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在运行时或编辑器程序集中获取指定基类的所有子类的名称。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="typeBase">基类类型。</param>
|
||||||
|
/// <returns>指定基类的所有子类的名称。</returns>
|
||||||
|
internal static string[] GetRuntimeOrEditorTypeNames(System.Type typeBase)
|
||||||
|
{
|
||||||
|
return GetTypeNames(typeBase, RuntimeOrEditorAssemblyNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string[] GetTypeNames(System.Type typeBase, string[] assemblyNames)
|
||||||
|
{
|
||||||
|
var typeNames = new List<string>();
|
||||||
|
foreach (var assemblyName in assemblyNames)
|
||||||
|
{
|
||||||
|
Assembly assembly = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
assembly = Assembly.Load(assemblyName);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (assembly == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = assembly.GetTypes();
|
||||||
|
foreach (var type in types)
|
||||||
|
{
|
||||||
|
if (type.IsClass && !type.IsAbstract && typeBase.IsAssignableFrom(type))
|
||||||
|
{
|
||||||
|
typeNames.Add(type.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typeNames.Sort();
|
||||||
|
return typeNames.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/Misc/TypeUtil.cs.meta
Normal file
11
Editor/Misc/TypeUtil.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 82f73088e6e538649abbb7e35e3d6bf5
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
8
Editor/ObjectPool.meta
Normal file
8
Editor/ObjectPool.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f8f1cd19221bf3c48b13c9b505adc436
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
141
Editor/ObjectPool/ObjectPoolComponentInspector.cs
Normal file
141
Editor/ObjectPool/ObjectPoolComponentInspector.cs
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
using AlicizaX;
|
||||||
|
using AlicizaX.ObjectPool;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Text;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
[CustomEditor(typeof(ObjectPoolComponent))]
|
||||||
|
internal sealed class ObjectPoolComponentInspector : GameFrameworkInspector
|
||||||
|
{
|
||||||
|
private readonly HashSet<string> m_OpenedItems = new HashSet<string>();
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
|
||||||
|
if (!EditorApplication.isPlaying)
|
||||||
|
{
|
||||||
|
EditorGUILayout.HelpBox("Available during runtime only.", MessageType.Info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ObjectPoolComponent t = (ObjectPoolComponent)target;
|
||||||
|
|
||||||
|
if (IsPrefabInHierarchy(t.gameObject))
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("Object Pool Count", t.Count.ToString());
|
||||||
|
|
||||||
|
ObjectPoolBase[] objectPools = t.GetAllObjectPools(true);
|
||||||
|
foreach (ObjectPoolBase objectPool in objectPools)
|
||||||
|
{
|
||||||
|
DrawObjectPool(objectPool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Repaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private void DrawObjectPool(ObjectPoolBase objectPool)
|
||||||
|
{
|
||||||
|
bool lastState = m_OpenedItems.Contains(objectPool.FullName);
|
||||||
|
bool currentState = EditorGUILayout.Foldout(lastState, objectPool.FullName);
|
||||||
|
if (currentState != lastState)
|
||||||
|
{
|
||||||
|
if (currentState)
|
||||||
|
{
|
||||||
|
m_OpenedItems.Add(objectPool.FullName);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_OpenedItems.Remove(objectPool.FullName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentState)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginVertical("box");
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("Name", objectPool.Name);
|
||||||
|
EditorGUILayout.LabelField("Type", objectPool.ObjectType.FullName);
|
||||||
|
EditorGUILayout.LabelField("Auto Release Interval", objectPool.AutoReleaseInterval.ToString());
|
||||||
|
EditorGUILayout.LabelField("Capacity", objectPool.Capacity.ToString());
|
||||||
|
EditorGUILayout.LabelField("Used Count", objectPool.Count.ToString());
|
||||||
|
EditorGUILayout.LabelField("Can Release Count", objectPool.CanReleaseCount.ToString());
|
||||||
|
EditorGUILayout.LabelField("Expire Time", objectPool.ExpireTime.ToString());
|
||||||
|
EditorGUILayout.LabelField("Priority", objectPool.Priority.ToString());
|
||||||
|
ObjectInfo[] objectInfos = objectPool.GetAllObjectInfos();
|
||||||
|
if (objectInfos.Length > 0)
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("Name", objectPool.AllowMultiSpawn ? "Locked\tCount\tFlag\tPriority\tLast Use Time" : "Locked\tIn Use\tFlag\tPriority\tLast Use Time");
|
||||||
|
foreach (ObjectInfo objectInfo in objectInfos)
|
||||||
|
{
|
||||||
|
#if UNITY_6000_0_OR_NEWER
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "<None>" : objectInfo.Name,
|
||||||
|
objectPool.AllowMultiSpawn
|
||||||
|
? Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}\t{4:yyyy-MM-dd HH:mm:ss,-12}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())
|
||||||
|
: Utility.Text.Format("{0,-12}\t{1,-12}\t{2,-12}\t{3,-12}\t{4:yyyy-MM-dd HH:mm:ss,-12}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()));
|
||||||
|
#else
|
||||||
|
EditorGUILayout.LabelField(string.IsNullOrEmpty(objectInfo.Name) ? "<None>" : objectInfo.Name,
|
||||||
|
objectPool.AllowMultiSpawn
|
||||||
|
? Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())
|
||||||
|
: Utility.Text.Format("{0}\t{1}\t{2}\t{3}\t{4:yyyy-MM-dd HH:mm:ss}", objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime()));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Release"))
|
||||||
|
{
|
||||||
|
objectPool.Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Release All Unused"))
|
||||||
|
{
|
||||||
|
objectPool.ReleaseAllUnused();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GUILayout.Button("Export CSV Data"))
|
||||||
|
{
|
||||||
|
string exportFileName = EditorUtility.SaveFilePanel("Export CSV Data", string.Empty, Utility.Text.Format("Object Pool Data - {0}.csv", objectPool.Name), string.Empty);
|
||||||
|
if (!string.IsNullOrEmpty(exportFileName))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
string[] data = new string[objectInfos.Length + 1];
|
||||||
|
data[index++] = Utility.Text.Format("Name,Locked,{0},Custom Can Release Flag,Priority,Last Use Time", objectPool.AllowMultiSpawn ? "Count" : "In Use");
|
||||||
|
foreach (ObjectInfo objectInfo in objectInfos)
|
||||||
|
{
|
||||||
|
data[index++] = objectPool.AllowMultiSpawn
|
||||||
|
? Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, objectInfo.SpawnCount, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime())
|
||||||
|
: Utility.Text.Format("{0},{1},{2},{3},{4},{5:yyyy-MM-dd HH:mm:ss}", objectInfo.Name, objectInfo.Locked, objectInfo.IsInUse, objectInfo.CustomCanReleaseFlag, objectInfo.Priority, objectInfo.LastUseTime.ToLocalTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
File.WriteAllLines(exportFileName, data, Encoding.UTF8);
|
||||||
|
Debug.Log(Utility.Text.Format("Export object pool CSV data to '{0}' success.", exportFileName));
|
||||||
|
}
|
||||||
|
catch (Exception exception)
|
||||||
|
{
|
||||||
|
Debug.LogError(Utility.Text.Format("Export object pool CSV data to '{0}' failure, exception is '{1}'.", exportFileName, exception));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
GUILayout.Label("Object Pool is Empty ...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
|
||||||
|
EditorGUILayout.Separator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Editor/ObjectPool/ObjectPoolComponentInspector.cs.meta
Normal file
11
Editor/ObjectPool/ObjectPoolComponentInspector.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eb0d4111d9ba0ad469b2361c7731666a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@ -18,6 +18,7 @@ namespace AlicizaX.Resource.Editor
|
|||||||
"HostPlayMode (联机运行模式)",
|
"HostPlayMode (联机运行模式)",
|
||||||
"WebPlayMode (WebGL运行模式)"
|
"WebPlayMode (WebGL运行模式)"
|
||||||
};
|
};
|
||||||
|
|
||||||
private SerializedProperty _milliseconds = null;
|
private SerializedProperty _milliseconds = null;
|
||||||
private SerializedProperty _minUnloadUnusedAssetsInterval = null;
|
private SerializedProperty _minUnloadUnusedAssetsInterval = null;
|
||||||
private SerializedProperty _maxUnloadUnusedAssetsInterval = null;
|
private SerializedProperty _maxUnloadUnusedAssetsInterval = null;
|
||||||
@ -30,6 +31,7 @@ namespace AlicizaX.Resource.Editor
|
|||||||
private SerializedProperty _failedTryAgain = null;
|
private SerializedProperty _failedTryAgain = null;
|
||||||
private SerializedProperty _packageName = null;
|
private SerializedProperty _packageName = null;
|
||||||
private SerializedProperty _decryptionServices = null;
|
private SerializedProperty _decryptionServices = null;
|
||||||
|
private SerializedProperty _playMode = null;
|
||||||
private int _packageNameIndex = 0;
|
private int _packageNameIndex = 0;
|
||||||
private string[] _packageNames;
|
private string[] _packageNames;
|
||||||
|
|
||||||
@ -37,6 +39,7 @@ namespace AlicizaX.Resource.Editor
|
|||||||
private int m_DecryptionSelectIndex;
|
private int m_DecryptionSelectIndex;
|
||||||
|
|
||||||
private int _playModeIndex = 0;
|
private int _playModeIndex = 0;
|
||||||
|
|
||||||
public override void OnInspectorGUI()
|
public override void OnInspectorGUI()
|
||||||
{
|
{
|
||||||
base.OnInspectorGUI();
|
base.OnInspectorGUI();
|
||||||
@ -58,6 +61,7 @@ namespace AlicizaX.Resource.Editor
|
|||||||
if (selectedIndex != _playModeIndex)
|
if (selectedIndex != _playModeIndex)
|
||||||
{
|
{
|
||||||
_playModeIndex = selectedIndex;
|
_playModeIndex = selectedIndex;
|
||||||
|
_playMode.enumValueIndex = _playModeIndex;
|
||||||
EditorPrefs.SetInt(ResourceComponent.PrefsKey, selectedIndex);
|
EditorPrefs.SetInt(ResourceComponent.PrefsKey, selectedIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -230,7 +234,6 @@ namespace AlicizaX.Resource.Editor
|
|||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
{
|
{
|
||||||
|
|
||||||
_milliseconds = serializedObject.FindProperty("milliseconds");
|
_milliseconds = serializedObject.FindProperty("milliseconds");
|
||||||
_minUnloadUnusedAssetsInterval = serializedObject.FindProperty("minUnloadUnusedAssetsInterval");
|
_minUnloadUnusedAssetsInterval = serializedObject.FindProperty("minUnloadUnusedAssetsInterval");
|
||||||
_maxUnloadUnusedAssetsInterval = serializedObject.FindProperty("maxUnloadUnusedAssetsInterval");
|
_maxUnloadUnusedAssetsInterval = serializedObject.FindProperty("maxUnloadUnusedAssetsInterval");
|
||||||
@ -243,8 +246,11 @@ namespace AlicizaX.Resource.Editor
|
|||||||
_failedTryAgain = serializedObject.FindProperty("failedTryAgain");
|
_failedTryAgain = serializedObject.FindProperty("failedTryAgain");
|
||||||
_packageName = serializedObject.FindProperty("packageName");
|
_packageName = serializedObject.FindProperty("packageName");
|
||||||
_decryptionServices = serializedObject.FindProperty("_decryptionServices");
|
_decryptionServices = serializedObject.FindProperty("_decryptionServices");
|
||||||
|
_playMode = serializedObject.FindProperty("_playMode");
|
||||||
RefreshDecryptionServices();
|
RefreshDecryptionServices();
|
||||||
RefreshTypeNames();
|
RefreshTypeNames();
|
||||||
|
_playModeIndex = EditorPrefs.GetInt(ResourceComponent.PrefsKey, 0);
|
||||||
|
_playMode.enumValueIndex = _playModeIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
3
Editor/Utility.meta
Normal file
3
Editor/Utility.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 3a0cecfd631d46f09c53e7e2374100d0
|
||||||
|
timeCreated: 1758265178
|
||||||
1866
Editor/Utility/EditorDrawing.cs
Normal file
1866
Editor/Utility/EditorDrawing.cs
Normal file
File diff suppressed because it is too large
Load Diff
3
Editor/Utility/EditorDrawing.cs.meta
Normal file
3
Editor/Utility/EditorDrawing.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: cb3982e0339e441fbb4134b5be9094f0
|
||||||
|
timeCreated: 1758265207
|
||||||
519
Editor/Utility/EditorUtils.cs
Normal file
519
Editor/Utility/EditorUtils.cs
Normal file
@ -0,0 +1,519 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
public static class EditorUtils
|
||||||
|
{
|
||||||
|
public static class Styles
|
||||||
|
{
|
||||||
|
public static GUIStyle IconButton => GUI.skin.FindStyle("IconButton");
|
||||||
|
public static readonly GUIContent PlusIcon = EditorGUIUtility.TrIconContent("Toolbar Plus", "Add Item");
|
||||||
|
public static readonly GUIContent MinusIcon = EditorGUIUtility.TrIconContent("Toolbar Minus", "Remove Item");
|
||||||
|
public static readonly GUIContent TrashIcon = EditorGUIUtility.TrIconContent("TreeEditor.Trash", "Remove Item");
|
||||||
|
public static readonly GUIContent RefreshIcon = EditorGUIUtility.TrIconContent("Refresh", "Refresh");
|
||||||
|
public static readonly GUIContent Linked = EditorGUIUtility.TrIconContent("Linked");
|
||||||
|
public static readonly GUIContent UnLinked = EditorGUIUtility.TrIconContent("Unlinked");
|
||||||
|
public static readonly GUIContent Database = EditorGUIUtility.TrIconContent("Package Manager");
|
||||||
|
public static readonly GUIContent GreenLight = EditorGUIUtility.TrIconContent("greenLight");
|
||||||
|
public static readonly GUIContent OrangeLight = EditorGUIUtility.TrIconContent("orangeLight");
|
||||||
|
public static readonly GUIContent RedLight = EditorGUIUtility.TrIconContent("redLight");
|
||||||
|
|
||||||
|
public static GUIStyle RichLabel => new GUIStyle(EditorStyles.label)
|
||||||
|
{
|
||||||
|
richText = true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class BoxGroupScope : GUI.Scope
|
||||||
|
{
|
||||||
|
public BoxGroupScope(string icon, string title, float height = 22)
|
||||||
|
{
|
||||||
|
GUIContent iconTitle = EditorGUIUtility.TrTextContentWithIcon(" " + title, icon);
|
||||||
|
EditorGUILayout.BeginVertical(GUI.skin.box);
|
||||||
|
|
||||||
|
Rect headerRect = GUILayoutUtility.GetRect(1, height);
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
headerRect.x += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
EditorGUI.LabelField(headerRect, iconTitle, EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
public BoxGroupScope(string title, float height = 22)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginVertical(GUI.skin.box);
|
||||||
|
|
||||||
|
Rect headerRect = GUILayoutUtility.GetRect(1, height);
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
headerRect.x += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
EditorGUI.LabelField(headerRect, title, EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
EditorGUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void CloseScope()
|
||||||
|
{
|
||||||
|
EditorGUILayout.EndVertical();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public struct PopupArray
|
||||||
|
{
|
||||||
|
public List<string> contents;
|
||||||
|
public List<string> selected;
|
||||||
|
|
||||||
|
public PopupArray(string[] contents, string[] selected)
|
||||||
|
{
|
||||||
|
this.contents = new List<string>(contents);
|
||||||
|
this.selected = new List<string>(selected);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PopupElement
|
||||||
|
{
|
||||||
|
public Action<string[]> onSelect;
|
||||||
|
public PopupArray popupArray;
|
||||||
|
public string name;
|
||||||
|
|
||||||
|
public PopupElement(PopupArray popupArray, string name, Action<string[]> onSelect)
|
||||||
|
{
|
||||||
|
this.popupArray = popupArray;
|
||||||
|
this.name = name;
|
||||||
|
this.onSelect = onSelect;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawOutline(Rect rect, RectOffset border)
|
||||||
|
{
|
||||||
|
Color color = new Color(0.6f, 0.6f, 0.6f, 1.333f);
|
||||||
|
if (EditorGUIUtility.isProSkin)
|
||||||
|
{
|
||||||
|
color.r = 0.12f;
|
||||||
|
color.g = 0.12f;
|
||||||
|
color.b = 0.12f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Event.current.type != EventType.Repaint)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Color orgColor = GUI.color;
|
||||||
|
GUI.color *= color;
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, border.top), EditorGUIUtility.whiteTexture); //top
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.yMax - border.bottom, rect.width, border.bottom), EditorGUIUtility.whiteTexture); //bottom
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.y + 1, border.left, rect.height - 2 * border.left), EditorGUIUtility.whiteTexture); //left
|
||||||
|
GUI.DrawTexture(new Rect(rect.xMax - border.right, rect.y + 1, border.right, rect.height - 2 * border.right), EditorGUIUtility.whiteTexture); //right
|
||||||
|
|
||||||
|
GUI.color = orgColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawOutline(Rect rect, RectOffset border, Color color)
|
||||||
|
{
|
||||||
|
if (Event.current.type != EventType.Repaint)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Color orgColor = GUI.color;
|
||||||
|
GUI.color *= color;
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, border.top), EditorGUIUtility.whiteTexture); //top
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.yMax - border.bottom, rect.width, border.bottom), EditorGUIUtility.whiteTexture); //bottom
|
||||||
|
GUI.DrawTexture(new Rect(rect.x, rect.y + 1, border.left, rect.height - 2 * border.left), EditorGUIUtility.whiteTexture); //left
|
||||||
|
GUI.DrawTexture(new Rect(rect.xMax - border.right, rect.y + 1, border.right, rect.height - 2 * border.right), EditorGUIUtility.whiteTexture); //right
|
||||||
|
|
||||||
|
GUI.color = orgColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rect DrawHeader(float height, string title)
|
||||||
|
{
|
||||||
|
Rect rect = GUILayoutUtility.GetRect(0, height);
|
||||||
|
EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
var labelRect = rect;
|
||||||
|
labelRect.x += 3f;
|
||||||
|
|
||||||
|
EditorGUI.LabelField(labelRect, title, EditorStyles.boldLabel);
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawHeader(Rect rect, string title, float labelX, float labelY, GUIStyle labelStyle)
|
||||||
|
{
|
||||||
|
EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
var labelRect = rect;
|
||||||
|
labelRect.x += labelX;
|
||||||
|
labelRect.y += labelY;
|
||||||
|
|
||||||
|
EditorGUI.LabelField(labelRect, title, labelStyle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rect DrawHeaderWithBorder(GUIContent title, float height, ref Rect rect, bool rounded)
|
||||||
|
{
|
||||||
|
GUI.Box(rect, GUIContent.none, new GUIStyle(rounded ? "HelpBox" : "Tooltip"));
|
||||||
|
|
||||||
|
Rect headerRect = rect;
|
||||||
|
headerRect.height = height;
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
Rect labelRect = headerRect;
|
||||||
|
labelRect.y += height / 2;
|
||||||
|
EditorGUI.LabelField(labelRect, title, EditorStyles.miniBoldLabel);
|
||||||
|
|
||||||
|
rect.x += 1;
|
||||||
|
rect.y += 1;
|
||||||
|
rect.height -= 1;
|
||||||
|
rect.width -= 2;
|
||||||
|
rect.y += height;
|
||||||
|
rect.height -= height;
|
||||||
|
return rect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rect DrawHeaderWithBorder(GUIContent title, float height, ref Rect rect, GUIStyle boxStyle)
|
||||||
|
{
|
||||||
|
GUI.Box(rect, GUIContent.none, boxStyle);
|
||||||
|
rect.x += 1;
|
||||||
|
rect.y += 1;
|
||||||
|
rect.height -= 1;
|
||||||
|
rect.width -= 2;
|
||||||
|
|
||||||
|
var headerRect = rect;
|
||||||
|
headerRect.height = height + EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
|
||||||
|
rect.y += headerRect.height;
|
||||||
|
rect.height -= headerRect.height;
|
||||||
|
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
var labelRect = headerRect;
|
||||||
|
labelRect.y += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
labelRect.x += 2f;
|
||||||
|
|
||||||
|
EditorGUI.LabelField(labelRect, title, EditorStyles.miniBoldLabel);
|
||||||
|
|
||||||
|
return headerRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Rect DrawHeaderWithBorder(GUIContent title, float height, ref Rect rect, RectOffset border)
|
||||||
|
{
|
||||||
|
DrawOutline(rect, border);
|
||||||
|
rect.x += 1;
|
||||||
|
rect.y += 1;
|
||||||
|
rect.height -= 1;
|
||||||
|
rect.width -= 2;
|
||||||
|
|
||||||
|
var headerRect = rect;
|
||||||
|
headerRect.height = height + EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
|
||||||
|
rect.y += headerRect.height;
|
||||||
|
rect.height -= headerRect.height;
|
||||||
|
|
||||||
|
EditorGUI.DrawRect(headerRect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
var labelRect = headerRect;
|
||||||
|
labelRect.y += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
labelRect.x += 2f;
|
||||||
|
|
||||||
|
EditorGUI.LabelField(labelRect, title, EditorStyles.miniBoldLabel);
|
||||||
|
|
||||||
|
return headerRect;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawBoxFoldoutHeader(string title, bool state, float height = 22)
|
||||||
|
{
|
||||||
|
Rect rect = GUILayoutUtility.GetRect(1, height);
|
||||||
|
EditorGUI.DrawRect(rect, new Color(0.1f, 0.1f, 0.1f, 0.4f));
|
||||||
|
|
||||||
|
rect.x += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
Rect foldoutRect = EditorGUI.IndentedRect(rect);
|
||||||
|
state = GUI.Toggle(foldoutRect, state, GUIContent.none, EditorStyles.foldout);
|
||||||
|
|
||||||
|
rect.x += EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing * 2;
|
||||||
|
EditorGUI.LabelField(rect, new GUIContent(title), EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool DrawFoldoutHeader(float height, string title, bool state)
|
||||||
|
{
|
||||||
|
Rect rect = GUILayoutUtility.GetRect(1, height);
|
||||||
|
|
||||||
|
rect.x += EditorGUIUtility.standardVerticalSpacing;
|
||||||
|
Rect foldoutRect = EditorGUI.IndentedRect(rect);
|
||||||
|
state = GUI.Toggle(foldoutRect, state, GUIContent.none, EditorStyles.foldout);
|
||||||
|
|
||||||
|
rect.x += EditorGUIUtility.singleLineHeight - EditorGUIUtility.standardVerticalSpacing * 2;
|
||||||
|
EditorGUI.LabelField(rect, new GUIContent(title), EditorStyles.boldLabel);
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawFoldoutToggleHeader(Rect rect, string title, ref bool isExpanded, ref bool isEnabled, bool showFoldout = true, bool toggleDisable = false)
|
||||||
|
{
|
||||||
|
Color headerColor = new Color(0.1f, 0.1f, 0.1f, 0f);
|
||||||
|
|
||||||
|
var expandRect = rect;
|
||||||
|
expandRect.xMin += EditorGUIUtility.singleLineHeight * 2;
|
||||||
|
|
||||||
|
var foldoutRect = rect;
|
||||||
|
foldoutRect.width = EditorGUIUtility.singleLineHeight;
|
||||||
|
|
||||||
|
var toggleRect = rect;
|
||||||
|
toggleRect.width = EditorGUIUtility.singleLineHeight;
|
||||||
|
toggleRect.x += EditorGUIUtility.singleLineHeight;
|
||||||
|
|
||||||
|
var labelRect = rect;
|
||||||
|
labelRect.xMin += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing * 2;
|
||||||
|
|
||||||
|
if (showFoldout)
|
||||||
|
{
|
||||||
|
// events
|
||||||
|
var e = Event.current;
|
||||||
|
if (expandRect.Contains(e.mousePosition))
|
||||||
|
{
|
||||||
|
if (e.type == EventType.MouseDown && e.button == 0)
|
||||||
|
{
|
||||||
|
isExpanded = !isExpanded;
|
||||||
|
e.Use();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// foldout
|
||||||
|
isExpanded = GUI.Toggle(foldoutRect, isExpanded, GUIContent.none, EditorStyles.foldout);
|
||||||
|
}
|
||||||
|
|
||||||
|
// background
|
||||||
|
EditorGUI.DrawRect(rect, headerColor);
|
||||||
|
|
||||||
|
// toggle
|
||||||
|
using (new EditorGUI.DisabledGroupScope(toggleDisable))
|
||||||
|
{
|
||||||
|
isEnabled = GUI.Toggle(toggleRect, isEnabled, new GUIContent("", "Extension Enabled State"), EditorStyles.toggle);
|
||||||
|
}
|
||||||
|
|
||||||
|
// title
|
||||||
|
EditorGUI.LabelField(labelRect, new GUIContent(title), EditorStyles.boldLabel);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void PopupSelect(object data)
|
||||||
|
{
|
||||||
|
PopupElement element = (PopupElement)data;
|
||||||
|
PopupArray array = element.popupArray;
|
||||||
|
string name = element.name;
|
||||||
|
|
||||||
|
if (array.selected.Contains(name))
|
||||||
|
array.selected.Remove(name);
|
||||||
|
else array.selected.Add(name);
|
||||||
|
|
||||||
|
element.onSelect?.Invoke(array.selected.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawMultiSelectionPopup(Rect rect, string title, PopupArray popupArray, Action<string[]> onSelect)
|
||||||
|
{
|
||||||
|
GenericMenu menu = new GenericMenu();
|
||||||
|
|
||||||
|
for (int i = 0; i < popupArray.contents.Count; i++)
|
||||||
|
{
|
||||||
|
string name = popupArray.contents[i];
|
||||||
|
bool on = popupArray.selected.Contains(name);
|
||||||
|
|
||||||
|
PopupElement element = new PopupElement(popupArray, name, onSelect);
|
||||||
|
menu.AddItem(new GUIContent(name), on, PopupSelect, element);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(GUI.Button(rect, title, EditorStyles.popup))
|
||||||
|
{
|
||||||
|
menu.ShowAsContext();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawRelativeProperties(SerializedProperty root, float width)
|
||||||
|
{
|
||||||
|
var childrens = root.GetVisibleChildrens();
|
||||||
|
|
||||||
|
foreach (var childProperty in childrens)
|
||||||
|
{
|
||||||
|
float height = EditorGUI.GetPropertyHeight(childProperty, true);
|
||||||
|
|
||||||
|
Rect rect = GUILayoutUtility.GetRect(1f, height);
|
||||||
|
rect.xMin += width;
|
||||||
|
EditorGUI.PropertyField(rect, childProperty, true);
|
||||||
|
EditorGUILayout.Space(EditorGUIUtility.standardVerticalSpacing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<SerializedProperty> GetVisibleChildrens(this SerializedProperty serializedProperty)
|
||||||
|
{
|
||||||
|
SerializedProperty currentProperty = serializedProperty.Copy();
|
||||||
|
SerializedProperty nextSiblingProperty = serializedProperty.Copy();
|
||||||
|
{
|
||||||
|
nextSiblingProperty.NextVisible(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentProperty.NextVisible(true))
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (SerializedProperty.EqualContents(currentProperty, nextSiblingProperty))
|
||||||
|
break;
|
||||||
|
|
||||||
|
yield return currentProperty;
|
||||||
|
}
|
||||||
|
while (currentProperty.NextVisible(false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrHelpIconText(string message, string icon, bool rich = false)
|
||||||
|
{
|
||||||
|
GUIStyle style = new GUIStyle(EditorStyles.helpBox)
|
||||||
|
{
|
||||||
|
richText = rich
|
||||||
|
};
|
||||||
|
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(" " + message, icon), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrHelpIconText(Rect rect, string message, string icon, bool rich = false)
|
||||||
|
{
|
||||||
|
GUIStyle style = new GUIStyle(EditorStyles.helpBox)
|
||||||
|
{
|
||||||
|
richText = rich
|
||||||
|
};
|
||||||
|
|
||||||
|
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(" " + message, icon), style);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrHelpIconText(string message, MessageType messageType, bool rich = false, bool space = true)
|
||||||
|
{
|
||||||
|
string icon = string.Empty;
|
||||||
|
|
||||||
|
GUIStyle style = new GUIStyle(EditorStyles.helpBox)
|
||||||
|
{
|
||||||
|
richText = rich
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Info:
|
||||||
|
icon = "console.infoicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Warning:
|
||||||
|
icon = "console.warnicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Error:
|
||||||
|
icon = "console.erroricon.sml";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(icon))
|
||||||
|
{
|
||||||
|
string text = space ? " " + message : message;
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(text, icon), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContent(message), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrHelpIconText(Rect rect, string message, MessageType messageType, bool rich = false, bool space = true)
|
||||||
|
{
|
||||||
|
string icon = string.Empty;
|
||||||
|
|
||||||
|
GUIStyle style = new GUIStyle(EditorStyles.helpBox)
|
||||||
|
{
|
||||||
|
richText = rich
|
||||||
|
};
|
||||||
|
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Info:
|
||||||
|
icon = "console.infoicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Warning:
|
||||||
|
icon = "console.warnicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Error:
|
||||||
|
icon = "console.erroricon.sml";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(icon))
|
||||||
|
{
|
||||||
|
string text = space ? " " + message : message;
|
||||||
|
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(text, icon), style);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContent(message), style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrIconText(string message, string icon, GUIStyle style, bool rich = false, bool space = true)
|
||||||
|
{
|
||||||
|
style.richText = rich;
|
||||||
|
string text = space ? " " + message : message;
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(text, icon), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrIconText(string message, MessageType messageType, GUIStyle style, bool rich = false, bool space = true)
|
||||||
|
{
|
||||||
|
string icon = string.Empty;
|
||||||
|
style.richText = rich;
|
||||||
|
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Info:
|
||||||
|
icon = "console.infoicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Warning:
|
||||||
|
icon = "console.warnicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Error:
|
||||||
|
icon = "console.erroricon.sml";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(icon))
|
||||||
|
{
|
||||||
|
string text = space ? " " + message : message;
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(text, icon), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField(GUIContent.none, EditorGUIUtility.TrTextContent(message), style, new GUILayoutOption[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void TrIconText(Rect rect, string message, MessageType messageType, GUIStyle style, bool rich = false, bool space = true)
|
||||||
|
{
|
||||||
|
string icon = string.Empty;
|
||||||
|
style.richText = rich;
|
||||||
|
|
||||||
|
switch (messageType)
|
||||||
|
{
|
||||||
|
case MessageType.Info:
|
||||||
|
icon = "console.infoicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Warning:
|
||||||
|
icon = "console.warnicon.sml";
|
||||||
|
break;
|
||||||
|
case MessageType.Error:
|
||||||
|
icon = "console.erroricon.sml";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!string.IsNullOrEmpty(icon))
|
||||||
|
{
|
||||||
|
string text = space ? " " + message : message;
|
||||||
|
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContentWithIcon(text, icon), style);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContent(message), style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Editor/Utility/EditorUtils.cs.meta
Normal file
3
Editor/Utility/EditorUtils.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b87483fd614d43e781d70a25494f0616
|
||||||
|
timeCreated: 1758265230
|
||||||
207
Editor/Utility/PropertyCollection.cs
Normal file
207
Editor/Utility/PropertyCollection.cs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using UnityEditor;
|
||||||
|
using System.Linq;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AlicizaX.Editor
|
||||||
|
{
|
||||||
|
public class PropertyCollection : Dictionary<string, SerializedProperty>
|
||||||
|
{
|
||||||
|
public SerializedProperty GetRelative(string propertyPath)
|
||||||
|
{
|
||||||
|
string[] paths = propertyPath.Split(new char[] { '.' });
|
||||||
|
if (TryGetValue(paths[0], out SerializedProperty pathProperty))
|
||||||
|
{
|
||||||
|
for (int i = 1; i < paths.Length; i++)
|
||||||
|
{
|
||||||
|
pathProperty = pathProperty.FindPropertyRelative(paths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return pathProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawRelative(string propertyPath)
|
||||||
|
{
|
||||||
|
string[] paths = propertyPath.Split(new char[] { '.' });
|
||||||
|
if (TryGetValue(paths[0], out SerializedProperty pathProperty))
|
||||||
|
{
|
||||||
|
for (int i = 1; i < paths.Length; i++)
|
||||||
|
{
|
||||||
|
pathProperty = pathProperty.FindPropertyRelative(paths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(pathProperty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawRelative(string propertyPath, GUIContent label)
|
||||||
|
{
|
||||||
|
string[] paths = propertyPath.Split(new char[] { '.' });
|
||||||
|
if (TryGetValue(paths[0], out SerializedProperty pathProperty))
|
||||||
|
{
|
||||||
|
for (int i = 1; i < paths.Length; i++)
|
||||||
|
{
|
||||||
|
pathProperty = pathProperty.FindPropertyRelative(paths[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.PropertyField(pathProperty, label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(string propertyName, int indent = 0)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
{
|
||||||
|
if (indent > 0) EditorGUI.indentLevel += indent;
|
||||||
|
EditorGUILayout.PropertyField(property);
|
||||||
|
if (indent > 0) EditorGUI.indentLevel -= indent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawBacking(string propertyName)
|
||||||
|
{
|
||||||
|
propertyName = $"<{propertyName}>k__BackingField";
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUILayout.PropertyField(property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DrawGetBool(string propertyName)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(property);
|
||||||
|
return property.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DrawToggleLeft(string propertyName)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
{
|
||||||
|
GUIContent label = new(property.displayName, property.tooltip);
|
||||||
|
return property.boolValue = EditorGUILayout.ToggleLeft(label, property.boolValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawAll(bool indentDropdowns = false, int skip = 0)
|
||||||
|
{
|
||||||
|
foreach (var property in this.Skip(skip))
|
||||||
|
{
|
||||||
|
bool shouldIndent = property.Value.propertyType == SerializedPropertyType.Generic;
|
||||||
|
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel++;
|
||||||
|
EditorGUILayout.PropertyField(property.Value);
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawAllExcept(bool indentDropdowns = false, int skip = 0, params string[] except)
|
||||||
|
{
|
||||||
|
foreach (var property in this.Skip(skip))
|
||||||
|
{
|
||||||
|
if (except.Contains(property.Key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool shouldIndent = property.Value.propertyType == SerializedPropertyType.Generic;
|
||||||
|
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel++;
|
||||||
|
EditorGUILayout.PropertyField(property.Value);
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawAllPredicate(bool indentDropdowns, int skip, Predicate<string> predicate)
|
||||||
|
{
|
||||||
|
foreach (var property in this.Skip(skip))
|
||||||
|
{
|
||||||
|
if (!predicate(property.Key))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
bool shouldIndent = property.Value.propertyType == SerializedPropertyType.Generic;
|
||||||
|
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel++;
|
||||||
|
EditorGUILayout.PropertyField(property.Value);
|
||||||
|
if (indentDropdowns && shouldIndent) EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool BoolValue(string propertyName)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
return property.boolValue;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DrawArray(string propertyName)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
{
|
||||||
|
if (property.isArray) EditorGUI.indentLevel++;
|
||||||
|
EditorGUILayout.PropertyField(property);
|
||||||
|
if (property.isArray) EditorGUI.indentLevel--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(string propertyName, bool includeChildren)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUILayout.PropertyField(property, includeChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(string propertyName, GUIContent label)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUILayout.PropertyField(property, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool DrawGetBool(string propertyName, GUIContent label)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(property, label);
|
||||||
|
return property.boolValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(string propertyName, GUIContent label, bool includeChildren)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUILayout.PropertyField(property, label, includeChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Rect rect, string propertyName)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUI.PropertyField(rect, property);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Rect rect, string propertyName, bool includeChildren)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUI.PropertyField(rect, property, includeChildren);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Rect rect, string propertyName, GUIContent label)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUI.PropertyField(rect, property, label);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Draw(Rect rect, string propertyName, GUIContent label, bool includeChildren)
|
||||||
|
{
|
||||||
|
if (TryGetValue(propertyName, out SerializedProperty property))
|
||||||
|
EditorGUI.PropertyField(rect, property, label, includeChildren);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Editor/Utility/PropertyCollection.cs.meta
Normal file
3
Editor/Utility/PropertyCollection.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: c59762160e44443096c548c7ea024d00
|
||||||
|
timeCreated: 1758265184
|
||||||
BIN
Plugins/EventSourceGenerator.dll
Normal file
BIN
Plugins/EventSourceGenerator.dll
Normal file
Binary file not shown.
52
Plugins/EventSourceGenerator.dll.meta
Normal file
52
Plugins/EventSourceGenerator.dll.meta
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e0f9fe588fe13b14ca28cddf735a2f0b
|
||||||
|
labels:
|
||||||
|
- RoslynAnalyzer
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 3
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 1
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
Any:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
Exclude Editor: 1
|
||||||
|
Exclude Linux64: 0
|
||||||
|
Exclude OSXUniversal: 0
|
||||||
|
Exclude Win: 0
|
||||||
|
Exclude Win64: 0
|
||||||
|
Editor:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
Linux64:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
OSXUniversal:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
Win:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
Win64:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
WindowsStoreApps:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Plugins/ICSharpCode.SharpZipLib.dll
Normal file
BIN
Plugins/ICSharpCode.SharpZipLib.dll
Normal file
Binary file not shown.
83
Plugins/ICSharpCode.SharpZipLib.dll.meta
Normal file
83
Plugins/ICSharpCode.SharpZipLib.dll.meta
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: de67d260a82e87742b9c3c297379ffb3
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
: Linux
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: x86
|
||||||
|
- first:
|
||||||
|
: LinuxUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
: OSXIntel
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
: OSXIntel64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
OS: AnyOS
|
||||||
|
- first:
|
||||||
|
Standalone: Linux64
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: OSXUniversal
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: None
|
||||||
|
- first:
|
||||||
|
Standalone: Win
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Standalone: Win64
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Plugins/System.Buffers.dll
Normal file
BIN
Plugins/System.Buffers.dll
Normal file
Binary file not shown.
33
Plugins/System.Buffers.dll.meta
Normal file
33
Plugins/System.Buffers.dll.meta
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 80b599a6cb4f1c94dbb15cbb8b52b5e7
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Plugins/System.Memory.dll
Normal file
BIN
Plugins/System.Memory.dll
Normal file
Binary file not shown.
33
Plugins/System.Memory.dll.meta
Normal file
33
Plugins/System.Memory.dll.meta
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e69802479db3f6540b50e7515c7e7ef9
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Plugins/System.Runtime.CompilerServices.Unsafe.dll
Normal file
BIN
Plugins/System.Runtime.CompilerServices.Unsafe.dll
Normal file
Binary file not shown.
33
Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta
Normal file
33
Plugins/System.Runtime.CompilerServices.Unsafe.dll.meta
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8f0fcff9f03d0ec498f1e227c9c6878a
|
||||||
|
PluginImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
iconMap: {}
|
||||||
|
executionOrder: {}
|
||||||
|
defineConstraints: []
|
||||||
|
isPreloaded: 0
|
||||||
|
isOverridable: 0
|
||||||
|
isExplicitlyReferenced: 0
|
||||||
|
validateReferences: 1
|
||||||
|
platformData:
|
||||||
|
- first:
|
||||||
|
Any:
|
||||||
|
second:
|
||||||
|
enabled: 1
|
||||||
|
settings: {}
|
||||||
|
- first:
|
||||||
|
Editor: Editor
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
DefaultValueInitialized: true
|
||||||
|
- first:
|
||||||
|
Windows Store Apps: WindowsStoreApps
|
||||||
|
second:
|
||||||
|
enabled: 0
|
||||||
|
settings:
|
||||||
|
CPU: AnyCPU
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
BIN
Plugins/XLog.dll
Normal file
BIN
Plugins/XLog.dll
Normal file
Binary file not shown.
2
Plugins/XLog.dll.meta
Normal file
2
Plugins/XLog.dll.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d54020f8ad5378144bdeef5bb9b7a769
|
||||||
8
Runtime/ABase.meta
Normal file
8
Runtime/ABase.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 74d41a49b8f6d8442b0484a9d0f1a99d
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Runtime/ABase/Base.meta
Normal file
3
Runtime/ABase/Base.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 17ad22f068c740e7a51303c78a742268
|
||||||
|
timeCreated: 1736324891
|
||||||
8
Runtime/ABase/Base/DataStruct.meta
Normal file
8
Runtime/ABase/Base/DataStruct.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a40ddcd0fd47a4c06bb194117de12597
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
446
Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs
Normal file
446
Runtime/ABase/Base/DataStruct/GameFrameworkLinkedList.cs
Normal file
@ -0,0 +1,446 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架链表类。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">指定链表的元素类型。</typeparam>
|
||||||
|
public sealed class GameFrameworkLinkedList<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
|
||||||
|
{
|
||||||
|
private readonly LinkedList<T> m_LinkedList;
|
||||||
|
private readonly Queue<LinkedListNode<T>> m_CachedNodes;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏框架链表类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
public GameFrameworkLinkedList()
|
||||||
|
{
|
||||||
|
m_LinkedList = new LinkedList<T>();
|
||||||
|
m_CachedNodes = new Queue<LinkedListNode<T>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表中实际包含的结点数量。
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_LinkedList.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表结点缓存数量。
|
||||||
|
/// </summary>
|
||||||
|
public int CachedNodeCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_CachedNodes.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表的第一个结点。
|
||||||
|
/// </summary>
|
||||||
|
public LinkedListNode<T> First
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_LinkedList.First;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表的最后一个结点。
|
||||||
|
/// </summary>
|
||||||
|
public LinkedListNode<T> Last
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_LinkedList.Last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个值,该值指示 ICollection`1 是否为只读。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((ICollection<T>)m_LinkedList).IsReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取可用于同步对 ICollection 的访问的对象。
|
||||||
|
/// </summary>
|
||||||
|
public object SyncRoot
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((ICollection)m_LinkedList).SyncRoot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsSynchronized
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return ((ICollection)m_LinkedList).IsSynchronized;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表中指定的现有结点后添加包含指定值的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的现有结点。</param>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>包含指定值的新结点。</returns>
|
||||||
|
public LinkedListNode<T> AddAfter(LinkedListNode<T> node, T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> newNode = AcquireNode(value);
|
||||||
|
m_LinkedList.AddAfter(node, newNode);
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表中指定的现有结点后添加指定的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的现有结点。</param>
|
||||||
|
/// <param name="newNode">指定的新结点。</param>
|
||||||
|
public void AddAfter(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
||||||
|
{
|
||||||
|
m_LinkedList.AddAfter(node, newNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表中指定的现有结点前添加包含指定值的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的现有结点。</param>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>包含指定值的新结点。</returns>
|
||||||
|
public LinkedListNode<T> AddBefore(LinkedListNode<T> node, T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> newNode = AcquireNode(value);
|
||||||
|
m_LinkedList.AddBefore(node, newNode);
|
||||||
|
return newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表中指定的现有结点前添加指定的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的现有结点。</param>
|
||||||
|
/// <param name="newNode">指定的新结点。</param>
|
||||||
|
public void AddBefore(LinkedListNode<T> node, LinkedListNode<T> newNode)
|
||||||
|
{
|
||||||
|
m_LinkedList.AddBefore(node, newNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表的开头处添加包含指定值的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>包含指定值的新结点。</returns>
|
||||||
|
public LinkedListNode<T> AddFirst(T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> node = AcquireNode(value);
|
||||||
|
m_LinkedList.AddFirst(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表的开头处添加指定的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的新结点。</param>
|
||||||
|
public void AddFirst(LinkedListNode<T> node)
|
||||||
|
{
|
||||||
|
m_LinkedList.AddFirst(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表的结尾处添加包含指定值的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>包含指定值的新结点。</returns>
|
||||||
|
public LinkedListNode<T> AddLast(T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> node = AcquireNode(value);
|
||||||
|
m_LinkedList.AddLast(node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 在链表的结尾处添加指定的新结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的新结点。</param>
|
||||||
|
public void AddLast(LinkedListNode<T> node)
|
||||||
|
{
|
||||||
|
m_LinkedList.AddLast(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从链表中移除所有结点。
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
LinkedListNode<T> current = m_LinkedList.First;
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
ReleaseNode(current);
|
||||||
|
current = current.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_LinkedList.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清除链表结点缓存。
|
||||||
|
/// </summary>
|
||||||
|
public void ClearCachedNodes()
|
||||||
|
{
|
||||||
|
m_CachedNodes.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确定某值是否在链表中。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>某值是否在链表中。</returns>
|
||||||
|
public bool Contains(T value)
|
||||||
|
{
|
||||||
|
return m_LinkedList.Contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从目标数组的指定索引处开始将整个链表复制到兼容的一维数组。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">一维数组,它是从链表复制的元素的目标。数组必须具有从零开始的索引。</param>
|
||||||
|
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
|
||||||
|
public void CopyTo(T[] array, int index)
|
||||||
|
{
|
||||||
|
m_LinkedList.CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从特定的 ICollection 索引开始,将数组的元素复制到一个数组中。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="array">一维数组,它是从 ICollection 复制的元素的目标。数组必须具有从零开始的索引。</param>
|
||||||
|
/// <param name="index">array 中从零开始的索引,从此处开始复制。</param>
|
||||||
|
public void CopyTo(Array array, int index)
|
||||||
|
{
|
||||||
|
((ICollection)m_LinkedList).CopyTo(array, index);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找包含指定值的第一个结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要查找的指定值。</param>
|
||||||
|
/// <returns>包含指定值的第一个结点。</returns>
|
||||||
|
public LinkedListNode<T> Find(T value)
|
||||||
|
{
|
||||||
|
return m_LinkedList.Find(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找包含指定值的最后一个结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要查找的指定值。</param>
|
||||||
|
/// <returns>包含指定值的最后一个结点。</returns>
|
||||||
|
public LinkedListNode<T> FindLast(T value)
|
||||||
|
{
|
||||||
|
return m_LinkedList.FindLast(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从链表中移除指定值的第一个匹配项。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">指定值。</param>
|
||||||
|
/// <returns>是否移除成功。</returns>
|
||||||
|
public bool Remove(T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> node = m_LinkedList.Find(value);
|
||||||
|
if (node != null)
|
||||||
|
{
|
||||||
|
m_LinkedList.Remove(node);
|
||||||
|
ReleaseNode(node);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从链表中移除指定的结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="node">指定的结点。</param>
|
||||||
|
public void Remove(LinkedListNode<T> node)
|
||||||
|
{
|
||||||
|
m_LinkedList.Remove(node);
|
||||||
|
ReleaseNode(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除位于链表开头处的结点。
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveFirst()
|
||||||
|
{
|
||||||
|
LinkedListNode<T> first = m_LinkedList.First;
|
||||||
|
if (first == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("First is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_LinkedList.RemoveFirst();
|
||||||
|
ReleaseNode(first);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除位于链表结尾处的结点。
|
||||||
|
/// </summary>
|
||||||
|
public void RemoveLast()
|
||||||
|
{
|
||||||
|
LinkedListNode<T> last = m_LinkedList.Last;
|
||||||
|
if (last == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Last is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_LinkedList.RemoveLast();
|
||||||
|
ReleaseNode(last);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(m_LinkedList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private LinkedListNode<T> AcquireNode(T value)
|
||||||
|
{
|
||||||
|
LinkedListNode<T> node = null;
|
||||||
|
if (m_CachedNodes.Count > 0)
|
||||||
|
{
|
||||||
|
node = m_CachedNodes.Dequeue();
|
||||||
|
node.Value = value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = new LinkedListNode<T>(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReleaseNode(LinkedListNode<T> node)
|
||||||
|
{
|
||||||
|
node.Value = default(T);
|
||||||
|
m_CachedNodes.Enqueue(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将值添加到 ICollection`1 的结尾处。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要添加的值。</param>
|
||||||
|
void ICollection<T>.Add(T value)
|
||||||
|
{
|
||||||
|
AddLast(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct Enumerator : IEnumerator<T>, IEnumerator
|
||||||
|
{
|
||||||
|
private LinkedList<T>.Enumerator m_Enumerator;
|
||||||
|
|
||||||
|
internal Enumerator(LinkedList<T> linkedList)
|
||||||
|
{
|
||||||
|
if (linkedList == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Linked list is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Enumerator = linkedList.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前结点。
|
||||||
|
/// </summary>
|
||||||
|
public T Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Enumerator.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
object IEnumerator.Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Enumerator.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理枚举数。
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
m_Enumerator.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取下一个结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>返回下一个结点。</returns>
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
return m_Enumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置枚举数。
|
||||||
|
/// </summary>
|
||||||
|
void IEnumerator.Reset()
|
||||||
|
{
|
||||||
|
((IEnumerator<T>)m_Enumerator).Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8662d2b0651bb46308fa9ea5a24a9f08
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
210
Runtime/ABase/Base/DataStruct/GameFrameworkLinkedListRange.cs
Normal file
210
Runtime/ABase/Base/DataStruct/GameFrameworkLinkedListRange.cs
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架链表范围。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">指定链表范围的元素类型。</typeparam>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public readonly struct GameFrameworkLinkedListRange<T> : IEnumerable<T>, IEnumerable
|
||||||
|
{
|
||||||
|
private readonly LinkedListNode<T> m_First;
|
||||||
|
private readonly LinkedListNode<T> m_Terminal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏框架链表范围的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="first">链表范围的开始结点。</param>
|
||||||
|
/// <param name="terminal">链表范围的终结标记结点。</param>
|
||||||
|
public GameFrameworkLinkedListRange(LinkedListNode<T> first, LinkedListNode<T> terminal)
|
||||||
|
{
|
||||||
|
if (first == null || terminal == null || first == terminal)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Range is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_First = first;
|
||||||
|
m_Terminal = terminal;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表范围是否有效。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsValid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_First != null && m_Terminal != null && m_First != m_Terminal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表范围的开始结点。
|
||||||
|
/// </summary>
|
||||||
|
public LinkedListNode<T> First
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_First;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表范围的终结标记结点。
|
||||||
|
/// </summary>
|
||||||
|
public LinkedListNode<T> Terminal
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Terminal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取链表范围的结点数量。
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!IsValid)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int count = 0;
|
||||||
|
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查是否包含指定值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要检查的值。</param>
|
||||||
|
/// <returns>是否包含指定值。</returns>
|
||||||
|
public bool Contains(T value)
|
||||||
|
{
|
||||||
|
for (LinkedListNode<T> current = m_First; current != null && current != m_Terminal; current = current.Next)
|
||||||
|
{
|
||||||
|
if (current.Value.Equals(value))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator<T> IEnumerable<T>.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct Enumerator : IEnumerator<T>, IEnumerator
|
||||||
|
{
|
||||||
|
private readonly GameFrameworkLinkedListRange<T> m_GameFrameworkLinkedListRange;
|
||||||
|
private LinkedListNode<T> m_Current;
|
||||||
|
private T m_CurrentValue;
|
||||||
|
|
||||||
|
internal Enumerator(GameFrameworkLinkedListRange<T> range)
|
||||||
|
{
|
||||||
|
if (!range.IsValid)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Range is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_GameFrameworkLinkedListRange = range;
|
||||||
|
m_Current = m_GameFrameworkLinkedListRange.m_First;
|
||||||
|
m_CurrentValue = default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前结点。
|
||||||
|
/// </summary>
|
||||||
|
public T Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_CurrentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
object IEnumerator.Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_CurrentValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理枚举数。
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取下一个结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>返回下一个结点。</returns>
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
if (m_Current == null || m_Current == m_GameFrameworkLinkedListRange.m_Terminal)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_CurrentValue = m_Current.Value;
|
||||||
|
m_Current = m_Current.Next;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置枚举数。
|
||||||
|
/// </summary>
|
||||||
|
void IEnumerator.Reset()
|
||||||
|
{
|
||||||
|
m_Current = m_GameFrameworkLinkedListRange.m_First;
|
||||||
|
m_CurrentValue = default(T);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 7edbebe0b1fd848418e2f1d863b611e1
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
276
Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs
Normal file
276
Runtime/ABase/Base/DataStruct/GameFrameworkMultiDictionary.cs
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架多值字典类。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TKey">指定多值字典的主键类型。</typeparam>
|
||||||
|
/// <typeparam name="TValue">指定多值字典的值类型。</typeparam>
|
||||||
|
public sealed class GameFrameworkMultiDictionary<TKey, TValue> : IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerable
|
||||||
|
{
|
||||||
|
private readonly GameFrameworkLinkedList<TValue> m_LinkedList;
|
||||||
|
private readonly Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> m_Dictionary;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏框架多值字典类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
public GameFrameworkMultiDictionary()
|
||||||
|
{
|
||||||
|
m_LinkedList = new GameFrameworkLinkedList<TValue>();
|
||||||
|
m_Dictionary = new Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取多值字典中实际包含的主键数量。
|
||||||
|
/// </summary>
|
||||||
|
public int Count
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Dictionary.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取多值字典中指定主键的范围。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <returns>指定主键的范围。</returns>
|
||||||
|
public GameFrameworkLinkedListRange<TValue> this[TKey key]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
m_Dictionary.TryGetValue(key, out range);
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理多值字典。
|
||||||
|
/// </summary>
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
m_Dictionary.Clear();
|
||||||
|
m_LinkedList.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查多值字典中是否包含指定主键。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">要检查的主键。</param>
|
||||||
|
/// <returns>多值字典中是否包含指定主键。</returns>
|
||||||
|
public bool Contains(TKey key)
|
||||||
|
{
|
||||||
|
return m_Dictionary.ContainsKey(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查多值字典中是否包含指定值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">要检查的主键。</param>
|
||||||
|
/// <param name="value">要检查的值。</param>
|
||||||
|
/// <returns>多值字典中是否包含指定值。</returns>
|
||||||
|
public bool Contains(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
if (m_Dictionary.TryGetValue(key, out range))
|
||||||
|
{
|
||||||
|
return range.Contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试获取多值字典中指定主键的范围。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <param name="range">指定主键的范围。</param>
|
||||||
|
/// <returns>是否获取成功。</returns>
|
||||||
|
public bool TryGetValue(TKey key, out GameFrameworkLinkedListRange<TValue> range)
|
||||||
|
{
|
||||||
|
return m_Dictionary.TryGetValue(key, out range);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向指定的主键增加指定的值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <param name="value">指定的值。</param>
|
||||||
|
public void Add(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
if (m_Dictionary.TryGetValue(key, out range))
|
||||||
|
{
|
||||||
|
m_LinkedList.AddBefore(range.Terminal, value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LinkedListNode<TValue> first = m_LinkedList.AddLast(value);
|
||||||
|
LinkedListNode<TValue> terminal = m_LinkedList.AddLast(default(TValue));
|
||||||
|
m_Dictionary.Add(key, new GameFrameworkLinkedListRange<TValue>(first, terminal));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从指定的主键中移除指定的值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <param name="value">指定的值。</param>
|
||||||
|
/// <returns>是否移除成功。</returns>
|
||||||
|
public bool Remove(TKey key, TValue value)
|
||||||
|
{
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
if (m_Dictionary.TryGetValue(key, out range))
|
||||||
|
{
|
||||||
|
for (LinkedListNode<TValue> current = range.First; current != null && current != range.Terminal; current = current.Next)
|
||||||
|
{
|
||||||
|
if (current.Value.Equals(value))
|
||||||
|
{
|
||||||
|
if (current == range.First)
|
||||||
|
{
|
||||||
|
LinkedListNode<TValue> next = current.Next;
|
||||||
|
if (next == range.Terminal)
|
||||||
|
{
|
||||||
|
m_LinkedList.Remove(next);
|
||||||
|
m_Dictionary.Remove(key);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_Dictionary[key] = new GameFrameworkLinkedListRange<TValue>(next, range.Terminal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_LinkedList.Remove(current);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从指定的主键中移除所有的值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="key">指定的主键。</param>
|
||||||
|
/// <returns>是否移除成功。</returns>
|
||||||
|
public bool RemoveAll(TKey key)
|
||||||
|
{
|
||||||
|
GameFrameworkLinkedListRange<TValue> range = default(GameFrameworkLinkedListRange<TValue>);
|
||||||
|
if (m_Dictionary.TryGetValue(key, out range))
|
||||||
|
{
|
||||||
|
m_Dictionary.Remove(key);
|
||||||
|
|
||||||
|
LinkedListNode<TValue> current = range.First;
|
||||||
|
while (current != null)
|
||||||
|
{
|
||||||
|
LinkedListNode<TValue> next = current != range.Terminal ? current.Next : null;
|
||||||
|
m_LinkedList.Remove(current);
|
||||||
|
current = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
public Enumerator GetEnumerator()
|
||||||
|
{
|
||||||
|
return new Enumerator(m_Dictionary);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>> IEnumerable<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 返回循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>循环访问集合的枚举数。</returns>
|
||||||
|
IEnumerator IEnumerable.GetEnumerator()
|
||||||
|
{
|
||||||
|
return GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 循环访问集合的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct Enumerator : IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>, IEnumerator
|
||||||
|
{
|
||||||
|
private Dictionary<TKey, GameFrameworkLinkedListRange<TValue>>.Enumerator m_Enumerator;
|
||||||
|
|
||||||
|
internal Enumerator(Dictionary<TKey, GameFrameworkLinkedListRange<TValue>> dictionary)
|
||||||
|
{
|
||||||
|
if (dictionary == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Dictionary is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Enumerator = dictionary.GetEnumerator();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前结点。
|
||||||
|
/// </summary>
|
||||||
|
public KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>> Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Enumerator.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取当前的枚举数。
|
||||||
|
/// </summary>
|
||||||
|
object IEnumerator.Current
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return m_Enumerator.Current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清理枚举数。
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
m_Enumerator.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取下一个结点。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>返回下一个结点。</returns>
|
||||||
|
public bool MoveNext()
|
||||||
|
{
|
||||||
|
return m_Enumerator.MoveNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置枚举数。
|
||||||
|
/// </summary>
|
||||||
|
void IEnumerator.Reset()
|
||||||
|
{
|
||||||
|
((IEnumerator<KeyValuePair<TKey, GameFrameworkLinkedListRange<TValue>>>)m_Enumerator).Reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ce20200ce38864c44b02e0c1ebc7fc3a
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
199
Runtime/ABase/Base/DataStruct/GameFrameworkSerializer.cs
Normal file
199
Runtime/ABase/Base/DataStruct/GameFrameworkSerializer.cs
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架序列化器基类。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">要序列化的数据类型。</typeparam>
|
||||||
|
public abstract class GameFrameworkSerializer<T>
|
||||||
|
{
|
||||||
|
private readonly Dictionary<byte, SerializeCallback> _serializeCallbacks;
|
||||||
|
private readonly Dictionary<byte, DeserializeCallback> _deserializeCallbacks;
|
||||||
|
private readonly Dictionary<byte, TryGetValueCallback> _tryGetValueCallbacks;
|
||||||
|
private byte _latestSerializeCallbackVersion;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏框架序列化器基类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
public GameFrameworkSerializer()
|
||||||
|
{
|
||||||
|
_serializeCallbacks = new Dictionary<byte, SerializeCallback>();
|
||||||
|
_deserializeCallbacks = new Dictionary<byte, DeserializeCallback>();
|
||||||
|
_tryGetValueCallbacks = new Dictionary<byte, TryGetValueCallback>();
|
||||||
|
_latestSerializeCallbackVersion = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">目标流。</param>
|
||||||
|
/// <param name="data">要序列化的数据。</param>
|
||||||
|
/// <returns>是否序列化数据成功。</returns>
|
||||||
|
public delegate bool SerializeCallback(Stream stream, T data);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 反序列化回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">指定流。</param>
|
||||||
|
/// <returns>反序列化的数据。</returns>
|
||||||
|
public delegate T DeserializeCallback(Stream stream);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试从指定流获取指定键的值回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">指定流。</param>
|
||||||
|
/// <param name="key">指定键。</param>
|
||||||
|
/// <param name="value">指定键的值。</param>
|
||||||
|
/// <returns>是否从指定流获取指定键的值成功。</returns>
|
||||||
|
public delegate bool TryGetValueCallback(Stream stream, string key, out object value);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册序列化回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">序列化回调函数的版本。</param>
|
||||||
|
/// <param name="callback">序列化回调函数。</param>
|
||||||
|
public void RegisterSerializeCallback(byte version, SerializeCallback callback)
|
||||||
|
{
|
||||||
|
if (callback == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Serialize callback is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_serializeCallbacks[version] = callback;
|
||||||
|
if (version > _latestSerializeCallbackVersion)
|
||||||
|
{
|
||||||
|
_latestSerializeCallbackVersion = version;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册反序列化回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">反序列化回调函数的版本。</param>
|
||||||
|
/// <param name="callback">反序列化回调函数。</param>
|
||||||
|
public void RegisterDeserializeCallback(byte version, DeserializeCallback callback)
|
||||||
|
{
|
||||||
|
if (callback == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Deserialize callback is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_deserializeCallbacks[version] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册尝试从指定流获取指定键的值回调函数。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="version">尝试从指定流获取指定键的值回调函数的版本。</param>
|
||||||
|
/// <param name="callback">尝试从指定流获取指定键的值回调函数。</param>
|
||||||
|
public void RegisterTryGetValueCallback(byte version, TryGetValueCallback callback)
|
||||||
|
{
|
||||||
|
if (callback == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Try get value callback is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_tryGetValueCallbacks[version] = callback;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化数据到目标流中。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">目标流。</param>
|
||||||
|
/// <param name="data">要序列化的数据。</param>
|
||||||
|
/// <returns>是否序列化数据成功。</returns>
|
||||||
|
public bool Serialize(Stream stream, T data)
|
||||||
|
{
|
||||||
|
if (_serializeCallbacks.Count <= 0)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("No serialize callback registered.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return Serialize(stream, data, _latestSerializeCallbackVersion);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 序列化数据到目标流中。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">目标流。</param>
|
||||||
|
/// <param name="data">要序列化的数据。</param>
|
||||||
|
/// <param name="version">序列化回调函数的版本。</param>
|
||||||
|
/// <returns>是否序列化数据成功。</returns>
|
||||||
|
public bool Serialize(Stream stream, T data, byte version)
|
||||||
|
{
|
||||||
|
byte[] header = GetHeader();
|
||||||
|
stream.WriteByte(header[0]);
|
||||||
|
stream.WriteByte(header[1]);
|
||||||
|
stream.WriteByte(header[2]);
|
||||||
|
stream.WriteByte(version);
|
||||||
|
if (!_serializeCallbacks.TryGetValue(version, out var callback))
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("Serialize callback '{0}' is not exist.", version));
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(stream, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从指定流反序列化数据。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">指定流。</param>
|
||||||
|
/// <returns>反序列化的数据。</returns>
|
||||||
|
public T Deserialize(Stream stream)
|
||||||
|
{
|
||||||
|
byte[] header = GetHeader();
|
||||||
|
byte header0 = (byte)stream.ReadByte();
|
||||||
|
byte header1 = (byte)stream.ReadByte();
|
||||||
|
byte header2 = (byte)stream.ReadByte();
|
||||||
|
if (header0 != header[0] || header1 != header[1] || header2 != header[2])
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("Header is invalid, need '{0}{1}{2}', current '{3}{4}{5}'.", (char)header[0], (char)header[1], (char)header[2], (char)header0, (char)header1, (char)header2));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte version = (byte)stream.ReadByte();
|
||||||
|
if (!_deserializeCallbacks.TryGetValue(version, out var callback))
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("Deserialize callback '{0}' is not exist.", version));
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 尝试从指定流获取指定键的值。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">指定流。</param>
|
||||||
|
/// <param name="key">指定键。</param>
|
||||||
|
/// <param name="value">指定键的值。</param>
|
||||||
|
/// <returns>是否从指定流获取指定键的值成功。</returns>
|
||||||
|
public bool TryGetValue(Stream stream, string key, out object value)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
byte[] header = GetHeader();
|
||||||
|
byte header0 = (byte)stream.ReadByte();
|
||||||
|
byte header1 = (byte)stream.ReadByte();
|
||||||
|
byte header2 = (byte)stream.ReadByte();
|
||||||
|
if (header0 != header[0] || header1 != header[1] || header2 != header[2])
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte version = (byte)stream.ReadByte();
|
||||||
|
if (!_tryGetValueCallbacks.TryGetValue(version, out var callback))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return callback(stream, key, out value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取数据头标识。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>数据头标识。</returns>
|
||||||
|
protected abstract byte[] GetHeader();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2c8469a7db4474e1da10e383bc09e77f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
15
Runtime/ABase/Base/DataStruct/ObjectDontDestroyOnLoad.cs
Normal file
15
Runtime/ABase/Base/DataStruct/ObjectDontDestroyOnLoad.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 标记物体对象为不可销毁
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ObjectDontDestroyOnLoad : MonoBehaviour
|
||||||
|
{
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
DontDestroyOnLoad(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: eeb79f91247b409d97a8599f33d97808
|
||||||
|
timeCreated: 1730723224
|
||||||
130
Runtime/ABase/Base/DataStruct/SingletonManager.cs
Normal file
130
Runtime/ABase/Base/DataStruct/SingletonManager.cs
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 所有单例的统一管理器。
|
||||||
|
/// </summary>
|
||||||
|
[DefaultExecutionOrder(-9999)]
|
||||||
|
public sealed class SingletonManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
private static SingletonManager _instance;
|
||||||
|
private readonly Dictionary<Type, Component> _singletons = new();
|
||||||
|
|
||||||
|
public static SingletonManager Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
// 查找是否已有实例
|
||||||
|
_instance = FindFirstObjectByType<SingletonManager>();
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
var obj = new GameObject("[SingletonManagers]");
|
||||||
|
_instance = obj.AddComponent<SingletonManager>();
|
||||||
|
DontDestroyOnLoad(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注册一个单例。
|
||||||
|
/// </summary>
|
||||||
|
internal void Register<T>(T instance) where T : Component
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (!_singletons.ContainsKey(type))
|
||||||
|
{
|
||||||
|
_singletons[type] = instance;
|
||||||
|
instance.transform.SetParent(transform, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 注销单例。
|
||||||
|
/// </summary>
|
||||||
|
internal void Unregister<T>(T instance) where T : Component
|
||||||
|
{
|
||||||
|
var type = typeof(T);
|
||||||
|
if (_singletons.TryGetValue(type, out var current) && current == instance)
|
||||||
|
_singletons.Remove(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取一个已注册的单例(若不存在则返回 null)
|
||||||
|
/// </summary>
|
||||||
|
public T Get<T>() where T : Component
|
||||||
|
{
|
||||||
|
_singletons.TryGetValue(typeof(T), out var result);
|
||||||
|
return result as T;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 泛型单例基类。
|
||||||
|
/// 自动注册到 SingletonManager。
|
||||||
|
/// 支持动态创建与销毁。
|
||||||
|
/// </summary>
|
||||||
|
public abstract class Singleton<T> : MonoBehaviour where T : Component
|
||||||
|
{
|
||||||
|
private static T _instance;
|
||||||
|
private static readonly object _lock = new();
|
||||||
|
|
||||||
|
public static T Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance != null) return _instance;
|
||||||
|
|
||||||
|
lock (_lock)
|
||||||
|
{
|
||||||
|
if (_instance != null) return _instance;
|
||||||
|
|
||||||
|
// 检查 SingletonManager 是否存在
|
||||||
|
var manager = SingletonManager.Instance;
|
||||||
|
|
||||||
|
// 查找场景中是否已经存在该类型
|
||||||
|
_instance = manager.Get<T>();
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
var obj = new GameObject(typeof(T).Name);
|
||||||
|
_instance = obj.AddComponent<T>();
|
||||||
|
manager.Register(_instance);
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void Awake()
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = this as T;
|
||||||
|
SingletonManager.Instance.Register(_instance);
|
||||||
|
}
|
||||||
|
else if (_instance != this)
|
||||||
|
{
|
||||||
|
Destroy(gameObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDestroy()
|
||||||
|
{
|
||||||
|
if (_instance == this)
|
||||||
|
{
|
||||||
|
SingletonManager.Instance.Unregister(this as T);
|
||||||
|
_instance = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Base/DataStruct/SingletonManager.cs.meta
Normal file
3
Runtime/ABase/Base/DataStruct/SingletonManager.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e7535f150dae4dbeb5604b01e21e92ed
|
||||||
|
timeCreated: 1760162930
|
||||||
122
Runtime/ABase/Base/DataStruct/TypeNamePair.cs
Normal file
122
Runtime/ABase/Base/DataStruct/TypeNamePair.cs
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 类型和名称的组合值。
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public readonly struct TypeNamePair : IEquatable<TypeNamePair>
|
||||||
|
{
|
||||||
|
private readonly Type m_Type;
|
||||||
|
private readonly string m_Name;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化类型和名称的组合值的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">类型。</param>
|
||||||
|
public TypeNamePair(Type type) : this(type, string.Empty)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化类型和名称的组合值的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">类型。</param>
|
||||||
|
/// <param name="name">名称。</param>
|
||||||
|
public TypeNamePair(Type type, string name)
|
||||||
|
{
|
||||||
|
if (type == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
m_Type = type;
|
||||||
|
m_Name = name ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取类型。
|
||||||
|
/// </summary>
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get { return m_Type; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取名称。
|
||||||
|
/// </summary>
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return m_Name; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取类型和名称的组合值字符串。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>类型和名称的组合值字符串。</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
if (m_Type == null)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException("Type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
string typeName = m_Type.FullName;
|
||||||
|
return (string.IsNullOrEmpty(m_Name) ? typeName : Utility.Text.Format("{0}.{1}", typeName, m_Name)) ?? string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取对象的哈希值。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>对象的哈希值。</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return m_Type.GetHashCode() ^ m_Name.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 比较对象是否与自身相等。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">要比较的对象。</param>
|
||||||
|
/// <returns>被比较的对象是否与自身相等。</returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
return obj is TypeNamePair pair && Equals(pair);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 比较对象是否与自身相等。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要比较的对象。</param>
|
||||||
|
/// <returns>被比较的对象是否与自身相等。</returns>
|
||||||
|
public bool Equals(TypeNamePair value)
|
||||||
|
{
|
||||||
|
return m_Type == value.m_Type && m_Name == value.m_Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断两个对象是否相等。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">值 a。</param>
|
||||||
|
/// <param name="b">值 b。</param>
|
||||||
|
/// <returns>两个对象是否相等。</returns>
|
||||||
|
public static bool operator ==(TypeNamePair a, TypeNamePair b)
|
||||||
|
{
|
||||||
|
return a.Equals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 判断两个对象是否不相等。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="a">值 a。</param>
|
||||||
|
/// <param name="b">值 b。</param>
|
||||||
|
/// <returns>两个对象是否不相等。</returns>
|
||||||
|
public static bool operator !=(TypeNamePair a, TypeNamePair b)
|
||||||
|
{
|
||||||
|
return !(a == b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/DataStruct/TypeNamePair.cs.meta
Normal file
11
Runtime/ABase/Base/DataStruct/TypeNamePair.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 794a4497a986043dead37960f38aeb52
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Runtime/ABase/Base/Exception.meta
Normal file
3
Runtime/ABase/Base/Exception.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 6d2a87a6a5a0464580b7732d8291d278
|
||||||
|
timeCreated: 1736424688
|
||||||
49
Runtime/ABase/Base/Exception/GameFrameworkException.cs
Normal file
49
Runtime/ABase/Base/Exception/GameFrameworkException.cs
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架异常类。
|
||||||
|
/// </summary>
|
||||||
|
[Serializable]
|
||||||
|
public class GameFrameworkException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化游戏框架异常类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
public GameFrameworkException()
|
||||||
|
: base()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用指定错误消息初始化游戏框架异常类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">描述错误的消息。</param>
|
||||||
|
public GameFrameworkException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 使用指定错误消息和对作为此异常原因的内部异常的引用来初始化游戏框架异常类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">解释异常原因的错误消息。</param>
|
||||||
|
/// <param name="innerException">导致当前异常的异常。如果 innerException 参数不为空引用,则在处理内部异常的 catch 块中引发当前异常。</param>
|
||||||
|
public GameFrameworkException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 用序列化数据初始化游戏框架异常类的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="info">存有有关所引发异常的序列化的对象数据。</param>
|
||||||
|
/// <param name="context">包含有关源或目标的上下文信息。</param>
|
||||||
|
protected GameFrameworkException(SerializationInfo info, StreamingContext context)
|
||||||
|
: base(info, context)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/Exception/GameFrameworkException.cs.meta
Normal file
11
Runtime/ABase/Base/Exception/GameFrameworkException.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ae8e4ebd442c64fbdbbd8bfec15f1962
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
55
Runtime/ABase/Base/Exception/GameFrameworkGuard.cs
Normal file
55
Runtime/ABase/Base/Exception/GameFrameworkGuard.cs
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架异常静态方法
|
||||||
|
/// </summary>
|
||||||
|
public static class GameFrameworkGuard
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 确保指定的值不为null。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要检查的值。</param>
|
||||||
|
/// <param name="name">值的名称。</param>
|
||||||
|
/// <exception cref="ArgumentNullException">当值为null时引发。</exception>
|
||||||
|
public static void NotNullOrEmpty(string value, string name)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(value))
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(name, " can not be null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 确保指定的值不为null。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">值的类型。</typeparam>
|
||||||
|
/// <param name="value">要检查的值。</param>
|
||||||
|
/// <param name="name">值的名称。</param>
|
||||||
|
/// <exception cref="ArgumentNullException">当值为null时引发。</exception>
|
||||||
|
public static void NotNull<T>(T value, string name) where T : class
|
||||||
|
{
|
||||||
|
if (value == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(name, " can not be null.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查值是否在指定范围内,如果不在范围内则抛出 ArgumentOutOfRangeException 异常。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">要检查的值。</param>
|
||||||
|
/// <param name="min">允许的最小值。</param>
|
||||||
|
/// <param name="max">允许的最大值。</param>
|
||||||
|
/// <param name="name">值的名称。</param>
|
||||||
|
/// <exception cref="ArgumentOutOfRangeException">当值不在指定范围内时抛出。</exception>
|
||||||
|
public static void NotRange(int value, int min, int max, string name)
|
||||||
|
{
|
||||||
|
if (value > max || value < min)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(name, "value must between " + min + " and " + max);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Base/Exception/GameFrameworkGuard.cs.meta
Normal file
3
Runtime/ABase/Base/Exception/GameFrameworkGuard.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ca46f6f46a474facaebe8c44a049485c
|
||||||
|
timeCreated: 1702542639
|
||||||
3
Runtime/ABase/Base/MemoryPool.meta
Normal file
3
Runtime/ABase/Base/MemoryPool.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 68c2b9f042834f45893675afb0ba2ecf
|
||||||
|
timeCreated: 1742458629
|
||||||
13
Runtime/ABase/Base/MemoryPool/IMemory.cs
Normal file
13
Runtime/ABase/Base/MemoryPool/IMemory.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存对象Interface。
|
||||||
|
/// </summary>
|
||||||
|
public interface IMemory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 清理内存对象回收入池。
|
||||||
|
/// </summary>
|
||||||
|
void Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/MemoryPool/IMemory.cs.meta
Normal file
11
Runtime/ABase/Base/MemoryPool/IMemory.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 29d6300317e70b24381120ac8f5b0a92
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
156
Runtime/ABase/Base/MemoryPool/MemoryPool.MemoryCollection.cs
Normal file
156
Runtime/ABase/Base/MemoryPool/MemoryPool.MemoryCollection.cs
Normal file
@ -0,0 +1,156 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
public static partial class MemoryPool
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存池收集器。
|
||||||
|
/// </summary>
|
||||||
|
private sealed class MemoryCollection
|
||||||
|
{
|
||||||
|
private readonly Queue<IMemory> _memories;
|
||||||
|
private readonly Type _memoryType;
|
||||||
|
private int _usingMemoryCount;
|
||||||
|
private int _acquireMemoryCount;
|
||||||
|
private int _releaseMemoryCount;
|
||||||
|
private int _addMemoryCount;
|
||||||
|
private int _removeMemoryCount;
|
||||||
|
|
||||||
|
public MemoryCollection(Type memoryType)
|
||||||
|
{
|
||||||
|
_memories = new Queue<IMemory>();
|
||||||
|
_memoryType = memoryType;
|
||||||
|
_usingMemoryCount = 0;
|
||||||
|
_acquireMemoryCount = 0;
|
||||||
|
_releaseMemoryCount = 0;
|
||||||
|
_addMemoryCount = 0;
|
||||||
|
_removeMemoryCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type MemoryType => _memoryType;
|
||||||
|
|
||||||
|
public int UnusedMemoryCount => _memories.Count;
|
||||||
|
|
||||||
|
public int UsingMemoryCount => _usingMemoryCount;
|
||||||
|
|
||||||
|
public int AcquireMemoryCount => _acquireMemoryCount;
|
||||||
|
|
||||||
|
public int ReleaseMemoryCount => _releaseMemoryCount;
|
||||||
|
|
||||||
|
public int AddMemoryCount => _addMemoryCount;
|
||||||
|
|
||||||
|
public int RemoveMemoryCount => _removeMemoryCount;
|
||||||
|
|
||||||
|
public T Acquire<T>() where T : class, IMemory, new()
|
||||||
|
{
|
||||||
|
if (typeof(T) != _memoryType)
|
||||||
|
{
|
||||||
|
throw new Exception("Type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_usingMemoryCount++;
|
||||||
|
_acquireMemoryCount++;
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
if (_memories.Count > 0)
|
||||||
|
{
|
||||||
|
return (T)_memories.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addMemoryCount++;
|
||||||
|
return new T();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IMemory Acquire()
|
||||||
|
{
|
||||||
|
_usingMemoryCount++;
|
||||||
|
_acquireMemoryCount++;
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
if (_memories.Count > 0)
|
||||||
|
{
|
||||||
|
return _memories.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addMemoryCount++;
|
||||||
|
return (IMemory)Activator.CreateInstance(_memoryType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Release(IMemory memory)
|
||||||
|
{
|
||||||
|
memory.Clear();
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
if (_enableStrictCheck && _memories.Contains(memory))
|
||||||
|
{
|
||||||
|
throw new Exception("The memory has been released.");
|
||||||
|
}
|
||||||
|
|
||||||
|
_memories.Enqueue(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
_releaseMemoryCount++;
|
||||||
|
_usingMemoryCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add<T>(int count) where T : class, IMemory, new()
|
||||||
|
{
|
||||||
|
if (typeof(T) != _memoryType)
|
||||||
|
{
|
||||||
|
throw new Exception("Type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
_addMemoryCount += count;
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
_memories.Enqueue(new T());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Add(int count)
|
||||||
|
{
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
_addMemoryCount += count;
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
_memories.Enqueue((IMemory)Activator.CreateInstance(_memoryType));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Remove(int count)
|
||||||
|
{
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
if (count > _memories.Count)
|
||||||
|
{
|
||||||
|
count = _memories.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
_removeMemoryCount += count;
|
||||||
|
while (count-- > 0)
|
||||||
|
{
|
||||||
|
_memories.Dequeue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveAll()
|
||||||
|
{
|
||||||
|
lock (_memories)
|
||||||
|
{
|
||||||
|
_removeMemoryCount += _memories.Count;
|
||||||
|
_memories.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e4ec5f33991c55f41bceefbdb8089ae2
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
207
Runtime/ABase/Base/MemoryPool/MemoryPool.cs
Normal file
207
Runtime/ABase/Base/MemoryPool/MemoryPool.cs
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存池。
|
||||||
|
/// </summary>
|
||||||
|
public static partial class MemoryPool
|
||||||
|
{
|
||||||
|
private static readonly Dictionary<Type, MemoryCollection> _memoryCollections = new Dictionary<Type, MemoryCollection>();
|
||||||
|
private static bool _enableStrictCheck = false;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否开启强制检查。
|
||||||
|
/// </summary>
|
||||||
|
public static bool EnableStrictCheck
|
||||||
|
{
|
||||||
|
get => _enableStrictCheck;
|
||||||
|
set => _enableStrictCheck = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取内存池的数量。
|
||||||
|
/// </summary>
|
||||||
|
// ReSharper disable once InconsistentlySynchronizedField
|
||||||
|
public static int Count => _memoryCollections.Count;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取所有内存池的信息。
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>所有内存池的信息。</returns>
|
||||||
|
public static MemoryPoolInfo[] GetAllMemoryPoolInfos()
|
||||||
|
{
|
||||||
|
int index = 0;
|
||||||
|
MemoryPoolInfo[] results = null;
|
||||||
|
|
||||||
|
lock (_memoryCollections)
|
||||||
|
{
|
||||||
|
results = new MemoryPoolInfo[_memoryCollections.Count];
|
||||||
|
foreach (KeyValuePair<Type, MemoryCollection> memoryCollection in _memoryCollections)
|
||||||
|
{
|
||||||
|
results[index++] = new MemoryPoolInfo(memoryCollection.Key, memoryCollection.Value.UnusedMemoryCount, memoryCollection.Value.UsingMemoryCount, memoryCollection.Value.AcquireMemoryCount, memoryCollection.Value.ReleaseMemoryCount, memoryCollection.Value.AddMemoryCount, memoryCollection.Value.RemoveMemoryCount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 清除所有内存池。
|
||||||
|
/// </summary>
|
||||||
|
public static void ClearAll()
|
||||||
|
{
|
||||||
|
lock (_memoryCollections)
|
||||||
|
{
|
||||||
|
foreach (KeyValuePair<Type, MemoryCollection> memoryCollection in _memoryCollections)
|
||||||
|
{
|
||||||
|
memoryCollection.Value.RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
_memoryCollections.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池获取内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">内存对象类型。</typeparam>
|
||||||
|
/// <returns>内存对象。</returns>
|
||||||
|
public static T Acquire<T>() where T : class, IMemory, new()
|
||||||
|
{
|
||||||
|
return GetMemoryCollection(typeof(T)).Acquire<T>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池获取内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryType">内存对象类型。</param>
|
||||||
|
/// <returns>内存对象。</returns>
|
||||||
|
public static IMemory Acquire(Type memoryType)
|
||||||
|
{
|
||||||
|
InternalCheckMemoryType(memoryType);
|
||||||
|
return GetMemoryCollection(memoryType).Acquire();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将内存对象归还内存池。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memory">内存对象。</param>
|
||||||
|
public static void Release(IMemory memory)
|
||||||
|
{
|
||||||
|
if (memory == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Memory is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Type memoryType = memory.GetType();
|
||||||
|
InternalCheckMemoryType(memoryType);
|
||||||
|
GetMemoryCollection(memoryType).Release(memory);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向内存池中追加指定数量的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">内存对象类型。</typeparam>
|
||||||
|
/// <param name="count">追加数量。</param>
|
||||||
|
public static void Add<T>(int count) where T : class, IMemory, new()
|
||||||
|
{
|
||||||
|
GetMemoryCollection(typeof(T)).Add<T>(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 向内存池中追加指定数量的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryType">内存对象类型。</param>
|
||||||
|
/// <param name="count">追加数量。</param>
|
||||||
|
public static void Add(Type memoryType, int count)
|
||||||
|
{
|
||||||
|
InternalCheckMemoryType(memoryType);
|
||||||
|
GetMemoryCollection(memoryType).Add(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池中移除指定数量的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">内存对象类型。</typeparam>
|
||||||
|
/// <param name="count">移除数量。</param>
|
||||||
|
public static void Remove<T>(int count) where T : class, IMemory
|
||||||
|
{
|
||||||
|
GetMemoryCollection(typeof(T)).Remove(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池中移除指定数量的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryType">内存对象类型。</param>
|
||||||
|
/// <param name="count">移除数量。</param>
|
||||||
|
public static void Remove(Type memoryType, int count)
|
||||||
|
{
|
||||||
|
InternalCheckMemoryType(memoryType);
|
||||||
|
GetMemoryCollection(memoryType).Remove(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池中移除所有的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">内存对象类型。</typeparam>
|
||||||
|
public static void RemoveAll<T>() where T : class, IMemory
|
||||||
|
{
|
||||||
|
GetMemoryCollection(typeof(T)).RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池中移除所有的内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memoryType">内存对象类型。</param>
|
||||||
|
public static void RemoveAll(Type memoryType)
|
||||||
|
{
|
||||||
|
InternalCheckMemoryType(memoryType);
|
||||||
|
GetMemoryCollection(memoryType).RemoveAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void InternalCheckMemoryType(Type memoryType)
|
||||||
|
{
|
||||||
|
if (!_enableStrictCheck)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (memoryType == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Memory type is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!memoryType.IsClass || memoryType.IsAbstract)
|
||||||
|
{
|
||||||
|
throw new Exception("Memory type is not a non-abstract class type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeof(IMemory).IsAssignableFrom(memoryType))
|
||||||
|
{
|
||||||
|
throw new Exception(string.Format("Memory type '{0}' is invalid.", memoryType.FullName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static MemoryCollection GetMemoryCollection(Type memoryType)
|
||||||
|
{
|
||||||
|
if (memoryType == null)
|
||||||
|
{
|
||||||
|
throw new Exception("MemoryType is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryCollection memoryCollection = null;
|
||||||
|
lock (_memoryCollections)
|
||||||
|
{
|
||||||
|
if (!_memoryCollections.TryGetValue(memoryType, out memoryCollection))
|
||||||
|
{
|
||||||
|
memoryCollection = new MemoryCollection(memoryType);
|
||||||
|
_memoryCollections.Add(memoryType, memoryCollection);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return memoryCollection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/MemoryPool/MemoryPool.cs.meta
Normal file
11
Runtime/ABase/Base/MemoryPool/MemoryPool.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f253bd3093bf78d45ad11b73c134e9ff
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
57
Runtime/ABase/Base/MemoryPool/MemoryPoolExtension.cs
Normal file
57
Runtime/ABase/Base/MemoryPool/MemoryPoolExtension.cs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存池对象基类。
|
||||||
|
/// </summary>
|
||||||
|
public abstract class MemoryObject : IMemory
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 清理内存对象回收入池。
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Clear()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池中初始化。
|
||||||
|
/// </summary>
|
||||||
|
public abstract void InitFromPool();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 回收到内存池。
|
||||||
|
/// </summary>
|
||||||
|
public abstract void RecycleToPool();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static partial class MemoryPool
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 从内存池获取内存对象。
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="T">内存对象类型。</typeparam>
|
||||||
|
/// <returns>内存对象。</returns>
|
||||||
|
public static T Alloc<T>() where T : MemoryObject, new()
|
||||||
|
{
|
||||||
|
T memory = Acquire<T>();
|
||||||
|
memory.InitFromPool();
|
||||||
|
return memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 将内存对象归还内存池。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="memory">内存对象。</param>
|
||||||
|
public static void Dealloc(MemoryObject memory)
|
||||||
|
{
|
||||||
|
if (memory == null)
|
||||||
|
{
|
||||||
|
throw new Exception("Memory is invalid.");
|
||||||
|
}
|
||||||
|
|
||||||
|
memory.RecycleToPool();
|
||||||
|
Release(memory);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ad13ef73c22340058c4420733a22b580
|
||||||
|
timeCreated: 1701273442
|
||||||
118
Runtime/ABase/Base/MemoryPool/MemoryPoolInfo.cs
Normal file
118
Runtime/ABase/Base/MemoryPool/MemoryPoolInfo.cs
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存池信息。
|
||||||
|
/// </summary>
|
||||||
|
[StructLayout(LayoutKind.Auto)]
|
||||||
|
public struct MemoryPoolInfo
|
||||||
|
{
|
||||||
|
private readonly Type _type;
|
||||||
|
private readonly int _unusedMemoryCount;
|
||||||
|
private readonly int _usingMemoryCount;
|
||||||
|
private readonly int _acquireMemoryCount;
|
||||||
|
private readonly int _releaseMemoryCount;
|
||||||
|
private readonly int _addMemoryCount;
|
||||||
|
private readonly int _removeMemoryCount;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 初始化内存池信息的新实例。
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">内存池类型。</param>
|
||||||
|
/// <param name="unusedMemoryCount">未使用内存对象数量。</param>
|
||||||
|
/// <param name="usingMemoryCount">正在使用内存对象数量。</param>
|
||||||
|
/// <param name="acquireMemoryCount">获取内存对象数量。</param>
|
||||||
|
/// <param name="releaseMemoryCount">归还内存对象数量。</param>
|
||||||
|
/// <param name="addMemoryCount">增加内存对象数量。</param>
|
||||||
|
/// <param name="removeMemoryCount">移除内存对象数量。</param>
|
||||||
|
public MemoryPoolInfo(Type type, int unusedMemoryCount, int usingMemoryCount, int acquireMemoryCount, int releaseMemoryCount, int addMemoryCount, int removeMemoryCount)
|
||||||
|
{
|
||||||
|
_type = type;
|
||||||
|
_unusedMemoryCount = unusedMemoryCount;
|
||||||
|
_usingMemoryCount = usingMemoryCount;
|
||||||
|
_acquireMemoryCount = acquireMemoryCount;
|
||||||
|
_releaseMemoryCount = releaseMemoryCount;
|
||||||
|
_addMemoryCount = addMemoryCount;
|
||||||
|
_removeMemoryCount = removeMemoryCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取内存池类型。
|
||||||
|
/// </summary>
|
||||||
|
public Type Type
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _type;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取未使用内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int UnusedMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _unusedMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取正在使用内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int UsingMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _usingMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取获取内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int AcquireMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _acquireMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取归还内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int ReleaseMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _releaseMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取增加内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int AddMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _addMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取移除内存对象数量。
|
||||||
|
/// </summary>
|
||||||
|
public int RemoveMemoryCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return _removeMemoryCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/MemoryPool/MemoryPoolInfo.cs.meta
Normal file
11
Runtime/ABase/Base/MemoryPool/MemoryPoolInfo.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 444aa83c59c8f0445894e785975b5463
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
78
Runtime/ABase/Base/MemoryPool/MemoryPoolSetting.cs
Normal file
78
Runtime/ABase/Base/MemoryPool/MemoryPoolSetting.cs
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 内存强制检查类型。
|
||||||
|
/// </summary>
|
||||||
|
public enum MemoryStrictCheckType : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 总是启用。
|
||||||
|
/// </summary>
|
||||||
|
AlwaysEnable = 0,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 仅在开发模式时启用。
|
||||||
|
/// </summary>
|
||||||
|
OnlyEnableWhenDevelopment,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 仅在编辑器中启用。
|
||||||
|
/// </summary>
|
||||||
|
OnlyEnableInEditor,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 总是禁用。
|
||||||
|
/// </summary>
|
||||||
|
AlwaysDisable,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 内存池模块。
|
||||||
|
/// </summary>
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
public sealed class MemoryPoolSetting : MonoBehaviour
|
||||||
|
{
|
||||||
|
[SerializeField]
|
||||||
|
private MemoryStrictCheckType m_EnableStrictCheck = MemoryStrictCheckType.OnlyEnableWhenDevelopment;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否开启强制检查。
|
||||||
|
/// </summary>
|
||||||
|
public bool EnableStrictCheck
|
||||||
|
{
|
||||||
|
get => MemoryPool.EnableStrictCheck;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
MemoryPool.EnableStrictCheck = value;
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Log.Info("Strict checking is enabled for the Memory Pool. It will drastically affect the performance.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Start()
|
||||||
|
{
|
||||||
|
switch (m_EnableStrictCheck)
|
||||||
|
{
|
||||||
|
case MemoryStrictCheckType.AlwaysEnable:
|
||||||
|
EnableStrictCheck = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryStrictCheckType.OnlyEnableWhenDevelopment:
|
||||||
|
EnableStrictCheck = Debug.isDebugBuild;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case MemoryStrictCheckType.OnlyEnableInEditor:
|
||||||
|
EnableStrictCheck = Application.isEditor;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
EnableStrictCheck = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/MemoryPool/MemoryPoolSetting.cs.meta
Normal file
11
Runtime/ABase/Base/MemoryPool/MemoryPoolSetting.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 61474d279eb27214d9178822796f3b88
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Runtime/ABase/Base/Module.meta
Normal file
3
Runtime/ABase/Base/Module.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: aeb86cc258fa4378ba3b259a5d38e4df
|
||||||
|
timeCreated: 1736424998
|
||||||
42
Runtime/ABase/Base/Module/IModule.cs
Normal file
42
Runtime/ABase/Base/Module/IModule.cs
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
public interface IModule
|
||||||
|
{
|
||||||
|
protected internal void Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleAwake
|
||||||
|
{
|
||||||
|
protected internal void Awake();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IExecuteSystem
|
||||||
|
{
|
||||||
|
abstract int Priority { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleUpdate : IExecuteSystem
|
||||||
|
{
|
||||||
|
protected internal void Update(float elapseSeconds, float realElapseSeconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleLateUpdate : IExecuteSystem
|
||||||
|
{
|
||||||
|
protected internal void LateUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleFixedUpdate : IExecuteSystem
|
||||||
|
{
|
||||||
|
protected internal void FixedUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleDrawGizmos : IExecuteSystem
|
||||||
|
{
|
||||||
|
protected internal void DrawGizmos();
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface IModuleGUI : IExecuteSystem
|
||||||
|
{
|
||||||
|
protected internal void OnGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Base/Module/IModule.cs.meta
Normal file
3
Runtime/ABase/Base/Module/IModule.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 0ba192d5e9084d67b16b53e843e103b3
|
||||||
|
timeCreated: 1736424999
|
||||||
303
Runtime/ABase/Base/Module/ModuleSystem.cs
Normal file
303
Runtime/ABase/Base/Module/ModuleSystem.cs
Normal file
@ -0,0 +1,303 @@
|
|||||||
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
public static class ModuleSystem
|
||||||
|
{
|
||||||
|
internal const int DesignModuleCount = 32;
|
||||||
|
|
||||||
|
private static readonly Dictionary<Type, IModule> _moduleMaps = new Dictionary<Type, IModule>(DesignModuleCount);
|
||||||
|
private static readonly GameFrameworkLinkedList<IModule> _modules = new GameFrameworkLinkedList<IModule>();
|
||||||
|
|
||||||
|
// Update systems
|
||||||
|
private static readonly GameFrameworkLinkedList<IModuleUpdate> _updateModules = new GameFrameworkLinkedList<IModuleUpdate>();
|
||||||
|
private static readonly IModuleUpdate[] _updateExecuteArray = new IModuleUpdate[DesignModuleCount];
|
||||||
|
private static int _updateExecuteCount;
|
||||||
|
|
||||||
|
// LateUpdate systems
|
||||||
|
private static readonly GameFrameworkLinkedList<IModuleLateUpdate> _lateUpdateModules = new GameFrameworkLinkedList<IModuleLateUpdate>();
|
||||||
|
private static readonly IModuleLateUpdate[] _lateUpdateExecuteArray = new IModuleLateUpdate[DesignModuleCount];
|
||||||
|
private static int _lateUpdateExecuteCount;
|
||||||
|
|
||||||
|
// FixedUpdate systems
|
||||||
|
private static readonly GameFrameworkLinkedList<IModuleFixedUpdate> _fixedUpdateModules = new GameFrameworkLinkedList<IModuleFixedUpdate>();
|
||||||
|
private static readonly IModuleFixedUpdate[] _fixedUpdateExecuteArray = new IModuleFixedUpdate[DesignModuleCount];
|
||||||
|
private static int _fixedUpdateExecuteCount;
|
||||||
|
|
||||||
|
// Gizmos systems
|
||||||
|
private static readonly GameFrameworkLinkedList<IModuleDrawGizmos> _gizmosUpdateModules = new GameFrameworkLinkedList<IModuleDrawGizmos>();
|
||||||
|
private static readonly IModuleDrawGizmos[] _gizmosUpdateExecuteArray = new IModuleDrawGizmos[DesignModuleCount];
|
||||||
|
private static int _gizmosExecuteCount;
|
||||||
|
|
||||||
|
// GUI systems
|
||||||
|
private static readonly GameFrameworkLinkedList<IModuleGUI> _guiUpdateModules = new GameFrameworkLinkedList<IModuleGUI>();
|
||||||
|
private static readonly IModuleGUI[] _guiUpdateExecuteArray = new IModuleGUI[DesignModuleCount];
|
||||||
|
private static int _guiExecuteCount;
|
||||||
|
|
||||||
|
// Dirty flags
|
||||||
|
private static bool _isExecuteListDirty;
|
||||||
|
private static bool _isLateExecuteListDirty;
|
||||||
|
private static bool _isFixedExecuteListDirty;
|
||||||
|
private static bool _isGizmosExecuteListDirty;
|
||||||
|
private static bool _isGUIExecuteListDirty;
|
||||||
|
|
||||||
|
internal static void Dispose()
|
||||||
|
{
|
||||||
|
// Clear all modules and execute arrays
|
||||||
|
_updateModules.Clear();
|
||||||
|
Array.Clear(_updateExecuteArray, 0, _updateExecuteArray.Length);
|
||||||
|
_updateExecuteCount = 0;
|
||||||
|
|
||||||
|
_lateUpdateModules.Clear();
|
||||||
|
Array.Clear(_lateUpdateExecuteArray, 0, _lateUpdateExecuteArray.Length);
|
||||||
|
_lateUpdateExecuteCount = 0;
|
||||||
|
|
||||||
|
_fixedUpdateModules.Clear();
|
||||||
|
Array.Clear(_fixedUpdateExecuteArray, 0, _fixedUpdateExecuteArray.Length);
|
||||||
|
_fixedUpdateExecuteCount = 0;
|
||||||
|
|
||||||
|
_gizmosUpdateModules.Clear();
|
||||||
|
Array.Clear(_gizmosUpdateExecuteArray, 0, _gizmosUpdateExecuteArray.Length);
|
||||||
|
_gizmosExecuteCount = 0;
|
||||||
|
|
||||||
|
_guiUpdateModules.Clear();
|
||||||
|
Array.Clear(_guiUpdateExecuteArray, 0, _guiUpdateExecuteArray.Length);
|
||||||
|
_guiExecuteCount = 0;
|
||||||
|
|
||||||
|
// Dispose all modules
|
||||||
|
for (var current = _modules.Last; current != null; current = current.Previous)
|
||||||
|
{
|
||||||
|
current.Value.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_modules.Clear();
|
||||||
|
_moduleMaps.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Public System
|
||||||
|
|
||||||
|
public static T RegisterModule<T, TImple>() where T : IModule where TImple : class, T, new()
|
||||||
|
{
|
||||||
|
Type interfaceType = typeof(T);
|
||||||
|
Type implType = typeof(TImple);
|
||||||
|
if (!interfaceType.IsInterface)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("You must register module by interface, but '{0}' is not.", interfaceType.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!implType.IsClass || implType.IsInterface || implType.IsAbstract)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("You must register module by Class and not Interface and Abstract, but '{0}' is not.", implType.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!typeof(IModule).IsAssignableFrom(interfaceType))
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("Module must implement IModule.", interfaceType.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GetModule(interfaceType) != null)
|
||||||
|
{
|
||||||
|
Log.Error("Already Register {0}", interfaceType.FullName);
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
TImple impl = new TImple();
|
||||||
|
return (T)SetModuleInstance(interfaceType, impl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T GetModule<T>() where T : class
|
||||||
|
{
|
||||||
|
Type interfaceType = typeof(T);
|
||||||
|
if (!interfaceType.IsInterface)
|
||||||
|
{
|
||||||
|
throw new GameFrameworkException(Utility.Text.Format("You must get module by interface, but '{0}' is not.", interfaceType.FullName));
|
||||||
|
}
|
||||||
|
|
||||||
|
return GetModule(interfaceType) as T;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IModule GetModule(Type moduleType)
|
||||||
|
{
|
||||||
|
return _moduleMaps.TryGetValue(moduleType, out var ret) ? ret : default;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IModule SetModuleInstance<TImpl>(Type interfaceType, TImpl impl) where TImpl : class, IModule
|
||||||
|
{
|
||||||
|
_moduleMaps[interfaceType] = impl;
|
||||||
|
_modules.AddLast(impl);
|
||||||
|
|
||||||
|
if (impl is IModuleAwake awakeSystem)
|
||||||
|
{
|
||||||
|
awakeSystem.Awake();
|
||||||
|
}
|
||||||
|
|
||||||
|
CheckSystemLife(impl);
|
||||||
|
return impl;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private static void CheckSystemLife(IModule module)
|
||||||
|
{
|
||||||
|
if (module is IModuleUpdate updateSystem)
|
||||||
|
{
|
||||||
|
BindSystemLife(updateSystem, _updateModules, ref _isExecuteListDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module is IModuleLateUpdate lateUpdate)
|
||||||
|
{
|
||||||
|
BindSystemLife(lateUpdate, _lateUpdateModules, ref _isLateExecuteListDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module is IModuleFixedUpdate fixedUpdate)
|
||||||
|
{
|
||||||
|
BindSystemLife(fixedUpdate, _fixedUpdateModules, ref _isFixedExecuteListDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module is IModuleDrawGizmos drawGizmosUpdate)
|
||||||
|
{
|
||||||
|
BindSystemLife(drawGizmosUpdate, _gizmosUpdateModules, ref _isGizmosExecuteListDirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (module is IModuleGUI guiUpdate)
|
||||||
|
{
|
||||||
|
BindSystemLife(guiUpdate, _guiUpdateModules, ref _isGUIExecuteListDirty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BindSystemLife<T>(T system, GameFrameworkLinkedList<T> updateModule, ref bool executeDirty) where T : IExecuteSystem
|
||||||
|
{
|
||||||
|
var current = updateModule.First;
|
||||||
|
while (current != null && system.Priority <= current.Value.Priority)
|
||||||
|
{
|
||||||
|
current = current.Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current != null)
|
||||||
|
{
|
||||||
|
updateModule.AddBefore(current, system);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
updateModule.AddLast(system);
|
||||||
|
}
|
||||||
|
|
||||||
|
executeDirty = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region BuildExecuteList
|
||||||
|
|
||||||
|
private static void BuildExecuteList()
|
||||||
|
{
|
||||||
|
if (!_isExecuteListDirty) return;
|
||||||
|
_isExecuteListDirty = false;
|
||||||
|
_updateExecuteCount = 0;
|
||||||
|
foreach (var module in _updateModules)
|
||||||
|
{
|
||||||
|
if (_updateExecuteCount >= _updateExecuteArray.Length) break;
|
||||||
|
_updateExecuteArray[_updateExecuteCount++] = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BuildLateExecuteList()
|
||||||
|
{
|
||||||
|
if (!_isLateExecuteListDirty) return;
|
||||||
|
_isLateExecuteListDirty = false;
|
||||||
|
_lateUpdateExecuteCount = 0;
|
||||||
|
foreach (var module in _lateUpdateModules)
|
||||||
|
{
|
||||||
|
if (_lateUpdateExecuteCount >= _lateUpdateExecuteArray.Length) break;
|
||||||
|
_lateUpdateExecuteArray[_lateUpdateExecuteCount++] = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BuildFixedExecuteList()
|
||||||
|
{
|
||||||
|
if (!_isFixedExecuteListDirty) return;
|
||||||
|
_isFixedExecuteListDirty = false;
|
||||||
|
_fixedUpdateExecuteCount = 0;
|
||||||
|
foreach (var module in _fixedUpdateModules)
|
||||||
|
{
|
||||||
|
if (_fixedUpdateExecuteCount >= _fixedUpdateExecuteArray.Length) break;
|
||||||
|
_fixedUpdateExecuteArray[_fixedUpdateExecuteCount++] = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BuildGizmosExecuteList()
|
||||||
|
{
|
||||||
|
if (!_isGizmosExecuteListDirty) return;
|
||||||
|
_isGizmosExecuteListDirty = false;
|
||||||
|
_gizmosExecuteCount = 0;
|
||||||
|
foreach (var module in _gizmosUpdateModules)
|
||||||
|
{
|
||||||
|
if (_gizmosExecuteCount >= _gizmosUpdateExecuteArray.Length) break;
|
||||||
|
_gizmosUpdateExecuteArray[_gizmosExecuteCount++] = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void BuildGUIExecuteList()
|
||||||
|
{
|
||||||
|
if (!_isGUIExecuteListDirty) return;
|
||||||
|
_isGUIExecuteListDirty = false;
|
||||||
|
_guiExecuteCount = 0;
|
||||||
|
foreach (var module in _guiUpdateModules)
|
||||||
|
{
|
||||||
|
if (_guiExecuteCount >= _guiUpdateExecuteArray.Length) break;
|
||||||
|
_guiUpdateExecuteArray[_guiExecuteCount++] = module;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region RunExecuteList
|
||||||
|
|
||||||
|
internal static void UpdateExecuteList(float elapseSeconds, float realElapseSeconds)
|
||||||
|
{
|
||||||
|
BuildExecuteList();
|
||||||
|
for (int i = 0; i < _updateExecuteCount; i++)
|
||||||
|
{
|
||||||
|
_updateExecuteArray[i].Update(elapseSeconds, realElapseSeconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void UpdateLateExecuteList()
|
||||||
|
{
|
||||||
|
BuildLateExecuteList();
|
||||||
|
for (int i = 0; i < _lateUpdateExecuteCount; i++)
|
||||||
|
{
|
||||||
|
_lateUpdateExecuteArray[i].LateUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void UpdateFixedExecuteList()
|
||||||
|
{
|
||||||
|
BuildFixedExecuteList();
|
||||||
|
for (int i = 0; i < _fixedUpdateExecuteCount; i++)
|
||||||
|
{
|
||||||
|
_fixedUpdateExecuteArray[i].FixedUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void UpdateGizmosExecuteList()
|
||||||
|
{
|
||||||
|
BuildGizmosExecuteList();
|
||||||
|
for (int i = 0; i < _gizmosExecuteCount; i++)
|
||||||
|
{
|
||||||
|
_gizmosUpdateExecuteArray[i].DrawGizmos();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static void UpdateGUIExecuteList()
|
||||||
|
{
|
||||||
|
BuildGUIExecuteList();
|
||||||
|
for (int i = 0; i < _guiExecuteCount; i++)
|
||||||
|
{
|
||||||
|
_guiUpdateExecuteArray[i].OnGUI();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Base/Module/ModuleSystem.cs.meta
Normal file
3
Runtime/ABase/Base/Module/ModuleSystem.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b9fa1d3abb954b57989b94b4c77e45ce
|
||||||
|
timeCreated: 1736928479
|
||||||
220
Runtime/ABase/Base/RootModule.cs
Normal file
220
Runtime/ABase/Base/RootModule.cs
Normal file
@ -0,0 +1,220 @@
|
|||||||
|
using System;
|
||||||
|
using AlicizaX.ObjectPool;
|
||||||
|
using Cysharp.Threading.Tasks;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 基础组件。
|
||||||
|
/// </summary>
|
||||||
|
[DisallowMultipleComponent]
|
||||||
|
[UnityEngine.Scripting.Preserve]
|
||||||
|
public sealed class RootModule : MonoBehaviour
|
||||||
|
{
|
||||||
|
private static RootModule _instance = null;
|
||||||
|
|
||||||
|
public static RootModule Instance
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_instance == null)
|
||||||
|
{
|
||||||
|
_instance = FindObjectOfType<RootModule>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return _instance;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private const int DEFAULT_DPI = 96;
|
||||||
|
|
||||||
|
private float _gameSpeedBeforePause = 1f;
|
||||||
|
|
||||||
|
[SerializeField] private int frameRate = 120;
|
||||||
|
|
||||||
|
[SerializeField] private float gameSpeed = 1f;
|
||||||
|
|
||||||
|
[SerializeField] private bool runInBackground = true;
|
||||||
|
|
||||||
|
[SerializeField] private bool neverSleep = true;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置游戏帧率。
|
||||||
|
/// </summary>
|
||||||
|
public int FrameRate
|
||||||
|
{
|
||||||
|
get => frameRate;
|
||||||
|
set => Application.targetFrameRate = frameRate = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置游戏速度。
|
||||||
|
/// </summary>
|
||||||
|
public float GameSpeed
|
||||||
|
{
|
||||||
|
get => gameSpeed;
|
||||||
|
set => Time.timeScale = gameSpeed = value >= 0f ? value : 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取游戏是否暂停。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsGamePaused => gameSpeed <= 0f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取是否正常游戏速度。
|
||||||
|
/// </summary>
|
||||||
|
public bool IsNormalGameSpeed => Math.Abs(gameSpeed - 1f) < 0.01f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否允许后台运行。
|
||||||
|
/// </summary>
|
||||||
|
public bool RunInBackground
|
||||||
|
{
|
||||||
|
get => runInBackground;
|
||||||
|
set => Application.runInBackground = runInBackground = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取或设置是否禁止休眠。
|
||||||
|
/// </summary>
|
||||||
|
public bool NeverSleep
|
||||||
|
{
|
||||||
|
get => neverSleep;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
neverSleep = value;
|
||||||
|
Screen.sleepTimeout = value ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 暂停游戏。
|
||||||
|
/// </summary>
|
||||||
|
public void PauseGame()
|
||||||
|
{
|
||||||
|
if (IsGamePaused)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_gameSpeedBeforePause = GameSpeed;
|
||||||
|
GameSpeed = 0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 恢复游戏。
|
||||||
|
/// </summary>
|
||||||
|
public void ResumeGame()
|
||||||
|
{
|
||||||
|
if (!IsGamePaused)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameSpeed = _gameSpeedBeforePause;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 重置为正常游戏速度。
|
||||||
|
/// </summary>
|
||||||
|
public void ResetNormalGameSpeed()
|
||||||
|
{
|
||||||
|
if (IsNormalGameSpeed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
GameSpeed = 1f;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 游戏框架组件初始化。
|
||||||
|
/// </summary>
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
_instance = this;
|
||||||
|
DontDestroyOnLoad(this);
|
||||||
|
Utility.Unity.MakeEntity(transform);
|
||||||
|
|
||||||
|
Log.Init();
|
||||||
|
|
||||||
|
Log.Info("Game Version: {0}, Unity Version: {1}", AppVersion.GameVersion, Application.unityVersion);
|
||||||
|
|
||||||
|
Utility.Converter.ScreenDpi = Screen.dpi;
|
||||||
|
if (Utility.Converter.ScreenDpi <= 0)
|
||||||
|
{
|
||||||
|
Utility.Converter.ScreenDpi = DEFAULT_DPI;
|
||||||
|
}
|
||||||
|
|
||||||
|
Application.targetFrameRate = frameRate;
|
||||||
|
Time.timeScale = gameSpeed;
|
||||||
|
Application.runInBackground = runInBackground;
|
||||||
|
Screen.sleepTimeout = neverSleep ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting;
|
||||||
|
|
||||||
|
Application.lowMemory += OnLowMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnApplicationQuit()
|
||||||
|
{
|
||||||
|
Application.lowMemory -= OnLowMemory;
|
||||||
|
StopAllCoroutines();
|
||||||
|
Shutdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
internal void Shutdown()
|
||||||
|
{
|
||||||
|
Destroy(gameObject);
|
||||||
|
Utility.Unity.Shutdown();
|
||||||
|
MemoryPool.ClearAll();
|
||||||
|
Utility.Marshal.FreeCachedHGlobal();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
ModuleSystem.UpdateExecuteList(Time.deltaTime, Time.unscaledDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LateUpdate()
|
||||||
|
{
|
||||||
|
ModuleSystem.UpdateLateExecuteList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FixedUpdate()
|
||||||
|
{
|
||||||
|
ModuleSystem.UpdateFixedExecuteList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDrawGizmos()
|
||||||
|
{
|
||||||
|
ModuleSystem.UpdateGizmosExecuteList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnGUI()
|
||||||
|
{
|
||||||
|
ModuleSystem.UpdateGUIExecuteList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnDestroy()
|
||||||
|
{
|
||||||
|
await UniTask.Yield();
|
||||||
|
ModuleSystem.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void OnLowMemory()
|
||||||
|
{
|
||||||
|
Log.Warning("Low memory reported...");
|
||||||
|
|
||||||
|
IObjectPoolModule objectPoolModule = ModuleSystem.GetModule<IObjectPoolModule>();
|
||||||
|
if (objectPoolModule != null)
|
||||||
|
{
|
||||||
|
objectPoolModule.ReleaseAllUnused();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Base/RootModule.cs.meta
Normal file
3
Runtime/ABase/Base/RootModule.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 252fa1bb9e36411fb4582d0656b987bf
|
||||||
|
timeCreated: 1737362886
|
||||||
8
Runtime/ABase/Base/Version.meta
Normal file
8
Runtime/ABase/Base/Version.meta
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e3e833a043cfd47c1ba1b3fbff22109c
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
28
Runtime/ABase/Base/Version/AppVersion.cs
Normal file
28
Runtime/ABase/Base/Version/AppVersion.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// 版本号类。
|
||||||
|
/// </summary>
|
||||||
|
public static partial class AppVersion
|
||||||
|
{
|
||||||
|
private const string GameFrameworkVersionString = "1.0.0";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取游戏框架版本号。
|
||||||
|
/// </summary>
|
||||||
|
public static string GameFrameworkVersion
|
||||||
|
{
|
||||||
|
get { return GameFrameworkVersionString; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取游戏版本号。
|
||||||
|
/// </summary>
|
||||||
|
public static string GameVersion
|
||||||
|
{
|
||||||
|
get { return Application.version; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Runtime/ABase/Base/Version/AppVersion.cs.meta
Normal file
11
Runtime/ABase/Base/Version/AppVersion.cs.meta
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9d3aeaaff9b2447338611e06c6eca6f6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
3
Runtime/ABase/Event.meta
Normal file
3
Runtime/ABase/Event.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 421689177e8f4c58ae0ce91e5ea9f9c3
|
||||||
|
timeCreated: 1736415505
|
||||||
36
Runtime/ABase/Event/EventRuntimeHandle.cs
Normal file
36
Runtime/ABase/Event/EventRuntimeHandle.cs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using Unity.IL2CPP.CompilerServices;
|
||||||
|
|
||||||
|
namespace AlicizaX
|
||||||
|
{
|
||||||
|
public interface IEventArgs { }
|
||||||
|
|
||||||
|
[AttributeUsage(AttributeTargets.Struct)]
|
||||||
|
public sealed class PrewarmAttribute : Attribute
|
||||||
|
{
|
||||||
|
public int Capacity { get; }
|
||||||
|
public PrewarmAttribute(int capacity) => Capacity = capacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
[Il2CppSetOption(Option.NullChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.DivideByZeroChecks, false)]
|
||||||
|
[Il2CppSetOption(Option.ArrayBoundsChecks, false)]
|
||||||
|
public readonly struct EventRuntimeHandle
|
||||||
|
{
|
||||||
|
private readonly Action<int,int> _unsubscribe;
|
||||||
|
private readonly int _index;
|
||||||
|
private readonly int _version;
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public EventRuntimeHandle(Action<int,int> unsubscribe, int index, int version)
|
||||||
|
{
|
||||||
|
_unsubscribe = unsubscribe;
|
||||||
|
_index = index;
|
||||||
|
_version = version;
|
||||||
|
}
|
||||||
|
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
public void Dispose() => _unsubscribe?.Invoke(_index, _version);
|
||||||
|
}
|
||||||
|
}
|
||||||
3
Runtime/ABase/Event/EventRuntimeHandle.cs.meta
Normal file
3
Runtime/ABase/Event/EventRuntimeHandle.cs.meta
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d85feee75c2d4b54bd6b593fe55145d7
|
||||||
|
timeCreated: 1740488369
|
||||||
74
Runtime/ABase/Event/Il2CppSetOptionAttribute.cs
Normal file
74
Runtime/ABase/Event/Il2CppSetOptionAttribute.cs
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Unity.IL2CPP.CompilerServices
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The code generation options available for IL to C++ conversion.
|
||||||
|
/// Enable or disabled these with caution.
|
||||||
|
/// </summary>
|
||||||
|
public enum Option
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable code generation for null checks.
|
||||||
|
///
|
||||||
|
/// Global null check support is enabled by default when il2cpp.exe
|
||||||
|
/// is launched from the Unity editor.
|
||||||
|
///
|
||||||
|
/// Disabling this will prevent NullReferenceException exceptions from
|
||||||
|
/// being thrown in generated code. In *most* cases, code that dereferences
|
||||||
|
/// a null pointer will crash then. Sometimes the point where the crash
|
||||||
|
/// happens is later than the location where the null reference check would
|
||||||
|
/// have been emitted though.
|
||||||
|
/// </summary>
|
||||||
|
NullChecks = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable code generation for array bounds checks.
|
||||||
|
///
|
||||||
|
/// Global array bounds check support is enabled by default when il2cpp.exe
|
||||||
|
/// is launched from the Unity editor.
|
||||||
|
///
|
||||||
|
/// Disabling this will prevent IndexOutOfRangeException exceptions from
|
||||||
|
/// being thrown in generated code. This will allow reading and writing to
|
||||||
|
/// memory outside of the bounds of an array without any runtime checks.
|
||||||
|
/// Disable this check with extreme caution.
|
||||||
|
/// </summary>
|
||||||
|
ArrayBoundsChecks = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// Enable or disable code generation for divide by zero checks.
|
||||||
|
///
|
||||||
|
/// Global divide by zero check support is disabled by default when il2cpp.exe
|
||||||
|
/// is launched from the Unity editor.
|
||||||
|
///
|
||||||
|
/// Enabling this will cause DivideByZeroException exceptions to be
|
||||||
|
/// thrown in generated code. Most code doesn't need to handle this
|
||||||
|
/// exception, so it is probably safe to leave it disabled.
|
||||||
|
/// </summary>
|
||||||
|
DivideByZeroChecks = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use this attribute on an assembly, struct, class, method, or property to inform the IL2CPP code conversion utility to override the
|
||||||
|
/// global setting for one of a few different runtime checks.
|
||||||
|
///
|
||||||
|
/// Example:
|
||||||
|
///
|
||||||
|
/// [Il2CppSetOption(Option.NullChecks, false)]
|
||||||
|
/// public static string MethodWithNullChecksDisabled()
|
||||||
|
/// {
|
||||||
|
/// var tmp = new Object();
|
||||||
|
/// return tmp.ToString();
|
||||||
|
/// }
|
||||||
|
/// </summary>
|
||||||
|
[AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Struct | AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Delegate, Inherited = false, AllowMultiple = true)]
|
||||||
|
public class Il2CppSetOptionAttribute : Attribute
|
||||||
|
{
|
||||||
|
public Option Option { get; private set; }
|
||||||
|
public object Value { get; private set; }
|
||||||
|
|
||||||
|
public Il2CppSetOptionAttribute(Option option, object value)
|
||||||
|
{
|
||||||
|
Option = option;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Runtime/ABase/Event/Il2CppSetOptionAttribute.cs.meta
Normal file
2
Runtime/ABase/Event/Il2CppSetOptionAttribute.cs.meta
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 997668ad76a5387428e679240d659155
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user