Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Error / incorrect values when reading Nullable<T> properties #826

Open
7 tasks done
Lanying600 opened this issue Jan 9, 2025 · 3 comments
Open
7 tasks done

Comments

@Lanying600
Copy link

Lanying600 commented Jan 9, 2025

All of the following criteria must be met

  • All Requirements must be installed.
  • Changed the title so that it doesn't just says "[Bug]: "
  • I have searched the GitHub issues for my bug, even in the closed issues.

All of the following are optional to answer

  • Tried reinstalling the Game.
  • Tried reinstalling MelonLoader.
  • Tried restarting PC.
  • Was able to see the Start Screen.

Describe the issue.

Trying to read a property that is Nullable<T> will result in an exception if value is null, or an incorrect value if not null.

I would expect to be able to read the property with a null conditional operator like so
MelonLogger.Msg(template.Duration?.value);
But this results in the exception in the logs below if the value is null.

To try to avoid this I can catch the exception

int? duration = null;
try
{
    duration = template.Duration?.value;
}
catch (Exception)
{
    // ignored
}

and this no longer throws, but the value returned is incorrect, in this case -534465616. Calling GetValueOrDefault will return default in these cases.

Full log below

[09:54:08.328] ------------------------------
[09:54:08.360] MelonLoader v0.6.6 Open-Beta
[09:54:08.361] OS: Windows 10
[09:54:08.361] Hash Code: 81E5A4A5974318B4F948B1A58B8459762E3F307B880356782FAB3857F0658A37
[09:54:08.361] ------------------------------
[09:54:08.362] Game Type: Il2cpp
[09:54:08.362] Game Arch: x64
[09:54:08.362] ------------------------------
[09:54:08.362] Command-Line: 
[09:54:08.363] ------------------------------
[09:54:08.363] Core::BasePath = C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen
[09:54:08.363] Game::BasePath = C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen
[09:54:08.364] Game::DataPath = C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\Pantheon_Data
[09:54:08.364] Game::ApplicationPath = C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\Pantheon.exe
[09:54:08.364] Runtime Type: net6
[09:54:08.814] ------------------------------
[09:54:08.815] Game Name: Pantheon
[09:54:08.815] Game Developer: Visionary Realms
[09:54:08.817] Unity Version: 2022.3.51f1
[09:54:08.817] Game Version:    
[09:54:08.817] ------------------------------

[09:54:09.984] Preferences Loaded!

[09:54:09.998] Loading UserLibs from 'C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\UserLibs'...

[09:54:10.010] Loading Plugins from 'C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\Plugins'...
[09:54:10.012] 0 Plugins loaded.
[09:54:15.420] Loading Il2CppAssemblyGenerator...
[09:54:15.443] [Il2CppAssemblyGenerator] Contacting RemoteAPI...
[09:54:15.633] [Il2CppAssemblyGenerator] Game Not Found on RemoteAPI Host (https://api.melonloader.com/api/v1/game/pantheon)
[09:54:15.633] [Il2CppAssemblyGenerator] RemoteAPI.DumperVersion = null
[09:54:15.634] [Il2CppAssemblyGenerator] RemoteAPI.ObfuscationRegex = null
[09:54:15.634] [Il2CppAssemblyGenerator] RemoteAPI.MappingURL = null
[09:54:15.635] [Il2CppAssemblyGenerator] RemoteAPI.MappingFileSHA512 = null
[09:54:15.641] [Il2CppAssemblyGenerator] Using Cpp2IL Version: 2022.1.0-pre-release.18
[09:54:15.641] [Il2CppAssemblyGenerator] Using Il2CppInterop Version = 1.4.6-ci.579+9d4599dc78d69ede49a2ee96a1ccf41eec02db5b
[09:54:15.641] [Il2CppAssemblyGenerator] Using Unity Dependencies Version = 2022.3.51
[09:54:15.642] [Il2CppAssemblyGenerator] Using Deobfuscation Regex = null
[09:54:15.643] [Il2CppAssemblyGenerator] Cpp2IL is up to date.
[09:54:15.643] [Il2CppAssemblyGenerator] UnityDependencies is up to date.
[09:54:15.643] [Il2CppAssemblyGenerator] Checking GameAssembly...
[09:54:15.869] [Il2CppAssemblyGenerator] Assembly is up to date. No Generation Needed.

[09:54:15.873] Loading Mods from 'C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\Mods'...
[09:54:15.895] ------------------------------
[09:54:15.900] Melon Assembly loaded: '.\Mods\Pantheon.dll'
[09:54:15.900] SHA256 Hash: '7E2E439310F4CE0798FDE9803EB63B5830401C91F5A76ED13ED35799B1306FAB'

[09:54:16.361] ------------------------------
[09:54:16.361] Test v1.0.0
[09:54:16.361] by Test
[09:54:16.363] Assembly: Test.dll
[09:54:16.364] ------------------------------
[09:54:16.364] ------------------------------
[09:54:16.365] 1 Mod loaded.

[09:54:17.639] [Il2CppInterop] Class::Init signatures have been exhausted, using a substitute!
[09:54:17.816] [Il2CppInterop] Registered mono type Il2CppInterop.Runtime.DelegateSupport+Il2CppToMonoDelegateReference in il2cpp domain
[09:54:17.903] [Il2CppInterop] Registered mono type MelonLoader.Support.MonoEnumeratorWrapper in il2cpp domain
[09:54:17.963] [Il2CppInterop] Registered mono type MelonLoader.Support.SM_Component in il2cpp domain
[09:54:17.975] Support Module Loaded: C:\Program Files (x86)\Steam\steamapps\common\Pantheon Rise of the Fallen\MelonLoader\Dependencies\SupportModules\Il2Cpp.dll
[09:54:18.355] Mod Initialized!
[09:54:18.584] [Il2CppInterop] Registered mono type Pantheon.OutlineHandler in il2cpp domain
[09:55:39.283] [Test] System.NullReferenceException: Object reference not set to an instance of an object.
   at Il2CppInterop.Runtime.InteropTypes.Il2CppObjectBase.CreateGCHandle(IntPtr objHdl) in /home/runner/work/Il2CppInterop/Il2CppInterop/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs:line 50
   at Il2CppInterop.Runtime.InteropTypes.Il2CppObjectBase..ctor(IntPtr pointer) in /home/runner/work/Il2CppInterop/Il2CppInterop/Il2CppInterop.Runtime/InteropTypes/Il2CppObjectBase.cs:line 21
   at Il2CppSystem.Object..ctor(IntPtr pointer)
   at Il2CppSystem.ValueType..ctor(IntPtr pointer)
   at Il2CppSystem.Nullable`1..ctor(IntPtr pointer)
   at Il2Cpp.ItemTemplate.get_Durability()
   at Pantheon.Extensions.ItemTemplateExtensions.ToItemPayload(ItemTemplate template)
   at Pantheon.ModMain.OnUpdate()
   at MelonLoader.MelonEventBase`1.Invoke(Action`1 delegateInvoker) in D:\a\MelonLoader\MelonLoader\MelonLoader\Melons\Events\MelonEvent.cs:line 143

Did you attach your log file?

Yes, I attached my log file to the text box above.

@slxdy
Copy link
Contributor

slxdy commented Jan 9, 2025

If thats a normal nullable, how are you getting an Il2CppInterop exception?

@Lanying600
Copy link
Author

Lanying600 commented Jan 9, 2025

The property in this case is an Il2CppSystem.Nullable:
public unsafe Il2CppSystem.Nullable<int> Duration
Apologies for not making this clear in the issue. Here is the full definition in case it is useful to you:

public unsafe Il2CppSystem.Nullable<int> Duration
{
  [CallerCount(0)] get
  {
	IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase) this);
	System.IntPtr* numPtr = (System.IntPtr*) null;
	System.IntPtr exc;
	System.IntPtr pointer = IL2CPP.il2cpp_runtime_invoke(ItemTemplate.NativeMethodInfoPtr_get_Duration_Public_get_Nullable_1_Int32_0, IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase) this), (void**) numPtr, ref exc);
	Il2CppInterop.Runtime.Il2CppException.RaiseExceptionIfNecessary(exc);
	return new Il2CppSystem.Nullable<int>(pointer);
  }
  [CallerCount(0)] set
  {
	IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase) this);
	System.IntPtr* numPtr = stackalloc System.IntPtr[1]
	{
	  IL2CPP.il2cpp_object_unbox(IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase) value))
	};
	System.IntPtr exc;
	IL2CPP.il2cpp_runtime_invoke(ItemTemplate.NativeMethodInfoPtr_set_Duration_Public_set_Void_Nullable_1_Int32_0, IL2CPP.Il2CppObjectBaseToPtrNotNull((Il2CppObjectBase) this), (void**) numPtr, ref exc);
	Il2CppInterop.Runtime.Il2CppException.RaiseExceptionIfNecessary(exc);
  }
}

@Lanying600
Copy link
Author

I have a found a workaround, but I don't know if this is expected behaviour. In the case that the property is not null, unboxing to the type gives the correct value. Please let me know if there is a better way to do this.

int? duration = null;
try
{
    duration = template.Duration?.Unbox<int>();
}
catch (Exception)
{
    // ignored
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants