Halen84 / ScriptHookRDR2DotNet-V2

An ASI plugin for Red Dead Redemption 2, which allows anyone to create scripts using any .NET language.
zlib License
55 stars 10 forks source link

worldGetAll... Pool Functions CTD #2

Open Halen84 opened 1 year ago

Halen84 commented 1 year ago

Calling any of the import pool functions from AB's ScriptHook, will eventually cause a crash to desktop at random. These functions include worldGetAllVehicles(), worldGetAllPeds(), worldGetAllObjects(), and worldGetAllPickups().

This happens on all versions, including the old ScriptHookRDRDotNet. This also happens on both AB's ScriptHook and keps ScriptHook V2, so I think it's safe to assume that it's a C# issue.

Stack Trace:

Exception Info: System.AccessViolationException
   at RDR2DN.NativeMemory.worldGetAllPeds(Int32[], Int32)
   at RDR2.World.GetAllPeds()
   at MyProject.Main.OnTick(System.Object, System.EventArgs)
   at RDR2DN.Script.MainLoop()
   at System.Threading.ExecutionContext.RunInternal(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
   at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object)
   at System.Threading.ThreadHelper.ThreadStart()

My only logical guess would be the array (arr) parameter. The worldGetAllPeds implementation is using a C-Styled array, which is somewhat different from a C# int[] array. Can't figure out if this is the cause or not. I've already spent hours trying to debug this. Tried all kinds of different marshalling methods of the parameter. Just can't get it to work properly.

My current guess as to what the issue might be is this: AB's states that these pool functions "can be called only in the same thread as natives". So maybe there's an issue there.

Currently, my only solution is to just implement these pool functions in C# itself instead of importing them from ScriptHook.

Halen84 commented 1 year ago

Getting back to this, and a "temporary" workaround is to add [HandleProcessCorruptedStateExceptions] attribute to World.GetAllPeds() and wrap the worldGetAllPeds() call in a try catch with no exception parameter. Same applies to other pool functions.

Kep told me that his scripthook v2 doesn't crash as of 1491.17, but I haven't tested it.

leonard2z commented 1 year ago

Still an issue here. World.GetAllPeds() keeps returning empty array.

Halen84 commented 1 year ago

Still an issue here. World.GetAllPeds() keeps returning empty array.

It returns an empty array when the internal call to worldGetAllPeds failed. See comment above, or check source code.

Halen84 commented 1 year ago

Reopened as I would like to fix this entirely instead of doing a band aid fix. No idea if it's a C# issues or an issue with AB's scripthook.

kagikn commented 1 year ago

Would sound silly, but I think it's because all worldGetAll function imports are missing In and Out attributes at the arr parameter (the In attribute is implicitly specified in this case btw). I haven't actually tested this, but I feel like that's the problem. Managed arrays should be marshalled in both ways when you call those functions. Just in case you have no idea what In and Out are, they are InAttribute and OutAttribute of System.Runtime.InteropServices. There's a document that explains how to marshal arrays. Managed arrays can be moved to another addresses and that can bother you without proper marshaling or pinning when you call unmanaged functions and use managed arrays for them, so you should be careful…

It would be better if this runtime fetches pool handles without relying on AB's scripthook like how SHVDN fetches pool handles as you won't always have to use large buffer arrays in that way, but should be another topic. It would be worth noting that gameconfig.xml specifies the CObject pool (which Prop instances would use) should allocate a block of memory that can contain 3000 elements of CObject (yes, in RDR3, this is more than that of GTA5), though.

Edit: You're probably aware of this, but I heard some people said worldGetAll functions don't properly work in AB's scripthook (not V2) since December 2022. If that is correct, I'm sorry, I don't have set up modding environment for RDR and can't throughly inspect that, so I can't help you in this aspect soon (but still worth learning how to marshal arrays I guess?).

Halen84 commented 1 year ago

I believe I have already tried that in the past and it didn't work, but I'll try again just to make sure. I've already tried so many different ways to marshal that array, but none of them work. Lol man I've spent HOURS on the array parameter trying to debug that shit and eventually gave up and just stuck with the [HandleProcessCorruptedStateExceptions] band aid fix.

Edit: Yeah no the [Out] and [In] didn't work as expected. I really appreciate the help though. Looks like I'm going to have to implement these functions in C#. Can't rely on people to switch to keps V2.

And yes, I've heard lots of people say that the worldGetAll pool functions have been broken ever since AB rewrote his ScriptHook or whatever, but I never had any issue with them at least in C++, so I'm not sure. I guess really the only fix is to use keps ScriptHook V2 unless I decide to implement them in C# instead.