# 故障恢复

> 读日志、排除插件、上报故障。

先看载体的日志，再把插件逐个移走，直到服务端能起来。

## 日志在哪

| 载体 | 日志 | 崩溃数据 |
| --- | --- | --- |
| LeviLamina | `logs/latest.log` | `logs/crash/` —— `trace_*.log` 与 `minidump_*.dmp` |
| Endstone | `logs/latest.log`，另有轮转的 `logs/YYYY-MM-DD-N.log.gz` | `.sentry-native/` |
| 自持态 | 启动器的输出，以及服务端自己的日志 | — |

LeviLamina 下日志是共用的：服务端行与框架行落在同一个文件。Endstone 的轮转上限是 1000 个文件； LeviLamina 的在 `plugins/LeviLamina/config/Config.json` 里配。

## 框架没起来

启动序列会报告结果，载体把它写进日志而不是结束进程。找十六进制码：

| 日志里的码 | 含义 |
| --- | --- |
| `0xFFFFFFFE` | 插件管理器缺少寄宿契约入口。 |
| `0xFFFFFFFD` | 载体与插件管理器的寄宿契约版本不一致。 |

这两个是 `-2` 与 `-3` 按无符号打印的结果。它们都不是进程退出码：服务端继续运行，只是框架不在。 把不一致修掉——通常是升级做了一半——再重启。见[升级与回滚](/zh/framework/server/updating/)。

缺 .NET 10 运行时失败在更早的位置，表现也不同：运行时查找会先返回自己的错误码。

## 插件没装上

插件管理器会逐个报告它拒绝了哪些包、为什么。常见原因：

- **目录名与清单 `name` 不一致。** 两者必须相等。
- **声明的依赖不在。** 插件被跳过，不会半装载。
- **`api_version` 与这条框架线不兼容。**
- **没有加载器认领这个包。** 源码插件需要对应的加载器包；父级态下，从别的服务器搬来的包跑不起来， 多半是这个原因。

## 排除插件

服务端起不来又不知道是哪个插件时，先把它们全部移走：

1. 停服。
2. 把 `plugins/` 下的插件目录移走，但把基础设施留下：
   - `plugins/hosihikari/` 每次都留——那是框架本身；
   - LeviLamina 下 `plugins/LeviLamina/` 也要留——那是父级加载器，就装在这个目录里；
   - Endstone 的父级不在 `plugins/` 下，不用另留。
3. 启动。能起来，说明框架没问题，问题在某个包里。
4. 分两半搬回来，每轮之间重启，直到服务端失败。最后那一批里有问题插件。
5. 把它留在外面，然后上报。

把父级加载器连同插件一起移走，什么也证明不了：没有父级，就没有东西去激活框架，失败原因跟插件无关。 每个载体都适用。自持态目前没有运行期启停，每轮都必须重启，步骤一样。

## 插件卸不掉

卸载是经过验证的：框架让加载器确认程序集装载上下文已被回收，默认最多等 30 秒。超时按卸载失败记录， 插件留在 `Detached` 槽里——不会被当成已经消失。常见原因是静态状态、还在跑的线程，以及插件在 `OnUnload` 里没清掉的引用。见[插件包与清单](/zh/framework/develop/plugin-package/)。

## 上报要带什么

- 框架、加载器与插件的版本（`lip list`）。
- 载体与 BDS 版本。
- 失败前后的日志行，取自 `logs/latest.log`。
- 上面那些路径里的崩溃文件。
- 出问题之前改了什么——一次升级、一个新插件、一处配置。

发布前删掉服务器 IP、玩家名与世界数据。漏洞走所属仓的私有表单上报，不要开公开 issue；见该仓的安全策略。
