Files
zeling_v2/Assets/_Game/Scripts/Editor/Hub/DataHubWindow.cs
Joywayer a1b4e629aa feat: Implement Room Streaming System
- Add RoomStreamingManager to manage room loading and unloading based on player proximity.
- Create StreamingBudgetConfigSO for memory and performance budgeting of the streaming system.
- Introduce TransitionDirector to handle seamless and atmospheric fade transitions between rooms.
- Develop WorldGraph to represent room connectivity and facilitate neighbor queries and distance calculations.
- Implement RoomNode and RoomEdge classes to structure room data and connections.
2026-05-23 19:10:29 +08:00

276 lines
10 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using BaseGames.Editor.Modules;
namespace BaseGames.Editor
{
/// <summary>
/// 数据管理总枢纽窗口DataHub
/// 布局导航侧边栏120px | TwoPaneSplitView → 列表区220px + 详情区flex
/// 菜单BaseGames / Data Hub (priority=50)
/// </summary>
public class DataHubWindow : EditorWindow
{
private const string UssPath = "Assets/_Game/Scripts/Editor/UIToolkit/Editor.uss";
private const string PrefKey = "DataHub.ActiveModuleId";
private const float NavWidth = 120f;
private const float ListWidth = 220f;
private const float MinWinWidth = 680f;
private const float MinWinHeight = 420f;
[MenuItem("BaseGames/Data Hub", priority = 50)]
public static void Open()
{
var wnd = GetWindow<DataHubWindow>();
wnd.titleContent = new GUIContent("Data Hub", EditorGUIUtility.IconContent("d_ScriptableObject Icon").image);
wnd.minSize = new Vector2(MinWinWidth, MinWinHeight);
}
// ── 状态 ─────────────────────────────────────────────────────────────
private readonly List<IDataModule> _modules = new();
private readonly HashSet<string> _initializedIds = new();
private IDataModule _activeModule;
private VisualElement _navSidebar;
// 缓存:列表区和详情区引用(由 TwoPaneSplitView 子节点提供)
private VisualElement _listWrapper;
private VisualElement _detailWrapper;
// 当前选中资产
private UnityEngine.Object _selected;
// ── 生命周期 ──────────────────────────────────────────────────────────
public void CreateGUI()
{
// USS
var uss = AssetDatabase.LoadAssetAtPath<StyleSheet>(UssPath);
if (uss != null) rootVisualElement.styleSheets.Add(uss);
// 注册模块
RegisterModules();
// 构建 UI
BuildLayout();
// 恢复上次激活的模块
string savedId = EditorPrefs.GetString(PrefKey, string.Empty);
var toActivate = _modules.Find(m => m.ModuleId == savedId) ?? _modules.FirstOrDefault();
if (toActivate != null) ActivateModule(toActivate);
}
// ── 模块注册 ──────────────────────────────────────────────────────────
private void RegisterModules()
{
_modules.Clear();
_modules.Add(new WeaponModule());
_modules.Add(new SkillModule());
_modules.Add(new EnemyModule());
_modules.Add(new FormModule());
_modules.Add(new BossSkillModule());
_modules.Add(new CharmModule());
_modules.Add(new StreamingModule());
}
// ── 布局 ─────────────────────────────────────────────────────────────
private void BuildLayout()
{
var root = rootVisualElement;
root.style.flexDirection = FlexDirection.Row;
root.style.flexGrow = 1;
// 导航侧边栏
_navSidebar = BuildNavSidebar();
root.Add(_navSidebar);
// 垂直分隔线
var divider = new VisualElement();
divider.style.width = 1;
divider.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.25f));
root.Add(divider);
// TwoPaneSplitView列表 + 详情)
var split = new TwoPaneSplitView(0, ListWidth, TwoPaneSplitViewOrientation.Horizontal);
split.style.flexGrow = 1;
root.Add(split);
// 列表区容器
_listWrapper = new VisualElement();
_listWrapper.style.flexGrow = 1;
_listWrapper.style.overflow = Overflow.Hidden;
split.Add(_listWrapper);
// 详情区:外层 ScrollView 提供滚动视口_detailWrapper 是内容容器(自然高度)
var detailScroll = new ScrollView(ScrollViewMode.Vertical);
detailScroll.style.flexGrow = 1;
detailScroll.style.overflow = Overflow.Hidden;
split.Add(detailScroll);
_detailWrapper = new VisualElement();
_detailWrapper.style.flexDirection = FlexDirection.Column;
_detailWrapper.style.paddingBottom = 16;
detailScroll.Add(_detailWrapper);
}
private VisualElement BuildNavSidebar()
{
var sidebar = new VisualElement();
sidebar.style.width = NavWidth;
sidebar.style.flexShrink = 0;
sidebar.style.flexDirection = FlexDirection.Column;
sidebar.style.paddingTop = 8;
// 标题
var title = new Label("DATA HUB");
title.style.fontSize = 10;
title.style.opacity = 0.5f;
title.style.paddingLeft = 10;
title.style.marginBottom = 6;
title.style.unityFontStyleAndWeight = FontStyle.Bold;
sidebar.Add(title);
foreach (var module in _modules)
{
var btn = BuildNavItem(module);
sidebar.Add(btn);
}
// 弹性填充
var spacer = new VisualElement();
spacer.style.flexGrow = 1;
sidebar.Add(spacer);
return sidebar;
}
private Button BuildNavItem(IDataModule module)
{
var btn = new Button(() => ActivateModule(module));
btn.name = "nav-" + module.ModuleId;
btn.style.flexDirection = FlexDirection.Row;
btn.style.alignItems = Align.Center;
btn.style.paddingLeft = 10;
btn.style.paddingRight = 8;
btn.style.paddingTop = 8;
btn.style.paddingBottom = 8;
btn.style.borderTopLeftRadius = 0;
btn.style.borderTopRightRadius = 0;
btn.style.borderBottomLeftRadius = 0;
btn.style.borderBottomRightRadius = 0;
btn.style.borderLeftWidth = 0;
btn.style.borderRightWidth = 0;
btn.style.borderTopWidth = 0;
btn.style.borderBottomWidth = 0;
btn.style.backgroundColor = new StyleColor(Color.clear);
btn.style.marginBottom = 2;
// 图标(容错:图标名无效时跳过,不报错)
if (!string.IsNullOrEmpty(module.IconName))
{
var content = EditorGUIUtility.IconContent(module.IconName);
if (content?.image != null)
{
var icon = new Image { image = content.image };
icon.style.width = 16;
icon.style.height = 16;
icon.style.marginRight = 6;
btn.Add(icon);
}
}
var label = new Label(module.DisplayName);
label.style.flexGrow = 1;
btn.Add(label);
return btn;
}
// ── 模块切换 ──────────────────────────────────────────────────────────
private void ActivateModule(IDataModule module)
{
if (_activeModule == module) return;
_activeModule = module;
_selected = null;
// 更新导航项视觉状态
foreach (var m in _modules)
{
var navBtn = _navSidebar.Q<Button>("nav-" + m.ModuleId);
if (navBtn == null) continue;
if (m == module)
{
navBtn.style.backgroundColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.18f));
navBtn.style.borderLeftWidth = 3;
navBtn.style.borderLeftColor = new StyleColor(new Color(0.4f, 0.65f, 1f, 1f));
}
else
{
navBtn.style.backgroundColor = new StyleColor(Color.clear);
navBtn.style.borderLeftWidth = 0;
}
}
// 初始化模块(首次激活时调用一次)
if (!_initializedIds.Contains(module.ModuleId))
{
_initializedIds.Add(module.ModuleId);
module.Initialize();
}
module.OnActivated();
// 重建列表区
_listWrapper.Clear();
module.BuildListPane(_listWrapper, OnModuleSelected);
// 清空详情区
RebuildDetailPane(null);
EditorPrefs.SetString(PrefKey, module.ModuleId);
}
private void OnModuleSelected(UnityEngine.Object selected)
{
_selected = selected;
RebuildDetailPane(selected);
}
private void RebuildDetailPane(UnityEngine.Object selected)
{
_detailWrapper.Clear();
if (_activeModule == null) return;
if (selected == null)
{
var placeholder = new Label("← 从左侧列表选择一项");
placeholder.style.opacity = 0.45f;
placeholder.style.marginTop = 60;
placeholder.style.unityTextAlign = TextAnchor.MiddleCenter;
_detailWrapper.Add(placeholder);
return;
}
_activeModule.BuildDetailPane(_detailWrapper, selected);
}
// ── 公共辅助(供 Module 回调使用)────────────────────────────────────
/// <summary>通知 Hub 已完成重命名,需要刷新详情区标题。</summary>
public void NotifyRenamed(UnityEngine.Object asset)
{
if (_activeModule == null || asset == null) return;
RebuildDetailPane(asset);
}
}
}