Test mod
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
# Example Mod
|
||||
|
||||
Made by you. List where textures and other assets come from and their licenses here.
|
||||
@@ -0,0 +1,31 @@
|
||||
# Example Mod
|
||||
|
||||
A bworld mod. The format is described in `MODS.md` at the root of the bworld repo.
|
||||
|
||||
## Files
|
||||
|
||||
| Path | What it's for |
|
||||
| --------------------- | ------------------------------------------------------------------------------------ |
|
||||
| `manifest.json` | The mod's id, name, version, dependencies and scripts. |
|
||||
| `blocks/*.json` | One block per file. Blocks get an item form with the same id unless `"item": false`. |
|
||||
| `items/*.json` | Items that aren't a block's item form. |
|
||||
| `recipes/*.json` | `shaped` crafting, `furnace` smelting and `fuel`. |
|
||||
| `textures/*.png` | 16×16 textures, named `example_mod:<file name>`. |
|
||||
| `worldgen/ores.json` | Ores to generate (optional, not included here). |
|
||||
| `scripts/server.ts` | Game logic: block components, commands, events. Never sent to players. |
|
||||
| `scripts/client.ts` | Sent to players: custom screens, HUD, keybinds. |
|
||||
| `scripts/worldgen.ts` | Terrain features. Runs on the server and every client and must be deterministic. |
|
||||
| `CREDITS.md` | Licenses and thanks, shown on the About page. |
|
||||
|
||||
Delete what you don't use, including its entry in `manifest.json`.
|
||||
|
||||
## Checking it
|
||||
|
||||
From the bworld repo:
|
||||
|
||||
```sh
|
||||
deno task check-mods
|
||||
```
|
||||
|
||||
This validates the manifest and every data file, checks that the ids, textures and items you refer to exist, and
|
||||
typechecks the scripts.
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"block": {
|
||||
"id": "example_mod:example_block",
|
||||
"textures": "example_mod:example_block",
|
||||
"mining": { "toughness": 3, "tool": "pickaxe", "requires_tool": false },
|
||||
"drops": "example_mod:example_block",
|
||||
"interactive": true,
|
||||
"components": {
|
||||
"example_mod:announce": { "message": "You found the example block!" }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"item": {
|
||||
"id": "example_mod:example_item",
|
||||
"texture": "example_mod:example_item",
|
||||
"lore": "Four of these make an example block."
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"id": "example_mod",
|
||||
"name": "Example Mod",
|
||||
"description": "What this mod adds, in a sentence or two.",
|
||||
"version": "0.1.0",
|
||||
"authors": [],
|
||||
"game_version": ">=0.1.0",
|
||||
"dependencies": [
|
||||
{ "id": "bworld", "version": ">=0.1.0" }
|
||||
],
|
||||
"scripts": {
|
||||
"server": "scripts/server.ts",
|
||||
"client": "scripts/client.ts",
|
||||
"worldgen": "scripts/worldgen.ts"
|
||||
},
|
||||
"credits": "CREDITS.md"
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"format_version": 1,
|
||||
"recipe": {
|
||||
"type": "shaped",
|
||||
"pattern": ["EE", "EE"],
|
||||
"key": { "E": "example_mod:example_item" },
|
||||
"result": { "id": "example_mod:example_block", "count": 1 }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { ClientContext } from "bworld/client";
|
||||
|
||||
// called on every player's client after the mod is downloaded, before the world shows up.
|
||||
// everything here is visible to players, so keep secrets and game rules in server.ts
|
||||
export function setup(ctx: ClientContext) {
|
||||
ctx.log("loaded");
|
||||
|
||||
// a HUD element, drawn every frame
|
||||
// ctx.hud.register("example_mod:hint", {
|
||||
// on_render(g) {
|
||||
// g.text("example mod is here", 8, 8);
|
||||
// },
|
||||
// });
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
import type { ServerContext } from "bworld/server";
|
||||
|
||||
// called once when the server starts
|
||||
export function setup(ctx: ServerContext) {
|
||||
// used by blocks/example_block.json, which passes { message } as params
|
||||
ctx.components.register_block<{ message: string }>("example_mod:announce", {
|
||||
on_interact(_block, params, player) {
|
||||
player.send_message(params.message);
|
||||
// handled, so right clicking it doesn't place a block
|
||||
return true;
|
||||
},
|
||||
});
|
||||
|
||||
// /example_mod:hello, or /hello when no other mod uses that name
|
||||
ctx.commands.register("hello", {
|
||||
description: "Say hello",
|
||||
usage: "/hello",
|
||||
run(_args, player) {
|
||||
player.send_message(`Hello ${player.name}!`);
|
||||
},
|
||||
});
|
||||
|
||||
ctx.events.after.player_join.subscribe(({ player }) => {
|
||||
ctx.log(`${player.name} joined`);
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { WorldgenContext } from "bworld/worldgen";
|
||||
|
||||
// runs in chunk workers on the server and every client, which must all generate the same world.
|
||||
// only use chunk.rng and the noise helpers, never Math.random or the time
|
||||
export function setup(gen: WorldgenContext) {
|
||||
// a boulder on one chunk in ten
|
||||
gen.register_feature("example_mod:boulders", (chunk) => {
|
||||
if (chunk.rng.next() > 0.1) {
|
||||
return;
|
||||
}
|
||||
const x = chunk.x * 16 + Math.floor(chunk.rng.next() * 16);
|
||||
const z = chunk.z * 16 + Math.floor(chunk.rng.next() * 16);
|
||||
chunk.set_block(x, chunk.height_at(x, z) + 1, z, "bworld:stone");
|
||||
});
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 201 B |
Binary file not shown.
|
After Width: | Height: | Size: 189 B |
Reference in New Issue
Block a user