Skip to content
服务器插件与终端接口

第一个服务器插件 ​

本页讲清楚插件项目的搭建、最小插件类、生命周期与事件注册。内容同时覆盖两种常见开发方式:引用社区源码(基于 sc2.2network)和引用发行 DLL(插件站/发行构建)。接口成员签名一致,仅命名空间与引用方式不同,详见下方说明。

构建与目标版本

  • 社区源码构建:服务端来自 sc2.2network 源码树,命令基类 AbstractProcessCmd 位于 Game.Server 命名空间,目标框架 net10.0,使用项目引用(ProjectReference)。
  • 发行 DLL 构建:服务端来自插件站/发行包,命令基类 AbstractProcessCmd 位于 Game.Server.EssentialCmd 命名空间,目标框架 .NET 8.0,引用 Engine.dll、GameEntitySystem.dll 等发行程序集。

开发时请锁定你服务端对应的提交或发行标签,并以 接口参考 为准。

插件是什么 ​

插件是一个继承 ServerPlugin 的 C# 类库(.dll)。服务端启动时会扫描 Plugins 目录,实例化其中所有非抽象的 ServerPlugin 与 AbstractProcessCmd 子类并加载。

方式一:引用社区源码(推荐用于维护现有服) ​

目标框架 net10.0,直接引用同一源码树中的服务端项目:

xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net10.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
  </PropertyGroup>
  <ItemGroup>
    <ProjectReference Include="..\..\EngineServer\EngineServer.csproj" />
    <ProjectReference Include="..\..\EntitySystemServer\EntitySystemServer.csproj" />
    <ProjectReference Include="..\..\SurvivalcraftServer\SurvivalcraftServer.csproj" />
  </ItemGroup>
</Project>

路径要按你的项目位置调整。若使用发行 DLL 引用,也必须来自目标服务端同一构建。

最小插件类:

csharp
using Game.Server;

namespace Workshop.Example;

public sealed class HelloPlugin : ServerPlugin
{
    public override int Version => 10000;
    public override string Name => "Workshop.Hello";

    public override void Initialize()
    {
        // 只执行一次:在这里注册事件处理器。
    }

    public override void Load()
    {
        // 世界加载后读取配置和持久化数据。
    }

    public override void Save()
    {
        // 随世界保存插件数据。
    }

    public override void Update(float dt)
    {
        // 每帧调用,避免阻塞 IO 和长耗时工作。
    }
}

方式二:引用发行 DLL(插件站 / 发行构建) ​

目标框架 .NET 8.0,引用游戏目录下的发行程序集:

xml
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <OutputType>Library</OutputType>
    <AssemblyName>MyPlugin</AssemblyName>
  </PropertyGroup>
  <ItemGroup>
    <Reference Include="Engine">
      <HintPath>游戏目录\Engine.dll</HintPath>
    </Reference>
    <Reference Include="GameEntitySystem">
      <HintPath>游戏目录\GameEntitySystem.dll</HintPath>
    </Reference>
    <Reference Include="LiteNetLib">
      <HintPath>游戏目录\LiteNetLib.dll</HintPath>
    </Reference>
    <Reference Include="Newtonsoft.Json">
      <HintPath>游戏目录\Newtonsoft.Json.dll</HintPath>
    </Reference>
  </ItemGroup>
</Project>

不需要引用 Game.dll,插件通过实体系统操作游戏。引用路径中的 游戏目录 请替换为你实际的服务端目录。

最简插件(发行构建写法):

csharp
using Game.Server;

public class MyPlugin : ServerPlugin
{
    public override string Name => "我的插件";
    public override int Version => 1;
    public byte FirstLevel => 0;

    public override void Initialize()
    {
        Console.WriteLine("插件加载成功!");
    }

    public override void Load() { }
    public override void Save() { }
}

必须实现的成员 ​

成员类型说明
Namestring插件名称,显示在日志中
Versionint版本号,整数(例:10000 表示 1.0.0)
FirstLevelbyte优先级,默认填 0 即可
Initialize()方法插件加载时执行一次,用来注册事件
Load()方法世界加载后调用,读取数据/配置
Save()方法保存数据时调用(关闭或自动保存)
Update(float dt)方法每帧调用,可选重写,避免阻塞

插件的生命周期 ​

服务器启动
    ↓
Initialize() 被调用 ← 在这里注册事件监听
    ↓
Load() 被调用 ← 在这里读取配置文件
    ↓
插件运行中(Update 每帧调用)...
    ↓
Save() 被调用 ← 服务器关闭或自动保存时
    ↓
服务器关闭

服务端会扫描 Plugins 目录的 .dll,加载程序集,并实例化其中非抽象的 ServerPlugin 与 AbstractProcessCmd 子类。因此插件类必须公开、非抽象,并能由加载器正常构造。

注册事件 ​

在 Initialize() 中注册你想监听的事件:

csharp
using Game.Server;
using Game.Server.PlayerEvent;

public class MyPlugin : ServerPlugin, IPlayerEnterGameEventHandle
{
    public override string Name => "MyPlugin";
    public override int Version => 1;
    public byte FirstLevel => 0;

    public override void Initialize()
    {
        // 注册玩家进入/离开事件
        PlayerEnterGameEventManager.AddObject(this);
    }

    void IPlayerEnterGameEventHandle.PlayerEnter(PlayerData player)
    {
        Console.WriteLine($"欢迎 {player.Name}!");
    }

    void IPlayerEnterGameEventHandle.PlayerLeave(PlayerData player)
    {
        Console.WriteLine($"{player.Name} 离开了");
    }

    public override void Load() { }
    public override void Save() { }
}

大多数事件都有对应的 XxxEventManager.AddObject(this) 与 RemoveObject(this)。事件订阅建议放在 Initialize(),避免 Load() 多次执行导致重复订阅。

编译与安装 ​

powershell
dotnet build -c Release

把输出 DLL 及其独有依赖复制到测试服务端的 Plugins 目录,然后依次验证:加载、初始化、世界读取、玩家加入、save、exit 和重启恢复。不要把服务端已有的核心 DLL 再复制进插件目录。

可用事件接口(速览) ​

接口说明
IPlayerEnterGameEventHandle玩家进入/离开
IPlayerMoveHandle玩家移动
IPlayerBreakAndPlaceHandle方块破坏/放置
IPlayerInteractEventHandle玩家交互(点击、攻击等)

完整清单与签名见 接口参考 与 事件系统。

常见问题 ​

Q: 插件没加载? A: 检查 .dll 是否在 Plugins 文件夹,检查是否有报错;确认插件类是 public 且非抽象。

Q: 报错找不到类型? A: 确认引用了正确的程序集(发行 DLL 方式检查 HintPath,源码方式检查 ProjectReference)。注意命令基类命名空间:源码构建为 Game.Server,发行构建为 Game.Server.EssentialCmd。

Q: 事件没触发? A: 确认在 Initialize() 中调用了对应的 EventManager.AddObject(this)。

下一步阅读 命令系统、事件系统、玩家管理 与 接口参考。

参与共建发现错误或有建议?两种零门槛方式,无需本地环境

玩家共建文档 · 原版、插件版、联机版与插件联机版请注意区分