Data调整

This commit is contained in:
SoulliesOfficial
2025-11-30 14:21:08 -05:00
parent ad4948207e
commit afbeeebe75
34 changed files with 533 additions and 202 deletions

8
Assets/AI Toolkit.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b4468c37c2d718a4896baa8c5aa2e2e8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ed82fe2a188a4644d8b3d3d050c27b6b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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:

View File

@@ -25,6 +25,8 @@ MonoBehaviour:
cardLayoutTags: []
functionText: Card_Basic_HellfireBlast_FunctionText
cardDescription:
intentionIconKeys: []
intentionValueNames: []
baseWeight: 1
variableAttributes:
dictionaryList:

View File

@@ -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

View File

@@ -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设置AttrBaseAttrOffset=0以及DisplayAttr进入Current")]
public SerializableDictionary<string, float> variableAttributes = new SerializableDictionary<string, float>();

View File

@@ -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

View File

@@ -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>();
}
}
}

View File

@@ -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