提交GAS 打算做一个帧同步的GAS

This commit is contained in:
DESKTOP-5RP3AKU\Jisol
2024-10-18 03:16:09 +08:00
parent b0a2e4a900
commit d9b0c78827
726 changed files with 76601 additions and 0 deletions

View File

@@ -0,0 +1,223 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using GAS.Editor.General;
using GAS.General;
using GAS.General.Validation;
using Sirenix.OdinInspector;
using Sirenix.Utilities.Editor;
using UnityEditor;
using UnityEngine;
namespace GAS.Editor
{
[Serializable]
public class AttributeSetConfig
{
public static AttributeSetAsset ParentAsset;
private static IEnumerable AttributeChoices = new ValueDropdownList<string>();
[HorizontalGroup("A")]
[HorizontalGroup("A/R", order: 1)]
[DisplayAsString(TextAlignment.Left, FontSize = 18)]
[HideLabel]
[ValidateInput("@ExistDuplicatedAttribute() == false", GASTextDefine.ERROR_DuplicatedAttribute)]
[InfoBox(GASTextDefine.ERROR_Empty, InfoMessageType.Error, VisibleIf = "EmptyAttribute")]
[InfoBox(GASTextDefine.ERROR_EmptyName, InfoMessageType.Error, VisibleIf = "EmptyAttributeSetName")]
public string Name = "Unnamed";
[Space]
[ListDrawerSettings(ShowFoldout = true, ShowIndexLabels = false, ShowItemCount = false, ShowPaging = false)]
[ValueDropdown("AttributeChoices", IsUniqueList = true)]
[DisableContextMenu(disableForMember: false, disableCollectionElements: true)]
[CustomContextMenu("排序", "@SortAttributeNames()")]
[LabelText("Attributes")]
[Searchable]
public List<string> AttributeNames = new();
private void SortAttributeNames() => AttributeNames = AttributeNames.OrderBy(x => x).ToList();
[HorizontalGroup("A", Width = 50)]
[HorizontalGroup("A/L", order: 0, Width = 50)]
[Button(SdfIconType.Brush, "", ButtonHeight = 25)]
public void EditName()
{
StringEditWindow.OpenWindow("AttributeSet Name", Name, Validations.ValidateVariableName, OnEditNameSuccess,
"Edit AttributeSet Name");
}
private void OnEditNameSuccess(string newName)
{
Name = newName;
ParentAsset.SaveAsset();
}
public static void SetAttributeChoices(List<string> attributeChoices)
{
var choices = new ValueDropdownList<string>();
foreach (var attribute in attributeChoices)
{
choices.Add(attribute, attribute);
}
AttributeChoices = choices;
}
public bool EmptyAttribute()
{
return AttributeNames.Count == 0;
}
public bool EmptyAttributeSetName()
{
return string.IsNullOrEmpty(Name);
}
public bool ExistDuplicatedAttribute()
{
var duplicates = AttributeNames
.Where(a => !string.IsNullOrEmpty(a))
.GroupBy(a => a)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList();
return duplicates.Count > 0;
}
}
[FilePath(GasDefine.GAS_ATTRIBUTE_SET_ASSET_PATH)]
public class AttributeSetAsset : ScriptableSingleton<AttributeSetAsset>
{
[BoxGroup("Warning", order: -1)]
[HideLabel]
[ShowIf("ExistDuplicatedAttributeSetName")]
[DisplayAsString(TextAlignment.Left, true)]
public string ERROR_DuplicatedAttributeSet = "";
[VerticalGroup("AttributeSetConfigs", order: 1)]
[ListDrawerSettings(ShowFoldout = true,
CustomAddFunction = "OnAddAttributeSet",
CustomRemoveElementFunction = "OnRemoveElement",
CustomRemoveIndexFunction = "OnRemoveIndex")]
[DisableContextMenu(disableForMember: false, disableCollectionElements: true)]
[CustomContextMenu("排序", "@SortAttributeSetConfigs()")]
[Searchable]
public List<AttributeSetConfig> AttributeSetConfigs = new List<AttributeSetConfig>();
private void SortAttributeSetConfigs() => AttributeSetConfigs = AttributeSetConfigs.OrderBy(x => x.Name).ToList();
private void OnEnable()
{
AttributeSetConfig.ParentAsset = this;
var asset = AttributeAsset.LoadOrCreate();
var attributeChoices = asset != null ? (from attr in asset.attributes where !string.IsNullOrWhiteSpace(attr.Name) select attr.Name).ToList() : new();
AttributeSetConfig.SetAttributeChoices(attributeChoices);
}
public void SaveAsset()
{
EditorUtility.SetDirty(this);
UpdateAsset(this);
Save();
Debug.Log("[EX] AttributeSetAsset save!");
}
[VerticalGroup("Generate AttributeSet Code", order: 0)]
[GUIColor(0, 0.9f, 0)]
[Button(SdfIconType.Upload, GASTextDefine.BUTTON_GenerateAttributeSetCode, ButtonHeight = 30, Expanded = true)]
[InfoBox(GASTextDefine.ERROR_InElements, InfoMessageType.Error, VisibleIf = "ErrorInElements")]
private void GenCode()
{
if (ExistDuplicatedAttributeSetName() || ErrorInElements())
{
EditorUtility.DisplayDialog("Warning", "Please check the warning message!\n" +
"Fix the AttributeSet Error!\n", "OK");
return;
}
SaveAsset();
AttributeSetClassGen.Gen();
AssetDatabase.Refresh();
}
bool ErrorInElements()
{
return AttributeSetConfigs.Any(attribute =>
attribute.EmptyAttribute() ||
attribute.ExistDuplicatedAttribute() ||
attribute.EmptyAttributeSetName());
}
bool ExistDuplicatedAttributeSetName()
{
var duplicates = AttributeSetConfigs
.Where(a => !string.IsNullOrEmpty(a.Name))
.GroupBy(a => a.Name)
.Where(group => group.Count() > 1)
.Select(group => group.Key)
.ToList();
if (duplicates.Count > 0)
{
var duplicatedAttributeSets = duplicates.Aggregate("", (current, d) => current + d + ",");
duplicatedAttributeSets = duplicatedAttributeSets.Remove(duplicatedAttributeSets.Length - 1, 1);
ERROR_DuplicatedAttributeSet =
string.Format(GASTextDefine.ERROR_DuplicatedAttributeSet, duplicatedAttributeSets);
}
return duplicates.Count > 0;
}
private void OnAddAttributeSet()
{
StringEditWindow.OpenWindow("AttributeSet Name", "", (newName) =>
{
var validateVariableName = Validations.ValidateVariableName(newName);
if (!validateVariableName.IsValid)
{
return validateVariableName;
}
if (AttributeSetConfigs.Exists(x => x.Name == newName))
{
return ValidationResult.Invalid($"The name(\"{newName}\") already exists!");
}
return ValidationResult.Valid;
},
attributeSetName => AttributeSetConfigs.Add(new AttributeSetConfig() { Name = attributeSetName }),
"Create new AttributeSet");
GUIUtility.ExitGUI(); // In order to solve: "EndLayoutGroup: BeginLayoutGroup must be called first."
}
private int OnRemoveElement(AttributeSetConfig attributeSet)
{
var result = EditorUtility.DisplayDialog("Confirmation",
$"Are you sure you want to REMOVE AttributeSet:{attributeSet.Name}?",
"Yes", "No");
if (!result) return -1;
Debug.Log($"[EX] AttributeSet Asset remove element:{attributeSet.Name} !");
SaveAsset();
return AttributeSetConfigs.IndexOf(attributeSet);
}
private int OnRemoveIndex(int index)
{
var attributeSet = AttributeSetConfigs[index];
var result = EditorUtility.DisplayDialog("Confirmation",
$"Are you sure you want to REMOVE AttributeSet:{attributeSet.Name}?",
"Yes", "No");
if (!result) return -1;
AttributeSetConfigs.RemoveAt(index);
Debug.Log($"[EX] Attribute Asset remove element:{attributeSet.Name} !");
SaveAsset();
return index;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b9c4e9ba159c4e7d8da87897fb20cb56
timeCreated: 1703054408

View File

@@ -0,0 +1,257 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using GAS.Runtime;
using UnityEditor;
using UnityEngine;
namespace GAS.Editor
{
public static class AttributeSetClassGen
{
public static void Gen()
{
var attributeSetAsset = AttributeSetAsset.LoadOrCreate();
var attributeAsset = AttributeAsset.LoadOrCreate();
var attributeNames =
(from t in attributeAsset.attributes where !string.IsNullOrWhiteSpace(t.Name) select t.Name)
.ToList();
// Check if AttributeSet contains attribute that is not defined in AttributeAsset
foreach (var attributeSetConfig in attributeSetAsset.AttributeSetConfigs)
{
foreach (var attributeName in attributeSetConfig.AttributeNames)
{
if (!attributeNames.Contains(attributeName))
{
var msg = $"Invalid Attribute(\"{attributeName}\") in AttributeSet(\"{attributeSetConfig.Name}\"), \"{attributeName}\" is not defined in AttributeAsset!";
Debug.LogError(msg);
EditorUtility.DisplayDialog("Error", msg, "OK");
return;
}
}
}
var invalidAttributes = attributeAsset.attributes.Where(x =>
x.CalculateMode is CalculateMode.MinValueOnly or CalculateMode.MaxValueOnly &&
x.SupportedOperation != SupportedOperation.Override).ToArray();
if (invalidAttributes.Length > 0)
{
var msg =
$"计算模式为\"\"或\"取最大值\"的属性只能支持\"替换\"操作:\n{string.Join("\n", invalidAttributes.Select(x => $"\"{x.Name}\""))}";
Debug.LogError(msg.Replace("\n", ", "));
EditorUtility.DisplayDialog("Error", msg, "OK");
return;
}
string pathWithoutAssets = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
var filePath =
$"{pathWithoutAssets}/{GASSettingAsset.CodeGenPath}/{GasDefine.GAS_ATTRIBUTESET_LIB_CSHARP_SCRIPT_NAME}";
GenerateAttributeCollection(attributeSetAsset.AttributeSetConfigs, attributeAsset, filePath);
Console.WriteLine($"Generated Code Script at path: {filePath}");
}
private static void GenerateAttributeCollection(List<AttributeSetConfig> attributeSetConfigs,
AttributeAsset attributeAsset, string filePath)
{
using var writer = new IndentedWriter(new StreamWriter(filePath));
writer.WriteLine("///////////////////////////////////");
writer.WriteLine("//// This is a generated file. ////");
writer.WriteLine("//// Do not modify it. ////");
writer.WriteLine("///////////////////////////////////");
writer.WriteLine("");
writer.WriteLine("using System;");
writer.WriteLine("using System.Collections.Generic;");
writer.WriteLine("");
writer.WriteLine("namespace GAS.Runtime");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeSetConfig in attributeSetConfigs.OrderBy(x => x.Name))
{
var validName = EditorUtil.MakeValidIdentifier(attributeSetConfig.Name);
writer.WriteLine($"public class AS_{validName} : AttributeSet");
writer.WriteLine("{");
writer.Indent++;
{
bool skippedFirst = false;
foreach (var attributeName in attributeSetConfig.AttributeNames.OrderBy(x => x))
{
var attributeAccessor = attributeAsset.attributes.Find(x => x.Name == attributeName);
if (!skippedFirst) skippedFirst = true;
else writer.WriteLine("");
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine($"#region {attributeName}");
writer.WriteLine("");
{
writer.WriteLine($"/// <summary>{attributeAccessor.Comment}</summary>");
writer.WriteLine($"public AttributeBase {validAttrName} {{ get; }} = new(\"AS_{validName}\", \"{attributeName}\", {attributeAccessor.DefaultValue}f, CalculateMode.{attributeAccessor.CalculateMode}, (SupportedOperation){(byte)attributeAccessor.SupportedOperation}, {(attributeAccessor.LimitMinValue ? attributeAccessor.MinValue + "f" : "float.MinValue")}, {(attributeAccessor.LimitMaxValue ? attributeAccessor.MaxValue + "f" : "float.MaxValue")});");
writer.WriteLine("");
writer.WriteLine($"public void Init{validAttrName}(float value) => {validAttrName}.Init(value);");
writer.WriteLine($"public void SetCurrent{validAttrName}(float value) => {validAttrName}.SetCurrentValue(value);");
writer.WriteLine($"public void SetBase{validAttrName}(float value) => {validAttrName}.SetBaseValue(value);");
writer.WriteLine($"public void SetMin{validAttrName}(float value) => {validAttrName}.SetMinValue(value);");
writer.WriteLine($"public void SetMax{validAttrName}(float value) => {validAttrName}.SetMaxValue(value);");
writer.WriteLine($"public void SetMinMax{validAttrName}(float min, float max) => {validAttrName}.SetMinMaxValue(min, max);");
}
writer.WriteLine("");
writer.WriteLine($"#endregion {attributeName}");
}
writer.WriteLine("");
writer.WriteLine("public override AttributeBase this[string key]");
writer.WriteLine("{");
writer.Indent++;
{
writer.WriteLine("get");
writer.WriteLine("{");
writer.Indent++;
{
writer.WriteLine("switch (key)");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeName in attributeSetConfig.AttributeNames)
{
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine($"case \"{validAttrName}\":");
writer.Indent++;
{
writer.WriteLine($"return {validAttrName};");
}
writer.Indent--;
}
}
writer.Indent--;
writer.WriteLine("}");
writer.WriteLine("");
writer.WriteLine("return null;");
}
writer.Indent--;
writer.WriteLine("}");
}
writer.Indent--;
writer.WriteLine("}");
writer.WriteLine("");
writer.WriteLine("public override string[] AttributeNames { get; } =");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeName in attributeSetConfig.AttributeNames)
{
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine($"\"{validAttrName}\",");
}
}
writer.Indent--;
writer.WriteLine("};");
writer.WriteLine("");
writer.WriteLine("public override void SetOwner(AbilitySystemComponent owner)");
writer.WriteLine("{");
writer.Indent++;
{
writer.WriteLine("_owner = owner;");
foreach (var attributeName in attributeSetConfig.AttributeNames)
{
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine($"{validAttrName}.SetOwner(owner);");
}
}
writer.Indent--;
writer.WriteLine("}");
writer.WriteLine("");
writer.WriteLine("public static class Lookup");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeName in attributeSetConfig.AttributeNames)
{
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine(
$"public const string {attributeName} = \"AS_{validName}.{validAttrName}\";");
}
}
writer.Indent--;
writer.WriteLine("}");
}
writer.Indent--;
writer.WriteLine("}");
writer.WriteLine("");
}
writer.WriteLine($"public static class GAttrSetLib");
writer.WriteLine("{");
writer.Indent++;
{
writer.WriteLine("public static readonly IReadOnlyDictionary<string, Type> AttrSetTypeDict = new Dictionary<string, Type>");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeSet in attributeSetConfigs)
{
var validName = EditorUtil.MakeValidIdentifier(attributeSet.Name);
writer.WriteLine($"{{ \"{attributeSet.Name}\", typeof(AS_{validName}) }},");
}
}
writer.Indent--;
writer.WriteLine("};");
writer.WriteLine("");
writer.WriteLine("public static readonly IReadOnlyDictionary<Type, string> TypeToName = new Dictionary<Type, string>");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeSet in attributeSetConfigs)
{
var validName = EditorUtil.MakeValidIdentifier(attributeSet.Name);
writer.WriteLine($"{{ typeof(AS_{validName}), nameof(AS_{validName}) }},");
}
}
writer.Indent--;
writer.WriteLine("};");
writer.WriteLine("");
writer.WriteLine("public static readonly IReadOnlyList<string> AttributeFullNames = new List<string>");
writer.WriteLine("{");
writer.Indent++;
{
foreach (var attributeSet in attributeSetConfigs)
{
var validName = EditorUtil.MakeValidIdentifier(attributeSet.Name);
foreach (var attributeName in attributeSet.AttributeNames)
{
string validAttrName = EditorUtil.MakeValidIdentifier(attributeName);
writer.WriteLine($"\"AS_{validName}.{validAttrName}\",");
}
}
}
writer.Indent--;
writer.WriteLine("};");
}
writer.Indent--;
writer.WriteLine("}");
}
writer.Indent--;
writer.Write("}");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8e974fd010a447309cdd4bd5abb5ac24
timeCreated: 1703129737

View File

@@ -0,0 +1,133 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace GAS.Editor
{
public class AttributeSetConfigEditorWindow : EditorWindow
{
private static List<string> _attributeOptions;
public string editedName = "";
public List<string> attributeNames;
private Action<string, List<string>> _callback;
private Func<AttributeSetConfig, bool> _checkAttributeSetValid;
private List<int> _selectedAttributeIndexes;
private GUIStyle BigFontLabelStyle;
private static List<string> AttributeOptions
{
get
{
if (_attributeOptions == null)
{
var asset = AttributeAsset.LoadOrCreate();
_attributeOptions = asset != null ? (from attr in asset.attributes where !string.IsNullOrWhiteSpace(attr.Name) select attr.Name).OrderBy(x => x).ToList() : new();
}
return _attributeOptions;
}
}
public static void OpenWindow(string initialString, List<string> attributeNames,
Action<string, List<string>> callback, Func<AttributeSetConfig, bool> checkAttributeSetValid)
{
var window = GetWindow<AttributeSetConfigEditorWindow>();
window.Init(initialString, attributeNames, callback, checkAttributeSetValid);
window.Show();
}
Vector2 scrollPosition = Vector2.zero;
private void OnGUI()
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("AttributeSet:", GUILayout.Width(80));
editedName = EditorGUILayout.TextField("", editedName);
EditorGUILayout.EndHorizontal();
EditorGUILayout.Space();
if (GUILayout.Button("Add Attribute", GUILayout.Width(100)))
{
attributeNames.Add("");
_selectedAttributeIndexes.Add(-1);
}
EditorGUILayout.Space();
scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition, GUI.skin.box);
for (var i = 0; i < attributeNames.Count; i++)
{
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField("Attribute:", GUILayout.Width(80));
_selectedAttributeIndexes[i] = EditorGUILayout.Popup("", _selectedAttributeIndexes[i],
AttributeOptions.ToArray());
// 更新选中的字符串
attributeNames[i] = _selectedAttributeIndexes[i] < 0
? ""
: AttributeOptions[_selectedAttributeIndexes[i]];
if (GUILayout.Button("Remove", GUILayout.Width(100)))
{
attributeNames.RemoveAt(i);
return;
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndScrollView();
EditorGUILayout.Space();
GUILayout.FlexibleSpace();
if (GUILayout.Button("Save")) Save();
}
public void Init(string initialString, List<string> attributeNames, Action<string, List<string>> callback,
Func<AttributeSetConfig, bool> checkAttributeSetValid)
{
editedName = initialString;
_callback = callback;
_checkAttributeSetValid = checkAttributeSetValid;
this.attributeNames = attributeNames;
_selectedAttributeIndexes = new List<int>();
foreach (var attributeName in attributeNames)
_selectedAttributeIndexes.Add(AttributeOptions.IndexOf(attributeName));
BigFontLabelStyle = new GUIStyle(EditorStyles.label);
BigFontLabelStyle.fontSize = 20; // 设置字体大小为 16
}
private void Save()
{
var attributeSetConfig = new AttributeSetConfig()
{
Name = editedName,
AttributeNames = attributeNames
};
var valid = _checkAttributeSetValid?.Invoke(attributeSetConfig) ?? true;
if (valid)
{
_callback?.Invoke(editedName, attributeNames);
Close();
}
}
private void OnDisable()
{
Save();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a9a04f50ed041b3b47a5ad09eff154d
timeCreated: 1703128232

View File

@@ -0,0 +1,27 @@
#if UNITY_EDITOR
namespace GAS.Editor
{
using System.Collections.Generic;
using GAS;
using Runtime;
using UnityEditor;
using Editor;
public static class AttributeSetEditorUtil
{
public static List<string> GetAttributeSetChoice()
{
var choices = new List<string>();
var asset = AttributeSetAsset.LoadOrCreate();
foreach (var attributeSetConfig in asset.AttributeSetConfigs)
{
var config = attributeSetConfig;
choices.Add(config.Name);
}
return choices;
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f7dd544418f04fa688f327cc695056d1
timeCreated: 1704248957

View File

@@ -0,0 +1,65 @@
#if UNITY_EDITOR
namespace GAS.Editor
{
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
public class AttributeSetSettingsProvider: SettingsProvider
{
private AttributeSetAsset _asset;
private Editor _editor;
public AttributeSetSettingsProvider() : base("Project/EX Gameplay Ability System/AttributeSet Manager", SettingsScope.Project)
{
}
public override void OnActivate(string searchContext, VisualElement rootElement)
{
var asset = AttributeSetAsset.LoadOrCreate();
_asset = asset;
_editor = Editor.CreateEditor(asset);
GASSettingStatusWatcher.OnEditorFocused += OnEditorFocused;
}
public override void OnDeactivate()
{
base.OnDeactivate();
GASSettingStatusWatcher.OnEditorFocused -= OnEditorFocused;
AttributeSetAsset.Save();
}
private void OnEditorFocused()
{
Repaint();
}
public override void OnGUI(string searchContext)
{
base.OnGUI(searchContext);
if (_editor == null) return;
EditorGUILayout.BeginVertical(GUI.skin.box);
EditorGUILayout.Space();
_editor.OnInspectorGUI();
EditorGUILayout.EndVertical();
}
static AttributeSetSettingsProvider provider;
[SettingsProvider]
public static SettingsProvider CreateMyCustomSettingsProvider()
{
if (AttributeSetAsset.Instance && provider == null)
{
provider = new AttributeSetSettingsProvider();
using (var so = new SerializedObject(AttributeSetAsset.Instance))
{
provider.keywords = GetSearchKeywordsFromSerializedObject(so);
}
}
return provider;
}
}
}
#endif

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4a9b99ebbddc406ebd77864cc1a51026
timeCreated: 1713234604