From c154356e93f8090999ac4e999f87055dc46dd1d4 Mon Sep 17 00:00:00 2001 From: Paula Date: Thu, 12 Mar 2026 22:41:27 -0300 Subject: [PATCH] Cool 3d --- client/components/dimension.ts | 89 ++++++++++++++++++++----- client/game.ts | 4 +- client/generation.ts | 54 +++++++-------- client/renderer/core.ts | 7 +- client/renderer/models.ts | 96 +++++++++++++++++---------- client/systems/dimension_logic.ts | 10 +-- client/systems/rendering/dimension.ts | 48 +++++++++++--- client/tiles/chest.ts | 2 +- client/tiles/crops.ts | 8 +-- client/tiles/dirt.ts | 14 ++-- client/tiles/furnace.ts | 2 +- client/tiles/grass.ts | 6 +- client/tiles/mod.ts | 1 + client/tiles/stone.ts | 6 ++ client/tiles/tree.ts | 2 +- client/tiles/water.ts | 2 +- common/everything_registry.ts | 64 ++++++++++++++---- 17 files changed, 287 insertions(+), 128 deletions(-) create mode 100644 client/tiles/stone.ts diff --git a/client/components/dimension.ts b/client/components/dimension.ts index 14a505f..347699d 100644 --- a/client/components/dimension.ts +++ b/client/components/dimension.ts @@ -4,7 +4,7 @@ import { AssetManager } from "../assets.ts"; import { ClientWorld } from "../client_world.ts"; import { Texture } from "../renderer/mod.ts"; -export interface Tile { +export interface Block { x: number; y: number; z: number; @@ -13,35 +13,90 @@ export interface Tile { tickable?: boolean; } +export const CHUNK_SIDE_SIZE = 16; +export const CHUNK_HEIGHT = 128; +export const CHUNK_AREA = CHUNK_SIDE_SIZE * CHUNK_SIDE_SIZE; + +export interface Chunk { + x: number; + z: number; + blocks: Int32Array; +} + export class Dimension extends Component { - image: Texture; - tiles: Tile[]; + image: Texture = AssetManager.instance.get("bworld:textures"); + chunks: Chunk[] = []; second_timer = 0; tick_timer = 0; - constructor(tiles: Tile[]) { - super(); - this.image = AssetManager.instance.get("bworld:textures"); - this.tiles = tiles; + add_chunk(x: number, z: number) { + const chunk = { x, z, blocks: new Int32Array(CHUNK_AREA * CHUNK_HEIGHT) }; + this.chunks.push(chunk); + return chunk; } - add_tile(world: ClientWorld, tile: Tile) { - this.tiles.push(tile); - const tile_info = EverythingRegistry.get("tiles", tile.id); - if (tile_info?.on_create) { - tile_info?.on_create(world, tile); + add_block(world: ClientWorld, block: Block) { + const block_chunk_x = Math.floor(block.x / CHUNK_SIDE_SIZE); + const block_chunk_z = Math.floor(block.z / CHUNK_SIDE_SIZE); + let chunk = this.chunks.find((chunk) => chunk.x === block_chunk_x && chunk.z === block_chunk_z); + if (!chunk) { + chunk = this.add_chunk(block_chunk_x, block_chunk_z); + } + + const [nid, block_info] = EverythingRegistry.get_full("blocks", block.id)!; + + const lx = block.x - block_chunk_x * CHUNK_SIDE_SIZE; + const lz = block.z - block_chunk_z * CHUNK_SIDE_SIZE; + const ly = block.y; + + const index = ly * CHUNK_SIDE_SIZE * CHUNK_SIDE_SIZE + lz * CHUNK_SIDE_SIZE + lx; + + chunk.blocks[index] = nid; + if (block_info?.on_create) { + block_info?.on_create(world, block); } } - delete_tile(_world: ClientWorld, tile: Tile) { - const index = this.tiles.indexOf(tile); - if (index !== -1) { - this.tiles.splice(index, 1); + get_block(x: number, y: number, z: number) { + const chunk_x = Math.floor(x / CHUNK_SIDE_SIZE); + const chunk_z = Math.floor(z / CHUNK_SIDE_SIZE); + + const chunk = this.chunks.find( + (c) => c.x === chunk_x && c.z === chunk_z, + ); + + if (!chunk) { + return 0; } - // const tile_info = EverythingRegistry.get("tiles", tile.id); + const lx = x - chunk_x * CHUNK_SIDE_SIZE; + const lz = z - chunk_z * CHUNK_SIDE_SIZE; + const ly = y; + + const index = ly * CHUNK_SIDE_SIZE * CHUNK_SIDE_SIZE + lz * CHUNK_SIDE_SIZE + lx; + + return chunk.blocks[index]; + } + + delete_tile(_world: ClientWorld, _block: Block) { + // const index = this.blocks.indexOf(tile); + // if (index !== -1) { + // this.blocks.splice(index, 1); + // } + + // const tile_info = EverythingRegistry.get("blocks", tile.id); // if (tile_info?.on_delete) { // tile_info?.on_delete(world, tile); // } } + + index_to_xyz(index: number) { + const y = Math.floor(index / CHUNK_AREA); + const rem = index % CHUNK_AREA; + + const z = Math.floor(rem / CHUNK_SIDE_SIZE); + const x = rem % CHUNK_SIDE_SIZE; + + return [x, y, z]; + } } diff --git a/client/game.ts b/client/game.ts index 0527296..24d59b9 100644 --- a/client/game.ts +++ b/client/game.ts @@ -13,10 +13,10 @@ export function start_game(world: ClientWorld) { world.clear_entities(); const dimension = new Entity("dimension"); - world.dimension = new Dimension([]); + world.dimension = new Dimension(); dimension.add(world.dimension); world.add_entity(dimension); - generate(dimension.get(Dimension)!, 20, 20); + generate(world, dimension.get(Dimension)!, 32, 32); create_player(world); diff --git a/client/generation.ts b/client/generation.ts index c3bbc3f..ae8a8f2 100644 --- a/client/generation.ts +++ b/client/generation.ts @@ -1,47 +1,47 @@ import { Alea, create_noise_2d } from "@paulaboks/rng"; import { Dimension } from "./components/dimension.ts"; +import { ClientWorld } from "./client_world.ts"; -export function generate(dimension: Dimension, width: number, height: number, seed = "seed") { +export function generate( + world: ClientWorld, + dimension: Dimension, + width: number, + depth: number, + max_height = 64, + seed = "seed", +) { const height_noise = create_noise_2d(new Alea(seed + "_height")); - const tree_noise = create_noise_2d(new Alea(seed + "_trees")); const scale = 0.05; - for (let z = 0; z < height; z++) { + for (let z = 0; z < depth; z++) { for (let x = 0; x < width; x++) { - // multi-octave terrain const nx = x * scale; const nz = z * scale; - let h = height_noise(nx, nz) * 1 + height_noise(nx * 2, nz * 2) * 0.5 + height_noise(nx * 4, nz * 4) * 0.25; + // multi-octave terrain + let h = height_noise(nx, nz) * 1 + + height_noise(nx * 2, nz * 2) * 0.5 + + height_noise(nx * 4, nz * 4) * 0.25; - h /= 1.75; // normalize + h /= 1.75; - let id = "bworld:grass"; + // convert noise to terrain height + const terrain_height = Math.floor((h * 0.5 + 0.5) * max_height); - if (h < -0.25) { - id = "bworld:water"; - } else if (h < -0.15) { - id = "bworld:sand"; - } else { - id = "bworld:grass"; - } + for (let y = 0; y <= terrain_height; y++) { + let id = "bworld:stone"; - dimension.tiles.push({ x, z, id, y: 0 }); - - // tree placement - /*if (id === "bworld:grass") { - const t = tree_noise(x * 0.12, y * 0.12); - - if (t > 0.65) { - dimension.tiles.push({ - x, - y, - id: "bworld:tree", - }); + // simple terrain layers + if (y === terrain_height) { + id = "bworld:grass"; + } else if (y > terrain_height - 4) { + id = "bworld:dirt"; } - }*/ + + dimension.add_block(world, { x, y, z, id }); + } } } } diff --git a/client/renderer/core.ts b/client/renderer/core.ts index 13ce0ff..90404f6 100644 --- a/client/renderer/core.ts +++ b/client/renderer/core.ts @@ -4,7 +4,7 @@ import { mat4 } from "gl-matrix"; export let gl: WebGLRenderingContext; export let canvas: HTMLCanvasElement; -const MAX_SPRITES = 10000; +const MAX_SPRITES = 100000; const VERTS_PER_SPRITE = 6; const FLOATS_PER_VERT = 9; @@ -101,6 +101,9 @@ export function init_window(canvas_element: HTMLCanvasElement) { gl.enable(gl.BLEND); gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); + gl.cullFace(gl.BACK); + gl.frontFace(gl.CCW); + create_white_texture(); } @@ -165,6 +168,7 @@ export function begin_mode_3d(new_camera: Camera) { camera = new_camera; gl.enable(gl.DEPTH_TEST); + gl.enable(gl.CULL_FACE); update_camera(); } @@ -178,6 +182,7 @@ export function end_mode_3d() { mode3d = false; gl.disable(gl.DEPTH_TEST); + gl.disable(gl.CULL_FACE); } export function clear_background(r: number, g: number, b: number, a = 1) { diff --git a/client/renderer/models.ts b/client/renderer/models.ts index b453d1c..3a55aeb 100644 --- a/client/renderer/models.ts +++ b/client/renderer/models.ts @@ -17,6 +17,12 @@ export function push_cube( g = 1, b = 1, a = 1, + front = true, + back = true, + left = true, + right = true, + top = true, + bottom = true, ) { if (get_current_texture() !== texture.tex) { flush_batch(); @@ -32,45 +38,63 @@ export function push_cube( const u1 = (sx + sw) / texture.width; const v1 = (sy + sh) / texture.height; - push_vertex(x, y, z2, u0, v0, r, g, b, a); - push_vertex(x2, y, z2, u1, v0, r, g, b, a); - push_vertex(x, y2, z2, u0, v1, r, g, b, a); - push_vertex(x2, y, z2, u1, v0, r, g, b, a); - push_vertex(x2, y2, z2, u1, v1, r, g, b, a); - push_vertex(x, y2, z2, u0, v1, r, g, b, a); + // front (+z) + if (front) { + push_vertex(x, y, z2, u0, v0, r, g, b, a); + push_vertex(x2, y, z2, u1, v0, r, g, b, a); + push_vertex(x, y2, z2, u0, v1, r, g, b, a); + push_vertex(x2, y, z2, u1, v0, r, g, b, a); + push_vertex(x2, y2, z2, u1, v1, r, g, b, a); + push_vertex(x, y2, z2, u0, v1, r, g, b, a); + } - push_vertex(x2, y, z, u0, v0, r, g, b, a); - push_vertex(x, y, z, u1, v0, r, g, b, a); - push_vertex(x2, y2, z, u0, v1, r, g, b, a); - push_vertex(x, y, z, u1, v0, r, g, b, a); - push_vertex(x, y2, z, u1, v1, r, g, b, a); - push_vertex(x2, y2, z, u0, v1, r, g, b, a); + // back (-z) + if (back) { + push_vertex(x2, y, z, u0, v0, r, g, b, a); + push_vertex(x, y, z, u1, v0, r, g, b, a); + push_vertex(x2, y2, z, u0, v1, r, g, b, a); + push_vertex(x, y, z, u1, v0, r, g, b, a); + push_vertex(x, y2, z, u1, v1, r, g, b, a); + push_vertex(x2, y2, z, u0, v1, r, g, b, a); + } - push_vertex(x, y, z, u0, v0, r, g, b, a); - push_vertex(x, y, z2, u1, v0, r, g, b, a); - push_vertex(x, y2, z, u0, v1, r, g, b, a); - push_vertex(x, y, z2, u1, v0, r, g, b, a); - push_vertex(x, y2, z2, u1, v1, r, g, b, a); - push_vertex(x, y2, z, u0, v1, r, g, b, a); + // left (-x) + if (left) { + push_vertex(x, y, z, u0, v0, r, g, b, a); + push_vertex(x, y, z2, u1, v0, r, g, b, a); + push_vertex(x, y2, z, u0, v1, r, g, b, a); + push_vertex(x, y, z2, u1, v0, r, g, b, a); + push_vertex(x, y2, z2, u1, v1, r, g, b, a); + push_vertex(x, y2, z, u0, v1, r, g, b, a); + } - push_vertex(x2, y, z2, u0, v0, r, g, b, a); - push_vertex(x2, y, z, u1, v0, r, g, b, a); - push_vertex(x2, y2, z2, u0, v1, r, g, b, a); - push_vertex(x2, y, z, u1, v0, r, g, b, a); - push_vertex(x2, y2, z, u1, v1, r, g, b, a); - push_vertex(x2, y2, z2, u0, v1, r, g, b, a); + // right (+x) + if (right) { + push_vertex(x2, y, z2, u0, v0, r, g, b, a); + push_vertex(x2, y, z, u1, v0, r, g, b, a); + push_vertex(x2, y2, z2, u0, v1, r, g, b, a); + push_vertex(x2, y, z, u1, v0, r, g, b, a); + push_vertex(x2, y2, z, u1, v1, r, g, b, a); + push_vertex(x2, y2, z2, u0, v1, r, g, b, a); + } - push_vertex(x, y2, z2, u0, v0, r, g, b, a); - push_vertex(x2, y2, z2, u1, v0, r, g, b, a); - push_vertex(x, y2, z, u0, v1, r, g, b, a); - push_vertex(x2, y2, z2, u1, v0, r, g, b, a); - push_vertex(x2, y2, z, u1, v1, r, g, b, a); - push_vertex(x, y2, z, u0, v1, r, g, b, a); + // top (+y) + if (top) { + push_vertex(x, y2, z2, u0, v0, r, g, b, a); + push_vertex(x2, y2, z2, u1, v0, r, g, b, a); + push_vertex(x, y2, z, u0, v1, r, g, b, a); + push_vertex(x2, y2, z2, u1, v0, r, g, b, a); + push_vertex(x2, y2, z, u1, v1, r, g, b, a); + push_vertex(x, y2, z, u0, v1, r, g, b, a); + } - push_vertex(x, y, z, u0, v0, r, g, b, a); - push_vertex(x2, y, z, u1, v0, r, g, b, a); - push_vertex(x, y, z2, u0, v1, r, g, b, a); - push_vertex(x2, y, z, u1, v0, r, g, b, a); - push_vertex(x2, y, z2, u1, v1, r, g, b, a); - push_vertex(x, y, z2, u0, v1, r, g, b, a); + // bottom (-y) + if (bottom) { + push_vertex(x, y, z, u0, v0, r, g, b, a); + push_vertex(x2, y, z, u1, v0, r, g, b, a); + push_vertex(x, y, z2, u0, v1, r, g, b, a); + push_vertex(x2, y, z, u1, v0, r, g, b, a); + push_vertex(x2, y, z2, u1, v1, r, g, b, a); + push_vertex(x, y, z2, u0, v1, r, g, b, a); + } } diff --git a/client/systems/dimension_logic.ts b/client/systems/dimension_logic.ts index 916dc8c..97d62eb 100644 --- a/client/systems/dimension_logic.ts +++ b/client/systems/dimension_logic.ts @@ -44,7 +44,7 @@ export class DimensionLogicSystem extends System { const tile = dimension.tiles.findLast((tile) => tile.x === tile_x && tile.y === tile_y); if (tile) { - const tile_info = EverythingRegistry.get("tiles", tile.id); + const tile_info = EverythingRegistry.get("blocks", tile.id); if (!tile_info) { return; @@ -75,9 +75,9 @@ export class DimensionLogicSystem extends System { }*/ } handle_second(world: ClientWorld, dimension: Dimension) { - const tickables = dimension.tiles.filter((t) => t.tickable); + const tickables = dimension.blocks.filter((t) => t.tickable); for (const tickable of tickables) { - const tile_info = EverythingRegistry.get("tiles", tickable.id); + const tile_info = EverythingRegistry.get("blocks", tickable.id); if (tile_info && tile_info.on_second) { tile_info.on_second(world, tickable, dimension.second_timer); } @@ -86,9 +86,9 @@ export class DimensionLogicSystem extends System { } handle_tick(world: ClientWorld, dimension: Dimension) { - const tickables = dimension.tiles.filter((t) => t.tickable); + const tickables = dimension.blocks.filter((t) => t.tickable); for (const tickable of tickables) { - const tile_info = EverythingRegistry.get("tiles", tickable.id); + const tile_info = EverythingRegistry.get("blocks", tickable.id); if (tile_info && tile_info.on_tick) { tile_info.on_tick(world, tickable, dimension.tick_timer); } diff --git a/client/systems/rendering/dimension.ts b/client/systems/rendering/dimension.ts index 97530bb..91896ad 100644 --- a/client/systems/rendering/dimension.ts +++ b/client/systems/rendering/dimension.ts @@ -1,18 +1,40 @@ import { get_sprite_region } from "$/common/utils.ts"; -import { Dimension } from "$/client/components/dimension.ts"; +import { Chunk, CHUNK_SIDE_SIZE, Dimension } from "$/client/components/dimension.ts"; import { TEXTURE_SIZE } from "$/common/constants.ts"; import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; import { push_cube } from "$/client/renderer/mod.ts"; export function render_dimension(dimension: Dimension /*, camera: Camera*/) { - for (const tile of dimension.tiles) { - let texture_id = tile.id; - const tile_info = EverythingRegistry.get("tiles", tile.id); + for (const chunk of dimension.chunks) { + render_chunk(chunk, dimension); + } +} + +function render_chunk(chunk: Chunk, dimension: Dimension) { + const blocks_registry = EverythingRegistry.get_registry("blocks"); + for (let i = 0; i < chunk.blocks.length; i += 1) { + const block_nid = chunk.blocks[i]; + if (block_nid === 0) { + continue; + } + const [x, y, z] = dimension.index_to_xyz(i); + + const wx = chunk.x * CHUNK_SIDE_SIZE + x; + const wz = chunk.z * CHUNK_SIDE_SIZE + z; + const front = dimension.get_block(wx, y, wz + 1) === 0; + const back = dimension.get_block(wx, y, wz - 1) === 0; + const left = dimension.get_block(wx - 1, y, wz) === 0; + const right = dimension.get_block(wx + 1, y, wz) === 0; + const top = dimension.get_block(wx, y + 1, wz) === 0; + const bottom = dimension.get_block(wx, y - 1, wz) === 0; + + const tile_info = blocks_registry[block_nid]; + let texture_id = "bworld:missing"; if (tile_info?.texture_id) { if (typeof tile_info.texture_id === "string") { texture_id = tile_info.texture_id; } else { - texture_id = tile_info.texture_id(tile); + // texture_id = tile_info.texture_id(tile); } } @@ -20,9 +42,9 @@ export function render_dimension(dimension: Dimension /*, camera: Camera*/) { push_cube( dimension.image, - tile.x, - tile.y, - tile.z, + wx, + y, + wz, 1, 1, 1, @@ -30,6 +52,16 @@ export function render_dimension(dimension: Dimension /*, camera: Camera*/) { region.y * TEXTURE_SIZE, TEXTURE_SIZE, TEXTURE_SIZE, + 1, + 1, + 1, + 1, + front, + back, + left, + right, + top, + bottom, ); } } diff --git a/client/tiles/chest.ts b/client/tiles/chest.ts index 8234608..7a8fca1 100644 --- a/client/tiles/chest.ts +++ b/client/tiles/chest.ts @@ -7,7 +7,7 @@ interface TileChestData { inventory: Inventory; } -EverythingRegistry.register>("tiles", "bworld:chest", { +EverythingRegistry.register>("blocks", "bworld:chest", { texture_id: "bworld:chest", has_collision: false, diff --git a/client/tiles/crops.ts b/client/tiles/crops.ts index b15edf1..f3f4124 100644 --- a/client/tiles/crops.ts +++ b/client/tiles/crops.ts @@ -125,22 +125,22 @@ function create_crop_tile(crop_id: string) { } EverythingRegistry.register>( - "tiles", + "blocks", "bworld:tomato_crop", create_crop_tile("bworld:tomato"), ); EverythingRegistry.register>( - "tiles", + "blocks", "bworld:carrot_crop", create_crop_tile("bworld:carrot"), ); EverythingRegistry.register>( - "tiles", + "blocks", "bworld:potato_crop", create_crop_tile("bworld:potato"), ); EverythingRegistry.register>( - "tiles", + "blocks", "bworld:pumpkin_crop", create_crop_tile("bworld:pumpkin"), ); diff --git a/client/tiles/dirt.ts b/client/tiles/dirt.ts index 5d86035..814d5ed 100644 --- a/client/tiles/dirt.ts +++ b/client/tiles/dirt.ts @@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t import { WateringCanData } from "../items/watering_can.ts"; import { PlayerComponent } from "../player.ts"; -EverythingRegistry.register("tiles", "bworld:dirt", { +EverythingRegistry.register("blocks", "bworld:dirt", { texture_id: "bworld:dirt", has_collision: false, @@ -16,7 +16,7 @@ EverythingRegistry.register("tiles", "bworld:dirt", { }, }); -EverythingRegistry.register("tiles", "bworld:hoed_dirt", { +EverythingRegistry.register("blocks", "bworld:hoed_dirt", { texture_id: "bworld:hoed_dirt", has_collision: false, @@ -50,7 +50,7 @@ EverythingRegistry.register("tiles", "bworld:hoed_dirt", { }, }); -EverythingRegistry.register("tiles", "bworld:hoed_watered_dirt", { +EverythingRegistry.register("blocks", "bworld:hoed_watered_dirt", { texture_id: "bworld:hoed_watered_dirt", has_collision: false, @@ -75,19 +75,19 @@ EverythingRegistry.register("tiles", "bworld:hoed_watered_dirt", { } if (item.type_id === "bworld:tomato_seeds") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:tomato_crop", tickable: true }); + world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:tomato_crop", tickable: true }); item.amount -= 1; player_inventory.container.set_item(player_inventory.hotbar_selected, item); } else if (item.type_id === "bworld:potato_seeds") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:potato_crop", tickable: true }); + world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:potato_crop", tickable: true }); item.amount -= 1; player_inventory.container.set_item(player_inventory.hotbar_selected, item); } else if (item.type_id === "bworld:pumpkin_seeds") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:pumpkin_crop", tickable: true }); + world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:pumpkin_crop", tickable: true }); item.amount -= 1; player_inventory.container.set_item(player_inventory.hotbar_selected, item); } else if (item.type_id === "bworld:carrot_seeds") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:carrot_crop", tickable: true }); + world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:carrot_crop", tickable: true }); item.amount -= 1; player_inventory.container.set_item(player_inventory.hotbar_selected, item); } diff --git a/client/tiles/furnace.ts b/client/tiles/furnace.ts index 15a1020..f086578 100644 --- a/client/tiles/furnace.ts +++ b/client/tiles/furnace.ts @@ -66,7 +66,7 @@ interface TileChestData { fuel: number; } -EverythingRegistry.register>("tiles", "bworld:furnace", { +EverythingRegistry.register>("blocks", "bworld:furnace", { texture_id: "bworld:furnace", has_collision: false, diff --git a/client/tiles/grass.ts b/client/tiles/grass.ts index 2eb7cd8..e3e9bd1 100644 --- a/client/tiles/grass.ts +++ b/client/tiles/grass.ts @@ -1,7 +1,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; import { PlayerComponent } from "../player.ts"; -EverythingRegistry.register("tiles", "bworld:grass", { +EverythingRegistry.register("blocks", "bworld:grass", { texture_id: "bworld:grass", has_collision: false, @@ -12,9 +12,9 @@ EverythingRegistry.register("tiles", "bworld:grass", { if (item?.type_id === "bworld:hoe") { tile.id = "bworld:hoed_dirt"; } else if (item?.type_id === "bworld:chest") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:chest" }); + // world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:chest" }); } else if (item?.type_id === "bworld:furnace") { - world.dimension.add_tile(world, { x: tile.x, y: tile.y, id: "bworld:furnace", tickable: true }); + // world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:furnace", tickable: true }); } }, }); diff --git a/client/tiles/mod.ts b/client/tiles/mod.ts index 5eb7f89..feb1635 100644 --- a/client/tiles/mod.ts +++ b/client/tiles/mod.ts @@ -5,3 +5,4 @@ import "./crops.ts"; import "./water.ts"; import "./chest.ts"; import "./furnace.ts"; +import "./stone.ts"; diff --git a/client/tiles/stone.ts b/client/tiles/stone.ts new file mode 100644 index 0000000..09ccdaf --- /dev/null +++ b/client/tiles/stone.ts @@ -0,0 +1,6 @@ +import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts"; + +EverythingRegistry.register("blocks", "bworld:stone", { + texture_id: "bworld:stone", + has_collision: true, +}); diff --git a/client/tiles/tree.ts b/client/tiles/tree.ts index a5100dc..95eaba8 100644 --- a/client/tiles/tree.ts +++ b/client/tiles/tree.ts @@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t import { ItemStack } from "../inventory.ts"; import { PlayerComponent } from "../player.ts"; -EverythingRegistry.register("tiles", "bworld:tree", { +EverythingRegistry.register("blocks", "bworld:tree", { texture_id: "bworld:tree", has_collision: false, diff --git a/client/tiles/water.ts b/client/tiles/water.ts index 3f17971..234d30e 100644 --- a/client/tiles/water.ts +++ b/client/tiles/water.ts @@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t import { WateringCanData } from "../items/watering_can.ts"; import { PlayerComponent } from "../player.ts"; -EverythingRegistry.register("tiles", "bworld:water", { +EverythingRegistry.register("blocks", "bworld:water", { texture_id: "bworld:water", has_collision: true, diff --git a/common/everything_registry.ts b/common/everything_registry.ts index 8451bdb..38f47ed 100644 --- a/common/everything_registry.ts +++ b/common/everything_registry.ts @@ -1,28 +1,64 @@ -import { ClientWorld } from "../client/client_world.ts"; -import { Tile } from "../client/components/dimension.ts"; -import { ItemStack } from "../client/inventory.ts"; +import { ClientWorld } from "$/client/client_world.ts"; +import { Block } from "$/client/components/dimension.ts"; +import { ItemStack } from "$/client/inventory.ts"; export class EverythingRegistry { - static #registries = new Map(); + static #key_to_id = new Map>(); + static #id_to_value = new Map(); - static register(registry_name: string, key: string, value: T) { - this.#registries.set(`${registry_name}__${key}`, value); + static register(registry: string, key: string, value: T) { + if (!this.#key_to_id.has(registry)) { + this.#key_to_id.set(registry, new Map()); + this.#id_to_value.set(registry, []); + } + + const key_map = this.#key_to_id.get(registry)!; + const values = this.#id_to_value.get(registry)!; + + const id = values.length + 1; + + key_map.set(key, id); + values[id] = value; } - static get(registry_name: string, key: string): T { - return this.#registries.get(`${registry_name}__${key}`) as T; + static get(registry: string, key: string): T | undefined { + const id = this.#key_to_id.get(registry)?.get(key); + if (id === undefined) { + return undefined; + } + return this.#id_to_value.get(registry)?.[id] as T; + } + + static get_id(registry: string, key: string): number | undefined { + return this.#key_to_id.get(registry)?.get(key); + } + + static get_full(registry: string, key: string): [number, T] | undefined { + const id = this.#key_to_id.get(registry)?.get(key); + if (id === undefined) { + return undefined; + } + return [id, this.#id_to_value.get(registry)?.[id] as T]; + } + + static get_by_id(registry: string, id: number): T | undefined { + return this.#id_to_value.get(registry)?.[id] as T; + } + + static get_registry(registry: string): T[] { + return this.#id_to_value.get(registry) as T[]; } } export interface TileRegistry { - texture_id: string | ((tile: Tile) => string); + texture_id: string | ((tile: Block) => string); has_collision: boolean; - on_create?(world: ClientWorld, tile: Tile): void; - on_click?(world: ClientWorld, tile: Tile): void; - on_interact?(world: ClientWorld, tile: Tile): void; - on_tick?(world: ClientWorld, tile: Tile, tick_delta: number): void; - on_second?(world: ClientWorld, tile: Tile, second_delta: number): void; + on_create?(world: ClientWorld, tile: Block): void; + on_click?(world: ClientWorld, tile: Block): void; + on_interact?(world: ClientWorld, tile: Block): void; + on_tick?(world: ClientWorld, tile: Block, tick_delta: number): void; + on_second?(world: ClientWorld, tile: Block, second_delta: number): void; } export interface ItemRegistry {