Data调整
This commit is contained in:
8
Assets/AI Toolkit.meta
Normal file
8
Assets/AI Toolkit.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b4468c37c2d718a4896baa8c5aa2e2e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/AI Toolkit/Temp.meta
Normal file
8
Assets/AI Toolkit/Temp.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed82fe2a188a4644d8b3d3d050c27b6b
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -25,6 +25,8 @@ MonoBehaviour:
|
||||
functionText: Card_Basic_GreatswordSweep_FunctionText
|
||||
cardDescription: '$Keyword("Sorcery"), $Keyword("LifeSteal"): $Attribute("LifeStealPercent",
|
||||
true, true), deal $Attribute("Damage") darkness damage 3 times to all enemies.'
|
||||
intentionIconKeys: []
|
||||
intentionValueNames: []
|
||||
baseWeight: 0
|
||||
variableAttributes:
|
||||
dictionaryList:
|
||||
|
||||
@@ -25,6 +25,8 @@ MonoBehaviour:
|
||||
cardLayoutTags: []
|
||||
functionText: Card_Basic_HellfireBlast_FunctionText
|
||||
cardDescription:
|
||||
intentionIconKeys: []
|
||||
intentionValueNames: []
|
||||
baseWeight: 1
|
||||
variableAttributes:
|
||||
dictionaryList:
|
||||
|
||||
@@ -12,4 +12,11 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: afb8fcbb8d897e449a135120c7516dbd, type: 3}
|
||||
m_Name: Basic_ModEditReference
|
||||
m_EditorClassIdentifier: GameAPI::Continentis.Mods.ModEditReference
|
||||
cardKeywordsReference: {fileID: 11400000, guid: af4030fdce3a4774b90f808d1a3bced8, type: 2}
|
||||
groups:
|
||||
- groupName: CardKeywords
|
||||
items:
|
||||
- TargetSelf
|
||||
- groupName: IntentionIconKeys
|
||||
items:
|
||||
- PhysicsAttack
|
||||
- MagicAttack
|
||||
|
||||
@@ -43,7 +43,10 @@ namespace Continentis.MainGame.Card
|
||||
public string functionText;
|
||||
public string cardDescription;
|
||||
|
||||
[Header("Intention")] public float baseWeight = 0f;
|
||||
[Header("Intention")]
|
||||
public List<string> intentionIconKeys;
|
||||
public List<string> intentionValueNames;
|
||||
public float baseWeight = 0f;
|
||||
|
||||
[Header("Attributes")] [Tooltip("可变属性,这个属性会自动设置BaseAttr进入Original,设置Attr,BaseAttrOffset=0,以及DisplayAttr进入Current")]
|
||||
public SerializableDictionary<string, float> variableAttributes = new SerializableDictionary<string, float>();
|
||||
|
||||
@@ -27,8 +27,11 @@ namespace Continentis.MainGame.Card
|
||||
private SerializedProperty functionTextProp;
|
||||
private SerializedProperty cardDescriptionProp;
|
||||
|
||||
private SerializedProperty intentionIconKeysProp;
|
||||
private SerializedProperty intentionValueNamesProp;
|
||||
private SerializedProperty baseWeightProp;
|
||||
|
||||
|
||||
private SerializedProperty variableAttributesProp;
|
||||
private SerializedProperty originalAttributesProp;
|
||||
private SerializedProperty runtimeCurrentAttributesProp;
|
||||
@@ -42,9 +45,6 @@ namespace Continentis.MainGame.Card
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
|
||||
LoadAllKeywordsFromEditRefs();
|
||||
|
||||
// 在启用时,根据我们修改后的字段名找到对应的SerializedProperty
|
||||
modNameProp = serializedObject.FindProperty("modName");
|
||||
classNameProp = serializedObject.FindProperty("className");
|
||||
@@ -57,7 +57,11 @@ namespace Continentis.MainGame.Card
|
||||
cardLayoutTagsProp = serializedObject.FindProperty("cardLayoutTags");
|
||||
functionTextProp = serializedObject.FindProperty("functionText");
|
||||
cardDescriptionProp = serializedObject.FindProperty("cardDescription");
|
||||
|
||||
intentionIconKeysProp = serializedObject.FindProperty("intentionIconKeys");
|
||||
intentionValueNamesProp = serializedObject.FindProperty("intentionValueNames");
|
||||
baseWeightProp = serializedObject.FindProperty("baseWeight");
|
||||
|
||||
variableAttributesProp = serializedObject.FindProperty("variableAttributes");
|
||||
originalAttributesProp = serializedObject.FindProperty("originalAttributes");
|
||||
runtimeCurrentAttributesProp = serializedObject.FindProperty("runtimeCurrentAttributes");
|
||||
@@ -116,11 +120,7 @@ namespace Continentis.MainGame.Card
|
||||
|
||||
EditorGUILayout.PropertyField(cardRarityProp);
|
||||
EditorGUILayout.PropertyField(cardTypeProp);
|
||||
EditorGUILayout.PropertyField(keywordsProp, true);
|
||||
if (keywordsProp.isExpanded)
|
||||
{
|
||||
DrawKeywordSelector();
|
||||
}
|
||||
DrawListWithEditRefSelector(keywordsProp, "CardKeywords");
|
||||
|
||||
EditorGUILayout.PropertyField(cardSpriteProp);
|
||||
EditorGUILayout.PropertyField(cardLayoutTagsProp, true);
|
||||
@@ -129,6 +129,8 @@ namespace Continentis.MainGame.Card
|
||||
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.LabelField("Attributes", EditorStyles.boldLabel);
|
||||
DrawListWithEditRefSelector(intentionIconKeysProp, "IntentionIconKeys");
|
||||
DrawListWithLocalSelector(intentionValueNamesProp, "variableAttributes");
|
||||
EditorGUILayout.PropertyField(baseWeightProp);
|
||||
EditorGUILayout.PropertyField(variableAttributesProp, true);
|
||||
EditorGUILayout.PropertyField(originalAttributesProp, true);
|
||||
@@ -150,106 +152,5 @@ namespace Continentis.MainGame.Card
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public partial class CardDataEditor
|
||||
{
|
||||
private List<string> allAvailableKeywords;
|
||||
|
||||
/// <summary>
|
||||
/// 使用 AssetDatabase 查找项目中的所有 KeywordDatabase 并合并它们的列表
|
||||
/// </summary>
|
||||
private void LoadAllKeywordsFromEditRefs()
|
||||
{
|
||||
// 使用 HashSet 来自动处理重复的关键词
|
||||
HashSet<string> allKeywordsSet = new HashSet<string>();
|
||||
|
||||
// 1. 查找项目中所有类型为 "KeywordDatabase" 的
|
||||
// "t:KeywordDatabase" 是一个搜索过滤器,t: 表示按类型搜索
|
||||
string[] guids = AssetDatabase.FindAssets("t:ModEditReference");
|
||||
|
||||
foreach (string guid in guids)
|
||||
{
|
||||
// 2. 将 GUID 转换为资产路径
|
||||
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
|
||||
// 3. 加载该路径下的 ScriptableObject
|
||||
ModEditReference editRef = AssetDatabase.LoadAssetAtPath<ModEditReference>(assetPath);
|
||||
EditKeywordsReference cardKeywordsRef = editRef.cardKeywordsReference;
|
||||
|
||||
if (cardKeywordsRef != null && cardKeywordsRef.keywordRefs != null)
|
||||
{
|
||||
// 4. 将词库中的所有词添加到 Set 中
|
||||
foreach (string keyword in cardKeywordsRef.keywordRefs.Keys)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(keyword))
|
||||
{
|
||||
allKeywordsSet.Add(keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 将 Set 转换为 List 并排序,以便在菜单中清晰显示
|
||||
allAvailableKeywords = allKeywordsSet.ToList();
|
||||
allAvailableKeywords.Sort();
|
||||
}
|
||||
|
||||
private void DrawKeywordSelector()
|
||||
{
|
||||
// 1. 检查是否找到了任何关键词
|
||||
if (allAvailableKeywords == null || allAvailableKeywords.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("在项目中没有找到任何 KeywordDatabase,或者词库为空。", MessageType.Warning);
|
||||
// 显示一个刷新按钮,以防用户刚刚创建了词库
|
||||
if (GUILayout.Button("Refresh Keyword Edit References"))
|
||||
{
|
||||
LoadAllKeywordsFromEditRefs();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
List<string> currentKeywords = (target as CardData)!.keywords;
|
||||
|
||||
// 2. 找出尚未添加的关键词
|
||||
List<string> keywordsToAdd = allAvailableKeywords.Except(currentKeywords).ToList();
|
||||
|
||||
// 3. 如果所有关键词都添加了,显示提示
|
||||
if (keywordsToAdd.Count == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("所有可用的关键词都已添加。", MessageType.Info);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 4. 绘制 "Add Keyword" 按钮
|
||||
if (GUILayout.Button("Add Keyword from Edit Refs..."))
|
||||
{
|
||||
GenericMenu menu = new GenericMenu();
|
||||
foreach (string keyword in keywordsToAdd)
|
||||
{
|
||||
menu.AddItem(new GUIContent(keyword), false, () => {
|
||||
AddKeywordToList(keyword);
|
||||
});
|
||||
}
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
}
|
||||
|
||||
// 5. (可选) 添加一个手动刷新按钮
|
||||
// 因为 AssetDatabase.FindAssets() 速度很快,所以我们也可以在每次GUI绘制时都调用
|
||||
// 但如果词库很多,使用按钮刷新更好。
|
||||
/*if (GUILayout.Button("Refresh Keyword Databases"))
|
||||
{
|
||||
LoadAllKeywordsFromEditRefs();
|
||||
}*/
|
||||
}
|
||||
|
||||
private void AddKeywordToList(string keyword)
|
||||
{
|
||||
keywordsProp.InsertArrayElementAtIndex(keywordsProp.arraySize);
|
||||
SerializedProperty newElement = keywordsProp.GetArrayElementAtIndex(keywordsProp.arraySize - 1);
|
||||
newElement.stringValue = keyword;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,3 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using SLSFramework.General;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Serialization;
|
||||
@@ -7,6 +10,23 @@ namespace Continentis.Mods
|
||||
[CreateAssetMenu(fileName = "ModEditReference", menuName = "Continentis/Mod/Edit Reference", order = 2)]
|
||||
public class ModEditReference : ScriptableObject
|
||||
{
|
||||
[FormerlySerializedAs("keywordsReference")] public EditKeywordsReference cardKeywordsReference;
|
||||
[Serializable]
|
||||
public struct ContentGroup
|
||||
{
|
||||
public string groupName; // 例如 "FunctionalTags", "BuffIDs"
|
||||
public List<string> items;
|
||||
}
|
||||
|
||||
public List<ContentGroup> groups = new List<ContentGroup>();
|
||||
|
||||
public List<string> GetItems(string groupName)
|
||||
{
|
||||
foreach (var contentGroup in groups.Where(contentGroup => contentGroup.groupName == groupName))
|
||||
{
|
||||
return contentGroup.items;
|
||||
}
|
||||
|
||||
return new List<string>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Continentis.Mods;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
@@ -135,7 +136,244 @@ namespace SLSFramework.UModAssistance
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region List<string>选择器,通过类型查找资产,将其名称存储在列表中
|
||||
public partial class DataEditor
|
||||
{
|
||||
/// <summary>
|
||||
/// (旧功能) 从 EditorContentCollection 中选择
|
||||
/// </summary>
|
||||
private void DrawContentSelector(SerializedProperty targetListProp, string groupName, string label = null)
|
||||
{
|
||||
if (!targetListProp.isExpanded) return;
|
||||
|
||||
DrawGenericSelectorButton($"Add {groupName}...", targetListProp, () =>
|
||||
{
|
||||
// 1. 查找所有配置文件
|
||||
var collections = FindAllModEditReferences();
|
||||
|
||||
if (collections == null || collections.Count == 0)
|
||||
{
|
||||
Debug.LogError("No 'EditorContentCollection' assets found in the project.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 2. 整合所有文件中的同名 Group 数据
|
||||
List<string> aggregatedItems = new List<string>();
|
||||
bool groupFound = false;
|
||||
|
||||
foreach (var collection in collections)
|
||||
{
|
||||
var items = collection.GetItems(groupName);
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
aggregatedItems.AddRange(items);
|
||||
groupFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!groupFound)
|
||||
{
|
||||
Debug.LogWarning($"Group '{groupName}' not found in any EditorContentCollection.");
|
||||
return null;
|
||||
}
|
||||
|
||||
// 3. 去重并返回 (使用 Linq 的 Distinct)
|
||||
return aggregatedItems.Distinct().ToList();
|
||||
}, $"Select {groupName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// (新功能) 从当前对象的另一个字段 (List<string> 或 Dictionary) 中选择
|
||||
/// </summary>
|
||||
/// <param name="targetListProp">要添加元素的目标 List</param>
|
||||
/// <param name="sourceFieldName">数据源字段的变量名 (可以是 List<string> 或 Dictionary<string, T>)</param>
|
||||
/// <param name="label">可选标签</param>
|
||||
/// <param name="buttonLabel">可选按钮标签</param>
|
||||
private void DrawLocalContentSelector(SerializedProperty targetListProp, string sourceFieldName, string label = null, string buttonLabel = null)
|
||||
{
|
||||
if (string.IsNullOrEmpty(buttonLabel)) buttonLabel = $"Add from {sourceFieldName}...";
|
||||
|
||||
DrawGenericSelectorButton(buttonLabel, targetListProp, () =>
|
||||
{
|
||||
// 数据获取逻辑:利用反射从当前对象内部查找
|
||||
var targetObj = serializedObject.targetObject;
|
||||
// 支持私有和公有字段
|
||||
var field = targetObj.GetType().GetField(sourceFieldName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
var value = field.GetValue(targetObj);
|
||||
if (value != null)
|
||||
{
|
||||
// 情况 1: 它是 Dictionary (SerializableDictionary 或 普通 Dictionary)
|
||||
// 我们通过反射查找 "Keys" 属性,这样兼容性最好
|
||||
var keysProp = value.GetType().GetProperty("Keys");
|
||||
if (keysProp != null)
|
||||
{
|
||||
var keys = keysProp.GetValue(value) as System.Collections.IEnumerable;
|
||||
if (keys != null)
|
||||
{
|
||||
// 将所有 Key 转为 string 返回
|
||||
return keys.Cast<object>().Select(k => k.ToString()).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
// 情况 2: 它是 List<string> 或 string[]
|
||||
if (value is IEnumerable<string> list)
|
||||
{
|
||||
return list.ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Could not find valid string list or dictionary keys in field '{sourceFieldName}'.");
|
||||
return null;
|
||||
}, $"Select from {sourceFieldName}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 这是一个私有的通用辅助方法,处理按钮绘制和窗口调用
|
||||
/// </summary>
|
||||
private void DrawGenericSelectorButton(string buttonText, SerializedProperty targetListProp, Func<List<string>> dataProvider, string windowTitle)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
// 仅仅为了排版美观的占位
|
||||
// EditorGUILayout.LabelField("", GUILayout.Width(0));
|
||||
|
||||
if (GUILayout.Button(buttonText, GUILayout.Height(20)))
|
||||
{
|
||||
// 1. 获取数据 (执行传入的逻辑)
|
||||
List<string> items = dataProvider?.Invoke();
|
||||
|
||||
if (items != null && items.Count > 0)
|
||||
{
|
||||
// 2. 打开通用窗口
|
||||
ContentSelectorWindow.Show(windowTitle, items, (selectedItem) =>
|
||||
{
|
||||
// 3. 添加到列表的通用逻辑
|
||||
bool alreadyExists = false;
|
||||
for (int i = 0; i < targetListProp.arraySize; i++)
|
||||
{
|
||||
if (targetListProp.GetArrayElementAtIndex(i).stringValue == selectedItem)
|
||||
{
|
||||
alreadyExists = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!alreadyExists)
|
||||
{
|
||||
targetListProp.InsertArrayElementAtIndex(targetListProp.arraySize);
|
||||
targetListProp.GetArrayElementAtIndex(targetListProp.arraySize - 1).stringValue = selectedItem;
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogWarning($"Item '{selectedItem}' already exists.");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 组合绘制:默认列表UI + 本地源选择按钮
|
||||
/// </summary>
|
||||
protected void DrawListWithLocalSelector(SerializedProperty listProp, string sourceFieldName, string label = null)
|
||||
{
|
||||
if (label != null) EditorGUILayout.PropertyField(listProp, new GUIContent(label), true);
|
||||
else EditorGUILayout.PropertyField(listProp, true);
|
||||
|
||||
if (listProp.isExpanded)
|
||||
{
|
||||
DrawLocalContentSelector(listProp, sourceFieldName);
|
||||
}
|
||||
//EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
// (DrawListWithContentSelector 保持不变,可以继续使用)
|
||||
protected void DrawListWithEditRefSelector(SerializedProperty listProp, string groupName, string label = null)
|
||||
{
|
||||
if (label != null) EditorGUILayout.PropertyField(listProp, new GUIContent(label), true);
|
||||
else EditorGUILayout.PropertyField(listProp, true);
|
||||
|
||||
if (listProp.isExpanded)
|
||||
{
|
||||
DrawContentSelector(listProp, groupName);
|
||||
}
|
||||
//EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
private static List<ModEditReference> FindAllModEditReferences()
|
||||
{
|
||||
string[] guids = AssetDatabase.FindAssets("t:ModEditReference");
|
||||
List<ModEditReference> results = new List<ModEditReference>();
|
||||
|
||||
foreach (var guid in guids)
|
||||
{
|
||||
var asset = AssetDatabase.LoadAssetAtPath<ModEditReference>(AssetDatabase.GUIDToAssetPath(guid));
|
||||
if (asset != null)
|
||||
{
|
||||
results.Add(asset);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
// --- 重构后的通用窗口 ---
|
||||
private class ContentSelectorWindow : EditorWindow
|
||||
{
|
||||
private Action<string> _onSelectCallback;
|
||||
private List<string> _allItems; // 数据直接从外部传入
|
||||
private List<string> _filteredItems;
|
||||
private string _searchString = "";
|
||||
private Vector2 _scrollPos;
|
||||
|
||||
// Show 方法现在的签名变得更通用了,不再绑定 groupName
|
||||
public static void Show(string title, List<string> items, Action<string> onSelect)
|
||||
{
|
||||
var window = GetWindow<ContentSelectorWindow>(true, title, true);
|
||||
window.minSize = new Vector2(250, 300);
|
||||
window._onSelectCallback = onSelect;
|
||||
window._allItems = items; // 直接接收数据
|
||||
window.FilterList();
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
EditorGUI.BeginChangeCheck();
|
||||
_searchString = GUILayout.TextField(_searchString, GUI.skin.FindStyle("ToolbarSearchTextField"));
|
||||
if (GUILayout.Button("", GUI.skin.FindStyle("ToolbarSearchCancelButton"))) _searchString = "";
|
||||
if (EditorGUI.EndChangeCheck()) FilterList();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
_scrollPos = EditorGUILayout.BeginScrollView(_scrollPos);
|
||||
if (_filteredItems != null)
|
||||
{
|
||||
foreach (var item in _filteredItems)
|
||||
{
|
||||
if (GUILayout.Button(item, EditorStyles.label))
|
||||
{
|
||||
_onSelectCallback?.Invoke(item);
|
||||
// this.Close(); // 可选:点击后关闭
|
||||
}
|
||||
}
|
||||
}
|
||||
EditorGUILayout.EndScrollView();
|
||||
}
|
||||
|
||||
private void FilterList()
|
||||
{
|
||||
if (string.IsNullOrEmpty(_searchString)) _filteredItems = new List<string>(_allItems);
|
||||
else _filteredItems = _allItems.Where(i => i.IndexOf(_searchString, StringComparison.OrdinalIgnoreCase) >= 0).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Searchable Type选择器,将获取的类型名存入一个string中
|
||||
|
||||
public partial class DataEditor
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user