Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Question How to know [InitializeOnLoad] or [InitializeOnLoadMethod] execute order?

Discussion in 'Scripting' started by jkpk11111111, Sep 27, 2022.

  1. jkpk11111111

    jkpk11111111

    Joined:
    Aug 16, 2021
    Posts:
    2
    I have many scripts that use these two attributes([InitializeOnLoad],[InitializeOnLoadMethod]), including some third-party plug-ins.
    But I have no way of knowing the order in which these static methods are called during initialization.
    Recently, however, I encountered the problem that the editor may freeze when it starts.
    I suspect that there are infinite loops in these static methods.
    I have tried to add Debug.Log to these methods for troubleshooting.
    However, I found that many third-party plug-ins also use these two attributes. They only provide DLLs, so I can't modify the code
    I tried to use Rider Attach to freeze the Unity process, but in fact, I can't pause it after freezing
    How can I troubleshoot such problems?
    Is there any way for me to know the execution order of this type of method, which is convenient for unified management and troubleshooting? Or what can I do to execute logic before all these method calls?
    When Unity freezes, the last log is:

    Begin MonoManager ReloadAssembly
    Native extension for iOS target not found
    Native extension for Android target not found
    Native extension for WebGL target not found
    Native extension for WindowsStandalone target not found
    Refreshing native plugins compatible for Editor in 1.21 ms, found 0 plugins.
    Preloading 0 native plugins for Editor in 0.00 ms.
     
  2. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    764
    Hey,

    I've worked with several projects and this attribute is always useful.
    However, I strongly advise against relying on the order of execution of these attributes. It's better to have only one per app and then manage yours however you want. Here's an example, which also let's you pass params to the initializers:

    Code (CSharp):
    1.  
    2.         public class MyInitializeOnLoadAttribute : Attribute
    3.         {
    4.             public int Order { get; }
    5.  
    6.             public MyInitializeOnLoadAttribute(int order)
    7.             {
    8.                 Order = order;
    9.             }
    10.         }
    11.  
    12.         [MyInitializeOnLoad(1)]
    13.         public class SomeClass1
    14.         {
    15.             static void OnLoad(object someParams)
    16.             {
    17.  
    18.             }
    19.         }
    20.  
    21.         [MyInitializeOnLoad(2)]
    22.         public class SomeClass2
    23.         {
    24.             static void OnLoad(object someParams)
    25.             {
    26.  
    27.             }
    28.         }
    29.  
    30.         [MyInitializeOnLoad(3)]
    31.         public class SomeClass3
    32.         {
    33.             static void OnLoad(object someParams)
    34.             {
    35.  
    36.             }
    37.         }
    38.  
    39.         [InitializeOnLoad]
    40.         public class AppInit
    41.         {
    42.             static AppInit()
    43.             {
    44.                 var calls = FindAllInitializerTypes();
    45.                 calls.Sort((a, b) => a.order - b.order);
    46.  
    47.                 var someParams = new object();
    48.                 foreach (var call in calls)
    49.                 {
    50.                     var method = call.type.GetMethod("OnLoad", BindingFlags.Static | BindingFlags.NonPublic);
    51.                     method.Invoke(null, new object[] { someParams });
    52.                 }
    53.             }
    54.  
    55.             static List<(Type type, int order)> FindAllInitializerTypes()
    56.             {
    57.                 var calls = new List<(Type type, int order)>();
    58.                 foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
    59.                 {
    60.                     foreach (var type in assembly.GetTypes())
    61.                     {
    62.                         var attrs = type.GetCustomAttributes(typeof(MyInitializeOnLoadAttribute), false);
    63.                         if (attrs.Length == 0)
    64.                             continue;
    65.  
    66.                         var attr = attrs[0] as MyInitializeOnLoadAttribute;
    67.                         calls.Add((type, attr.Order));
    68.                     }
    69.                 }
    70.  
    71.                 if (calls.Exists(call => calls.Exists(call2 => call != call2 && call.order == call2.order)))
    72.                     throw new InvalidOperationException($"Found duplicate order for attribute {nameof(MyInitializeOnLoadAttribute)}");
    73.  
    74.                 return calls;
    75.             }
    76.         }
    77.  
     
    mopthrow and SisusCo like this.
  3. jkpk11111111

    jkpk11111111

    Joined:
    Aug 16, 2021
    Posts:
    2
    Thanks a lot for your suggestion, I also think a unified entry is needed to handle this.
    But for 3rd party plugins I can't make such changes
    Is there any way to help me troubleshoot?
     
  4. xucian

    xucian

    Joined:
    Mar 7, 2016
    Posts:
    764
    Well, it's tougher for plugins. The authors themselves are responsible for them, so maybe try reaching them as they're more likely than not to help. Docs say these attributes aren't affected by the script execution order in proj settings, so I don't see many options other than modifying the plugins yourself or talking to the author