From c4c9a22fc42bc8ef9052040cd162ce865c588464 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=80=9D=E6=B5=B7?= <1464576565@qq.com> Date: Fri, 17 Apr 2026 21:01:20 +0800 Subject: [PATCH] 11 --- Editor/GameObjectPool/GameObjectPoolEditor.cs | 22 +- .../GameObjectPool/PoolConfigEditorWindow.cs | 596 +++++++++++++ .../PoolConfigEditorWindow.cs.meta | 11 + .../PoolConfigScriptableObjectEditor.cs | 167 +--- Runtime/ABase/GameObjectPool/Components.meta | 8 + .../Components/PoolComponents.cs | 308 +++++++ .../Components/PoolComponents.cs.meta | 11 + .../ABase/GameObjectPool/Data/PoolConfig.cs | 200 ++++- .../GameObjectPool/Data/PoolConfig.cs.meta | 10 +- .../Data/PoolConfigScriptableObject.cs | 32 +- .../GameObjectPool/GameObjectPoolManager.cs | 382 +++++---- .../ABase/GameObjectPool/RuntimePoolModels.cs | 807 +++++++++++++++--- Runtime/ABase/GameObjectPool/fe.md | 722 ++++++++++++++++ Runtime/ABase/GameObjectPool/fe.md.meta | 7 + 14 files changed, 2767 insertions(+), 516 deletions(-) create mode 100644 Editor/GameObjectPool/PoolConfigEditorWindow.cs create mode 100644 Editor/GameObjectPool/PoolConfigEditorWindow.cs.meta create mode 100644 Runtime/ABase/GameObjectPool/Components.meta create mode 100644 Runtime/ABase/GameObjectPool/Components/PoolComponents.cs create mode 100644 Runtime/ABase/GameObjectPool/Components/PoolComponents.cs.meta create mode 100644 Runtime/ABase/GameObjectPool/fe.md create mode 100644 Runtime/ABase/GameObjectPool/fe.md.meta diff --git a/Editor/GameObjectPool/GameObjectPoolEditor.cs b/Editor/GameObjectPool/GameObjectPoolEditor.cs index 1609618..64aa142 100644 --- a/Editor/GameObjectPool/GameObjectPoolEditor.cs +++ b/Editor/GameObjectPool/GameObjectPoolEditor.cs @@ -80,13 +80,26 @@ namespace AlicizaX if (_foldoutState[key]) { - EditorGUILayout.LabelField("Match Mode", snapshot.matchMode.ToString()); + EditorGUILayout.LabelField("Entry", snapshot.entryName); EditorGUILayout.LabelField("Loader", snapshot.loaderType.ToString()); - EditorGUILayout.LabelField("Capacity", snapshot.capacity.ToString()); + EditorGUILayout.LabelField("Overflow Policy", snapshot.overflowPolicy.ToString()); + EditorGUILayout.LabelField("Min Retained", snapshot.minRetained.ToString()); + EditorGUILayout.LabelField("Soft Capacity", snapshot.softCapacity.ToString()); + EditorGUILayout.LabelField("Hard Capacity", snapshot.hardCapacity.ToString()); EditorGUILayout.LabelField("Inactive", snapshot.inactiveCount.ToString()); - EditorGUILayout.LabelField("Idle Timeout", $"{snapshot.instanceIdleTimeout:F1}s"); - EditorGUILayout.LabelField("Prefab Unload Delay", $"{snapshot.prefabUnloadDelay:F1}s"); EditorGUILayout.LabelField("Prefab Loaded", snapshot.prefabLoaded ? "Yes" : "No"); + EditorGUILayout.LabelField("Prefab Idle", $"{snapshot.prefabIdleDuration:F1}s"); + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Acquire", snapshot.acquireCount.ToString()); + EditorGUILayout.LabelField("Release", snapshot.releaseCount.ToString()); + EditorGUILayout.LabelField("Hit", snapshot.hitCount.ToString()); + EditorGUILayout.LabelField("Miss", snapshot.missCount.ToString()); + EditorGUILayout.LabelField("Expand", snapshot.expandCount.ToString()); + EditorGUILayout.LabelField("Exhausted", snapshot.exhaustedCount.ToString()); + EditorGUILayout.LabelField("Auto Recycle", snapshot.autoRecycleCount.ToString()); + EditorGUILayout.LabelField("Destroy", snapshot.destroyCount.ToString()); + EditorGUILayout.LabelField("Peak Active", snapshot.peakActive.ToString()); + EditorGUILayout.LabelField("Peak Total", snapshot.peakTotal.ToString()); if (snapshot.instances.Count > 0) { @@ -114,6 +127,7 @@ namespace AlicizaX EditorGUILayout.BeginVertical(); EditorGUILayout.LabelField(instance.instanceName, EditorStyles.boldLabel); EditorGUILayout.LabelField("State", instance.isActive ? "Active" : "Inactive"); + EditorGUILayout.LabelField("Life", $"{instance.lifeDuration:F1}s"); if (!instance.isActive) { EditorGUILayout.LabelField("Idle", $"{instance.idleDuration:F1}s"); diff --git a/Editor/GameObjectPool/PoolConfigEditorWindow.cs b/Editor/GameObjectPool/PoolConfigEditorWindow.cs new file mode 100644 index 0000000..c54df31 --- /dev/null +++ b/Editor/GameObjectPool/PoolConfigEditorWindow.cs @@ -0,0 +1,596 @@ +using System.Collections.Generic; +using AlicizaX.Editor; +using UnityEditor; +using UnityEditor.Callbacks; +using UnityEditor.UIElements; +using UnityEngine; +using UnityEngine.UIElements; + +namespace AlicizaX +{ + public sealed class PoolConfigEditorWindow : EditorWindow + { + private const float MinLeftWidth = 240f; + private const float InitialLeftWidth = 300f; + private const int ListItemHeight = 46; + private const string WindowTitle = "Pool Config Editor"; + + private static readonly Color LeftPanelColor = new Color(0.22f, 0.22f, 0.22f, 1f); + private static readonly Color RightPanelColor = new Color(0.16f, 0.16f, 0.16f, 1f); + + private PoolConfigScriptableObject _asset; + private SerializedObject _serializedObject; + private SerializedProperty _entriesProperty; + private readonly List _entryIndices = new List(); + + private int _selectedIndex; + private bool _hasUnsavedChanges; + + private ToolbarButton _saveButton; + private Label _titleLabel; + private VisualElement _leftPane; + private ListView _listView; + private ScrollView _detailScrollView; + private Label _detailTitleLabel; + private VisualElement _detailFieldsContainer; + private VisualElement _emptyContainer; + + [MenuItem("AlicizaX/GameObjectPool/Open PoolConfig Editor")] + public static void OpenWindow() + { + Open(Selection.activeObject as PoolConfigScriptableObject); + } + + public static void Open(PoolConfigScriptableObject asset) + { + PoolConfigEditorWindow window = GetWindow(false, WindowTitle, true); + window.minSize = new Vector2(920f, 560f); + window.SetAsset(asset); + window.Show(); + } + + [OnOpenAsset(0)] + private static bool OnOpenAsset(int instanceId, int line) + { + Object obj = EditorUtility.InstanceIDToObject(instanceId); + if (obj is not PoolConfigScriptableObject asset) + { + return false; + } + + Open(asset); + return true; + } + + private void CreateGUI() + { + titleContent = new GUIContent(WindowTitle, EditorGUIUtility.IconContent("ScriptableObject Icon").image); + BuildUi(); + + if (_asset == null && Selection.activeObject is PoolConfigScriptableObject selectedAsset) + { + SetAsset(selectedAsset); + } + else + { + RefreshUi(); + } + } + + private void OnEnable() + { + titleContent = new GUIContent(WindowTitle, EditorGUIUtility.IconContent("ScriptableObject Icon").image); + if (rootVisualElement.childCount == 0) + { + BuildUi(); + } + + if (_asset == null && Selection.activeObject is PoolConfigScriptableObject selectedAsset) + { + SetAsset(selectedAsset); + } + else + { + RefreshUi(); + } + } + + private void OnSelectionChange() + { + if (Selection.activeObject is PoolConfigScriptableObject selectedAsset && selectedAsset != _asset) + { + SetAsset(selectedAsset); + } + } + + private void BuildUi() + { + rootVisualElement.Clear(); + rootVisualElement.style.flexDirection = FlexDirection.Column; + + Toolbar toolbar = new Toolbar(); + toolbar.style.flexShrink = 0f; + + _saveButton = new ToolbarButton(SaveAsset) + { + tooltip = "Save PoolConfig" + }; + _saveButton.Add(new Image + { + image = EditorGUIUtility.IconContent("SaveActive").image, + scaleMode = ScaleMode.ScaleToFit + }); + + _titleLabel = new Label(); + _titleLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + _titleLabel.style.flexGrow = 1f; + _titleLabel.style.marginLeft = 6f; + _titleLabel.style.unityTextAlign = TextAnchor.MiddleLeft; + + toolbar.Add(_saveButton); + toolbar.Add(_titleLabel); + rootVisualElement.Add(toolbar); + + TwoPaneSplitView splitView = new TwoPaneSplitView(0, InitialLeftWidth, TwoPaneSplitViewOrientation.Horizontal); + splitView.style.flexGrow = 1f; + rootVisualElement.Add(splitView); + + _leftPane = new VisualElement(); + _leftPane.style.flexGrow = 1f; + _leftPane.style.minWidth = MinLeftWidth; + _leftPane.style.backgroundColor = LeftPanelColor; + _leftPane.style.paddingLeft = 4f; + _leftPane.style.paddingRight = 4f; + _leftPane.style.paddingTop = 4f; + _leftPane.style.paddingBottom = 4f; + + VisualElement rightPane = new VisualElement(); + rightPane.style.flexGrow = 1f; + rightPane.style.backgroundColor = RightPanelColor; + rightPane.style.paddingLeft = 10f; + rightPane.style.paddingRight = 10f; + rightPane.style.paddingTop = 8f; + rightPane.style.paddingBottom = 8f; + + splitView.Add(_leftPane); + splitView.Add(rightPane); + + BuildLeftPane(); + BuildRightPane(rightPane); + } + + private void BuildLeftPane() + { + _listView = new ListView + { + selectionType = SelectionType.Single, + virtualizationMethod = CollectionVirtualizationMethod.FixedHeight, + reorderable = false, + showBorder = false, + showAlternatingRowBackgrounds = AlternatingRowBackground.None, + style = + { + flexGrow = 1f, + marginBottom = 4f + }, + fixedItemHeight = ListItemHeight + }; + + _listView.makeItem = MakeListItem; + _listView.bindItem = BindListItem; + _listView.selectionChanged += _ => OnListSelectionChanged(); + _leftPane.Add(_listView); + + VisualElement footer = new VisualElement(); + footer.style.flexDirection = FlexDirection.Row; + footer.style.justifyContent = Justify.Center; + footer.style.alignItems = Align.Center; + footer.style.flexShrink = 0f; + footer.style.height = 28f; + + Button addButton = new Button(AddEntry) + { + tooltip = "Add Item" + }; + addButton.style.width = 24f; + addButton.style.height = 20f; + addButton.style.marginRight = 4f; + addButton.Add(new Image + { + image = EditorUtils.Styles.PlusIcon.image, + scaleMode = ScaleMode.ScaleToFit + }); + + Button removeButton = new Button(RemoveEntry) + { + tooltip = "Remove Item", + name = "remove-button" + }; + removeButton.style.width = 24f; + removeButton.style.height = 20f; + removeButton.Add(new Image + { + image = EditorUtils.Styles.MinusIcon.image, + scaleMode = ScaleMode.ScaleToFit + }); + removeButton.SetEnabled(false); + + footer.Add(addButton); + footer.Add(removeButton); + _leftPane.Add(footer); + } + + private void BuildRightPane(VisualElement rightPane) + { + _emptyContainer = new VisualElement + { + style = + { + flexGrow = 1f, + justifyContent = Justify.Center + } + }; + _emptyContainer.Add(new HelpBox("No entry selected.", HelpBoxMessageType.Info)); + + _detailScrollView = new ScrollView + { + style = + { + flexGrow = 1f + } + }; + + _detailTitleLabel = new Label(); + _detailTitleLabel.style.unityFontStyleAndWeight = FontStyle.Bold; + _detailTitleLabel.style.marginBottom = 6f; + _detailTitleLabel.style.unityTextAlign = TextAnchor.MiddleLeft; + + _detailFieldsContainer = new VisualElement(); + _detailFieldsContainer.style.flexDirection = FlexDirection.Column; + _detailFieldsContainer.style.flexGrow = 1f; + + _detailScrollView.Add(_detailTitleLabel); + _detailScrollView.Add(_detailFieldsContainer); + + rightPane.Add(_emptyContainer); + rightPane.Add(_detailScrollView); + } + + private VisualElement MakeListItem() + { + VisualElement root = new VisualElement(); + root.style.height = ListItemHeight; + root.style.flexDirection = FlexDirection.Column; + root.style.justifyContent = Justify.Center; + root.style.paddingLeft = 8f; + root.style.paddingRight = 8f; + root.style.paddingTop = 6f; + root.style.paddingBottom = 6f; + root.style.marginBottom = 2f; + + Label primary = new Label { name = "primary" }; + primary.style.unityTextAlign = TextAnchor.MiddleLeft; + + Label secondary = new Label { name = "secondary" }; + secondary.style.unityTextAlign = TextAnchor.MiddleLeft; + secondary.style.fontSize = 11f; + secondary.style.color = new Color(0.72f, 0.72f, 0.72f, 1f); + + root.Add(primary); + root.Add(secondary); + return root; + } + + private void BindListItem(VisualElement element, int index) + { + SerializedProperty entry = GetEntryAt(index); + element.Q