- QuestSO: Add ValidateBranchCycles() DFS detection for branches[].nextQuest loop - QuestSO: Mark three legacy prerequisite fields with v2.0 removal warning in Tooltip - IQuestManager: Add QuestLockReason enum + QuestLockInfo struct (strongly-typed lock info) - IQuestManager: Add GetQuestLockInfo() method to interface; GetQuestLockReason() now delegates to it - IQuestEventSource: Add OnQuestStateChanged(questId, oldState, newState) unified event - QuestManager: Implement GetQuestLockInfo(); fire OnQuestStateChanged on all state transitions - DialogueManager: Add one-frame yield in HandleChoices before ShowChoices (skip-debounce fix) - DialogueManager: Increment _playbackId in ForceEnd() to invalidate residual choice callbacks - DialogueSequenceSO: Add UNITY_EDITOR debug log in TryGetActiveVariant on variant match - WorldStateRegistry: Add OnBatchStateChanged event + BatchMark() batch-write API - DialogueModule: List badge shows warning indicator for unconditional-shadowing variants - DialogueModule: BuildVariantsCard shows logic mode (AND/OR) alongside flag conditions Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
157 lines
6.3 KiB
C#
157 lines
6.3 KiB
C#
using System;
|
|
using UnityEditor;
|
|
using UnityEditor.UIElements;
|
|
using UnityEngine;
|
|
using UnityEngine.UIElements;
|
|
using BaseGames.World.Streaming;
|
|
|
|
namespace BaseGames.Editor.Modules
|
|
{
|
|
/// <summary>
|
|
/// DataHub 流式加载模块 —— 管理 <see cref="StreamingBudgetConfigSO"/> 资产。
|
|
/// </summary>
|
|
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<StreamingBudgetConfigSO> _listPane;
|
|
private DetailHeader _header;
|
|
private StreamingBudgetConfigSO _selected;
|
|
|
|
public void Initialize()
|
|
{
|
|
_listPane = new SoListPane<StreamingBudgetConfigSO>(
|
|
Folder, Prefix,
|
|
cfg => $"休眠上限 {cfg.MaxDormantRooms} 预加载深度 {cfg.PreloadLookaheadHops}跳");
|
|
_listPane.SelectionChanged = sel =>
|
|
{
|
|
_selected = sel;
|
|
};
|
|
}
|
|
|
|
public void BuildListPane(VisualElement container, Action<UnityEngine.Object> 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<StreamingBudgetConfigSO>(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;
|
|
}
|
|
}
|
|
}
|