-
Notifications
You must be signed in to change notification settings - Fork 0
Refactor: SdkModule & Integration ModClient #17
Copy link
Copy link
Open
Description
Refactor: NdGameSdk Module System (EntryPoint + Submodules)
Summary
Refactor the NdGameSdk module model so the SDK can:
- Run without any module: only
InitializeSdk(cfg)is called; base patches/components are active. - Optionally host one Main EntryPoint module (e.g.,
Nd.modclient) and any number of Submodules registered by that EntryPoint.
This gives developers two paths:
- Build a custom EntryPoint (strict/specific purpose of modding).
- Build submodules that extend the approved EntryPoint (
Nd.modclient).
Scope / Goals
- Allow
InitializeSdk(&cfg)to succeed with no module. - Enforce single EntryPoint (a.k.a. “Main module”).
- Add Submodule concept (+ register/unregister).
- Both EntryPoint and Submodules can use SDK components & events.
- EntryPoint can discover/track submodules and optionally expose internal services to them (via a small “services bridge”).
- Provide soft standards + a patching utility component to avoid chaos.
Non-goals
- Changing core SDK component lifecycle.
Public API
New/Updated
InitializeSdk(const SdkConfig* cfg)RegisterEntryPoint(ISdkModule* main, EntryPointServices* services /*nullable*/)UnregisterEntryPoint(ISdkModule* main)RegisterSubmodule(ISdkModule* sub)UnregisterSubmodule(ISdkModule* sub)GetEntryPoint() -> ISdkModule* /*nullable*/GetSubmodules() -> std::vector<ISdkModule*>HasEntryPoint() -> boolenum class SdkModuleKind { EntryPoint, Submodule }struct EntryPointServices { virtual ~EntryPointServices() = default; /* opaque bridge */ }
Deprecated
RegisterSdkModule(ISdkModule* main)→ alias toRegisterEntryPoint.
ISdkModule (lifecycle hooks)
OnModuleRegistered()OnRoleAssigned(SdkModuleKind role, ISdkModule* entrypoint, EntryPointServices* services)
EntryPoint:role=EntryPoint, entrypoint=this
Submodule:role=Submodule, entrypoint=GetEntryPoint()- (EntryPoint only)
OnSubmoduleRegistered(ISdkModule* sub),OnSubmoduleUnregistered(ISdkModule* sub)
Errors (extend SdkModuleException)
AlreadyHasEntryPointNoEntryPointInvalidRole
Runtime Rules
- Base-only mode: only
InitializeSdk. No modules registered. SDK logs that it runs without an EntryPoint; components still function. - EntryPoint: can be registered once. Second registration →
AlreadyHasEntryPoint. - Submodules: require an active EntryPoint; otherwise →
NoEntryPoint. - Wiring: EntryPoint and Submodules receive the same SDK component events.
- Order on register:
OnModuleRegistered()→OnRoleAssigned(...).
EntryPoint also receivesOnSubmoduleRegistered/Unregistered. - Lifetime: SDK does not own module objects. On EntryPoint unload, SDK auto-unregisters submodules first.
- Thread-safety: operations guarded by a registry mutex.
Soft Standards: Patching Utilities (SDK Component)
Try to Introduce a PatchManager SDK component to standardize patching:
- Capabilities (conceptual):
- Detours (store by name/id), branch/call patches, byte patches with restore.
- Grouping/scope (remove by group); auto-cleanup on module unload.
- Address resolution goes through SDK discovery (patterns/symbols), no raw magic offsets in modules.
- Naming convention:
"<ModuleName>/<System>/<Action>". - Logging: success/failure with name + address; verify page protection & instruction boundaries.
Access via
GetSharedSdkComponent<PatchManager>().
EntryPoint Services Bridge
- Minimal
EntryPointServicesinterface acts as an opaque bridge from EntryPoint to Submodules. - The EntryPoint (e.g.,
Nd.modclient) implements a derived services class to expose optional internals (e.g.,NdModsaccessor) that submodules can consume afterOnRoleAssigned.
Migration Notes
- Base-only: just call
InitializeSdk(&cfg); skip registration. - Existing main module: replace
RegisterSdkModule(main)withRegisterEntryPoint(main, &services /*optional*/); optionally handle submodule callbacks. - Submodules: implement
ISdkModule, rely on EntryPoint to callRegisterSubmodule(this); useOnRoleAssignedto bind services and SDK components.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels