<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki2.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E6%8F%92%E4%BB%B6%E5%A5%91%E7%BA%A6%E4%B8%8E%E6%89%93%E5%8C%85%E7%BA%A6%E5%AE%9A</id>
	<title>插件契约与打包约定 - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki2.lessokaji.com/index.php?action=history&amp;feed=atom&amp;title=%E6%8F%92%E4%BB%B6%E5%A5%91%E7%BA%A6%E4%B8%8E%E6%89%93%E5%8C%85%E7%BA%A6%E5%AE%9A"/>
	<link rel="alternate" type="text/html" href="https://wiki2.lessokaji.com/index.php?title=%E6%8F%92%E4%BB%B6%E5%A5%91%E7%BA%A6%E4%B8%8E%E6%89%93%E5%8C%85%E7%BA%A6%E5%AE%9A&amp;action=history"/>
	<updated>2026-05-16T17:14:55Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.40.0</generator>
	<entry>
		<id>https://wiki2.lessokaji.com/index.php?title=%E6%8F%92%E4%BB%B6%E5%A5%91%E7%BA%A6%E4%B8%8E%E6%89%93%E5%8C%85%E7%BA%A6%E5%AE%9A&amp;diff=1046&amp;oldid=prev</id>
		<title>Artheru：​Initial bilingual draft (auto-published)</title>
		<link rel="alternate" type="text/html" href="https://wiki2.lessokaji.com/index.php?title=%E6%8F%92%E4%BB%B6%E5%A5%91%E7%BA%A6%E4%B8%8E%E6%89%93%E5%8C%85%E7%BA%A6%E5%AE%9A&amp;diff=1046&amp;oldid=prev"/>
		<updated>2026-05-16T14:00:47Z</updated>

		<summary type="html">&lt;p&gt;Initial bilingual draft (auto-published)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;&amp;lt;languages/&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== 概述 / Overview ==&lt;br /&gt;
本页讲所有 MDCS 插件 ''共通'' 的约定 —— 不论是雷达 / 相机 / 底盘 / Movement / 还是 SimpleComposer 插件，这些规则都适用。具体的 ''基类签名''见各家族页面。&lt;br /&gt;
&lt;br /&gt;
This page covers the conventions ''shared by every MDCS plugin'' — lidar, camera, cart, Movement, fleet — regardless of family. The family-specific ''base-class contracts'' live on their own pages.&lt;br /&gt;
&lt;br /&gt;
== 1. 命名约定 / Naming convention ==&lt;br /&gt;
=== MainIOObject 命名 ===&lt;br /&gt;
'''Medulla 端插件''' (lidar / camera / cart) 的入口类 ''必须叫 `MainIOObject`'' —— 严格区分大小写。&lt;br /&gt;
The Medulla-side plugin entry class ''must be named exactly `MainIOObject`'' — case-sensitive.&lt;br /&gt;
&lt;br /&gt;
Medulla 加载器 (`D:\src\M2\MedullaCore\MedullaIO.cs:299`) 反射查找：&lt;br /&gt;
The loader does reflection lookup:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;csharp&amp;quot;&amp;gt;&lt;br /&gt;
var type = asm.GetTypes().FirstOrDefault(t =&amp;gt; t.Name == &amp;quot;MainIOObject&amp;quot;);&lt;br /&gt;
return Activator.CreateInstance(type);  // parameterless ctor required&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
没有 `[Plugin]` 属性，没有 manifest。仅靠类名 + 无参构造函数。&lt;br /&gt;
No `[Plugin]` attribute, no manifest — just the class name and a parameterless ctor.&lt;br /&gt;
&lt;br /&gt;
【注意】 改类名或删默认构造函数 → 加载静默失败 → 几分钟后由 `Hedingben` toast 间接报错。先用 `io load &amp;lt;yourplugin&amp;gt;.dll` 在 Medulla console 单独测试加载。&amp;lt;br&amp;gt;&lt;br /&gt;
Renaming or removing the parameterless ctor → silent load failure surfacing later in `Hedingben`. Test `io load` in isolation first.&lt;br /&gt;
&lt;br /&gt;
=== Clumsy / Simple 插件类名 ===&lt;br /&gt;
Clumsy `MovementDefinition` 子类 + Simple `Car` / `ClumsyCar` / `BusinessLogic` 子类不要求特定类名，但用 ''属性'' 标识：&lt;br /&gt;
Clumsy / Simple plugins don't need a specific name; they use attributes to identify themselves:&lt;br /&gt;
&lt;br /&gt;
* `[CarType]` 标 Simple 端 Car 子类&lt;br /&gt;
* `[MovementTest]` 标 Clumsy Movement 测试入口&lt;br /&gt;
* `[CoderMethod]` 标 SimpleCore TopazScript 编码器方法&lt;br /&gt;
&lt;br /&gt;
=== 文件夹与 DLL 命名 / Folder &amp;amp; DLL naming ===&lt;br /&gt;
* 一方插件 / First-party: `D:\src\M2\OfficialPlugins\&amp;lt;VendorModel&amp;gt;\`&lt;br /&gt;
* 三方插件 / Third-party: 任意；通常 `&amp;lt;vendor-name&amp;gt;\&amp;lt;model&amp;gt;\`&lt;br /&gt;
* DLL 名 = `&amp;lt;VendorModel&amp;gt;.dll`，部署到 `medulla/plugins/&amp;lt;vendor&amp;gt;/` 或 `simplecomposer/plugins/`&lt;br /&gt;
&lt;br /&gt;
== 2. 项目文件 / .csproj ==&lt;br /&gt;
=== 目标框架 / Target framework ===&lt;br /&gt;
* '''.NET 6.0''' or '''.NET 8.0''' — 推荐 / preferred&lt;br /&gt;
* '''.NET Framework 4.8''' — 部分旧雷达驱动用 / some legacy lidar drivers&lt;br /&gt;
&lt;br /&gt;
=== 引用 / References ===&lt;br /&gt;
所有插件 csproj 都引用 ''参考程序集''（`Ref&amp;lt;Name&amp;gt;.dll`），不引用 impl DLL：&lt;br /&gt;
All plugin csproj reference '''reference-only assemblies''' (`Ref&amp;lt;Name&amp;gt;.dll`), not the implementation DLLs:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;ItemGroup&amp;gt;&lt;br /&gt;
  &amp;lt;PackageReference Include=&amp;quot;Fody&amp;quot; Version=&amp;quot;6.x&amp;quot; PrivateAssets=&amp;quot;all&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;PackageReference Include=&amp;quot;Costura.Fody&amp;quot; Version=&amp;quot;5.x&amp;quot; /&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Include=&amp;quot;RefFundamentalLib&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;HintPath&amp;gt;..\tools\RefFundamentalLib.dll&amp;lt;/HintPath&amp;gt;&lt;br /&gt;
  &amp;lt;/Reference&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Include=&amp;quot;RefMedullaCore&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;HintPath&amp;gt;..\tools\RefMedullaCore.dll&amp;lt;/HintPath&amp;gt;&lt;br /&gt;
  &amp;lt;/Reference&amp;gt;&lt;br /&gt;
  &amp;lt;Reference Include=&amp;quot;RefLidarController&amp;quot;&amp;gt;&lt;br /&gt;
    &amp;lt;HintPath&amp;gt;..\tools\RefLidarController.dll&amp;lt;/HintPath&amp;gt;&lt;br /&gt;
  &amp;lt;/Reference&amp;gt;&lt;br /&gt;
&amp;lt;/ItemGroup&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
`..\tools\` 模式 ''全仓库一致'' —— 不要改成 NuGet。&lt;br /&gt;
The `..\tools\` HintPath pattern is repo-wide; don't try to NuGet-ify it.&lt;br /&gt;
&lt;br /&gt;
=== Costura.Fody 胖 DLL ===&lt;br /&gt;
插件输出是单 `.dll`，所有依赖（包括 LessokajiWeaver 工具库）嵌入为 base64 资源。客户只需要 1 个文件部署。&lt;br /&gt;
Plugin output is a single `.dll` with all deps embedded as base64 resources. Customer deployment = 1 file.&lt;br /&gt;
&lt;br /&gt;
`FodyWeavers.xml` 在工程根：&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;Weavers&amp;gt;&lt;br /&gt;
  &amp;lt;Costura/&amp;gt;&lt;br /&gt;
  &amp;lt;LessokajiWeaver/&amp;gt;&lt;br /&gt;
&amp;lt;/Weavers&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
【注意】 ''Costura 缓存''可能让你看不到 FundamentalLib 升级 —— 重新构建插件后再部署，否则胖 DLL 里还是旧版 FundamentalLib。&amp;lt;br&amp;gt;&lt;br /&gt;
Costura caches dependencies in the fat DLL. After upgrading FundamentalLib, '''rebuild plugins''' before deploying.&lt;br /&gt;
&lt;br /&gt;
== 3. 版本与助记词 / Version + mnemonic ==&lt;br /&gt;
每次修改插件，AssemblyInformationalVersion 加 ''单词助记词''：&lt;br /&gt;
Every plugin modification adds a single mnemonic word to AssemblyInformationalVersion:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;xml&amp;quot;&amp;gt;&lt;br /&gt;
&amp;lt;AssemblyInformationalVersion&amp;gt;1.4.0+kindling&amp;lt;/AssemblyInformationalVersion&amp;gt;&lt;br /&gt;
&amp;lt;!-- 下次改动 / next change --&amp;gt;&lt;br /&gt;
&amp;lt;AssemblyInformationalVersion&amp;gt;1.4.1+lantern&amp;lt;/AssemblyInformationalVersion&amp;gt;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
目的：现场调试时 ''肉眼区分''两个数字看起来一样的二进制。&lt;br /&gt;
Purpose: visually disambiguate two binaries with the same number in the field.&lt;br /&gt;
&lt;br /&gt;
或者用 `[ReplaceWithCompileInfo]` —— LessokajiWeaver 在编译期注入时间戳 + git 哈希到 static string 字段。&lt;br /&gt;
Alternative: `[ReplaceWithCompileInfo]` — LessokajiWeaver injects timestamp + git hash at compile time.&lt;br /&gt;
&lt;br /&gt;
== 4. 部署 / Deployment ==&lt;br /&gt;
=== Medulla 端 / Medulla-side ===&lt;br /&gt;
DLL 放到 `medulla/plugins/&amp;lt;vendor&amp;gt;/&amp;lt;plugin&amp;gt;.dll`，`startup.iocmd` 加：&lt;br /&gt;
Drop the DLL into `medulla/plugins/&amp;lt;vendor&amp;gt;/`, add to `startup.iocmd`:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;text&amp;quot;&amp;gt;&lt;br /&gt;
foo = io load plugins/&amp;lt;vendor&amp;gt;/&amp;lt;plugin&amp;gt;.dll&lt;br /&gt;
foo Init                    # if your plugin has an Init method&lt;br /&gt;
foo Start &amp;lt;args&amp;gt;            # invoke whatever it needs&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
startup.iocmd 语法见 [[Special:MyLanguage/startup.iocmd脚本语法|startup.iocmd脚本语法]]。&lt;br /&gt;
&lt;br /&gt;
=== SimpleComposer 端 / SimpleComposer-side ===&lt;br /&gt;
DLL 放到 `simplecomposer/plugins/&amp;lt;plugin&amp;gt;.dll`。SimpleComposer 启动时（`D:\src\Simple\SimpleComposer\Program.cs:107-162`）自动扫所有 DLL，按 `[CarType]` / `HeuristicsContainer` / `CustomOperationsBeforeLoading.Set` / `BusinessLogic` 类型分类注册。&lt;br /&gt;
&lt;br /&gt;
Drop into `simplecomposer/plugins/`. SimpleComposer auto-scans on boot.&lt;br /&gt;
&lt;br /&gt;
== 5. 加载生命周期 / Load lifecycle ==&lt;br /&gt;
&lt;br /&gt;
  Medulla:&lt;br /&gt;
    io load X.dll → reflection scan → instantiate MainIOObject&lt;br /&gt;
       ↓ (your ctor runs; no hardware contact)&lt;br /&gt;
    cart Init → connect hardware → spawn LadderLogics&lt;br /&gt;
       ↓&lt;br /&gt;
    Operation(0), Operation(1), ...&lt;br /&gt;
&lt;br /&gt;
  SimpleComposer:&lt;br /&gt;
    Program.cs startup&lt;br /&gt;
       → load every plugins/*.dll&lt;br /&gt;
       → scan for [CarType] / HeuristicsContainer / BusinessLogic / CustomOps&lt;br /&gt;
       → register&lt;br /&gt;
       → MyAsmHelper.Init() invoked&lt;br /&gt;
&lt;br /&gt;
【注意】 Medulla 加载器 ''不调'' `Init()`。你需要 startup.iocmd 显式调用 `cart Init`。&amp;lt;br&amp;gt;&lt;br /&gt;
The Medulla loader does NOT call `Init()`. You must invoke `cart Init` from startup.iocmd.&lt;br /&gt;
&lt;br /&gt;
== 6. 一切重启 vs 热替换 / Restart vs hot swap ==&lt;br /&gt;
* '''Medulla 插件''': '''必须'''停 Medulla → 替换 DLL → 启动。热替换会导致 Costura 缓存冲突 / undefined behaviour。&lt;br /&gt;
* '''SimpleComposer 插件''': 同上 —— 关 SimpleComposer → 替换 → 启动。&lt;br /&gt;
* '''Clumsy MovementDefinition''': 同 Clumsy 进程重启。&lt;br /&gt;
&lt;br /&gt;
Hot swap is not supported. Always stop-replace-start.&lt;br /&gt;
&lt;br /&gt;
== 7. 跨平台 / Cross-platform ==&lt;br /&gt;
* Medulla / Detour / Clumsy / SimpleComposer 都可在 Linux 运行（.NET 6/8）。&lt;br /&gt;
* DObject 在 Linux 用文件后备（见 [[Special:MyLanguage/DObject共享内存协议|DObject 共享内存协议]]）。&lt;br /&gt;
* libVRender (CycleGUI 渲染) 已有 Linux 构建，但 Windows 是主战场。&lt;br /&gt;
&lt;br /&gt;
== 相关页面 / See also ==&lt;br /&gt;
* [[Special:MyLanguage/startup.iocmd脚本语法|startup.iocmd脚本语法]]&lt;br /&gt;
* [[Special:MyLanguage/IOObject属性参考|IOObject属性参考]]&lt;br /&gt;
* [[Special:MyLanguage/CartDefinition属性参考|CartDefinition属性参考]]&lt;br /&gt;
* [[Special:MyLanguage/LadderLogic框架|LadderLogic框架]]&lt;br /&gt;
* [[Special:MyLanguage/插件测试与发布|插件测试与发布]]&lt;br /&gt;
* [[Special:MyLanguage/Medulla软件架构|Medulla软件架构]]&lt;br /&gt;
* [[Special:MyLanguage/MDCS-plugin-helper|MDCS-plugin-helper]] — 脚手架工具&lt;br /&gt;
&lt;br /&gt;
[[Category:二次开发相关说明]]&lt;br /&gt;
[[Category:开发手册]]&lt;/div&gt;</summary>
		<author><name>Artheru</name></author>
	</entry>
</feed>