|
|
|
|
@@ -8,7 +8,7 @@ using BaseGames.Player;
|
|
|
|
|
namespace BaseGames.Editor.Modules
|
|
|
|
|
{
|
|
|
|
|
/// <summary>
|
|
|
|
|
/// DataHub 形态模块 —— 管理 FormConfigSO(含三列 FormSO 预览)和 FormSO 资产。
|
|
|
|
|
/// DataHub 形态模块 —— Tab 切换管理 FormConfigSO 和 FormSO 资产。
|
|
|
|
|
/// </summary>
|
|
|
|
|
public class FormModule : IDataModule
|
|
|
|
|
{
|
|
|
|
|
@@ -17,11 +17,17 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
|
|
|
|
|
public string ModuleId => "form";
|
|
|
|
|
public string DisplayName => "形态";
|
|
|
|
|
public string IconName => "d_AvatarPivot";
|
|
|
|
|
public string IconName => null;
|
|
|
|
|
|
|
|
|
|
private SoListPane<FormConfigSO> _listPane;
|
|
|
|
|
private DetailHeader _header;
|
|
|
|
|
private FormConfigSO _selected;
|
|
|
|
|
private int _activeTab = 0; // 0=FormConfig, 1=FormSO
|
|
|
|
|
|
|
|
|
|
private SoListPane<FormConfigSO> _configPane;
|
|
|
|
|
private SoListPane<FormSO> _formPane;
|
|
|
|
|
private Action<UnityEngine.Object> _onSelected;
|
|
|
|
|
|
|
|
|
|
private DetailHeader _header;
|
|
|
|
|
private FormConfigSO _selectedConfig;
|
|
|
|
|
private FormSO _selectedForm;
|
|
|
|
|
|
|
|
|
|
private static readonly (FormType type, string label, Color accent)[] FormDefs =
|
|
|
|
|
{
|
|
|
|
|
@@ -32,59 +38,137 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
|
|
|
|
|
public void Initialize()
|
|
|
|
|
{
|
|
|
|
|
_listPane = new SoListPane<FormConfigSO>(ConfigFolder, "PLY_FormConfig_");
|
|
|
|
|
_configPane = new SoListPane<FormConfigSO>(ConfigFolder, "PLY_FormConfig_");
|
|
|
|
|
_configPane.SelectionChanged = s => { _selectedConfig = s; _onSelected?.Invoke(s); };
|
|
|
|
|
|
|
|
|
|
_formPane = new SoListPane<FormSO>(FormFolder, "PLY_Form_",
|
|
|
|
|
f => f.formType.ToString());
|
|
|
|
|
_formPane.SelectionChanged = s => { _selectedForm = s; _onSelected?.Invoke(s); };
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void BuildListPane(VisualElement container, Action<UnityEngine.Object> onSelected)
|
|
|
|
|
{
|
|
|
|
|
_listPane.SelectionChanged = sel =>
|
|
|
|
|
{
|
|
|
|
|
_selected = sel;
|
|
|
|
|
onSelected?.Invoke(sel);
|
|
|
|
|
};
|
|
|
|
|
container.Add(_listPane);
|
|
|
|
|
_listPane.Refresh();
|
|
|
|
|
_onSelected = onSelected;
|
|
|
|
|
container.style.flexDirection = FlexDirection.Column;
|
|
|
|
|
|
|
|
|
|
// Tab bar
|
|
|
|
|
var tabBar = new VisualElement();
|
|
|
|
|
tabBar.style.flexDirection = FlexDirection.Row;
|
|
|
|
|
tabBar.style.borderBottomWidth = 1;
|
|
|
|
|
tabBar.style.borderBottomColor = new StyleColor(new Color(0.5f, 0.5f, 0.5f, 0.3f));
|
|
|
|
|
container.Add(tabBar);
|
|
|
|
|
|
|
|
|
|
var btnConfig = BuildTabBtn("配置 (Config)", 0, tabBar);
|
|
|
|
|
var btnForm = BuildTabBtn("形态 (Form)", 1, tabBar);
|
|
|
|
|
|
|
|
|
|
var listArea = new VisualElement();
|
|
|
|
|
listArea.style.flexGrow = 1;
|
|
|
|
|
container.Add(listArea);
|
|
|
|
|
|
|
|
|
|
ShowTab(0, listArea, new[] { btnConfig, btnForm });
|
|
|
|
|
btnConfig.clicked += () => ShowTab(0, listArea, new[] { btnConfig, btnForm });
|
|
|
|
|
btnForm.clicked += () => ShowTab(1, listArea, new[] { btnConfig, btnForm });
|
|
|
|
|
|
|
|
|
|
_configPane.Refresh();
|
|
|
|
|
_formPane.Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void BuildDetailPane(VisualElement container, UnityEngine.Object selected)
|
|
|
|
|
{
|
|
|
|
|
_selected = selected as FormConfigSO;
|
|
|
|
|
|
|
|
|
|
_header = new DetailHeader();
|
|
|
|
|
_header.SetAsset(_selected);
|
|
|
|
|
_header.RenameRequested += OnRenameRequested;
|
|
|
|
|
_header.SetAsset(selected);
|
|
|
|
|
_header.RenameRequested += name => OnRenameRequested(selected, name);
|
|
|
|
|
container.Add(_header);
|
|
|
|
|
|
|
|
|
|
if (_selected == null) return;
|
|
|
|
|
if (selected == null) return;
|
|
|
|
|
|
|
|
|
|
// 操作按钮
|
|
|
|
|
container.Add(BuildActionBar(_selected));
|
|
|
|
|
container.Add(SkillModule.MakeDivider());
|
|
|
|
|
|
|
|
|
|
// 三列形态网格
|
|
|
|
|
var grid = BuildFormGrid(_selected);
|
|
|
|
|
container.Add(grid);
|
|
|
|
|
|
|
|
|
|
container.Add(SkillModule.MakeDivider());
|
|
|
|
|
|
|
|
|
|
// Raw Inspector
|
|
|
|
|
var insp = new InspectorElement(_selected);
|
|
|
|
|
insp.style.flexGrow = 1;
|
|
|
|
|
container.Add(insp);
|
|
|
|
|
if (selected is FormConfigSO config)
|
|
|
|
|
{
|
|
|
|
|
container.Add(BuildConfigActionBar(config));
|
|
|
|
|
container.Add(SkillModule.MakeDivider());
|
|
|
|
|
container.Add(BuildFormGrid(config));
|
|
|
|
|
container.Add(SkillModule.MakeDivider());
|
|
|
|
|
var insp = new InspectorElement(config);
|
|
|
|
|
insp.style.flexGrow = 1;
|
|
|
|
|
container.Add(insp);
|
|
|
|
|
}
|
|
|
|
|
else if (selected is FormSO form)
|
|
|
|
|
{
|
|
|
|
|
container.Add(BuildFormCard(form));
|
|
|
|
|
container.Add(BuildFormActionBar(form));
|
|
|
|
|
container.Add(SkillModule.MakeDivider());
|
|
|
|
|
var insp = new InspectorElement(form);
|
|
|
|
|
insp.style.flexGrow = 1;
|
|
|
|
|
container.Add(insp);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public void OnActivated() => _listPane?.Refresh();
|
|
|
|
|
|
|
|
|
|
// ── 内部 ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private void OnRenameRequested(string newName)
|
|
|
|
|
public void OnActivated()
|
|
|
|
|
{
|
|
|
|
|
if (_selected == null) return;
|
|
|
|
|
var (ok, err) = AssetOperations.Rename(_selected, newName);
|
|
|
|
|
if (!ok) EditorUtility.DisplayDialog("重命名失败", err, "确定");
|
|
|
|
|
else { _header.SetAsset(_selected); _listPane.Invalidate(); }
|
|
|
|
|
_configPane?.Refresh();
|
|
|
|
|
_formPane?.Refresh();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── Tab UI ────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private Button BuildTabBtn(string text, int tabIdx, VisualElement bar)
|
|
|
|
|
{
|
|
|
|
|
var btn = new Button { text = text };
|
|
|
|
|
btn.style.flexGrow = 1;
|
|
|
|
|
btn.style.paddingTop = 5;
|
|
|
|
|
btn.style.paddingBottom = 5;
|
|
|
|
|
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.userData = tabIdx;
|
|
|
|
|
bar.Add(btn);
|
|
|
|
|
return btn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ShowTab(int tab, VisualElement area, Button[] tabBtns)
|
|
|
|
|
{
|
|
|
|
|
_activeTab = tab;
|
|
|
|
|
area.Clear();
|
|
|
|
|
for (int i = 0; i < tabBtns.Length; i++)
|
|
|
|
|
{
|
|
|
|
|
if (i == tab)
|
|
|
|
|
{
|
|
|
|
|
tabBtns[i].style.borderBottomWidth = 2;
|
|
|
|
|
tabBtns[i].style.borderBottomColor = new StyleColor(new Color(0.4f, 0.65f, 1f, 1f));
|
|
|
|
|
tabBtns[i].style.opacity = 1f;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tabBtns[i].style.borderBottomWidth = 0;
|
|
|
|
|
tabBtns[i].style.opacity = 0.65f;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (tab == 0) { _configPane.style.flexGrow = 1; area.Add(_configPane); }
|
|
|
|
|
else { _formPane.style.flexGrow = 1; area.Add(_formPane); }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── 重命名 ────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private void OnRenameRequested(UnityEngine.Object asset, string newName)
|
|
|
|
|
{
|
|
|
|
|
var (ok, err) = AssetOperations.Rename(asset, newName);
|
|
|
|
|
if (!ok) EditorUtility.DisplayDialog("重命名失败", err, "确定");
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_header.SetAsset(asset);
|
|
|
|
|
if (_activeTab == 0) _configPane.Invalidate();
|
|
|
|
|
else _formPane.Invalidate();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── FormConfigSO 详情 ─────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private VisualElement BuildFormGrid(FormConfigSO config)
|
|
|
|
|
{
|
|
|
|
|
var grid = new VisualElement();
|
|
|
|
|
@@ -108,17 +192,17 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
FormConfigSO config, FormType ft, string label, Color accent)
|
|
|
|
|
{
|
|
|
|
|
var col = new VisualElement();
|
|
|
|
|
col.style.flexGrow = 1;
|
|
|
|
|
col.style.borderTopWidth = 2;
|
|
|
|
|
col.style.borderTopColor = new StyleColor(accent);
|
|
|
|
|
col.style.borderLeftWidth = 1;
|
|
|
|
|
col.style.borderRightWidth = 1;
|
|
|
|
|
col.style.borderBottomWidth = 1;
|
|
|
|
|
col.style.borderLeftColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderRightColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderBottomColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderTopLeftRadius = 4;
|
|
|
|
|
col.style.borderTopRightRadius = 4;
|
|
|
|
|
col.style.flexGrow = 1;
|
|
|
|
|
col.style.borderTopWidth = 2;
|
|
|
|
|
col.style.borderTopColor = new StyleColor(accent);
|
|
|
|
|
col.style.borderLeftWidth = 1;
|
|
|
|
|
col.style.borderRightWidth = 1;
|
|
|
|
|
col.style.borderBottomWidth = 1;
|
|
|
|
|
col.style.borderLeftColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderRightColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderBottomColor = new StyleColor(new Color(accent.r, accent.g, accent.b, 0.35f));
|
|
|
|
|
col.style.borderTopLeftRadius = 4;
|
|
|
|
|
col.style.borderTopRightRadius = 4;
|
|
|
|
|
col.style.borderBottomLeftRadius = 4;
|
|
|
|
|
col.style.borderBottomRightRadius = 4;
|
|
|
|
|
col.style.paddingLeft = 8;
|
|
|
|
|
@@ -133,8 +217,8 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
titleRow.style.marginBottom = 6;
|
|
|
|
|
|
|
|
|
|
var dot = new VisualElement();
|
|
|
|
|
dot.style.width = 10;
|
|
|
|
|
dot.style.height = 10;
|
|
|
|
|
dot.style.width = 10;
|
|
|
|
|
dot.style.height = 10;
|
|
|
|
|
dot.style.borderTopLeftRadius = 5;
|
|
|
|
|
dot.style.borderTopRightRadius = 5;
|
|
|
|
|
dot.style.borderBottomLeftRadius = 5;
|
|
|
|
|
@@ -149,10 +233,7 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
FormSO current = config.GetFormByType(ft);
|
|
|
|
|
var formField = new ObjectField("FormSO") { objectType = typeof(FormSO), value = current };
|
|
|
|
|
formField.RegisterValueChangedCallback(e =>
|
|
|
|
|
{
|
|
|
|
|
var newForm = e.newValue as FormSO;
|
|
|
|
|
SetFormByType(config, ft, newForm);
|
|
|
|
|
});
|
|
|
|
|
SetFormByType(config, ft, e.newValue as FormSO));
|
|
|
|
|
col.Add(formField);
|
|
|
|
|
|
|
|
|
|
// 武器只读预览
|
|
|
|
|
@@ -179,31 +260,59 @@ namespace BaseGames.Editor.Modules
|
|
|
|
|
EditorUtility.SetDirty(config);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private VisualElement BuildActionBar(FormConfigSO config)
|
|
|
|
|
private VisualElement BuildConfigActionBar(FormConfigSO config)
|
|
|
|
|
{
|
|
|
|
|
var bar = SkillModule.MakeActionBar();
|
|
|
|
|
new Button(() => { EditorGUIUtility.PingObject(config); Selection.activeObject = config; })
|
|
|
|
|
{ text = "定位" }.AlsoAddTo(bar);
|
|
|
|
|
new Button(() =>
|
|
|
|
|
{
|
|
|
|
|
var c = AssetOperations.Clone(config, ConfigFolder);
|
|
|
|
|
if (c != null) _listPane.Refresh(c);
|
|
|
|
|
}) { text = "克隆..." }.AlsoAddTo(bar);
|
|
|
|
|
var del = new Button(() =>
|
|
|
|
|
{
|
|
|
|
|
if (AssetOperations.Delete(config)) _listPane.Refresh(null);
|
|
|
|
|
}) { text = "删除" };
|
|
|
|
|
del.style.borderLeftColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
|
|
|
|
del.style.borderRightColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
|
|
|
|
del.style.borderTopColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
|
|
|
|
del.style.borderBottomColor = new StyleColor(new Color(0.8f, 0.3f, 0.3f, 0.6f));
|
|
|
|
|
del.style.borderLeftWidth = 1;
|
|
|
|
|
del.style.borderRightWidth = 1;
|
|
|
|
|
del.style.borderTopWidth = 1;
|
|
|
|
|
del.style.borderBottomWidth = 1;
|
|
|
|
|
del.style.marginLeft = 8;
|
|
|
|
|
new Button(() => { var c = AssetOperations.Clone(config, ConfigFolder); if (c != null) _configPane.Refresh(c); })
|
|
|
|
|
{ text = "克隆..." }.AlsoAddTo(bar);
|
|
|
|
|
var del = new Button(() => { if (AssetOperations.Delete(config)) _configPane.Refresh(null); }) { text = "删除" };
|
|
|
|
|
ApplyDeleteStyle(del);
|
|
|
|
|
del.AlsoAddTo(bar);
|
|
|
|
|
return bar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── FormSO 详情 ───────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
private static VisualElement BuildFormCard(FormSO f)
|
|
|
|
|
{
|
|
|
|
|
var card = SkillModule.MakeCard();
|
|
|
|
|
SkillModule.AddChip(card, "类型", f.formType.ToString());
|
|
|
|
|
SkillModule.AddChip(card, "ID", string.IsNullOrEmpty(f.formId) ? "-" : f.formId);
|
|
|
|
|
SkillModule.AddChip(card, "显示名", string.IsNullOrEmpty(f.displayName) ? "-" : f.displayName);
|
|
|
|
|
if (f.defaultWeapon != null)
|
|
|
|
|
SkillModule.AddChip(card, "默认武器", f.defaultWeapon.name);
|
|
|
|
|
return card;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private VisualElement BuildFormActionBar(FormSO form)
|
|
|
|
|
{
|
|
|
|
|
var bar = SkillModule.MakeActionBar();
|
|
|
|
|
new Button(() => { EditorGUIUtility.PingObject(form); Selection.activeObject = form; })
|
|
|
|
|
{ text = "定位" }.AlsoAddTo(bar);
|
|
|
|
|
new Button(() => { var c = AssetOperations.Clone(form, FormFolder); if (c != null) _formPane.Refresh(c); })
|
|
|
|
|
{ text = "克隆..." }.AlsoAddTo(bar);
|
|
|
|
|
var del = new Button(() => { if (AssetOperations.Delete(form)) _formPane.Refresh(null); }) { text = "删除" };
|
|
|
|
|
ApplyDeleteStyle(del);
|
|
|
|
|
del.AlsoAddTo(bar);
|
|
|
|
|
return bar;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ── 共用 ─────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|