Assembly and CreateInstance bug. works fine in editor but not in build

Hello,
I’ve ran into this weird bug that I just can’t fix it.

I run the game in editor and everything works just fine. but when I run the development build in windows or on my Android device the game freezes and it doesn’t show any error. Tried to catch the error with try and catch and LogCat and there is no error.

I manually debugged the code and got to this method in one specific script. When I run the built version the last Debug.Log console massage I get is the "DEBUG 3". Even the Debug.Log(craftedItems.Count); shows 20 which is correct.
On the other hand I have the same exact code with GetTypes and create them with CreateInstance for some other purpose and there is nothing wrong with them and they work fine.

I didn’t create any Assembly Definition and nothing special. I use Unity-2023-1.5f1 version!

Edit: With Preserve nothing changes. Even I set the Managed Scripting Level to Disable so unity doesnt delete any lines of code I still have the problem!

Second Edit: Updating unity editor to 2023.2.16f1 didn’t solve the problem.

Third Edit: The problem is with the new BluePrintItem(). Seems that I can not create any instance of BluePrintItem. on calling new BluePrintItem the build version gets crashed without any error log. HELP ME PLEASE :slight_smile:

private void InitTierCraftedList()
{
    Debug.Log("DEBUG 1");
    List<Type> craftedItems = Assembly.GetAssembly(typeof(BluePrintItem)).GetTypes().ToList().
        Where(Thetype => Thetype.IsClass &&
        !Thetype.IsAbstract && Thetype.IsSubclassOf(typeof(BluePrintItem))).ToList();

    Debug.Log("DEBUG 2");
    Debug.Log(craftedItems.Count);
    foreach (var item in craftedItems)
    {
        Debug.Log("DEBUG 3");
        BluePrintItem target = (BluePrintItem)Activator.CreateInstance(item);
        int highestTier = 0;
        Debug.Log("DEBUG 342");
        foreach (var material in target.materialsList)
        {
            Debug.Log("DEBUG 4");
            if (material.GetItemTier() > highestTier)
            {
                highestTier = material.GetItemTier();
                Debug.Log("DEBUG 5");
            }
        }
        Debug.Log("DEBUG 6");
        switch (highestTier)
        {
            case 1: firstTierItems.Add(target.CraftedItemReference()); break;
            case 2: secondTierItems.Add(target.CraftedItemReference()); break;
            case 3: thirdTierItems.Add(target.CraftedItemReference()); break;
            case 4: forthTierItems.Add(target.CraftedItemReference()); break;
            default: Debug.LogWarning("CHECK HERE ASAP"); break;
        }
    }
    Debug.Log("DEBUG 7");
    craftedItems.Clear();
    craftedItems = Assembly.GetAssembly(typeof(MaterialItem))
    .GetTypes().Where(TheType => TheType.IsClass && !TheType.IsAbstract && TheType.IsSubclassOf(typeof(MaterialItem))).ToList();
    Debug.Log("DEBUG 8");
    foreach (var item in craftedItems)
    {
        Debug.Log("DEBUG 9");
        MaterialItem target = (MaterialItem)Activator.CreateInstance(item);
        Debug.Log("DEBUG 10");
        switch (target.GetItemTier())
        {
            case 1: firstTierItems.Add(target); break;
            case 2: secondTierItems.Add(target); break;
            case 3: thirdTierItems.Add(target); break;
            case 4: forthTierItems.Add(target); break;
            default: Debug.LogWarning("CHECK HERE ASAP"); break;
        }
        //firstTierItems.Add(target);
        Debug.Log("DEBUG 11");
    }
    craftedItems.Clear();
    craftedItems = Assembly.GetAssembly(typeof(Herb))
    .GetTypes().Where(TheType => TheType.IsClass && !TheType.IsAbstract && TheType.IsSubclassOf(typeof(Herb))).ToList();
    Debug.Log("DEBUG 12");
    foreach (var item in craftedItems)
    {
        Herb target = (Herb)Activator.CreateInstance(item);
        switch (target.GetHerbTier())
        {
            case 1: firstTierItems.Add(target); break;
            case 2: secondTierItems.Add(target); break;
            case 3: thirdTierItems.Add(target); break;
            case 4: forthTierItems.Add(target); break;
            default: Debug.LogWarning("CHECK HERE ASAP"); break;
        }
        //firstTierItems.Add(target);
    }
    Debug.Log("DEBUG 13");
    craftedItems.Clear();
    craftedItems = Assembly.GetAssembly(typeof(Seed))
    .GetTypes().Where(TheType => TheType.IsClass && !TheType.IsAbstract && TheType.IsSubclassOf(typeof(Seed))).ToList();
    Debug.Log("DEBUG 14");
    foreach (var item in craftedItems)
    {
        Seed target = (Seed)Activator.CreateInstance(item);
        switch (target.GetSeedTier())
        {
            case 1: firstTierItems.Add(target); break;
            case 2: secondTierItems.Add(target); break;
            case 3: thirdTierItems.Add(target); break;
            case 4: forthTierItems.Add(target); break;
            default: Debug.LogWarning("CHECK HERE ASAP"); break;
        }
        //firstTierItems.Add(Target);
        Debug.Log("DEBUG 15");
    }
}

Keep in mind that when you build for android or IL2CPP in general, you work in an AOT environment. So no dynamic code compilation. That doesn’t rule out reflection as a whole, but you have to keep in mind that code stripping is a thing. If a class or a certain method isn’t actually “used” in the code, it may be stripped away. So if you only use a class through reflection, this would not work on AOT platforms. You either have to ensure that all relevant classes are actually used in a class / code that is not stripped, or add all types to the Link.xml file or use the Preserve attribute as mentioned here.

Thanks for the reply.
I have the same problem with PC build with mono backend setting. and I have the same exact problem. Problem is I have the same exact code some where else in the project with exact purpose and it’s working fine and it creates the classes as I need it. but on this script which is called TierManager every reflection based code that I call have the same problem. I call another CreateInstance method on another different non-monobehaviour class and the build version gets stuck. Thing is this CreateInstance method is on a different class and I think that just the call from TierManager will cause this problem. Have no clue on how to fix this. Will try to add the preserve attribute to this TierManager class and see if it’s gonna work!
Edit: With Preserve nothing changes. Even I set the Managed Scripting Level to Disable so unity doesnt delete any lines of code I still have the problem!
Second Edit: Updating unity editor to 2023.2.16f1 didn’t solve the problem.

New update on this problem as if i know i’m the only one here :smiley:
I figured out that the whenever the tier manager is calling the non-monobehaviour class to create a instance of it the build version crashes.
Is there any thing that can block the call of this specific script to this non-monobehaviour class that I have?

Fixed!
Apparently if you write your addressable load method like this you get no error in editor and you freeze in build. Without anyway of finding out that the release is the only problem in the build version.
Still dont know why it should work in editor and not in build version!!

protected void LoadFarmIcon()
{
    try
    {
        AsyncOperationHandle<Sprite> handle = Addressables.LoadAssetAsync<Sprite>(farmIconAddress);
        handle.WaitForCompletion(); // Wait for the async operation to complete synchronously

        if (handle.Status == AsyncOperationStatus.Succeeded)
        {
            farmIcon = handle.Result;
            Addressables.Release(handle); // THIS FORSAKEN LINE!
        }
        else
        {
            Debug.LogError("Failed to load the asset");
        }
    }
    catch (Exception e)
    {
        Debug.LogException(e);
    }
}