init
This commit is contained in:
commit
bf0d8340af
8
Editor.meta
Normal file
8
Editor.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b73c9e1fb3e5eac40a2114fac7192502
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
19
Editor/AlicizaX.Editor.asmdef
Normal file
19
Editor/AlicizaX.Editor.asmdef
Normal file
@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "AlicizaX.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:75b6f2078d190f14dbda4a5b747d709c",
|
||||
"GUID:2373f786d14518f44b0f475db77ba4de"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
7
Editor/AlicizaX.Editor.asmdef.meta
Normal file
7
Editor/AlicizaX.Editor.asmdef.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: acfef7cabed3b0a42b25edb1cd4fa259
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
Editor/Constant.meta
Normal file
3
Editor/Constant.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1478a6e22f3d4f5e8ff645e5272c8b34
|
||||
timeCreated: 1736931429
|
15
Editor/Constant/ComponentTargetAttribute.cs
Normal file
15
Editor/Constant/ComponentTargetAttribute.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class ComponentTargetAttribute : Attribute
|
||||
{
|
||||
public Type Type;
|
||||
|
||||
public ComponentTargetAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Constant/ComponentTargetAttribute.cs.meta
Normal file
3
Editor/Constant/ComponentTargetAttribute.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27f61e6762d146a0a331a670a8c203fc
|
||||
timeCreated: 1737090681
|
16
Editor/Constant/DisplayNameAttribute.cs
Normal file
16
Editor/Constant/DisplayNameAttribute.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class DisplayNameAttribute:Attribute
|
||||
{
|
||||
public string DisplayName;
|
||||
|
||||
public DisplayNameAttribute(string displayName)
|
||||
{
|
||||
DisplayName = displayName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
Editor/Constant/DisplayNameAttribute.cs.meta
Normal file
3
Editor/Constant/DisplayNameAttribute.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 15a53446355a45549c7060c581d194ac
|
||||
timeCreated: 1737013039
|
3
Editor/EditorWindow.meta
Normal file
3
Editor/EditorWindow.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 99e99734386545c192a5493105e66c77
|
||||
timeCreated: 1737524069
|
96
Editor/EditorWindow/GameFrameworkPreferenceWindow.cs
Normal file
96
Editor/EditorWindow/GameFrameworkPreferenceWindow.cs
Normal file
@ -0,0 +1,96 @@
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.Runtime;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public class GameFrameworkPreferenceWindow : OdinMenuEditorWindow
|
||||
{
|
||||
private List<Type> m_TabTypes;
|
||||
private readonly Dictionary<Type, GameFrameworkTabBase> _tabBases = new();
|
||||
|
||||
[MenuItem("AlicizaX/Preference Window")]
|
||||
public static void ShowWindow()
|
||||
{
|
||||
GetWindow<GameFrameworkPreferenceWindow>(true, "Preference Window");
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
this.position = new Rect(this.position.x, this.position.y, 800, 600);
|
||||
|
||||
var assemblies = Utility.Assembly.GetAssemblies();
|
||||
|
||||
m_TabTypes = new List<Type>();
|
||||
|
||||
foreach (var assembly in assemblies)
|
||||
{
|
||||
var types = assembly.GetTypes();
|
||||
foreach (var type in types)
|
||||
{
|
||||
if (typeof(GameFrameworkTabBase).IsAssignableFrom(type) && type.IsClass && !type.IsAbstract)
|
||||
{
|
||||
var displayNameAttr = (DisplayNameAttribute)Attribute.GetCustomAttribute(type, typeof(DisplayNameAttribute));
|
||||
if (displayNameAttr != null)
|
||||
{
|
||||
m_TabTypes.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_TabTypes = m_TabTypes.OrderBy(t => ((DisplayNameAttribute)Attribute.GetCustomAttribute(t, typeof(DisplayNameAttribute))).DisplayName).ToList();
|
||||
}
|
||||
|
||||
|
||||
protected override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
if (this.MenuTree != null && this.MenuTree.Selection.SelectedValue != null)
|
||||
{
|
||||
var selectTarget = this.MenuTree.Selection.SelectedValue;
|
||||
if (selectTarget != null)
|
||||
{
|
||||
var selectType = selectTarget.GetType();
|
||||
if (_tabBases.TryGetValue(selectType, out GameFrameworkTabBase tab))
|
||||
{
|
||||
tab.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override OdinMenuTree BuildMenuTree()
|
||||
{
|
||||
var tree = new OdinMenuTree();
|
||||
foreach (var tabType in m_TabTypes)
|
||||
{
|
||||
DisplayNameAttribute displayNameAttribute = (DisplayNameAttribute)Attribute.GetCustomAttribute(tabType, typeof(DisplayNameAttribute));
|
||||
GameFrameworkTabBase instance = (GameFrameworkTabBase)Activator.CreateInstance(tabType);
|
||||
_tabBases.Add(tabType, instance);
|
||||
tree.Add(displayNameAttribute.DisplayName, instance);
|
||||
}
|
||||
|
||||
tree.Selection.SelectionChanged += SelectionOnSelectionChanged;
|
||||
return tree;
|
||||
}
|
||||
|
||||
private void SelectionOnSelectionChanged(SelectionChangedType obj)
|
||||
{
|
||||
var selectTarget = this.MenuTree.Selection.SelectedValue;
|
||||
if (selectTarget != null)
|
||||
{
|
||||
var selectType = selectTarget.GetType();
|
||||
if (_tabBases.TryGetValue(selectType, out GameFrameworkTabBase tab))
|
||||
{
|
||||
tab.Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 305213ea3645462caff0daecd6be32d3
|
||||
timeCreated: 1737012834
|
12
Editor/EditorWindow/GameFrameworkTabBase.cs
Normal file
12
Editor/EditorWindow/GameFrameworkTabBase.cs
Normal file
@ -0,0 +1,12 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public abstract class GameFrameworkTabBase
|
||||
{
|
||||
protected internal virtual void Save()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/EditorWindow/GameFrameworkTabBase.cs.meta
Normal file
3
Editor/EditorWindow/GameFrameworkTabBase.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df5db70793c4475d9de5654c637a7ea1
|
||||
timeCreated: 1737010059
|
8
Editor/HybridCLR.meta
Normal file
8
Editor/HybridCLR.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 596231b03a2cf834d8b2833300d9f524
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
106
Editor/HybridCLR/BuildDLLCommand.cs
Normal file
106
Editor/HybridCLR/BuildDLLCommand.cs
Normal file
@ -0,0 +1,106 @@
|
||||
#if ENABLE_HYBRIDCLR
|
||||
using HybridCLR.Editor;
|
||||
using HybridCLR.Editor.Commands;
|
||||
#endif
|
||||
using AlicizaX.Editor;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class BuildDLLCommand
|
||||
{
|
||||
private const string EnableHybridClrScriptingDefineSymbol = "ENABLE_HYBRIDCLR";
|
||||
|
||||
static BuildDLLCommand()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 禁用HybridCLR宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/HybridCLR/Define Symbols/Disable HybridCLR", false, 30)]
|
||||
public static void Disable()
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol);
|
||||
HybridCLR.Editor.SettingsUtil.Enable = false;
|
||||
SyncAssemblyContent.RefreshAssembly();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启HybridCLR宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/HybridCLR/Define Symbols/Enable HybridCLR", false, 31)]
|
||||
public static void Enable()
|
||||
{
|
||||
ScriptingDefineSymbols.RemoveScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol);
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableHybridClrScriptingDefineSymbol);
|
||||
HybridCLR.Editor.SettingsUtil.Enable = true;
|
||||
SyncAssemblyContent.RefreshAssembly();
|
||||
}
|
||||
|
||||
#if ENABLE_HYBRIDCLR
|
||||
[MenuItem("AlicizaX/HybridCLR/Build/BuildAssets And CopyTo AssemblyTextAssetPath")]
|
||||
public static void BuildAndCopyDlls()
|
||||
{
|
||||
|
||||
BuildTarget target = EditorUserBuildSettings.activeBuildTarget;
|
||||
CompileDllCommand.CompileDll(target);
|
||||
CopyAOTHotUpdateDlls(target);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void BuildAndCopyDlls(BuildTarget target)
|
||||
{
|
||||
#if ENABLE_HYBRIDCLR
|
||||
CompileDllCommand.CompileDll(target);
|
||||
CopyAOTHotUpdateDlls(target);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CopyAOTHotUpdateDlls(BuildTarget target)
|
||||
{
|
||||
CopyAOTAssembliesToAssetPath();
|
||||
CopyHotUpdateAssembliesToAssetPath();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
public static void CopyAOTAssembliesToAssetPath()
|
||||
{
|
||||
#if ENABLE_HYBRIDCLR
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
string aotAssembliesSrcDir = SettingsUtil.GetAssembliesPostIl2CppStripDir(target);
|
||||
string aotAssembliesDstDir = Application.dataPath + "/" + ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>().AssemblyTextAssetPath;
|
||||
|
||||
foreach (var dll in ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>().AOTMetaAssemblies)
|
||||
{
|
||||
string srcDllPath = $"{aotAssembliesSrcDir}/{dll}";
|
||||
if (!System.IO.File.Exists(srcDllPath))
|
||||
{
|
||||
Debug.LogError($"ab中添加AOT补充元数据dll:{srcDllPath} 时发生错误,文件不存在。裁剪后的AOT dll在BuildPlayer时才能生成,因此需要你先构建一次游戏App后再打包。");
|
||||
continue;
|
||||
}
|
||||
|
||||
string dllBytesPath = $"{aotAssembliesDstDir}/{dll}.bytes";
|
||||
System.IO.File.Copy(srcDllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyAOTAssembliesToStreamingAssets] copy AOT dll {srcDllPath} -> {dllBytesPath}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void CopyHotUpdateAssembliesToAssetPath()
|
||||
{
|
||||
#if ENABLE_HYBRIDCLR
|
||||
var target = EditorUserBuildSettings.activeBuildTarget;
|
||||
|
||||
string hotfixDllSrcDir = SettingsUtil.GetHotUpdateDllsOutputDirByTarget(target);
|
||||
string hotfixAssembliesDstDir = Application.dataPath + "/" + ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>().AssemblyTextAssetPath;
|
||||
foreach (var dll in SettingsUtil.HotUpdateAssemblyFilesExcludePreserved)
|
||||
{
|
||||
string dllPath = $"{hotfixDllSrcDir}/{dll}";
|
||||
string dllBytesPath = $"{hotfixAssembliesDstDir}/{dll}.bytes";
|
||||
System.IO.File.Copy(dllPath, dllBytesPath, true);
|
||||
Debug.Log($"[CopyHotUpdateAssembliesToStreamingAssets] copy hotfix dll {dllPath} -> {dllBytesPath}");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
3
Editor/HybridCLR/BuildDLLCommand.cs.meta
Normal file
3
Editor/HybridCLR/BuildDLLCommand.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0761954ba63648b8b73f8ebb736bb9eb
|
||||
timeCreated: 1737524294
|
37
Editor/HybridCLR/HybridCLRSettingTab.cs
Normal file
37
Editor/HybridCLR/HybridCLRSettingTab.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.Editor;
|
||||
using Sirenix.OdinInspector;
|
||||
using Sirenix.OdinInspector.Editor;
|
||||
using Sirenix.Serialization;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
[DisplayName("热更设置")]
|
||||
[Serializable]
|
||||
internal sealed class HybridCLRSettingTab : GameFrameworkTabBase
|
||||
{
|
||||
[Required][InlineEditor(InlineEditorObjectFieldModes.CompletelyHidden)][DisableInPlayMode] [HideLabel]
|
||||
public FrameworkHotUpdateSettings FrameworkHotUpdateSettings;
|
||||
|
||||
public HybridCLRSettingTab()
|
||||
{
|
||||
FrameworkHotUpdateSettings = ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>();
|
||||
}
|
||||
|
||||
[Sirenix.OdinInspector.Button(ButtonSizes.Large)]
|
||||
protected void RefreshAssembly()
|
||||
{
|
||||
SyncAssemblyContent.RefreshAssembly();
|
||||
}
|
||||
|
||||
protected internal override void Save()
|
||||
{
|
||||
base.Save();
|
||||
EditorUtility.SetDirty(FrameworkHotUpdateSettings);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/HybridCLR/HybridCLRSettingTab.cs.meta
Normal file
3
Editor/HybridCLR/HybridCLRSettingTab.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ab21809ce8ad4d5ebe950b70107deb00
|
||||
timeCreated: 1737525094
|
15
Editor/HybridCLR/SynAssemblysContent.cs
Normal file
15
Editor/HybridCLR/SynAssemblysContent.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using UnityEditor;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public static class SyncAssemblyContent
|
||||
{
|
||||
public static void RefreshAssembly()
|
||||
{
|
||||
ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>().HotUpdateAssemblies = HybridCLR.Editor.SettingsUtil.HotUpdateAssemblyFilesIncludePreserved;
|
||||
ScriptableSingletonUtil.Get<FrameworkHotUpdateSettings>().AOTMetaAssemblies = HybridCLR.Editor.SettingsUtil.AOTAssemblyNames;
|
||||
AssetDatabase.Refresh();
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/HybridCLR/SynAssemblysContent.cs.meta
Normal file
3
Editor/HybridCLR/SynAssemblysContent.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c08b751d385441058a634280266803eb
|
||||
timeCreated: 1737524480
|
3
Editor/Inspector.meta
Normal file
3
Editor/Inspector.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6a6566b690eb46c3acc8685a8ccabfeb
|
||||
timeCreated: 1737362727
|
139
Editor/Inspector/BaseComponentInspector.cs
Normal file
139
Editor/Inspector/BaseComponentInspector.cs
Normal file
@ -0,0 +1,139 @@
|
||||
using AlicizaX;
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[CustomEditor(typeof(BaseComponent))]
|
||||
internal sealed class BaseComponentInspector : 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 m_FrameRate = null;
|
||||
private SerializedProperty m_GameSpeed = null;
|
||||
private SerializedProperty m_RunInBackground = null;
|
||||
private SerializedProperty m_NeverSleep = null;
|
||||
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
BaseComponent t = (BaseComponent) target;
|
||||
|
||||
|
||||
|
||||
int frameRate = EditorGUILayout.IntSlider("Frame Rate", m_FrameRate.intValue, 1, 120);
|
||||
if (frameRate != m_FrameRate.intValue)
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
t.FrameRate = frameRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FrameRate.intValue = frameRate;
|
||||
}
|
||||
}
|
||||
|
||||
EditorGUILayout.BeginVertical("box");
|
||||
{
|
||||
float gameSpeed = EditorGUILayout.Slider("Game Speed", m_GameSpeed.floatValue, 0f, 8f);
|
||||
int selectedGameSpeed = GUILayout.SelectionGrid(GetSelectedGameSpeed(gameSpeed), GameSpeedForDisplay, 5);
|
||||
if (selectedGameSpeed >= 0)
|
||||
{
|
||||
gameSpeed = GetGameSpeed(selectedGameSpeed);
|
||||
}
|
||||
|
||||
if (gameSpeed != m_GameSpeed.floatValue)
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
t.GameSpeed = gameSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_GameSpeed.floatValue = gameSpeed;
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndVertical();
|
||||
|
||||
bool runInBackground = EditorGUILayout.Toggle("Run in Background", m_RunInBackground.boolValue);
|
||||
if (runInBackground != m_RunInBackground.boolValue)
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
t.RunInBackground = runInBackground;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_RunInBackground.boolValue = runInBackground;
|
||||
}
|
||||
}
|
||||
|
||||
bool neverSleep = EditorGUILayout.Toggle("Never Sleep", m_NeverSleep.boolValue);
|
||||
if (neverSleep != m_NeverSleep.boolValue)
|
||||
{
|
||||
if (EditorApplication.isPlaying)
|
||||
{
|
||||
t.NeverSleep = neverSleep;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_NeverSleep.boolValue = neverSleep;
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
protected override void OnCompileComplete()
|
||||
{
|
||||
base.OnCompileComplete();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
m_FrameRate = serializedObject.FindProperty("m_FrameRate");
|
||||
m_GameSpeed = serializedObject.FindProperty("m_GameSpeed");
|
||||
m_RunInBackground = serializedObject.FindProperty("m_RunInBackground");
|
||||
m_NeverSleep = serializedObject.FindProperty("m_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 (gameSpeed == GameSpeed[i])
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
11
Editor/Inspector/BaseComponentInspector.cs.meta
Normal file
11
Editor/Inspector/BaseComponentInspector.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:
|
79
Editor/Inspector/ComponentTypeComponentInspector.cs
Normal file
79
Editor/Inspector/ComponentTypeComponentInspector.cs
Normal file
@ -0,0 +1,79 @@
|
||||
using System.Collections.Generic;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public abstract class ComponentTypeComponentInspector : GameFrameworkInspector
|
||||
{
|
||||
protected SerializedProperty ComponentType = null;
|
||||
protected string[] ComponentTypeNames = null;
|
||||
protected int ComponentTypeNameIndex = 0;
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUI.BeginDisabledGroup(EditorApplication.isPlayingOrWillChangePlaymode);
|
||||
{
|
||||
int componentTypeSelectedIndex = EditorGUILayout.Popup("ComponentType", ComponentTypeNameIndex, ComponentTypeNames);
|
||||
if (componentTypeSelectedIndex != ComponentTypeNameIndex)
|
||||
{
|
||||
ComponentTypeNameIndex = componentTypeSelectedIndex;
|
||||
|
||||
ComponentType.stringValue = componentTypeSelectedIndex <= 0 ? null : ComponentTypeNames[componentTypeSelectedIndex];
|
||||
}
|
||||
}
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
protected override void OnCompileComplete()
|
||||
{
|
||||
base.OnCompileComplete();
|
||||
|
||||
RefreshTypeNames();
|
||||
}
|
||||
|
||||
protected virtual void Enable()
|
||||
{
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
ComponentType = serializedObject.FindProperty("componentType");
|
||||
Enable();
|
||||
RefreshTypeNames();
|
||||
}
|
||||
|
||||
protected abstract void RefreshTypeNames();
|
||||
|
||||
protected void RefreshComponentTypeNames(System.Type type)
|
||||
{
|
||||
List<string> managerTypeNames = new List<string>
|
||||
{
|
||||
NoneOptionName
|
||||
};
|
||||
|
||||
managerTypeNames.AddRange(Utility.Assembly.GetRuntimeTypeNames(type));
|
||||
ComponentTypeNames = managerTypeNames.ToArray();
|
||||
ComponentTypeNameIndex = 0;
|
||||
if (!ComponentType.stringValue.IsNullOrEmpty())
|
||||
{
|
||||
ComponentTypeNameIndex = managerTypeNames.IndexOf(ComponentType.stringValue);
|
||||
if (ComponentTypeNameIndex <= 0)
|
||||
{
|
||||
ComponentTypeNameIndex = 0;
|
||||
ComponentType.stringValue = null;
|
||||
}
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/ComponentTypeComponentInspector.cs.meta
Normal file
3
Editor/Inspector/ComponentTypeComponentInspector.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd05e24936f94181ad58fb5c7b3c1e38
|
||||
timeCreated: 1712812404
|
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:
|
145
Editor/Inspector/ObjectPoolComponentInspector.cs
Normal file
145
Editor/Inspector/ObjectPoolComponentInspector.cs
Normal file
@ -0,0 +1,145 @@
|
||||
using AlicizaX;
|
||||
using AlicizaX.ObjectPool;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[CustomEditor(typeof(ObjectPoolComponent))]
|
||||
internal sealed class ObjectPoolComponentInspector : ComponentTypeComponentInspector
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
protected override void RefreshTypeNames()
|
||||
{
|
||||
RefreshComponentTypeNames(typeof(IObjectPoolManager));
|
||||
}
|
||||
|
||||
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/Inspector/ObjectPoolComponentInspector.cs.meta
Normal file
11
Editor/Inspector/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:
|
150
Editor/Inspector/ReferencePoolComponentInspector.cs
Normal file
150
Editor/Inspector/ReferencePoolComponentInspector.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using AlicizaX;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[CustomEditor(typeof(ReferencePoolComponent))]
|
||||
internal sealed class ReferencePoolComponentInspector : GameFrameworkInspector
|
||||
{
|
||||
private readonly Dictionary<string, List<ReferencePoolInfo>> m_ReferencePoolInfos = new Dictionary<string, List<ReferencePoolInfo>>(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();
|
||||
|
||||
ReferencePoolComponent t = (ReferencePoolComponent)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", ReferencePool.Count.ToString());
|
||||
m_ShowFullClassName = EditorGUILayout.Toggle("Show Full Class Name", m_ShowFullClassName);
|
||||
m_ReferencePoolInfos.Clear();
|
||||
ReferencePoolInfo[] referencePoolInfos = ReferencePool.GetAllReferencePoolInfos();
|
||||
foreach (ReferencePoolInfo referencePoolInfo in referencePoolInfos)
|
||||
{
|
||||
string assemblyName = referencePoolInfo.Type.Assembly.GetName().Name;
|
||||
List<ReferencePoolInfo> results = null;
|
||||
if (!m_ReferencePoolInfos.TryGetValue(assemblyName, out results))
|
||||
{
|
||||
results = new List<ReferencePoolInfo>();
|
||||
m_ReferencePoolInfos.Add(assemblyName, results);
|
||||
}
|
||||
|
||||
results.Add(referencePoolInfo);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<string, List<ReferencePoolInfo>> 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 (ReferencePoolInfo 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 (ReferencePoolInfo referencePoolInfo in assemblyReferencePoolInfo.Value)
|
||||
{
|
||||
data[index++] = Utility.Text.Format("{0},{1},{2},{3},{4},{5},{6},{7}", referencePoolInfo.Type.Name, referencePoolInfo.Type.FullName, referencePoolInfo.UnusedReferenceCount, referencePoolInfo.UsingReferenceCount, referencePoolInfo.AcquireReferenceCount, referencePoolInfo.ReleaseReferenceCount, referencePoolInfo.AddReferenceCount, referencePoolInfo.RemoveReferenceCount);
|
||||
}
|
||||
|
||||
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(ReferencePoolInfo 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.UnusedReferenceCount, referencePoolInfo.UsingReferenceCount, referencePoolInfo.AcquireReferenceCount, referencePoolInfo.ReleaseReferenceCount, referencePoolInfo.AddReferenceCount, referencePoolInfo.RemoveReferenceCount));
|
||||
#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.UnusedReferenceCount, referencePoolInfo.UsingReferenceCount, referencePoolInfo.AcquireReferenceCount, referencePoolInfo.ReleaseReferenceCount, referencePoolInfo.AddReferenceCount, referencePoolInfo.RemoveReferenceCount));
|
||||
#endif
|
||||
}
|
||||
|
||||
private int Comparison(ReferencePoolInfo a, ReferencePoolInfo b)
|
||||
{
|
||||
if (m_ShowFullClassName)
|
||||
{
|
||||
return a.Type.FullName.CompareTo(b.Type.FullName);
|
||||
}
|
||||
else
|
||||
{
|
||||
return a.Type.Name.CompareTo(b.Type.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Editor/Inspector/ReferencePoolComponentInspector.cs.meta
Normal file
11
Editor/Inspector/ReferencePoolComponentInspector.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:
|
3
Editor/Misc.meta
Normal file
3
Editor/Misc.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6d5d730968b49849be897d89a8b9049
|
||||
timeCreated: 1736410513
|
91
Editor/Misc/HelperInfo.cs
Normal file
91
Editor/Misc/HelperInfo.cs
Normal file
@ -0,0 +1,91 @@
|
||||
using AlicizaX;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public sealed class HelperInfo<T> where T : MonoBehaviour
|
||||
{
|
||||
private const string CustomOptionName = "<Custom>";
|
||||
|
||||
private readonly string m_Name;
|
||||
|
||||
private SerializedProperty m_HelperTypeName;
|
||||
private SerializedProperty m_CustomHelper;
|
||||
private string[] m_HelperTypeNames;
|
||||
private int m_HelperTypeNameIndex;
|
||||
|
||||
public HelperInfo(string name)
|
||||
{
|
||||
m_Name = name;
|
||||
|
||||
m_HelperTypeName = null;
|
||||
m_CustomHelper = null;
|
||||
m_HelperTypeNames = null;
|
||||
m_HelperTypeNameIndex = 0;
|
||||
}
|
||||
|
||||
public void Init(SerializedObject serializedObject)
|
||||
{
|
||||
m_HelperTypeName = serializedObject.FindProperty(Utility.Text.Format("m_{0}HelperTypeName", m_Name));
|
||||
m_CustomHelper = serializedObject.FindProperty(Utility.Text.Format("m_Custom{0}Helper", m_Name));
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
string displayName = FieldNameForDisplay(m_Name);
|
||||
int selectedIndex = EditorGUILayout.Popup(Utility.Text.Format("{0} Helper", displayName), m_HelperTypeNameIndex, m_HelperTypeNames);
|
||||
if (selectedIndex != m_HelperTypeNameIndex)
|
||||
{
|
||||
m_HelperTypeNameIndex = selectedIndex;
|
||||
m_HelperTypeName.stringValue = selectedIndex <= 0 ? null : m_HelperTypeNames[selectedIndex];
|
||||
}
|
||||
|
||||
if (m_HelperTypeNameIndex <= 0)
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_CustomHelper);
|
||||
if (m_CustomHelper.objectReferenceValue == null)
|
||||
{
|
||||
EditorGUILayout.HelpBox(Utility.Text.Format("You must set Custom {0} Helper.", displayName), MessageType.Error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
List<string> helperTypeNameList = new List<string>
|
||||
{
|
||||
CustomOptionName
|
||||
};
|
||||
|
||||
helperTypeNameList.AddRange(Utility.Assembly.GetRuntimeTypeNames(typeof(T)));
|
||||
m_HelperTypeNames = helperTypeNameList.ToArray();
|
||||
|
||||
m_HelperTypeNameIndex = 0;
|
||||
if (!string.IsNullOrEmpty(m_HelperTypeName.stringValue))
|
||||
{
|
||||
m_HelperTypeNameIndex = helperTypeNameList.IndexOf(m_HelperTypeName.stringValue);
|
||||
if (m_HelperTypeNameIndex <= 0)
|
||||
{
|
||||
m_HelperTypeNameIndex = 0;
|
||||
m_HelperTypeName.stringValue = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string FieldNameForDisplay(string fieldName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fieldName))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
string str = Regex.Replace(fieldName, @"^m_", string.Empty);
|
||||
str = Regex.Replace(str, @"((?<=[a-z])[A-Z]|[A-Z](?=[a-z]))", @" $1").TrimStart();
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
11
Editor/Misc/HelperInfo.cs.meta
Normal file
11
Editor/Misc/HelperInfo.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ff85bf9d2c44a14d90f78221024499e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
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("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("AlicizaX/Scripting Define Symbols/Enable All Logs", false, 31)]
|
||||
public static void EnableAllLogs()
|
||||
{
|
||||
DisableAllLogs();
|
||||
ScriptingDefineSymbols.AddScriptingDefineSymbol(EnableLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启调试及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Scripting Define Symbols/Enable Debug And Above Logs", false, 32)]
|
||||
public static void EnableDebugAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableDebugAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启信息及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Scripting Define Symbols/Enable Info And Above Logs", false, 33)]
|
||||
public static void EnableInfoAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableInfoAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启警告及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Scripting Define Symbols/Enable Warning And Above Logs", false, 34)]
|
||||
public static void EnableWarningAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableWarningAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启错误及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Scripting Define Symbols/Enable Error And Above Logs", false, 35)]
|
||||
public static void EnableErrorAndAboveLogs()
|
||||
{
|
||||
SetAboveLogScriptingDefineSymbol(EnableErrorAndAboveLogScriptingDefineSymbol);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 开启严重错误及以上级别的日志脚本宏定义。
|
||||
/// </summary>
|
||||
[MenuItem("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:
|
85
Editor/Misc/OpenFolder.cs
Normal file
85
Editor/Misc/OpenFolder.cs
Normal file
@ -0,0 +1,85 @@
|
||||
using AlicizaX;
|
||||
using System.Diagnostics;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
/// <summary>
|
||||
/// 打开文件夹相关的实用函数。
|
||||
/// </summary>
|
||||
public static class OpenFolder
|
||||
{
|
||||
/// <summary>
|
||||
/// 打开 Data Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Open Folder/Data Path", false, 10)]
|
||||
public static void OpenFolderDataPath()
|
||||
{
|
||||
Execute(Application.dataPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Persistent Data Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Open Folder/Persistent Data Path", false, 11)]
|
||||
public static void OpenFolderPersistentDataPath()
|
||||
{
|
||||
Execute(Application.persistentDataPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Streaming Assets Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("AlicizaX/Open Folder/Streaming Assets Path", false, 12)]
|
||||
public static void OpenFolderStreamingAssetsPath()
|
||||
{
|
||||
Execute(Application.streamingAssetsPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 打开 Temporary Cache Path 文件夹。
|
||||
/// </summary>
|
||||
[MenuItem("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("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:
|
40
Editor/Misc/ScriptableSingletonUtil.cs
Normal file
40
Editor/Misc/ScriptableSingletonUtil.cs
Normal file
@ -0,0 +1,40 @@
|
||||
using System;
|
||||
using AlicizaX.Runtime;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
public static class ScriptableSingletonUtil
|
||||
{
|
||||
public static T Get<T>() where T : ScriptableObject
|
||||
{
|
||||
string assetType = typeof(T).Name;
|
||||
T globalSetting = default;
|
||||
string[] globalAssetPaths = UnityEditor.AssetDatabase.FindAssets($"t:{assetType}");
|
||||
if (globalAssetPaths.Length > 1)
|
||||
{
|
||||
foreach (var assetPath in globalAssetPaths)
|
||||
{
|
||||
Debug.LogError($"Could not had Multiple {assetType}. Repeated Path: {UnityEditor.AssetDatabase.GUIDToAssetPath(assetPath)}");
|
||||
}
|
||||
|
||||
throw new Exception($"Could not had Multiple {assetType}");
|
||||
}
|
||||
|
||||
if (globalAssetPaths.Length == 1)
|
||||
{
|
||||
string path = UnityEditor.AssetDatabase.GUIDToAssetPath(globalAssetPaths[0]);
|
||||
globalSetting = UnityEditor.AssetDatabase.LoadAssetAtPath<T>(path);
|
||||
}
|
||||
|
||||
|
||||
if (globalSetting == null)
|
||||
{
|
||||
Debug.LogError($"Could not found {assetType} asset");
|
||||
return null;
|
||||
}
|
||||
|
||||
return globalSetting;
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Misc/ScriptableSingletonUtil.cs.meta
Normal file
3
Editor/Misc/ScriptableSingletonUtil.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7544b657bf904330859e64362e5098a8
|
||||
timeCreated: 1737536609
|
150
Editor/Misc/ScriptingDefineSymbols.cs
Normal file
150
Editor/Misc/ScriptingDefineSymbols.cs
Normal file
@ -0,0 +1,150 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
|
||||
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)
|
||||
{
|
||||
return PlayerSettings.GetScriptingDefineSymbolsForGroup(buildTargetGroup).Split(';');
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置指定平台的脚本宏定义。
|
||||
/// </summary>
|
||||
/// <param name="buildTargetGroup">要设置脚本宏定义的平台。</param>
|
||||
/// <param name="scriptingDefineSymbols">要设置的脚本宏定义。</param>
|
||||
public static void SetScriptingDefineSymbols(BuildTargetGroup buildTargetGroup, string[] scriptingDefineSymbols)
|
||||
{
|
||||
PlayerSettings.SetScriptingDefineSymbolsForGroup(buildTargetGroup, string.Join(";", scriptingDefineSymbols));
|
||||
}
|
||||
}
|
||||
}
|
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.Runtime;
|
||||
|
||||
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:
|
3
Editor/Publisher.meta
Normal file
3
Editor/Publisher.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 33e7b1423d7c447a984510c0d398311f
|
||||
timeCreated: 1737530322
|
26
Editor/Publisher/FrameworkPublisherSettingTab.cs
Normal file
26
Editor/Publisher/FrameworkPublisherSettingTab.cs
Normal file
@ -0,0 +1,26 @@
|
||||
using AlicizaX.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
|
||||
namespace AlicizaX.Editor
|
||||
{
|
||||
[System.Serializable]
|
||||
[DisplayName("发布设置")]
|
||||
internal sealed class FrameworkPublisherSettingTab : GameFrameworkTabBase
|
||||
{
|
||||
[Required] [InlineEditor(InlineEditorObjectFieldModes.CompletelyHidden)] [DisableInPlayMode] [HideLabel]
|
||||
public FrameworkPublishSettings FrameworkPublishSettings;
|
||||
|
||||
public FrameworkPublisherSettingTab()
|
||||
{
|
||||
FrameworkPublishSettings = ScriptableSingletonUtil.Get<FrameworkPublishSettings>();
|
||||
}
|
||||
|
||||
protected internal override void Save()
|
||||
{
|
||||
base.Save();
|
||||
EditorUtility.SetDirty(FrameworkPublishSettings);
|
||||
AssetDatabase.SaveAssets();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Publisher/FrameworkPublisherSettingTab.cs.meta
Normal file
3
Editor/Publisher/FrameworkPublisherSettingTab.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a6011b6ff89947deb4077e2578ad897e
|
||||
timeCreated: 1737536018
|
8
Plugins.meta
Normal file
8
Plugins.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01e1cc22fd7cf9b4db27fb012d38717b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
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:
|
8
Resources.meta
Normal file
8
Resources.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54ef4f369757e0d4da4a7095678088b6
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
30
Resources/FrameworkHotUpdateSettings.asset
Normal file
30
Resources/FrameworkHotUpdateSettings.asset
Normal file
@ -0,0 +1,30 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 7c0f00a264c34df985e6c6b6e3f8b353, type: 3}
|
||||
m_Name: FrameworkHotUpdateSettings
|
||||
m_EditorClassIdentifier:
|
||||
HotUpdateAssemblies:
|
||||
- GameLib.dll
|
||||
- GameProto.dll
|
||||
- GameBase.dll
|
||||
- GameLogic.dll
|
||||
AOTMetaAssemblies:
|
||||
- mscorlib.dll
|
||||
- System.dll
|
||||
- System.Core.dll
|
||||
- UnityEngine.CoreModule.dll
|
||||
- YooAsset.Runtime.dll
|
||||
- UniTask.Runtime.dll
|
||||
- ZString.dll
|
||||
LogicMainDllName: GameLogic.dll
|
||||
AssemblyTextAssetExtension: .bytes
|
||||
AssemblyTextAssetPath: AssetRaw/DLL
|
8
Resources/FrameworkHotUpdateSettings.asset.meta
Normal file
8
Resources/FrameworkHotUpdateSettings.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: efd2da5560bdcde42a91ff632fccad20
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
22
Resources/FrameworkPublishSettings.asset
Normal file
22
Resources/FrameworkPublishSettings.asset
Normal file
@ -0,0 +1,22 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 7f734b9c80c9475690a0edad9a7626bd, type: 3}
|
||||
m_Name: FrameworkPublishSettings
|
||||
m_EditorClassIdentifier:
|
||||
Configs:
|
||||
- Version_Type: Release
|
||||
CheckUrl: http://127.0.0.1:8080/UpdateData.json
|
||||
- Version_Type: Dev
|
||||
CheckUrl: http://127.0.0.1:8080/UpdateData.json
|
||||
- Version_Type: Test
|
||||
CheckUrl: http://127.0.0.1:8080/UpdateData.json
|
||||
AppStageType: Dev
|
8
Resources/FrameworkPublishSettings.asset.meta
Normal file
8
Resources/FrameworkPublishSettings.asset.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: db8426664259b2946b313fa434c0e847
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Runtime.meta
Normal file
8
Runtime.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ab3c5927fe6e974c92865c4452d9c99
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
17
Runtime/AlicizaX.Runtime.asmdef
Normal file
17
Runtime/AlicizaX.Runtime.asmdef
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "AlicizaX.Runtime",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:33661e06c33d31b4c9223810bf503247",
|
||||
"GUID:f51ebe6a0ceec4240a699833d6309b23"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": true,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
7
Runtime/AlicizaX.Runtime.asmdef.meta
Normal file
7
Runtime/AlicizaX.Runtime.asmdef.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 75b6f2078d190f14dbda4a5b747d709c
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
3
Runtime/Base.meta
Normal file
3
Runtime/Base.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17ad22f068c740e7a51303c78a742268
|
||||
timeCreated: 1736324891
|
167
Runtime/Base/BaseComponent.cs
Normal file
167
Runtime/Base/BaseComponent.cs
Normal file
@ -0,0 +1,167 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 基础组件。
|
||||
/// </summary>
|
||||
[DisallowMultipleComponent]
|
||||
[AddComponentMenu("Game Framework/Base")]
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public sealed class BaseComponent : GameFrameworkComponent
|
||||
{
|
||||
private const int DefaultDpi = 96;
|
||||
|
||||
private float m_GameSpeedBeforePause = 1f;
|
||||
|
||||
[SerializeField] private int m_FrameRate = 30;
|
||||
|
||||
[SerializeField] private float m_GameSpeed = 1f;
|
||||
|
||||
[SerializeField] private bool m_RunInBackground = true;
|
||||
|
||||
[SerializeField] private bool m_NeverSleep = true;
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置游戏帧率。
|
||||
/// </summary>
|
||||
public int FrameRate
|
||||
{
|
||||
get { return m_FrameRate; }
|
||||
set { Application.targetFrameRate = m_FrameRate = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置游戏速度。
|
||||
/// </summary>
|
||||
public float GameSpeed
|
||||
{
|
||||
get { return m_GameSpeed; }
|
||||
set { Time.timeScale = m_GameSpeed = value >= 0f ? value : 0f; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取游戏是否暂停。
|
||||
/// </summary>
|
||||
public bool IsGamePaused
|
||||
{
|
||||
get { return m_GameSpeed <= 0f; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取是否正常游戏速度。
|
||||
/// </summary>
|
||||
public bool IsNormalGameSpeed
|
||||
{
|
||||
get { return m_GameSpeed == 1f; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否允许后台运行。
|
||||
/// </summary>
|
||||
public bool RunInBackground
|
||||
{
|
||||
get { return m_RunInBackground; }
|
||||
set { Application.runInBackground = m_RunInBackground = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取或设置是否禁止休眠。
|
||||
/// </summary>
|
||||
public bool NeverSleep
|
||||
{
|
||||
get { return m_NeverSleep; }
|
||||
set
|
||||
{
|
||||
m_NeverSleep = value;
|
||||
Screen.sleepTimeout = value ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 游戏框架组件初始化。
|
||||
/// </summary>
|
||||
protected override void Awake()
|
||||
{
|
||||
IsAutoRegister = false;
|
||||
base.Awake();
|
||||
|
||||
GameModuleMonoProxy _monoProxyProxy = new GameObject("GameModuleMonoProxy").AddComponent<GameModuleMonoProxy>();
|
||||
_monoProxyProxy.gameObject.hideFlags = HideFlags.HideInHierarchy | HideFlags.HideInInspector;
|
||||
|
||||
|
||||
DontDestroyOnLoad(this);
|
||||
|
||||
Utility.Unity.MakeEntity(transform);
|
||||
|
||||
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 = DefaultDpi;
|
||||
}
|
||||
|
||||
|
||||
Application.targetFrameRate = m_FrameRate;
|
||||
Time.timeScale = m_GameSpeed;
|
||||
Application.runInBackground = m_RunInBackground;
|
||||
Screen.sleepTimeout = m_NeverSleep ? SleepTimeout.NeverSleep : SleepTimeout.SystemSetting;
|
||||
}
|
||||
|
||||
private void OnApplicationQuit()
|
||||
{
|
||||
StopAllCoroutines();
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 暂停游戏。
|
||||
/// </summary>
|
||||
public void PauseGame()
|
||||
{
|
||||
if (IsGamePaused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_GameSpeedBeforePause = GameSpeed;
|
||||
GameSpeed = 0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 恢复游戏。
|
||||
/// </summary>
|
||||
public void ResumeGame()
|
||||
{
|
||||
if (!IsGamePaused)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameSpeed = m_GameSpeedBeforePause;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 重置为正常游戏速度。
|
||||
/// </summary>
|
||||
public void ResetNormalGameSpeed()
|
||||
{
|
||||
if (IsNormalGameSpeed)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameSpeed = 1f;
|
||||
}
|
||||
|
||||
internal void Shutdown()
|
||||
{
|
||||
Destroy(gameObject);
|
||||
Utility.Unity.Shutdown();
|
||||
ReferencePool.ClearAll();
|
||||
Utility.Marshal.FreeCachedHGlobal();
|
||||
}
|
||||
}
|
||||
}
|
3
Runtime/Base/BaseComponent.cs.meta
Normal file
3
Runtime/Base/BaseComponent.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 252fa1bb9e36411fb4582d0656b987bf
|
||||
timeCreated: 1737362886
|
8
Runtime/Base/DataStruct.meta
Normal file
8
Runtime/Base/DataStruct.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a40ddcd0fd47a4c06bb194117de12597
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
446
Runtime/Base/DataStruct/GameFrameworkLinkedList.cs
Normal file
446
Runtime/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.Runtime
|
||||
{
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/DataStruct/GameFrameworkLinkedList.cs.meta
Normal file
11
Runtime/Base/DataStruct/GameFrameworkLinkedList.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8662d2b0651bb46308fa9ea5a24a9f08
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
210
Runtime/Base/DataStruct/GameFrameworkLinkedListRange.cs
Normal file
210
Runtime/Base/DataStruct/GameFrameworkLinkedListRange.cs
Normal file
@ -0,0 +1,210 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/DataStruct/GameFrameworkLinkedListRange.cs.meta
Normal file
11
Runtime/Base/DataStruct/GameFrameworkLinkedListRange.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7edbebe0b1fd848418e2f1d863b611e1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
47
Runtime/Base/DataStruct/GameFrameworkMonoSingleton.cs
Normal file
47
Runtime/Base/DataStruct/GameFrameworkMonoSingleton.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏框架单例
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class GameFrameworkMonoSingleton<T> : MonoBehaviour where T : MonoBehaviour
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
protected GameFrameworkMonoSingleton()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单例对象
|
||||
/// </summary>
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
#if UNITY_6000_0_OR_NEWER
|
||||
_instance = Object.FindFirstObjectByType<T>();
|
||||
#else
|
||||
_instance = (T)Object.FindObjectOfType(typeof(T));
|
||||
#endif
|
||||
}
|
||||
|
||||
if (_instance == null)
|
||||
{
|
||||
var insObj = new GameObject();
|
||||
_instance = insObj.AddComponent<T>();
|
||||
_instance.name = "[Singleton]" + typeof(T);
|
||||
Object.DontDestroyOnLoad(insObj);
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5901cab8f8ec41e1a15c88e7200aa2de
|
||||
timeCreated: 1716261821
|
276
Runtime/Base/DataStruct/GameFrameworkMultiDictionary.cs
Normal file
276
Runtime/Base/DataStruct/GameFrameworkMultiDictionary.cs
Normal file
@ -0,0 +1,276 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/DataStruct/GameFrameworkMultiDictionary.cs.meta
Normal file
11
Runtime/Base/DataStruct/GameFrameworkMultiDictionary.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce20200ce38864c44b02e0c1ebc7fc3a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
199
Runtime/Base/DataStruct/GameFrameworkSerializer.cs
Normal file
199
Runtime/Base/DataStruct/GameFrameworkSerializer.cs
Normal file
@ -0,0 +1,199 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <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();
|
||||
}
|
||||
}
|
11
Runtime/Base/DataStruct/GameFrameworkSerializer.cs.meta
Normal file
11
Runtime/Base/DataStruct/GameFrameworkSerializer.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2c8469a7db4474e1da10e383bc09e77f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
32
Runtime/Base/DataStruct/GameFrameworkSingleton.cs
Normal file
32
Runtime/Base/DataStruct/GameFrameworkSingleton.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏框架单例
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
public abstract class GameFrameworkSingleton<T> where T : class, new()
|
||||
{
|
||||
private static T _instance;
|
||||
|
||||
[UnityEngine.Scripting.Preserve]
|
||||
protected GameFrameworkSingleton()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 单例对象
|
||||
/// </summary>
|
||||
public static T Instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_instance == null)
|
||||
{
|
||||
_instance = new T();
|
||||
}
|
||||
|
||||
return _instance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Runtime/Base/DataStruct/GameFrameworkSingleton.cs.meta
Normal file
3
Runtime/Base/DataStruct/GameFrameworkSingleton.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df1019efa8544a009c5d62d42e0eb753
|
||||
timeCreated: 1715511521
|
15
Runtime/Base/DataStruct/ObjectDontDestroyOnLoad.cs
Normal file
15
Runtime/Base/DataStruct/ObjectDontDestroyOnLoad.cs
Normal file
@ -0,0 +1,15 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 标记物体对象为不可销毁
|
||||
/// </summary>
|
||||
public sealed class ObjectDontDestroyOnLoad : MonoBehaviour
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
DontDestroyOnLoad(this);
|
||||
}
|
||||
}
|
||||
}
|
3
Runtime/Base/DataStruct/ObjectDontDestroyOnLoad.cs.meta
Normal file
3
Runtime/Base/DataStruct/ObjectDontDestroyOnLoad.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eeb79f91247b409d97a8599f33d97808
|
||||
timeCreated: 1730723224
|
122
Runtime/Base/DataStruct/TypeNamePair.cs
Normal file
122
Runtime/Base/DataStruct/TypeNamePair.cs
Normal file
@ -0,0 +1,122 @@
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <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/Base/DataStruct/TypeNamePair.cs.meta
Normal file
11
Runtime/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/Base/Event.meta
Normal file
3
Runtime/Base/Event.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 71df78781abe4068a2c8a8fbedca8acf
|
||||
timeCreated: 1736415662
|
56
Runtime/Base/Event/EventListenerProxy.cs
Normal file
56
Runtime/Base/Event/EventListenerProxy.cs
Normal file
@ -0,0 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 游戏事件管理器。
|
||||
/// </summary>
|
||||
public class EventListenerProxy : IReference
|
||||
{
|
||||
private readonly bool _isInit = false;
|
||||
private readonly List<Action<Delegate>> clearHandlers;
|
||||
private readonly List<Delegate> actionCallBack;
|
||||
|
||||
/// <summary>
|
||||
/// 游戏事件管理器构造函数。
|
||||
/// </summary>
|
||||
public EventListenerProxy()
|
||||
{
|
||||
if (_isInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
_isInit = true;
|
||||
clearHandlers = new List<Action<Delegate>>();
|
||||
actionCallBack = new List<Delegate>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理内存对象回收入池。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
if (!_isInit)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < clearHandlers.Count; ++i)
|
||||
{
|
||||
var clearAction = clearHandlers[i];
|
||||
var handle = actionCallBack[i];
|
||||
clearAction(handle);
|
||||
}
|
||||
|
||||
clearHandlers.Clear();
|
||||
actionCallBack.Clear();
|
||||
}
|
||||
|
||||
public void AddEventImp(Action<Delegate> handler,Delegate action)
|
||||
{
|
||||
clearHandlers.Add(handler);
|
||||
actionCallBack.Add(action);
|
||||
}
|
||||
}
|
||||
}
|
3
Runtime/Base/Event/EventListenerProxy.cs.meta
Normal file
3
Runtime/Base/Event/EventListenerProxy.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb346bc3be28f89468e2c071e7ab9594
|
||||
timeCreated: 1680273952
|
8
Runtime/Base/Event/IEventBase.cs
Normal file
8
Runtime/Base/Event/IEventBase.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using System;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
public interface IEvent
|
||||
{
|
||||
}
|
||||
}
|
11
Runtime/Base/Event/IEventBase.cs.meta
Normal file
11
Runtime/Base/Event/IEventBase.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 421f7c10db9f44f4ba100040ad0baabc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
7
Runtime/Base/Event/IEventListenerProxy.cs
Normal file
7
Runtime/Base/Event/IEventListenerProxy.cs
Normal file
@ -0,0 +1,7 @@
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
public interface IEventListenerProxy
|
||||
{
|
||||
public EventListenerProxy EventListener { get; }
|
||||
}
|
||||
}
|
3
Runtime/Base/Event/IEventListenerProxy.cs.meta
Normal file
3
Runtime/Base/Event/IEventListenerProxy.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4798c5e2685443cd96fc39a7dc5e9df3
|
||||
timeCreated: 1730786771
|
3
Runtime/Base/EventPool.meta
Normal file
3
Runtime/Base/EventPool.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 48751c35576345908f4dda6ef1133f4a
|
||||
timeCreated: 1737376697
|
16
Runtime/Base/EventPool/BaseEventArgs.cs
Normal file
16
Runtime/Base/EventPool/BaseEventArgs.cs
Normal file
@ -0,0 +1,16 @@
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件基类。
|
||||
/// </summary>
|
||||
public abstract class BaseEventArgs : GameFrameworkEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取事件ID。
|
||||
/// </summary>
|
||||
public abstract string Id
|
||||
{
|
||||
get;
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/EventPool/BaseEventArgs.cs.meta
Normal file
11
Runtime/Base/EventPool/BaseEventArgs.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd577b63758c544d7878cb56583ace8b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
50
Runtime/Base/EventPool/EventPool.EventNode.cs
Normal file
50
Runtime/Base/EventPool/EventPool.EventNode.cs
Normal file
@ -0,0 +1,50 @@
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
public sealed partial class EventPool<T> where T : BaseEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件结点。
|
||||
/// </summary>
|
||||
private sealed class EventNode : IReference
|
||||
{
|
||||
private object _sender = null;
|
||||
private T _eventArgs = null;
|
||||
|
||||
/// <summary>
|
||||
/// 发送者
|
||||
/// </summary>
|
||||
public object Sender
|
||||
{
|
||||
get { return _sender; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件参数
|
||||
/// </summary>
|
||||
public T EventArgs
|
||||
{
|
||||
get { return _eventArgs; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建事件节点
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="eventArgs"></param>
|
||||
/// <returns></returns>
|
||||
public static EventNode Create(object sender, T eventArgs)
|
||||
{
|
||||
EventNode eventNodeNode = ReferencePool.Acquire<EventNode>();
|
||||
eventNodeNode._sender = sender;
|
||||
eventNodeNode._eventArgs = eventArgs;
|
||||
return eventNodeNode;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_sender = null;
|
||||
_eventArgs = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/EventPool/EventPool.EventNode.cs.meta
Normal file
11
Runtime/Base/EventPool/EventPool.EventNode.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1c00abe73a3d34fd7a8c24ea2a6ff6ae
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
319
Runtime/Base/EventPool/EventPool.cs
Normal file
319
Runtime/Base/EventPool/EventPool.cs
Normal file
@ -0,0 +1,319 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace AlicizaX.Runtime
|
||||
{
|
||||
/// <summary>
|
||||
/// 事件池。
|
||||
/// </summary>
|
||||
/// <typeparam name="T">事件类型。</typeparam>
|
||||
public sealed partial class EventPool<T> where T : BaseEventArgs
|
||||
{
|
||||
private readonly object _lock = new object();
|
||||
private readonly GameFrameworkMultiDictionary<string, EventHandler<T>> _eventHandlers;
|
||||
private readonly Queue<EventNode> _events;
|
||||
private readonly Dictionary<object, LinkedListNode<EventHandler<T>>> _cachedNodes;
|
||||
private readonly Dictionary<object, LinkedListNode<EventHandler<T>>> _tempNodes;
|
||||
private readonly EventPoolMode _eventPoolMode;
|
||||
private EventHandler<T> _defaultHandler;
|
||||
|
||||
/// <summary>
|
||||
/// 初始化事件池的新实例。
|
||||
/// </summary>
|
||||
/// <param name="mode">事件池模式。</param>
|
||||
public EventPool(EventPoolMode mode)
|
||||
{
|
||||
_eventHandlers = new GameFrameworkMultiDictionary<string, EventHandler<T>>();
|
||||
_events = new Queue<EventNode>();
|
||||
_cachedNodes = new Dictionary<object, LinkedListNode<EventHandler<T>>>();
|
||||
_tempNodes = new Dictionary<object, LinkedListNode<EventHandler<T>>>();
|
||||
_eventPoolMode = mode;
|
||||
_defaultHandler = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取事件处理函数的数量。
|
||||
/// </summary>
|
||||
public int EventHandlerCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _eventHandlers.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取事件数量。
|
||||
/// </summary>
|
||||
public int EventCount
|
||||
{
|
||||
get
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
return _events.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 事件池轮询。
|
||||
/// </summary>
|
||||
/// <param name="elapseSeconds">逻辑流逝时间,以秒为单位。</param>
|
||||
/// <param name="realElapseSeconds">真实流逝时间,以秒为单位。</param>
|
||||
public void Update(float elapseSeconds, float realElapseSeconds)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
while (_events.Count > 0)
|
||||
{
|
||||
EventNode eventNodeNode = _events.Dequeue();
|
||||
HandleEvent(eventNodeNode.Sender, eventNodeNode.EventArgs);
|
||||
ReferencePool.Release(eventNodeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 关闭并清理事件池。
|
||||
/// </summary>
|
||||
public void Shutdown()
|
||||
{
|
||||
Clear();
|
||||
_eventHandlers.Clear();
|
||||
_cachedNodes.Clear();
|
||||
_tempNodes.Clear();
|
||||
_defaultHandler = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 清理事件。
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_events.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取事件处理函数的数量。
|
||||
/// </summary>
|
||||
/// <param name="id">事件类型编号。</param>
|
||||
/// <returns>事件处理函数的数量。</returns>
|
||||
public int Count(string id)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (_eventHandlers.TryGetValue(id, out var listRange))
|
||||
{
|
||||
return listRange.Count;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 检查是否存在事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="id">事件类型编号。</param>
|
||||
/// <param name="handler">要检查的事件处理函数。</param>
|
||||
/// <returns>是否存在事件处理函数。</returns>
|
||||
public bool Check(string id, EventHandler<T> handler)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
throw new GameFrameworkException("Event handler is invalid.");
|
||||
}
|
||||
|
||||
return _eventHandlers.Contains(id, handler);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 订阅事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="id">事件类型编号。</param>
|
||||
/// <param name="handler">要订阅的事件处理函数。</param>
|
||||
public void Subscribe(string id, EventHandler<T> handler)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
throw new GameFrameworkException("Event handler is invalid.");
|
||||
}
|
||||
|
||||
if (!_eventHandlers.Contains(id))
|
||||
{
|
||||
_eventHandlers.Add(id, handler);
|
||||
}
|
||||
else if ((_eventPoolMode & EventPoolMode.AllowMultiHandler) != EventPoolMode.AllowMultiHandler)
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow multi handler.", id));
|
||||
}
|
||||
else if ((_eventPoolMode & EventPoolMode.AllowDuplicateHandler) != EventPoolMode.AllowDuplicateHandler && Check(id, handler))
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow duplicate handler.", id));
|
||||
}
|
||||
else
|
||||
{
|
||||
_eventHandlers.Add(id, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 取消订阅事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="id">事件类型编号。</param>
|
||||
/// <param name="handler">要取消订阅的事件处理函数。</param>
|
||||
public void Unsubscribe(string id, EventHandler<T> handler)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (handler == null)
|
||||
{
|
||||
throw new GameFrameworkException("Event handler is invalid.");
|
||||
}
|
||||
|
||||
if (_cachedNodes.Count > 0)
|
||||
{
|
||||
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in _cachedNodes)
|
||||
{
|
||||
if (cachedNode.Value != null && cachedNode.Value.Value == handler)
|
||||
{
|
||||
_tempNodes.Add(cachedNode.Key, cachedNode.Value.Next);
|
||||
}
|
||||
}
|
||||
|
||||
if (_tempNodes.Count > 0)
|
||||
{
|
||||
foreach (KeyValuePair<object, LinkedListNode<EventHandler<T>>> cachedNode in _tempNodes)
|
||||
{
|
||||
_cachedNodes[cachedNode.Key] = cachedNode.Value;
|
||||
}
|
||||
|
||||
_tempNodes.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
if (!_eventHandlers.Remove(id, handler))
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not exists specified handler.", id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置默认事件处理函数。
|
||||
/// </summary>
|
||||
/// <param name="handler">要设置的默认事件处理函数。</param>
|
||||
public void SetDefaultHandler(EventHandler<T> handler)
|
||||
{
|
||||
_defaultHandler = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 抛出事件,这个操作是线程安全的,即使不在主线程中抛出,也可保证在主线程中回调事件处理函数,但事件会在抛出后的下一帧分发。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源。</param>
|
||||
/// <param name="e">事件参数。</param>
|
||||
public void Fire(object sender, T e)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
throw new GameFrameworkException("Event is invalid.");
|
||||
}
|
||||
|
||||
var eventNodeNode = EventNode.Create(sender, e);
|
||||
lock (_events)
|
||||
{
|
||||
_events.Enqueue(eventNodeNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 抛出事件立即模式,这个操作不是线程安全的,事件会立刻分发。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源。</param>
|
||||
/// <param name="e">事件参数。</param>
|
||||
public void FireNow(object sender, T e)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (e == null)
|
||||
{
|
||||
throw new GameFrameworkException("Event is invalid.");
|
||||
}
|
||||
|
||||
HandleEvent(sender, e);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理事件结点。
|
||||
/// </summary>
|
||||
/// <param name="sender">事件源。</param>
|
||||
/// <param name="e">事件参数。</param>
|
||||
private void HandleEvent(object sender, T e)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
bool noHandlerException = false;
|
||||
if (_eventHandlers.TryGetValue(e.Id, out var range))
|
||||
{
|
||||
LinkedListNode<EventHandler<T>> current = range.First;
|
||||
while (current != null && current != range.Terminal)
|
||||
{
|
||||
_cachedNodes[e] = current.Next != range.Terminal ? current.Next : null;
|
||||
try
|
||||
{
|
||||
current.Value?.Invoke(sender, e);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Fatal(exception);
|
||||
}
|
||||
|
||||
current = _cachedNodes[e];
|
||||
}
|
||||
|
||||
_cachedNodes.Remove(e);
|
||||
}
|
||||
else if (_defaultHandler != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
_defaultHandler(sender, e);
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.Fatal(exception);
|
||||
}
|
||||
}
|
||||
else if ((_eventPoolMode & EventPoolMode.AllowNoHandler) == 0)
|
||||
{
|
||||
noHandlerException = true;
|
||||
}
|
||||
|
||||
ReferencePool.Release(e);
|
||||
|
||||
if (noHandlerException)
|
||||
{
|
||||
throw new GameFrameworkException(Utility.Text.Format("Event '{0}' not allow no handler.", e.Id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/Base/EventPool/EventPool.cs.meta
Normal file
11
Runtime/Base/EventPool/EventPool.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: eb4fb50ba60224c5180bc2aed4efeb71
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user