AssetDatabase.Refresh准备就绪时的通知

Kay*_*Kay 2 c# unity-game-engine

我有一个Unity3D编辑器类,可以动态创建新资产.然后我使用默认选项调用AssetDatabase.Refresh(强烈建议使用).由于刷新是一种异步方式,因此我需要一种在刷新准备就绪时获取信息的方法.

背景:

我编写了一个代码生成器,用于创建C#脚本.它旨在为场景中的活动游戏对象创建辅助组件.到目前为止一切正常,该文件是由System.File.IO中的方法创建的.现在我想自动将新创建的MonoBehaviour添加到活动游戏对象中.

目前的状况/限制因素:

  • 正如预期的那样,在刷新过程中会销毁所有活动对象.这使得无法使用任何标准轮询方法,如调用或协同程序,因为它们在游戏对象被销毁时终止.
  • 轮询通常不是一个好的解决方案,但在这种情况下也可以.另一方面,我不想使用线程,因为在Unity中不建议这样做.
  • 如果静态构造函数的类具有InitializeOnLoadAttribute设置或者在活动场景中引用该组件,则在刷新就绪后立即调用静态构造函数.

可能有用的(繁琐的)方式:

  • 定义一个ActionAfterRefresh包含元信息的代码和在刷新后要执行的代码,例如要加载的类名和AddComponent在构造函数中执行代码的代码.
  • 将此类序列化为特殊缓存目录中的JSON文件
  • 定义一个Loader具有静态构造函数的类:
    • 查看缓存目录中是否存在匹配的JSON文件.如果是这样,请创建一个实例并执行代码
    • 删除JSON文件

我认为这可行,我猜你知道为什么我写的很麻烦.有没有更智能,更好,更快的方法来实现这一目标?我是否忽略了实时保存的OnRefreshDatabaseReady事件?

谢谢你的帮助

Ser*_*sch 6

通知

方式1

这很有趣,但您已经列出了这个选项:

  • 如果其类已设置InitializeOnLoadAttribute,则在刷新就绪后立即调用静态构造函数

因此,如果[InitializeOnLoadAttribute]调用某个类的静态构造函数:这是Unity刚刚重建解决方案的一个好兆头.

方式2.黑魔法:)

它没有文档,但是如果[DidReloadScripts]在任何编辑器类中向静态方法添加属性,则在Unity重新编译脚本之后将调用此方法.见例子:

public class SomeEditorClass
{
    [DidReloadScripts]
    public static void OnCompileScripts()
    {
        Debug.Log("Bla-bla-bla");
    }
}
Run Code Online (Sandbox Code Playgroud)

使用编辑器窗口在重建之间生存

但是为了使用所有这些来解决您的问题,您仍然需要一种在解决方案重建之间存储一些数据的方法.如果您正在从编辑器窗口进行"操作",那么您可以使用以下技巧:Unity存储EditorWindow对象状态.所以,你可以这样做:

[InitializeOnLoadAttribute]
public class YourWindow : EditorWindow
{
    const string path = @"Assets/Bla-bla-bla.cs";
    private static bool justRecompiled;

    static YourWindow()
    {
        justRecompiled = true;
    }

    [MenuItem("Test/YourWindow")]
    public static void Generate()
    {
        GetWindow(typeof(YourWindow));
    }

    private bool waitingForRecompiling;
    private GameObject gameObject;

    public void OnRecompile()
    {
        MonoScript monoScript = AssetDatabase.LoadAssetAtPath(path, typeof(MonoScript)) as MonoScript;
        Type monoScriptClass = monoScript.GetClass();
        if (gameObject.GetComponent(monoScriptClass) == null)
            gameObject.AddComponent(monoScriptClass);
    }

    public void OnGUI()
    {
        if (GUILayout.Button("Execute"))
            if (Selection.activeGameObject != null)
            {
                // Do your script file generation here
                waitingForRecompiling = true;
                gameObject = Selection.activeGameObject;
                AssetDatabase.ImportAsset(path);
            }
    }

    public void Update()
    {
        if (justRecompiled && waitingForRecompiling)
        {
            waitingForRecompiling = false;
            OnRecompile();
        }
        justRecompiled = false;
    }
}
Run Code Online (Sandbox Code Playgroud)

这有点难看,但仍然是一个选择.