Search Unity

Question InvalidProgramException: Invalid IL code in XXX: IL_022d: ldfld 0x0400044

Discussion in 'Entity Component System' started by Dan-Foster, Jun 7, 2021.

  1. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    Hi there,

    I've just gone to write a seemingly innocuous Entites.ForEach.Run() lambda that results in "InvalidProgramException: Invalid Il code" being emitted when the system is ran. - Code and exception below.

    This exception goes away if I schedule the job then immediately complete rather than Run it. It seems like a waste to me to schedule this job if I'm just reading the data into UI Elements.

    Does anyone know why this is happening? Is there something that I'm missing?

    Thanks,
    Dan

    Code (CSharp):
    1.         NativeArray<int> scores = new NativeArray<int>( 2, Allocator.TempJob );
    2.         Entities
    3.             .ForEach( ( in TeamDataComponent teamData ) =>
    4.             {
    5.                 scores[teamData.teamId] = teamData.score;
    6.             } ).Run();
    7.        
    8.         CompleteDependency();
    9.  
    10.         blueScore.text.text = scores[0].ToString();
    11.         redScore.text.text = scores[1].ToString();
    12.  
    13.         scores.Dispose();


    Produced exception :

    InvalidProgramException: Invalid IL code in IngameUISystem:OnUpdate (): IL_022d: ldfld     0x04000446
     
  2. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Maybe update dots packages if they're out of date? I used to get this a lot for no reason at all but haven't seen it since around Entities .16/.17.
     
  3. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    It looks like I am using Entities 0.17.0.
     
  4. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Jobs/Burst and Collections updated too? I thought it might have been something on the Jobs/Burst side that sometimes doesn't state errors correctly.

    Worst case also can try upgrading Unity or deleting /Library and redownloading the packages, but don't upgrade past Unity 2020 LTS, and not Collections .17, it's broken for some.
     
    Last edited: Jun 8, 2021
  5. tertle

    tertle

    Joined:
    Jan 25, 2011
    Posts:
    3,759
    This shouldn't be a problem since it's using Run. It's only a requirement for ScheduleParallel.

    Anyway putting the OPs code in my own project works completely fine so I'm not sure what the problem is. It looks completely valid to me and looking at the generated code in the DOTS compiler inspector it generates fine.

    One random note though that CompleteDependency call is redundant.
     
  6. RecursiveEclipse

    RecursiveEclipse

    Joined:
    Sep 6, 2018
    Posts:
    298
    Whoops, I read that Schedule wasn't an issue the first time I posted, and forgot when I came back. You're correct.

    I recall having this issue when I tried to dispose 1 specific array of 3 using WithDisposeOnCompletion() or Dispose with JobHandle, for no reason at all, just wouldn't let me dispose of it.
     
    Last edited: Jun 8, 2021
  7. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    I had tried deleting the library folder before, but the error persisted.

    Just looking at the versions of packages now.

    My Editor version is 2020.3.11f1.

    I have updated Burst to 1.4.8.
    The Jobs package is on 0.8.0-preview.23 - Latest.

    The problem still persists, I've deleted the library folder again after the Burst package update, but the problem still remains.

    My Collections package is on version0.15.0-preview.21 - Updating this causes a compile error in the Entities package.

    Something I've just tried is turning off Burst Compile, but still not change when using Run().
     
  8. PeppeJ2

    PeppeJ2

    Joined:
    May 13, 2014
    Posts:
    43
    Can you paste the full OnUpdate loop?
     
  9. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    Code (CSharp):
    1. using Unity.Collections;
    2. using Unity.Entities;
    3. using Unity.Jobs;
    4. using Unity.NetCode;
    5. using UnityEngine;
    6.  
    7. [UpdateInGroup( typeof( ClientPresentationSystemGroup ) )]
    8. [AlwaysSynchronizeSystem]
    9. public class IngameUISystem : SystemBase
    10. {
    11.     private UIAddressableManager uiAddressableManager;
    12.  
    13.     protected override void OnCreate()
    14.     {
    15.         RequireSingletonForUpdate<InGameUITag>();
    16.     }
    17.  
    18.     protected override void OnUpdate()
    19.     {
    20.         if( uiAddressableManager == null )
    21.             uiAddressableManager = GameObject.FindObjectOfType<UIAddressableManager>( true );
    22.         if( uiAddressableManager == null )
    23.         {
    24.             return;
    25.         }
    26.  
    27.         HeldWeaponComponent heldWeapon = default( HeldWeaponComponent );
    28.         Health health = default( Health );
    29.         if( HasSingleton<LocalPlayer>() )
    30.         {
    31.             Entity localPlayerEntity = GetSingletonEntity<LocalPlayer>();
    32.             heldWeapon = EntityManager.GetComponentData<HeldWeaponComponent>( localPlayerEntity );
    33.             health = EntityManager.GetComponentData<Health>( localPlayerEntity );
    34.         }
    35.  
    36.         UIAddressable currentAmmo = uiAddressableManager.GetAddressable( "AmmoCurrent" );
    37.         UIAddressable reserveAmmo = uiAddressableManager.GetAddressable( "AmmoReserve" );
    38.  
    39.         if( heldWeapon.entity == Entity.Null )
    40.         {
    41.             currentAmmo.text.text = "-";
    42.             reserveAmmo.text.text = "-";
    43.         }
    44.         else
    45.         {
    46.             var weaponData = GetComponent<WeaponDataComponent>( heldWeapon.entity );
    47.             currentAmmo.text.text = weaponData.currentAmmo.ToString();
    48.             reserveAmmo.text.text = weaponData.reserveAmmo.ToString();
    49.         }
    50.  
    51.  
    52.         UIAddressable healthUi = uiAddressableManager.GetAddressable( "Health" );
    53.         int hp = (int)health.Value;
    54.         healthUi.text.text = hp.ToString();
    55.         if( hp > 80 )
    56.         {
    57.             healthUi.text.color = Color.white;
    58.         }
    59.         else if( hp > 50 )
    60.         {
    61.             healthUi.text.color = Color.grey;
    62.         }
    63.         else
    64.         {
    65.             healthUi.text.color = Color.red;
    66.         }
    67.  
    68.  
    69.         UIAddressable blueScore = uiAddressableManager.GetAddressable( "BlueScore" );
    70.         UIAddressable redScore = uiAddressableManager.GetAddressable( "RedScore" );
    71.  
    72.         NativeArray<int> scores = new NativeArray<int>( 2, Allocator.TempJob );
    73.         Entities
    74.             .ForEach( ( in TeamDataComponent teamData ) =>
    75.             {
    76.                 scores[teamData.teamId] = teamData.score;
    77.             } ).Run();
    78.  
    79.  
    80.         blueScore.text.text = scores[0].ToString();
    81.         redScore.text.text = scores[1].ToString();
    82.  
    83.         scores.Dispose();
    84.     }
    85. }
    86.  
     
  10. PeppeJ2

    PeppeJ2

    Joined:
    May 13, 2014
    Posts:
    43
    Try adding an empty scope, like this:
    I had similiar issues with ForEach where if an captured array is defined in the same scope it goes bananas.
     
    Last edited: Jun 9, 2021
  11. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    So trying just the ForEach in brackets still threw the exception, but moving it into it's own function did work. How horrid haha. Example code below.

    Code (CSharp):
    1.     private void UpdateScore()
    2.     {
    3.         UIAddressable blueScore = uiAddressableManager.GetAddressable( "BlueScore" );
    4.         UIAddressable redScore = uiAddressableManager.GetAddressable( "RedScore" );
    5.  
    6.         NativeArray<int> scores = new NativeArray<int>( 2, Allocator.TempJob );
    7.         UpdateScoreTest( scores );
    8.         blueScore.text.text = scores[0].ToString();
    9.         redScore.text.text = scores[1].ToString();
    10.  
    11.         scores.Dispose();
    12.     }
    13.  
    14.     private void UpdateScoreTest( NativeArray<int> scores )
    15.     {
    16.         Entities
    17.             .ForEach( ( in TeamDataComponent teamData ) =>
    18.             {
    19.                 scores[teamData.teamId] = teamData.score;
    20.             } ).Run();
    21.     }
     
  12. Dan-Foster

    Dan-Foster

    Joined:
    Aug 7, 2019
    Posts:
    53
    So just to update with how I'm probably going to leave this code right now. I've swapped to using an EntityQuery to get the components rather than going into a ForEach.

    Code (CSharp):
    1.     private void UpdateScore()
    2.     {
    3.         UIAddressable blueScore = uiAddressableManager.GetAddressable( "BlueScore" );
    4.         UIAddressable redScore = uiAddressableManager.GetAddressable( "RedScore" );
    5.        
    6.         var scoresData = teamScoresQuery.ToComponentDataArray<TeamDataComponent>( Allocator.TempJob );
    7.         for( int i = 0; i < scoresData.Length; ++i )
    8.         {
    9.             var current = scoresData[i];
    10.             if( current.teamId == 0 )
    11.                 blueScore.text.text = current.score.ToString();
    12.             if( current.teamId == 1 )
    13.                 redScore.text.text = current.score.ToString();
    14.         }
    15.         scoresData.Dispose();
    16.     }