Search Unity

Checking if a specific file asset exists when opening a project

Discussion in 'Editor & General Support' started by NGC6543, Jan 14, 2020.

  1. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    Hi,
    I'm trying to write a code that checks if a specific file(ScriptableObject asset) exists in my project when the project is opened. Currently I'm doing this with `InitializeOnLoadMethodAttribute`.

    Code (CSharp):
    1. class MyClass
    2. {
    3.     [InitializeOnLoadMethod]
    4.     static void CheckAsset()
    5.     {
    6.         var asset = Resources.Load<ScriptType>(FileName);
    7.         if (asset == null)
    8.         {
    9.             /*
    10.                 Create an asset at Assets/Resources and notify the user.
    11.             */
    12.         }
    13.     }
    14. }
    The above works as expected.

    But if I upgrade the project to a differen version of Unity, the `CheckAsset()` is called before asset importing progress is started. And apparantly the `var asset` is null, since it replaces the existing asset with new one.

    I've also tried to use `SceneManager.sceneLoaded` like this :

    Code (CSharp):
    1. class MyClass
    2. {
    3.     [InitializeOnLoadMethod]
    4.     static void RegisterSceneLoadedListener()
    5.     {
    6.         SceneManager.sceneLoaded += SceneloadedListener;
    7.     }
    8.    
    9.     static void SceneLoadedListener(Scene scene, LoadSceneMode loadSceneMode)
    10.     {
    11.         CheckAsset();
    12.     }
    13.    
    14.     static void CheckAsset()
    15.     {
    16.         var asset = Resources.Load<ScriptType>(FileName);
    17.         if (asset == null)
    18.         {
    19.             /*
    20.                 Create an asset at Assets/Resources and notify the user.
    21.             */
    22.         }
    23.     }
    24. }
    But it didn't work : `RegisterSceneLoadedListener()` is called, but `SceneLoadedListener()` doesn't being called when the project is opened or a new scene is opened.

    In the end, I used `System.IO.File` to check if the file at the location exists. But I'm wondering if there are other methods to achieve this.

    Is there an Editor event or callback that is called when the project has finished loading? I've searched the `EditorApplication` scripting API but couldn't find one with similar functionality.
     
  2. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    279
  3. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    Thanks for the reply, @JustAnotherDude .

    I'm maintaining an in-house SDK for Unity, and it is structured as 'package'. Since we import that package as a submodule, we need to have some project-specific settings under the 'Assets/' folder to avoid unwanted submodule changes. And I want to automate that requirements when a user has imported the package.

    And yes, I need this functionality in the Editor only, and the 'InitializeOnLoadMethod' attribute only works in the Editor, afaik.

    I've already tried AssetPostprocessor(though not mentioned above) and decided not to use it because this is called every single time there is a change in AssetDatabase.

    I've just found this Unity Answer(https://answers.unity.com/questions/1339703/initializeonload-for-editor-load-only.html) which might be used to distinguish if the invocation was made for the first time.

    But it still doesn't guarantee if the project is subject to upgrade, because the project upgrade is done this way :
    User confirms project upgrade
    All the scripts in the project is imported and compiled -> InitializeOnLoadMethod is called right after this!
    Rest of the assets are imported
    When finished, the Editor is opened.​
    I think that's the reason why Resources.Load returns null when the project is being upgraded.

    So, all I'm looking for is an event right after the editor has finished opening.
     
  4. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    Or maybe I can combine the AssetPostprocessor with SessionState. I'll try that tomorrow and see if that works
     
  5. JustAnotherDude

    JustAnotherDude

    Joined:
    Oct 28, 2013
    Posts:
    279
    I would certainly use InitializeOnLoad as the link you posted used, however for your case I'd simply manage my plugin creating a file in the ProjectSettings folder of the unity project that would contain the version of the SDK, if the versions are the same, do nothing, else upgrade it.

    It would still run everytime onload runs but a simple check for a string in a file is hardly noticeable.

    I'd also use System.IO.File for file operations and avoid using Resources.
     
  6. NGC6543

    NGC6543

    Joined:
    Jun 3, 2015
    Posts:
    228
    It’s a nice idea!
    But the problem is that the sdk contains another third-party plugin and the asset file is used as a license key for that plugin. The license should vary per project, and it uses Resources.Load, so I don’t have an option for different location. I think Resources.Load is useful for its type casting.

    Anyway, with your help I could come up with nice solution. Thanks again for your help!