Files
Cielonos/Assets/Scripts/MainGame/Characters/Player/Items/Data/ComboData.cs
SoulliesOfficial f26f9fd374 爆更
2026-03-20 12:07:44 -04:00

207 lines
6.9 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 Sirenix.OdinInspector;
using SoftCircuits.Collections;
using UnityEngine;
namespace Cielonos.MainGame.Characters.Inventory
{
/// <summary>
/// 存储连招树定义的 ScriptableObject。
/// 这是你的“蓝图”资产。
/// </summary>
[CreateAssetMenu(fileName = "ComboData", menuName = "Cielonos/Items/ComboData")]
public class ComboData : SerializedScriptableObject
{
//[InlineProperty] public ComboTreeData tree;
[InlineProperty]
[Title("连招树编辑器", "可视化编辑连招树的节点和分支")]
public Dictionary<string, ComboTreeData> comboTrees;
public ComboTreeData mainTree => comboTrees["Main"];
[OnInspectorInit]
private void OnEnable()
{
if (comboTrees == null)
{
comboTrees = new Dictionary<string, ComboTreeData>();
ComboTreeData tree = new ComboTreeData();
if (tree.nodes == null || tree.nodes.Count == 0)
{
tree.nodes = new List<ComboNodeData>();
tree.nodes.Add(new ComboNodeData() { referenceName = "Root" });
}
tree.InitializeNodeReferences();
comboTrees["Main"] = tree;
}
}
}
/// <summary>
/// 连招树的数据容器
/// </summary>
[Serializable]
public class ComboTreeData
{
public float resetTime = 0.25f;
[ListDrawerSettings(
DraggableItems = true, // 现在可以安全地拖动排序了!
NumberOfItemsPerPage = 20,
CustomAddFunction = "AddNode",
CustomRemoveElementFunction = "RemoveNode",
ListElementLabelName = "GetComboNodeLabel")]
[HideReferenceObjectPicker]
public List<ComboNodeData> nodes;
/// <summary>
/// Odin Inspector 自定义添加按钮的实现
/// </summary>
private void AddNode()
{
// 查找一个唯一的默认名称
int counter = nodes.Count - 1;
string newName = counter.ToString();
while (nodes.Any(n => n.referenceName == newName))
{
counter++;
newName = counter.ToString();
}
var newNode = new ComboNodeData() { referenceName = newName };
nodes.Add(newNode);
// 添加后,立即初始化引用
InitializeNodeReferences();
}
/// <summary>
/// Odin Inspector 自定义移除按钮的实现
/// </summary>
private void RemoveNode(ComboNodeData node)
{
// 规则:不可删除 RootNode
if (node.referenceName == "Root")
{
Debug.LogWarning("不能删除 Root 节点。");
return;
}
nodes.Remove(node);
InitializeNodeReferences(); // 移除后,更新引用
}
/// <summary>
/// 将父树实例传递给所有节点和分支用于Odin下拉列表
/// </summary>
public void InitializeNodeReferences()
{
if (nodes == null) return;
}
/// <summary>
/// 帮助 Odin 下拉列表获取所有可用节点名称
/// </summary>
public IEnumerable<string> GetNodeReferenceNames()
{
if (nodes == null) return Enumerable.Empty<string>();
return nodes.Select(n => n.referenceName).Where(n => !string.IsNullOrEmpty(n));
}
public ComboSubmodule.ComboTree ToRuntime(ComboSubmodule owner)
{
var runtimeTree = new ComboSubmodule.ComboTree(owner, resetTime);
runtimeTree.nodes = new List<ComboSubmodule.ComboTree.Node>();
// 创建运行时节点
foreach (var nodeData in nodes)
{
var runtimeNode = new ComboSubmodule.ComboTree.Node(nodes.IndexOf(nodeData), nodeData.referenceName);
runtimeNode.branches = new List<ComboSubmodule.ComboTree.Branch>();
// 创建运行时分支
foreach (var branchData in nodeData.branches)
{
var runtimeBranch = new ComboSubmodule.ComboTree.Branch(nodes.FindIndex(n => n.referenceName == branchData.nextNodeRefName), branchData.operation);
runtimeNode.branches.Add(runtimeBranch);
}
runtimeTree.nodes.Add(runtimeNode);
}
return runtimeTree;
}
}
/// <summary>
/// 连招节点的数据定义
/// </summary>
[Serializable]
public class ComboNodeData
{
[ValidateInput("ValidateReferenceName", "引用名称(Reference Name)必须唯一且不能为空。")]
[InfoBox("这是 Root 节点,是所有连招的起点。", InfoMessageType.Info, "IsRootNode")]
public string referenceName;
[ListDrawerSettings(NumberOfItemsPerPage = 10, CustomAddFunction = "AddBranch")]
[HideReferenceObjectPicker]
public List<ComboBranchData> branches = new List<ComboBranchData>();
private bool IsRootNode() => referenceName == "Root";
private bool ValidateReferenceName(string name, ref string errorMessage)
{
if (string.IsNullOrEmpty(name))
{
errorMessage = "引用名称不能为空。";
return false;
}
return true;
}
private void AddBranch()
{
branches.Add(new ComboBranchData());
}
private string GetComboNodeLabel()
{
// 1. 获取当前节点名称
string name = string.IsNullOrEmpty(referenceName) ? "[未命名]" : referenceName;
// 2. 如果没有分支,直接返回节点名
if (branches == null || branches.Count == 0)
{
return name;
}
// 3. 拼接子节点名称
// 这里使用 Linq 提取所有分支的目标节点名
// 格式示例: "Root - (1, 2, 3)"
List<string> targetNodes = branches
.Select(b => b == null || string.IsNullOrEmpty(b.nextNodeRefName) ? "?" : $"{b.operation}->{b.nextNodeRefName}").ToList();
return $"{name} - ({string.Join(", ", targetNodes)})";
}
}
/// <summary>
/// 连招分支的数据定义
/// </summary>
[Serializable]
public class ComboBranchData
{
[Tooltip("触发此分支的输入操作,例如 'L', 'R', 'Attack'")] [HorizontalGroup("Branch", 100)] [LabelWidth(60)]
public string operation;
[Tooltip("此分支链接到的下一个节点")]
[HorizontalGroup("Branch")]
[LabelText("下一个节点")]
public string nextNodeRefName; // <-- 使用名称引用,而不是索引
}
}