跳转至

第一个 Zig 模组

这里构建的是 examples/hello-pier-zig:一个命令、一个玩家加入事件的监听器、一个延时任务,以及一个任何模组都能用的服务和总线主题。

包结构

Text Only
1
2
3
4
build.zig
build.zig.zon
src/main.zig
manifest.json

build.zig.zon 依赖绑定。在 Pier 仓库里,示例按路径指向它;你自己的模组用 zig fetch --save 获取。

Zig
1
2
3
.dependencies = .{
    .pier = .{ .path = "../../bindings/zig" },
},

build.zig 构建一个导入了 pier 模块的动态库:

Zig
const pier_dep = b.dependency("pier", .{ .target = target, .optimize = optimize });
const lib = b.addLibrary(.{
    .linkage = .dynamic,
    .name = "hello_pier_zig",
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
        .imports = &.{.{ .name = "levilamina", .module = pier_dep.module("levilamina") }},
    }),
});
b.installArtifact(lib);

src/main.zig

Zig
const std = @import("std");
const levilamina = @import("levilamina");

const Hello = struct {
    var joins: ?levilamina.Listener = null;

    pub fn enable(ctx: *levilamina.Context) !void {
        ctx.info("enabled");
        joins = try levilamina.subscribe("ll::event::PlayerJoinEvent", .normal, onJoin);
        _ = try levilamina.scheduleAfter(1000, later);
    }

    pub fn disable(_: *levilamina.Context) !void {
        if (joins) |*listener| try listener.unsubscribe();
    }

    fn onJoin(ev: *const levilamina.Event) void {
        levilamina.logf(.info, "a player joined: {s}", .{ev.snbt});
    }

    fn later() void {
        levilamina.log(.info, "one second later");
    }
};

comptime {
    levilamina.exportMod(Hello, "hello-pier-zig");
}

exportMod 为这个模组类型导出 pier_main。它先完成握手,在填写 vtable 之前调用 load;宿主之后再调用 enable、disable 和 unload。 类型里声明的每一个都接收 *levilamina.Context 并返回 !void;返回的错误会连同名字记进日志,并拒绝这一步。

构建和安装

Text Only
zig build

zig-out/bin/hello_pier_zig.dll 就是模组。把它和 manifest.json 放进 plugins/hello-pier-zig/,再启动服务器。 日志会显示模组加载、启用,一秒后出现任务打印的那一行。/hellozig 在游戏里和控制台都能用。

如果模组没有加载,排错列出了各条日志的含义。