简体   繁体   English

重新加载程序集以访问新的ScriptableObject脚本类型

[英]Reload Assembly for access to new ScriptableObject script type

I am creating a new script from a template. 我正在从模板创建一个新脚本。 However, this new script type is not accessible until the Assembly has had a chance to re-compile. 但是,直到大会有机会重新编译之前,无法访问此新脚本类型。 I am trying to create an instance of the new ScriptableObject, in order to generate it through code. 我试图创建新的ScriptableObject的实例,以便通过代码生成它。

public override void Def()
{
  NewAssetName = EditorGUILayout.TextField(NewAssetName);

  EditorGUILayout.BeginHorizontal();
  if (GUILayout.Button("Add"))
  {                    
    TemplateLines = File.ReadAllLines("E:/Unity/Editor/Data/Resources/ScriptTemplates/NewScriptableObject.cs.txt");

    for (int i = 0; i < TemplateLines.Length; i++)
                        {
    if (TemplateLines[i].Contains("#SCRIPTNAME#"))
    {
      TemplateLines[i] = TemplateLines[i].Replace("#SCRIPTNAME#", NewAssetName);
    }
  }

  NewFilePath = "Assets/" + NewAssetName + '/' + NewAssetName + ".cs";
  NewSOPath = "Assets/" + NewAssetName + '/' + NewAssetName + ".asset";

  File.WriteAllLines(NewFilePath, TemplateLines);

  ScriptableObject NewSO = CreateInstance(TypeName);        
  AssetDatabase.CreateAsset(NewSO, NewSOPath);
}

Everything works fine, up until I use CreateInstance(); 一切正常,直到使用CreateInstance()为止; At this point, the type does not exist yet. 此时,该类型尚不存在。 I have to wait for the Assembly to re-compile and capitulate the type... 我必须等待大会重新编译并简化类型...

I have Googled the concept of refreshing the Assembly, but have not found anything. 我用Google搜索刷新大会的概念,但没有发现任何东西。

I have also Googled using async/await in order to delay calling CreateInstance(), until AFTER the Assembly, for sure, has the new type... So far, these attempts have either locked up the Editor, or do not work as intended... (I am new to this async style in C#) 我也使用async / await进行了Google搜索,以延迟调用CreateInstance(),直到确定该程序集具有新类型后为止。到目前为止,这些尝试要么锁定了编辑器,要么无法正常工作...(我是C#中这种异步样式的新手)

I am open to either an Assembly solution, or an async solution, for solving this problem. 我愿意使用Assembly解决方案或异步解决方案来解决此问题。

One solution is to save a request to create your scriptable object in EditorPrefs and create your asset in a callback after scripts reloaded. 一种解决方案是保存一个请求,以便在EditorPrefs中创建可编写脚本的对象,并在重新加载脚本后在回调中创建资产。 Unfortunately, you can't do that without locking the editor. 不幸的是,如果不锁定编辑器就无法做到这一点。

using UnityEditor;
using UnityEngine;

public class EditorUtils
{
    [MenuItem("Tools/Create SO")]
    private static void CreateSO()
    {
        GenerateAndSaveSOClass();

        ShouldCreateSO = true;

        AssetDatabase.Refresh();
        AssetDatabase.SaveAssets();
    }

    private static bool ShouldCreateSO
    {
        get { return EditorPrefs.GetBool("should_create", false); }
        set { EditorPrefs.SetBool("should_create", value);}
    }

    [UnityEditor.Callbacks.DidReloadScripts]
    private static void OnScriptsReloaded()
    {
        if (ShouldCreateSO)
        {
            ShouldCreateSO = false;

            var so = ScriptableObject.CreateInstance("MyClassName");
            var path = "Assets/SO.asset";

            AssetDatabase.CreateAsset(so, path);
        }
    }

    private static void GenerateAndSaveSOClass()
    {
        // TODO: generate and save class
    }
}

This is what wound up working: 这是结束工作的原因:

using UnityEditor;
using UnityEngine;

public class HandleNewScriptAndSO : ScriptableObject
{
    public StringRef ActiveDirectory_Ref;
    public StringRef NewSOName;
    public BoolRef TypeHasBeenAdded_Ref;

    private string NewSOPath;

    private void OnEnable()
    {
        AssemblyReloadEvents.afterAssemblyReload += GenerateNewSO;
    }

    public void GenerateNewSO()
    {
        if (TypeHasBeenAdded_Ref.Val)
        {            
            ScriptableObject NewSO = CreateInstance(NewSOName.Val);
            NewSOPath = ActiveDirectory_Ref.Val + '/' + NewSOName.Val + '/' + NewSOName.Val + ".asset";
            AssetDatabase.CreateAsset(NewSO, NewSOPath);

            TypeHasBeenAdded_Ref.Val = false;
        }            
    }        
}

The boolean is set to true when the user presses the 'Add' button in the EditorWindow: 当用户在EditorWindow中按下“添加”按钮时,布尔值设置为true:

  if (GUILayout.Button("Add") && NewSOName_Ref.Val != "")
  {
    AssetDatabase.CreateFolder(ActiveDirectory_Ref.Val, NewSOName_Ref.Val);

    TemplateLines = File.ReadAllLines("E:/Unity/Editor/Data/Resources/ScriptTemplates/NewScriptableObject.cs.txt");

    for (int i = 0; i < TemplateLines.Length; i++)
    {
      if (TemplateLines[i].Contains("#SCRIPTNAME#"))
      {
        TemplateLines[i] = TemplateLines[i].Replace("#SCRIPTNAME#", NewSOName_Ref.Val);
      }
    }

    NewFilePath = ActiveDirectory_Ref.Val + '/' + NewSOName_Ref.Val + '/' + NewSOName_Ref.Val + ".cs";

    File.WriteAllLines(NewFilePath, TemplateLines);

    TypeHasBeenAdded_Ref.Val = true;

    AssetDatabase.Refresh();

  }

'AssemblyReloadEvents.afterAssemblyReload' delegated needed to be subscribed with the code to add the new objects. 需要委托委派的“ AssemblyReloadEvents.afterAssemblyReload”添加代码以添加新对象。 It also needed to be bool-guarded, in order to make sure it only runs when the user issues a fresh Add. 为了确保它仅在用户发出新的“添加”时才运行,还需要对其进行防呆保护。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM