Skip to content

Installation

3cxc edited this page Sep 26, 2026 · 3 revisions

Installation

Requirements

Component Minimum
.NET SDK 8.0
Runtime .NET NativeAOT (plugin side)
Host OS Windows / Linux / macOS

Plugins are compiled with PublishAot=true and export unmanaged entry points. Cross-platform plugins must be built separately for each target OS.


Adding NativePluginKit to a Project

Option 1 — NuGet

<PackageReference Include="NativePluginKit" Version="1.2.0" />

Option 2 — Project Reference

If you are working inside the same solution:

<ProjectReference Include="..\NativePluginKit\NativePluginKit.csproj" />

Option 3 — Git Submodule

git submodule add https://github.com/GoWelkinDev/NativePluginKit.git

Host-Side Setup

In your client's initialization code, build a HostApiTable and create a PluginLoader:

using NativePluginKit.Loader;
using NativePluginKit.Loader.Constants;

var api = HostApiBridgeBuilder.Create(
    freeString:             ptr => Marshal.FreeCoTaskMem(ptr),
    transition:             (pathPtr, fadeOut) => { /* ... */ },
    getCurrentScenePath:    () => IntPtr.Zero,
    printLog:               ptr => { /* ... */ },
    printWarning:           ptr => { /* ... */ },
    printError:             ptr => { /* ... */ },
    logDebug:               ptr => { /* ... */ },
    getCharacterImagePath:  ptr => IntPtr.Zero,
    getExecutableDirectory: () => IntPtr.Zero,
    getPluginsDirectory:    () => IntPtr.Zero,
    getTimeSinceStartup:    () => 0,
    registerEvent:          (t, cb, ud) => true,
    unregisterEvent:        (t, cb, ud) => true,
    getCurrentTimelineName: () => IntPtr.Zero,
    isBattle:               () => 0,
    startTimeline:          (ptr, battle) => { },
    endTimeline:            skip => { },
    sendSignal:             ptr => { },
    // Cards, Entity — see HostApiBridgeBuilder.Create full signature
    /* ... */
);

var loader = new PluginLoader(
    logAction:  msg => Console.WriteLine(msg),
    apiTable:   api,
    apiVersion: new Version(1, 0, 0));

loader.LoadPluginsFromDirectory(
    Path.Combine(AppContext.BaseDirectory, "plugins"));

The Create method takes 70+ parameters. In real projects you should keep all delegate instances in static readonly fields to prevent GC collection — HostApiBridgeBuilder already stores strong references internally, but the lambdas themselves must not be ephemeral.


Plugin-Side Setup

  1. Create a new Class Library targeting net8.0.

  2. Add the following to the .csproj:

    <PropertyGroup>
      <TargetFramework>net8.0</TargetFramework>
      <Nullable>enable</Nullable>
      <PublishAot>true</PublishAot>
      <NativeLib>Shared</NativeLib>
      <IlcExportUnmanagedEntrypoints>true</IlcExportUnmanagedEntrypoints>
      <RuntimeIdentifier>win-x64</RuntimeIdentifier>   <!-- or linux-x64 / osx-x64 -->
      <InvariantGlobalization>true</InvariantGlobalization>
    </PropertyGroup>
    
    <ItemGroup>
      <ProjectReference Include="..\NativePluginKit\NativePluginKit.csproj" />
      <ProjectReference Include="..\NativePluginKit.SourceGenerators\NativePluginKit.SourceGenerators.csproj"
                        OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
      <UnmanagedEntryPointsAssembly Include="NativePluginKit" />
    </ItemGroup>

    UnmanagedEntryPointsAssembly is required so that Plugin.GetPluginInfo (declared in NativePluginKit) is exported from the plugin DLL.

  3. Build:

    dotnet publish -c Release -r win-x64
  4. Copy the output YourPlugin.dll into <GameRoot>/plugins/.

Clone this wiki locally