该特性类似Unity的
InitializeOnLoad
,但是该特性是带优先级的,不过他的本质也是在InitializeOnLoad
实现,不过会出现一个问题就是当你修改代码触发了InitializeOnLoad
后,InitializeOnRun
标记的类如果调用了Unity相关的API,你可能会看到类似的错误UnityException: xxxxAPI is not allowed to be called from a ScriptableObject constructor (or instance field initializer), call it in OnEnable instead. Called from ScriptableObject 'AnimationRuntimeExecuteEventRegisteredEditorModule'. 'xxxxxxx'
如果遇到这样的错误,请吧这部分代码放入EditorApplication.update.
- YAMLObject
- 如果你需要对Yaml进行一些手动处理,那这个类你会很常用,我是用来做数据保护的,因为
ScriptableObject
如果因为版本变动了,如果不做数据保护或处理的话,那老数据会丢失. - 使用方式:使用起来很简单,只需
UnityYAMLObject _unityYamlObj = new UnityYAMLObject("Yaml文件路径")
,我同时提供了一个YAMLObjectEditor
它有一个DrawYaml
函数,可以将YAML绘制出来 - 一个简单的数据保护例子:
//1.0版本
{
[CreateAssetMenu()]
public class TestObj:ScriptableObject
{
public const string ScriptVersion = "1.0";
[HideInInspector]
public string AssetVersion = "1.0";
public List<string> Strs;
}
}
//2.0版本,List<string> 变为了 List<TestC>
{
[Serializable]
public struct TestC
{
public string Str;
public int Int;
}
[CreateAssetMenu()]
public class TestObj:ScriptableObject
{
public const string ScriptVersion = "2.0";
[HideInInspector]
public string AssetVersion = "2.0";
public List<TestC> Strs;
}
}
[CustomEditor(typeof(TestObj))]
public class customEditorTestObj : YAMLObjectEditor
{
private SerializedProperty script;
private TestObj _tt;
private string _scriptBigVersion;
private string _assetBigVersion;
private string _assetPath;
private UnityYAMLObject _unityYamlObj;
void OnEnable()
{
_tt = (TestObj) target;
_getBigVersion();
_assetPath = AssetDatabase.GetAssetPath(target);
_unityYamlObj = new UnityYAMLObject(_assetPath);
}
private void _getBigVersion()
{
_scriptBigVersion = _getBigVersion(TestObj.ScriptVersion);
_assetBigVersion = _getBigVersion(_tt.AssetVersion);
}
private string _getBigVersion(string version)
{
return version.Split('.')[0];
}
public override void OnInspectorGUI()
{
if (_scriptBigVersion != _assetBigVersion)
{
serializedObject.Update();
EditorGUILayout.LabelField(
$"资源文件大版本号`{_assetBigVersion}`不符,目前资源大版本号是`{_scriptBigVersion}` 跳过序列化.避免数据丢失.");
//升级按钮,将版本从1.0升级为2.0
if (GUILayout.Button("Update"))
{
//获取1.0的 Strs 数据
YamlSequenceNode aa = (YamlSequenceNode) _unityYamlObj.GetNode("Strs");
_tt.Strs = new List<TestC>();
//进行数据升级
foreach (var yamlNode in aa.Children)
{
_tt.aa.Add(new TestC() {Str = yamlNode.ToString()});
}
//更新版本为2.0
_tt.AssetVersion = "2.0";
Debug.Log("Update Complete.");
serializedObject.ApplyModifiedProperties();
//刷新大版本号
_getBigVersion();
EditorUtility.SetDirty(target);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
//版本不匹配,绘制YAML
GUI.enabled = false;
{
EditorGUILayout.LabelField($"Asset Version:{_tt.AssetVersion}");
EditorGUILayout.LabelField("Old Asset Filed:");
EditorGUI.indentLevel++;
{
bool show = false;
int index = 0;
foreach (var node in _unityYamlObj.Root.Children)
{
if (node.Key.ToString() == "AssetVersion")
{
show = true;
}
EditorGUI.indentLevel++;
{
if (show)
{
//绘制YAML
DrawYaml(node.Key.ToString(), node.Value);
}
}
EditorGUI.indentLevel--;
index++;
}
}
EditorGUI.indentLevel--;
}
GUI.enabled = true;
return;
}
this.DrawDefaultInspector();
}
}
例子效果:
- AnimationEventUtil的使用,注意以下API操作都没有Undo
- 这个类主要是Animation Event的增,删,查的扩展方法,扩展类为
AnimationClip
,ModelImporter
- AnimationClip API:
- GetEves(List) : 获取动画全部事件,填充的数据的List
- AddEve(AnimationEvent) : 添加事件
- AddEves(IEnumerable) : 添加一组事件
- RemoveEve(int) : 删除事件,参数是事件的索引
- RemoveAllEve() : 删除所有的事件
- ModelImporter API:
- GetAnimationClipEvents(AnimationClip, List) : 获取给定的AnimationClip的所有动画事件,List为填充的数据
- GetAnimationClipEvents(string, List) : 获取给定名字的动画的所有动画事件,List为填充的数据
- GetModelAnimationClipsEvents(Dictionary<string,List>) : 获取
ModelImporter
中所有动画的动画事件,字典为填充的数据- AddEve(string,AnimationEvent) : 添加事件
- AddEve(AnimationClip,AnimationEvent) : 添加事件
- AddEves(string,IEnumerable) : 添加一组事件
- AddEves(AnimationClip,IEnumerable) : 添加一组事件
- RemoveEve(string,int) : 删除事件,int为事件索引
- RemoveEve(AnimationClip,int) : 删除事件,int为事件索引
- RemoveAllEve() : 删除
ModelImporter
所有AnimationClip
的动画事件,该操作有提示框出现- RemoveAllEve(AnimationClip) : 删除
ModelImporter
中指定AnimationClip
的所有动画事件- RemoveAllEve(string) : 删除
ModelImporter
中指定名字的AnimationClip
所有动画事件- RemoveAllSameFunctionNameEvent(string) :
string
为事件名,
删除ModelImporter
中所有AnimationClip
事件名为string
的事件`
- AssetUtil
- 该类主要是一些Asset操作的封装,如加载,资源得刷新,子资源添加
- Cfg
- 主要是用来加载配置和获取/保存数据的.
- 3种数据保存的方式:
- CSVEncrypting(加密的CSV)保存方式,使用方式为
Cfg.CSVEncrypting.xxxx
,配置保存路径在项目路径(不含Assets)/IcEFConfig/Csv.IcCED
- EditorPrefs保存方式,使用方式为
Cfg.U.Prefs.xxx
- EditorUserSettings保存方式,使用方式为
Cfg.U.UserSettings.xxx
- EncryptionAndDecrypting 加密/解密
- 目前提供了一个对称加密/解密方式,使用方式为
byte[] _key = {0x94, 0x54, 0x43, 0x32, 0x87, 0x23, 0x68, 0x12, 0x34, 0x90, 0x33, 0x21, 0x43, 0x35, 0x73, 0x10};
//记住在任何地方开始前设置一下Key
EncryptionAndDecrypting.Symmetric.Key = _key;
//加密
var enStr = EncryptionAndDecrypting.Symmetric.Encryption("我需要加密,我是保密的!");
///解密
var deStr = EncryptionAndDecrypting.Symmetric.Decrypting(enStr);
- 静态的LocalizationManager
- 为什么会有一个静态的?因为有些操作是在
static
中操作的,你可能会说,那我在static函数中new一个LocalizationManager
也可以吖,是的,没问题,但是静态的LocalizationManager
是用来解决静态公用多语言的,我一般是在InitializeOnRun运行时将自己的静态语言进行加载,如编辑器的Title
- GameobjectUtil
- 可以获取子物体路径及物体是否是子物体
- ObjectUtil
Unity.Object
的工具类,目前有函数是查找Unity.Object的
- ScriptingDefineUtil
- 可以增加/删除预编译(宏)
- PathUtil
- 路径相关的操作
- EditorFrameLog
- Log输出的,创建自己的Log器,实现
IEditorFrameLog
然后调用EditorFrameLog.SetEditorFrameLog
即可,默认会设置为UnityEngine.Debug
的实现
- EditorGUILayoutUtil
- EditorGUILayout的一些封装及一个高级的EnumPopup
- GUIUtil
- GUI的一些常用操作封装