Ideas for v4 API
See original GitHub issueSince v3.7.0 is coming soon, which contains various performance improvements, compatibility fixes for earlier game versions and a lot of features, it’s definitely a good idea we should start thinking how we should design the v4 API. We could provide more organized/polished APIs before I start thinking about how to create another runtime variant of SHVDN built against .NET 7+ with the use of features only available in .NET Core environment, such as Span
.
More ideas will be suggested periodically, so it would be great if you could leave your own idea/feedback below.
Separate AppDomain per script
Since you can share variables between scripts without using dedicated ways in v2 and v3, we can’t use separate AppDomain
s for scripts built agains v2 or v3 in favor of compatibility (See #1162 for the details).
Struct InputArgument
One of our biggest design mistakes IMO. No need to use class for a single 8 byte value that can be exposed in the public without having too much of issues. For OutputArgument
, we could define a implicit operator to convert to InputArgument
. We don’t want to push the GC pressure for native calls in future APIs.
Weapon Classes Restructure
We could make brand new weapon or ped inventory classes such as PedInventory
, PedWeaponInventory
, PedWeaponInventoryItem
, PedAmmoInventory
, and PedAmmoInventoryItem
. There is CWeapon
, which manages weapon states such as the current ammo count in clip (not a subclass of CObject
btw), so we should not reserve Weapon
class for the class for weapon inventory item of a ped IMO.
Remove Auto Model Loading from Methods For Entity Creation
Looks like the not a few script developers casually create entities just with World.Create*
(not applies to CreateRandom
variants as they use one of loaded ambient models), while you cannot control how you load models by those methods and it is not guaranteed you can create multiple entities with different models at the same frame.
Not a few script developers don’t bother to mark models they requested as no longer needed so the game can free the resource for the models, either.
Script developers will care about model resource handling as you would need to in ysc or C++ scripts in the v4 API. More code to write in your scripts, but you may fail to create multiple entities with different models otherwise.
SHVDN will return null if fails to create due to the model absent (CREATE_*
natives won’t crash even if the model is not loaded like equivalent opcodes do crash the game in that case in 3D Era games, will return zero instead in that case).
Separate TextStyle class
We should separate text drawing or measureing class and text style class just like how RAGENativeUI handles the current text style. Separating them would increase performance as we can avoid redundant native calls for applying text style (you can’t avoid END_TEXT_COMMAND_DISPLAY_TEXT
setting the font style values to default ones however).
Dedicated Static Control Class
Simple, the Game
class is kinda bloated for control methods. Since the exe has the dedicated class CControl
, making a dedicated class for Control would make sense.
Await support for custom Task-ish class (but not for built-in Task in favor of performance)
It would be great if you can use the await syntax, correct? Looks like we shouldn’t use the classic Task
s in SHVDN built against .NET Framework, because Task
/Task<T>
that are used for the default .NET scheduler suffers way more overhead than in .NET Core/NET 5+. FiveM suffered the slow Tasks and they are introducing the custom Task-ish classes Coroutine/Coroutine<T>. Looks like we should not introduce our custom task scheduler for built-in Task
in SHVDN that runs on .NET Framework, either. Maybe it won’t suffer too much of overhead if we use our custom task scheduler for built-in Task
in a new SHVDN equivalent runtime built against .NET 7+ though.
For your information, the built-in Tasks allocates less resources such as ExecutionContext
in .NET Core 2.1, and there are more improvements for async jobs in .NET 6.
Don’t use more than 1 thread for all .NET scripts (if possible)
I believe there’s no need to use more than one dedicated thread for .NET scripts as long as we can stop executing them when an unhandled exception is thrown or they takes too much time in one loop without a debugger attached. We might need one dedicated thread for more stack space, though.
If we use a task scheduler (that execute in a single thread) to process scripts, we’ll end up in losing the ability to abort scripts that takes too long time in one loop without letting them execute one loop, but I wouldn’t care that ability too much since The docs of .NET doesn’t recommend to use Thread.Abort
very much and it’s not supported in .NET 5+. RAGE Plugin Hook doesn’t abort plugin execution during a loop for long execution time and instead it terminates the plugin after the loop ends FYI.
The compatibility may break too much if we reduce the number threads to one, but we could do this without worrying about the compatibility for the v4 API before the first official version with v4 API is published.
Misc
- Don’t force script developers to create duplicate native calls
Vehicle.CreatePedOnSeat
andVehicle.CreateRandomPedOnSeat
throwArgumentException
is the seat is occupied, but that forcesVehicle.IsSeatFree
to be called twice to guarantee the methods will not throwArgumentException
for the seat being occupied. - Make ISpatial only have Position
Having rotation prevent the
NavMeshBlockingObject
from havingISpatial
. The same case may happen in other classes that represents the game classes or structs. - Rename the Enum Bone to PedBoneTag
Tasks
- Provide separate AppDomain per script
- Made InputArgument struct instead of class for v4 API
- Restructure weapon classes for v4 API
- Remove Auto Model Loading from Methods For Entity Creation for v4 API
- Create Dedicated Control class for v4 API
- Support async/await for custom Task-ish classes (no support for built-in Task in favor of performance)
Issue Analytics
- State:
- Created 4 months ago
- Reactions:6
- Comments:6 (4 by maintainers)
Top GitHub Comments
Enabled GitHub Discussions for more potential engagement in discussions. crosire wouldn’t have enabled this, but I’m giving it a try. Maybe we can spot design flaws more easily. Discord server for SHVDN? I’ll need more time to set up for that.
I thought of nuget packages providing interfaces for abstraction for API layers, but I am speculating you’ll end up dealing with versioning issues on interface implementation (such as old and new version resolution). However, maybe we shouldn’t create many custom interfaces in API itself in the first place, since you would think of mocking typically when you use third party libraries IMO. I haven’t used mocks much due to the nature of game modding where you can’t exactly predict how functions embedded in the game works without people with good reverse engineering skill, but using your own mocks is a generally better option to me. I remember when I mocked my own sockets where a Web API is used in production in a tiny web app of mine a year ago, but don’t remember when I used some mocks provided by libraries themselves (not talking about libraries such as Jest).
As for
PlayerProvider
you provided, it doesn’t seem to me mock does a job for properties too good, since none of them doesn’t execute complex logics afaik.Game.Player.Character
only fetches local player index (always zero in SP) and gets the player ped handle (will have to register script entity index, but still not too complex).Player.CanControlCharacter
basically reads/writes a value from/to a 4-byte value and that’s it.Player.IsDead
will only check if the player ped is not lower than the fatal injury threshold.