Item entities
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
import { assert, assertEquals } from "@std/assert";
|
||||
import { ItemStack } from "$/common/inventory.ts";
|
||||
import { test_game } from "./helpers.ts";
|
||||
|
||||
// a stone floor at y 99 so drops have something to land on, high above the generated terrain
|
||||
function build_floor(game: Awaited<ReturnType<typeof test_game>>["game"]) {
|
||||
for (let x = -3; x <= 9; x++) {
|
||||
for (let z = -4; z <= 4; z++) {
|
||||
game.set_block(x, 99, z, "bworld:stone");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const inventory_count = (
|
||||
messages: { type: string; container?: string; items?: ({ id: string; count: number } | null)[] }[],
|
||||
id: string,
|
||||
) => (messages.filter((m) => m.type === "container" && m.container === "inventory").at(-1)?.items ?? [])
|
||||
.reduce((sum, item) => sum + (item?.id === id ? item.count : 0), 0);
|
||||
|
||||
Deno.test("breaking a block drops its item, which lands and gets picked up by walking to it", async () => {
|
||||
const { game, take, send, join } = await test_game("mods");
|
||||
join(1, "alice");
|
||||
build_floor(game);
|
||||
game.set_block(5, 100, 0, "bworld:dirt");
|
||||
send(1, { type: "move", x: 0.5, y: 100, z: 0.5, yaw: 0, pitch: 0 });
|
||||
take(1);
|
||||
|
||||
send(1, { type: "break_block", x: 5, y: 100, z: 0 });
|
||||
const messages = take(1);
|
||||
const added = messages.find((m) => m.type === "add_entity");
|
||||
assertEquals(added?.entity.kind, "item");
|
||||
assertEquals(added?.entity.item, { id: "bworld:dirt", count: 1 });
|
||||
assertEquals(inventory_count(messages, "bworld:dirt"), 0, "it drops instead of going into the inventory");
|
||||
|
||||
for (let i = 0; i < 40; i++) game.tick();
|
||||
const [item] = game.item_entities();
|
||||
assert(item.on_ground, "it fell onto the floor");
|
||||
assertEquals(item.y, 100);
|
||||
assert(Math.abs(item.x - 5.5) < 1.5 && Math.abs(item.z - 0.5) < 1.5, "it stays near the block");
|
||||
assert(take(1).some((m) => m.type === "move_entity" && m.id === item.id));
|
||||
|
||||
send(1, { type: "move", x: item.x, y: 100, z: item.z, yaw: 0, pitch: 0 });
|
||||
game.tick();
|
||||
const picked = take(1);
|
||||
assert(picked.some((m) => m.type === "take_entity" && m.id === item.id));
|
||||
assertEquals(inventory_count(picked, "bworld:dirt"), 1);
|
||||
assertEquals(game.item_entities(), []);
|
||||
});
|
||||
|
||||
Deno.test("items that don't fit in the inventory drop at the player's feet and stay there", async () => {
|
||||
const { game, take, send, join } = await test_game("mods");
|
||||
join(1, "alice");
|
||||
build_floor(game);
|
||||
send(1, { type: "move", x: 0.5, y: 100, z: 0.5, yaw: 0, pitch: 0 });
|
||||
|
||||
// a full inventory, then 10 more
|
||||
send(1, { type: "chat", text: `/give bworld:stone ${64 * 36}` });
|
||||
assertEquals(game.item_entities(), []);
|
||||
send(1, { type: "chat", text: "/give bworld:stone 10" });
|
||||
const [item] = game.item_entities();
|
||||
assertEquals(item.item.amount, 10);
|
||||
|
||||
for (let i = 0; i < 60; i++) game.tick();
|
||||
assertEquals(game.item_entities().length, 1, "a full inventory can't pick it up");
|
||||
assert(take(1).some((m) => m.type === "add_entity"));
|
||||
});
|
||||
|
||||
Deno.test("stacks next to each other merge, and items on the ground are saved with the world", async () => {
|
||||
const { game, join } = await test_game("mods");
|
||||
join(1, "alice");
|
||||
build_floor(game);
|
||||
for (let i = 0; i < 3; i++) {
|
||||
game.spawn_item(6.5, 100, 0.5, new ItemStack("bworld:dirt", 2));
|
||||
}
|
||||
game.tick();
|
||||
game.tick();
|
||||
assertEquals(game.item_entities().map((entity) => entity.item.amount), [6]);
|
||||
|
||||
const saved = game.save();
|
||||
const reloaded = await test_game("mods", saved);
|
||||
assertEquals(reloaded.game.item_entities().map((entity) => [entity.item.type_id, entity.item.amount]), [[
|
||||
"bworld:dirt",
|
||||
6,
|
||||
]]);
|
||||
const joined = reloaded.join(2, "bob");
|
||||
assertEquals(joined.entities.map((entity: { item: unknown }) => entity.item), [{ id: "bworld:dirt", count: 6 }]);
|
||||
});
|
||||
Reference in New Issue
Block a user