using System; using UnityEditor; using UnityEditor.UIElements; using UnityEngine; using UnityEngine.UIElements; using BaseGames.World.Streaming; namespace BaseGames.Editor.Modules { /// /// DataHub 流式加载模块 —— 管理 资产。 /// public class StreamingModule : IDataModule, IDataModuleOrdered { private const string Folder = "Assets/_Game/Data/Streaming"; private const string Prefix = "STR_"; public string ModuleId => "streaming"; public string DisplayName => "流式加载"; public string IconName => "d_RectTransformBlueprint"; public int DisplayOrder => 70; private SoListPane _listPane; private DetailHeader _header; private StreamingBudgetConfigSO _selected; public void Initialize() { _listPane = new SoListPane( Folder, Prefix, cfg => $"休眠上限 {cfg.MaxDormantRooms} 预加载深度 {cfg.PreloadLookaheadHops}跳"); _listPane.SelectionChanged = sel => { _selected = sel; }; } public void BuildListPane(VisualElement container, Action onSelected) { _listPane.SelectionChanged = sel => { _selected = sel; onSelected?.Invoke(sel); }; // 顶部操作栏(新建) var topBar = new VisualElement(); topBar.style.flexDirection = FlexDirection.Row; topBar.style.paddingLeft = 8; topBar.style.paddingRight = 8; topBar.style.paddingTop = 6; topBar.style.paddingBottom = 6; topBar.style.borderBottomWidth = 1; topBar.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.3f)); container.Add(topBar); var createBtn = new Button(() => { var created = AssetOperations.Create(Folder, "STR_BudgetConfig_New"); if (created != null) _listPane.Refresh(created); }) { text = "+ 新建配置" }; createBtn.style.flexGrow = 1; topBar.Add(createBtn); container.Add(_listPane); _listPane.style.flexGrow = 1; _listPane.Refresh(); } public void BuildDetailPane(VisualElement container, UnityEngine.Object selected) { _selected = selected as StreamingBudgetConfigSO; _header = new DetailHeader(); _header.SetAsset(_selected); _header.RenameRequested += newName => OnRenameRequested(selected, newName); container.Add(_header); if (_selected == null) return; container.Add(BuildStatsCard(_selected)); container.Add(BuildActionBar(_selected)); container.Add(SkillModule.MakeDivider()); container.Add(new InspectorElement(_selected)); } public void OnActivated() => _listPane?.Refresh(); // ── Stats Card ──────────────────────────────────────────────────────── private static VisualElement BuildStatsCard(StreamingBudgetConfigSO cfg) { var card = SkillModule.MakeCard(); SkillModule.AddChip(card, "最大休眠房间", $"{cfg.MaxDormantRooms}"); SkillModule.AddChip(card, "内存上限", $"{cfg.MaxMemoryMB} MB"); SkillModule.AddChip(card, "并发加载数", $"{cfg.MaxConcurrentLoads}"); SkillModule.AddChip(card, "预加载跳数", $"{cfg.PreloadLookaheadHops}"); SkillModule.AddChip(card, "冷却时长", $"{cfg.CoolingDuration:F1}s"); SkillModule.AddChip(card, "每帧激活数", $"{cfg.LifecycleActivatePerFrame}"); return card; } // ── Action Bar ──────────────────────────────────────────────────────── private VisualElement BuildActionBar(StreamingBudgetConfigSO cfg) { var bar = SkillModule.MakeActionBar(); new Button(() => { EditorGUIUtility.PingObject(cfg); Selection.activeObject = cfg; }) { text = "定位" }.AlsoAddTo(bar); new Button(() => { var c = AssetOperations.Clone(cfg, Folder); if (c != null) _listPane.Refresh(c); }) { text = "克隆..." }.AlsoAddTo(bar); var del = new Button(() => { if (AssetOperations.Delete(cfg)) _listPane.Refresh(null); }) { text = "删除" }; ApplyDeleteStyle(del); del.AlsoAddTo(bar); return bar; } // ── 重命名 ──────────────────────────────────────────────────────────── private void OnRenameRequested(UnityEngine.Object asset, string newName) { var (ok, err) = AssetOperations.Rename(asset, newName); if (!ok) EditorUtility.DisplayDialog("重命名失败", err, "确定"); else { _header.SetAsset(asset); _listPane.Invalidate(); } } // ── 共用 ───────────────────────────────────────────────────────────── private static void ApplyDeleteStyle(Button btn) { var c = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f)); btn.style.borderLeftColor = c; btn.style.borderRightColor = c; btn.style.borderTopColor = c; btn.style.borderBottomColor = c; btn.style.borderLeftWidth = 1; btn.style.borderRightWidth = 1; btn.style.borderTopWidth = 1; btn.style.borderBottomWidth = 1; btn.style.marginLeft = 8; } } }