Repository navigation
Conversation
|
@Noggog I think this one is probably worth taking a closer look at when you have time.
|
Noggog
left a comment
There was a problem hiding this comment.
For now, consumers need to call GameRegistration.Register(); before using APIs that rely on game registration or mappings.
Not sure i'd like to put that burden on without some serious discussion that there aren't ways to avoid this. If we're gonna do this, i think we do it right so that it's seamless to existing users of the library.
Is this our endgame plan to require this call? Or is there an idea in mind to avoid it we're planning on doing as a followup? Little bit of research suggests we can maybe make use of [ModuleInitializer] concepts?
internal static class GameRegistrationInit
{
[ModuleInitializer]
internal static void Init() => GameRegistration.Register();
}Sounds like AOT apps call this function automatically somehow? Not too familiar.
|
Thanks for the review!
No, I don't consider an explicit The key difference is that the reflection path auto-discovers games at runtime, whereas the AOT-safe path inherently requires static reachability, so runtime discovery is heavily constrained under Native AOT. This is a real behavioral change, not just an implementation detail. It's also why I wanted to explicitly separate the two paths at the current stage: the AOT-safe path doesn't fully work yet, so this lets us tell consumers that AOT support is still incomplete and that, if they opt in, they need to call
As for hiding the call, I did consider a library-side Another possibility, once AOT compatibility is further along, is a source generator that emits the registration call in the consuming application. I haven't verified this yet. A generator can only emit code rather than invoke it, so it would most likely have to emit a That's arguably more acceptable than having the library do it (CA2255 targets libraries). It would also have an extra benefit: the registration would happen at an appropriate time during the consumer's startup, without them having to think about it (unless the consumer has multiple It would still need to be idempotent, though, and its interaction with trimming would need testing. It also raises a new problem: if the consumer is itself a library, we would just push CA2255 onto them. Happy to hear your thoughts on whether a seamless route seems worth pursuing. |
There was a problem hiding this comment.
Ah, if GameRegistration.Register() is just needed for people opting into AOT, then that's okay. As long as typical users like Synthesis patchers not using AOT still work out of the box.
If that's the case, then we can just punt for now and solve the seamlessness for AOT users as a followup
|
Ah, that’s exactly what I meant! So, are we good to merge this PR? That said, I think the current API works fine as an internal implementation detail, but feels a bit awkward as a public API. Would you like me to follow up with another PR that adds a public registration/initialization API (in MutagenInitializer.Initialize(Game.Skyrim);
MutagenInitializer.Initialize(Game.Starfield);
MutagenInitializer.Initialize(Game.Skyrim, Game.Starfield);
MutagenInitializer.Initialize(Game.All);The idea is for each |
Related to #696
This is the first step toward Native AOT support. It introduces an explicit static registration path for Skyrim.
For now, consumers need to call
GameRegistration.Register();before using APIs that rely on game registration or mappings.It passes my local Native AOT tests as well as tests against a real-world use case.
The three
DynamicDependencyannotations are currently required, though it may be possible to remove them once the later stages of the Native AOT work are complete.I’d also like to add proper Native AOT smoke-test infrastructure, but I think the way that should be organized is something that should be decided by the maintainers. Personally, I’d probably lean toward using tools such as NUKE / Fallout to orchestrate the tests.