mirror of
https://gitee.com/jisol/jisol-game/
synced 2025-09-27 02:36:14 +00:00
提交GAS 打算做一个帧同步的GAS
This commit is contained in:
228
JEX_GAS/Assets/GAS/Editor/Attributes/AttributeAsset.cs
Normal file
228
JEX_GAS/Assets/GAS/Editor/Attributes/AttributeAsset.cs
Normal file
@@ -0,0 +1,228 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GAS.Editor.General;
|
||||
using GAS.General;
|
||||
using GAS.General.Validation;
|
||||
using GAS.Runtime;
|
||||
using Sirenix.OdinInspector;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
[FilePath(GasDefine.GAS_ATTRIBUTE_ASSET_PATH)]
|
||||
internal class AttributeAsset : ScriptableSingleton<AttributeAsset>
|
||||
{
|
||||
[BoxGroup("Warning", order: -1)]
|
||||
[HideLabel]
|
||||
[ShowIf("ExistDuplicatedAttribute")]
|
||||
[DisplayAsString(TextAlignment.Left, true)]
|
||||
[NonSerialized]
|
||||
[ShowInInspector]
|
||||
private string Warning_DuplicatedAttribute = "";
|
||||
|
||||
[VerticalGroup("Attributes", order: 1)]
|
||||
[ListDrawerSettings(
|
||||
ShowFoldout = true,
|
||||
CustomRemoveElementFunction = "OnRemoveElement",
|
||||
CustomRemoveIndexFunction = "OnRemoveIndex",
|
||||
CustomAddFunction = "OnAddAttribute",
|
||||
ShowPaging = false)]
|
||||
[Searchable]
|
||||
[OnValueChanged("@SaveAsset()", true)]
|
||||
[OnCollectionChanged(after: "@SaveAsset()")]
|
||||
[CustomContextMenu("排序", "@SortAttributes()")]
|
||||
[SerializeField]
|
||||
public List<AttributeAccessor> attributes = new();
|
||||
|
||||
private void SortAttributes() => attributes = attributes.OrderBy(x => x.Name).ToList();
|
||||
|
||||
[VerticalGroup("Gen Code", order: 0)]
|
||||
[GUIColor(0, 0.9f, 0)]
|
||||
[Button(SdfIconType.Upload, GASTextDefine.BUTTON_GenerateAttributeCollection, ButtonHeight = 30, Expanded = true)]
|
||||
[ValidateInput("@ExistEmptyAttribute() == false", GASTextDefine.TIP_Warning_EmptyAttribute)]
|
||||
void GenCode()
|
||||
{
|
||||
if (ExistEmptyAttribute() || ExistDuplicatedAttribute())
|
||||
{
|
||||
EditorUtility.DisplayDialog("Warning", "Please check the warning message!\n" +
|
||||
"Fix the Attribute Error!\n", "OK");
|
||||
return;
|
||||
}
|
||||
|
||||
SaveAsset();
|
||||
AttributeCollectionGen.Gen();
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private void SaveAsset()
|
||||
{
|
||||
Debug.Log("[EX] Attribute Asset save!");
|
||||
EditorUtility.SetDirty(this);
|
||||
UpdateAsset(this);
|
||||
Save();
|
||||
}
|
||||
|
||||
private int OnRemoveElement(AttributeAccessor attribute)
|
||||
{
|
||||
var result = EditorUtility.DisplayDialog("Confirmation",
|
||||
$"Are you sure you want to REMOVE Attribute:{attribute.Name}?",
|
||||
"Yes", "No");
|
||||
|
||||
if (!result) return -1;
|
||||
|
||||
Debug.Log($"[EX] Attribute Asset remove element:{attribute.Name} !");
|
||||
SaveAsset();
|
||||
return attributes.IndexOf(attribute);
|
||||
}
|
||||
|
||||
private int OnRemoveIndex(int index)
|
||||
{
|
||||
var attribute = attributes[index];
|
||||
var result = EditorUtility.DisplayDialog("Confirmation",
|
||||
$"Are you sure you want to REMOVE Attribute:{attribute.Name}?",
|
||||
"Yes", "No");
|
||||
|
||||
if (!result) return -1;
|
||||
|
||||
attributes.RemoveAt(index);
|
||||
Debug.Log($"[EX] Attribute Asset remove element:{attribute.Name} !");
|
||||
SaveAsset();
|
||||
return index;
|
||||
}
|
||||
|
||||
private void OnAddAttribute()
|
||||
{
|
||||
StringEditWindow.OpenWindow("创建新属性", null, newName =>
|
||||
{
|
||||
var validateVariableName = Validations.ValidateVariableName(newName);
|
||||
|
||||
if (validateVariableName.IsValid == false)
|
||||
{
|
||||
return validateVariableName;
|
||||
}
|
||||
|
||||
if (attributes.Exists(x => x.Name == newName))
|
||||
{
|
||||
return ValidationResult.Invalid($"属性名已存在: \"{newName}\"!");
|
||||
}
|
||||
|
||||
return ValidationResult.Valid;
|
||||
}, x =>
|
||||
{
|
||||
attributes.Add(new AttributeAccessor { Name = x });
|
||||
SaveAsset();
|
||||
Debug.Log("[EX] Attribute Asset add element!");
|
||||
});
|
||||
GUIUtility.ExitGUI(); // In order to solve: "EndLayoutGroup: BeginLayoutGroup must be called first."
|
||||
}
|
||||
|
||||
private bool ExistEmptyAttribute()
|
||||
{
|
||||
return attributes.Any(attribute => string.IsNullOrEmpty(attribute.Name));
|
||||
}
|
||||
|
||||
private bool ExistDuplicatedAttribute()
|
||||
{
|
||||
var duplicates = attributes
|
||||
.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 duplicatedAttributes = duplicates.Aggregate("", (current, d) => current + d + ",");
|
||||
duplicatedAttributes = duplicatedAttributes.Remove(duplicatedAttributes.Length - 1, 1);
|
||||
Warning_DuplicatedAttribute =
|
||||
string.Format(GASTextDefine.TIP_Warning_DuplicatedAttribute, duplicatedAttributes);
|
||||
}
|
||||
|
||||
return duplicates.Count > 0;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal sealed class AttributeAccessor
|
||||
{
|
||||
private const int LabelWidth = 100;
|
||||
|
||||
private string DisplayName => $"{Name} - {Comment}";
|
||||
|
||||
[FoldoutGroup("$DisplayName", false)]
|
||||
[LabelText("属性名"), LabelWidth(LabelWidth)]
|
||||
[DelayedProperty]
|
||||
[ValidateInput("@Validations.IsValidVariableName($value)", "Attribute name is invalid!")]
|
||||
[PropertyOrder(1)]
|
||||
public string Name = "Unnamed";
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[DelayedProperty]
|
||||
[LabelText("备注"), LabelWidth(LabelWidth)]
|
||||
[PropertyOrder(2)]
|
||||
public string Comment = "";
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[LabelText("计算模式"), LabelWidth(LabelWidth)]
|
||||
[PropertyOrder(3)]
|
||||
[OnValueChanged("@OnCalculateModeChanged()")]
|
||||
[HorizontalGroup("$DisplayName/d")]
|
||||
public CalculateMode CalculateMode = CalculateMode.Stacking;
|
||||
|
||||
private void OnCalculateModeChanged()
|
||||
{
|
||||
if (CalculateMode is CalculateMode.MinValueOnly or CalculateMode.MaxValueOnly)
|
||||
{
|
||||
SupportedOperation = SupportedOperation.Override;
|
||||
}
|
||||
}
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[LabelText("支持运算"), LabelWidth(LabelWidth)]
|
||||
[PropertyOrder(4)]
|
||||
[DisableIf(
|
||||
"@CalculateMode == GAS.Runtime.CalculateMode.MinValueOnly || CalculateMode == GAS.Runtime.CalculateMode.MaxValueOnly")]
|
||||
[HorizontalGroup("$DisplayName/d")]
|
||||
public SupportedOperation SupportedOperation = SupportedOperation.All;
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[LabelText("默认值"), LabelWidth(LabelWidth)]
|
||||
[DelayedProperty]
|
||||
[PropertyOrder(5)]
|
||||
[HorizontalGroup("$DisplayName/Values")]
|
||||
public float DefaultValue = 0f;
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[LabelText("最小值"), LabelWidth(40)]
|
||||
[DelayedProperty]
|
||||
[PropertyOrder(6)]
|
||||
[HorizontalGroup("$DisplayName/Values")]
|
||||
[ToggleLeft]
|
||||
public bool LimitMinValue = false;
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[HideLabel]
|
||||
[DelayedProperty]
|
||||
[PropertyOrder(6)]
|
||||
[EnableIf("LimitMinValue")]
|
||||
[HorizontalGroup("$DisplayName/Values")]
|
||||
public float MinValue = float.MinValue;
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[LabelText("最大值"), LabelWidth(50)]
|
||||
[DelayedProperty]
|
||||
[PropertyOrder(6)]
|
||||
[HorizontalGroup("$DisplayName/Values")]
|
||||
public bool LimitMaxValue = false;
|
||||
|
||||
[FoldoutGroup("$DisplayName")]
|
||||
[HideLabel]
|
||||
[DelayedProperty]
|
||||
[PropertyOrder(7)]
|
||||
[EnableIf("LimitMaxValue")]
|
||||
[HorizontalGroup("$DisplayName/Values")]
|
||||
public float MaxValue = float.MaxValue;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a2112111feb463caf561bfc7cfe18ab
|
||||
timeCreated: 1701944033
|
@@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace GAS.Editor
|
||||
{
|
||||
public static class AttributeCollectionGen
|
||||
{
|
||||
private sealed class AttributeInfo
|
||||
{
|
||||
public string Name;
|
||||
public string Comment;
|
||||
}
|
||||
|
||||
public static void Gen()
|
||||
{
|
||||
var asset = AttributeAsset.LoadOrCreate();
|
||||
string pathWithoutAssets = Application.dataPath.Substring(0, Application.dataPath.Length - 6);
|
||||
var filePath =
|
||||
$"{pathWithoutAssets}/{GASSettingAsset.CodeGenPath}/{GasDefine.GAS_ATTRIBUTE_LIB_CSHARP_SCRIPT_NAME}";
|
||||
|
||||
|
||||
var attributeInfos = (from t in asset.attributes
|
||||
where !string.IsNullOrWhiteSpace(t.Name)
|
||||
select new AttributeInfo { Name = t.Name, Comment = t.Comment }).ToList();
|
||||
|
||||
|
||||
GenerateAttributeCollection(attributeInfos, filePath);
|
||||
|
||||
Console.WriteLine($"Generated GTagLib at path: {filePath}");
|
||||
}
|
||||
|
||||
private static void GenerateAttributeCollection(IEnumerable<AttributeInfo> attributes, 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.Collections.Generic;");
|
||||
writer.WriteLine("");
|
||||
|
||||
writer.WriteLine("namespace GAS.Runtime");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
writer.WriteLine("public static class GAttrLib");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
bool skippedFirst = false;
|
||||
|
||||
var names = new List<string>();
|
||||
// Generate members for each ATTRIBUTE
|
||||
foreach (var attr in attributes)
|
||||
{
|
||||
if (!skippedFirst) skippedFirst = true;
|
||||
else writer.WriteLine();
|
||||
|
||||
var validName = EditorUtil.MakeValidIdentifier(attr.Name);
|
||||
writer.WriteLine($"/// <summary>{attr.Comment}</summary>");
|
||||
writer.WriteLine($"public const string {validName} = \"{attr.Name}\";");
|
||||
names.Add(validName);
|
||||
}
|
||||
|
||||
writer.WriteLine("");
|
||||
|
||||
writer.WriteLine("// For facilitating the creation of a Value Dropdown in the editor.");
|
||||
writer.WriteLine("public static readonly IReadOnlyList<string> AttributeNames = new List<string>");
|
||||
writer.WriteLine("{");
|
||||
writer.Indent++;
|
||||
{
|
||||
foreach (var name in names)
|
||||
{
|
||||
writer.WriteLine($"{name},");
|
||||
}
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("};");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.WriteLine("}");
|
||||
}
|
||||
writer.Indent--;
|
||||
writer.Write("}");
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7edde281db414809898e374a4258eaa3
|
||||
timeCreated: 1703058917
|
26
JEX_GAS/Assets/GAS/Editor/Attributes/AttributeEditorUtil.cs
Normal file
26
JEX_GAS/Assets/GAS/Editor/Attributes/AttributeEditorUtil.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GAS;
|
||||
using Editor;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
public static class AttributeEditorUtil
|
||||
{
|
||||
public static List<string> GetAttributeNameChoices()
|
||||
{
|
||||
var names = new List<string>();
|
||||
var asset = AttributeSetAsset.LoadOrCreate();
|
||||
foreach (var attributeSetConfig in asset.AttributeSetConfigs)
|
||||
{
|
||||
var config = attributeSetConfig;
|
||||
names.AddRange(attributeSetConfig.AttributeNames.Select(shortName => $"AS_{config.Name}.{shortName}"));
|
||||
}
|
||||
return names;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 969e6a6cb3f14c15b1f56a877a8e140a
|
||||
timeCreated: 1703843617
|
@@ -0,0 +1,65 @@
|
||||
#if UNITY_EDITOR
|
||||
namespace GAS.Editor
|
||||
{
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
public class AttributeSettingsProvider: SettingsProvider
|
||||
{
|
||||
private AttributeAsset _asset;
|
||||
private Editor _editor;
|
||||
|
||||
public AttributeSettingsProvider() : base("Project/EX Gameplay Ability System/Attribute Manager", SettingsScope.Project)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnActivate(string searchContext, VisualElement rootElement)
|
||||
{
|
||||
var asset = AttributeAsset.LoadOrCreate();
|
||||
_asset = asset;
|
||||
_editor = Editor.CreateEditor(asset);
|
||||
GASSettingStatusWatcher.OnEditorFocused += OnEditorFocused;
|
||||
}
|
||||
|
||||
public override void OnDeactivate()
|
||||
{
|
||||
base.OnDeactivate();
|
||||
GASSettingStatusWatcher.OnEditorFocused -= OnEditorFocused;
|
||||
AttributeAsset.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 AttributeSettingsProvider provider;
|
||||
[SettingsProvider]
|
||||
public static SettingsProvider CreateMyCustomSettingsProvider()
|
||||
{
|
||||
if (AttributeAsset.Instance && provider == null)
|
||||
{
|
||||
provider = new AttributeSettingsProvider();
|
||||
using (var so = new SerializedObject(AttributeAsset.Instance))
|
||||
{
|
||||
provider.keywords = GetSearchKeywordsFromSerializedObject(so);
|
||||
}
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 90f28a2ebfe04dd6b5bf214db4e2b23f
|
||||
timeCreated: 1713233741
|
Reference in New Issue
Block a user