Skip to content
Ling edited this page Jul 7, 2026 · 3 revisions

常见问题

为什么 NuGet 包名和命名空间不一样?

NuGet 包 ID 是:

PlainCraftLauncher.Plugin.Abstractions

代码命名空间和程序集是:

PCL.Plugin.Abstractions
PCL.Plugin.Abstractions.dll

这是正常的。NuGet.org 上部分短前缀可能被保留,包 ID 需要避开保留前缀;为了不破坏宿主和插件之间的程序集类型身份,程序集名保持 PCL.Plugin.Abstractions

为什么 C# 插件要引用 SDK 包?

DLL 插件需要和宿主共享同一个 IPclPluginIPluginContextIPluginHost 等类型。宿主通过这些类型识别插件入口并调用生命周期方法。

即使接口代码长得一样,只要来自不同程序集,在 CLR 看来就不是同一个类型。

为什么要写 ExcludeAssets="runtime"

插件包不应携带自己的 PCL.Plugin.Abstractions.dll。宿主会提供 SDK 契约程序集。

推荐:

<PackageReference Include="PlainCraftLauncher.Plugin.Abstractions" Version="1.1.0" ExcludeAssets="runtime" />

JavaScript 插件为什么不用引用 SDK?

JS 文件不是 .NET 程序集。宿主内部有 JavaScript 适配层,会把 JS 的 load(ctx) / unload() 映射到统一插件生命周期。

JavaScript 插件能使用 npm 吗?

不能。当前 JS 插件不是 Node.js 环境,没有 npm、node_modules、Node 标准库或浏览器 DOM。

可以使用:

  • 宿主注入的 ctx / pcl
  • require(path) 加载插件目录内脚本。
  • dotnet facade 调用 .NET 类型或插件携带的 DLL。

JS 的 require 是 CommonJS 吗?

不是完整 CommonJS。它只会读取插件目录内的目标脚本并执行,返回脚本求值结果。

不要依赖 Node.js 的模块解析规则。

插件可以引用启动器内部项目吗?

不推荐。公开插件应尽量只依赖 SDK 包 PlainCraftLauncher.Plugin.Abstractions

如果插件需要宿主尚未暴露的能力,应优先把能力抽象进 SDK,再由宿主实现。

插件可以启动 Minecraft 或修改主题吗?

当前公开 SDK 有意不暴露游戏启动、账户登录、主题/品牌资产相关入口。

插件不应依赖启动器内部实现绕过这些边界。

Host.UiHost.CommandsHost.Extensions 为什么是 null?

通常是 manifest 没声明对应能力。

示例:

"capabilities": ["ContributeTools", "RegisterExtension"]

还要注意 UI 能力需要在 UI 就绪后使用,推荐加载时机 WindowCreated

插件卸载时必须做什么?

释放所有注册项、取消事件订阅、停止后台任务、关闭文件句柄或本地进程。

C# 插件在 UnloadAsync 中完成。JS 插件在 unload() 中完成。通过 JS UI facade 注册的面板会被宿主上下文跟踪并释放。

如何选择 C# 还是 JS?

选择 C#:

  • 需要复杂逻辑。
  • 需要长期维护。
  • 需要完整 WPF UI。
  • 需要调用 .NET 库或管理外部进程。

选择 JS:

  • 快速验证想法。
  • 做简单 UI 面板。
  • 写轻量自动化。
  • 不想建立完整编译项目。

可以同时有 DLL 和 JS 吗?

一个插件包的入口通常选择一种类型。JS 插件可以通过 dotnet.loadAssembly 加载插件目录内的辅助 DLL;C# 插件也可以自己嵌入脚本引擎,但这不属于宿主 JS 插件入口。

SDK 版本和插件版本怎么对应?

插件版本是你自己的插件版本。minApiVersion 表示插件需要的最低 PCL 插件 SDK API 版本。

例如使用 1.1.0 新增能力时:

"minApiVersion": "1.1.0.0"

Clone this wiki locally