From 05f80c81ad4029e3e31aa9843fc67578b5f9af7a Mon Sep 17 00:00:00 2001 From: paulaboks Date: Fri, 25 Sep 2026 17:21:46 -0300 Subject: [PATCH] Remove collision from water --- client/entity/entity.ts | 3 +-- client/level/client_level.ts | 6 ++++++ mods/bworld/blocks/chest.json | 1 - mods/bworld/blocks/dirt.json | 1 - mods/bworld/blocks/grass.json | 1 - mods/bworld/blocks/hoed_dirt.json | 1 - server/game/game_server.ts | 2 +- server/game/world.ts | 5 +++++ tests/item_entity_test.ts | 13 +++++++++++++ 9 files changed, 26 insertions(+), 7 deletions(-) diff --git a/client/entity/entity.ts b/client/entity/entity.ts index b2d5a89..b0c00d9 100644 --- a/client/entity/entity.ts +++ b/client/entity/entity.ts @@ -1,4 +1,3 @@ -import { AIR } from "$/common/constants.ts"; import { move_body } from "$/common/physics.ts"; import type { ClientLevel } from "../level/client_level.ts"; @@ -73,7 +72,7 @@ export abstract class Entity { // falls and moves by its velocity for one tick, see move_body move() { - const collisions = move_body(this, this.gravity, (x, y, z) => this.level.get_block(x, y, z) !== AIR); + const collisions = move_body(this, this.gravity, (x, y, z) => this.level.has_collision(x, y, z)); this.colliding_x = collisions.x; this.colliding_y = collisions.y; this.colliding_z = collisions.z; diff --git a/client/level/client_level.ts b/client/level/client_level.ts index 2bed785..bc8d0bf 100644 --- a/client/level/client_level.ts +++ b/client/level/client_level.ts @@ -254,6 +254,12 @@ export class ClientLevel { return chunk.blocks[index] & ID_MASK; } + // whether entities bump into the block there. unloaded chunks count as solid, so nothing falls out of the world + has_collision(x: number, y: number, z: number) { + const block = this.get_block(x, y, z); + return block === VOID || (block !== AIR && (this.#blocks[block]?.has_collision ?? true)); + } + // only changes what this client shows, drops and everything else happen on the server break_block(x: number, y: number, z: number) { const block_chunk_x = Math.floor(x / CHUNK_SIZE); diff --git a/mods/bworld/blocks/chest.json b/mods/bworld/blocks/chest.json index f49da6b..b1cd08b 100644 --- a/mods/bworld/blocks/chest.json +++ b/mods/bworld/blocks/chest.json @@ -3,7 +3,6 @@ "block": { "id": "bworld:chest", "textures": "bworld:planks", - "collision": false, "mining": { "toughness": 8, "tool": "axe" diff --git a/mods/bworld/blocks/dirt.json b/mods/bworld/blocks/dirt.json index 867fe01..3945190 100644 --- a/mods/bworld/blocks/dirt.json +++ b/mods/bworld/blocks/dirt.json @@ -3,7 +3,6 @@ "block": { "id": "bworld:dirt", "textures": "bworld:dirt", - "collision": false, "mining": { "toughness": 2, "tool": "shovel" diff --git a/mods/bworld/blocks/grass.json b/mods/bworld/blocks/grass.json index 5bc531b..c9d458d 100644 --- a/mods/bworld/blocks/grass.json +++ b/mods/bworld/blocks/grass.json @@ -7,7 +7,6 @@ "bottom": "bworld:dirt", "side": "bworld:grass_side" }, - "collision": false, "mining": { "toughness": 2, "tool": "shovel" diff --git a/mods/bworld/blocks/hoed_dirt.json b/mods/bworld/blocks/hoed_dirt.json index 706aa66..b5698f4 100644 --- a/mods/bworld/blocks/hoed_dirt.json +++ b/mods/bworld/blocks/hoed_dirt.json @@ -7,7 +7,6 @@ "top": "bworld:hoed_dirt", "bottom": "bworld:dirt" }, - "collision": false, "mining": { "toughness": 5, "tool": "shovel" diff --git a/server/game/game_server.ts b/server/game/game_server.ts index 8f4d0ae..0eeec7d 100644 --- a/server/game/game_server.ts +++ b/server/game/game_server.ts @@ -829,7 +829,7 @@ export class GameServer { if (this.#entities.size === 0) { return; } - const is_solid = (x: number, y: number, z: number) => this.world.get_block_nid(x, y, z) !== AIR; + const is_solid = (x: number, y: number, z: number) => this.world.has_collision(x, y, z); const active = [...this.#entities.values()].filter((entity) => this.#near_any_player(entity.x, entity.z)); for (const entity of active) { diff --git a/server/game/world.ts b/server/game/world.ts index 59c951c..e29a9ab 100644 --- a/server/game/world.ts +++ b/server/game/world.ts @@ -113,6 +113,11 @@ export class ServerWorld { return this.#get_chunk(chunk_x, chunk_z)[index_in_chunk(x, y, z, chunk_x, chunk_z)]; } + // whether entities bump into the block there, water and other blocks with "collision": false don't + has_collision(x: number, y: number, z: number) { + return this.get_block_info(x, y, z)?.has_collision ?? false; + } + get_block_info(x: number, y: number, z: number): BlockRegistry | undefined { const nid = this.get_block_nid(x, y, z); return nid === AIR ? undefined : EverythingRegistry.get_by_id("blocks", nid); diff --git a/tests/item_entity_test.ts b/tests/item_entity_test.ts index b7e2fb5..f2bc403 100644 --- a/tests/item_entity_test.ts +++ b/tests/item_entity_test.ts @@ -114,3 +114,16 @@ Deno.test("q throws one of an item the way the player looks, ctrl throws the who send(1, { type: "drop_item", container: "crafting", index: 9, all: true }); assertEquals(game.item_entities().length, 2); }); + +Deno.test("water has no collision, items sink through it to the floor", async () => { + const { game, join } = await test_game("mods"); + join(1, "alice"); + build_floor(game); + for (let y = 100; y <= 102; y++) { + game.set_block(6, y, 0, "bworld:water"); + } + const item = game.spawn_item(6.5, 104, 0.5, new ItemStack("bworld:dirt")); + for (let i = 0; i < 40; i++) game.tick(); + assert(item.on_ground); + assertEquals(item.y, 100, "on the stone under the water"); +});