Add Zig bindings for the Pumpkin plugin API
The bindings under src/wit are generated from the pumpkin-plugin-wit submodule by tools/gen.zig. The canonical ABI is handled at comptime in src/abi.zig, so plugins are plain wasm32-freestanding modules and only need wasm-tools to become a component. On top of that there is a small hand written layer: plugin registration, typed event handlers, declarative commands (cmd), text components from struct literals (msg) and std.log support.
This commit is contained in:
commit
28c3e929ca
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.zig-cache/
|
||||
zig-out/
|
||||
zig-pkg/
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
[submodule "wit"]
|
||||
path = wit
|
||||
url = https://github.com/Pumpkin-MC/pumpkin-plugin-wit
|
||||
176
LICENSE-APACHE
Normal file
176
LICENSE-APACHE
Normal file
@ -0,0 +1,176 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or exemplary damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
21
LICENSE-MIT
Normal file
21
LICENSE-MIT
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2024-2026 Pumpkin Contributors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
77
README.md
Normal file
77
README.md
Normal file
@ -0,0 +1,77 @@
|
||||
# Pumpkin API for Zig
|
||||
|
||||
This package provides Zig bindings for building Pumpkin plugins using WebAssembly (Wasm) components.
|
||||
|
||||
You will need [Zig](https://ziglang.org/download/) 0.16.0 and [`wasm-tools`](https://github.com/bytecodealliance/wasm-tools) in your `PATH`.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. Setup Your Project
|
||||
|
||||
Add the package to your project:
|
||||
|
||||
```sh
|
||||
zig fetch --save git+https://github.com/Pumpkin-MC/pumpkin-api-zig
|
||||
```
|
||||
|
||||
Create a `build.zig` for your plugin:
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
const pumpkin_api = @import("pumpkin_api_zig");
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
_ = pumpkin_api.addPlugin(b, b.dependency("pumpkin_api_zig", .{}), .{
|
||||
.name = "pumpkin-plugin-example",
|
||||
.root_source_file = b.path("src/main.zig"),
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
2. Write Your Plugin
|
||||
|
||||
Create your source file (e.g. `src/main.zig`):
|
||||
|
||||
```zig
|
||||
const std = @import("std");
|
||||
const pumpkin = @import("pumpkin");
|
||||
|
||||
pub const std_options: std.Options = .{ .logFn = pumpkin.logFn };
|
||||
|
||||
const MyPlugin = struct {
|
||||
pub const metadata: pumpkin.Metadata = .{
|
||||
.name = "pumpkin-plugin-example",
|
||||
.version = "0.1.0",
|
||||
.authors = &.{"You"},
|
||||
.description = "An example plugin in Zig.",
|
||||
};
|
||||
|
||||
pub const events = .{
|
||||
.player_join_event = onJoin,
|
||||
};
|
||||
|
||||
pub fn onLoad(_: pumpkin.Context) !void {
|
||||
std.log.info("Hello from Zig!", .{});
|
||||
}
|
||||
|
||||
fn onJoin(_: pumpkin.Server, ev: *pumpkin.EventData(.player_join_event)) void {
|
||||
std.log.info("{s} joined", .{ev.player.getName()});
|
||||
}
|
||||
};
|
||||
|
||||
comptime {
|
||||
pumpkin.register(MyPlugin);
|
||||
}
|
||||
```
|
||||
|
||||
Everything the API returns, handles included, is only valid until the current callback returns. Call `keep()` on a handle to hold on to it, then release it with `deinit()` when you're done.
|
||||
|
||||
3. Build Your Plugin
|
||||
|
||||
Compile your plugin into a WebAssembly component:
|
||||
|
||||
```sh
|
||||
zig build
|
||||
```
|
||||
|
||||
This will produce `zig-out/pumpkin-plugin-example.wasm` ready to be loaded into Pumpkin.
|
||||
122
build.zig
Normal file
122
build.zig
Normal file
@ -0,0 +1,122 @@
|
||||
const std = @import("std");
|
||||
|
||||
pub const PluginOptions = struct {
|
||||
name: []const u8,
|
||||
root_source_file: std.Build.LazyPath,
|
||||
optimize: std.builtin.OptimizeMode = .ReleaseSmall,
|
||||
};
|
||||
|
||||
/// Builds a plugin and installs `<name>.wasm`, ready to be dropped into the
|
||||
/// server's `plugins` folder. Needs `wasm-tools` in PATH.
|
||||
///
|
||||
/// `api` is this package as the caller sees it:
|
||||
/// const api = b.dependency("pumpkin_api_zig", .{});
|
||||
pub fn addPlugin(b: *std.Build, api: *std.Build.Dependency, options: PluginOptions) *std.Build.Step.InstallFile {
|
||||
return addPluginFrom(b, api.builder, options);
|
||||
}
|
||||
|
||||
fn addPluginFrom(b: *std.Build, api: *std.Build, options: PluginOptions) *std.Build.Step.InstallFile {
|
||||
const target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding });
|
||||
|
||||
const pumpkin = api.createModule(.{
|
||||
.root_source_file = api.path("src/pumpkin.zig"),
|
||||
.target = target,
|
||||
.optimize = options.optimize,
|
||||
});
|
||||
|
||||
const core = b.addExecutable(.{
|
||||
.name = options.name,
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = options.root_source_file,
|
||||
.target = target,
|
||||
.optimize = options.optimize,
|
||||
.imports = &.{.{ .name = "pumpkin", .module = pumpkin }},
|
||||
}),
|
||||
});
|
||||
core.entry = .disabled;
|
||||
core.rdynamic = true;
|
||||
|
||||
// Zig has no component model target, so the core module gets its WIT
|
||||
// attached and is wrapped into a component afterwards.
|
||||
const embed = b.addSystemCommand(&.{ "wasm-tools", "component", "embed", "--world", "plugin" });
|
||||
embed.addFileArg(api.path("src/plugin.wit"));
|
||||
embed.addFileArg(core.getEmittedBin());
|
||||
embed.addArg("-o");
|
||||
const embedded = embed.addOutputFileArg("embedded.wasm");
|
||||
|
||||
const new = b.addSystemCommand(&.{ "wasm-tools", "component", "new" });
|
||||
new.addFileArg(embedded);
|
||||
new.addArg("-o");
|
||||
const component = new.addOutputFileArg(b.fmt("{s}.wasm", .{options.name}));
|
||||
|
||||
const install = b.addInstallFile(component, b.fmt("{s}.wasm", .{options.name}));
|
||||
b.getInstallStep().dependOn(&install.step);
|
||||
return install;
|
||||
}
|
||||
|
||||
pub fn build(b: *std.Build) void {
|
||||
_ = addPluginFrom(b, b, .{
|
||||
.name = "pumpkin-plugin-example",
|
||||
.root_source_file = b.path("example/src/main.zig"),
|
||||
});
|
||||
|
||||
const test_step = b.step("test", "Run unit tests");
|
||||
for ([_][]const u8{ "src/abi.zig", "tools/gen.zig" }) |path| {
|
||||
const tests = b.addTest(.{
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path(path),
|
||||
.target = b.graph.host,
|
||||
}),
|
||||
});
|
||||
test_step.dependOn(&b.addRunArtifact(tests).step);
|
||||
}
|
||||
|
||||
const check = b.addObject(.{
|
||||
.name = "check",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("src/check.zig"),
|
||||
.target = b.resolveTargetQuery(.{ .cpu_arch = .wasm32, .os_tag = .freestanding }),
|
||||
.optimize = .ReleaseSmall,
|
||||
}),
|
||||
});
|
||||
b.step("check", "Compile every generated binding").dependOn(&check.step);
|
||||
|
||||
// zig build gen: src/wit/ and src/plugin.wit from the wit submodule.
|
||||
// Directory inputs aren't hashed, so these always rerun.
|
||||
const dump = b.addSystemCommand(&.{ "wasm-tools", "component", "wit", "--json" });
|
||||
dump.addDirectoryArg(b.path("wit/v0.1"));
|
||||
dump.has_side_effects = true;
|
||||
const json = dump.captureStdOut(.{});
|
||||
|
||||
const merge = b.addSystemCommand(&.{ "wasm-tools", "component", "wit", "-o", "src/plugin.wit" });
|
||||
merge.addDirectoryArg(b.path("wit/v0.1"));
|
||||
merge.setCwd(b.path("."));
|
||||
merge.has_side_effects = true;
|
||||
|
||||
const generator = b.addExecutable(.{
|
||||
.name = "gen",
|
||||
.root_module = b.createModule(.{
|
||||
.root_source_file = b.path("tools/gen.zig"),
|
||||
.target = b.graph.host,
|
||||
}),
|
||||
});
|
||||
const generate = b.addRunArtifact(generator);
|
||||
generate.addFileArg(json);
|
||||
generate.addArg("src");
|
||||
generate.setCwd(b.path("."));
|
||||
generate.has_side_effects = true;
|
||||
|
||||
const fmt = b.addFmt(.{ .paths = &.{ "src/wit", "src/wit.zig" } });
|
||||
fmt.step.dependOn(&generate.step);
|
||||
fmt.step.dependOn(&merge.step);
|
||||
b.step("gen", "Regenerate src/wit from wit/v0.1").dependOn(&fmt.step);
|
||||
|
||||
// zig build fixtures: rewrites what the generator test compares against.
|
||||
// demo.json comes from `wasm-tools component wit tools/testdata/wit --json`.
|
||||
const fixtures = b.addRunArtifact(generator);
|
||||
fixtures.addFileArg(b.path("tools/testdata/demo.json"));
|
||||
fixtures.addArg("tools/testdata/expected");
|
||||
fixtures.setCwd(b.path("."));
|
||||
fixtures.has_side_effects = true;
|
||||
b.step("fixtures", "Update the generator test snapshots").dependOn(&fixtures.step);
|
||||
}
|
||||
13
build.zig.zon
Normal file
13
build.zig.zon
Normal file
@ -0,0 +1,13 @@
|
||||
.{
|
||||
.name = .pumpkin_api_zig,
|
||||
.version = "0.1.0",
|
||||
.fingerprint = 0x8b5633e6f3f6f585,
|
||||
.minimum_zig_version = "0.16.0",
|
||||
.paths = .{
|
||||
"build.zig",
|
||||
"build.zig.zon",
|
||||
"src",
|
||||
"LICENSE-MIT",
|
||||
"LICENSE-APACHE",
|
||||
},
|
||||
}
|
||||
70
example/src/main.zig
Normal file
70
example/src/main.zig
Normal file
@ -0,0 +1,70 @@
|
||||
const std = @import("std");
|
||||
const pumpkin = @import("pumpkin");
|
||||
const cmd = pumpkin.cmd;
|
||||
const msg = pumpkin.msg;
|
||||
|
||||
pub const std_options: std.Options = .{ .logFn = pumpkin.logFn };
|
||||
|
||||
const log = std.log.scoped(.example);
|
||||
|
||||
const Example = struct {
|
||||
pub const metadata: pumpkin.Metadata = .{
|
||||
.name = "pumpkin-plugin-example",
|
||||
.version = "0.1.0",
|
||||
.authors = &.{"You"},
|
||||
.description = "An example plugin in Zig.",
|
||||
};
|
||||
|
||||
pub const events = .{
|
||||
.player_join_event = onJoin,
|
||||
.player_chat_event = .{ onChat, pumpkin.EventOptions{ .priority = .high } },
|
||||
};
|
||||
|
||||
// /greet and /greet <targets>
|
||||
pub const commands: []const cmd.Spec = &.{.{
|
||||
.names = &.{ "greet", "hi" },
|
||||
.description = "Says hello.",
|
||||
.permission = "pumpkin-plugin-example:command.greet",
|
||||
.run = greetSender,
|
||||
.then = &.{
|
||||
.argument("targets", .players, .{ .run = greetTargets }),
|
||||
},
|
||||
}};
|
||||
|
||||
pub fn onLoad(_: pumpkin.Context) !void {
|
||||
log.info("Hello from Zig!", .{});
|
||||
}
|
||||
|
||||
fn onJoin(_: pumpkin.Server, ev: *pumpkin.EventData(.player_join_event)) void {
|
||||
log.info("{s} joined", .{ev.player.getName()});
|
||||
ev.join_message = msg.build(&.{
|
||||
.{ .text = "+ ", .color = .green, .bold = true },
|
||||
.{ .text = ev.player.getName(), .color = .yellow },
|
||||
});
|
||||
}
|
||||
|
||||
fn onChat(_: pumpkin.Server, ev: *pumpkin.EventData(.player_chat_event)) void {
|
||||
if (std.mem.indexOf(u8, ev.message, "spoiler") != null) ev.cancelled = true;
|
||||
}
|
||||
|
||||
fn greetSender(sender: cmd.Sender, _: pumpkin.Server, _: cmd.Args) cmd.Result {
|
||||
sender.sendMessage(msg.build(&.{
|
||||
.{ .text = "Hello from Zig! ", .color = .gold },
|
||||
.{ .text = "[again]", .color = .gray, .click = .{ .run_command = "/greet" }, .hover = "Runs /greet" },
|
||||
}));
|
||||
return cmd.ok(1);
|
||||
}
|
||||
|
||||
fn greetTargets(sender: cmd.Sender, _: pumpkin.Server, args: cmd.Args) cmd.Result {
|
||||
const targets = cmd.get(args, "targets", .players) orelse return cmd.fail("nobody to greet");
|
||||
for (targets) |target| {
|
||||
target.sendSystemMessage(msg.fmt(.aqua, "{s} says hello", .{sender.getName()}), false);
|
||||
}
|
||||
sender.sendMessage(msg.fmt(null, "Greeted {d} player(s).", .{targets.len}));
|
||||
return cmd.ok(@intCast(targets.len));
|
||||
}
|
||||
};
|
||||
|
||||
comptime {
|
||||
pumpkin.register(Example);
|
||||
}
|
||||
687
src/abi.zig
Normal file
687
src/abi.zig
Normal file
@ -0,0 +1,687 @@
|
||||
//! Component model canonical ABI, driven by Zig types at comptime.
|
||||
//!
|
||||
//! WIT types map to Zig like this:
|
||||
//! string, list<T> []const u8, []const T
|
||||
//! record, tuple struct, tuple
|
||||
//! variant, result union(enum)
|
||||
//! option<T> ?T
|
||||
//! enum enum(uN)
|
||||
//! flags packed struct(uN) of bools
|
||||
//! own<R> non-exhaustive enum(u32)
|
||||
//! borrow<R> Borrowed(R), parameters only
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
|
||||
pub fn Result(comptime T: type, comptime E: type) type {
|
||||
return union(enum) { ok: T, err: E };
|
||||
}
|
||||
|
||||
const is_wasm = builtin.cpu.arch == .wasm32;
|
||||
const backing = if (is_wasm) std.heap.wasm_allocator else std.heap.page_allocator;
|
||||
|
||||
var call_arena: std.heap.ArenaAllocator = .init(backing);
|
||||
|
||||
/// Everything the host hands us lives here and is gone once the current export returns.
|
||||
pub fn arena() std.mem.Allocator {
|
||||
return call_arena.allocator();
|
||||
}
|
||||
|
||||
const DropFn = *const fn (i32) callconv(.c) void;
|
||||
const Tracked = struct { handle: u32, drop: DropFn };
|
||||
|
||||
/// Owned handles received during the current export, newest last.
|
||||
var tracked: std.ArrayList(Tracked) = .empty;
|
||||
|
||||
fn track(comptime T: type, handle: T) void {
|
||||
tracked.append(backing, .{ .handle = @intFromEnum(handle), .drop = T.resource_drop }) catch @panic("OOM");
|
||||
}
|
||||
|
||||
fn untrack(comptime T: type, handle: T) void {
|
||||
var i = tracked.items.len;
|
||||
while (i > 0) {
|
||||
i -= 1;
|
||||
const item = tracked.items[i];
|
||||
if (item.handle == @intFromEnum(handle) and item.drop == T.resource_drop) {
|
||||
_ = tracked.orderedRemove(i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Takes a handle out of the per-call cleanup so it can be stored across calls.
|
||||
/// From then on it has to be released with `deinit`.
|
||||
pub fn keep(comptime T: type, handle: T) void {
|
||||
untrack(T, handle);
|
||||
}
|
||||
|
||||
pub fn drop(comptime T: type, handle: T) void {
|
||||
untrack(T, handle);
|
||||
T.resource_drop(@bitCast(@intFromEnum(handle)));
|
||||
}
|
||||
|
||||
/// A handle that is only lent to the callee. Plain handles are given away when lowered.
|
||||
pub fn Borrowed(comptime T: type) type {
|
||||
return struct {
|
||||
handle: T,
|
||||
|
||||
pub const wit_borrowed = {};
|
||||
};
|
||||
}
|
||||
|
||||
pub fn borrow(handle: anytype) Borrowed(@TypeOf(handle)) {
|
||||
return .{ .handle = handle };
|
||||
}
|
||||
|
||||
fn isBorrowed(comptime T: type) bool {
|
||||
return @typeInfo(T) == .@"struct" and @hasDecl(T, "wit_borrowed");
|
||||
}
|
||||
|
||||
pub const Stats = struct {
|
||||
/// Size of the linear memory. Wasm memory never shrinks, so this is the
|
||||
/// number to watch for leaks.
|
||||
memory_bytes: usize,
|
||||
/// What the per-call arena holds on to between calls.
|
||||
arena_bytes: usize,
|
||||
/// Handles that will be released when the current call ends.
|
||||
tracked_handles: usize,
|
||||
};
|
||||
|
||||
pub fn stats() Stats {
|
||||
return .{
|
||||
.memory_bytes = if (is_wasm) @wasmMemorySize(0) * std.wasm.page_size else 0,
|
||||
.arena_bytes = call_arena.queryCapacity(),
|
||||
.tracked_handles = tracked.items.len,
|
||||
};
|
||||
}
|
||||
|
||||
/// Drops the handles nobody kept. This calls into the host, which is not
|
||||
/// allowed from a post-return function, so it can't be left to `endCall`.
|
||||
fn releaseHandles() void {
|
||||
while (tracked.pop()) |item| item.drop(@bitCast(item.handle));
|
||||
}
|
||||
|
||||
/// Resets the arena. With an indirect result the host still reads from it
|
||||
/// after the export returns, those exports call this from `cabi_post_*`.
|
||||
pub fn endCall() void {
|
||||
releaseHandles();
|
||||
_ = call_arena.reset(.retain_capacity);
|
||||
}
|
||||
|
||||
fn cabiRealloc(old: ?[*]u8, old_len: usize, alignment: usize, new_len: usize) callconv(.c) ?[*]u8 {
|
||||
const a: std.mem.Alignment = .fromByteUnits(alignment);
|
||||
const new = arena().rawAlloc(new_len, a, @returnAddress()) orelse @panic("OOM");
|
||||
if (old) |p| @memcpy(new[0..old_len], p[0..old_len]);
|
||||
return new;
|
||||
}
|
||||
|
||||
comptime {
|
||||
if (is_wasm) @export(&cabiRealloc, .{ .name = "cabi_realloc" });
|
||||
}
|
||||
|
||||
const Core = enum { i32, i64, f32, f64 };
|
||||
|
||||
fn CoreType(comptime c: Core) type {
|
||||
return switch (c) {
|
||||
.i32 => i32,
|
||||
.i64 => i64,
|
||||
.f32 => f32,
|
||||
.f64 => f64,
|
||||
};
|
||||
}
|
||||
|
||||
const max_flat_params = 16;
|
||||
|
||||
// The event variant alone has a few hundred cases.
|
||||
const branch_quota = 10_000_000;
|
||||
|
||||
fn isHandle(comptime T: type) bool {
|
||||
return @typeInfo(T) == .@"enum" and !@typeInfo(T).@"enum".is_exhaustive;
|
||||
}
|
||||
|
||||
fn Discriminant(comptime cases: usize) type {
|
||||
if (cases <= 1 << 8) return u8;
|
||||
if (cases <= 1 << 16) return u16;
|
||||
return u32;
|
||||
}
|
||||
|
||||
fn caseCount(comptime T: type) comptime_int {
|
||||
return switch (@typeInfo(T)) {
|
||||
.optional => 2,
|
||||
.@"union" => |u| u.fields.len,
|
||||
.@"enum" => |e| e.fields.len,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
/// Whether a []const T already has the canonical layout in memory.
|
||||
fn isPlain(comptime T: type) bool {
|
||||
return switch (@typeInfo(T)) {
|
||||
.int => |i| i.bits == 8 or i.bits == 16 or i.bits == 32 or i.bits == 64,
|
||||
.float => true,
|
||||
else => false,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn alignOf(comptime T: type) comptime_int {
|
||||
@setEvalBranchQuota(branch_quota);
|
||||
return switch (@typeInfo(T)) {
|
||||
.void => 1,
|
||||
.bool => 1,
|
||||
.int => |i| if (i.bits == 21) 4 else @divExact(i.bits, 8),
|
||||
.float => |f| @divExact(f.bits, 8),
|
||||
.pointer => 4,
|
||||
.@"enum" => if (isHandle(T)) 4 else @sizeOf(Discriminant(caseCount(T))),
|
||||
.optional => |o| @max(1, alignOf(o.child)),
|
||||
.@"union" => |u| blk: {
|
||||
var a = @sizeOf(Discriminant(u.fields.len));
|
||||
for (u.fields) |f| a = @max(a, alignOf(f.type));
|
||||
break :blk a;
|
||||
},
|
||||
.@"struct" => |s| blk: {
|
||||
if (s.layout == .@"packed") break :blk @sizeOf(s.backing_integer.?);
|
||||
if (isBorrowed(T)) break :blk 4;
|
||||
var a = 1;
|
||||
for (s.fields) |f| a = @max(a, alignOf(f.type));
|
||||
break :blk a;
|
||||
},
|
||||
else => @compileError("no canonical ABI for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
|
||||
fn alignUp(comptime n: comptime_int, comptime a: comptime_int) comptime_int {
|
||||
return @divFloor(n + a - 1, a) * a;
|
||||
}
|
||||
|
||||
pub fn sizeOf(comptime T: type) comptime_int {
|
||||
@setEvalBranchQuota(branch_quota);
|
||||
return switch (@typeInfo(T)) {
|
||||
.void => 0,
|
||||
.bool => 1,
|
||||
.int => |i| if (i.bits == 21) 4 else @divExact(i.bits, 8),
|
||||
.float => |f| @divExact(f.bits, 8),
|
||||
.pointer => 8,
|
||||
.@"enum" => if (isHandle(T)) 4 else @sizeOf(Discriminant(caseCount(T))),
|
||||
.optional => |o| alignUp(payloadOffset(T) + sizeOf(o.child), alignOf(T)),
|
||||
.@"union" => |u| blk: {
|
||||
var max = 0;
|
||||
for (u.fields) |f| max = @max(max, sizeOf(f.type));
|
||||
break :blk alignUp(payloadOffset(T) + max, alignOf(T));
|
||||
},
|
||||
.@"struct" => |s| blk: {
|
||||
if (s.layout == .@"packed") break :blk @sizeOf(s.backing_integer.?);
|
||||
if (isBorrowed(T)) break :blk 4;
|
||||
var n = 0;
|
||||
for (s.fields) |f| n = alignUp(n, alignOf(f.type)) + sizeOf(f.type);
|
||||
break :blk alignUp(n, alignOf(T));
|
||||
},
|
||||
else => @compileError("no canonical ABI for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
|
||||
fn payloadOffset(comptime T: type) comptime_int {
|
||||
@setEvalBranchQuota(branch_quota);
|
||||
const disc = @sizeOf(Discriminant(caseCount(T)));
|
||||
const payload_align = switch (@typeInfo(T)) {
|
||||
.optional => |o| alignOf(o.child),
|
||||
.@"union" => alignOf(T),
|
||||
else => unreachable,
|
||||
};
|
||||
return alignUp(disc, payload_align);
|
||||
}
|
||||
|
||||
fn fieldOffset(comptime T: type, comptime index: usize) comptime_int {
|
||||
@setEvalBranchQuota(branch_quota);
|
||||
var n = 0;
|
||||
for (@typeInfo(T).@"struct".fields, 0..) |f, i| {
|
||||
n = alignUp(n, alignOf(f.type));
|
||||
if (i == index) return n;
|
||||
n += sizeOf(f.type);
|
||||
}
|
||||
unreachable;
|
||||
}
|
||||
|
||||
fn join(a: Core, b: Core) Core {
|
||||
if (a == b) return a;
|
||||
if ((a == .i32 and b == .f32) or (a == .f32 and b == .i32)) return .i32;
|
||||
return .i64;
|
||||
}
|
||||
|
||||
fn flattenCases(comptime payloads: []const type) []const Core {
|
||||
var out: []const Core = &.{};
|
||||
for (payloads) |P| {
|
||||
const flat = flatten(P);
|
||||
var merged: []const Core = &.{};
|
||||
for (0..@max(out.len, flat.len)) |i| {
|
||||
const c = if (i >= out.len) flat[i] else if (i >= flat.len) out[i] else join(out[i], flat[i]);
|
||||
merged = merged ++ [1]Core{c};
|
||||
}
|
||||
out = merged;
|
||||
}
|
||||
return [1]Core{.i32} ++ out;
|
||||
}
|
||||
|
||||
pub fn flatten(comptime T: type) []const Core {
|
||||
return comptime blk: {
|
||||
@setEvalBranchQuota(branch_quota);
|
||||
break :blk flattenType(T);
|
||||
};
|
||||
}
|
||||
|
||||
fn flattenType(comptime T: type) []const Core {
|
||||
return switch (@typeInfo(T)) {
|
||||
.void => &.{},
|
||||
.bool, .@"enum" => &.{.i32},
|
||||
.int => |i| if (i.bits == 64) &.{.i64} else &.{.i32},
|
||||
.float => |f| if (f.bits == 64) &.{.f64} else &.{.f32},
|
||||
.pointer => &.{ .i32, .i32 },
|
||||
.optional => |o| flattenCases(&.{ void, o.child }),
|
||||
.@"union" => |u| blk: {
|
||||
var payloads: []const type = &.{};
|
||||
for (u.fields) |f| payloads = payloads ++ [1]type{f.type};
|
||||
break :blk flattenCases(payloads);
|
||||
},
|
||||
.@"struct" => |s| blk: {
|
||||
if (s.layout == .@"packed" or isBorrowed(T)) break :blk &.{.i32};
|
||||
var out: []const Core = &.{};
|
||||
for (s.fields) |f| out = out ++ flatten(f.type);
|
||||
break :blk out;
|
||||
},
|
||||
else => @compileError("no canonical ABI for " ++ @typeName(T)),
|
||||
};
|
||||
}
|
||||
|
||||
// Flat values travel as raw bits in u64 slots, which makes the variant
|
||||
// payload joins (f32 in an i32 slot, i32 in an i64 slot, ...) free.
|
||||
|
||||
fn lowerSlice(comptime T: type, items: []const T, slots: []u64) void {
|
||||
slots[1] = items.len;
|
||||
if (items.len == 0) {
|
||||
slots[0] = 0;
|
||||
return;
|
||||
}
|
||||
if (comptime isPlain(T)) {
|
||||
slots[0] = @intFromPtr(items.ptr);
|
||||
return;
|
||||
}
|
||||
const a: std.mem.Alignment = comptime .fromByteUnits(alignOf(T));
|
||||
const buf = arena().alignedAlloc(u8, a, items.len * sizeOf(T)) catch @panic("OOM");
|
||||
for (items, 0..) |item, i| store(T, item, buf.ptr + i * sizeOf(T));
|
||||
slots[0] = @intFromPtr(buf.ptr);
|
||||
}
|
||||
|
||||
fn liftSlice(comptime T: type, addr: u64, len: u64) []const T {
|
||||
if (len == 0) return &.{};
|
||||
const n: usize = @intCast(len);
|
||||
if (comptime isPlain(T)) {
|
||||
const ptr: [*]const T = @ptrFromInt(@as(usize, @intCast(addr)));
|
||||
return ptr[0..n];
|
||||
}
|
||||
const base: [*]const u8 = @ptrFromInt(@as(usize, @intCast(addr)));
|
||||
const out = arena().alloc(T, n) catch @panic("OOM");
|
||||
for (out, 0..) |*item, i| item.* = load(T, base + i * sizeOf(T));
|
||||
return out;
|
||||
}
|
||||
|
||||
pub fn lowerFlat(comptime T: type, value: T, slots: []u64) void {
|
||||
switch (@typeInfo(T)) {
|
||||
.void => {},
|
||||
.bool => slots[0] = @intFromBool(value),
|
||||
.int => |i| {
|
||||
if (i.bits == 64) {
|
||||
slots[0] = @bitCast(value);
|
||||
} else if (i.signedness == .signed) {
|
||||
slots[0] = @as(u32, @bitCast(@as(i32, value)));
|
||||
} else {
|
||||
slots[0] = value;
|
||||
}
|
||||
},
|
||||
.float => |f| slots[0] = if (f.bits == 64) @bitCast(value) else @as(u32, @bitCast(value)),
|
||||
.pointer => |p| lowerSlice(p.child, value, slots),
|
||||
.@"enum" => {
|
||||
if (comptime isHandle(T)) untrack(T, value);
|
||||
slots[0] = @intFromEnum(value);
|
||||
},
|
||||
.optional => |o| {
|
||||
@memset(slots[0..comptime flatten(T).len], 0);
|
||||
if (value) |v| {
|
||||
slots[0] = 1;
|
||||
lowerFlat(o.child, v, slots[1..]);
|
||||
}
|
||||
},
|
||||
.@"union" => |u| {
|
||||
@memset(slots[0..comptime flatten(T).len], 0);
|
||||
switch (value) {
|
||||
inline else => |v, tag| {
|
||||
slots[0] = @intFromEnum(tag);
|
||||
lowerFlat(u.fields[@intFromEnum(tag)].type, v, slots[1..]);
|
||||
},
|
||||
}
|
||||
},
|
||||
.@"struct" => |s| {
|
||||
if (s.layout == .@"packed") {
|
||||
slots[0] = @as(s.backing_integer.?, @bitCast(value));
|
||||
return;
|
||||
}
|
||||
if (comptime isBorrowed(T)) {
|
||||
slots[0] = @intFromEnum(value.handle);
|
||||
return;
|
||||
}
|
||||
var at: usize = 0;
|
||||
inline for (s.fields) |f| {
|
||||
lowerFlat(f.type, @field(value, f.name), slots[at..]);
|
||||
at += comptime flatten(f.type).len;
|
||||
}
|
||||
},
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn liftFlat(comptime T: type, slots: []const u64) T {
|
||||
switch (@typeInfo(T)) {
|
||||
.void => return {},
|
||||
.bool => return slots[0] != 0,
|
||||
.int => |i| {
|
||||
if (i.bits == 64) return @bitCast(slots[0]);
|
||||
const word: u32 = @truncate(slots[0]);
|
||||
if (i.signedness == .signed) return @truncate(@as(i32, @bitCast(word)));
|
||||
return @truncate(word);
|
||||
},
|
||||
.float => |f| {
|
||||
if (f.bits == 64) return @bitCast(slots[0]);
|
||||
return @bitCast(@as(u32, @truncate(slots[0])));
|
||||
},
|
||||
.pointer => |p| return liftSlice(p.child, slots[0], slots[1]),
|
||||
.@"enum" => {
|
||||
const value: T = @enumFromInt(slots[0]);
|
||||
if (comptime isHandle(T)) track(T, value);
|
||||
return value;
|
||||
},
|
||||
.optional => |o| return if (slots[0] == 0) null else liftFlat(o.child, slots[1..]),
|
||||
.@"union" => |u| {
|
||||
inline for (u.fields, 0..) |f, i| {
|
||||
if (slots[0] == i) return @unionInit(T, f.name, liftFlat(f.type, slots[1..]));
|
||||
}
|
||||
unreachable;
|
||||
},
|
||||
.@"struct" => |s| {
|
||||
if (s.layout == .@"packed") return @bitCast(@as(s.backing_integer.?, @truncate(slots[0])));
|
||||
if (comptime isBorrowed(T)) @compileError("borrowed handles can only be passed to imports");
|
||||
var out: T = undefined;
|
||||
var at: usize = 0;
|
||||
inline for (s.fields) |f| {
|
||||
@field(out, f.name) = liftFlat(f.type, slots[at..]);
|
||||
at += comptime flatten(f.type).len;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn put(comptime Int: type, ptr: [*]u8, value: Int) void {
|
||||
std.mem.writeInt(Int, ptr[0..@sizeOf(Int)], value, .little);
|
||||
}
|
||||
|
||||
fn get(comptime Int: type, ptr: [*]const u8) Int {
|
||||
return std.mem.readInt(Int, ptr[0..@sizeOf(Int)], .little);
|
||||
}
|
||||
|
||||
pub fn store(comptime T: type, value: T, ptr: [*]u8) void {
|
||||
switch (@typeInfo(T)) {
|
||||
.void => {},
|
||||
.bool => ptr[0] = @intFromBool(value),
|
||||
.int => |i| if (i.bits == 21) put(u32, ptr, value) else put(T, ptr, value),
|
||||
.float => |f| put(std.meta.Int(.unsigned, f.bits), ptr, @bitCast(value)),
|
||||
.pointer => |p| {
|
||||
var slots: [2]u64 = undefined;
|
||||
lowerSlice(p.child, value, &slots);
|
||||
put(u32, ptr, @intCast(slots[0]));
|
||||
put(u32, ptr + 4, @intCast(slots[1]));
|
||||
},
|
||||
.@"enum" => {
|
||||
if (comptime isHandle(T)) {
|
||||
untrack(T, value);
|
||||
return put(u32, ptr, @intFromEnum(value));
|
||||
}
|
||||
put(Discriminant(caseCount(T)), ptr, @intFromEnum(value));
|
||||
},
|
||||
.optional => |o| {
|
||||
ptr[0] = @intFromBool(value != null);
|
||||
if (value) |v| store(o.child, v, ptr + payloadOffset(T));
|
||||
},
|
||||
.@"union" => |u| switch (value) {
|
||||
inline else => |v, tag| {
|
||||
put(Discriminant(u.fields.len), ptr, @intFromEnum(tag));
|
||||
store(u.fields[@intFromEnum(tag)].type, v, ptr + payloadOffset(T));
|
||||
},
|
||||
},
|
||||
.@"struct" => |s| {
|
||||
if (s.layout == .@"packed") return put(s.backing_integer.?, ptr, @bitCast(value));
|
||||
if (comptime isBorrowed(T)) return put(u32, ptr, @intFromEnum(value.handle));
|
||||
inline for (s.fields, 0..) |f, i| {
|
||||
store(f.type, @field(value, f.name), ptr + fieldOffset(T, i));
|
||||
}
|
||||
},
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(comptime T: type, ptr: [*]const u8) T {
|
||||
switch (@typeInfo(T)) {
|
||||
.void => return {},
|
||||
.bool => return ptr[0] != 0,
|
||||
.int => |i| return if (i.bits == 21) @truncate(get(u32, ptr)) else get(T, ptr),
|
||||
.float => |f| return @bitCast(get(std.meta.Int(.unsigned, f.bits), ptr)),
|
||||
.pointer => |p| return liftSlice(p.child, get(u32, ptr), get(u32, ptr + 4)),
|
||||
.@"enum" => {
|
||||
if (comptime isHandle(T)) {
|
||||
const value: T = @enumFromInt(get(u32, ptr));
|
||||
track(T, value);
|
||||
return value;
|
||||
}
|
||||
return @enumFromInt(get(Discriminant(caseCount(T)), ptr));
|
||||
},
|
||||
.optional => |o| return if (ptr[0] == 0) null else load(o.child, ptr + payloadOffset(T)),
|
||||
.@"union" => |u| {
|
||||
const tag = get(Discriminant(u.fields.len), ptr);
|
||||
inline for (u.fields, 0..) |f, i| {
|
||||
if (tag == i) return @unionInit(T, f.name, load(f.type, ptr + payloadOffset(T)));
|
||||
}
|
||||
unreachable;
|
||||
},
|
||||
.@"struct" => |s| {
|
||||
if (s.layout == .@"packed") return @bitCast(get(s.backing_integer.?, ptr));
|
||||
var out: T = undefined;
|
||||
inline for (s.fields, 0..) |f, i| {
|
||||
@field(out, f.name) = load(f.type, ptr + fieldOffset(T, i));
|
||||
}
|
||||
return out;
|
||||
},
|
||||
else => comptime unreachable,
|
||||
}
|
||||
}
|
||||
|
||||
fn toCore(comptime C: type, slot: u64) C {
|
||||
return switch (C) {
|
||||
i32 => @bitCast(@as(u32, @truncate(slot))),
|
||||
i64 => @bitCast(slot),
|
||||
f32 => @bitCast(@as(u32, @truncate(slot))),
|
||||
f64 => @bitCast(slot),
|
||||
else => comptime unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn fromCore(value: anytype) u64 {
|
||||
return switch (@TypeOf(value)) {
|
||||
i32, f32 => @as(u32, @bitCast(value)),
|
||||
i64, f64 => @bitCast(value),
|
||||
else => comptime unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
fn scratch(comptime T: type) [*]u8 {
|
||||
const a: std.mem.Alignment = comptime .fromByteUnits(alignOf(T));
|
||||
const buf = arena().alignedAlloc(u8, a, @max(sizeOf(T), 1)) catch @panic("OOM");
|
||||
return buf.ptr;
|
||||
}
|
||||
|
||||
/// The generator spells out raw signatures on its own, make sure it agrees with us.
|
||||
fn checkSignature(comptime Func: type, comptime Args: type, comptime Ret: type) void {
|
||||
const info = @typeInfo(Func).@"fn";
|
||||
const args = flatten(Args);
|
||||
const ret = flatten(Ret);
|
||||
|
||||
var expected: []const Core = if (args.len > max_flat_params) &.{.i32} else args;
|
||||
if (ret.len > 1) expected = expected ++ [1]Core{.i32};
|
||||
const expected_ret = if (ret.len == 1) CoreType(ret[0]) else void;
|
||||
|
||||
var ok = info.params.len == expected.len and info.return_type.? == expected_ret;
|
||||
if (ok) for (info.params, expected) |p, e| {
|
||||
if (p.type.? != CoreType(e)) ok = false;
|
||||
};
|
||||
if (!ok) @compileError("raw signature " ++ @typeName(Func) ++ " does not match " ++ @typeName(Args) ++ " -> " ++ @typeName(Ret));
|
||||
}
|
||||
|
||||
/// Calls an imported function. `func` is the raw extern with the flattened signature.
|
||||
pub fn call(func: anytype, comptime Ret: type, args: anytype) Ret {
|
||||
const Args = @TypeOf(args);
|
||||
const Raw = std.meta.ArgsTuple(@TypeOf(func));
|
||||
const n = comptime flatten(Args).len;
|
||||
const ret_flat = comptime flatten(Ret).len;
|
||||
|
||||
var slots: [@max(n, 1)]u64 = undefined;
|
||||
var raw: Raw = undefined;
|
||||
const used = comptime if (n > max_flat_params) 1 else n;
|
||||
comptime checkSignature(@TypeOf(func), Args, Ret);
|
||||
if (n > max_flat_params) {
|
||||
const buf = scratch(Args);
|
||||
store(Args, args, buf);
|
||||
raw[0] = @bitCast(@as(u32, @intFromPtr(buf)));
|
||||
} else {
|
||||
lowerFlat(Args, args, &slots);
|
||||
inline for (0..n) |i| raw[i] = toCore(@TypeOf(raw[i]), slots[i]);
|
||||
}
|
||||
|
||||
if (ret_flat > 1) {
|
||||
const out = scratch(Ret);
|
||||
raw[used] = @bitCast(@as(u32, @intFromPtr(out)));
|
||||
@call(.auto, func, raw);
|
||||
return load(Ret, out);
|
||||
}
|
||||
if (ret_flat == 0) {
|
||||
@call(.auto, func, raw);
|
||||
return liftFlat(Ret, &.{});
|
||||
}
|
||||
const slot = fromCore(@call(.auto, func, raw));
|
||||
return liftFlat(Ret, &.{slot});
|
||||
}
|
||||
|
||||
/// Turns the raw parameters of an export back into `Args`.
|
||||
pub fn liftArgs(comptime Args: type, raw: anytype) Args {
|
||||
const n = comptime flatten(Args).len;
|
||||
if (n > max_flat_params) {
|
||||
const ptr: [*]const u8 = @ptrFromInt(@as(u32, @bitCast(raw[0])));
|
||||
return load(Args, ptr);
|
||||
}
|
||||
var slots: [@max(n, 1)]u64 = undefined;
|
||||
inline for (0..n) |i| slots[i] = fromCore(raw[i]);
|
||||
return liftFlat(Args, &slots);
|
||||
}
|
||||
|
||||
pub fn RawReturn(comptime Ret: type) type {
|
||||
const flat = flatten(Ret);
|
||||
if (flat.len == 0) return void;
|
||||
if (flat.len == 1) return CoreType(flat[0]);
|
||||
return i32;
|
||||
}
|
||||
|
||||
/// Lowers the return value of an export, the last thing an export does.
|
||||
/// Handles that are part of `value` go back to the host, the rest is released.
|
||||
pub fn lowerReturn(comptime Ret: type, value: Ret) RawReturn(Ret) {
|
||||
defer releaseHandles();
|
||||
const flat = comptime flatten(Ret);
|
||||
if (flat.len == 0) return;
|
||||
if (flat.len == 1) {
|
||||
var slots: [1]u64 = undefined;
|
||||
lowerFlat(Ret, value, &slots);
|
||||
return toCore(CoreType(flat[0]), slots[0]);
|
||||
}
|
||||
const out = scratch(Ret);
|
||||
store(Ret, value, out);
|
||||
return @bitCast(@as(u32, @intFromPtr(out)));
|
||||
}
|
||||
|
||||
test "layout" {
|
||||
const Pos = struct { f64, f64, f64 };
|
||||
try std.testing.expectEqual(24, sizeOf(Pos));
|
||||
try std.testing.expectEqual(8, alignOf(Pos));
|
||||
|
||||
const Rec = struct { a: u8, b: u32, c: []const u8, d: ?u16 };
|
||||
try std.testing.expectEqual(4, alignOf(Rec));
|
||||
try std.testing.expectEqual(20, sizeOf(Rec));
|
||||
|
||||
const Var = union(enum) { a, b: u64, c: []const u8 };
|
||||
try std.testing.expectEqual(8, alignOf(Var));
|
||||
try std.testing.expectEqual(16, sizeOf(Var));
|
||||
try std.testing.expectEqual(2, sizeOf(?u8));
|
||||
try std.testing.expectEqual(16, sizeOf(?f64));
|
||||
}
|
||||
|
||||
test "flatten" {
|
||||
try std.testing.expectEqualSlices(Core, &.{ .i32, .i32 }, flatten([]const u8));
|
||||
try std.testing.expectEqualSlices(Core, &.{ .i32, .f64 }, flatten(?f64));
|
||||
try std.testing.expectEqualSlices(Core, &.{ .i32, .i32 }, flatten(Result(f32, u32)));
|
||||
try std.testing.expectEqualSlices(Core, &.{ .i32, .i64, .i32 }, flatten(union(enum) { a: f64, b: []const u8, c }));
|
||||
}
|
||||
|
||||
test "flat round trip" {
|
||||
const Rec = struct { a: i8, b: ?f32, c: Result(void, u64), d: packed struct(u8) { x: bool, y: bool, _: u6 = 0 } };
|
||||
const value: Rec = .{ .a = -3, .b = 1.5, .c = .{ .err = 1 << 40 }, .d = .{ .x = false, .y = true } };
|
||||
var slots: [flatten(Rec).len]u64 = undefined;
|
||||
lowerFlat(Rec, value, &slots);
|
||||
try std.testing.expectEqual(@as(u64, 0xffff_fffd), slots[0]);
|
||||
try std.testing.expectEqualDeep(value, liftFlat(Rec, &slots));
|
||||
}
|
||||
|
||||
test "memory round trip" {
|
||||
const Rec = struct { a: u16, b: ?i64, c: union(enum) { x: f32, y: bool }, d: enum(u8) { p, q } };
|
||||
const value: Rec = .{ .a = 7, .b = -9, .c = .{ .y = true }, .d = .q };
|
||||
var buf: [sizeOf(Rec)]u8 align(8) = undefined;
|
||||
store(Rec, value, &buf);
|
||||
try std.testing.expectEqualDeep(value, load(Rec, &buf));
|
||||
}
|
||||
|
||||
test "handle tracking" {
|
||||
const Res = enum(u32) {
|
||||
_,
|
||||
|
||||
var dropped: [8]u32 = undefined;
|
||||
var count: usize = 0;
|
||||
|
||||
pub const resource_drop = &record;
|
||||
|
||||
fn record(handle: i32) callconv(.c) void {
|
||||
dropped[count] = @intCast(handle);
|
||||
count += 1;
|
||||
}
|
||||
};
|
||||
const Pair = struct { a: Res, b: ?Res };
|
||||
|
||||
var slots: [flatten(Pair).len]u64 = .{ 1, 1, 2 };
|
||||
const pair = liftFlat(Pair, &slots);
|
||||
const third = liftFlat(Res, &.{3});
|
||||
const fourth = liftFlat(Res, &.{4});
|
||||
try std.testing.expectEqual(4, tracked.items.len);
|
||||
|
||||
// Given away, lent, kept, dropped by hand. Only `a` is left for endCall.
|
||||
lowerFlat(Res, pair.b.?, &slots);
|
||||
lowerFlat(Borrowed(Res), borrow(pair.a), &slots);
|
||||
keep(Res, third);
|
||||
drop(Res, fourth);
|
||||
try std.testing.expectEqualSlices(u32, &.{4}, Res.dropped[0..Res.count]);
|
||||
|
||||
lowerReturn(void, {});
|
||||
try std.testing.expectEqualSlices(u32, &.{ 4, 1 }, Res.dropped[0..Res.count]);
|
||||
try std.testing.expectEqual(0, tracked.items.len);
|
||||
}
|
||||
31
src/check.zig
Normal file
31
src/check.zig
Normal file
@ -0,0 +1,31 @@
|
||||
//! Not part of the package. Zig only analyzes what gets used, so a plugin build
|
||||
//! never looks at most of src/wit. This takes the address of every generated
|
||||
//! function to get all of them compiled, see `zig build check`.
|
||||
|
||||
const std = @import("std");
|
||||
const wit = @import("wit.zig");
|
||||
|
||||
fn collect(comptime T: type) []const *const anyopaque {
|
||||
var out: []const *const anyopaque = &.{};
|
||||
for (std.meta.declarations(T)) |decl| {
|
||||
const Decl = @TypeOf(@field(T, decl.name));
|
||||
if (Decl == type) {
|
||||
const Inner = @field(T, decl.name);
|
||||
switch (@typeInfo(Inner)) {
|
||||
.@"struct", .@"enum", .@"union" => out = out ++ collect(Inner),
|
||||
else => {},
|
||||
}
|
||||
} else if (@typeInfo(Decl) == .@"fn" and !@typeInfo(Decl).@"fn".is_generic) {
|
||||
out = out ++ [1]*const anyopaque{@ptrCast(&@field(T, decl.name))};
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
const all = blk: {
|
||||
@setEvalBranchQuota(10_000_000);
|
||||
const list = collect(wit);
|
||||
break :blk list[0..list.len].*;
|
||||
};
|
||||
|
||||
export const table: [all.len]*const anyopaque = all;
|
||||
146
src/cmd.zig
Normal file
146
src/cmd.zig
Normal file
@ -0,0 +1,146 @@
|
||||
//! Declarative commands on top of the generated `command` interface.
|
||||
//!
|
||||
//! try pumpkin.cmd.register(ctx, .{
|
||||
//! .names = &.{ "greet", "hi" },
|
||||
//! .description = "Greets players.",
|
||||
//! .permission = "my-plugin:command.greet",
|
||||
//! .run = greetSelf,
|
||||
//! .then = &.{
|
||||
//! .argument("targets", .players, .{ .run = greetTargets }),
|
||||
//! },
|
||||
//! });
|
||||
|
||||
const std = @import("std");
|
||||
const abi = @import("abi.zig");
|
||||
const wit = @import("wit.zig");
|
||||
|
||||
const command = wit.command;
|
||||
const Context = wit.context.Context;
|
||||
const Server = wit.server.Server;
|
||||
const TextComponent = wit.text.TextComponent;
|
||||
|
||||
pub const Sender = command.CommandSender;
|
||||
pub const Args = command.ConsumedArgs;
|
||||
pub const Arg = command.Arg;
|
||||
pub const ArgumentType = command.ArgumentType;
|
||||
pub const Result = abi.Result(i32, command.CommandError);
|
||||
|
||||
pub const Handler = fn (Sender, Server, Args) Result;
|
||||
pub const Suggester = fn (Sender, Server, command.SuggestionRequest) command.CommandSuggestions;
|
||||
|
||||
pub const Node = struct {
|
||||
kind: union(enum) {
|
||||
literal: []const u8,
|
||||
argument: struct { name: []const u8, type: ArgumentType },
|
||||
},
|
||||
options: Options,
|
||||
|
||||
pub const Options = struct {
|
||||
run: ?*const Handler = null,
|
||||
/// Only meaningful on arguments.
|
||||
suggest: ?*const Suggester = null,
|
||||
then: []const Node = &.{},
|
||||
};
|
||||
|
||||
pub fn literal(name: []const u8, options: Options) Node {
|
||||
return .{ .kind = .{ .literal = name }, .options = options };
|
||||
}
|
||||
|
||||
pub fn argument(name: []const u8, arg_type: ArgumentType, options: Options) Node {
|
||||
return .{ .kind = .{ .argument = .{ .name = name, .type = arg_type } }, .options = options };
|
||||
}
|
||||
|
||||
fn build(node: Node) command.CommandNode {
|
||||
const built: command.CommandNode = switch (node.kind) {
|
||||
.literal => |name| .literal(name),
|
||||
.argument => |arg| .argument(arg.name, arg.type),
|
||||
};
|
||||
if (node.options.run) |handler| built.executeWithHandlerId(@intFromPtr(handler));
|
||||
if (node.options.suggest) |suggester| built.suggestWithHandlerId(@intFromPtr(suggester));
|
||||
for (node.options.then) |child| built.then(child.build());
|
||||
return built;
|
||||
}
|
||||
};
|
||||
|
||||
pub const Spec = struct {
|
||||
/// The command's name followed by its aliases.
|
||||
names: []const []const u8,
|
||||
description: []const u8 = "",
|
||||
/// Has to start with "<plugin name>:". A node the server has never heard
|
||||
/// of denies everyone, so `register` registers it as well.
|
||||
permission: []const u8,
|
||||
default: wit.permission.PermissionDefault = .allow,
|
||||
run: ?*const Handler = null,
|
||||
then: []const Node = &.{},
|
||||
};
|
||||
|
||||
pub fn register(ctx: Context, spec: Spec) error{PermissionRejected}!void {
|
||||
switch (ctx.registerPermission(.{
|
||||
.node = spec.permission,
|
||||
.description = spec.description,
|
||||
.default = spec.default,
|
||||
.children = &.{},
|
||||
})) {
|
||||
.ok => {},
|
||||
.err => |message| {
|
||||
std.log.err("permission {s}: {s}", .{ spec.permission, message });
|
||||
return error.PermissionRejected;
|
||||
},
|
||||
}
|
||||
|
||||
const root: command.Command = .init(spec.names, spec.description);
|
||||
if (spec.run) |handler| root.executeWithHandlerId(@intFromPtr(handler));
|
||||
for (spec.then) |child| root.then(child.build());
|
||||
ctx.registerCommand(root, spec.permission);
|
||||
}
|
||||
|
||||
pub fn ok(count: i32) Result {
|
||||
return .{ .ok = count };
|
||||
}
|
||||
|
||||
pub fn fail(message: []const u8) Result {
|
||||
return .{ .err = .{ .command_failed = .text(message) } };
|
||||
}
|
||||
|
||||
/// The value of argument `name` if it was parsed as `tag`.
|
||||
pub fn get(args: Args, name: []const u8, comptime tag: std.meta.Tag(Arg)) ?@FieldType(Arg, @tagName(tag)) {
|
||||
const value = args.getValue(name);
|
||||
return if (value == tag) @field(value, @tagName(tag)) else null;
|
||||
}
|
||||
|
||||
/// Any numeric argument as an integer, null when missing or out of bounds.
|
||||
pub fn int(args: Args, name: []const u8) ?i64 {
|
||||
return switch ((get(args, name, .num) orelse return null)) {
|
||||
.ok => |number| switch (number) {
|
||||
.int32 => |v| v,
|
||||
.int64 => |v| v,
|
||||
.float32 => |v| @intFromFloat(v),
|
||||
.float64 => |v| @intFromFloat(v),
|
||||
},
|
||||
.err => null,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn float(args: Args, name: []const u8) ?f64 {
|
||||
return switch ((get(args, name, .num) orelse return null)) {
|
||||
.ok => |number| switch (number) {
|
||||
.int32 => |v| @floatFromInt(v),
|
||||
.int64 => |v| @floatFromInt(v),
|
||||
.float32 => |v| v,
|
||||
.float64 => |v| v,
|
||||
},
|
||||
.err => null,
|
||||
};
|
||||
}
|
||||
|
||||
/// Suggests `values` for the word under the cursor.
|
||||
pub fn suggestions(request: command.SuggestionRequest, values: []const []const u8) command.CommandSuggestions {
|
||||
const out = abi.arena().alloc(command.CommandSuggestion, values.len) catch @panic("OOM");
|
||||
var n: usize = 0;
|
||||
for (values) |value| {
|
||||
if (!std.mem.startsWith(u8, value, request.remaining)) continue;
|
||||
out[n] = .{ .value = value, .tooltip = null };
|
||||
n += 1;
|
||||
}
|
||||
return .{ .start = request.start, .length = @intCast(request.remaining.len), .values = out[0..n] };
|
||||
}
|
||||
83
src/msg.zig
Normal file
83
src/msg.zig
Normal file
@ -0,0 +1,83 @@
|
||||
//! Text components from struct literals instead of a call per style.
|
||||
//!
|
||||
//! sender.sendMessage(pumpkin.msg.build(&.{
|
||||
//! .{ .text = "[Shop] ", .color = .gold, .bold = true },
|
||||
//! .{ .text = "open", .click = .{ .run_command = "/shop" }, .hover = "Opens the shop" },
|
||||
//! }));
|
||||
|
||||
const std = @import("std");
|
||||
const abi = @import("abi.zig");
|
||||
const wit = @import("wit.zig");
|
||||
|
||||
const TextComponent = wit.text.TextComponent;
|
||||
|
||||
pub const Color = wit.common.NamedColor;
|
||||
pub const Rgb = wit.common.RgbColor;
|
||||
|
||||
pub const Click = union(enum) {
|
||||
open_url: []const u8,
|
||||
run_command: []const u8,
|
||||
suggest_command: []const u8,
|
||||
copy: []const u8,
|
||||
change_page: u32,
|
||||
};
|
||||
|
||||
pub const Span = struct {
|
||||
text: []const u8 = "",
|
||||
/// A translation key, used instead of `text`.
|
||||
translate: ?[]const u8 = null,
|
||||
color: ?Color = null,
|
||||
/// Wins over `color`.
|
||||
rgb: ?Rgb = null,
|
||||
bold: ?bool = null,
|
||||
italic: ?bool = null,
|
||||
underlined: ?bool = null,
|
||||
strikethrough: ?bool = null,
|
||||
obfuscated: ?bool = null,
|
||||
click: ?Click = null,
|
||||
/// Plain text shown on hover.
|
||||
hover: ?[]const u8 = null,
|
||||
/// Inserted into the chat box on shift click.
|
||||
insertion: ?[]const u8 = null,
|
||||
font: ?[]const u8 = null,
|
||||
};
|
||||
|
||||
pub fn span(s: Span) TextComponent {
|
||||
const out: TextComponent = if (s.translate) |key| .translate(key, &.{}) else .text(s.text);
|
||||
|
||||
if (s.rgb) |rgb| out.colorRgb(rgb) else if (s.color) |color| out.colorNamed(color);
|
||||
if (s.bold) |v| out.bold(v);
|
||||
if (s.italic) |v| out.italic(v);
|
||||
if (s.underlined) |v| out.underlined(v);
|
||||
if (s.strikethrough) |v| out.strikethrough(v);
|
||||
if (s.obfuscated) |v| out.obfuscated(v);
|
||||
if (s.insertion) |v| out.insertion(v);
|
||||
if (s.font) |v| out.font(v);
|
||||
if (s.hover) |v| out.hoverShowText(.text(v));
|
||||
if (s.click) |click| switch (click) {
|
||||
.open_url => |v| out.clickOpenUrl(v),
|
||||
.run_command => |v| out.clickRunCommand(v),
|
||||
.suggest_command => |v| out.clickSuggestCommand(v),
|
||||
.copy => |v| out.clickCopyToClipboard(v),
|
||||
.change_page => |v| out.clickChangePage(v),
|
||||
};
|
||||
return out;
|
||||
}
|
||||
|
||||
/// One component made of `spans`, in order.
|
||||
pub fn build(spans: []const Span) TextComponent {
|
||||
if (spans.len == 1) return span(spans[0]);
|
||||
const root: TextComponent = .text("");
|
||||
for (spans) |s| root.addChild(span(s));
|
||||
return root;
|
||||
}
|
||||
|
||||
pub fn plain(text: []const u8) TextComponent {
|
||||
return .text(text);
|
||||
}
|
||||
|
||||
/// A formatted single color message, `color` may be null.
|
||||
pub fn fmt(color: ?Color, comptime format: []const u8, args: anytype) TextComponent {
|
||||
const text = std.fmt.allocPrint(abi.arena(), format, args) catch @panic("OOM");
|
||||
return span(.{ .text = text, .color = color });
|
||||
}
|
||||
14266
src/plugin.wit
Normal file
14266
src/plugin.wit
Normal file
File diff suppressed because it is too large
Load Diff
307
src/pumpkin.zig
Normal file
307
src/pumpkin.zig
Normal file
@ -0,0 +1,307 @@
|
||||
//! Zig bindings for Pumpkin's plugin API.
|
||||
//!
|
||||
//! The namespaces below mirror the WIT interfaces one to one and are generated.
|
||||
//! What's written by hand here is the glue a plugin needs to get going:
|
||||
//! `register`, typed event and task handlers, `cmd` for commands, `msg` for
|
||||
//! text components and `std.log` support.
|
||||
//!
|
||||
//! Whatever the API hands out is only good until the current callback returns:
|
||||
//! strings, slices and records live in a per-call arena and handles are
|
||||
//! released along with it. Call `keep` on a handle to hold on to it, from then
|
||||
//! on it is yours to `deinit`. Functions that take a handle over are marked
|
||||
//! "Consumes" in their docs.
|
||||
|
||||
const std = @import("std");
|
||||
|
||||
pub const abi = @import("abi.zig");
|
||||
pub const cmd = @import("cmd.zig");
|
||||
pub const msg = @import("msg.zig");
|
||||
const wit = @import("wit.zig");
|
||||
|
||||
pub const advancement = wit.advancement;
|
||||
pub const attributes = wit.attributes;
|
||||
pub const bedrock_packets = wit.bedrock_packets;
|
||||
pub const biomes = wit.biomes;
|
||||
pub const block_entity = wit.block_entity;
|
||||
pub const boss_bar = wit.boss_bar;
|
||||
pub const command = wit.command;
|
||||
pub const common = wit.common;
|
||||
pub const context = wit.context;
|
||||
pub const damage_types = wit.damage_types;
|
||||
pub const data_components = wit.data_components;
|
||||
pub const datapack = wit.datapack;
|
||||
pub const display = wit.display;
|
||||
pub const enchantments = wit.enchantments;
|
||||
pub const entity = wit.entity;
|
||||
pub const entity_statuses = wit.entity_statuses;
|
||||
pub const entity_types = wit.entity_types;
|
||||
pub const event = wit.event;
|
||||
pub const forms = wit.forms;
|
||||
pub const game_events = wit.game_events;
|
||||
pub const game_rules = wit.game_rules;
|
||||
pub const gui = wit.gui;
|
||||
pub const i18n = wit.i18n;
|
||||
pub const inventory = wit.inventory;
|
||||
pub const ipc = wit.ipc;
|
||||
pub const item_stack = wit.item_stack;
|
||||
pub const java_dialogs = wit.java_dialogs;
|
||||
pub const java_packets = wit.java_packets;
|
||||
pub const logging = wit.logging;
|
||||
pub const particles = wit.particles;
|
||||
pub const permission = wit.permission;
|
||||
pub const player = wit.player;
|
||||
pub const potions = wit.potions;
|
||||
pub const recipe = wit.recipe;
|
||||
pub const scheduler = wit.scheduler;
|
||||
pub const scoreboard = wit.scoreboard;
|
||||
pub const screens = wit.screens;
|
||||
pub const server = wit.server;
|
||||
pub const sounds = wit.sounds;
|
||||
pub const statistics = wit.statistics;
|
||||
pub const status_effect = wit.status_effect;
|
||||
pub const text = wit.text;
|
||||
pub const uuid = wit.uuid;
|
||||
pub const world = wit.world;
|
||||
|
||||
pub const Context = context.Context;
|
||||
pub const Server = server.Server;
|
||||
pub const Player = player.Player;
|
||||
pub const Entity = world.Entity;
|
||||
pub const World = world.World;
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const Event = event.Event;
|
||||
pub const EventType = event.EventType;
|
||||
pub const EventPriority = event.EventPriority;
|
||||
pub const CommandSender = command.CommandSender;
|
||||
pub const ConsumedArgs = command.ConsumedArgs;
|
||||
pub const CommandError = command.CommandError;
|
||||
pub const CommandResult = abi.Result(i32, CommandError);
|
||||
|
||||
pub const Metadata = struct {
|
||||
name: []const u8,
|
||||
version: []const u8,
|
||||
authors: []const []const u8 = &.{},
|
||||
description: []const u8 = "",
|
||||
dependencies: []const []const u8 = &.{},
|
||||
permissions: []const []const u8 = &.{},
|
||||
};
|
||||
|
||||
/// Plug this into `std_options.logFn` to route `std.log` to the server console.
|
||||
pub fn logFn(
|
||||
comptime level: std.log.Level,
|
||||
comptime scope: @EnumLiteral(),
|
||||
comptime format: []const u8,
|
||||
args: anytype,
|
||||
) void {
|
||||
const prefix = if (scope == .default) "" else "(" ++ @tagName(scope) ++ ") ";
|
||||
const message = std.fmt.allocPrint(abi.arena(), prefix ++ format, args) catch return;
|
||||
logging.log(switch (level) {
|
||||
.err => .@"error",
|
||||
.warn => .warn,
|
||||
.info => .info,
|
||||
.debug => .debug,
|
||||
}, message);
|
||||
}
|
||||
|
||||
pub const EventOptions = struct {
|
||||
priority: EventPriority = .normal,
|
||||
/// Whether the server waits for the handler before carrying on.
|
||||
/// Changes made to the event are only seen when this is set.
|
||||
blocking: bool = true,
|
||||
};
|
||||
|
||||
pub fn EventData(comptime event_type: EventType) type {
|
||||
return @FieldType(Event, @tagName(event_type));
|
||||
}
|
||||
|
||||
/// Registers `handler` for one kind of event. It gets the payload of exactly
|
||||
/// that event and may edit it in place, e.g. set `cancelled`.
|
||||
pub fn on(
|
||||
ctx: Context,
|
||||
comptime event_type: EventType,
|
||||
comptime handler: fn (Server, *EventData(event_type)) void,
|
||||
options: EventOptions,
|
||||
) void {
|
||||
const glue = struct {
|
||||
fn dispatch(srv: Server, ev: *Event) void {
|
||||
handler(srv, &@field(ev, @tagName(event_type)));
|
||||
}
|
||||
};
|
||||
ctx.registerEvent(handlerId(&glue.dispatch), event_type, options.priority, options.blocking);
|
||||
}
|
||||
|
||||
pub const EventHandler = fn (Server, *Event) void;
|
||||
pub const CommandHandler = fn (CommandSender, Server, ConsumedArgs) CommandResult;
|
||||
pub const SuggestionHandler = fn (CommandSender, Server, command.SuggestionRequest) command.CommandSuggestions;
|
||||
pub const TaskHandler = fn (Server) void;
|
||||
pub const GenerateHandler = fn (world.GenerationPhase, world.ChunkBuffer) void;
|
||||
|
||||
pub const AiGoal = struct {
|
||||
canStart: *const fn (Server, Entity) bool,
|
||||
shouldContinue: *const fn (Server, Entity) bool,
|
||||
start: *const fn (Server, Entity) void = noop,
|
||||
tick: *const fn (Server, Entity) void = noop,
|
||||
stop: *const fn (Server, Entity) void = noop,
|
||||
|
||||
fn noop(_: Server, _: Entity) void {}
|
||||
};
|
||||
|
||||
/// The server hands ids back untouched, so an id is simply the address of the
|
||||
/// handler. Works for every `*-with-handler-id` style function in the API,
|
||||
/// pass a pointer to a function of the matching `*Handler` type or to a
|
||||
/// static `AiGoal`.
|
||||
pub fn handlerId(handler: anytype) u32 {
|
||||
return @intFromPtr(handler);
|
||||
}
|
||||
|
||||
pub fn runLater(comptime handler: TaskHandler, delay_ticks: u64) u32 {
|
||||
return scheduler.scheduleDelayedTask(handlerId(&handler), delay_ticks);
|
||||
}
|
||||
|
||||
pub fn runEvery(comptime handler: TaskHandler, delay_ticks: u64, period_ticks: u64) u32 {
|
||||
return scheduler.scheduleRepeatingTask(handlerId(&handler), delay_ticks, period_ticks);
|
||||
}
|
||||
|
||||
/// Registers what `Plugin.events` lists, each entry being `.event_name = handler`
|
||||
/// or `.event_name = .{ handler, EventOptions{...} }`.
|
||||
fn registerEvents(comptime Plugin: type, ctx: Context) void {
|
||||
const table = Plugin.events;
|
||||
inline for (@typeInfo(@TypeOf(table)).@"struct".fields) |field| {
|
||||
const event_type = comptime std.meta.stringToEnum(EventType, field.name) orelse
|
||||
@compileError("no event called '" ++ field.name ++ "'");
|
||||
const entry = @field(table, field.name);
|
||||
if (@typeInfo(@TypeOf(entry)) == .@"fn") {
|
||||
on(ctx, event_type, entry, .{});
|
||||
} else {
|
||||
on(ctx, event_type, entry[0], entry[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Exports the plugin world for `Plugin`. Call it from a `comptime` block.
|
||||
///
|
||||
/// `Plugin` needs a `pub const metadata: Metadata` and can have any of
|
||||
/// pub const events = .{ .player_join_event = onJoin, ... }
|
||||
/// pub const commands: []const cmd.Spec = &.{ ... }
|
||||
/// pub fn onLoad(ctx: Context) !void
|
||||
/// pub fn onUnload(ctx: Context) !void
|
||||
/// pub fn onIpcMessage(sender: ipc.PluginId, message: ipc.IpcMessage) abi.Result(ipc.IpcMessage, []const u8)
|
||||
///
|
||||
/// Events and commands are registered before `onLoad` runs.
|
||||
pub fn register(comptime Plugin: type) void {
|
||||
const glue = struct {
|
||||
fn initPlugin() void {}
|
||||
|
||||
fn getMetadata() wit.metadata.PluginMetadata {
|
||||
const meta: Metadata = Plugin.metadata;
|
||||
return .{
|
||||
.name = meta.name,
|
||||
.version = meta.version,
|
||||
.authors = meta.authors,
|
||||
.description = meta.description,
|
||||
.dependencies = meta.dependencies,
|
||||
.permissions = meta.permissions,
|
||||
};
|
||||
}
|
||||
|
||||
fn onLoad(ctx: Context) abi.Result(void, []const u8) {
|
||||
if (@hasDecl(Plugin, "events")) registerEvents(Plugin, ctx);
|
||||
if (@hasDecl(Plugin, "commands")) {
|
||||
const specs: []const cmd.Spec = Plugin.commands;
|
||||
for (specs) |spec| cmd.register(ctx, spec) catch |err| return .{ .err = @errorName(err) };
|
||||
}
|
||||
return lifecycle("onLoad", ctx);
|
||||
}
|
||||
|
||||
fn onUnload(ctx: Context) abi.Result(void, []const u8) {
|
||||
return lifecycle("onUnload", ctx);
|
||||
}
|
||||
|
||||
fn lifecycle(comptime name: []const u8, ctx: Context) abi.Result(void, []const u8) {
|
||||
if (!@hasDecl(Plugin, name)) return .ok;
|
||||
@field(Plugin, name)(ctx) catch |err| return .{ .err = @errorName(err) };
|
||||
return .ok;
|
||||
}
|
||||
|
||||
fn handleEvent(id: u32, srv: Server, ev: Event) Event {
|
||||
var out = ev;
|
||||
handlerFromId(EventHandler, id)(srv, &out);
|
||||
return out;
|
||||
}
|
||||
|
||||
fn handleCommand(id: u32, sender: CommandSender, srv: Server, args: ConsumedArgs) CommandResult {
|
||||
return handlerFromId(CommandHandler, id)(sender, srv, args);
|
||||
}
|
||||
|
||||
fn handleCommandSuggestion(
|
||||
id: u32,
|
||||
sender: CommandSender,
|
||||
srv: Server,
|
||||
request: command.SuggestionRequest,
|
||||
) command.CommandSuggestions {
|
||||
return handlerFromId(SuggestionHandler, id)(sender, srv, request);
|
||||
}
|
||||
|
||||
fn handleTask(id: u32, srv: Server) void {
|
||||
handlerFromId(TaskHandler, id)(srv);
|
||||
}
|
||||
|
||||
fn handleIpcMessage(sender: ipc.PluginId, message: ipc.IpcMessage) abi.Result(ipc.IpcMessage, []const u8) {
|
||||
if (@hasDecl(Plugin, "onIpcMessage")) return Plugin.onIpcMessage(sender, message);
|
||||
return .{ .err = "this plugin does not take messages" };
|
||||
}
|
||||
|
||||
fn aiCanStart(id: u32, srv: Server, mob: Entity) bool {
|
||||
return goalFromId(id).canStart(srv, mob);
|
||||
}
|
||||
|
||||
fn aiShouldContinue(id: u32, srv: Server, mob: Entity) bool {
|
||||
return goalFromId(id).shouldContinue(srv, mob);
|
||||
}
|
||||
|
||||
fn aiStart(id: u32, srv: Server, mob: Entity) void {
|
||||
goalFromId(id).start(srv, mob);
|
||||
}
|
||||
|
||||
fn aiTick(id: u32, srv: Server, mob: Entity) void {
|
||||
goalFromId(id).tick(srv, mob);
|
||||
}
|
||||
|
||||
fn aiStop(id: u32, srv: Server, mob: Entity) void {
|
||||
goalFromId(id).stop(srv, mob);
|
||||
}
|
||||
|
||||
fn handleGeneratePhase(id: u32, phase: world.GenerationPhase, chunk: world.ChunkBuffer) void {
|
||||
handlerFromId(GenerateHandler, id)(phase, chunk);
|
||||
}
|
||||
};
|
||||
|
||||
const exports = wit.exports;
|
||||
exports.initPlugin(glue.initPlugin);
|
||||
exports.getMetadata(glue.getMetadata);
|
||||
exports.onLoad(glue.onLoad);
|
||||
exports.onUnload(glue.onUnload);
|
||||
exports.handleEvent(glue.handleEvent);
|
||||
exports.handleCommand(glue.handleCommand);
|
||||
exports.handleCommandSuggestion(glue.handleCommandSuggestion);
|
||||
exports.handleTask(glue.handleTask);
|
||||
exports.handleIpcMessage(glue.handleIpcMessage);
|
||||
exports.handleAiGoalCanStart(glue.aiCanStart);
|
||||
exports.handleAiGoalShouldContinue(glue.aiShouldContinue);
|
||||
exports.handleAiGoalStart(glue.aiStart);
|
||||
exports.handleAiGoalTick(glue.aiTick);
|
||||
exports.handleAiGoalStop(glue.aiStop);
|
||||
exports.handleGeneratePhase(glue.handleGeneratePhase);
|
||||
}
|
||||
|
||||
fn handlerFromId(comptime Fn: type, id: u32) *const Fn {
|
||||
return @ptrFromInt(id);
|
||||
}
|
||||
|
||||
fn goalFromId(id: u32) *const AiGoal {
|
||||
return @ptrFromInt(id);
|
||||
}
|
||||
|
||||
test {
|
||||
_ = abi;
|
||||
}
|
||||
48
src/wit.zig
Normal file
48
src/wit.zig
Normal file
@ -0,0 +1,48 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const attributes = @import("wit/attributes.zig");
|
||||
pub const biomes = @import("wit/biomes.zig");
|
||||
pub const common = @import("wit/common.zig");
|
||||
pub const damage_types = @import("wit/damage_types.zig");
|
||||
pub const data_components = @import("wit/data_components.zig");
|
||||
pub const datapack = @import("wit/datapack.zig");
|
||||
pub const entity_statuses = @import("wit/entity_statuses.zig");
|
||||
pub const entity_types = @import("wit/entity_types.zig");
|
||||
pub const game_events = @import("wit/game_events.zig");
|
||||
pub const game_rules = @import("wit/game_rules.zig");
|
||||
pub const i18n = @import("wit/i18n.zig");
|
||||
pub const ipc = @import("wit/ipc.zig");
|
||||
pub const logging = @import("wit/logging.zig");
|
||||
pub const metadata = @import("wit/metadata.zig");
|
||||
pub const particles = @import("wit/particles.zig");
|
||||
pub const permission = @import("wit/permission.zig");
|
||||
pub const potions = @import("wit/potions.zig");
|
||||
pub const scheduler = @import("wit/scheduler.zig");
|
||||
pub const screens = @import("wit/screens.zig");
|
||||
pub const sounds = @import("wit/sounds.zig");
|
||||
pub const statistics = @import("wit/statistics.zig");
|
||||
pub const status_effect = @import("wit/status_effect.zig");
|
||||
pub const text = @import("wit/text.zig");
|
||||
pub const advancement = @import("wit/advancement.zig");
|
||||
pub const enchantments = @import("wit/enchantments.zig");
|
||||
pub const forms = @import("wit/forms.zig");
|
||||
pub const item_stack = @import("wit/item_stack.zig");
|
||||
pub const inventory = @import("wit/inventory.zig");
|
||||
pub const block_entity = @import("wit/block_entity.zig");
|
||||
pub const gui = @import("wit/gui.zig");
|
||||
pub const java_dialogs = @import("wit/java_dialogs.zig");
|
||||
pub const recipe = @import("wit/recipe.zig");
|
||||
pub const scoreboard = @import("wit/scoreboard.zig");
|
||||
pub const uuid = @import("wit/uuid.zig");
|
||||
pub const bedrock_packets = @import("wit/bedrock_packets.zig");
|
||||
pub const java_packets = @import("wit/java_packets.zig");
|
||||
pub const world = @import("wit/world.zig");
|
||||
pub const display = @import("wit/display.zig");
|
||||
pub const entity = @import("wit/entity.zig");
|
||||
pub const player = @import("wit/player.zig");
|
||||
pub const boss_bar = @import("wit/boss_bar.zig");
|
||||
pub const event = @import("wit/event.zig");
|
||||
pub const server = @import("wit/server.zig");
|
||||
pub const command = @import("wit/command.zig");
|
||||
pub const context = @import("wit/context.zig");
|
||||
pub const exports = @import("wit/exports.zig");
|
||||
41
src/wit/advancement.zig
Normal file
41
src/wit/advancement.zig
Normal file
@ -0,0 +1,41 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const text = @import("text.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
|
||||
/// Frame type for an advancement.
|
||||
pub const FrameType = enum(u8) {
|
||||
task,
|
||||
challenge,
|
||||
goal,
|
||||
};
|
||||
|
||||
/// Display information for an advancement.
|
||||
pub const AdvancementDisplay = struct {
|
||||
title: TextComponent,
|
||||
description: TextComponent,
|
||||
frame: FrameType,
|
||||
show_toast: bool,
|
||||
hidden: bool,
|
||||
announce_to_chat: bool,
|
||||
background: ?[]const u8,
|
||||
x: f32,
|
||||
y: f32,
|
||||
};
|
||||
|
||||
/// Detailed information about an advancement.
|
||||
pub const AdvancementInfo = struct {
|
||||
id: []const u8,
|
||||
parent_id: ?[]const u8,
|
||||
criteria: []const []const u8,
|
||||
display: ?AdvancementDisplay,
|
||||
};
|
||||
|
||||
/// Represents progress of an advancement for a player.
|
||||
pub const AdvancementProgress = struct {
|
||||
advancement_id: []const u8,
|
||||
done: bool,
|
||||
awarded_criteria: []const []const u8,
|
||||
remaining_criteria: []const []const u8,
|
||||
};
|
||||
56
src/wit/attributes.zig
Normal file
56
src/wit/attributes.zig
Normal file
@ -0,0 +1,56 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const Attribute = enum(u8) {
|
||||
air_drag_modifier,
|
||||
armor,
|
||||
armor_toughness,
|
||||
attack_damage,
|
||||
attack_knockback,
|
||||
attack_speed,
|
||||
below_name_distance,
|
||||
block_break_speed,
|
||||
block_interaction_range,
|
||||
bounciness,
|
||||
burning_time,
|
||||
camera_distance,
|
||||
explosion_knockback_resistance,
|
||||
entity_interaction_range,
|
||||
fall_damage_multiplier,
|
||||
flying_speed,
|
||||
follow_range,
|
||||
friction_modifier,
|
||||
gravity,
|
||||
jump_strength,
|
||||
knockback_resistance,
|
||||
luck,
|
||||
max_absorption,
|
||||
max_health,
|
||||
mining_efficiency,
|
||||
movement_efficiency,
|
||||
movement_speed,
|
||||
name_tag_distance,
|
||||
oxygen_bonus,
|
||||
safe_fall_distance,
|
||||
scale,
|
||||
sneaking_speed,
|
||||
spawn_reinforcements,
|
||||
step_height,
|
||||
submerged_mining_speed,
|
||||
sweeping_damage_ratio,
|
||||
tempt_range,
|
||||
water_movement_efficiency,
|
||||
waypoint_transmit_range,
|
||||
waypoint_receive_range,
|
||||
};
|
||||
|
||||
pub const ModifierOperation = enum(u8) {
|
||||
add,
|
||||
multiply_base,
|
||||
multiply_total,
|
||||
};
|
||||
|
||||
pub const AttributeModifier = struct {
|
||||
id: []const u8,
|
||||
amount: f64,
|
||||
operation: ModifierOperation,
|
||||
};
|
||||
1901
src/wit/bedrock_packets.zig
Normal file
1901
src/wit/bedrock_packets.zig
Normal file
File diff suppressed because it is too large
Load Diff
70
src/wit/biomes.zig
Normal file
70
src/wit/biomes.zig
Normal file
@ -0,0 +1,70 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const Biome = enum(u8) {
|
||||
badlands,
|
||||
bamboo_jungle,
|
||||
basalt_deltas,
|
||||
beach,
|
||||
birch_forest,
|
||||
cherry_grove,
|
||||
cold_ocean,
|
||||
crimson_forest,
|
||||
dark_forest,
|
||||
deep_cold_ocean,
|
||||
deep_dark,
|
||||
deep_frozen_ocean,
|
||||
deep_lukewarm_ocean,
|
||||
deep_ocean,
|
||||
desert,
|
||||
dripstone_caves,
|
||||
end_barrens,
|
||||
end_highlands,
|
||||
end_midlands,
|
||||
eroded_badlands,
|
||||
flower_forest,
|
||||
forest,
|
||||
frozen_ocean,
|
||||
frozen_peaks,
|
||||
frozen_river,
|
||||
grove,
|
||||
ice_spikes,
|
||||
jagged_peaks,
|
||||
jungle,
|
||||
lukewarm_ocean,
|
||||
lush_caves,
|
||||
mangrove_swamp,
|
||||
meadow,
|
||||
mushroom_fields,
|
||||
nether_wastes,
|
||||
ocean,
|
||||
old_growth_birch_forest,
|
||||
old_growth_pine_taiga,
|
||||
old_growth_spruce_taiga,
|
||||
pale_garden,
|
||||
plains,
|
||||
river,
|
||||
savanna,
|
||||
savanna_plateau,
|
||||
small_end_islands,
|
||||
snowy_beach,
|
||||
snowy_plains,
|
||||
snowy_slopes,
|
||||
snowy_taiga,
|
||||
soul_sand_valley,
|
||||
sparse_jungle,
|
||||
stony_peaks,
|
||||
stony_shore,
|
||||
sulfur_caves,
|
||||
sunflower_plains,
|
||||
swamp,
|
||||
taiga,
|
||||
the_end,
|
||||
the_void,
|
||||
warm_ocean,
|
||||
warped_forest,
|
||||
windswept_forest,
|
||||
windswept_gravelly_hills,
|
||||
windswept_hills,
|
||||
windswept_savanna,
|
||||
wooded_badlands,
|
||||
};
|
||||
1865
src/wit/block_entity.zig
Normal file
1865
src/wit/block_entity.zig
Normal file
File diff suppressed because it is too large
Load Diff
157
src/wit/boss_bar.zig
Normal file
157
src/wit/boss_bar.zig
Normal file
@ -0,0 +1,157 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const text = @import("text.zig");
|
||||
const player = @import("player.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const Player = player.Player;
|
||||
|
||||
/// Represents the color of a boss bar.
|
||||
pub const BossBarColor = enum(u8) {
|
||||
pink,
|
||||
blue,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
purple,
|
||||
white,
|
||||
};
|
||||
|
||||
/// Represents the notches/divisions of a boss bar.
|
||||
pub const BossBarDivision = enum(u8) {
|
||||
no_division,
|
||||
notches_6,
|
||||
notches_10,
|
||||
notches_12,
|
||||
notches_20,
|
||||
};
|
||||
|
||||
/// Metadata flags that can be toggled on a boss bar.
|
||||
pub const BossBarMetadata = struct {
|
||||
/// Darkens the sky for players who see the boss bar.
|
||||
darken_sky: bool,
|
||||
/// If true, the bar is considered a "dragon bar" (used for Ender Dragon).
|
||||
dragon_bar: bool,
|
||||
/// If true, fog is created around the players who see the boss bar.
|
||||
create_fog: bool,
|
||||
};
|
||||
|
||||
/// Represents a boss bar that can be shown to players.
|
||||
pub const BossBar = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]boss-bar";
|
||||
|
||||
/// Creates a new boss bar.
|
||||
///
|
||||
/// Consumes `title`.
|
||||
pub fn init(title: TextComponent, color: BossBarColor, division: BossBarDivision) BossBar {
|
||||
return abi.call(raw.@"[constructor]boss-bar", BossBar, .{ title, color, division });
|
||||
}
|
||||
|
||||
/// Returns the title of this boss bar.
|
||||
pub fn getTitle(self: BossBar) TextComponent {
|
||||
return abi.call(raw.@"[method]boss-bar.get-title", TextComponent, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the title of this boss bar.
|
||||
///
|
||||
/// Consumes `title`.
|
||||
pub fn setTitle(self: BossBar, title: TextComponent) void {
|
||||
return abi.call(raw.@"[method]boss-bar.set-title", void, .{ abi.borrow(self), title });
|
||||
}
|
||||
|
||||
/// Returns the health (0.0 to 1.0) of this boss bar.
|
||||
pub fn getHealth(self: BossBar) f32 {
|
||||
return abi.call(raw.@"[method]boss-bar.get-health", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the health (0.0 to 1.0) of this boss bar.
|
||||
pub fn setHealth(self: BossBar, health: f32) void {
|
||||
return abi.call(raw.@"[method]boss-bar.set-health", void, .{ abi.borrow(self), health });
|
||||
}
|
||||
|
||||
/// Returns the color of this boss bar.
|
||||
pub fn getColor(self: BossBar) BossBarColor {
|
||||
return abi.call(raw.@"[method]boss-bar.get-color", BossBarColor, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the color of this boss bar.
|
||||
pub fn setColor(self: BossBar, color: BossBarColor) void {
|
||||
return abi.call(raw.@"[method]boss-bar.set-color", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
/// Returns the division of this boss bar.
|
||||
pub fn getDivision(self: BossBar) BossBarDivision {
|
||||
return abi.call(raw.@"[method]boss-bar.get-division", BossBarDivision, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the division of this boss bar.
|
||||
pub fn setDivision(self: BossBar, division: BossBarDivision) void {
|
||||
return abi.call(raw.@"[method]boss-bar.set-division", void, .{ abi.borrow(self), division });
|
||||
}
|
||||
|
||||
/// Returns the currently active metadata on this boss bar.
|
||||
pub fn getMetadata(self: BossBar) BossBarMetadata {
|
||||
return abi.call(raw.@"[method]boss-bar.get-metadata", BossBarMetadata, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Updates the metadata on this boss bar.
|
||||
pub fn setMetadata(self: BossBar, metadata: BossBarMetadata) void {
|
||||
return abi.call(raw.@"[method]boss-bar.set-metadata", void, .{ abi.borrow(self), metadata });
|
||||
}
|
||||
|
||||
/// Adds a player to this boss bar, making it visible to them.
|
||||
///
|
||||
/// Consumes `player_`.
|
||||
pub fn addPlayer(self: BossBar, player_: Player) void {
|
||||
return abi.call(raw.@"[method]boss-bar.add-player", void, .{ abi.borrow(self), player_ });
|
||||
}
|
||||
|
||||
/// Removes a player from this boss bar, hiding it from them.
|
||||
///
|
||||
/// Consumes `player_`.
|
||||
pub fn removePlayer(self: BossBar, player_: Player) void {
|
||||
return abi.call(raw.@"[method]boss-bar.remove-player", void, .{ abi.borrow(self), player_ });
|
||||
}
|
||||
|
||||
/// Returns a list of all players currently seeing this boss bar.
|
||||
pub fn getPlayers(self: BossBar) []const Player {
|
||||
return abi.call(raw.@"[method]boss-bar.get-players", []const Player, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Removes this boss bar from all players and cleans it up.
|
||||
pub fn removeAll(self: BossBar) void {
|
||||
return abi.call(raw.@"[method]boss-bar.remove-all", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: BossBar) void {
|
||||
abi.keep(BossBar, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: BossBar) void {
|
||||
abi.drop(BossBar, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[constructor]boss-bar"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-title"(i32) i32;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.set-title"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-health"(i32) f32;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.set-health"(i32, f32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-color"(i32) i32;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.set-color"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-division"(i32) i32;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.set-division"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-metadata"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.set-metadata"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.add-player"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.remove-player"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.get-players"(i32, i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[method]boss-bar.remove-all"(i32) void;
|
||||
extern "pumpkin:plugin/boss-bar@0.1.0" fn @"[resource-drop]boss-bar"(i32) void;
|
||||
};
|
||||
434
src/wit/command.zig
Normal file
434
src/wit/command.zig
Normal file
@ -0,0 +1,434 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const world = @import("world.zig");
|
||||
const player = @import("player.zig");
|
||||
const block_entity = @import("block_entity.zig");
|
||||
const common = @import("common.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
const server = @import("server.zig");
|
||||
const text = @import("text.zig");
|
||||
|
||||
pub const World = world.World;
|
||||
pub const Entity = world.Entity;
|
||||
pub const Player = player.Player;
|
||||
pub const CommandBlockEntity = block_entity.CommandBlockEntity;
|
||||
pub const Position = common.Position;
|
||||
pub const BlockPos = common.BlockPos;
|
||||
pub const Locale = common.Locale;
|
||||
pub const GameMode = common.GameMode;
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
pub const Server = server.Server;
|
||||
pub const Difficulty = server.Difficulty;
|
||||
pub const TextComponent = text.TextComponent;
|
||||
|
||||
pub const CommandError = union(enum) {
|
||||
invalid_consumption: ?[]const u8,
|
||||
invalid_requirement,
|
||||
permission_denied,
|
||||
command_failed: TextComponent,
|
||||
};
|
||||
|
||||
pub const CommandNode = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]command-node";
|
||||
|
||||
pub fn literal(name: []const u8) CommandNode {
|
||||
return abi.call(raw.@"[static]command-node.literal", CommandNode, .{name});
|
||||
}
|
||||
|
||||
pub fn argument(name: []const u8, @"type": ArgumentType) CommandNode {
|
||||
return abi.call(raw.@"[static]command-node.argument", CommandNode, .{ name, @"type" });
|
||||
}
|
||||
|
||||
/// Consumes `node`.
|
||||
pub fn then(self: CommandNode, node: CommandNode) void {
|
||||
return abi.call(raw.@"[method]command-node.then", void, .{ abi.borrow(self), node });
|
||||
}
|
||||
|
||||
pub fn executeWithHandlerId(self: CommandNode, handler_id: u32) void {
|
||||
return abi.call(raw.@"[method]command-node.execute-with-handler-id", void, .{ abi.borrow(self), handler_id });
|
||||
}
|
||||
|
||||
pub fn suggestWithHandlerId(self: CommandNode, handler_id: u32) void {
|
||||
return abi.call(raw.@"[method]command-node.suggest-with-handler-id", void, .{ abi.borrow(self), handler_id });
|
||||
}
|
||||
|
||||
pub fn requireWithHandlerId(self: CommandNode, handler_id: u32) void {
|
||||
return abi.call(raw.@"[method]command-node.require-with-handler-id", void, .{ abi.borrow(self), handler_id });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: CommandNode) void {
|
||||
abi.keep(CommandNode, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: CommandNode) void {
|
||||
abi.drop(CommandNode, self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const SuggestionRequest = struct {
|
||||
input: []const u8,
|
||||
cursor: u32,
|
||||
start: u32,
|
||||
remaining: []const u8,
|
||||
};
|
||||
|
||||
pub const CommandSuggestion = struct {
|
||||
value: []const u8,
|
||||
tooltip: ?TextComponent,
|
||||
};
|
||||
|
||||
pub const CommandSuggestions = struct {
|
||||
start: u32,
|
||||
length: u32,
|
||||
values: []const CommandSuggestion,
|
||||
};
|
||||
|
||||
pub const EntityArgument = struct {
|
||||
single: bool,
|
||||
players_only: bool,
|
||||
};
|
||||
|
||||
pub const CommandSenderType = union(enum) {
|
||||
rcon,
|
||||
console,
|
||||
player: Player,
|
||||
command_block: struct { CommandBlockEntity, World },
|
||||
dummy,
|
||||
};
|
||||
|
||||
pub const PermissionLevel = enum(u8) {
|
||||
zero,
|
||||
one,
|
||||
two,
|
||||
three,
|
||||
four,
|
||||
};
|
||||
|
||||
pub const CommandSender = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]command-sender";
|
||||
|
||||
pub fn getCommandSenderType(self: CommandSender) CommandSenderType {
|
||||
return abi.call(raw.@"[method]command-sender.get-command-sender-type", CommandSenderType, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getName(self: CommandSender) []const u8 {
|
||||
return abi.call(raw.@"[method]command-sender.get-name", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Consumes `text_`.
|
||||
pub fn sendMessage(self: CommandSender, text_: TextComponent) void {
|
||||
return abi.call(raw.@"[method]command-sender.send-message", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
/// Consumes `text_`.
|
||||
pub fn sendSystemMessage(self: CommandSender, text_: TextComponent) void {
|
||||
return abi.call(raw.@"[method]command-sender.send-system-message", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
/// Consumes `text_`.
|
||||
pub fn sendError(self: CommandSender, text_: TextComponent) void {
|
||||
return abi.call(raw.@"[method]command-sender.send-error", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
pub fn setSuccessCount(self: CommandSender, count: i32) void {
|
||||
return abi.call(raw.@"[method]command-sender.set-success-count", void, .{ abi.borrow(self), count });
|
||||
}
|
||||
|
||||
pub fn isPlayer(self: CommandSender) bool {
|
||||
return abi.call(raw.@"[method]command-sender.is-player", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn isConsole(self: CommandSender) bool {
|
||||
return abi.call(raw.@"[method]command-sender.is-console", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn asPlayer(self: CommandSender) ?Player {
|
||||
return abi.call(raw.@"[method]command-sender.as-player", ?Player, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn permissionLevel(self: CommandSender) PermissionLevel {
|
||||
return abi.call(raw.@"[method]command-sender.permission-level", PermissionLevel, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn hasPermissionLevel(self: CommandSender, level: PermissionLevel) bool {
|
||||
return abi.call(raw.@"[method]command-sender.has-permission-level", bool, .{ abi.borrow(self), level });
|
||||
}
|
||||
|
||||
pub fn hasPermission(self: CommandSender, server_: Server, node: []const u8) bool {
|
||||
return abi.call(raw.@"[method]command-sender.has-permission", bool, .{ abi.borrow(self), abi.borrow(server_), node });
|
||||
}
|
||||
|
||||
pub fn position(self: CommandSender) ?Position {
|
||||
return abi.call(raw.@"[method]command-sender.position", ?Position, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn world(self: CommandSender) ?World {
|
||||
return abi.call(raw.@"[method]command-sender.world", ?World, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getLocale(self: CommandSender) Locale {
|
||||
return abi.call(raw.@"[method]command-sender.get-locale", Locale, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn shouldReceiveFeedback(self: CommandSender) bool {
|
||||
return abi.call(raw.@"[method]command-sender.should-receive-feedback", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn shouldBroadcastConsoleToOps(self: CommandSender) bool {
|
||||
return abi.call(raw.@"[method]command-sender.should-broadcast-console-to-ops", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn shouldTrackOutput(self: CommandSender) bool {
|
||||
return abi.call(raw.@"[method]command-sender.should-track-output", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: CommandSender) void {
|
||||
abi.keep(CommandSender, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: CommandSender) void {
|
||||
abi.drop(CommandSender, self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const StringType = enum(u8) {
|
||||
single_word,
|
||||
quotable,
|
||||
greedy,
|
||||
};
|
||||
|
||||
pub const ArgumentType = union(enum) {
|
||||
bool,
|
||||
float: struct { ?f32, ?f32 },
|
||||
double: struct { ?f64, ?f64 },
|
||||
integer: struct { ?i32, ?i32 },
|
||||
long: struct { ?i64, ?i64 },
|
||||
string: StringType,
|
||||
entities,
|
||||
entity,
|
||||
players,
|
||||
game_profile,
|
||||
block_pos,
|
||||
column_pos,
|
||||
position3d,
|
||||
position2d,
|
||||
block_state,
|
||||
block_predicate,
|
||||
item,
|
||||
item_predicate,
|
||||
color,
|
||||
component,
|
||||
style,
|
||||
message,
|
||||
nbt_compound_tag,
|
||||
nbt_tag,
|
||||
nbt_path,
|
||||
objective,
|
||||
objective_criteria,
|
||||
operation,
|
||||
particle,
|
||||
angle,
|
||||
rotation,
|
||||
scoreboard_slot,
|
||||
score_holder: bool,
|
||||
swizzle,
|
||||
team,
|
||||
item_slot,
|
||||
resource_location,
|
||||
mob_effect,
|
||||
function,
|
||||
entity_anchor,
|
||||
int_range,
|
||||
float_range,
|
||||
dimension,
|
||||
gamemode,
|
||||
difficulty,
|
||||
time: ?i32,
|
||||
resource: []const u8,
|
||||
resource_or_tag: []const u8,
|
||||
resource_or_tag_key: []const u8,
|
||||
resource_key: []const u8,
|
||||
template_mirror,
|
||||
template_rotation,
|
||||
uuid,
|
||||
};
|
||||
|
||||
pub const SuggestionType = enum(u8) {
|
||||
ask_server,
|
||||
all_recipes,
|
||||
available_sounds,
|
||||
available_biomes,
|
||||
summonable_entities,
|
||||
};
|
||||
|
||||
pub const BossbarColor = enum(u8) {
|
||||
pink,
|
||||
blue,
|
||||
red,
|
||||
green,
|
||||
yellow,
|
||||
purple,
|
||||
white,
|
||||
};
|
||||
|
||||
pub const BossbarStyle = enum(u8) {
|
||||
no_division,
|
||||
notches6,
|
||||
notches10,
|
||||
notches12,
|
||||
notches20,
|
||||
};
|
||||
|
||||
pub const SoundCategory = enum(u8) {
|
||||
master,
|
||||
music,
|
||||
records,
|
||||
weather,
|
||||
blocks,
|
||||
hostile,
|
||||
neutral,
|
||||
players,
|
||||
ambient,
|
||||
voice,
|
||||
};
|
||||
|
||||
pub const EntityAnchor = enum(u8) {
|
||||
eyes,
|
||||
feet,
|
||||
};
|
||||
|
||||
pub const Number = union(enum) {
|
||||
float64: f64,
|
||||
float32: f32,
|
||||
int32: i32,
|
||||
int64: i64,
|
||||
};
|
||||
|
||||
pub const NotInBounds = union(enum) {
|
||||
lower_bound: struct { Number, Number },
|
||||
upper_bound: struct { Number, Number },
|
||||
};
|
||||
|
||||
pub const Arg = union(enum) {
|
||||
simple: []const u8,
|
||||
msg: []const u8,
|
||||
bool: bool,
|
||||
item: []const u8,
|
||||
item_predicate: []const u8,
|
||||
resource_location: []const u8,
|
||||
block: []const u8,
|
||||
block_predicate: []const u8,
|
||||
time: i32,
|
||||
num: abi.Result(Number, NotInBounds),
|
||||
block_pos: BlockPos,
|
||||
pos3d: struct { f64, f64, f64 },
|
||||
pos2d: struct { f64, f64 },
|
||||
rotation: struct { f32, bool, f32, bool },
|
||||
gamemode: GameMode,
|
||||
difficulty: Difficulty,
|
||||
players: []const Player,
|
||||
particle: []const u8,
|
||||
text_component: TextComponent,
|
||||
bossbar_color: BossbarColor,
|
||||
bossbar_style: BossbarStyle,
|
||||
sound_category: SoundCategory,
|
||||
damage_type: []const u8,
|
||||
effect: []const u8,
|
||||
enchantment: []const u8,
|
||||
advancement: []const u8,
|
||||
entity_anchor: EntityAnchor,
|
||||
};
|
||||
|
||||
pub const ConsumedArgs = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]consumed-args";
|
||||
|
||||
pub fn getValue(self: ConsumedArgs, key: []const u8) Arg {
|
||||
return abi.call(raw.@"[method]consumed-args.get-value", Arg, .{ abi.borrow(self), key });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: ConsumedArgs) void {
|
||||
abi.keep(ConsumedArgs, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: ConsumedArgs) void {
|
||||
abi.drop(ConsumedArgs, self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const Command = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]command";
|
||||
|
||||
/// First name is primary, rest are aliases
|
||||
pub fn init(names: []const []const u8, description: []const u8) Command {
|
||||
return abi.call(raw.@"[constructor]command", Command, .{ names, description });
|
||||
}
|
||||
|
||||
/// Consumes `node`.
|
||||
pub fn then(self: Command, node: CommandNode) void {
|
||||
return abi.call(raw.@"[method]command.then", void, .{ abi.borrow(self), node });
|
||||
}
|
||||
|
||||
pub fn executeWithHandlerId(self: Command, handler_id: u32) void {
|
||||
return abi.call(raw.@"[method]command.execute-with-handler-id", void, .{ abi.borrow(self), handler_id });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Command) void {
|
||||
abi.keep(Command, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Command) void {
|
||||
abi.drop(Command, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[static]command-node.literal"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[static]command-node.argument"(i32, i32, i32, i32, i64, i32, i64) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-node.then"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-node.execute-with-handler-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-node.suggest-with-handler-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-node.require-with-handler-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.get-command-sender-type"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.get-name"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.send-message"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.send-system-message"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.send-error"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.set-success-count"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.is-player"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.is-console"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.as-player"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.permission-level"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.has-permission-level"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.has-permission"(i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.position"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.world"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.get-locale"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.should-receive-feedback"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.should-broadcast-console-to-ops"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command-sender.should-track-output"(i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]consumed-args.get-value"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[constructor]command"(i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command.then"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[method]command.execute-with-handler-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[resource-drop]command-node"(i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[resource-drop]command-sender"(i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[resource-drop]consumed-args"(i32) void;
|
||||
extern "pumpkin:plugin/command@0.1.0" fn @"[resource-drop]command"(i32) void;
|
||||
};
|
||||
260
src/wit/common.zig
Normal file
260
src/wit/common.zig
Normal file
@ -0,0 +1,260 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
/// Serialized text component as a postcard byte array.
|
||||
/// @deprecated Use the text-component resource from the text interface instead.
|
||||
pub const RawTextComponent = []const u8;
|
||||
|
||||
/// Represents one entry in an NBT compound tag.
|
||||
pub const NbtEntry = struct {
|
||||
key: []const u8,
|
||||
value: u32,
|
||||
};
|
||||
|
||||
/// Represents a Minecraft NBT tag.
|
||||
pub const NbtTag = union(enum) {
|
||||
byte: i8,
|
||||
short: i16,
|
||||
int: i32,
|
||||
long: i64,
|
||||
float: f32,
|
||||
double: f64,
|
||||
byte_array: []const i8,
|
||||
string_tag: []const u8,
|
||||
list_tag: []const u32,
|
||||
compound: []const NbtEntry,
|
||||
int_array: []const i32,
|
||||
long_array: []const i64,
|
||||
};
|
||||
|
||||
/// Represents a Minecraft NBT tag tree.
|
||||
pub const NbtTree = struct {
|
||||
root: u32,
|
||||
tags: []const NbtTag,
|
||||
};
|
||||
|
||||
/// A position in the world grid (integers).
|
||||
pub const BlockPos = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
z: i32,
|
||||
};
|
||||
|
||||
/// A precise coordinate in the world (floats).
|
||||
pub const Position = struct { f64, f64, f64 };
|
||||
|
||||
/// Represents the hands of a player.
|
||||
pub const Hand = enum(u8) {
|
||||
left,
|
||||
right,
|
||||
};
|
||||
|
||||
/// Represents the game modes available in Minecraft.
|
||||
pub const GameMode = enum(u8) {
|
||||
survival,
|
||||
creative,
|
||||
adventure,
|
||||
spectator,
|
||||
};
|
||||
|
||||
/// The 16 base Minecraft colors.
|
||||
pub const NamedColor = enum(u8) {
|
||||
black,
|
||||
dark_blue,
|
||||
dark_green,
|
||||
dark_aqua,
|
||||
dark_red,
|
||||
dark_purple,
|
||||
gold,
|
||||
gray,
|
||||
dark_gray,
|
||||
blue,
|
||||
green,
|
||||
aqua,
|
||||
red,
|
||||
light_purple,
|
||||
yellow,
|
||||
white,
|
||||
};
|
||||
|
||||
/// An RGB color represented by its red, green, and blue components.
|
||||
pub const RgbColor = struct {
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
};
|
||||
|
||||
/// An ARGB color with alpha (transparency) channel.
|
||||
pub const ArgbColor = struct {
|
||||
a: u8,
|
||||
r: u8,
|
||||
g: u8,
|
||||
b: u8,
|
||||
};
|
||||
|
||||
/// Represents the type of click interaction in a GUI.
|
||||
pub const ClickType = enum(u8) {
|
||||
left,
|
||||
right,
|
||||
shift_left,
|
||||
shift_right,
|
||||
middle,
|
||||
drop,
|
||||
control_drop,
|
||||
double_click,
|
||||
number_key,
|
||||
unknown,
|
||||
};
|
||||
|
||||
/// Represents the various poses an entity can be in.
|
||||
pub const EntityPose = enum(u8) {
|
||||
standing,
|
||||
fall_flying,
|
||||
sleeping,
|
||||
swimming,
|
||||
spin_attack,
|
||||
crouching,
|
||||
long_jumping,
|
||||
dying,
|
||||
croaking,
|
||||
using_tongue,
|
||||
sitting,
|
||||
roaring,
|
||||
sniffing,
|
||||
emerging,
|
||||
digging,
|
||||
sliding,
|
||||
shooting,
|
||||
inhaling,
|
||||
};
|
||||
|
||||
/// All Minecraft-supported locales.
|
||||
pub const Locale = enum(u8) {
|
||||
af_za,
|
||||
ar_sa,
|
||||
ast_es,
|
||||
az_az,
|
||||
ba_ru,
|
||||
bar,
|
||||
be_by,
|
||||
bg_bg,
|
||||
br_fr,
|
||||
brb,
|
||||
bs_ba,
|
||||
ca_es,
|
||||
cs_cz,
|
||||
cy_gb,
|
||||
da_dk,
|
||||
de_at,
|
||||
de_ch,
|
||||
de_de,
|
||||
el_gr,
|
||||
en_au,
|
||||
en_ca,
|
||||
en_gb,
|
||||
en_nz,
|
||||
en_pt,
|
||||
en_ud,
|
||||
en_us,
|
||||
enp,
|
||||
enws,
|
||||
eo_uy,
|
||||
es_ar,
|
||||
es_cl,
|
||||
es_ec,
|
||||
es_es,
|
||||
es_mx,
|
||||
es_uy,
|
||||
es_ve,
|
||||
esan,
|
||||
et_ee,
|
||||
eu_es,
|
||||
fa_ir,
|
||||
fi_fi,
|
||||
fil_ph,
|
||||
fo_fo,
|
||||
fr_ca,
|
||||
fr_fr,
|
||||
fra_de,
|
||||
fur_it,
|
||||
fy_nl,
|
||||
ga_ie,
|
||||
gd_gb,
|
||||
gl_es,
|
||||
haw_us,
|
||||
he_il,
|
||||
hi_in,
|
||||
hr_hr,
|
||||
hu_hu,
|
||||
hy_am,
|
||||
id_id,
|
||||
ig_ng,
|
||||
io_en,
|
||||
is_is,
|
||||
isv,
|
||||
it_it,
|
||||
ja_jp,
|
||||
jbo_en,
|
||||
ka_ge,
|
||||
kk_kz,
|
||||
kn_in,
|
||||
ko_kr,
|
||||
ksh,
|
||||
kw_gb,
|
||||
la_la,
|
||||
lb_lu,
|
||||
li_li,
|
||||
lmo,
|
||||
lo_la,
|
||||
lol_us,
|
||||
lt_lt,
|
||||
lv_lv,
|
||||
lzh,
|
||||
mk_mk,
|
||||
mn_mn,
|
||||
ms_my,
|
||||
mt_mt,
|
||||
nah,
|
||||
nds_de,
|
||||
nl_be,
|
||||
nl_nl,
|
||||
nn_no,
|
||||
no_no,
|
||||
oc_fr,
|
||||
ovd,
|
||||
pl_pl,
|
||||
pt_br,
|
||||
pt_pt,
|
||||
qya_aa,
|
||||
ro_ro,
|
||||
rpr,
|
||||
ru_ru,
|
||||
ry_ua,
|
||||
sah_sah,
|
||||
se_no,
|
||||
sk_sk,
|
||||
sl_si,
|
||||
so_so,
|
||||
sq_al,
|
||||
sr_cs,
|
||||
sr_sp,
|
||||
sv_se,
|
||||
sxu,
|
||||
szl,
|
||||
ta_in,
|
||||
th_th,
|
||||
tl_ph,
|
||||
tlh_aa,
|
||||
tok,
|
||||
tr_tr,
|
||||
tt_ru,
|
||||
uk_ua,
|
||||
val_es,
|
||||
vec_it,
|
||||
vi_vn,
|
||||
yi_de,
|
||||
yo_ng,
|
||||
zh_cn,
|
||||
zh_hk,
|
||||
zh_tw,
|
||||
zlm_arab,
|
||||
};
|
||||
104
src/wit/context.zig
Normal file
104
src/wit/context.zig
Normal file
@ -0,0 +1,104 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const server = @import("server.zig");
|
||||
const event = @import("event.zig");
|
||||
const command = @import("command.zig");
|
||||
const permission = @import("permission.zig");
|
||||
|
||||
pub const Server = server.Server;
|
||||
pub const EventType = event.EventType;
|
||||
pub const EventPriority = event.EventPriority;
|
||||
pub const Command = command.Command;
|
||||
pub const Permission = permission.Permission;
|
||||
|
||||
/// Verified marketplace metadata for signed plugins.
|
||||
pub const MarketplaceMetadata = struct {
|
||||
/// The marketplace base URL where this plugin is registered.
|
||||
marketplace_url: []const u8,
|
||||
/// The unique plugin ID on the marketplace.
|
||||
plugin_id: i64,
|
||||
/// The canonical plugin name.
|
||||
plugin_name: []const u8,
|
||||
/// The semver version string of the plugin.
|
||||
version: []const u8,
|
||||
/// Developer ID.
|
||||
dev_id: i64,
|
||||
/// Developer display name or username.
|
||||
dev_name: []const u8,
|
||||
/// Whether this is a paid marketplace plugin.
|
||||
is_paid: bool,
|
||||
/// The buyer / licensee user ID (0 for free/open-source).
|
||||
user_id: i64,
|
||||
/// Unique license key issued to the buyer, if paid.
|
||||
license_key: ?[]const u8,
|
||||
/// ISO-8601 timestamp of when this binary/license was issued.
|
||||
issued_at: []const u8,
|
||||
};
|
||||
|
||||
/// A contextual handle for plugin-related operations.
|
||||
pub const Context = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]context";
|
||||
|
||||
/// Registers a handler for a specific event.
|
||||
///
|
||||
/// * `handler-id`: Unique ID for the event handler.
|
||||
/// * `event-type`: The type of event to listen for.
|
||||
/// * `event-priority`: When this handler should be called relative to others.
|
||||
/// * `blocking`: Whether the event should wait for this handler to finish.
|
||||
pub fn registerEvent(self: Context, handler_id: u32, event_type: EventType, event_priority: EventPriority, blocking: bool) void {
|
||||
return abi.call(raw.@"[method]context.register-event", void, .{ abi.borrow(self), handler_id, event_type, event_priority, blocking });
|
||||
}
|
||||
|
||||
/// Registers a new command.
|
||||
///
|
||||
/// * `command`: The command definition.
|
||||
/// * `permission`: The required permission node to execute this command.
|
||||
///
|
||||
/// Consumes `command_`.
|
||||
pub fn registerCommand(self: Context, command_: Command, permission_: []const u8) void {
|
||||
return abi.call(raw.@"[method]context.register-command", void, .{ abi.borrow(self), command_, permission_ });
|
||||
}
|
||||
|
||||
/// Registers a permission node with the server.
|
||||
pub fn registerPermission(self: Context, permission_: Permission) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]context.register-permission", abi.Result(void, []const u8), .{ abi.borrow(self), permission_ });
|
||||
}
|
||||
|
||||
/// Returns the path to the plugin's private data folder.
|
||||
pub fn getDataFolder(self: Context) []const u8 {
|
||||
return abi.call(raw.@"[method]context.get-data-folder", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the global server instance.
|
||||
pub fn getServer(self: Context) Server {
|
||||
return abi.call(raw.@"[method]context.get-server", Server, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns verified marketplace metadata if this plugin binary is signed, or none if unsigned.
|
||||
pub fn getMarketplaceMetadata(self: Context) ?MarketplaceMetadata {
|
||||
return abi.call(raw.@"[method]context.get-marketplace-metadata", ?MarketplaceMetadata, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Context) void {
|
||||
abi.keep(Context, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Context) void {
|
||||
abi.drop(Context, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.register-event"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.register-command"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.register-permission"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.get-data-folder"(i32, i32) void;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.get-server"(i32) i32;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[method]context.get-marketplace-metadata"(i32, i32) void;
|
||||
extern "pumpkin:plugin/context@0.1.0" fn @"[resource-drop]context"(i32) void;
|
||||
};
|
||||
55
src/wit/damage_types.zig
Normal file
55
src/wit/damage_types.zig
Normal file
@ -0,0 +1,55 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const DamageType = enum(u8) {
|
||||
arrow,
|
||||
bad_respawn_point,
|
||||
cactus,
|
||||
campfire,
|
||||
cramming,
|
||||
dragon_breath,
|
||||
drown,
|
||||
dry_out,
|
||||
ender_pearl,
|
||||
explosion,
|
||||
fall,
|
||||
falling_anvil,
|
||||
falling_block,
|
||||
falling_stalactite,
|
||||
fireball,
|
||||
fireworks,
|
||||
fly_into_wall,
|
||||
freeze,
|
||||
generic,
|
||||
generic_kill,
|
||||
hot_floor,
|
||||
in_fire,
|
||||
in_wall,
|
||||
indirect_magic,
|
||||
lava,
|
||||
lightning_bolt,
|
||||
mace_smash,
|
||||
magic,
|
||||
mob_attack,
|
||||
mob_attack_no_aggro,
|
||||
mob_projectile,
|
||||
on_fire,
|
||||
out_of_world,
|
||||
outside_border,
|
||||
player_attack,
|
||||
player_explosion,
|
||||
sonic_boom,
|
||||
spear,
|
||||
spit,
|
||||
stalagmite,
|
||||
starve,
|
||||
sting,
|
||||
sulfur_cube_hot,
|
||||
sweet_berry_bush,
|
||||
thorns,
|
||||
thrown,
|
||||
trident,
|
||||
unattributed_fireball,
|
||||
wind_charge,
|
||||
wither,
|
||||
wither_skull,
|
||||
};
|
||||
115
src/wit/data_components.zig
Normal file
115
src/wit/data_components.zig
Normal file
@ -0,0 +1,115 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const DataComponent = enum(u8) {
|
||||
custom_data,
|
||||
max_stack_size,
|
||||
max_damage,
|
||||
damage,
|
||||
unbreakable,
|
||||
use_effects,
|
||||
custom_name,
|
||||
minimum_attack_charge,
|
||||
damage_type,
|
||||
item_name,
|
||||
item_model,
|
||||
lore,
|
||||
rarity,
|
||||
enchantments,
|
||||
can_place_on,
|
||||
can_break,
|
||||
attribute_modifiers,
|
||||
custom_model_data,
|
||||
tooltip_display,
|
||||
repair_cost,
|
||||
creative_slot_lock,
|
||||
enchantment_glint_override,
|
||||
intangible_projectile,
|
||||
food,
|
||||
consumable,
|
||||
use_remainder,
|
||||
use_cooldown,
|
||||
damage_resistant,
|
||||
tool,
|
||||
weapon,
|
||||
attack_range,
|
||||
enchantable,
|
||||
equippable,
|
||||
repairable,
|
||||
glider,
|
||||
tooltip_style,
|
||||
death_protection,
|
||||
blocks_attacks,
|
||||
piercing_weapon,
|
||||
kinetic_weapon,
|
||||
swing_animation,
|
||||
additional_trade_cost,
|
||||
stored_enchantments,
|
||||
dye,
|
||||
dyed_color,
|
||||
map_color,
|
||||
map_id,
|
||||
map_decorations,
|
||||
map_post_processing,
|
||||
charged_projectiles,
|
||||
bundle_contents,
|
||||
potion_contents,
|
||||
potion_duration_scale,
|
||||
suspicious_stew_effects,
|
||||
writable_book_content,
|
||||
written_book_content,
|
||||
trim,
|
||||
debug_stick_state,
|
||||
entity_data,
|
||||
bucket_entity_data,
|
||||
block_entity_data,
|
||||
instrument,
|
||||
provides_trim_material,
|
||||
ominous_bottle_amplifier,
|
||||
jukebox_playable,
|
||||
provides_banner_patterns,
|
||||
recipes,
|
||||
lodestone_tracker,
|
||||
firework_explosion,
|
||||
fireworks,
|
||||
profile,
|
||||
note_block_sound,
|
||||
banner_patterns,
|
||||
base_color,
|
||||
pot_decorations,
|
||||
container,
|
||||
block_state,
|
||||
bees,
|
||||
sulfur_cube_content,
|
||||
lock,
|
||||
container_loot,
|
||||
break_sound,
|
||||
villager_variant,
|
||||
wolf_variant,
|
||||
wolf_sound_variant,
|
||||
wolf_collar,
|
||||
fox_variant,
|
||||
salmon_size,
|
||||
parrot_variant,
|
||||
tropical_fish_pattern,
|
||||
tropical_fish_base_color,
|
||||
tropical_fish_pattern_color,
|
||||
mooshroom_variant,
|
||||
rabbit_variant,
|
||||
pig_variant,
|
||||
pig_sound_variant,
|
||||
cow_variant,
|
||||
cow_sound_variant,
|
||||
chicken_variant,
|
||||
chicken_sound_variant,
|
||||
zombie_nautilus_variant,
|
||||
frog_variant,
|
||||
horse_variant,
|
||||
painting_variant,
|
||||
llama_variant,
|
||||
axolotl_variant,
|
||||
cat_variant,
|
||||
cat_sound_variant,
|
||||
cat_collar,
|
||||
sheep_color,
|
||||
shulker_color,
|
||||
};
|
||||
99
src/wit/datapack.zig
Normal file
99
src/wit/datapack.zig
Normal file
@ -0,0 +1,99 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
|
||||
/// Information about a discovered or loaded datapack.
|
||||
pub const DatapackInfo = struct {
|
||||
id: []const u8,
|
||||
name: []const u8,
|
||||
description: []const u8,
|
||||
pack_format: u32,
|
||||
is_enabled: bool,
|
||||
recipe_count: u32,
|
||||
function_count: u32,
|
||||
};
|
||||
|
||||
/// Position options for enabling a datapack relative to other packs.
|
||||
pub const EnablePosition = union(enum) {
|
||||
first,
|
||||
last,
|
||||
before: []const u8,
|
||||
after: []const u8,
|
||||
};
|
||||
|
||||
/// Global manager for inspecting and controlling server datapacks.
|
||||
pub const DatapackManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]datapack-manager";
|
||||
|
||||
/// Returns all known datapacks (both enabled and available/disabled).
|
||||
pub fn listAllPacks(self: DatapackManager) []const DatapackInfo {
|
||||
return abi.call(raw.@"[method]datapack-manager.list-all-packs", []const DatapackInfo, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns only currently enabled datapacks.
|
||||
pub fn listEnabledPacks(self: DatapackManager) []const DatapackInfo {
|
||||
return abi.call(raw.@"[method]datapack-manager.list-enabled-packs", []const DatapackInfo, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns available (disabled) datapacks.
|
||||
pub fn listAvailablePacks(self: DatapackManager) []const DatapackInfo {
|
||||
return abi.call(raw.@"[method]datapack-manager.list-available-packs", []const DatapackInfo, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Retrieves details about a specific datapack by name or ID.
|
||||
pub fn getPack(self: DatapackManager, name: []const u8) ?DatapackInfo {
|
||||
return abi.call(raw.@"[method]datapack-manager.get-pack", ?DatapackInfo, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Checks if a datapack is currently enabled.
|
||||
pub fn isEnabled(self: DatapackManager, name: []const u8) bool {
|
||||
return abi.call(raw.@"[method]datapack-manager.is-enabled", bool, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Enables a datapack with a specific priority position.
|
||||
pub fn enablePack(self: DatapackManager, name: []const u8, position: EnablePosition) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]datapack-manager.enable-pack", abi.Result(void, []const u8), .{ abi.borrow(self), name, position });
|
||||
}
|
||||
|
||||
/// Disables an enabled datapack.
|
||||
pub fn disablePack(self: DatapackManager, name: []const u8) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]datapack-manager.disable-pack", abi.Result(void, []const u8), .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Reloads all enabled datapacks, recipes, and function tags,
|
||||
/// synchronizes recipes with online players, and triggers `#minecraft:load`.
|
||||
pub fn reload(self: DatapackManager) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]datapack-manager.reload", abi.Result(void, []const u8), .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Executes a datapack function or function tag (e.g. "namespace:fn" or "#namespace:tag").
|
||||
/// Returns the number of commands executed.
|
||||
pub fn executeFunction(self: DatapackManager, name: []const u8) abi.Result(u32, []const u8) {
|
||||
return abi.call(raw.@"[method]datapack-manager.execute-function", abi.Result(u32, []const u8), .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: DatapackManager) void {
|
||||
abi.keep(DatapackManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: DatapackManager) void {
|
||||
abi.drop(DatapackManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.list-all-packs"(i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.list-enabled-packs"(i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.list-available-packs"(i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.get-pack"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.is-enabled"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.enable-pack"(i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.disable-pack"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.reload"(i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[method]datapack-manager.execute-function"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/datapack@0.1.0" fn @"[resource-drop]datapack-manager"(i32) void;
|
||||
};
|
||||
492
src/wit/display.zig
Normal file
492
src/wit/display.zig
Normal file
@ -0,0 +1,492 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const world = @import("world.zig");
|
||||
const text = @import("text.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
const uuid = @import("uuid.zig");
|
||||
|
||||
pub const Entity = world.Entity;
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
pub const Uuid = uuid.Uuid;
|
||||
|
||||
/// Billboard rendering constraints for display entities.
|
||||
pub const BillboardMode = enum(u8) {
|
||||
fixed,
|
||||
vertical,
|
||||
horizontal,
|
||||
center,
|
||||
};
|
||||
|
||||
/// Item display transformation modes for item display entities.
|
||||
pub const ItemDisplayMode = enum(u8) {
|
||||
none,
|
||||
thirdperson_lefthand,
|
||||
thirdperson_righthand,
|
||||
firstperson_lefthand,
|
||||
firstperson_righthand,
|
||||
head,
|
||||
gui,
|
||||
ground,
|
||||
fixed,
|
||||
};
|
||||
|
||||
/// Text alignment options for text display entities.
|
||||
pub const TextAlignment = enum(u8) {
|
||||
center,
|
||||
left,
|
||||
right,
|
||||
};
|
||||
|
||||
/// 3D single-precision vector.
|
||||
pub const Vector3f = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
};
|
||||
|
||||
/// Single-precision quaternion representing a 3D rotation.
|
||||
pub const Quaternionf = struct {
|
||||
x: f32,
|
||||
y: f32,
|
||||
z: f32,
|
||||
w: f32,
|
||||
};
|
||||
|
||||
/// Transformation (translation, scale, left and right rotations) for display entities.
|
||||
pub const DisplayTransformation = struct {
|
||||
translation: Vector3f,
|
||||
scale: Vector3f,
|
||||
left_rotation: Quaternionf,
|
||||
right_rotation: Quaternionf,
|
||||
};
|
||||
|
||||
/// Common base resource for all display entities.
|
||||
pub const DisplayEntity = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]display-entity";
|
||||
|
||||
pub fn fromEntity(entity: Entity) ?DisplayEntity {
|
||||
return abi.call(raw.@"[static]display-entity.from-entity", ?DisplayEntity, .{abi.borrow(entity)});
|
||||
}
|
||||
|
||||
pub fn getEntity(self: DisplayEntity) Entity {
|
||||
return abi.call(raw.@"[method]display-entity.get-entity", Entity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getTransformation(self: DisplayEntity) DisplayTransformation {
|
||||
return abi.call(raw.@"[method]display-entity.get-transformation", DisplayTransformation, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setTransformation(self: DisplayEntity, transformation: DisplayTransformation) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-transformation", void, .{ abi.borrow(self), transformation });
|
||||
}
|
||||
|
||||
pub fn getInterpolationDuration(self: DisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-interpolation-duration", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setInterpolationDuration(self: DisplayEntity, duration: i32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-interpolation-duration", void, .{ abi.borrow(self), duration });
|
||||
}
|
||||
|
||||
pub fn getInterpolationStart(self: DisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-interpolation-start", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setInterpolationStart(self: DisplayEntity, delta_ticks: i32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-interpolation-start", void, .{ abi.borrow(self), delta_ticks });
|
||||
}
|
||||
|
||||
pub fn getTeleportDuration(self: DisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-teleport-duration", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setTeleportDuration(self: DisplayEntity, duration: i32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-teleport-duration", void, .{ abi.borrow(self), duration });
|
||||
}
|
||||
|
||||
pub fn getBillboard(self: DisplayEntity) BillboardMode {
|
||||
return abi.call(raw.@"[method]display-entity.get-billboard", BillboardMode, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setBillboard(self: DisplayEntity, mode: BillboardMode) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-billboard", void, .{ abi.borrow(self), mode });
|
||||
}
|
||||
|
||||
pub fn getViewRange(self: DisplayEntity) f32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-view-range", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setViewRange(self: DisplayEntity, range: f32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-view-range", void, .{ abi.borrow(self), range });
|
||||
}
|
||||
|
||||
pub fn getShadowRadius(self: DisplayEntity) f32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-shadow-radius", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setShadowRadius(self: DisplayEntity, radius: f32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-shadow-radius", void, .{ abi.borrow(self), radius });
|
||||
}
|
||||
|
||||
pub fn getShadowStrength(self: DisplayEntity) f32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-shadow-strength", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setShadowStrength(self: DisplayEntity, strength: f32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-shadow-strength", void, .{ abi.borrow(self), strength });
|
||||
}
|
||||
|
||||
pub fn getDisplayWidth(self: DisplayEntity) f32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-display-width", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setDisplayWidth(self: DisplayEntity, width: f32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-display-width", void, .{ abi.borrow(self), width });
|
||||
}
|
||||
|
||||
pub fn getDisplayHeight(self: DisplayEntity) f32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-display-height", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setDisplayHeight(self: DisplayEntity, height: f32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-display-height", void, .{ abi.borrow(self), height });
|
||||
}
|
||||
|
||||
pub fn getGlowColorOverride(self: DisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-glow-color-override", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setGlowColorOverride(self: DisplayEntity, color: i32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-glow-color-override", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
pub fn getBrightness(self: DisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]display-entity.get-brightness", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setBrightness(self: DisplayEntity, brightness: i32) void {
|
||||
return abi.call(raw.@"[method]display-entity.set-brightness", void, .{ abi.borrow(self), brightness });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: DisplayEntity) void {
|
||||
abi.keep(DisplayEntity, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: DisplayEntity) void {
|
||||
abi.drop(DisplayEntity, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Resource specifically for Block Display entities.
|
||||
pub const BlockDisplayEntity = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]block-display-entity";
|
||||
|
||||
pub fn fromEntity(entity: Entity) ?BlockDisplayEntity {
|
||||
return abi.call(raw.@"[static]block-display-entity.from-entity", ?BlockDisplayEntity, .{abi.borrow(entity)});
|
||||
}
|
||||
|
||||
pub fn getDisplay(self: BlockDisplayEntity) DisplayEntity {
|
||||
return abi.call(raw.@"[method]block-display-entity.get-display", DisplayEntity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getEntity(self: BlockDisplayEntity) Entity {
|
||||
return abi.call(raw.@"[method]block-display-entity.get-entity", Entity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getBlockStateId(self: BlockDisplayEntity) u16 {
|
||||
return abi.call(raw.@"[method]block-display-entity.get-block-state-id", u16, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setBlockStateId(self: BlockDisplayEntity, state_id: u16) void {
|
||||
return abi.call(raw.@"[method]block-display-entity.set-block-state-id", void, .{ abi.borrow(self), state_id });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: BlockDisplayEntity) void {
|
||||
abi.keep(BlockDisplayEntity, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: BlockDisplayEntity) void {
|
||||
abi.drop(BlockDisplayEntity, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Resource specifically for Item Display entities.
|
||||
pub const ItemDisplayEntity = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]item-display-entity";
|
||||
|
||||
pub fn fromEntity(entity: Entity) ?ItemDisplayEntity {
|
||||
return abi.call(raw.@"[static]item-display-entity.from-entity", ?ItemDisplayEntity, .{abi.borrow(entity)});
|
||||
}
|
||||
|
||||
pub fn getDisplay(self: ItemDisplayEntity) DisplayEntity {
|
||||
return abi.call(raw.@"[method]item-display-entity.get-display", DisplayEntity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getEntity(self: ItemDisplayEntity) Entity {
|
||||
return abi.call(raw.@"[method]item-display-entity.get-entity", Entity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getItem(self: ItemDisplayEntity) ?ItemStack {
|
||||
return abi.call(raw.@"[method]item-display-entity.get-item", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setItem(self: ItemDisplayEntity, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]item-display-entity.set-item", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn getItemDisplayMode(self: ItemDisplayEntity) ItemDisplayMode {
|
||||
return abi.call(raw.@"[method]item-display-entity.get-item-display-mode", ItemDisplayMode, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setItemDisplayMode(self: ItemDisplayEntity, mode: ItemDisplayMode) void {
|
||||
return abi.call(raw.@"[method]item-display-entity.set-item-display-mode", void, .{ abi.borrow(self), mode });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: ItemDisplayEntity) void {
|
||||
abi.keep(ItemDisplayEntity, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: ItemDisplayEntity) void {
|
||||
abi.drop(ItemDisplayEntity, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Resource specifically for Text Display entities.
|
||||
pub const TextDisplayEntity = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]text-display-entity";
|
||||
|
||||
pub fn fromEntity(entity: Entity) ?TextDisplayEntity {
|
||||
return abi.call(raw.@"[static]text-display-entity.from-entity", ?TextDisplayEntity, .{abi.borrow(entity)});
|
||||
}
|
||||
|
||||
pub fn getDisplay(self: TextDisplayEntity) DisplayEntity {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-display", DisplayEntity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getEntity(self: TextDisplayEntity) Entity {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-entity", Entity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getText(self: TextDisplayEntity) TextComponent {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-text", TextComponent, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Consumes `text_`.
|
||||
pub fn setText(self: TextDisplayEntity, text_: TextComponent) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-text", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
pub fn getLineWidth(self: TextDisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-line-width", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setLineWidth(self: TextDisplayEntity, width: i32) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-line-width", void, .{ abi.borrow(self), width });
|
||||
}
|
||||
|
||||
pub fn getBackground(self: TextDisplayEntity) i32 {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-background", i32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setBackground(self: TextDisplayEntity, color: i32) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-background", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
pub fn getTextOpacity(self: TextDisplayEntity) i8 {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-text-opacity", i8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setTextOpacity(self: TextDisplayEntity, opacity: i8) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-text-opacity", void, .{ abi.borrow(self), opacity });
|
||||
}
|
||||
|
||||
pub fn getShadow(self: TextDisplayEntity) bool {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-shadow", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setShadow(self: TextDisplayEntity, shadow: bool) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-shadow", void, .{ abi.borrow(self), shadow });
|
||||
}
|
||||
|
||||
pub fn getSeeThrough(self: TextDisplayEntity) bool {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-see-through", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setSeeThrough(self: TextDisplayEntity, see_through: bool) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-see-through", void, .{ abi.borrow(self), see_through });
|
||||
}
|
||||
|
||||
pub fn getDefaultBackground(self: TextDisplayEntity) bool {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-default-background", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setDefaultBackground(self: TextDisplayEntity, default_background: bool) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-default-background", void, .{ abi.borrow(self), default_background });
|
||||
}
|
||||
|
||||
pub fn getAlignment(self: TextDisplayEntity) TextAlignment {
|
||||
return abi.call(raw.@"[method]text-display-entity.get-alignment", TextAlignment, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setAlignment(self: TextDisplayEntity, alignment: TextAlignment) void {
|
||||
return abi.call(raw.@"[method]text-display-entity.set-alignment", void, .{ abi.borrow(self), alignment });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: TextDisplayEntity) void {
|
||||
abi.keep(TextDisplayEntity, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: TextDisplayEntity) void {
|
||||
abi.drop(TextDisplayEntity, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Resource specifically for Interaction entities.
|
||||
pub const InteractionEntity = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]interaction-entity";
|
||||
|
||||
pub fn fromEntity(entity: Entity) ?InteractionEntity {
|
||||
return abi.call(raw.@"[static]interaction-entity.from-entity", ?InteractionEntity, .{abi.borrow(entity)});
|
||||
}
|
||||
|
||||
pub fn getEntity(self: InteractionEntity) Entity {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-entity", Entity, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getWidth(self: InteractionEntity) f32 {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-width", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setWidth(self: InteractionEntity, width: f32) void {
|
||||
return abi.call(raw.@"[method]interaction-entity.set-width", void, .{ abi.borrow(self), width });
|
||||
}
|
||||
|
||||
pub fn getHeight(self: InteractionEntity) f32 {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-height", f32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setHeight(self: InteractionEntity, height: f32) void {
|
||||
return abi.call(raw.@"[method]interaction-entity.set-height", void, .{ abi.borrow(self), height });
|
||||
}
|
||||
|
||||
pub fn getResponse(self: InteractionEntity) bool {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-response", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setResponse(self: InteractionEntity, response: bool) void {
|
||||
return abi.call(raw.@"[method]interaction-entity.set-response", void, .{ abi.borrow(self), response });
|
||||
}
|
||||
|
||||
pub fn getLastAttacker(self: InteractionEntity) ?Uuid {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-last-attacker", ?Uuid, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getLastInteraction(self: InteractionEntity) ?Uuid {
|
||||
return abi.call(raw.@"[method]interaction-entity.get-last-interaction", ?Uuid, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: InteractionEntity) void {
|
||||
abi.keep(InteractionEntity, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: InteractionEntity) void {
|
||||
abi.drop(InteractionEntity, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[static]display-entity.from-entity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-entity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-transformation"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-transformation"(i32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-interpolation-duration"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-interpolation-duration"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-interpolation-start"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-interpolation-start"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-teleport-duration"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-teleport-duration"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-billboard"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-billboard"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-view-range"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-view-range"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-shadow-radius"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-shadow-radius"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-shadow-strength"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-shadow-strength"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-display-width"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-display-width"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-display-height"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-display-height"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-glow-color-override"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-glow-color-override"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.get-brightness"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]display-entity.set-brightness"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[static]block-display-entity.from-entity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]block-display-entity.get-display"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]block-display-entity.get-entity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]block-display-entity.get-block-state-id"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]block-display-entity.set-block-state-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[static]item-display-entity.from-entity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.get-display"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.get-entity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.get-item"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.set-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.get-item-display-mode"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]item-display-entity.set-item-display-mode"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[static]text-display-entity.from-entity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-display"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-entity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-text"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-text"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-line-width"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-line-width"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-background"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-background"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-text-opacity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-text-opacity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-shadow"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-shadow"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-see-through"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-see-through"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-default-background"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-default-background"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.get-alignment"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]text-display-entity.set-alignment"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[static]interaction-entity.from-entity"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-entity"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-width"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.set-width"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-height"(i32) f32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.set-height"(i32, f32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-response"(i32) i32;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.set-response"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-last-attacker"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[method]interaction-entity.get-last-interaction"(i32, i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[resource-drop]display-entity"(i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[resource-drop]block-display-entity"(i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[resource-drop]item-display-entity"(i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[resource-drop]text-display-entity"(i32) void;
|
||||
extern "pumpkin:plugin/display@0.1.0" fn @"[resource-drop]interaction-entity"(i32) void;
|
||||
};
|
||||
133
src/wit/enchantments.zig
Normal file
133
src/wit/enchantments.zig
Normal file
@ -0,0 +1,133 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const text = @import("text.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
|
||||
/// Equipment slot where an enchantment is active.
|
||||
pub const AttributeModifierSlot = enum(u8) {
|
||||
any,
|
||||
main_hand,
|
||||
off_hand,
|
||||
hand,
|
||||
feet,
|
||||
legs,
|
||||
chest,
|
||||
head,
|
||||
armor,
|
||||
body,
|
||||
saddle,
|
||||
};
|
||||
|
||||
/// Vanilla enchantments enum.
|
||||
pub const Enchantment = enum(u8) {
|
||||
aqua_affinity,
|
||||
bane_of_arthropods,
|
||||
binding_curse,
|
||||
blast_protection,
|
||||
breach,
|
||||
channeling,
|
||||
density,
|
||||
depth_strider,
|
||||
efficiency,
|
||||
feather_falling,
|
||||
fire_aspect,
|
||||
fire_protection,
|
||||
flame,
|
||||
fortune,
|
||||
frost_walker,
|
||||
impaling,
|
||||
infinity,
|
||||
knockback,
|
||||
looting,
|
||||
loyalty,
|
||||
luck_of_the_sea,
|
||||
lunge,
|
||||
lure,
|
||||
mending,
|
||||
multishot,
|
||||
piercing,
|
||||
power,
|
||||
projectile_protection,
|
||||
protection,
|
||||
punch,
|
||||
quick_charge,
|
||||
respiration,
|
||||
riptide,
|
||||
sharpness,
|
||||
silk_touch,
|
||||
smite,
|
||||
soul_speed,
|
||||
sweeping_edge,
|
||||
swift_sneak,
|
||||
thorns,
|
||||
unbreaking,
|
||||
vanishing_curse,
|
||||
wind_burst,
|
||||
};
|
||||
|
||||
/// Represents a custom enchantment definition.
|
||||
pub const CustomEnchantment = struct {
|
||||
/// Unique identifier for the enchantment (e.g. "my_plugin:lifesteal").
|
||||
id: []const u8,
|
||||
/// Description or display name of the enchantment.
|
||||
description: TextComponent,
|
||||
/// Maximum level of the enchantment (e.g. 1..=10).
|
||||
max_level: u32,
|
||||
/// Base anvil repair/combination cost multiplier.
|
||||
anvil_cost: u32,
|
||||
/// Tag or item pattern for supported items (e.g. "#minecraft:enchantable/weapon").
|
||||
supported_items: []const u8,
|
||||
/// Weight / rarity of the enchantment (higher = more common, default 5).
|
||||
weight: u32,
|
||||
/// Equipment slots where this enchantment is active.
|
||||
slots: []const AttributeModifierSlot,
|
||||
/// List of exclusive/conflicting enchantment IDs.
|
||||
exclusive_set: []const []const u8,
|
||||
};
|
||||
|
||||
/// Global manager for registering and querying custom enchantments.
|
||||
pub const EnchantmentManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]enchantment-manager";
|
||||
|
||||
/// Registers a new custom enchantment with the server.
|
||||
pub fn registerEnchantment(self: EnchantmentManager, enchantment: CustomEnchantment) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]enchantment-manager.register-enchantment", abi.Result(void, []const u8), .{ abi.borrow(self), enchantment });
|
||||
}
|
||||
|
||||
/// Gets an enchantment definition by its ID.
|
||||
pub fn getEnchantment(self: EnchantmentManager, id: []const u8) ?CustomEnchantment {
|
||||
return abi.call(raw.@"[method]enchantment-manager.get-enchantment", ?CustomEnchantment, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Checks if an enchantment ID is registered.
|
||||
pub fn hasEnchantment(self: EnchantmentManager, id: []const u8) bool {
|
||||
return abi.call(raw.@"[method]enchantment-manager.has-enchantment", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns all registered custom enchantment IDs.
|
||||
pub fn getAllEnchantmentIds(self: EnchantmentManager) []const []const u8 {
|
||||
return abi.call(raw.@"[method]enchantment-manager.get-all-enchantment-ids", []const []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: EnchantmentManager) void {
|
||||
abi.keep(EnchantmentManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: EnchantmentManager) void {
|
||||
abi.drop(EnchantmentManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/enchantments@0.1.0" fn @"[method]enchantment-manager.register-enchantment"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/enchantments@0.1.0" fn @"[method]enchantment-manager.get-enchantment"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/enchantments@0.1.0" fn @"[method]enchantment-manager.has-enchantment"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/enchantments@0.1.0" fn @"[method]enchantment-manager.get-all-enchantment-ids"(i32, i32) void;
|
||||
extern "pumpkin:plugin/enchantments@0.1.0" fn @"[resource-drop]enchantment-manager"(i32) void;
|
||||
};
|
||||
27
src/wit/entity.zig
Normal file
27
src/wit/entity.zig
Normal file
@ -0,0 +1,27 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const world = @import("world.zig");
|
||||
|
||||
pub const Entity = world.Entity;
|
||||
pub const LivingEntity = world.LivingEntity;
|
||||
pub const Mob = world.Mob;
|
||||
pub const PathNodeType = world.PathNodeType;
|
||||
pub const DyeColor = world.DyeColor;
|
||||
pub const VillagerProfession = world.VillagerProfession;
|
||||
pub const MobData = world.MobData;
|
||||
pub const SheepData = world.SheepData;
|
||||
pub const WolfData = world.WolfData;
|
||||
pub const CatData = world.CatData;
|
||||
pub const VillagerData = world.VillagerData;
|
||||
pub const CreeperData = world.CreeperData;
|
||||
pub const SlimeData = world.SlimeData;
|
||||
pub const EndermanData = world.EndermanData;
|
||||
pub const IronGolemData = world.IronGolemData;
|
||||
pub const FoxData = world.FoxData;
|
||||
pub const AgeableData = world.AgeableData;
|
||||
pub const ZombieData = world.ZombieData;
|
||||
pub const ShulkerData = world.ShulkerData;
|
||||
pub const RaycastResult = world.RaycastResult;
|
||||
pub const RayTraceBlockResult = world.RayTraceBlockResult;
|
||||
pub const RayTraceEntityResult = world.RayTraceEntityResult;
|
||||
pub const BlockDirection = world.BlockDirection;
|
||||
66
src/wit/entity_statuses.zig
Normal file
66
src/wit/entity_statuses.zig
Normal file
@ -0,0 +1,66 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const EntityStatus = enum(u8) {
|
||||
armadillo_peek,
|
||||
armorstand_wobble,
|
||||
body_break,
|
||||
cancel_shake_wetness,
|
||||
chest_break,
|
||||
death,
|
||||
dolphin_looking_for_treasure,
|
||||
drown_particles,
|
||||
eat_grass,
|
||||
end_ram,
|
||||
feet_break,
|
||||
fireworks_explode,
|
||||
fishing_rod_reel_in,
|
||||
fox_eat,
|
||||
full_debug_info,
|
||||
guardian_attack_sound,
|
||||
head_break,
|
||||
honey_jump,
|
||||
honey_slide,
|
||||
in_love_hearts,
|
||||
jump,
|
||||
kinetic_hit,
|
||||
legs_break,
|
||||
love_hearts,
|
||||
mainhand_break,
|
||||
offer_flower,
|
||||
offhand_break,
|
||||
permission_level_admins,
|
||||
permission_level_all,
|
||||
permission_level_gamemasters,
|
||||
permission_level_moderators,
|
||||
permission_level_owners,
|
||||
poof,
|
||||
protected_from_death,
|
||||
ravager_roared,
|
||||
ravager_stunned,
|
||||
reduced_debug_info,
|
||||
saddle_break,
|
||||
shake,
|
||||
shake_wetness,
|
||||
silverfish_merge_anim,
|
||||
sniffer_digging_sound,
|
||||
sonic_charge,
|
||||
squid_anim_synch,
|
||||
start_attacking,
|
||||
start_ram,
|
||||
stop_attacking,
|
||||
stop_offer_flower,
|
||||
swap_hands,
|
||||
taming_failed,
|
||||
taming_succeeded,
|
||||
teleport,
|
||||
tendrils_shiver,
|
||||
tnt_prime,
|
||||
trusting_failed,
|
||||
trusting_succeeded,
|
||||
use_item_complete,
|
||||
villager_angry,
|
||||
villager_happy,
|
||||
villager_sweat,
|
||||
witch_hat_magic,
|
||||
zombie_converting,
|
||||
};
|
||||
162
src/wit/entity_types.zig
Normal file
162
src/wit/entity_types.zig
Normal file
@ -0,0 +1,162 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const EntityType = enum(u8) {
|
||||
acacia_boat,
|
||||
acacia_chest_boat,
|
||||
allay,
|
||||
area_effect_cloud,
|
||||
armadillo,
|
||||
armor_stand,
|
||||
arrow,
|
||||
axolotl,
|
||||
bamboo_chest_raft,
|
||||
bamboo_raft,
|
||||
bat,
|
||||
bee,
|
||||
birch_boat,
|
||||
birch_chest_boat,
|
||||
blaze,
|
||||
block_display,
|
||||
bogged,
|
||||
breeze,
|
||||
breeze_wind_charge,
|
||||
camel,
|
||||
camel_husk,
|
||||
cat,
|
||||
cave_spider,
|
||||
cherry_boat,
|
||||
cherry_chest_boat,
|
||||
chest_minecart,
|
||||
chicken,
|
||||
cod,
|
||||
command_block_minecart,
|
||||
copper_golem,
|
||||
cow,
|
||||
creaking,
|
||||
creeper,
|
||||
dark_oak_boat,
|
||||
dark_oak_chest_boat,
|
||||
dolphin,
|
||||
donkey,
|
||||
dragon_fireball,
|
||||
drowned,
|
||||
egg,
|
||||
elder_guardian,
|
||||
end_crystal,
|
||||
ender_dragon,
|
||||
ender_pearl,
|
||||
enderman,
|
||||
endermite,
|
||||
evoker,
|
||||
evoker_fangs,
|
||||
experience_bottle,
|
||||
experience_orb,
|
||||
eye_of_ender,
|
||||
falling_block,
|
||||
fireball,
|
||||
firework_rocket,
|
||||
fishing_bobber,
|
||||
fox,
|
||||
frog,
|
||||
furnace_minecart,
|
||||
ghast,
|
||||
giant,
|
||||
glow_item_frame,
|
||||
glow_squid,
|
||||
goat,
|
||||
guardian,
|
||||
happy_ghast,
|
||||
hoglin,
|
||||
hopper_minecart,
|
||||
horse,
|
||||
husk,
|
||||
illusioner,
|
||||
interaction,
|
||||
iron_golem,
|
||||
item,
|
||||
item_display,
|
||||
item_frame,
|
||||
jungle_boat,
|
||||
jungle_chest_boat,
|
||||
leash_knot,
|
||||
lightning_bolt,
|
||||
lingering_potion,
|
||||
llama,
|
||||
llama_spit,
|
||||
magma_cube,
|
||||
mangrove_boat,
|
||||
mangrove_chest_boat,
|
||||
mannequin,
|
||||
marker,
|
||||
minecart,
|
||||
mooshroom,
|
||||
mule,
|
||||
nautilus,
|
||||
oak_boat,
|
||||
oak_chest_boat,
|
||||
ocelot,
|
||||
ominous_item_spawner,
|
||||
painting,
|
||||
pale_oak_boat,
|
||||
pale_oak_chest_boat,
|
||||
panda,
|
||||
parched,
|
||||
parrot,
|
||||
phantom,
|
||||
pig,
|
||||
piglin,
|
||||
piglin_brute,
|
||||
pillager,
|
||||
player,
|
||||
polar_bear,
|
||||
pufferfish,
|
||||
rabbit,
|
||||
ravager,
|
||||
salmon,
|
||||
sheep,
|
||||
shulker,
|
||||
shulker_bullet,
|
||||
silverfish,
|
||||
skeleton,
|
||||
skeleton_horse,
|
||||
slime,
|
||||
small_fireball,
|
||||
sniffer,
|
||||
snow_golem,
|
||||
snowball,
|
||||
spawner_minecart,
|
||||
spectral_arrow,
|
||||
spider,
|
||||
splash_potion,
|
||||
spruce_boat,
|
||||
spruce_chest_boat,
|
||||
squid,
|
||||
stray,
|
||||
strider,
|
||||
sulfur_cube,
|
||||
tadpole,
|
||||
text_display,
|
||||
tnt,
|
||||
tnt_minecart,
|
||||
trader_llama,
|
||||
trident,
|
||||
tropical_fish,
|
||||
turtle,
|
||||
vex,
|
||||
villager,
|
||||
vindicator,
|
||||
wandering_trader,
|
||||
warden,
|
||||
wind_charge,
|
||||
witch,
|
||||
wither,
|
||||
wither_skeleton,
|
||||
wither_skull,
|
||||
wolf,
|
||||
zoglin,
|
||||
zombie,
|
||||
zombie_horse,
|
||||
zombie_nautilus,
|
||||
zombie_villager,
|
||||
zombified_piglin,
|
||||
};
|
||||
2454
src/wit/event.zig
Normal file
2454
src/wit/event.zig
Normal file
File diff suppressed because it is too large
Load Diff
217
src/wit/exports.zig
Normal file
217
src/wit/exports.zig
Normal file
@ -0,0 +1,217 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const std = @import("std");
|
||||
const abi = @import("../abi.zig");
|
||||
const context = @import("context.zig");
|
||||
const server = @import("server.zig");
|
||||
const event = @import("event.zig");
|
||||
const command = @import("command.zig");
|
||||
const ipc = @import("ipc.zig");
|
||||
const world = @import("world.zig");
|
||||
const metadata = @import("metadata.zig");
|
||||
|
||||
/// --- Plugin-provided exports ---
|
||||
/// Called by the host once to initialize the plugin.
|
||||
/// Internal use only; plugins should use the `register_plugin!` macro.
|
||||
pub fn initPlugin(comptime impl: fn () void) void {
|
||||
const glue = struct {
|
||||
fn call() callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{});
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "init-plugin" });
|
||||
}
|
||||
|
||||
/// Called when the plugin is being loaded.
|
||||
/// Use this to register commands, events, and perform initial setup.
|
||||
pub fn onLoad(comptime impl: fn (context.Context) abi.Result(void, []const u8)) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{p0});
|
||||
return abi.lowerReturn(abi.Result(void, []const u8), @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "on-load" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_on-load" });
|
||||
}
|
||||
|
||||
/// Called when the plugin is being unloaded.
|
||||
/// Use this to save data and clean up resources.
|
||||
pub fn onUnload(comptime impl: fn (context.Context) abi.Result(void, []const u8)) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{p0});
|
||||
return abi.lowerReturn(abi.Result(void, []const u8), @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "on-unload" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_on-unload" });
|
||||
}
|
||||
|
||||
/// Dispatches an event to the plugin for handling.
|
||||
pub fn handleEvent(comptime impl: fn (u32, server.Server, event.Event) event.Event) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{p0});
|
||||
return abi.lowerReturn(event.Event, @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-event" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_handle-event" });
|
||||
}
|
||||
|
||||
/// Dispatches a command execution to the plugin.
|
||||
pub fn handleCommand(comptime impl: fn (u32, command.CommandSender, server.Server, command.ConsumedArgs) abi.Result(i32, command.CommandError)) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32, p3: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2, p3 });
|
||||
return abi.lowerReturn(abi.Result(i32, command.CommandError), @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-command" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_handle-command" });
|
||||
}
|
||||
|
||||
/// Dispatches a command suggestion request to the plugin.
|
||||
pub fn handleCommandSuggestion(comptime impl: fn (u32, command.CommandSender, server.Server, command.SuggestionRequest) command.CommandSuggestions) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32, p3: i32, p4: i32, p5: i32, p6: i32, p7: i32, p8: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2, p3, p4, p5, p6, p7, p8 });
|
||||
return abi.lowerReturn(command.CommandSuggestions, @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-command-suggestion" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_handle-command-suggestion" });
|
||||
}
|
||||
|
||||
/// Dispatches a scheduled task execution to the plugin.
|
||||
pub fn handleTask(comptime impl: fn (u32, server.Server) void) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32) callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-task" });
|
||||
}
|
||||
|
||||
/// Processes an incoming message from another plugin if possible, and returns (a possibly empty) response.
|
||||
pub fn handleIpcMessage(comptime impl: fn (ipc.PluginId, ipc.IpcMessage) abi.Result(ipc.IpcMessage, []const u8)) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32, p3: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2, p3 });
|
||||
return abi.lowerReturn(abi.Result(ipc.IpcMessage, []const u8), @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ipc-message" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_handle-ipc-message" });
|
||||
}
|
||||
|
||||
pub fn handleAiGoalCanStart(comptime impl: fn (u32, server.Server, world.Entity) bool) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(bool, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ai-goal-can-start" });
|
||||
}
|
||||
|
||||
pub fn handleAiGoalShouldContinue(comptime impl: fn (u32, server.Server, world.Entity) bool) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(bool, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ai-goal-should-continue" });
|
||||
}
|
||||
|
||||
pub fn handleAiGoalStart(comptime impl: fn (u32, server.Server, world.Entity) void) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ai-goal-start" });
|
||||
}
|
||||
|
||||
pub fn handleAiGoalTick(comptime impl: fn (u32, server.Server, world.Entity) void) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ai-goal-tick" });
|
||||
}
|
||||
|
||||
pub fn handleAiGoalStop(comptime impl: fn (u32, server.Server, world.Entity) void) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-ai-goal-stop" });
|
||||
}
|
||||
|
||||
/// Dispatches a chunk generation phase to the plugin.
|
||||
pub fn handleGeneratePhase(comptime impl: fn (u32, world.GenerationPhase, world.ChunkBuffer) void) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32) callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "handle-generate-phase" });
|
||||
}
|
||||
|
||||
pub fn getMetadata(comptime impl: fn () metadata.PluginMetadata) void {
|
||||
const glue = struct {
|
||||
fn call() callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{});
|
||||
return abi.lowerReturn(metadata.PluginMetadata, @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "pumpkin:plugin/metadata@0.1.0#get-metadata" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_pumpkin:plugin/metadata@0.1.0#get-metadata" });
|
||||
}
|
||||
56
src/wit/forms.zig
Normal file
56
src/wit/forms.zig
Normal file
@ -0,0 +1,56 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const text = @import("text.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
|
||||
pub const ImageType = enum(u8) {
|
||||
url,
|
||||
path,
|
||||
};
|
||||
|
||||
pub const FormImage = struct {
|
||||
type: ImageType,
|
||||
data: []const u8,
|
||||
};
|
||||
|
||||
pub const SimpleFormButton = struct {
|
||||
text: TextComponent,
|
||||
image: ?FormImage,
|
||||
};
|
||||
|
||||
pub const SimpleForm = struct {
|
||||
title: TextComponent,
|
||||
content: TextComponent,
|
||||
buttons: []const SimpleFormButton,
|
||||
};
|
||||
|
||||
pub const ModalForm = struct {
|
||||
title: TextComponent,
|
||||
content: TextComponent,
|
||||
button1: TextComponent,
|
||||
button2: TextComponent,
|
||||
};
|
||||
|
||||
pub const CustomFormElement = union(enum) {
|
||||
label: TextComponent,
|
||||
toggle: struct { TextComponent, bool },
|
||||
slider: struct { TextComponent, f32, f32, f32, f32 },
|
||||
/// text, min, max, step, default
|
||||
step_slider: struct { TextComponent, []const []const u8, u32 },
|
||||
/// text, steps, default
|
||||
dropdown: struct { TextComponent, []const []const u8, u32 },
|
||||
/// text, options, default
|
||||
input: struct { TextComponent, []const u8, []const u8 },
|
||||
};
|
||||
|
||||
pub const CustomForm = struct {
|
||||
title: TextComponent,
|
||||
elements: []const CustomFormElement,
|
||||
};
|
||||
|
||||
pub const Form = union(enum) {
|
||||
simple: SimpleForm,
|
||||
modal: ModalForm,
|
||||
custom: CustomForm,
|
||||
};
|
||||
65
src/wit/game_events.zig
Normal file
65
src/wit/game_events.zig
Normal file
@ -0,0 +1,65 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const GameEvent = enum(u8) {
|
||||
block_activate,
|
||||
block_attach,
|
||||
block_change,
|
||||
block_close,
|
||||
block_deactivate,
|
||||
block_destroy,
|
||||
block_detach,
|
||||
block_open,
|
||||
block_place,
|
||||
bounce,
|
||||
container_close,
|
||||
container_open,
|
||||
drink,
|
||||
eat,
|
||||
elytra_glide,
|
||||
entity_damage,
|
||||
entity_die,
|
||||
entity_dismount,
|
||||
entity_interact,
|
||||
entity_mount,
|
||||
entity_place,
|
||||
entity_action,
|
||||
equip,
|
||||
explode,
|
||||
flap,
|
||||
fluid_pickup,
|
||||
fluid_place,
|
||||
hit_ground,
|
||||
instrument_play,
|
||||
item_interact_finish,
|
||||
item_interact_start,
|
||||
jukebox_play,
|
||||
jukebox_stop_play,
|
||||
lightning_strike,
|
||||
note_block_play,
|
||||
prime_fuse,
|
||||
projectile_land,
|
||||
projectile_shoot,
|
||||
sculk_sensor_tendrils_clicking,
|
||||
shear,
|
||||
shriek,
|
||||
splash,
|
||||
step,
|
||||
swim,
|
||||
teleport,
|
||||
unequip,
|
||||
resonate_1,
|
||||
resonate_2,
|
||||
resonate_3,
|
||||
resonate_4,
|
||||
resonate_5,
|
||||
resonate_6,
|
||||
resonate_7,
|
||||
resonate_8,
|
||||
resonate_9,
|
||||
resonate_10,
|
||||
resonate_11,
|
||||
resonate_12,
|
||||
resonate_13,
|
||||
resonate_14,
|
||||
resonate_15,
|
||||
};
|
||||
68
src/wit/game_rules.zig
Normal file
68
src/wit/game_rules.zig
Normal file
@ -0,0 +1,68 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const GameRule = enum(u8) {
|
||||
advance_time,
|
||||
advance_weather,
|
||||
allow_entering_nether_using_portals,
|
||||
block_drops,
|
||||
block_explosion_drop_decay,
|
||||
command_block_output,
|
||||
command_blocks_work,
|
||||
drowning_damage,
|
||||
elytra_movement_check,
|
||||
ender_pearls_vanish_on_death,
|
||||
entity_drops,
|
||||
fall_damage,
|
||||
fire_damage,
|
||||
fire_spread_radius_around_player,
|
||||
forgive_dead_players,
|
||||
freeze_damage,
|
||||
global_sound_events,
|
||||
immediate_respawn,
|
||||
keep_inventory,
|
||||
lava_source_conversion,
|
||||
limited_crafting,
|
||||
locator_bar,
|
||||
log_admin_commands,
|
||||
max_block_modifications,
|
||||
max_command_forks,
|
||||
max_command_sequence_length,
|
||||
max_entity_cramming,
|
||||
max_minecart_speed,
|
||||
max_snow_accumulation_height,
|
||||
mob_drops,
|
||||
mob_explosion_drop_decay,
|
||||
mob_griefing,
|
||||
natural_health_regeneration,
|
||||
player_movement_check,
|
||||
players_nether_portal_creative_delay,
|
||||
players_nether_portal_default_delay,
|
||||
players_sleeping_percentage,
|
||||
projectiles_can_break_blocks,
|
||||
pvp,
|
||||
raids,
|
||||
random_tick_speed,
|
||||
reduced_debug_info,
|
||||
respawn_radius,
|
||||
send_command_feedback,
|
||||
show_advancement_messages,
|
||||
show_death_messages,
|
||||
spawn_mobs,
|
||||
spawn_monsters,
|
||||
spawn_patrols,
|
||||
spawn_phantoms,
|
||||
spawn_wandering_traders,
|
||||
spawn_wardens,
|
||||
spawner_blocks_work,
|
||||
spectators_generate_chunks,
|
||||
spread_vines,
|
||||
tnt_explodes,
|
||||
tnt_explosion_drop_decay,
|
||||
universal_anger,
|
||||
water_source_conversion,
|
||||
};
|
||||
|
||||
pub const GameRuleValue = union(enum) {
|
||||
int: i32,
|
||||
bool: bool,
|
||||
};
|
||||
105
src/wit/gui.zig
Normal file
105
src/wit/gui.zig
Normal file
@ -0,0 +1,105 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const text = @import("text.zig");
|
||||
const common = @import("common.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
const screens = @import("screens.zig");
|
||||
const inventory = @import("inventory.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const ClickType = common.ClickType;
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
pub const Screen = screens.Screen;
|
||||
pub const Inventory = inventory.Inventory;
|
||||
|
||||
pub const Gui = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]gui";
|
||||
|
||||
/// Consumes `title`.
|
||||
pub fn init(@"type": Screen, title: TextComponent) Gui {
|
||||
return abi.call(raw.@"[constructor]gui", Gui, .{ @"type", title });
|
||||
}
|
||||
|
||||
/// Returns the underlying inventory handle for this GUI.
|
||||
pub fn getInventory(self: Gui) Inventory {
|
||||
return abi.call(raw.@"[method]gui.get-inventory", Inventory, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Consumes `item`.
|
||||
pub fn setItem(self: Gui, slot: u32, item: ItemStack) void {
|
||||
return abi.call(raw.@"[method]gui.set-item", void, .{ abi.borrow(self), slot, item });
|
||||
}
|
||||
|
||||
pub fn getItem(self: Gui, slot: u32) ?ItemStack {
|
||||
return abi.call(raw.@"[method]gui.get-item", ?ItemStack, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
/// Returns the type of this GUI.
|
||||
pub fn getType(self: Gui) Screen {
|
||||
return abi.call(raw.@"[method]gui.get-type", Screen, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the title of this GUI.
|
||||
pub fn getTitle(self: Gui) TextComponent {
|
||||
return abi.call(raw.@"[method]gui.get-title", TextComponent, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the number of slots in this GUI.
|
||||
pub fn getSize(self: Gui) u32 {
|
||||
return abi.call(raw.@"[method]gui.get-size", u32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Clears all items from the GUI.
|
||||
pub fn clearItems(self: Gui) void {
|
||||
return abi.call(raw.@"[method]gui.clear-items", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets whether players can grab items out of the inventory.
|
||||
pub fn setAllowGrabItems(self: Gui, allow: bool) void {
|
||||
return abi.call(raw.@"[method]gui.set-allow-grab-items", void, .{ abi.borrow(self), allow });
|
||||
}
|
||||
|
||||
/// Returns whether players can grab items out of the inventory.
|
||||
pub fn getAllowGrabItems(self: Gui) bool {
|
||||
return abi.call(raw.@"[method]gui.get-allow-grab-items", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets whether players can put items into the inventory from their own.
|
||||
pub fn setAllowPutItems(self: Gui, allow: bool) void {
|
||||
return abi.call(raw.@"[method]gui.set-allow-put-items", void, .{ abi.borrow(self), allow });
|
||||
}
|
||||
|
||||
/// Returns whether players can put items into the inventory from their own.
|
||||
pub fn getAllowPutItems(self: Gui) bool {
|
||||
return abi.call(raw.@"[method]gui.get-allow-put-items", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Gui) void {
|
||||
abi.keep(Gui, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Gui) void {
|
||||
abi.drop(Gui, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[constructor]gui"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-inventory"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.set-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-type"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-title"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-size"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.clear-items"(i32) void;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.set-allow-grab-items"(i32, i32) void;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-allow-grab-items"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.set-allow-put-items"(i32, i32) void;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[method]gui.get-allow-put-items"(i32) i32;
|
||||
extern "pumpkin:plugin/gui@0.1.0" fn @"[resource-drop]gui"(i32) void;
|
||||
};
|
||||
33
src/wit/i18n.zig
Normal file
33
src/wit/i18n.zig
Normal file
@ -0,0 +1,33 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const common = @import("common.zig");
|
||||
|
||||
pub const Locale = common.Locale;
|
||||
|
||||
/// Retrieves a translated string from the host.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `key`: The namespaced translation key (e.g. `pumpkin:my_key`).
|
||||
/// * `locale`: The target locale.
|
||||
///
|
||||
/// # Returns
|
||||
/// The localized string, falling back to English or the key itself.
|
||||
pub fn translate(key: []const u8, locale: Locale) []const u8 {
|
||||
return abi.call(raw.translate, []const u8, .{ key, locale });
|
||||
}
|
||||
|
||||
/// Loads custom translations from a JSON string.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `namespace`: The namespace to associate these keys with.
|
||||
/// * `json`: A JSON string containing a flat map of translations.
|
||||
/// * `locale`: The target locale for these translations.
|
||||
pub fn loadTranslations(namespace: []const u8, json: []const u8, locale: Locale) void {
|
||||
return abi.call(raw.@"load-translations", void, .{ namespace, json, locale });
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/i18n@0.1.0" fn translate(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/i18n@0.1.0" fn @"load-translations"(i32, i32, i32, i32, i32) void;
|
||||
};
|
||||
206
src/wit/inventory.zig
Normal file
206
src/wit/inventory.zig
Normal file
@ -0,0 +1,206 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
const common = @import("common.zig");
|
||||
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
pub const Hand = common.Hand;
|
||||
|
||||
/// Common inventory resource used across GUIs, player inventories, and containers.
|
||||
pub const Inventory = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]inventory";
|
||||
|
||||
/// Returns the number of slots in this inventory.
|
||||
pub fn getSize(self: Inventory) u32 {
|
||||
return abi.call(raw.@"[method]inventory.get-size", u32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns true if all slots in this inventory are empty.
|
||||
pub fn isEmpty(self: Inventory) bool {
|
||||
return abi.call(raw.@"[method]inventory.is-empty", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the item in the specified slot index, or none if empty.
|
||||
pub fn getItem(self: Inventory, slot: u32) ?ItemStack {
|
||||
return abi.call(raw.@"[method]inventory.get-item", ?ItemStack, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
/// Sets the item in the specified slot index.
|
||||
pub fn setItem(self: Inventory, slot: u32, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]inventory.set-item", void, .{ abi.borrow(self), slot, item });
|
||||
}
|
||||
|
||||
/// Removes and returns the item in the specified slot index.
|
||||
pub fn removeItem(self: Inventory, slot: u32) ?ItemStack {
|
||||
return abi.call(raw.@"[method]inventory.remove-item", ?ItemStack, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
/// Clears all items from this inventory.
|
||||
pub fn clear(self: Inventory) void {
|
||||
return abi.call(raw.@"[method]inventory.clear", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns all items in this inventory as a list of slots.
|
||||
pub fn getAllItems(self: Inventory) []const ?ItemStack {
|
||||
return abi.call(raw.@"[method]inventory.get-all-items", []const ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets all items in this inventory from a list.
|
||||
pub fn setAllItems(self: Inventory, items: []const ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]inventory.set-all-items", void, .{ abi.borrow(self), items });
|
||||
}
|
||||
|
||||
/// Counts the total number of items with the given ID in this inventory.
|
||||
pub fn countItem(self: Inventory, item_id: []const u8) u32 {
|
||||
return abi.call(raw.@"[method]inventory.count-item", u32, .{ abi.borrow(self), item_id });
|
||||
}
|
||||
|
||||
/// Checks if the inventory contains at least one item with the given ID.
|
||||
pub fn containsItem(self: Inventory, item_id: []const u8) bool {
|
||||
return abi.call(raw.@"[method]inventory.contains-item", bool, .{ abi.borrow(self), item_id });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Inventory) void {
|
||||
abi.keep(Inventory, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Inventory) void {
|
||||
abi.drop(Inventory, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialized player inventory handle providing access to main inventory, armor, offhand, and hotbar.
|
||||
pub const PlayerInventory = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]player-inventory";
|
||||
|
||||
/// Returns the generic 36-slot inventory handle (hotbar + main storage).
|
||||
pub fn asInventory(self: PlayerInventory) Inventory {
|
||||
return abi.call(raw.@"[method]player-inventory.as-inventory", Inventory, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the item currently held in the specified hand.
|
||||
pub fn getItemInHand(self: PlayerInventory, hand: Hand) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-item-in-hand", ?ItemStack, .{ abi.borrow(self), hand });
|
||||
}
|
||||
|
||||
/// Sets the item in the specified hand.
|
||||
pub fn setItemInHand(self: PlayerInventory, hand: Hand, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-item-in-hand", void, .{ abi.borrow(self), hand, item });
|
||||
}
|
||||
|
||||
/// Returns the currently selected hotbar slot index (0-8).
|
||||
pub fn getSelectedSlot(self: PlayerInventory) u8 {
|
||||
return abi.call(raw.@"[method]player-inventory.get-selected-slot", u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the currently selected hotbar slot index (0-8).
|
||||
pub fn setSelectedSlot(self: PlayerInventory, slot: u8) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-selected-slot", void, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
/// Armor slot accessors
|
||||
pub fn getHelmet(self: PlayerInventory) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-helmet", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setHelmet(self: PlayerInventory, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-helmet", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn getChestplate(self: PlayerInventory) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-chestplate", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setChestplate(self: PlayerInventory, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-chestplate", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn getLeggings(self: PlayerInventory) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-leggings", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setLeggings(self: PlayerInventory, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-leggings", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn getBoots(self: PlayerInventory) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-boots", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setBoots(self: PlayerInventory, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-boots", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn getOffHand(self: PlayerInventory) ?ItemStack {
|
||||
return abi.call(raw.@"[method]player-inventory.get-off-hand", ?ItemStack, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn setOffHand(self: PlayerInventory, item: ?ItemStack) void {
|
||||
return abi.call(raw.@"[method]player-inventory.set-off-hand", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
/// Clears all armor slots.
|
||||
pub fn clearArmor(self: PlayerInventory) void {
|
||||
return abi.call(raw.@"[method]player-inventory.clear-armor", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Clears the 36 main inventory slots.
|
||||
pub fn clearMain(self: PlayerInventory) void {
|
||||
return abi.call(raw.@"[method]player-inventory.clear-main", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Clears all slots (main inventory, armor, offhand).
|
||||
pub fn clearAll(self: PlayerInventory) void {
|
||||
return abi.call(raw.@"[method]player-inventory.clear-all", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: PlayerInventory) void {
|
||||
abi.keep(PlayerInventory, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: PlayerInventory) void {
|
||||
abi.drop(PlayerInventory, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.get-size"(i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.is-empty"(i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.get-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.set-item"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.remove-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.clear"(i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.get-all-items"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.set-all-items"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.count-item"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]inventory.contains-item"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.as-inventory"(i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-item-in-hand"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-item-in-hand"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-selected-slot"(i32) i32;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-selected-slot"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-helmet"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-helmet"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-chestplate"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-chestplate"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-leggings"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-leggings"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-boots"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-boots"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.get-off-hand"(i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.set-off-hand"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.clear-armor"(i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.clear-main"(i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[method]player-inventory.clear-all"(i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[resource-drop]inventory"(i32) void;
|
||||
extern "pumpkin:plugin/inventory@0.1.0" fn @"[resource-drop]player-inventory"(i32) void;
|
||||
};
|
||||
16
src/wit/ipc.zig
Normal file
16
src/wit/ipc.zig
Normal file
@ -0,0 +1,16 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
|
||||
pub const PluginId = []const u8;
|
||||
|
||||
pub const IpcMessage = []const u8;
|
||||
|
||||
/// Sends a message to the specified plugin, synchronously receiving a response (or an error).
|
||||
pub fn sendIpcMessage(recipient: PluginId, message: IpcMessage) abi.Result(abi.Result(IpcMessage, []const u8), void) {
|
||||
return abi.call(raw.@"send-ipc-message", abi.Result(abi.Result(IpcMessage, []const u8), void), .{ recipient, message });
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/ipc@0.1.0" fn @"send-ipc-message"(i32, i32, i32, i32, i32) void;
|
||||
};
|
||||
239
src/wit/item_stack.zig
Normal file
239
src/wit/item_stack.zig
Normal file
@ -0,0 +1,239 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const attributes = @import("attributes.zig");
|
||||
const data_components = @import("data_components.zig");
|
||||
const enchantments = @import("enchantments.zig");
|
||||
const text = @import("text.zig");
|
||||
const common = @import("common.zig");
|
||||
|
||||
pub const Attribute = attributes.Attribute;
|
||||
pub const AttributeModifier = attributes.AttributeModifier;
|
||||
pub const DataComponent = data_components.DataComponent;
|
||||
pub const AttributeModifierSlot = enchantments.AttributeModifierSlot;
|
||||
pub const Enchantment = enchantments.Enchantment;
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const NbtEntry = common.NbtEntry;
|
||||
pub const NbtTree = common.NbtTree;
|
||||
pub const NbtTag = common.NbtTag;
|
||||
|
||||
/// Represents an enchantment and its level.
|
||||
pub const EnchantmentValue = struct {
|
||||
enchantment: Enchantment,
|
||||
level: u32,
|
||||
};
|
||||
|
||||
/// Represents a custom enchantment and its level on an item stack.
|
||||
pub const CustomEnchantmentValue = struct {
|
||||
enchantment_id: []const u8,
|
||||
level: u32,
|
||||
};
|
||||
|
||||
/// Represents an attribute modifier applied to an item stack for a specific slot.
|
||||
pub const ItemAttributeModifier = struct {
|
||||
attribute: Attribute,
|
||||
modifier: AttributeModifier,
|
||||
slot: AttributeModifierSlot,
|
||||
};
|
||||
|
||||
/// Represents a data component and its serialized value.
|
||||
pub const DataComponentValue = struct {
|
||||
component: DataComponent,
|
||||
/// The serialized value of the component.
|
||||
value: []const u8,
|
||||
};
|
||||
|
||||
pub const ItemStack = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]item-stack";
|
||||
|
||||
pub fn init(registry_key: []const u8, count: u8) ItemStack {
|
||||
return abi.call(raw.@"[constructor]item-stack", ItemStack, .{ registry_key, count });
|
||||
}
|
||||
|
||||
/// Returns the unique registry key of the item (e.g., "minecraft:diamond").
|
||||
pub fn getRegistryKey(self: ItemStack) []const u8 {
|
||||
return abi.call(raw.@"[method]item-stack.get-registry-key", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the number of items in the stack.
|
||||
pub fn getCount(self: ItemStack) u8 {
|
||||
return abi.call(raw.@"[method]item-stack.get-count", u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the number of items in the stack.
|
||||
pub fn setCount(self: ItemStack, count: u8) void {
|
||||
return abi.call(raw.@"[method]item-stack.set-count", void, .{ abi.borrow(self), count });
|
||||
}
|
||||
|
||||
/// Returns the maximum number of items that can be in this stack.
|
||||
pub fn getMaxCount(self: ItemStack) u8 {
|
||||
return abi.call(raw.@"[method]item-stack.get-max-count", u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns all enchantments on this item stack.
|
||||
pub fn getEnchantments(self: ItemStack) []const EnchantmentValue {
|
||||
return abi.call(raw.@"[method]item-stack.get-enchantments", []const EnchantmentValue, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Adds an enchantment to this item stack.
|
||||
pub fn addEnchantment(self: ItemStack, enchantment: Enchantment, level: u32) void {
|
||||
return abi.call(raw.@"[method]item-stack.add-enchantment", void, .{ abi.borrow(self), enchantment, level });
|
||||
}
|
||||
|
||||
/// Removes an enchantment from this item stack.
|
||||
pub fn removeEnchantment(self: ItemStack, enchantment: Enchantment) void {
|
||||
return abi.call(raw.@"[method]item-stack.remove-enchantment", void, .{ abi.borrow(self), enchantment });
|
||||
}
|
||||
|
||||
/// Returns all custom enchantments on this item stack.
|
||||
pub fn getCustomEnchantments(self: ItemStack) []const CustomEnchantmentValue {
|
||||
return abi.call(raw.@"[method]item-stack.get-custom-enchantments", []const CustomEnchantmentValue, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Adds a custom enchantment to this item stack.
|
||||
pub fn addCustomEnchantment(self: ItemStack, enchantment_id: []const u8, level: u32) void {
|
||||
return abi.call(raw.@"[method]item-stack.add-custom-enchantment", void, .{ abi.borrow(self), enchantment_id, level });
|
||||
}
|
||||
|
||||
/// Removes a custom enchantment from this item stack.
|
||||
pub fn removeCustomEnchantment(self: ItemStack, enchantment_id: []const u8) void {
|
||||
return abi.call(raw.@"[method]item-stack.remove-custom-enchantment", void, .{ abi.borrow(self), enchantment_id });
|
||||
}
|
||||
|
||||
/// Returns the level of a custom enchantment on this item stack, if present.
|
||||
pub fn getCustomEnchantmentLevel(self: ItemStack, enchantment_id: []const u8) ?u32 {
|
||||
return abi.call(raw.@"[method]item-stack.get-custom-enchantment-level", ?u32, .{ abi.borrow(self), enchantment_id });
|
||||
}
|
||||
|
||||
/// Returns whether this item stack has a specific custom enchantment.
|
||||
pub fn hasCustomEnchantment(self: ItemStack, enchantment_id: []const u8) bool {
|
||||
return abi.call(raw.@"[method]item-stack.has-custom-enchantment", bool, .{ abi.borrow(self), enchantment_id });
|
||||
}
|
||||
|
||||
/// Returns all attribute modifiers on this item stack.
|
||||
pub fn getAttributeModifiers(self: ItemStack) []const ItemAttributeModifier {
|
||||
return abi.call(raw.@"[method]item-stack.get-attribute-modifiers", []const ItemAttributeModifier, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Adds an attribute modifier to this item stack.
|
||||
pub fn addAttributeModifier(self: ItemStack, modifier: ItemAttributeModifier) void {
|
||||
return abi.call(raw.@"[method]item-stack.add-attribute-modifier", void, .{ abi.borrow(self), modifier });
|
||||
}
|
||||
|
||||
/// Removes all attribute modifiers for a specific attribute from this item stack.
|
||||
pub fn removeAttributeModifiers(self: ItemStack, attribute: Attribute) void {
|
||||
return abi.call(raw.@"[method]item-stack.remove-attribute-modifiers", void, .{ abi.borrow(self), attribute });
|
||||
}
|
||||
|
||||
/// Clears all custom attribute modifiers from this item stack.
|
||||
pub fn clearAttributeModifiers(self: ItemStack) void {
|
||||
return abi.call(raw.@"[method]item-stack.clear-attribute-modifiers", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the lore of this item stack.
|
||||
pub fn getLore(self: ItemStack) []const TextComponent {
|
||||
return abi.call(raw.@"[method]item-stack.get-lore", []const TextComponent, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the lore of this item stack.
|
||||
pub fn setLore(self: ItemStack, lore: []const TextComponent) void {
|
||||
return abi.call(raw.@"[method]item-stack.set-lore", void, .{ abi.borrow(self), lore });
|
||||
}
|
||||
|
||||
/// Adds a line to the lore of this item stack.
|
||||
///
|
||||
/// Consumes `line`.
|
||||
pub fn addLore(self: ItemStack, line: TextComponent) void {
|
||||
return abi.call(raw.@"[method]item-stack.add-lore", void, .{ abi.borrow(self), line });
|
||||
}
|
||||
|
||||
/// Returns the custom name of this item stack, if set.
|
||||
pub fn getCustomName(self: ItemStack) ?TextComponent {
|
||||
return abi.call(raw.@"[method]item-stack.get-custom-name", ?TextComponent, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets the custom name of this item stack.
|
||||
pub fn setCustomName(self: ItemStack, name: ?TextComponent) void {
|
||||
return abi.call(raw.@"[method]item-stack.set-custom-name", void, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Sets a namespaced custom data value on this item stack.
|
||||
pub fn setCustomData(self: ItemStack, namespace: []const u8, key: []const u8, value: NbtTree) void {
|
||||
return abi.call(raw.@"[method]item-stack.set-custom-data", void, .{ abi.borrow(self), namespace, key, value });
|
||||
}
|
||||
|
||||
/// Returns a namespaced custom data value from this item stack, if set.
|
||||
pub fn getCustomData(self: ItemStack, namespace: []const u8, key: []const u8) ?NbtTree {
|
||||
return abi.call(raw.@"[method]item-stack.get-custom-data", ?NbtTree, .{ abi.borrow(self), namespace, key });
|
||||
}
|
||||
|
||||
/// Removes a namespaced custom data value from this item stack.
|
||||
pub fn removeCustomData(self: ItemStack, namespace: []const u8, key: []const u8) void {
|
||||
return abi.call(raw.@"[method]item-stack.remove-custom-data", void, .{ abi.borrow(self), namespace, key });
|
||||
}
|
||||
|
||||
/// Returns whether this item stack has a namespaced custom data value.
|
||||
pub fn hasCustomData(self: ItemStack, namespace: []const u8, key: []const u8) bool {
|
||||
return abi.call(raw.@"[method]item-stack.has-custom-data", bool, .{ abi.borrow(self), namespace, key });
|
||||
}
|
||||
|
||||
/// Returns all data components on this item stack.
|
||||
pub fn getComponents(self: ItemStack) []const DataComponentValue {
|
||||
return abi.call(raw.@"[method]item-stack.get-components", []const DataComponentValue, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Sets a data component on this item stack.
|
||||
pub fn setComponent(self: ItemStack, component: DataComponent, value: []const u8) void {
|
||||
return abi.call(raw.@"[method]item-stack.set-component", void, .{ abi.borrow(self), component, value });
|
||||
}
|
||||
|
||||
/// Removes a data component from this item stack.
|
||||
pub fn removeComponent(self: ItemStack, component: DataComponent) void {
|
||||
return abi.call(raw.@"[method]item-stack.remove-component", void, .{ abi.borrow(self), component });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: ItemStack) void {
|
||||
abi.keep(ItemStack, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: ItemStack) void {
|
||||
abi.drop(ItemStack, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[constructor]item-stack"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-registry-key"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-count"(i32) i32;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.set-count"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-max-count"(i32) i32;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-enchantments"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.add-enchantment"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.remove-enchantment"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-custom-enchantments"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.add-custom-enchantment"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.remove-custom-enchantment"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-custom-enchantment-level"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.has-custom-enchantment"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-attribute-modifiers"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.add-attribute-modifier"(i32, i32, i32, i32, f64, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.remove-attribute-modifiers"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.clear-attribute-modifiers"(i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-lore"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.set-lore"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.add-lore"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-custom-name"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.set-custom-name"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.set-custom-data"(i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-custom-data"(i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.remove-custom-data"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.has-custom-data"(i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.get-components"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.set-component"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[method]item-stack.remove-component"(i32, i32) void;
|
||||
extern "pumpkin:plugin/item-stack@0.1.0" fn @"[resource-drop]item-stack"(i32) void;
|
||||
};
|
||||
155
src/wit/java_dialogs.zig
Normal file
155
src/wit/java_dialogs.zig
Normal file
@ -0,0 +1,155 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const text = @import("text.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
|
||||
/// Represents the layout and button configuration of a dialog.
|
||||
pub const DialogType = enum(u8) {
|
||||
/// A simple dialog with a single "OK" button.
|
||||
notice,
|
||||
/// A dialog with "Yes" and "No" buttons.
|
||||
confirmation,
|
||||
/// A scrollable list of custom buttons.
|
||||
multi_action,
|
||||
/// A list of buttons that open other registered dialogs.
|
||||
dialog_list,
|
||||
/// A dedicated menu for displaying server-related links.
|
||||
server_links,
|
||||
};
|
||||
|
||||
/// Represents an element in the main content area of a dialog.
|
||||
pub const DialogBody = union(enum) {
|
||||
/// A simple text message.
|
||||
plain_message: TextComponent,
|
||||
/// A visual item display.
|
||||
item: ItemStack,
|
||||
};
|
||||
|
||||
/// A checkbox input control.
|
||||
pub const DialogInputBool = struct {
|
||||
label: TextComponent,
|
||||
default_value: bool,
|
||||
};
|
||||
|
||||
/// A text field input control.
|
||||
pub const DialogInputText = struct {
|
||||
label: TextComponent,
|
||||
placeholder: TextComponent,
|
||||
default_value: []const u8,
|
||||
};
|
||||
|
||||
/// A numerical range slider input control.
|
||||
pub const DialogInputNumberRange = struct {
|
||||
label: TextComponent,
|
||||
min_value: f32,
|
||||
max_value: f32,
|
||||
initial_value: f32,
|
||||
step: f32,
|
||||
label_format: ?[]const u8,
|
||||
};
|
||||
|
||||
/// A multiple-choice selection input control.
|
||||
pub const DialogInputSingleOption = struct {
|
||||
label: TextComponent,
|
||||
options: []const TextComponent,
|
||||
initial_index: u32,
|
||||
};
|
||||
|
||||
/// Represents an interactive input control in a dialog.
|
||||
pub const DialogInput = union(enum) {
|
||||
/// A checkbox for true/false states.
|
||||
bool: DialogInputBool,
|
||||
/// A simple string input field.
|
||||
text: DialogInputText,
|
||||
/// A slider for numerical input within a range.
|
||||
number_range: DialogInputNumberRange,
|
||||
/// A multiple-choice selection button.
|
||||
single_option: DialogInputSingleOption,
|
||||
};
|
||||
|
||||
/// Defines what happens after a dialog is closed.
|
||||
pub const AfterAction = enum(u8) {
|
||||
/// Returns the player to the previous screen (e.g., keeping an inventory open).
|
||||
peek,
|
||||
/// Closes all open screens.
|
||||
pop,
|
||||
};
|
||||
|
||||
/// Represents a custom server-side action.
|
||||
pub const CustomClickAction = struct {
|
||||
/// A unique identifier for the action (sent back to the server).
|
||||
id: []const u8,
|
||||
/// Optional binary data to send with the action.
|
||||
payload: ?[]const u8,
|
||||
};
|
||||
|
||||
/// Represents an action triggered by a button click.
|
||||
pub const Action = union(enum) {
|
||||
/// Opens an external URL.
|
||||
open_url: []const u8,
|
||||
/// Triggers a custom server-side callback with an ID and optional payload.
|
||||
custom_click: CustomClickAction,
|
||||
};
|
||||
|
||||
/// Represents a clickable button in a dialog.
|
||||
pub const ActionButton = struct {
|
||||
text: TextComponent,
|
||||
tooltip: ?TextComponent,
|
||||
width: ?u32,
|
||||
action: Action,
|
||||
};
|
||||
|
||||
/// Built-in link types recognized by the Java Edition client.
|
||||
pub const LinkType = enum(u8) {
|
||||
bug_report,
|
||||
community_guidelines,
|
||||
support,
|
||||
status,
|
||||
feedback,
|
||||
community,
|
||||
website,
|
||||
forums,
|
||||
news,
|
||||
announcements,
|
||||
};
|
||||
|
||||
/// The label for a link, which can be a built-in type or custom text.
|
||||
pub const LinkLabel = union(enum) {
|
||||
/// A built-in link type with a predefined icon/label.
|
||||
built_in: LinkType,
|
||||
/// A custom text component label.
|
||||
custom: TextComponent,
|
||||
};
|
||||
|
||||
/// Represents a link displayed in a Java Edition dialog.
|
||||
pub const Link = struct {
|
||||
/// The label to display for the link.
|
||||
label: LinkLabel,
|
||||
/// The URL the link points to.
|
||||
url: []const u8,
|
||||
};
|
||||
|
||||
/// Represents a dialog shown to a Java Edition player.
|
||||
pub const Dialog = struct {
|
||||
/// The main title of the dialog.
|
||||
title: TextComponent,
|
||||
/// The layout type of the dialog.
|
||||
type: DialogType,
|
||||
/// A list of body elements to display in the main area.
|
||||
body: []const DialogBody,
|
||||
/// A list of interactive input controls.
|
||||
inputs: []const DialogInput,
|
||||
/// A list of clickable buttons (for multi-action and other types).
|
||||
buttons: []const ActionButton,
|
||||
/// A list of links (primarily for server-links type).
|
||||
links: []const Link,
|
||||
/// What to do after the dialog is closed.
|
||||
after_action: ?AfterAction,
|
||||
/// Whether the player can exit the dialog using the Esc key.
|
||||
can_close_with_escape: bool,
|
||||
/// The text shown on buttons that link to/open this dialog.
|
||||
external_title: ?TextComponent,
|
||||
};
|
||||
2145
src/wit/java_packets.zig
Normal file
2145
src/wit/java_packets.zig
Normal file
File diff suppressed because it is too large
Load Diff
26
src/wit/logging.zig
Normal file
26
src/wit/logging.zig
Normal file
@ -0,0 +1,26 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
|
||||
pub const Level = enum(u8) {
|
||||
trace,
|
||||
debug,
|
||||
info,
|
||||
warn,
|
||||
@"error",
|
||||
};
|
||||
|
||||
/// log any general purpose message
|
||||
pub fn log(level: Level, message: []const u8) void {
|
||||
return abi.call(raw.log, void, .{ level, message });
|
||||
}
|
||||
|
||||
/// This function is meant to be used by the tracing crate.
|
||||
pub fn logTracing(event: []const u8) void {
|
||||
return abi.call(raw.@"log-tracing", void, .{event});
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/logging@0.1.0" fn log(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/logging@0.1.0" fn @"log-tracing"(i32, i32) void;
|
||||
};
|
||||
16
src/wit/metadata.zig
Normal file
16
src/wit/metadata.zig
Normal file
@ -0,0 +1,16 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const PluginMetadata = struct {
|
||||
/// Name of the plugin.
|
||||
name: []const u8,
|
||||
/// Plugin version (semver).
|
||||
version: []const u8,
|
||||
/// Plugin authors.
|
||||
authors: []const []const u8,
|
||||
/// Short description of the plugin.
|
||||
description: []const u8,
|
||||
/// Plugin dependencies.
|
||||
dependencies: []const []const u8,
|
||||
/// Permissions requested by the plugin.
|
||||
permissions: []const []const u8,
|
||||
};
|
||||
129
src/wit/particles.zig
Normal file
129
src/wit/particles.zig
Normal file
@ -0,0 +1,129 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const Particle = enum(u8) {
|
||||
angry_villager,
|
||||
block,
|
||||
block_marker,
|
||||
bubble,
|
||||
sulfur_bubbles,
|
||||
noxious_gas,
|
||||
noxious_gas_cloud,
|
||||
geyser,
|
||||
geyser_base,
|
||||
geyser_poof,
|
||||
geyser_plume,
|
||||
cloud,
|
||||
copper_fire_flame,
|
||||
crit,
|
||||
damage_indicator,
|
||||
dragon_breath,
|
||||
dripping_lava,
|
||||
falling_lava,
|
||||
landing_lava,
|
||||
dripping_water,
|
||||
falling_water,
|
||||
dust,
|
||||
dust_color_transition,
|
||||
effect,
|
||||
elder_guardian,
|
||||
enchanted_hit,
|
||||
enchant,
|
||||
end_rod,
|
||||
entity_effect,
|
||||
explosion_emitter,
|
||||
explosion,
|
||||
gust,
|
||||
small_gust,
|
||||
gust_emitter_large,
|
||||
gust_emitter_small,
|
||||
sonic_boom,
|
||||
falling_dust,
|
||||
firework,
|
||||
fishing,
|
||||
flame,
|
||||
infested,
|
||||
cherry_leaves,
|
||||
pale_oak_leaves,
|
||||
tinted_leaves,
|
||||
sculk_soul,
|
||||
sculk_charge,
|
||||
sculk_charge_pop,
|
||||
soul_fire_flame,
|
||||
soul,
|
||||
flash,
|
||||
happy_villager,
|
||||
composter,
|
||||
heart,
|
||||
instant_effect,
|
||||
item,
|
||||
vibration,
|
||||
trail,
|
||||
pause_mob_growth,
|
||||
reset_mob_growth,
|
||||
item_slime,
|
||||
item_cobweb,
|
||||
item_snowball,
|
||||
large_smoke,
|
||||
lava,
|
||||
mycelium,
|
||||
note,
|
||||
poof,
|
||||
portal,
|
||||
rain,
|
||||
smoke,
|
||||
white_smoke,
|
||||
sneeze,
|
||||
spit,
|
||||
squid_ink,
|
||||
sweep_attack,
|
||||
totem_of_undying,
|
||||
underwater,
|
||||
splash,
|
||||
witch,
|
||||
bubble_pop,
|
||||
current_down,
|
||||
bubble_column_up,
|
||||
nautilus,
|
||||
dolphin,
|
||||
campfire_cosy_smoke,
|
||||
campfire_signal_smoke,
|
||||
dripping_honey,
|
||||
falling_honey,
|
||||
landing_honey,
|
||||
falling_nectar,
|
||||
falling_spore_blossom,
|
||||
ash,
|
||||
crimson_spore,
|
||||
warped_spore,
|
||||
spore_blossom_air,
|
||||
dripping_obsidian_tear,
|
||||
falling_obsidian_tear,
|
||||
landing_obsidian_tear,
|
||||
reverse_portal,
|
||||
white_ash,
|
||||
small_flame,
|
||||
snowflake,
|
||||
dripping_dripstone_lava,
|
||||
falling_dripstone_lava,
|
||||
dripping_dripstone_water,
|
||||
falling_dripstone_water,
|
||||
glow_squid_ink,
|
||||
glow,
|
||||
wax_on,
|
||||
wax_off,
|
||||
electric_spark,
|
||||
scrape,
|
||||
shriek,
|
||||
egg_crack,
|
||||
dust_plume,
|
||||
trial_spawner_detection,
|
||||
trial_spawner_detection_ominous,
|
||||
vault_connection,
|
||||
dust_pillar,
|
||||
ominous_spawning,
|
||||
raid_omen,
|
||||
trial_omen,
|
||||
block_crumble,
|
||||
firefly,
|
||||
sulfur_cube_goo,
|
||||
};
|
||||
46
src/wit/permission.zig
Normal file
46
src/wit/permission.zig
Normal file
@ -0,0 +1,46 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
/// Represents the player's permission level
|
||||
///
|
||||
/// Permission levels determine the player's access to commands and server operations.
|
||||
/// Each numeric level corresponds to a specific role:
|
||||
/// - `Zero`: `normal`: Player can use basic commands.
|
||||
/// - `One`: `moderator`: Player can bypass spawn protection.
|
||||
/// - `Two`: `gamemaster`: Player or executor can use more commands and player can use command blocks.
|
||||
/// - `Three`: `admin`: Player or executor can use commands related to multiplayer management.
|
||||
/// - `Four`: `owner`: Player or executor can use all of the commands, including commands related to server management.
|
||||
pub const PermissionLevel = enum(u8) {
|
||||
zero,
|
||||
one,
|
||||
two,
|
||||
three,
|
||||
four,
|
||||
};
|
||||
|
||||
/// Describes the default behavior for permissions
|
||||
pub const PermissionDefault = union(enum) {
|
||||
/// Permission is not granted by default
|
||||
deny,
|
||||
/// Permission is granted by default
|
||||
allow,
|
||||
/// Permission is granted by default to operators
|
||||
op: PermissionLevel,
|
||||
};
|
||||
|
||||
/// A child permission entry
|
||||
pub const PermissionChild = struct {
|
||||
node: []const u8,
|
||||
value: bool,
|
||||
};
|
||||
|
||||
/// Defines a permission node in the system
|
||||
pub const Permission = struct {
|
||||
/// The full node name (e.g., "minecraft:command.gamemode")
|
||||
node: []const u8,
|
||||
/// Description of what this permission does
|
||||
description: []const u8,
|
||||
/// The default value of this permission
|
||||
default: PermissionDefault,
|
||||
/// Children nodes that are affected by this permission
|
||||
children: []const PermissionChild,
|
||||
};
|
||||
2193
src/wit/player.zig
Normal file
2193
src/wit/player.zig
Normal file
File diff suppressed because it is too large
Load Diff
50
src/wit/potions.zig
Normal file
50
src/wit/potions.zig
Normal file
@ -0,0 +1,50 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const PotionType = enum(u8) {
|
||||
water,
|
||||
mundane,
|
||||
thick,
|
||||
awkward,
|
||||
night_vision,
|
||||
long_night_vision,
|
||||
invisibility,
|
||||
long_invisibility,
|
||||
leaping,
|
||||
long_leaping,
|
||||
strong_leaping,
|
||||
fire_resistance,
|
||||
long_fire_resistance,
|
||||
swiftness,
|
||||
long_swiftness,
|
||||
strong_swiftness,
|
||||
slowness,
|
||||
long_slowness,
|
||||
strong_slowness,
|
||||
turtle_master,
|
||||
long_turtle_master,
|
||||
strong_turtle_master,
|
||||
water_breathing,
|
||||
long_water_breathing,
|
||||
healing,
|
||||
strong_healing,
|
||||
harming,
|
||||
strong_harming,
|
||||
poison,
|
||||
long_poison,
|
||||
strong_poison,
|
||||
regeneration,
|
||||
long_regeneration,
|
||||
strong_regeneration,
|
||||
strength,
|
||||
long_strength,
|
||||
strong_strength,
|
||||
weakness,
|
||||
long_weakness,
|
||||
luck,
|
||||
slow_falling,
|
||||
long_slow_falling,
|
||||
wind_charged,
|
||||
weaving,
|
||||
oozing,
|
||||
infested,
|
||||
};
|
||||
117
src/wit/recipe.zig
Normal file
117
src/wit/recipe.zig
Normal file
@ -0,0 +1,117 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const item_stack = @import("item_stack.zig");
|
||||
|
||||
pub const ItemStack = item_stack.ItemStack;
|
||||
|
||||
/// Recipe category for the recipe book.
|
||||
pub const RecipeCategory = enum(u8) {
|
||||
building,
|
||||
redstone,
|
||||
equipment,
|
||||
misc,
|
||||
food,
|
||||
blocks,
|
||||
};
|
||||
|
||||
/// Represents an ingredient in a recipe.
|
||||
pub const Ingredient = union(enum) {
|
||||
/// A specific item (e.g. "minecraft:diamond").
|
||||
item: []const u8,
|
||||
/// A tag group of items (e.g., "minecraft:logs").
|
||||
tag: []const u8,
|
||||
/// One of multiple specific items.
|
||||
one_of: []const []const u8,
|
||||
};
|
||||
|
||||
/// Represents a shaped crafting recipe.
|
||||
pub const ShapedRecipe = struct {
|
||||
/// The pattern of the recipe (e.g., ["# #", " s ", "# #"]).
|
||||
pattern: []const []const u8,
|
||||
/// Mapping of characters in the pattern to ingredients.
|
||||
key: []const struct { []const u8, Ingredient },
|
||||
/// The resulting item stack.
|
||||
output: ItemStack,
|
||||
/// The recipe group (optional).
|
||||
group: ?[]const u8,
|
||||
/// The recipe category in the recipe book.
|
||||
category: ?RecipeCategory,
|
||||
/// Whether to show a toast notification when the recipe is unlocked.
|
||||
show_notification: ?bool,
|
||||
};
|
||||
|
||||
/// Represents a shapeless crafting recipe.
|
||||
pub const ShapelessRecipe = struct {
|
||||
/// The list of ingredients required.
|
||||
ingredients: []const Ingredient,
|
||||
/// The resulting item stack.
|
||||
output: ItemStack,
|
||||
/// The recipe group (optional).
|
||||
group: ?[]const u8,
|
||||
/// The recipe category in the recipe book.
|
||||
category: ?RecipeCategory,
|
||||
};
|
||||
|
||||
/// Represents a cooking recipe (Smelting, Blasting, Smoking, Campfire).
|
||||
pub const CookingRecipe = struct {
|
||||
/// The ingredient to cook.
|
||||
ingredient: Ingredient,
|
||||
/// The resulting item stack.
|
||||
output: ItemStack,
|
||||
/// Experience points awarded.
|
||||
experience: f32,
|
||||
/// Cooking time in ticks.
|
||||
cooking_time: u32,
|
||||
/// The recipe group (optional).
|
||||
group: ?[]const u8,
|
||||
/// The recipe category in the recipe book.
|
||||
category: ?RecipeCategory,
|
||||
};
|
||||
|
||||
/// Types of cooking stations.
|
||||
pub const CookingType = enum(u8) {
|
||||
smelting,
|
||||
blasting,
|
||||
smoking,
|
||||
campfire,
|
||||
};
|
||||
|
||||
/// Common interface for registering recipes.
|
||||
pub const RecipeManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]recipe-manager";
|
||||
|
||||
/// Registers a shaped crafting recipe.
|
||||
pub fn registerShaped(self: RecipeManager, id: []const u8, recipe: ShapedRecipe) void {
|
||||
return abi.call(raw.@"[method]recipe-manager.register-shaped", void, .{ abi.borrow(self), id, recipe });
|
||||
}
|
||||
|
||||
/// Registers a shapeless crafting recipe.
|
||||
pub fn registerShapeless(self: RecipeManager, id: []const u8, recipe: ShapelessRecipe) void {
|
||||
return abi.call(raw.@"[method]recipe-manager.register-shapeless", void, .{ abi.borrow(self), id, recipe });
|
||||
}
|
||||
|
||||
/// Registers a cooking recipe.
|
||||
pub fn registerCooking(self: RecipeManager, id: []const u8, station_type: CookingType, recipe: CookingRecipe) void {
|
||||
return abi.call(raw.@"[method]recipe-manager.register-cooking", void, .{ abi.borrow(self), id, station_type, recipe });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: RecipeManager) void {
|
||||
abi.keep(RecipeManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: RecipeManager) void {
|
||||
abi.drop(RecipeManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/recipe@0.1.0" fn @"[method]recipe-manager.register-shaped"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/recipe@0.1.0" fn @"[method]recipe-manager.register-shapeless"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/recipe@0.1.0" fn @"[method]recipe-manager.register-cooking"(i32, i32, i32, i32, i32, i32, i32, i32, f32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/recipe@0.1.0" fn @"[resource-drop]recipe-manager"(i32) void;
|
||||
};
|
||||
37
src/wit/scheduler.zig
Normal file
37
src/wit/scheduler.zig
Normal file
@ -0,0 +1,37 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
|
||||
/// Schedules a task to be executed once after the specified number of ticks.
|
||||
///
|
||||
/// * `handler-id`: The unique ID of the handler to call when the task executes.
|
||||
/// * `delay-ticks`: The number of game ticks to wait before execution (20 ticks = 1 second).
|
||||
///
|
||||
/// Returns a unique task ID that can be used to cancel the task.
|
||||
pub fn scheduleDelayedTask(handler_id: u32, delay_ticks: u64) u32 {
|
||||
return abi.call(raw.@"schedule-delayed-task", u32, .{ handler_id, delay_ticks });
|
||||
}
|
||||
|
||||
/// Schedules a task to be executed repeatedly.
|
||||
///
|
||||
/// * `handler-id`: The unique ID of the handler to call when the task executes.
|
||||
/// * `delay-ticks`: The number of game ticks to wait before the first execution.
|
||||
/// * `period-ticks`: The number of game ticks between subsequent executions.
|
||||
///
|
||||
/// Returns a unique task ID that can be used to cancel the task.
|
||||
pub fn scheduleRepeatingTask(handler_id: u32, delay_ticks: u64, period_ticks: u64) u32 {
|
||||
return abi.call(raw.@"schedule-repeating-task", u32, .{ handler_id, delay_ticks, period_ticks });
|
||||
}
|
||||
|
||||
/// Cancels a scheduled task if it hasn't finished yet.
|
||||
///
|
||||
/// * `task-id`: The ID of the task to cancel.
|
||||
pub fn cancelTask(task_id: u32) void {
|
||||
return abi.call(raw.@"cancel-task", void, .{task_id});
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/scheduler@0.1.0" fn @"schedule-delayed-task"(i32, i64) i32;
|
||||
extern "pumpkin:plugin/scheduler@0.1.0" fn @"schedule-repeating-task"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/scheduler@0.1.0" fn @"cancel-task"(i32) void;
|
||||
};
|
||||
255
src/wit/scoreboard.zig
Normal file
255
src/wit/scoreboard.zig
Normal file
@ -0,0 +1,255 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const text = @import("text.zig");
|
||||
const common = @import("common.zig");
|
||||
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const NamedColor = common.NamedColor;
|
||||
|
||||
pub const RenderType = enum(u8) {
|
||||
integer,
|
||||
hearts,
|
||||
};
|
||||
|
||||
pub const NumberFormat = union(enum) {
|
||||
blank,
|
||||
fixed: TextComponent,
|
||||
};
|
||||
|
||||
pub const DisplaySlot = enum(u8) {
|
||||
player_list,
|
||||
sidebar,
|
||||
below_name,
|
||||
sidebar_team_black,
|
||||
sidebar_team_dark_blue,
|
||||
sidebar_team_dark_green,
|
||||
sidebar_team_dark_aqua,
|
||||
sidebar_team_dark_red,
|
||||
sidebar_team_dark_purple,
|
||||
sidebar_team_gold,
|
||||
sidebar_team_gray,
|
||||
sidebar_team_dark_gray,
|
||||
sidebar_team_blue,
|
||||
sidebar_team_green,
|
||||
sidebar_team_aqua,
|
||||
sidebar_team_red,
|
||||
sidebar_team_light_purple,
|
||||
sidebar_team_yellow,
|
||||
sidebar_team_white,
|
||||
};
|
||||
|
||||
pub const NametagVisibility = enum(u8) {
|
||||
always,
|
||||
never,
|
||||
hide_for_other_teams,
|
||||
hide_for_own_team,
|
||||
};
|
||||
|
||||
pub const CollisionRule = enum(u8) {
|
||||
always,
|
||||
never,
|
||||
push_other_teams,
|
||||
push_own_team,
|
||||
};
|
||||
|
||||
pub const TeamSettings = struct {
|
||||
display_name: TextComponent,
|
||||
friendly_fire: bool,
|
||||
see_friendly_invisibles: bool,
|
||||
nametag_visibility: NametagVisibility,
|
||||
collision_rule: CollisionRule,
|
||||
color: NamedColor,
|
||||
prefix: TextComponent,
|
||||
suffix: TextComponent,
|
||||
};
|
||||
|
||||
pub const Scoreboard = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]scoreboard";
|
||||
|
||||
/// Consumes `display_name`.
|
||||
pub fn addObjective(self: Scoreboard, name: []const u8, display_name: TextComponent, render_type: RenderType, number_format: ?NumberFormat) void {
|
||||
return abi.call(raw.@"[method]scoreboard.add-objective", void, .{ abi.borrow(self), name, display_name, render_type, number_format });
|
||||
}
|
||||
|
||||
/// Consumes `display_name`.
|
||||
pub fn updateObjective(self: Scoreboard, name: []const u8, display_name: TextComponent, render_type: RenderType, number_format: ?NumberFormat) void {
|
||||
return abi.call(raw.@"[method]scoreboard.update-objective", void, .{ abi.borrow(self), name, display_name, render_type, number_format });
|
||||
}
|
||||
|
||||
pub fn removeObjective(self: Scoreboard, name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.remove-objective", void, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
pub fn setDisplaySlot(self: Scoreboard, slot: DisplaySlot, objective_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.set-display-slot", void, .{ abi.borrow(self), slot, objective_name });
|
||||
}
|
||||
|
||||
pub fn clearDisplaySlot(self: Scoreboard, slot: DisplaySlot) void {
|
||||
return abi.call(raw.@"[method]scoreboard.clear-display-slot", void, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
pub fn updateScore(self: Scoreboard, entity_name: []const u8, objective_name: []const u8, value: i32, number_format: ?NumberFormat) void {
|
||||
return abi.call(raw.@"[method]scoreboard.update-score", void, .{ abi.borrow(self), entity_name, objective_name, value, number_format });
|
||||
}
|
||||
|
||||
pub fn addScore(self: Scoreboard, entity_name: []const u8, objective_name: []const u8, delta: i32) i32 {
|
||||
return abi.call(raw.@"[method]scoreboard.add-score", i32, .{ abi.borrow(self), entity_name, objective_name, delta });
|
||||
}
|
||||
|
||||
pub fn removeScore(self: Scoreboard, entity_name: []const u8, objective_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.remove-score", void, .{ abi.borrow(self), entity_name, objective_name });
|
||||
}
|
||||
|
||||
pub fn resetEntityScores(self: Scoreboard, entity_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.reset-entity-scores", void, .{ abi.borrow(self), entity_name });
|
||||
}
|
||||
|
||||
pub fn createTeam(self: Scoreboard, name: []const u8, settings: TeamSettings) void {
|
||||
return abi.call(raw.@"[method]scoreboard.create-team", void, .{ abi.borrow(self), name, settings });
|
||||
}
|
||||
|
||||
pub fn removeTeam(self: Scoreboard, name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.remove-team", void, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
pub fn updateTeam(self: Scoreboard, name: []const u8, settings: TeamSettings) void {
|
||||
return abi.call(raw.@"[method]scoreboard.update-team", void, .{ abi.borrow(self), name, settings });
|
||||
}
|
||||
|
||||
pub fn addPlayerToTeam(self: Scoreboard, team_name: []const u8, player_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.add-player-to-team", void, .{ abi.borrow(self), team_name, player_name });
|
||||
}
|
||||
|
||||
pub fn removePlayerFromTeam(self: Scoreboard, team_name: []const u8, player_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.remove-player-from-team", void, .{ abi.borrow(self), team_name, player_name });
|
||||
}
|
||||
|
||||
pub fn clearTeamPlayers(self: Scoreboard, team_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]scoreboard.clear-team-players", void, .{ abi.borrow(self), team_name });
|
||||
}
|
||||
|
||||
pub fn getTeams(self: Scoreboard) []const []const u8 {
|
||||
return abi.call(raw.@"[method]scoreboard.get-teams", []const []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn getTeam(self: Scoreboard, name: []const u8) ?TeamSettings {
|
||||
return abi.call(raw.@"[method]scoreboard.get-team", ?TeamSettings, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
pub fn getTeamPlayers(self: Scoreboard, team_name: []const u8) []const []const u8 {
|
||||
return abi.call(raw.@"[method]scoreboard.get-team-players", []const []const u8, .{ abi.borrow(self), team_name });
|
||||
}
|
||||
|
||||
pub fn getPlayerTeam(self: Scoreboard, player_name: []const u8) ?[]const u8 {
|
||||
return abi.call(raw.@"[method]scoreboard.get-player-team", ?[]const u8, .{ abi.borrow(self), player_name });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Scoreboard) void {
|
||||
abi.keep(Scoreboard, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Scoreboard) void {
|
||||
abi.drop(Scoreboard, self);
|
||||
}
|
||||
};
|
||||
|
||||
pub const BedrockSortOrder = enum(u8) {
|
||||
ascending,
|
||||
descending,
|
||||
};
|
||||
|
||||
pub const BedrockDisplaySlot = enum(u8) {
|
||||
player_list,
|
||||
sidebar,
|
||||
below_name,
|
||||
};
|
||||
|
||||
pub const BedrockScoreboard = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]bedrock-scoreboard";
|
||||
|
||||
pub fn addObjective(self: BedrockScoreboard, name: []const u8, display_name: []const u8, sort_order: BedrockSortOrder) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.add-objective", void, .{ abi.borrow(self), name, display_name, sort_order });
|
||||
}
|
||||
|
||||
pub fn updateObjective(self: BedrockScoreboard, name: []const u8, display_name: []const u8, sort_order: BedrockSortOrder) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.update-objective", void, .{ abi.borrow(self), name, display_name, sort_order });
|
||||
}
|
||||
|
||||
pub fn removeObjective(self: BedrockScoreboard, name: []const u8) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.remove-objective", void, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
pub fn setDisplaySlot(self: BedrockScoreboard, slot: BedrockDisplaySlot, objective_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.set-display-slot", void, .{ abi.borrow(self), slot, objective_name });
|
||||
}
|
||||
|
||||
pub fn clearDisplaySlot(self: BedrockScoreboard, slot: BedrockDisplaySlot) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.clear-display-slot", void, .{ abi.borrow(self), slot });
|
||||
}
|
||||
|
||||
pub fn updateScore(self: BedrockScoreboard, entity_name: []const u8, objective_name: []const u8, value: i32) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.update-score", void, .{ abi.borrow(self), entity_name, objective_name, value });
|
||||
}
|
||||
|
||||
pub fn addScore(self: BedrockScoreboard, entity_name: []const u8, objective_name: []const u8, delta: i32) i32 {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.add-score", i32, .{ abi.borrow(self), entity_name, objective_name, delta });
|
||||
}
|
||||
|
||||
pub fn removeScore(self: BedrockScoreboard, entity_name: []const u8, objective_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.remove-score", void, .{ abi.borrow(self), entity_name, objective_name });
|
||||
}
|
||||
|
||||
pub fn resetEntityScores(self: BedrockScoreboard, entity_name: []const u8) void {
|
||||
return abi.call(raw.@"[method]bedrock-scoreboard.reset-entity-scores", void, .{ abi.borrow(self), entity_name });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: BedrockScoreboard) void {
|
||||
abi.keep(BedrockScoreboard, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: BedrockScoreboard) void {
|
||||
abi.drop(BedrockScoreboard, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.add-objective"(i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.update-objective"(i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.remove-objective"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.set-display-slot"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.clear-display-slot"(i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.update-score"(i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.add-score"(i32, i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.remove-score"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.reset-entity-scores"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.create-team"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.remove-team"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.update-team"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.add-player-to-team"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.remove-player-from-team"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.clear-team-players"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.get-teams"(i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.get-team"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.get-team-players"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]scoreboard.get-player-team"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.add-objective"(i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.update-objective"(i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.remove-objective"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.set-display-slot"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.clear-display-slot"(i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.update-score"(i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.add-score"(i32, i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.remove-score"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[method]bedrock-scoreboard.reset-entity-scores"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[resource-drop]scoreboard"(i32) void;
|
||||
extern "pumpkin:plugin/scoreboard@0.1.0" fn @"[resource-drop]bedrock-scoreboard"(i32) void;
|
||||
};
|
||||
29
src/wit/screens.zig
Normal file
29
src/wit/screens.zig
Normal file
@ -0,0 +1,29 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const Screen = enum(u8) {
|
||||
generic_9x1,
|
||||
generic_9x2,
|
||||
generic_9x3,
|
||||
generic_9x4,
|
||||
generic_9x5,
|
||||
generic_9x6,
|
||||
generic_3x3,
|
||||
crafter_3x3,
|
||||
anvil,
|
||||
beacon,
|
||||
blast_furnace,
|
||||
brewing_stand,
|
||||
crafting,
|
||||
enchantment,
|
||||
furnace,
|
||||
grindstone,
|
||||
hopper,
|
||||
lectern,
|
||||
loom,
|
||||
merchant,
|
||||
shulker_box,
|
||||
smithing,
|
||||
smoker,
|
||||
cartography_table,
|
||||
stonecutter,
|
||||
};
|
||||
567
src/wit/server.zig
Normal file
567
src/wit/server.zig
Normal file
@ -0,0 +1,567 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const player = @import("player.zig");
|
||||
const common = @import("common.zig");
|
||||
const world = @import("world.zig");
|
||||
const text = @import("text.zig");
|
||||
const uuid = @import("uuid.zig");
|
||||
const recipe = @import("recipe.zig");
|
||||
const enchantments = @import("enchantments.zig");
|
||||
const permission = @import("permission.zig");
|
||||
const advancement = @import("advancement.zig");
|
||||
const datapack = @import("datapack.zig");
|
||||
|
||||
pub const Player = player.Player;
|
||||
pub const BanPlayerOptions = player.BanPlayerOptions;
|
||||
pub const BanIpOptions = player.BanIpOptions;
|
||||
pub const ServerLink = player.ServerLink;
|
||||
pub const KnownServerLink = player.KnownServerLink;
|
||||
pub const ServerLinkLabel = player.ServerLinkLabel;
|
||||
pub const GameMode = common.GameMode;
|
||||
pub const World = world.World;
|
||||
pub const TextComponent = text.TextComponent;
|
||||
pub const Uuid = uuid.Uuid;
|
||||
pub const RecipeManager = recipe.RecipeManager;
|
||||
pub const EnchantmentManager = enchantments.EnchantmentManager;
|
||||
pub const CustomEnchantment = enchantments.CustomEnchantment;
|
||||
pub const PermissionLevel = permission.PermissionLevel;
|
||||
pub const AdvancementInfo = advancement.AdvancementInfo;
|
||||
pub const DatapackManager = datapack.DatapackManager;
|
||||
pub const DatapackInfo = datapack.DatapackInfo;
|
||||
|
||||
/// Represents an operator entry in the ops configuration.
|
||||
pub const OpEntry = struct {
|
||||
uuid: Uuid,
|
||||
name: []const u8,
|
||||
level: PermissionLevel,
|
||||
bypasses_player_limit: bool,
|
||||
};
|
||||
|
||||
/// Interface for querying and managing server operators.
|
||||
pub const OpManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]op-manager";
|
||||
|
||||
/// Checks if a player UUID is currently an operator.
|
||||
pub fn isOp(self: OpManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]op-manager.is-op", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Retrieves the operator entry for a player UUID, if present.
|
||||
pub fn getOp(self: OpManager, id: Uuid) ?OpEntry {
|
||||
return abi.call(raw.@"[method]op-manager.get-op", ?OpEntry, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Gets the effective permission level for a player UUID (returns zero if not op).
|
||||
pub fn getPermissionLevel(self: OpManager, id: Uuid) PermissionLevel {
|
||||
return abi.call(raw.@"[method]op-manager.get-permission-level", PermissionLevel, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Grants operator status to a player (online or offline) with the specified level and bypass setting.
|
||||
pub fn opPlayer(self: OpManager, name: []const u8, id: Uuid, level: PermissionLevel, bypasses_player_limit: bool) void {
|
||||
return abi.call(raw.@"[method]op-manager.op-player", void, .{ abi.borrow(self), name, id, level, bypasses_player_limit });
|
||||
}
|
||||
|
||||
/// Revokes operator status from a player (online or offline). Returns true if the player was previously op.
|
||||
pub fn deopPlayer(self: OpManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]op-manager.deop-player", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns a list of all operator entries on the server.
|
||||
pub fn listOps(self: OpManager) []const OpEntry {
|
||||
return abi.call(raw.@"[method]op-manager.list-ops", []const OpEntry, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: OpManager) void {
|
||||
abi.keep(OpManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: OpManager) void {
|
||||
abi.drop(OpManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a banned player entry in the ban list.
|
||||
pub const BannedPlayerEntry = struct {
|
||||
uuid: Uuid,
|
||||
name: []const u8,
|
||||
created: []const u8,
|
||||
source: []const u8,
|
||||
expires: ?[]const u8,
|
||||
reason: []const u8,
|
||||
};
|
||||
|
||||
/// Represents a banned IP entry in the IP ban list.
|
||||
pub const BannedIpEntry = struct {
|
||||
ip: []const u8,
|
||||
created: []const u8,
|
||||
source: []const u8,
|
||||
expires: ?[]const u8,
|
||||
reason: []const u8,
|
||||
};
|
||||
|
||||
/// Global manager for player and IP bans.
|
||||
pub const BanManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]ban-manager";
|
||||
|
||||
/// Checks if a player UUID is currently banned.
|
||||
pub fn isPlayerBanned(self: BanManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]ban-manager.is-player-banned", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Retrieves the ban entry for a player UUID, if banned.
|
||||
pub fn getPlayerBan(self: BanManager, id: Uuid) ?BannedPlayerEntry {
|
||||
return abi.call(raw.@"[method]ban-manager.get-player-ban", ?BannedPlayerEntry, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Bans a player by name and UUID with the specified options (works for online and offline players).
|
||||
pub fn banPlayer(self: BanManager, name: []const u8, id: Uuid, options: BanPlayerOptions) void {
|
||||
return abi.call(raw.@"[method]ban-manager.ban-player", void, .{ abi.borrow(self), name, id, options });
|
||||
}
|
||||
|
||||
/// Removes a player ban by UUID. Returns true if the player was banned.
|
||||
pub fn unbanPlayer(self: BanManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]ban-manager.unban-player", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns all currently active player bans.
|
||||
pub fn listPlayerBans(self: BanManager) []const BannedPlayerEntry {
|
||||
return abi.call(raw.@"[method]ban-manager.list-player-bans", []const BannedPlayerEntry, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Checks if an IP address is currently banned.
|
||||
pub fn isIpBanned(self: BanManager, ip: []const u8) bool {
|
||||
return abi.call(raw.@"[method]ban-manager.is-ip-banned", bool, .{ abi.borrow(self), ip });
|
||||
}
|
||||
|
||||
/// Retrieves the ban entry for an IP address, if banned.
|
||||
pub fn getIpBan(self: BanManager, ip: []const u8) ?BannedIpEntry {
|
||||
return abi.call(raw.@"[method]ban-manager.get-ip-ban", ?BannedIpEntry, .{ abi.borrow(self), ip });
|
||||
}
|
||||
|
||||
/// Bans an IP address with the specified options.
|
||||
pub fn banIp(self: BanManager, ip: []const u8, options: BanIpOptions) void {
|
||||
return abi.call(raw.@"[method]ban-manager.ban-ip", void, .{ abi.borrow(self), ip, options });
|
||||
}
|
||||
|
||||
/// Removes an IP ban. Returns true if the IP was banned.
|
||||
pub fn unbanIp(self: BanManager, ip: []const u8) bool {
|
||||
return abi.call(raw.@"[method]ban-manager.unban-ip", bool, .{ abi.borrow(self), ip });
|
||||
}
|
||||
|
||||
/// Returns all currently active IP bans.
|
||||
pub fn listIpBans(self: BanManager) []const BannedIpEntry {
|
||||
return abi.call(raw.@"[method]ban-manager.list-ip-bans", []const BannedIpEntry, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: BanManager) void {
|
||||
abi.keep(BanManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: BanManager) void {
|
||||
abi.drop(BanManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a player entry in the server whitelist.
|
||||
pub const WhitelistEntry = struct {
|
||||
uuid: Uuid,
|
||||
name: []const u8,
|
||||
};
|
||||
|
||||
/// Global manager for the server whitelist.
|
||||
pub const WhitelistManager = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]whitelist-manager";
|
||||
|
||||
/// Returns whether the whitelist is currently enabled.
|
||||
pub fn isEnabled(self: WhitelistManager) bool {
|
||||
return abi.call(raw.@"[method]whitelist-manager.is-enabled", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Enables or disables the server whitelist. If enabled and enforce-whitelist is set, kicks non-whitelisted players.
|
||||
pub fn setEnabled(self: WhitelistManager, enabled: bool) void {
|
||||
return abi.call(raw.@"[method]whitelist-manager.set-enabled", void, .{ abi.borrow(self), enabled });
|
||||
}
|
||||
|
||||
/// Checks if a player UUID is on the whitelist.
|
||||
pub fn isWhitelisted(self: WhitelistManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]whitelist-manager.is-whitelisted", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Adds a player to the whitelist (online or offline). Returns true if newly added.
|
||||
pub fn addPlayer(self: WhitelistManager, name: []const u8, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]whitelist-manager.add-player", bool, .{ abi.borrow(self), name, id });
|
||||
}
|
||||
|
||||
/// Removes a player from the whitelist. Returns true if the player was on the whitelist.
|
||||
pub fn removePlayer(self: WhitelistManager, id: Uuid) bool {
|
||||
return abi.call(raw.@"[method]whitelist-manager.remove-player", bool, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns all whitelisted player entries.
|
||||
pub fn listEntries(self: WhitelistManager) []const WhitelistEntry {
|
||||
return abi.call(raw.@"[method]whitelist-manager.list-entries", []const WhitelistEntry, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: WhitelistManager) void {
|
||||
abi.keep(WhitelistManager, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: WhitelistManager) void {
|
||||
abi.drop(WhitelistManager, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents the difficulty setting of a Minecraft server.
|
||||
pub const Difficulty = enum(u8) {
|
||||
/// Hostile mobs do not spawn. Players regain health automatically.
|
||||
peaceful,
|
||||
/// Hostile mobs deal less damage.
|
||||
easy,
|
||||
/// Standard Minecraft difficulty.
|
||||
normal,
|
||||
/// Hostile mobs deal more damage.
|
||||
hard,
|
||||
};
|
||||
|
||||
/// Represents the three main Minecraft dimensions.
|
||||
pub const Dimension = enum(u8) {
|
||||
overworld,
|
||||
nether,
|
||||
end,
|
||||
};
|
||||
|
||||
pub const SysInfo = struct {
|
||||
cpu_count: ?u32,
|
||||
total_memory: ?u64,
|
||||
used_memory: ?u64,
|
||||
os_name: ?[]const u8,
|
||||
os_version: ?[]const u8,
|
||||
pumpkin_version: []const u8,
|
||||
};
|
||||
|
||||
pub const CommandSender = union(enum) {
|
||||
console,
|
||||
player: Player,
|
||||
};
|
||||
|
||||
/// Represents the global server instance.
|
||||
pub const Server = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]server";
|
||||
|
||||
/// Returns system information (CPU, Memory, OS).
|
||||
/// Fields are returned only if the plugin has the corresponding permissions.
|
||||
pub fn getSysInfo(self: Server) SysInfo {
|
||||
return abi.call(raw.@"[method]server.get-sys-info", SysInfo, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the current difficulty level of the server.
|
||||
pub fn getDifficulty(self: Server) Difficulty {
|
||||
return abi.call(raw.@"[method]server.get-difficulty", Difficulty, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the total number of players currently connected to the server.
|
||||
pub fn getPlayerCount(self: Server) u32 {
|
||||
return abi.call(raw.@"[method]server.get-player-count", u32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the rolling average Milliseconds Per Tick (MSPT).
|
||||
/// A value below 50.0 is required for a stable 20 TPS.
|
||||
pub fn getMspt(self: Server) f64 {
|
||||
return abi.call(raw.@"[method]server.get-mspt", f64, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the effective Ticks Per Second (TPS).
|
||||
/// Ideal value is 20.0.
|
||||
pub fn getTps(self: Server) f64 {
|
||||
return abi.call(raw.@"[method]server.get-tps", f64, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns a list of all online players across all worlds.
|
||||
pub fn getAllPlayers(self: Server) []const Player {
|
||||
return abi.call(raw.@"[method]server.get-all-players", []const Player, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Searches for a player by their exact name.
|
||||
pub fn getPlayerByName(self: Server, name: []const u8) ?Player {
|
||||
return abi.call(raw.@"[method]server.get-player-by-name", ?Player, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Searches for a player by their UUID string.
|
||||
pub fn getPlayerByUuid(self: Server, id: Uuid) ?Player {
|
||||
return abi.call(raw.@"[method]server.get-player-by-uuid", ?Player, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns a list of all worlds on this server.
|
||||
pub fn getAllWorlds(self: Server) []const World {
|
||||
return abi.call(raw.@"[method]server.get-all-worlds", []const World, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Gets a world by its dimension name (e.g., "minecraft:overworld") or custom world name (e.g., "world", "arena_1").
|
||||
pub fn getWorldByName(self: Server, name: []const u8) ?World {
|
||||
return abi.call(raw.@"[method]server.get-world-by-name", ?World, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Checks if a world exists by name or dimension.
|
||||
pub fn hasWorld(self: Server, name: []const u8) bool {
|
||||
return abi.call(raw.@"[method]server.has-world", bool, .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
pub fn executeCommand(self: Server, command: []const u8, sender: CommandSender) void {
|
||||
return abi.call(raw.@"[method]server.execute-command", void, .{ abi.borrow(self), command, sender });
|
||||
}
|
||||
|
||||
/// Creates or loads a world by its name and dimension.
|
||||
/// If a world with the given name already exists, it will be returned.
|
||||
pub fn createWorld(self: Server, name: []const u8, dimension: Dimension) World {
|
||||
return abi.call(raw.@"[method]server.create-world", World, .{ abi.borrow(self), name, dimension });
|
||||
}
|
||||
|
||||
/// Unloads and saves a world by its name or dimension.
|
||||
/// Returns an error if the world cannot be found, is the primary/default world, or still has players inside.
|
||||
pub fn unloadWorld(self: Server, name: []const u8) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]server.unload-world", abi.Result(void, []const u8), .{ abi.borrow(self), name });
|
||||
}
|
||||
|
||||
/// Saves all players, player advancements, and loaded worlds to disk.
|
||||
pub fn saveAll(self: Server) abi.Result(void, []const u8) {
|
||||
return abi.call(raw.@"[method]server.save-all", abi.Result(void, []const u8), .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns a list of all online players in a specific world.
|
||||
///
|
||||
/// Consumes `world_ref`.
|
||||
pub fn getPlayersInWorld(self: Server, world_ref: World) []const Player {
|
||||
return abi.call(raw.@"[method]server.get-players-in-world", []const Player, .{ abi.borrow(self), world_ref });
|
||||
}
|
||||
|
||||
/// Returns the number of online players in a specific world.
|
||||
///
|
||||
/// Consumes `world_ref`.
|
||||
pub fn getPlayerCountInWorld(self: Server, world_ref: World) u32 {
|
||||
return abi.call(raw.@"[method]server.get-player-count-in-world", u32, .{ abi.borrow(self), world_ref });
|
||||
}
|
||||
|
||||
/// Broadcasts a system chat message to all players.
|
||||
pub fn broadcast(self: Server, message: []const u8) void {
|
||||
return abi.call(raw.@"[method]server.broadcast", void, .{ abi.borrow(self), message });
|
||||
}
|
||||
|
||||
/// Deletes a signed chat message from all players' chat windows using its 256-byte signature.
|
||||
pub fn deleteMessageBySignature(self: Server, signature: []const u8) void {
|
||||
return abi.call(raw.@"[method]server.delete-message-by-signature", void, .{ abi.borrow(self), signature });
|
||||
}
|
||||
|
||||
/// Deletes a signed chat message from all players' chat windows using its signature cache ID.
|
||||
pub fn deleteMessageById(self: Server, signature_id: i32) void {
|
||||
return abi.call(raw.@"[method]server.delete-message-by-id", void, .{ abi.borrow(self), signature_id });
|
||||
}
|
||||
|
||||
/// Broadcasts a tab list header and footer to all players.
|
||||
///
|
||||
/// Consumes `header`.
|
||||
/// Consumes `footer`.
|
||||
pub fn broadcastTabListHeaderFooter(self: Server, header: TextComponent, footer: TextComponent) void {
|
||||
return abi.call(raw.@"[method]server.broadcast-tab-list-header-footer", void, .{ abi.borrow(self), header, footer });
|
||||
}
|
||||
|
||||
/// Returns the maximum number of players allowed on the server.
|
||||
pub fn getMaxPlayers(self: Server) u32 {
|
||||
return abi.call(raw.@"[method]server.get-max-players", u32, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns whether the server is in hardcore mode.
|
||||
pub fn isHardcore(self: Server) bool {
|
||||
return abi.call(raw.@"[method]server.is-hardcore", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns whether the server is in online mode (authenticates with Mojang).
|
||||
pub fn isOnlineMode(self: Server) bool {
|
||||
return abi.call(raw.@"[method]server.is-online-mode", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the server's Message of the Day (MOTD).
|
||||
pub fn getMotd(self: Server) []const u8 {
|
||||
return abi.call(raw.@"[method]server.get-motd", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns whether the server has a whitelist enabled.
|
||||
pub fn hasWhitelist(self: Server) bool {
|
||||
return abi.call(raw.@"[method]server.has-whitelist", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns whether the server allows the Nether dimension.
|
||||
pub fn getAllowNether(self: Server) bool {
|
||||
return abi.call(raw.@"[method]server.get-allow-nether", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns whether the server allows the End dimension.
|
||||
pub fn getAllowEnd(self: Server) bool {
|
||||
return abi.call(raw.@"[method]server.get-allow-end", bool, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the server's maximum view distance.
|
||||
pub fn getViewDistance(self: Server) u8 {
|
||||
return abi.call(raw.@"[method]server.get-view-distance", u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the server's maximum simulation distance.
|
||||
pub fn getSimulationDistance(self: Server) u8 {
|
||||
return abi.call(raw.@"[method]server.get-simulation-distance", u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the server's default gamemode.
|
||||
pub fn getDefaultGamemode(self: Server) GameMode {
|
||||
return abi.call(raw.@"[method]server.get-default-gamemode", GameMode, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the recipe manager to register custom recipes.
|
||||
pub fn getRecipeManager(self: Server) RecipeManager {
|
||||
return abi.call(raw.@"[method]server.get-recipe-manager", RecipeManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the operator manager to query or modify server operators.
|
||||
pub fn getOpManager(self: Server) OpManager {
|
||||
return abi.call(raw.@"[method]server.get-op-manager", OpManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the global ban manager for querying and modifying player and IP bans.
|
||||
pub fn getBanManager(self: Server) BanManager {
|
||||
return abi.call(raw.@"[method]server.get-ban-manager", BanManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the global whitelist manager for querying and modifying the server whitelist.
|
||||
pub fn getWhitelistManager(self: Server) WhitelistManager {
|
||||
return abi.call(raw.@"[method]server.get-whitelist-manager", WhitelistManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns detailed information about an advancement by its ID (e.g., "minecraft:story/mine_stone" or "story/mine_stone").
|
||||
pub fn getAdvancement(self: Server, id: []const u8) ?AdvancementInfo {
|
||||
return abi.call(raw.@"[method]server.get-advancement", ?AdvancementInfo, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns a list of all registered advancement IDs on the server.
|
||||
pub fn getAllAdvancementIds(self: Server) []const []const u8 {
|
||||
return abi.call(raw.@"[method]server.get-all-advancement-ids", []const []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the global enchantment manager for registering and querying custom enchantments.
|
||||
pub fn getEnchantmentManager(self: Server) EnchantmentManager {
|
||||
return abi.call(raw.@"[method]server.get-enchantment-manager", EnchantmentManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns information about an enchantment by its ID (vanilla or custom).
|
||||
pub fn getEnchantment(self: Server, id: []const u8) ?CustomEnchantment {
|
||||
return abi.call(raw.@"[method]server.get-enchantment", ?CustomEnchantment, .{ abi.borrow(self), id });
|
||||
}
|
||||
|
||||
/// Returns a list of all registered enchantment IDs (custom and vanilla) on the server.
|
||||
pub fn getAllEnchantmentIds(self: Server) []const []const u8 {
|
||||
return abi.call(raw.@"[method]server.get-all-enchantment-ids", []const []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Returns the global datapack manager for inspecting, enabling, disabling, and reloading datapacks.
|
||||
pub fn getDatapackManager(self: Server) DatapackManager {
|
||||
return abi.call(raw.@"[method]server.get-datapack-manager", DatapackManager, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Broadcasts custom server links to all connected players (displayed in the client Esc pause menu in 1.21+).
|
||||
pub fn setServerLinks(self: Server, links: []const ServerLink) void {
|
||||
return abi.call(raw.@"[method]server.set-server-links", void, .{ abi.borrow(self), links });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Server) void {
|
||||
abi.keep(Server, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Server) void {
|
||||
abi.drop(Server, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.is-op"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.get-op"(i32, i64, i64, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.get-permission-level"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.op-player"(i32, i32, i32, i64, i64, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.deop-player"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]op-manager.list-ops"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.is-player-banned"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.get-player-ban"(i32, i64, i64, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.ban-player"(i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.unban-player"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.list-player-bans"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.is-ip-banned"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.get-ip-ban"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.ban-ip"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i64, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.unban-ip"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]ban-manager.list-ip-bans"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.is-enabled"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.set-enabled"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.is-whitelisted"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.add-player"(i32, i32, i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.remove-player"(i32, i64, i64) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]whitelist-manager.list-entries"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-sys-info"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-difficulty"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-player-count"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-mspt"(i32) f64;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-tps"(i32) f64;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-all-players"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-player-by-name"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-player-by-uuid"(i32, i64, i64, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-all-worlds"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-world-by-name"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.has-world"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.execute-command"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.create-world"(i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.unload-world"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.save-all"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-players-in-world"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-player-count-in-world"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.broadcast"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.delete-message-by-signature"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.delete-message-by-id"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.broadcast-tab-list-header-footer"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-max-players"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.is-hardcore"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.is-online-mode"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-motd"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.has-whitelist"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-allow-nether"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-allow-end"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-view-distance"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-simulation-distance"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-default-gamemode"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-recipe-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-op-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-ban-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-whitelist-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-advancement"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-all-advancement-ids"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-enchantment-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-enchantment"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-all-enchantment-ids"(i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.get-datapack-manager"(i32) i32;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[method]server.set-server-links"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[resource-drop]op-manager"(i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[resource-drop]ban-manager"(i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[resource-drop]whitelist-manager"(i32) void;
|
||||
extern "pumpkin:plugin/server@0.1.0" fn @"[resource-drop]server"(i32) void;
|
||||
};
|
||||
1986
src/wit/sounds.zig
Normal file
1986
src/wit/sounds.zig
Normal file
File diff suppressed because it is too large
Load Diff
93
src/wit/statistics.zig
Normal file
93
src/wit/statistics.zig
Normal file
@ -0,0 +1,93 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const StatisticCategory = enum(u8) {
|
||||
mined,
|
||||
crafted,
|
||||
used,
|
||||
broken,
|
||||
picked_up,
|
||||
dropped,
|
||||
killed,
|
||||
killed_by,
|
||||
custom,
|
||||
};
|
||||
|
||||
pub const CustomStatistic = enum(u8) {
|
||||
leave_game,
|
||||
play_time,
|
||||
total_world_time,
|
||||
time_since_death,
|
||||
time_since_rest,
|
||||
sneak_time,
|
||||
walk_one_cm,
|
||||
crouch_one_cm,
|
||||
sprint_one_cm,
|
||||
walk_on_water_one_cm,
|
||||
fall_one_cm,
|
||||
climb_one_cm,
|
||||
fly_one_cm,
|
||||
walk_under_water_one_cm,
|
||||
minecart_one_cm,
|
||||
boat_one_cm,
|
||||
pig_one_cm,
|
||||
happy_ghast_one_cm,
|
||||
horse_one_cm,
|
||||
aviate_one_cm,
|
||||
swim_one_cm,
|
||||
strider_one_cm,
|
||||
nautilus_one_cm,
|
||||
jump,
|
||||
drop,
|
||||
damage_dealt,
|
||||
damage_dealt_absorbed,
|
||||
damage_dealt_resisted,
|
||||
damage_taken,
|
||||
damage_blocked_by_shield,
|
||||
damage_absorbed,
|
||||
damage_resisted,
|
||||
deaths,
|
||||
mob_kills,
|
||||
animals_bred,
|
||||
player_kills,
|
||||
fish_caught,
|
||||
talked_to_villager,
|
||||
traded_with_villager,
|
||||
eat_cake_slice,
|
||||
fill_cauldron,
|
||||
use_cauldron,
|
||||
clean_armor,
|
||||
clean_banner,
|
||||
clean_shulker_box,
|
||||
interact_with_brewingstand,
|
||||
interact_with_beacon,
|
||||
inspect_dropper,
|
||||
inspect_hopper,
|
||||
inspect_dispenser,
|
||||
play_noteblock,
|
||||
tune_noteblock,
|
||||
pot_flower,
|
||||
trigger_trapped_chest,
|
||||
open_enderchest,
|
||||
enchant_item,
|
||||
play_record,
|
||||
interact_with_furnace,
|
||||
interact_with_crafting_table,
|
||||
open_chest,
|
||||
sleep_in_bed,
|
||||
open_shulker_box,
|
||||
open_barrel,
|
||||
interact_with_blast_furnace,
|
||||
interact_with_smoker,
|
||||
interact_with_lectern,
|
||||
interact_with_campfire,
|
||||
interact_with_cartography_table,
|
||||
interact_with_loom,
|
||||
interact_with_stonecutter,
|
||||
bell_ring,
|
||||
raid_trigger,
|
||||
raid_win,
|
||||
interact_with_anvil,
|
||||
interact_with_grindstone,
|
||||
target_hit,
|
||||
interact_with_smithing_table,
|
||||
};
|
||||
52
src/wit/status_effect.zig
Normal file
52
src/wit/status_effect.zig
Normal file
@ -0,0 +1,52 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const StatusEffectType = enum(u8) {
|
||||
speed,
|
||||
slowness,
|
||||
haste,
|
||||
mining_fatigue,
|
||||
strength,
|
||||
instant_health,
|
||||
instant_damage,
|
||||
jump_boost,
|
||||
nausea,
|
||||
regeneration,
|
||||
resistance,
|
||||
fire_resistance,
|
||||
water_breathing,
|
||||
invisibility,
|
||||
blindness,
|
||||
night_vision,
|
||||
hunger,
|
||||
weakness,
|
||||
poison,
|
||||
wither,
|
||||
health_boost,
|
||||
absorption,
|
||||
saturation,
|
||||
glowing,
|
||||
levitation,
|
||||
luck,
|
||||
unluck,
|
||||
slow_falling,
|
||||
conduit_power,
|
||||
dolphins_grace,
|
||||
bad_omen,
|
||||
hero_of_the_village,
|
||||
darkness,
|
||||
trial_omen,
|
||||
raid_omen,
|
||||
wind_charged,
|
||||
weaving,
|
||||
oozing,
|
||||
infested,
|
||||
};
|
||||
|
||||
pub const StatusEffectInstance = struct {
|
||||
effect_type: StatusEffectType,
|
||||
duration: u32,
|
||||
amplifier: u8,
|
||||
ambient: bool,
|
||||
show_particles: bool,
|
||||
show_icon: bool,
|
||||
};
|
||||
231
src/wit/text.zig
Normal file
231
src/wit/text.zig
Normal file
@ -0,0 +1,231 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const common = @import("common.zig");
|
||||
|
||||
pub const NamedColor = common.NamedColor;
|
||||
pub const RgbColor = common.RgbColor;
|
||||
pub const ArgbColor = common.ArgbColor;
|
||||
|
||||
pub const TextComponent = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]text-component";
|
||||
|
||||
/// Creates a plain text component.
|
||||
pub fn text(plain: []const u8) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.text", TextComponent, .{plain});
|
||||
}
|
||||
|
||||
/// Creates a translation component.
|
||||
pub fn translate(key: []const u8, with: []const TextComponent) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.translate", TextComponent, .{ key, with });
|
||||
}
|
||||
|
||||
/// Creates a translation component with a Bedrock-specific fallback key.
|
||||
pub fn translateCross(java_key: []const u8, bedrock_key: []const u8, with: []const TextComponent) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.translate-cross", TextComponent, .{ java_key, bedrock_key, with });
|
||||
}
|
||||
|
||||
/// Creates an entity names / selector text component.
|
||||
pub fn entityNames(selector: []const u8, separator: ?[]const u8) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.entity-names", TextComponent, .{ selector, separator });
|
||||
}
|
||||
|
||||
/// Creates a keybind text component (e.g., "key.jump").
|
||||
pub fn keybind(keybind_: []const u8) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.keybind", TextComponent, .{keybind_});
|
||||
}
|
||||
|
||||
/// Creates a custom translation component.
|
||||
pub fn custom(namespace: []const u8, key: []const u8, locale: []const u8, with: []const TextComponent) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.custom", TextComponent, .{ namespace, key, locale, with });
|
||||
}
|
||||
|
||||
/// Parses a legacy Minecraft formatted string (using section signs '§' by default) into a text component.
|
||||
pub fn fromLegacyString(input: []const u8) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.from-legacy-string", TextComponent, .{input});
|
||||
}
|
||||
|
||||
/// Parses a legacy formatted string using a custom color code symbol (e.g. '&' or '§').
|
||||
pub fn fromLegacyStringWithCode(input: []const u8, code_symbol: u21) TextComponent {
|
||||
return abi.call(raw.@"[static]text-component.from-legacy-string-with-code", TextComponent, .{ input, code_symbol });
|
||||
}
|
||||
|
||||
/// Parses a standard Minecraft JSON text component.
|
||||
pub fn fromJson(json: []const u8) abi.Result(TextComponent, []const u8) {
|
||||
return abi.call(raw.@"[static]text-component.from-json", abi.Result(TextComponent, []const u8), .{json});
|
||||
}
|
||||
|
||||
/// Serializes the text component to JSON format.
|
||||
pub fn toJson(self: TextComponent) []const u8 {
|
||||
return abi.call(raw.@"[method]text-component.to-json", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Consumes `child`.
|
||||
pub fn addChild(self: TextComponent, child: TextComponent) void {
|
||||
return abi.call(raw.@"[method]text-component.add-child", void, .{ abi.borrow(self), child });
|
||||
}
|
||||
|
||||
pub fn addText(self: TextComponent, text_: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.add-text", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
pub fn getText(self: TextComponent) []const u8 {
|
||||
return abi.call(raw.@"[method]text-component.get-text", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn encode(self: TextComponent) []const u8 {
|
||||
return abi.call(raw.@"[method]text-component.encode", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn toPrettyConsole(self: TextComponent) []const u8 {
|
||||
return abi.call(raw.@"[method]text-component.to-pretty-console", []const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Style
|
||||
pub fn colorNamed(self: TextComponent, color: NamedColor) void {
|
||||
return abi.call(raw.@"[method]text-component.color-named", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
pub fn colorRgb(self: TextComponent, color: RgbColor) void {
|
||||
return abi.call(raw.@"[method]text-component.color-rgb", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
pub fn gradientNamed(self: TextComponent, colors: []const NamedColor) void {
|
||||
return abi.call(raw.@"[method]text-component.gradient-named", void, .{ abi.borrow(self), colors });
|
||||
}
|
||||
|
||||
pub fn gradient(self: TextComponent, colors: []const RgbColor) void {
|
||||
return abi.call(raw.@"[method]text-component.gradient", void, .{ abi.borrow(self), colors });
|
||||
}
|
||||
|
||||
pub fn rainbow(self: TextComponent) void {
|
||||
return abi.call(raw.@"[method]text-component.rainbow", void, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
pub fn bold(self: TextComponent, value: bool) void {
|
||||
return abi.call(raw.@"[method]text-component.bold", void, .{ abi.borrow(self), value });
|
||||
}
|
||||
|
||||
pub fn italic(self: TextComponent, value: bool) void {
|
||||
return abi.call(raw.@"[method]text-component.italic", void, .{ abi.borrow(self), value });
|
||||
}
|
||||
|
||||
pub fn underlined(self: TextComponent, value: bool) void {
|
||||
return abi.call(raw.@"[method]text-component.underlined", void, .{ abi.borrow(self), value });
|
||||
}
|
||||
|
||||
pub fn strikethrough(self: TextComponent, value: bool) void {
|
||||
return abi.call(raw.@"[method]text-component.strikethrough", void, .{ abi.borrow(self), value });
|
||||
}
|
||||
|
||||
pub fn obfuscated(self: TextComponent, value: bool) void {
|
||||
return abi.call(raw.@"[method]text-component.obfuscated", void, .{ abi.borrow(self), value });
|
||||
}
|
||||
|
||||
/// Text inserted into chat when shift-clicked
|
||||
pub fn insertion(self: TextComponent, text_: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.insertion", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
pub fn font(self: TextComponent, font_: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.font", void, .{ abi.borrow(self), font_ });
|
||||
}
|
||||
|
||||
pub fn shadowColor(self: TextComponent, color: ArgbColor) void {
|
||||
return abi.call(raw.@"[method]text-component.shadow-color", void, .{ abi.borrow(self), color });
|
||||
}
|
||||
|
||||
/// Click events
|
||||
pub fn clickOpenUrl(self: TextComponent, url: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.click-open-url", void, .{ abi.borrow(self), url });
|
||||
}
|
||||
|
||||
pub fn clickOpenFile(self: TextComponent, path: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.click-open-file", void, .{ abi.borrow(self), path });
|
||||
}
|
||||
|
||||
pub fn clickRunCommand(self: TextComponent, command: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.click-run-command", void, .{ abi.borrow(self), command });
|
||||
}
|
||||
|
||||
pub fn clickSuggestCommand(self: TextComponent, command: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.click-suggest-command", void, .{ abi.borrow(self), command });
|
||||
}
|
||||
|
||||
pub fn clickChangePage(self: TextComponent, page: u32) void {
|
||||
return abi.call(raw.@"[method]text-component.click-change-page", void, .{ abi.borrow(self), page });
|
||||
}
|
||||
|
||||
pub fn clickCopyToClipboard(self: TextComponent, text_: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.click-copy-to-clipboard", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
/// Hover events
|
||||
///
|
||||
/// Consumes `text_`.
|
||||
pub fn hoverShowText(self: TextComponent, text_: TextComponent) void {
|
||||
return abi.call(raw.@"[method]text-component.hover-show-text", void, .{ abi.borrow(self), text_ });
|
||||
}
|
||||
|
||||
/// Item data as SNBT string
|
||||
pub fn hoverShowItem(self: TextComponent, item: []const u8) void {
|
||||
return abi.call(raw.@"[method]text-component.hover-show-item", void, .{ abi.borrow(self), item });
|
||||
}
|
||||
|
||||
pub fn hoverShowEntity(self: TextComponent, entity_type: []const u8, id: []const u8, name: ?TextComponent) void {
|
||||
return abi.call(raw.@"[method]text-component.hover-show-entity", void, .{ abi.borrow(self), entity_type, id, name });
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: TextComponent) void {
|
||||
abi.keep(TextComponent, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: TextComponent) void {
|
||||
abi.drop(TextComponent, self);
|
||||
}
|
||||
};
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.text"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.translate"(i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.translate-cross"(i32, i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.entity-names"(i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.keybind"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.custom"(i32, i32, i32, i32, i32, i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.from-legacy-string"(i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.from-legacy-string-with-code"(i32, i32, i32) i32;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[static]text-component.from-json"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.to-json"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.add-child"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.add-text"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.get-text"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.encode"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.to-pretty-console"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.color-named"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.color-rgb"(i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.gradient-named"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.gradient"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.rainbow"(i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.bold"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.italic"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.underlined"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.strikethrough"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.obfuscated"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.insertion"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.font"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.shadow-color"(i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-open-url"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-open-file"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-run-command"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-suggest-command"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-change-page"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.click-copy-to-clipboard"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.hover-show-text"(i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.hover-show-item"(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[method]text-component.hover-show-entity"(i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/text@0.1.0" fn @"[resource-drop]text-component"(i32) void;
|
||||
};
|
||||
30
src/wit/uuid.zig
Normal file
30
src/wit/uuid.zig
Normal file
@ -0,0 +1,30 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
|
||||
/// A 128-bit UUID represented as two 64-bit integers.
|
||||
pub const Uuid = struct {
|
||||
high: u64,
|
||||
low: u64,
|
||||
};
|
||||
|
||||
/// Generates a new random v4 UUID.
|
||||
pub fn generate() Uuid {
|
||||
return abi.call(raw.generate, Uuid, .{});
|
||||
}
|
||||
|
||||
/// Parses a UUID from a string. Returns none if the string is not a valid UUID.
|
||||
pub fn parse(s: []const u8) ?Uuid {
|
||||
return abi.call(raw.parse, ?Uuid, .{s});
|
||||
}
|
||||
|
||||
/// Converts a UUID to its standard string representation.
|
||||
pub fn toString(id: Uuid) []const u8 {
|
||||
return abi.call(raw.@"to-string", []const u8, .{id});
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "pumpkin:plugin/uuid@0.1.0" fn generate(i32) void;
|
||||
extern "pumpkin:plugin/uuid@0.1.0" fn parse(i32, i32, i32) void;
|
||||
extern "pumpkin:plugin/uuid@0.1.0" fn @"to-string"(i64, i64, i32) void;
|
||||
};
|
||||
2055
src/wit/world.zig
Normal file
2055
src/wit/world.zig
Normal file
File diff suppressed because it is too large
Load Diff
818
tools/gen.zig
Normal file
818
tools/gen.zig
Normal file
@ -0,0 +1,818 @@
|
||||
//! Generates the Zig bindings from the output of `wasm-tools component wit --json`.
|
||||
//!
|
||||
//! usage: gen <wit.json> <src-dir>
|
||||
//!
|
||||
//! Writes <src-dir>/wit.zig, one file per interface under <src-dir>/wit/ and
|
||||
//! <src-dir>/wit/exports.zig for the world's exports.
|
||||
|
||||
const std = @import("std");
|
||||
const Allocator = std.mem.Allocator;
|
||||
const Value = std.json.Value;
|
||||
const Writer = std.Io.Writer;
|
||||
|
||||
pub const File = struct {
|
||||
path: []const u8,
|
||||
data: []const u8,
|
||||
};
|
||||
|
||||
const header = "// Generated by tools/gen.zig, do not edit.\n\n";
|
||||
|
||||
fn fatal(comptime fmt: []const u8, args: anytype) noreturn {
|
||||
std.debug.print("gen: " ++ fmt ++ "\n", args);
|
||||
std.process.exit(1);
|
||||
}
|
||||
|
||||
fn oom() noreturn {
|
||||
fatal("out of memory", .{});
|
||||
}
|
||||
|
||||
fn maybe(value: Value, key: []const u8) ?Value {
|
||||
if (value != .object) fatal("expected an object around '{s}'", .{key});
|
||||
const found = value.object.get(key) orelse return null;
|
||||
return if (found == .null) null else found;
|
||||
}
|
||||
|
||||
fn member(value: Value, key: []const u8) Value {
|
||||
return maybe(value, key) orelse fatal("missing '{s}'", .{key});
|
||||
}
|
||||
|
||||
fn items(value: Value) []const Value {
|
||||
if (value != .array) fatal("expected an array", .{});
|
||||
return value.array.items;
|
||||
}
|
||||
|
||||
fn text(value: Value) []const u8 {
|
||||
if (value != .string) fatal("expected a string", .{});
|
||||
return value.string;
|
||||
}
|
||||
|
||||
fn index(value: Value) usize {
|
||||
if (value != .integer) fatal("expected an index", .{});
|
||||
return @intCast(value.integer);
|
||||
}
|
||||
|
||||
const Kind = enum {
|
||||
record,
|
||||
variant,
|
||||
@"enum",
|
||||
flags,
|
||||
tuple,
|
||||
list,
|
||||
option,
|
||||
result,
|
||||
handle,
|
||||
resource,
|
||||
/// `use` or `type x = y`
|
||||
type,
|
||||
};
|
||||
|
||||
const Def = struct { kind: Kind, payload: Value };
|
||||
|
||||
const Core = enum { i32, i64, f32, f64 };
|
||||
|
||||
const Signature = struct {
|
||||
params: []const Core,
|
||||
result: ?Core,
|
||||
/// The result doesn't fit in a single value and goes through memory.
|
||||
indirect: bool,
|
||||
};
|
||||
|
||||
const Scope = std.StringArrayHashMapUnmanaged(void);
|
||||
|
||||
const Gen = struct {
|
||||
arena: Allocator,
|
||||
types: []const Value,
|
||||
interfaces: []const Value,
|
||||
world: Value,
|
||||
/// "pumpkin:plugin"
|
||||
namespace: []const u8,
|
||||
/// "0.1.0"
|
||||
version: []const u8,
|
||||
/// Interfaces the world imports. The rest only contribute types.
|
||||
imports: std.AutoArrayHashMapUnmanaged(usize, void) = .empty,
|
||||
|
||||
/// Interface being written, null for exports.zig.
|
||||
current: ?usize = null,
|
||||
/// Other interfaces the file being written refers to.
|
||||
used: std.AutoArrayHashMapUnmanaged(usize, void) = .empty,
|
||||
/// `used` of the previous pass over the same file. A parameter can't share
|
||||
/// its name with an imported module, and the imports are only known once
|
||||
/// the file has been written.
|
||||
imported: std.AutoArrayHashMapUnmanaged(usize, void) = .empty,
|
||||
|
||||
fn init(arena: Allocator, root: Value) Gen {
|
||||
const packages = items(member(root, "packages"));
|
||||
const worlds = items(member(root, "worlds"));
|
||||
if (packages.len != 1) fatal("expected one package, found {d}", .{packages.len});
|
||||
if (worlds.len != 1) fatal("expected one world, found {d}", .{worlds.len});
|
||||
|
||||
const package = text(member(packages[0], "name"));
|
||||
const at = std.mem.indexOfScalar(u8, package, '@') orelse fatal("package '{s}' has no version", .{package});
|
||||
|
||||
var g: Gen = .{
|
||||
.arena = arena,
|
||||
.types = items(member(root, "types")),
|
||||
.interfaces = items(member(root, "interfaces")),
|
||||
.world = worlds[0],
|
||||
.namespace = package[0..at],
|
||||
.version = package[at + 1 ..],
|
||||
};
|
||||
for (member(g.world, "imports").object.values()) |item| {
|
||||
const iface = maybe(item, "interface") orelse continue;
|
||||
g.imports.put(arena, index(member(iface, "id")), {}) catch oom();
|
||||
}
|
||||
g.validate();
|
||||
return g;
|
||||
}
|
||||
|
||||
fn def(g: *const Gen, id: usize) Def {
|
||||
if (id >= g.types.len) fatal("type {d} out of range", .{id});
|
||||
switch (member(g.types[id], "kind")) {
|
||||
.string => |name| {
|
||||
if (std.mem.eql(u8, name, "resource")) return .{ .kind = .resource, .payload = .null };
|
||||
fatal("unsupported type kind '{s}'", .{name});
|
||||
},
|
||||
.object => |o| {
|
||||
const name = o.keys()[0];
|
||||
const kind = std.meta.stringToEnum(Kind, name) orelse fatal("unsupported type kind '{s}'", .{name});
|
||||
return .{ .kind = kind, .payload = o.values()[0] };
|
||||
},
|
||||
else => fatal("malformed type {d}", .{id}),
|
||||
}
|
||||
}
|
||||
|
||||
fn nameOf(g: *const Gen, id: usize) ?[]const u8 {
|
||||
const name = maybe(g.types[id], "name") orelse return null;
|
||||
return text(name);
|
||||
}
|
||||
|
||||
fn ownerOf(g: *const Gen, id: usize) ?usize {
|
||||
const owner = maybe(g.types[id], "owner") orelse return null;
|
||||
if (owner != .object) return null;
|
||||
return index(owner.object.get("interface") orelse return null);
|
||||
}
|
||||
|
||||
fn interfaceName(g: *const Gen, iface: usize) []const u8 {
|
||||
return text(member(g.interfaces[iface], "name"));
|
||||
}
|
||||
|
||||
fn isBorrow(g: *const Gen, ref: Value) bool {
|
||||
if (ref != .integer) return false;
|
||||
const d = g.def(index(ref));
|
||||
return d.kind == .handle and d.payload.object.contains("borrow");
|
||||
}
|
||||
|
||||
fn isOwn(g: *const Gen, ref: Value) bool {
|
||||
if (ref != .integer) return false;
|
||||
const d = g.def(index(ref));
|
||||
return d.kind == .handle and d.payload.object.contains("own");
|
||||
}
|
||||
|
||||
/// The type references a definition is built from.
|
||||
fn children(g: *const Gen, d: Def) []const Value {
|
||||
var out: std.ArrayList(Value) = .empty;
|
||||
switch (d.kind) {
|
||||
.record => for (items(member(d.payload, "fields"))) |f| out.append(g.arena, member(f, "type")) catch oom(),
|
||||
.variant => for (items(member(d.payload, "cases"))) |c| {
|
||||
if (maybe(c, "type")) |t| out.append(g.arena, t) catch oom();
|
||||
},
|
||||
.tuple => out.appendSlice(g.arena, items(member(d.payload, "types"))) catch oom(),
|
||||
.list, .option, .type => out.append(g.arena, d.payload) catch oom(),
|
||||
.result => {
|
||||
if (maybe(d.payload, "ok")) |t| out.append(g.arena, t) catch oom();
|
||||
if (maybe(d.payload, "err")) |t| out.append(g.arena, t) catch oom();
|
||||
},
|
||||
.@"enum", .flags, .handle, .resource => {},
|
||||
}
|
||||
return out.items;
|
||||
}
|
||||
|
||||
/// Everything the generator or src/abi.zig can't express ends up here
|
||||
/// instead of in bindings that are quietly wrong.
|
||||
fn validate(g: *const Gen) void {
|
||||
for (0..g.types.len) |id| {
|
||||
const d = g.def(id);
|
||||
const label = g.nameOf(id) orelse "(anonymous)";
|
||||
if (d.kind == .flags and items(member(d.payload, "flags")).len > 32) {
|
||||
fatal("flags '{s}' has more than 32 members", .{label});
|
||||
}
|
||||
if (d.kind == .resource) {
|
||||
const owner = g.ownerOf(id) orelse fatal("resource '{s}' has no interface", .{label});
|
||||
if (!g.imports.contains(owner)) fatal("resource '{s}' is exported by the guest, which is not supported", .{label});
|
||||
}
|
||||
for (g.children(d)) |child| {
|
||||
if (g.isBorrow(child)) fatal("'{s}' contains a borrowed handle, only parameters may", .{label});
|
||||
}
|
||||
}
|
||||
|
||||
for (g.interfaces) |iface| {
|
||||
var it = member(iface, "functions").object.iterator();
|
||||
while (it.next()) |entry| g.validateFunc(entry.key_ptr.*, entry.value_ptr.*);
|
||||
}
|
||||
|
||||
var it = member(g.world, "exports").object.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const func = maybe(entry.value_ptr.*, "function") orelse continue;
|
||||
g.validateFunc(entry.key_ptr.*, func);
|
||||
for (items(member(func, "params"))) |p| {
|
||||
if (g.isBorrow(member(p, "type"))) fatal("export '{s}' borrows a handle, which is not supported", .{entry.key_ptr.*});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn validateFunc(g: *const Gen, name: []const u8, func: Value) void {
|
||||
const kind = switch (member(func, "kind")) {
|
||||
.string => |s| s,
|
||||
.object => |o| o.keys()[0],
|
||||
else => fatal("malformed function '{s}'", .{name}),
|
||||
};
|
||||
const known = [_][]const u8{ "freestanding", "method", "static", "constructor" };
|
||||
for (known) |k| {
|
||||
if (std.mem.eql(u8, kind, k)) break;
|
||||
} else fatal("function '{s}' is '{s}', which is not supported", .{ name, kind });
|
||||
|
||||
if (maybe(func, "result")) |result| {
|
||||
if (g.isBorrow(result)) fatal("function '{s}' returns a borrowed handle", .{name});
|
||||
}
|
||||
}
|
||||
|
||||
// naming
|
||||
|
||||
const Style = enum { snake, camel, title };
|
||||
|
||||
fn words(g: *const Gen, name: []const u8, style: Style) []const u8 {
|
||||
var out: std.ArrayList(u8) = .empty;
|
||||
var upper = style == .title;
|
||||
for (name) |c| {
|
||||
if (c == '-' or c == '.' or c == '_') {
|
||||
if (style == .snake) out.append(g.arena, '_') catch oom() else upper = true;
|
||||
continue;
|
||||
}
|
||||
out.append(g.arena, if (upper) std.ascii.toUpper(c) else c) catch oom();
|
||||
upper = false;
|
||||
}
|
||||
return out.items;
|
||||
}
|
||||
|
||||
fn moduleName(g: *const Gen, iface: usize) []const u8 {
|
||||
return g.words(g.interfaceName(iface), .snake);
|
||||
}
|
||||
|
||||
fn funcName(g: *const Gen, func: Value) []const u8 {
|
||||
const full = text(member(func, "name"));
|
||||
if (std.mem.startsWith(u8, full, "[constructor]")) return "init";
|
||||
const base = if (std.mem.indexOfScalar(u8, full, '.')) |dot| full[dot + 1 ..] else full;
|
||||
return g.words(base, .camel);
|
||||
}
|
||||
|
||||
fn declare(g: *const Gen, scope: *Scope, name: []const u8, where: []const u8) void {
|
||||
const entry = scope.getOrPut(g.arena, name) catch oom();
|
||||
if (entry.found_existing) fatal("'{s}' is declared twice in {s}", .{ name, where });
|
||||
}
|
||||
|
||||
fn print(g: *const Gen, comptime fmt: []const u8, args: anytype) []const u8 {
|
||||
return std.fmt.allocPrint(g.arena, fmt, args) catch oom();
|
||||
}
|
||||
|
||||
// type references
|
||||
|
||||
fn primitive(name: []const u8) []const u8 {
|
||||
const map = std.StaticStringMap([]const u8).initComptime(.{
|
||||
.{ "bool", "bool" }, .{ "string", "[]const u8" }, .{ "char", "u21" },
|
||||
.{ "u8", "u8" }, .{ "u16", "u16" }, .{ "u32", "u32" },
|
||||
.{ "u64", "u64" }, .{ "s8", "i8" }, .{ "s16", "i16" },
|
||||
.{ "s32", "i32" }, .{ "s64", "i64" }, .{ "f32", "f32" },
|
||||
.{ "f64", "f64" },
|
||||
});
|
||||
return map.get(name) orelse fatal("unknown primitive '{s}'", .{name});
|
||||
}
|
||||
|
||||
fn writeRef(g: *Gen, w: *Writer, ref: ?Value) Writer.Error!void {
|
||||
switch (ref orelse return w.writeAll("void")) {
|
||||
.string => |s| try w.writeAll(primitive(s)),
|
||||
.integer => try g.writeTypeId(w, index(ref.?)),
|
||||
else => fatal("malformed type reference", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
fn writeTypeId(g: *Gen, w: *Writer, id: usize) Writer.Error!void {
|
||||
const d = g.def(id);
|
||||
if (g.nameOf(id)) |name| {
|
||||
if (g.ownerOf(id)) |owner| {
|
||||
if (g.current != owner) {
|
||||
g.used.put(g.arena, owner, {}) catch oom();
|
||||
try w.print("{s}.", .{g.moduleName(owner)});
|
||||
}
|
||||
return w.writeAll(g.words(name, .title));
|
||||
}
|
||||
// Owned by the world, which only ever aliases interface types.
|
||||
if (d.kind != .type) fatal("the world defines '{s}' itself, which is not supported", .{name});
|
||||
return g.writeRef(w, d.payload);
|
||||
}
|
||||
if (d.kind == .handle) return g.writeTypeId(w, index(d.payload.object.values()[0]));
|
||||
try g.writeShape(w, d);
|
||||
}
|
||||
|
||||
/// list, option, result, tuple or an alias, the kinds that may be anonymous.
|
||||
fn writeShape(g: *Gen, w: *Writer, d: Def) Writer.Error!void {
|
||||
switch (d.kind) {
|
||||
.type => try g.writeRef(w, d.payload),
|
||||
.list => {
|
||||
try w.writeAll("[]const ");
|
||||
try g.writeRef(w, d.payload);
|
||||
},
|
||||
.option => {
|
||||
try w.writeAll("?");
|
||||
try g.writeRef(w, d.payload);
|
||||
},
|
||||
.result => {
|
||||
try w.writeAll("abi.Result(");
|
||||
try g.writeRef(w, maybe(d.payload, "ok"));
|
||||
try w.writeAll(", ");
|
||||
try g.writeRef(w, maybe(d.payload, "err"));
|
||||
try w.writeAll(")");
|
||||
},
|
||||
.tuple => {
|
||||
try w.writeAll("struct { ");
|
||||
for (items(member(d.payload, "types")), 0..) |item, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try g.writeRef(w, item);
|
||||
}
|
||||
try w.writeAll(" }");
|
||||
},
|
||||
else => fatal("'{s}' needs a name", .{@tagName(d.kind)}),
|
||||
}
|
||||
}
|
||||
|
||||
// Flattening. src/abi.zig does the same from the Zig types at comptime and
|
||||
// refuses to compile when the two disagree.
|
||||
|
||||
fn join(a: Core, b: Core) Core {
|
||||
if (a == b) return a;
|
||||
if ((a == .i32 and b == .f32) or (a == .f32 and b == .i32)) return .i32;
|
||||
return .i64;
|
||||
}
|
||||
|
||||
fn flatten(g: *const Gen, ref: ?Value, out: *std.ArrayList(Core)) void {
|
||||
switch (ref orelse return) {
|
||||
.string => |s| {
|
||||
const eql = std.mem.eql;
|
||||
if (eql(u8, s, "string")) return out.appendSlice(g.arena, &.{ .i32, .i32 }) catch oom();
|
||||
const core: Core = if (eql(u8, s, "u64") or eql(u8, s, "s64"))
|
||||
.i64
|
||||
else if (eql(u8, s, "f32"))
|
||||
.f32
|
||||
else if (eql(u8, s, "f64"))
|
||||
.f64
|
||||
else
|
||||
.i32;
|
||||
out.append(g.arena, core) catch oom();
|
||||
},
|
||||
.integer => {
|
||||
const d = g.def(index(ref.?));
|
||||
switch (d.kind) {
|
||||
.type => g.flatten(d.payload, out),
|
||||
.record, .tuple => for (g.children(d)) |child| g.flatten(child, out),
|
||||
.list => out.appendSlice(g.arena, &.{ .i32, .i32 }) catch oom(),
|
||||
.variant => {
|
||||
var payloads: std.ArrayList(?Value) = .empty;
|
||||
for (items(member(d.payload, "cases"))) |c| payloads.append(g.arena, maybe(c, "type")) catch oom();
|
||||
g.flattenCases(payloads.items, out);
|
||||
},
|
||||
.option => g.flattenCases(&.{ null, d.payload }, out),
|
||||
.result => g.flattenCases(&.{ maybe(d.payload, "ok"), maybe(d.payload, "err") }, out),
|
||||
.@"enum", .flags, .handle, .resource => out.append(g.arena, .i32) catch oom(),
|
||||
}
|
||||
},
|
||||
else => fatal("malformed type reference", .{}),
|
||||
}
|
||||
}
|
||||
|
||||
fn flattenCases(g: *const Gen, payloads: []const ?Value, out: *std.ArrayList(Core)) void {
|
||||
var joined: std.ArrayList(Core) = .empty;
|
||||
for (payloads) |payload| {
|
||||
var flat: std.ArrayList(Core) = .empty;
|
||||
g.flatten(payload, &flat);
|
||||
for (flat.items, 0..) |c, i| {
|
||||
if (i < joined.items.len) {
|
||||
joined.items[i] = join(joined.items[i], c);
|
||||
} else {
|
||||
joined.append(g.arena, c) catch oom();
|
||||
}
|
||||
}
|
||||
}
|
||||
out.append(g.arena, .i32) catch oom();
|
||||
out.appendSlice(g.arena, joined.items) catch oom();
|
||||
}
|
||||
|
||||
fn signature(g: *const Gen, func: Value, side: enum { import, @"export" }) Signature {
|
||||
var params: std.ArrayList(Core) = .empty;
|
||||
for (items(member(func, "params"))) |p| g.flatten(member(p, "type"), ¶ms);
|
||||
if (params.items.len > 16) {
|
||||
params.clearRetainingCapacity();
|
||||
params.append(g.arena, .i32) catch oom();
|
||||
}
|
||||
|
||||
var results: std.ArrayList(Core) = .empty;
|
||||
g.flatten(maybe(func, "result"), &results);
|
||||
if (results.items.len <= 1) {
|
||||
const result = if (results.items.len == 1) results.items[0] else null;
|
||||
return .{ .params = params.items, .result = result, .indirect = false };
|
||||
}
|
||||
if (side == .import) {
|
||||
params.append(g.arena, .i32) catch oom();
|
||||
return .{ .params = params.items, .result = null, .indirect = true };
|
||||
}
|
||||
return .{ .params = params.items, .result = .i32, .indirect = true };
|
||||
}
|
||||
|
||||
// declarations
|
||||
|
||||
fn writeDocs(w: *Writer, item: Value, indent: []const u8) Writer.Error!void {
|
||||
const docs = maybe(item, "docs") orelse return;
|
||||
const contents = maybe(docs, "contents") orelse return;
|
||||
var lines = std.mem.splitScalar(u8, text(contents), '\n');
|
||||
while (lines.next()) |line| {
|
||||
const trimmed = std.mem.trimEnd(u8, line, " \r");
|
||||
if (trimmed.len == 0) try w.print("{s}///\n", .{indent}) else try w.print("{s}/// {s}\n", .{ indent, trimmed });
|
||||
}
|
||||
}
|
||||
|
||||
fn fieldName(g: *const Gen, item: Value) std.zig.FormatId {
|
||||
return std.zig.fmtId(g.words(text(member(item, "name")), .snake));
|
||||
}
|
||||
|
||||
fn isPlainAlias(g: *const Gen, id: usize) bool {
|
||||
const d = g.def(id);
|
||||
return d.kind == .type and d.payload == .integer and maybe(g.types[id], "docs") == null;
|
||||
}
|
||||
|
||||
fn writeType(g: *Gen, w: *Writer, id: usize, funcs: Value) Writer.Error!void {
|
||||
const wit_name = g.nameOf(id).?;
|
||||
const name = g.words(wit_name, .title);
|
||||
const d = g.def(id);
|
||||
|
||||
try writeDocs(w, g.types[id], "");
|
||||
try w.print("pub const {s} = ", .{name});
|
||||
|
||||
switch (d.kind) {
|
||||
.record => {
|
||||
try w.writeAll("struct {\n");
|
||||
for (items(member(d.payload, "fields"))) |f| {
|
||||
try writeDocs(w, f, " ");
|
||||
try w.print(" {f}: ", .{g.fieldName(f)});
|
||||
try g.writeRef(w, member(f, "type"));
|
||||
try w.writeAll(",\n");
|
||||
}
|
||||
try w.writeAll("};\n\n");
|
||||
},
|
||||
.variant => {
|
||||
try w.writeAll("union(enum) {\n");
|
||||
for (items(member(d.payload, "cases"))) |c| {
|
||||
try writeDocs(w, c, " ");
|
||||
try w.print(" {f}", .{g.fieldName(c)});
|
||||
if (maybe(c, "type")) |t| {
|
||||
try w.writeAll(": ");
|
||||
try g.writeRef(w, t);
|
||||
}
|
||||
try w.writeAll(",\n");
|
||||
}
|
||||
try w.writeAll("};\n\n");
|
||||
},
|
||||
.@"enum" => {
|
||||
const cases = items(member(d.payload, "cases"));
|
||||
const tag = if (cases.len <= 1 << 8) "u8" else if (cases.len <= 1 << 16) "u16" else "u32";
|
||||
try w.print("enum({s}) {{\n", .{tag});
|
||||
for (cases) |c| {
|
||||
try writeDocs(w, c, " ");
|
||||
try w.print(" {f},\n", .{g.fieldName(c)});
|
||||
}
|
||||
try w.writeAll("};\n\n");
|
||||
},
|
||||
.flags => {
|
||||
const flags = items(member(d.payload, "flags"));
|
||||
const bits: usize = if (flags.len <= 8) 8 else if (flags.len <= 16) 16 else 32;
|
||||
try w.print("packed struct(u{d}) {{\n", .{bits});
|
||||
for (flags) |f| {
|
||||
try writeDocs(w, f, " ");
|
||||
try w.print(" {f}: bool = false,\n", .{g.fieldName(f)});
|
||||
}
|
||||
if (flags.len != bits) try w.print(" _: u{d} = 0,\n", .{bits - flags.len});
|
||||
try w.writeAll("};\n\n");
|
||||
},
|
||||
.resource => {
|
||||
try w.print(
|
||||
\\enum(u32) {{
|
||||
\\ _,
|
||||
\\
|
||||
\\ pub const resource_drop = &raw.{f};
|
||||
\\
|
||||
\\
|
||||
, .{std.zig.fmtId(g.print("[resource-drop]{s}", .{wit_name}))});
|
||||
try g.writeMethods(w, id, name, funcs);
|
||||
try w.print(
|
||||
\\ /// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
\\ pub fn keep(self: {0s}) void {{
|
||||
\\ abi.keep({0s}, self);
|
||||
\\ }}
|
||||
\\
|
||||
\\ /// Releases the handle now instead of when the callback returns.
|
||||
\\ pub fn deinit(self: {0s}) void {{
|
||||
\\ abi.drop({0s}, self);
|
||||
\\ }}
|
||||
\\}};
|
||||
\\
|
||||
\\
|
||||
, .{name});
|
||||
},
|
||||
.handle => fatal("'{s}' names a handle type", .{wit_name}),
|
||||
.type, .list, .option, .result, .tuple => {
|
||||
try g.writeShape(w, d);
|
||||
try w.writeAll(if (g.isPlainAlias(id)) ";\n" else ";\n\n");
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn methodOwner(func: Value) ?usize {
|
||||
const kind = member(func, "kind");
|
||||
if (kind != .object) return null;
|
||||
return index(kind.object.values()[0]);
|
||||
}
|
||||
|
||||
fn writeMethods(g: *Gen, w: *Writer, resource: usize, resource_name: []const u8, funcs: Value) Writer.Error!void {
|
||||
var scope: Scope = .empty;
|
||||
for ([_][]const u8{ "resource_drop", "keep", "deinit" }) |reserved| g.declare(&scope, reserved, resource_name);
|
||||
|
||||
for (funcs.object.values()) |func| {
|
||||
if (methodOwner(func) == resource) g.declare(&scope, g.funcName(func), resource_name);
|
||||
}
|
||||
for (funcs.object.values()) |func| {
|
||||
if (methodOwner(func) == resource) try g.writeFunc(w, func, " ", resource_name, &scope);
|
||||
}
|
||||
}
|
||||
|
||||
fn paramName(g: *const Gen, param: Value, scope: *const Scope) []const u8 {
|
||||
const name = g.words(text(member(param, "name")), .snake);
|
||||
if (scope.contains(name)) return g.print("{s}_", .{name});
|
||||
if (std.mem.eql(u8, name, "abi") or std.mem.eql(u8, name, "raw")) return g.print("{s}_", .{name});
|
||||
for (g.imported.keys()) |iface| {
|
||||
if (std.mem.eql(u8, g.moduleName(iface), name)) return g.print("{s}_", .{name});
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
fn writeFunc(
|
||||
g: *Gen,
|
||||
w: *Writer,
|
||||
func: Value,
|
||||
indent: []const u8,
|
||||
self_type: ?[]const u8,
|
||||
scope: *const Scope,
|
||||
) Writer.Error!void {
|
||||
const params = items(member(func, "params"));
|
||||
const is_method = std.mem.startsWith(u8, text(member(func, "name")), "[method]");
|
||||
|
||||
var names: std.ArrayList([]const u8) = .empty;
|
||||
for (params) |p| names.append(g.arena, g.paramName(p, scope)) catch oom();
|
||||
|
||||
try writeDocs(w, func, indent);
|
||||
var consumes = false;
|
||||
for (params, names.items) |p, name| {
|
||||
if (!g.isOwn(member(p, "type"))) continue;
|
||||
if (!consumes and maybe(func, "docs") != null) try w.print("{s}///\n", .{indent});
|
||||
consumes = true;
|
||||
try w.print("{s}/// Consumes `{s}`.\n", .{ indent, name });
|
||||
}
|
||||
|
||||
try w.print("{s}pub fn {f}(", .{ indent, std.zig.fmtId(g.funcName(func)) });
|
||||
for (params, names.items, 0..) |p, name, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try w.print("{f}: ", .{std.zig.fmtId(name)});
|
||||
if (is_method and i == 0) try w.writeAll(self_type.?) else try g.writeRef(w, member(p, "type"));
|
||||
}
|
||||
try w.writeAll(") ");
|
||||
try g.writeRef(w, maybe(func, "result"));
|
||||
|
||||
try w.print(" {{\n{s} return abi.call(raw.{f}, ", .{ indent, std.zig.fmtId(text(member(func, "name"))) });
|
||||
try g.writeRef(w, maybe(func, "result"));
|
||||
try w.writeAll(if (params.len > 1) ", .{ " else ", .{");
|
||||
for (params, names.items, 0..) |p, name, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
if (g.isBorrow(member(p, "type"))) {
|
||||
try w.print("abi.borrow({f})", .{std.zig.fmtId(name)});
|
||||
} else {
|
||||
try w.print("{f}", .{std.zig.fmtId(name)});
|
||||
}
|
||||
}
|
||||
try w.print("{s});\n{s}}}\n\n", .{ if (params.len > 1) " }" else "}", indent });
|
||||
}
|
||||
|
||||
fn writeRaw(w: *Writer, module: []const u8, name: []const u8, sig: Signature) Writer.Error!void {
|
||||
try w.print(" extern \"{s}\" fn {f}(", .{ module, std.zig.fmtId(name) });
|
||||
for (sig.params, 0..) |p, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try w.writeAll(@tagName(p));
|
||||
}
|
||||
try w.print(") {s};\n", .{if (sig.result) |r| @tagName(r) else "void"});
|
||||
}
|
||||
|
||||
fn writeImports(g: *const Gen, w: *Writer) Writer.Error!void {
|
||||
for (g.used.keys()) |iface| {
|
||||
const name = g.moduleName(iface);
|
||||
try w.print("const {f} = @import(\"{s}.zig\");\n", .{ std.zig.fmtId(name), name });
|
||||
}
|
||||
}
|
||||
|
||||
// files
|
||||
|
||||
fn interfaceFile(g: *Gen, iface: usize) Writer.Error![]const u8 {
|
||||
g.current = iface;
|
||||
g.imported = .empty;
|
||||
_ = try g.interfacePass(iface);
|
||||
g.imported = g.used;
|
||||
return g.interfacePass(iface);
|
||||
}
|
||||
|
||||
fn interfacePass(g: *Gen, iface: usize) Writer.Error![]const u8 {
|
||||
g.used = .empty;
|
||||
const where = g.interfaceName(iface);
|
||||
const types = member(g.interfaces[iface], "types").object;
|
||||
const no_funcs: Value = .{ .object = .empty };
|
||||
const funcs = if (g.imports.contains(iface)) member(g.interfaces[iface], "functions") else no_funcs;
|
||||
const module = g.print("{s}/{s}@{s}", .{ g.namespace, where, g.version });
|
||||
|
||||
var scope: Scope = .empty;
|
||||
for (types.keys()) |name| g.declare(&scope, g.words(name, .title), where);
|
||||
for (funcs.object.values()) |func| {
|
||||
if (methodOwner(func) == null) g.declare(&scope, g.funcName(func), where);
|
||||
}
|
||||
|
||||
var body: Writer.Allocating = .init(g.arena);
|
||||
const w = &body.writer;
|
||||
|
||||
// `use`d types come first in the JSON, keep them together like an import block.
|
||||
var in_aliases = false;
|
||||
for (types.values()) |id| {
|
||||
const is_alias = g.isPlainAlias(index(id));
|
||||
if (in_aliases and !is_alias) try w.writeAll("\n");
|
||||
in_aliases = is_alias;
|
||||
try g.writeType(w, index(id), funcs);
|
||||
}
|
||||
if (in_aliases) try w.writeAll("\n");
|
||||
|
||||
for (funcs.object.values()) |func| {
|
||||
if (methodOwner(func) == null) try g.writeFunc(w, func, "", null, &scope);
|
||||
}
|
||||
|
||||
var raw: Writer.Allocating = .init(g.arena);
|
||||
for (funcs.object.keys(), funcs.object.values()) |name, func| {
|
||||
try writeRaw(&raw.writer, module, name, g.signature(func, .import));
|
||||
}
|
||||
for (types.keys(), types.values()) |name, id| {
|
||||
if (g.def(index(id)).kind != .resource) continue;
|
||||
const drop: Signature = .{ .params = &.{.i32}, .result = null, .indirect = false };
|
||||
try writeRaw(&raw.writer, module, g.print("[resource-drop]{s}", .{name}), drop);
|
||||
}
|
||||
|
||||
var out: Writer.Allocating = .init(g.arena);
|
||||
try out.writer.writeAll(header);
|
||||
const uses_abi = raw.written().len != 0 or std.mem.indexOf(u8, body.written(), "abi.") != null;
|
||||
if (uses_abi) try out.writer.writeAll("const abi = @import(\"../abi.zig\");\n");
|
||||
try g.writeImports(&out.writer);
|
||||
if (uses_abi or g.used.count() != 0) try out.writer.writeAll("\n");
|
||||
try out.writer.writeAll(body.written());
|
||||
if (raw.written().len != 0) try out.writer.print("const raw = struct {{\n{s}}};\n", .{raw.written()});
|
||||
return g.print("{s}\n", .{std.mem.trimEnd(u8, out.written(), "\n")});
|
||||
}
|
||||
|
||||
fn writeExport(g: *Gen, w: *Writer, export_name: []const u8, func: Value) Writer.Error!void {
|
||||
const sig = g.signature(func, .@"export");
|
||||
const params = items(member(func, "params"));
|
||||
const base = if (std.mem.indexOfScalar(u8, export_name, '#')) |hash| export_name[hash + 1 ..] else export_name;
|
||||
|
||||
try writeDocs(w, func, "");
|
||||
try w.print("pub fn {f}(comptime impl: fn (", .{std.zig.fmtId(g.words(base, .camel))});
|
||||
for (params, 0..) |p, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try g.writeRef(w, member(p, "type"));
|
||||
}
|
||||
try w.writeAll(") ");
|
||||
try g.writeRef(w, maybe(func, "result"));
|
||||
|
||||
try w.writeAll(") void {\n const glue = struct {\n fn call(");
|
||||
for (sig.params, 0..) |p, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try w.print("p{d}: {s}", .{ i, @tagName(p) });
|
||||
}
|
||||
try w.print(") callconv(.c) {s} {{\n", .{if (sig.result) |r| @tagName(r) else "void"});
|
||||
|
||||
try w.writeAll(" const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), ");
|
||||
try w.writeAll(if (sig.params.len > 1) ".{ " else ".{");
|
||||
for (sig.params, 0..) |_, i| {
|
||||
if (i != 0) try w.writeAll(", ");
|
||||
try w.print("p{d}", .{i});
|
||||
}
|
||||
try w.writeAll(if (sig.params.len > 1) " });\n" else "});\n");
|
||||
|
||||
if (!sig.indirect) try w.writeAll(" defer abi.endCall();\n");
|
||||
try w.writeAll(" return abi.lowerReturn(");
|
||||
try g.writeRef(w, maybe(func, "result"));
|
||||
try w.writeAll(", @call(.auto, impl, args));\n }\n");
|
||||
|
||||
// The host reads an indirect result after we return, cleanup has to wait for post-return.
|
||||
if (sig.indirect) try w.writeAll("\n fn post(_: i32) callconv(.c) void {\n abi.endCall();\n }\n");
|
||||
try w.print(" }};\n @export(&glue.call, .{{ .name = \"{s}\" }});\n", .{export_name});
|
||||
if (sig.indirect) try w.print(" @export(&glue.post, .{{ .name = \"cabi_post_{s}\" }});\n", .{export_name});
|
||||
try w.writeAll("}\n\n");
|
||||
}
|
||||
|
||||
fn exportsFile(g: *Gen) Writer.Error![]const u8 {
|
||||
g.current = null;
|
||||
g.used = .empty;
|
||||
g.imported = .empty;
|
||||
|
||||
var scope: Scope = .empty;
|
||||
var body: Writer.Allocating = .init(g.arena);
|
||||
const exports = member(g.world, "exports").object;
|
||||
for (exports.keys(), exports.values()) |name, item| {
|
||||
if (maybe(item, "function")) |func| {
|
||||
g.declare(&scope, g.words(name, .camel), "the world's exports");
|
||||
try g.writeExport(&body.writer, name, func);
|
||||
continue;
|
||||
}
|
||||
const iface = index(member(member(item, "interface"), "id"));
|
||||
const funcs = member(g.interfaces[iface], "functions").object;
|
||||
for (funcs.keys(), funcs.values()) |func_name, func| {
|
||||
g.declare(&scope, g.words(func_name, .camel), "the world's exports");
|
||||
const full = g.print("{s}/{s}@{s}#{s}", .{ g.namespace, g.interfaceName(iface), g.version, func_name });
|
||||
try g.writeExport(&body.writer, full, func);
|
||||
}
|
||||
}
|
||||
|
||||
var out: Writer.Allocating = .init(g.arena);
|
||||
try out.writer.writeAll(header ++ "const std = @import(\"std\");\nconst abi = @import(\"../abi.zig\");\n");
|
||||
try g.writeImports(&out.writer);
|
||||
try out.writer.print("\n{s}\n", .{std.mem.trimEnd(u8, body.written(), "\n")});
|
||||
return out.written();
|
||||
}
|
||||
};
|
||||
|
||||
/// Paths are relative to the source directory.
|
||||
pub fn generate(arena: Allocator, source: []const u8) ![]const File {
|
||||
const root = try std.json.parseFromSliceLeaky(Value, arena, source, .{});
|
||||
var g: Gen = .init(arena, root);
|
||||
|
||||
var files: std.ArrayList(File) = .empty;
|
||||
var root_file: Writer.Allocating = .init(arena);
|
||||
try root_file.writer.writeAll(header);
|
||||
|
||||
for (0..g.interfaces.len) |iface| {
|
||||
const name = g.moduleName(iface);
|
||||
if (std.mem.eql(u8, name, "exports")) fatal("an interface is called 'exports'", .{});
|
||||
try files.append(arena, .{ .path = g.print("wit/{s}.zig", .{name}), .data = try g.interfaceFile(iface) });
|
||||
try root_file.writer.print("pub const {f} = @import(\"wit/{s}.zig\");\n", .{ std.zig.fmtId(name), name });
|
||||
}
|
||||
|
||||
try files.append(arena, .{ .path = "wit/exports.zig", .data = try g.exportsFile() });
|
||||
try root_file.writer.writeAll("pub const exports = @import(\"wit/exports.zig\");\n");
|
||||
try files.append(arena, .{ .path = "wit.zig", .data = root_file.written() });
|
||||
return files.items;
|
||||
}
|
||||
|
||||
pub fn main(init: std.process.Init) !void {
|
||||
const arena = init.arena.allocator();
|
||||
const io = init.io;
|
||||
const args = try init.minimal.args.toSlice(arena);
|
||||
if (args.len != 3) fatal("usage: gen <wit.json> <src-dir>", .{});
|
||||
|
||||
const cwd = std.Io.Dir.cwd();
|
||||
const source = cwd.readFileAlloc(io, args[1], arena, .unlimited) catch |err| {
|
||||
fatal("can't read {s}: {t}", .{ args[1], err });
|
||||
};
|
||||
|
||||
const out = try cwd.createDirPathOpen(io, args[2], .{});
|
||||
try out.createDirPath(io, "wit");
|
||||
for (try generate(arena, source)) |file| {
|
||||
try out.writeFile(io, .{ .sub_path = file.path, .data = file.data });
|
||||
}
|
||||
}
|
||||
|
||||
test "demo world" {
|
||||
var arena_state: std.heap.ArenaAllocator = .init(std.testing.allocator);
|
||||
defer arena_state.deinit();
|
||||
|
||||
const expected = [_]File{
|
||||
.{ .path = "wit/types.zig", .data = @embedFile("testdata/expected/wit/types.zig") },
|
||||
.{ .path = "wit/host.zig", .data = @embedFile("testdata/expected/wit/host.zig") },
|
||||
.{ .path = "wit/guest.zig", .data = @embedFile("testdata/expected/wit/guest.zig") },
|
||||
.{ .path = "wit/exports.zig", .data = @embedFile("testdata/expected/wit/exports.zig") },
|
||||
.{ .path = "wit.zig", .data = @embedFile("testdata/expected/wit.zig") },
|
||||
};
|
||||
|
||||
const files = try generate(arena_state.allocator(), @embedFile("testdata/demo.json"));
|
||||
try std.testing.expectEqual(expected.len, files.len);
|
||||
for (expected, files) |want, got| {
|
||||
try std.testing.expectEqualStrings(want.path, got.path);
|
||||
try std.testing.expectEqualStrings(want.data, got.data);
|
||||
}
|
||||
}
|
||||
507
tools/testdata/demo.json
vendored
Normal file
507
tools/testdata/demo.json
vendored
Normal file
@ -0,0 +1,507 @@
|
||||
{
|
||||
"worlds": [
|
||||
{
|
||||
"name": "plugin",
|
||||
"imports": {
|
||||
"interface-0": {
|
||||
"interface": {
|
||||
"id": 0
|
||||
}
|
||||
},
|
||||
"interface-1": {
|
||||
"interface": {
|
||||
"id": 1
|
||||
}
|
||||
},
|
||||
"canvas": {
|
||||
"type": 17
|
||||
},
|
||||
"shape": {
|
||||
"type": 18
|
||||
},
|
||||
"pair": {
|
||||
"type": 19
|
||||
}
|
||||
},
|
||||
"exports": {
|
||||
"start": {
|
||||
"function": {
|
||||
"name": "start",
|
||||
"kind": "freestanding",
|
||||
"params": [
|
||||
{
|
||||
"name": "canvas",
|
||||
"type": 21
|
||||
}
|
||||
],
|
||||
"result": 20
|
||||
}
|
||||
},
|
||||
"measure": {
|
||||
"function": {
|
||||
"name": "measure",
|
||||
"kind": "freestanding",
|
||||
"params": [
|
||||
{
|
||||
"name": "shape",
|
||||
"type": 18
|
||||
},
|
||||
{
|
||||
"name": "scale",
|
||||
"type": 19
|
||||
}
|
||||
],
|
||||
"result": "f32"
|
||||
}
|
||||
},
|
||||
"stop": {
|
||||
"function": {
|
||||
"name": "stop",
|
||||
"kind": "freestanding",
|
||||
"params": []
|
||||
}
|
||||
},
|
||||
"interface-2": {
|
||||
"interface": {
|
||||
"id": 2
|
||||
}
|
||||
}
|
||||
},
|
||||
"package": 0
|
||||
}
|
||||
],
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "types",
|
||||
"types": {
|
||||
"point": 1,
|
||||
"color": 2,
|
||||
"access": 3,
|
||||
"shape": 5,
|
||||
"pair": 6,
|
||||
"names": 7
|
||||
},
|
||||
"functions": {},
|
||||
"package": 0
|
||||
},
|
||||
{
|
||||
"name": "host",
|
||||
"types": {
|
||||
"point": 8,
|
||||
"color": 9,
|
||||
"shape": 10,
|
||||
"access": 11,
|
||||
"canvas": 12
|
||||
},
|
||||
"functions": {
|
||||
"[constructor]canvas": {
|
||||
"name": "[constructor]canvas",
|
||||
"kind": {
|
||||
"constructor": 12
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"name": "width",
|
||||
"type": "u32"
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"type": "u32"
|
||||
}
|
||||
],
|
||||
"result": 13
|
||||
},
|
||||
"[static]canvas.open": {
|
||||
"name": "[static]canvas.open",
|
||||
"kind": {
|
||||
"static": 12
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"name": "path",
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"result": 14,
|
||||
"docs": {
|
||||
"contents": "Opens a canvas stored on disk."
|
||||
}
|
||||
},
|
||||
"[method]canvas.draw": {
|
||||
"name": "[method]canvas.draw",
|
||||
"kind": {
|
||||
"method": 12
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"name": "self",
|
||||
"type": 15
|
||||
},
|
||||
{
|
||||
"name": "shape",
|
||||
"type": 10
|
||||
},
|
||||
{
|
||||
"name": "at",
|
||||
"type": 8
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"type": 9
|
||||
}
|
||||
]
|
||||
},
|
||||
"[method]canvas.blend": {
|
||||
"name": "[method]canvas.blend",
|
||||
"kind": {
|
||||
"method": 12
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"name": "self",
|
||||
"type": 15
|
||||
},
|
||||
{
|
||||
"name": "other",
|
||||
"type": 15
|
||||
},
|
||||
{
|
||||
"name": "types",
|
||||
"type": 11
|
||||
}
|
||||
],
|
||||
"docs": {
|
||||
"contents": "Copies `other` on top of this canvas."
|
||||
}
|
||||
},
|
||||
"[method]canvas.name": {
|
||||
"name": "[method]canvas.name",
|
||||
"kind": {
|
||||
"method": 12
|
||||
},
|
||||
"params": [
|
||||
{
|
||||
"name": "self",
|
||||
"type": 15
|
||||
}
|
||||
],
|
||||
"result": 0
|
||||
},
|
||||
"present": {
|
||||
"name": "present",
|
||||
"kind": "freestanding",
|
||||
"params": [
|
||||
{
|
||||
"name": "canvas",
|
||||
"type": 13
|
||||
}
|
||||
],
|
||||
"result": "u64",
|
||||
"docs": {
|
||||
"contents": "Shows the canvas and closes it."
|
||||
}
|
||||
},
|
||||
"log": {
|
||||
"name": "log",
|
||||
"kind": "freestanding",
|
||||
"params": [
|
||||
{
|
||||
"name": "message",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"package": 0
|
||||
},
|
||||
{
|
||||
"name": "guest",
|
||||
"types": {
|
||||
"point": 16
|
||||
},
|
||||
"functions": {
|
||||
"describe": {
|
||||
"name": "describe",
|
||||
"kind": "freestanding",
|
||||
"params": [],
|
||||
"result": 16
|
||||
}
|
||||
},
|
||||
"package": 0
|
||||
}
|
||||
],
|
||||
"types": [
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"option": "string"
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": "point",
|
||||
"kind": {
|
||||
"record": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "x",
|
||||
"type": "s32"
|
||||
},
|
||||
{
|
||||
"name": "y",
|
||||
"type": "s32"
|
||||
},
|
||||
{
|
||||
"name": "label",
|
||||
"type": 0,
|
||||
"docs": {
|
||||
"contents": "Optional label."
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
},
|
||||
"docs": {
|
||||
"contents": "Where something is."
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"kind": {
|
||||
"enum": {
|
||||
"cases": [
|
||||
{
|
||||
"name": "red"
|
||||
},
|
||||
{
|
||||
"name": "green"
|
||||
},
|
||||
{
|
||||
"name": "blue"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "access",
|
||||
"kind": {
|
||||
"flags": {
|
||||
"flags": [
|
||||
{
|
||||
"name": "read"
|
||||
},
|
||||
{
|
||||
"name": "write"
|
||||
},
|
||||
{
|
||||
"name": "exec"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"list": 1
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": "shape",
|
||||
"kind": {
|
||||
"variant": {
|
||||
"cases": [
|
||||
{
|
||||
"name": "nothing",
|
||||
"type": null
|
||||
},
|
||||
{
|
||||
"name": "circle",
|
||||
"type": "f32"
|
||||
},
|
||||
{
|
||||
"name": "polygon",
|
||||
"type": 4
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pair",
|
||||
"kind": {
|
||||
"tuple": {
|
||||
"types": [
|
||||
"u8",
|
||||
"f64"
|
||||
]
|
||||
}
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "names",
|
||||
"kind": {
|
||||
"list": "string"
|
||||
},
|
||||
"owner": {
|
||||
"interface": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "point",
|
||||
"kind": {
|
||||
"type": 1
|
||||
},
|
||||
"owner": {
|
||||
"interface": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"kind": {
|
||||
"type": 2
|
||||
},
|
||||
"owner": {
|
||||
"interface": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shape",
|
||||
"kind": {
|
||||
"type": 5
|
||||
},
|
||||
"owner": {
|
||||
"interface": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "access",
|
||||
"kind": {
|
||||
"type": 3
|
||||
},
|
||||
"owner": {
|
||||
"interface": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "canvas",
|
||||
"kind": "resource",
|
||||
"owner": {
|
||||
"interface": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"handle": {
|
||||
"own": 12
|
||||
}
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"result": {
|
||||
"ok": 13,
|
||||
"err": "string"
|
||||
}
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"handle": {
|
||||
"borrow": 12
|
||||
}
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": "point",
|
||||
"kind": {
|
||||
"type": 1
|
||||
},
|
||||
"owner": {
|
||||
"interface": 2
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "canvas",
|
||||
"kind": {
|
||||
"type": 12
|
||||
},
|
||||
"owner": {
|
||||
"world": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "shape",
|
||||
"kind": {
|
||||
"type": 5
|
||||
},
|
||||
"owner": {
|
||||
"world": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "pair",
|
||||
"kind": {
|
||||
"type": 6
|
||||
},
|
||||
"owner": {
|
||||
"world": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"result": {
|
||||
"ok": null,
|
||||
"err": "string"
|
||||
}
|
||||
},
|
||||
"owner": null
|
||||
},
|
||||
{
|
||||
"name": null,
|
||||
"kind": {
|
||||
"handle": {
|
||||
"own": 17
|
||||
}
|
||||
},
|
||||
"owner": null
|
||||
}
|
||||
],
|
||||
"packages": [
|
||||
{
|
||||
"name": "demo:gen@1.2.0",
|
||||
"interfaces": {
|
||||
"types": 0,
|
||||
"host": 1,
|
||||
"guest": 2
|
||||
},
|
||||
"worlds": {
|
||||
"plugin": 0
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
6
tools/testdata/expected/wit.zig
vendored
Normal file
6
tools/testdata/expected/wit.zig
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
pub const types = @import("wit/types.zig");
|
||||
pub const host = @import("wit/host.zig");
|
||||
pub const guest = @import("wit/guest.zig");
|
||||
pub const exports = @import("wit/exports.zig");
|
||||
59
tools/testdata/expected/wit/exports.zig
vendored
Normal file
59
tools/testdata/expected/wit/exports.zig
vendored
Normal file
@ -0,0 +1,59 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const std = @import("std");
|
||||
const abi = @import("../abi.zig");
|
||||
const host = @import("host.zig");
|
||||
const types = @import("types.zig");
|
||||
const guest = @import("guest.zig");
|
||||
|
||||
pub fn start(comptime impl: fn (host.Canvas) abi.Result(void, []const u8)) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32) callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{p0});
|
||||
return abi.lowerReturn(abi.Result(void, []const u8), @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "start" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_start" });
|
||||
}
|
||||
|
||||
pub fn measure(comptime impl: fn (types.Shape, types.Pair) f32) void {
|
||||
const glue = struct {
|
||||
fn call(p0: i32, p1: i32, p2: i32, p3: i32, p4: f64) callconv(.c) f32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{ p0, p1, p2, p3, p4 });
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(f32, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "measure" });
|
||||
}
|
||||
|
||||
pub fn stop(comptime impl: fn () void) void {
|
||||
const glue = struct {
|
||||
fn call() callconv(.c) void {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{});
|
||||
defer abi.endCall();
|
||||
return abi.lowerReturn(void, @call(.auto, impl, args));
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "stop" });
|
||||
}
|
||||
|
||||
pub fn describe(comptime impl: fn () guest.Point) void {
|
||||
const glue = struct {
|
||||
fn call() callconv(.c) i32 {
|
||||
const args = abi.liftArgs(std.meta.ArgsTuple(@TypeOf(impl)), .{});
|
||||
return abi.lowerReturn(guest.Point, @call(.auto, impl, args));
|
||||
}
|
||||
|
||||
fn post(_: i32) callconv(.c) void {
|
||||
abi.endCall();
|
||||
}
|
||||
};
|
||||
@export(&glue.call, .{ .name = "demo:gen/guest@1.2.0#describe" });
|
||||
@export(&glue.post, .{ .name = "cabi_post_demo:gen/guest@1.2.0#describe" });
|
||||
}
|
||||
5
tools/testdata/expected/wit/guest.zig
vendored
Normal file
5
tools/testdata/expected/wit/guest.zig
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const types = @import("types.zig");
|
||||
|
||||
pub const Point = types.Point;
|
||||
69
tools/testdata/expected/wit/host.zig
vendored
Normal file
69
tools/testdata/expected/wit/host.zig
vendored
Normal file
@ -0,0 +1,69 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
const abi = @import("../abi.zig");
|
||||
const types = @import("types.zig");
|
||||
|
||||
pub const Point = types.Point;
|
||||
pub const Color = types.Color;
|
||||
pub const Shape = types.Shape;
|
||||
pub const Access = types.Access;
|
||||
|
||||
pub const Canvas = enum(u32) {
|
||||
_,
|
||||
|
||||
pub const resource_drop = &raw.@"[resource-drop]canvas";
|
||||
|
||||
pub fn init(width: u32, height: u32) Canvas {
|
||||
return abi.call(raw.@"[constructor]canvas", Canvas, .{ width, height });
|
||||
}
|
||||
|
||||
/// Opens a canvas stored on disk.
|
||||
pub fn open(path: []const u8) abi.Result(Canvas, []const u8) {
|
||||
return abi.call(raw.@"[static]canvas.open", abi.Result(Canvas, []const u8), .{path});
|
||||
}
|
||||
|
||||
pub fn draw(self: Canvas, shape: Shape, at: Point, color: Color) void {
|
||||
return abi.call(raw.@"[method]canvas.draw", void, .{ abi.borrow(self), shape, at, color });
|
||||
}
|
||||
|
||||
/// Copies `other` on top of this canvas.
|
||||
pub fn blend(self: Canvas, other: Canvas, types_: Access) void {
|
||||
return abi.call(raw.@"[method]canvas.blend", void, .{ abi.borrow(self), abi.borrow(other), types_ });
|
||||
}
|
||||
|
||||
pub fn name(self: Canvas) ?[]const u8 {
|
||||
return abi.call(raw.@"[method]canvas.name", ?[]const u8, .{abi.borrow(self)});
|
||||
}
|
||||
|
||||
/// Keeps the handle alive past the current callback. Release it with `deinit`.
|
||||
pub fn keep(self: Canvas) void {
|
||||
abi.keep(Canvas, self);
|
||||
}
|
||||
|
||||
/// Releases the handle now instead of when the callback returns.
|
||||
pub fn deinit(self: Canvas) void {
|
||||
abi.drop(Canvas, self);
|
||||
}
|
||||
};
|
||||
|
||||
/// Shows the canvas and closes it.
|
||||
///
|
||||
/// Consumes `canvas`.
|
||||
pub fn present(canvas: Canvas) u64 {
|
||||
return abi.call(raw.present, u64, .{canvas});
|
||||
}
|
||||
|
||||
pub fn log(message: []const u8) void {
|
||||
return abi.call(raw.log, void, .{message});
|
||||
}
|
||||
|
||||
const raw = struct {
|
||||
extern "demo:gen/host@1.2.0" fn @"[constructor]canvas"(i32, i32) i32;
|
||||
extern "demo:gen/host@1.2.0" fn @"[static]canvas.open"(i32, i32, i32) void;
|
||||
extern "demo:gen/host@1.2.0" fn @"[method]canvas.draw"(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) void;
|
||||
extern "demo:gen/host@1.2.0" fn @"[method]canvas.blend"(i32, i32, i32) void;
|
||||
extern "demo:gen/host@1.2.0" fn @"[method]canvas.name"(i32, i32) void;
|
||||
extern "demo:gen/host@1.2.0" fn present(i32) i64;
|
||||
extern "demo:gen/host@1.2.0" fn log(i32, i32) void;
|
||||
extern "demo:gen/host@1.2.0" fn @"[resource-drop]canvas"(i32) void;
|
||||
};
|
||||
32
tools/testdata/expected/wit/types.zig
vendored
Normal file
32
tools/testdata/expected/wit/types.zig
vendored
Normal file
@ -0,0 +1,32 @@
|
||||
// Generated by tools/gen.zig, do not edit.
|
||||
|
||||
/// Where something is.
|
||||
pub const Point = struct {
|
||||
x: i32,
|
||||
y: i32,
|
||||
/// Optional label.
|
||||
label: ?[]const u8,
|
||||
};
|
||||
|
||||
pub const Color = enum(u8) {
|
||||
red,
|
||||
green,
|
||||
blue,
|
||||
};
|
||||
|
||||
pub const Access = packed struct(u8) {
|
||||
read: bool = false,
|
||||
write: bool = false,
|
||||
exec: bool = false,
|
||||
_: u5 = 0,
|
||||
};
|
||||
|
||||
pub const Shape = union(enum) {
|
||||
nothing,
|
||||
circle: f32,
|
||||
polygon: []const Point,
|
||||
};
|
||||
|
||||
pub const Pair = struct { u8, f64 };
|
||||
|
||||
pub const Names = []const []const u8;
|
||||
60
tools/testdata/wit/demo.wit
vendored
Normal file
60
tools/testdata/wit/demo.wit
vendored
Normal file
@ -0,0 +1,60 @@
|
||||
package demo:gen@1.2.0;
|
||||
|
||||
interface types {
|
||||
/// Where something is.
|
||||
record point {
|
||||
x: s32,
|
||||
y: s32,
|
||||
/// Optional label.
|
||||
label: option<string>,
|
||||
}
|
||||
|
||||
enum color { red, green, blue }
|
||||
|
||||
flags access { read, write, exec }
|
||||
|
||||
variant shape {
|
||||
nothing,
|
||||
circle(f32),
|
||||
polygon(list<point>),
|
||||
}
|
||||
|
||||
type pair = tuple<u8, f64>;
|
||||
type names = list<string>;
|
||||
}
|
||||
|
||||
interface host {
|
||||
use types.{point, color, shape, access};
|
||||
|
||||
resource canvas {
|
||||
constructor(width: u32, height: u32);
|
||||
/// Opens a canvas stored on disk.
|
||||
open: static func(path: string) -> result<canvas, string>;
|
||||
draw: func(shape: shape, at: point, color: color);
|
||||
/// Copies `other` on top of this canvas.
|
||||
blend: func(other: borrow<canvas>, types: access);
|
||||
name: func() -> option<string>;
|
||||
}
|
||||
|
||||
/// Shows the canvas and closes it.
|
||||
present: func(canvas: canvas) -> u64;
|
||||
log: func(message: string);
|
||||
}
|
||||
|
||||
interface guest {
|
||||
use types.{point};
|
||||
|
||||
describe: func() -> point;
|
||||
}
|
||||
|
||||
world plugin {
|
||||
use host.{canvas};
|
||||
use types.{shape, pair};
|
||||
|
||||
import host;
|
||||
|
||||
export guest;
|
||||
export start: func(canvas: canvas) -> result<_, string>;
|
||||
export measure: func(shape: shape, scale: pair) -> f32;
|
||||
export stop: func();
|
||||
}
|
||||
1
wit
Submodule
1
wit
Submodule
@ -0,0 +1 @@
|
||||
Subproject commit 2366bb9edb3d9a093e3f579c3dac541eba70e6d7
|
||||
Loading…
Reference in New Issue
Block a user