diff --git a/client/blocks/furnace.ts b/client/blocks/furnace.ts index ef4827b..f526b02 100644 --- a/client/blocks/furnace.ts +++ b/client/blocks/furnace.ts @@ -2,6 +2,7 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry. import { Container, Inventory, ItemStack } from "../inventory.ts"; import { PlayerComponent } from "../player.ts"; import { GuiFurnace } from "$/client/gui/gui_furnace.ts"; +import { register_block_item } from "../../common/utils.ts"; function can_craft(container: Container) { const input = container.get_item(0); @@ -66,50 +67,65 @@ interface TileChestData { fuel: number; } -EverythingRegistry.register>("blocks", "bworld:furnace", { - textures: "bworld:furnace", - has_collision: false, +const block = EverythingRegistry.register("blocks", "bworld:furnace", { + id: "bworld:furnace", + textures: { front: "bworld:furnace", side: "bworld:stone" }, + has_collision: true, + drop_table: "bworld:furnace", - on_interact(world, tile) { - const [player] = world.get_tag("player")!; + on_interact(dimension, block) { + const [player] = dimension.world.get_tag("player")!; const player_component = player.get(PlayerComponent)!; - if (tile.data && tile.data.inventory) { - const gui = new GuiFurnace(tile.data.inventory, player_component.player_inventory, tile.data); + const block_data = dimension.get_block_data(block.x, block.y, block.z); + if (block_data && block_data.data.inventory) { + const gui = new GuiFurnace(block_data.data.inventory, player_component.player_inventory, block_data.data); player_component.screens.push(gui); } }, - on_create(_, tile) { - tile.data = { - inventory: new Inventory(new Container(3)), - progress: 0, - fuel: 0, - }; + on_create(dimension, block) { + dimension.add_block_data({ + id: block.id, + x: block.x, + y: block.y, + z: block.z, + data: { + inventory: new Inventory(new Container(3)), + progress: 0, + fuel: 0, + }, + }); }, - on_tick(_, tile) { - if (!tile.data) { + on_break() { + // TODO: remove block data + }, + on_tick(dimension, block) { + const block_data = dimension.get_block_data(block.x, block.y, block.z); + if (!block_data) { return; } - if (tile.data.fuel > 0) { - tile.data.fuel -= 1; + if (block_data.data.fuel > 0) { + block_data.data.fuel -= 1; } - const container = tile.data.inventory.container; + const container = block_data.data.inventory.container; if (can_craft(container)) { - if (tile.data.fuel === 0 && has_fuel(container)) { + if (block_data.data.fuel === 0 && has_fuel(container)) { consume_fuel(container); - tile.data.fuel = 200; + block_data.data.fuel = 200; } - if (tile.data.fuel > 0) { - tile.data.progress += 1; + if (block_data.data.fuel > 0) { + block_data.data.progress += 1; - if (tile.data.progress >= 100) { - tile.data.progress = 0; + if (block_data.data.progress >= 100) { + block_data.data.progress = 0; craft(container, new ItemStack("bworld:coal")); } } } }, }); + +register_block_item(block); diff --git a/client/blocks/grass.ts b/client/blocks/grass.ts index bab755e..a059c35 100644 --- a/client/blocks/grass.ts +++ b/client/blocks/grass.ts @@ -2,11 +2,11 @@ import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry. import { PlayerComponent } from "../player.ts"; EverythingRegistry.register("blocks", "bworld:grass", { + id: "bworld:grass", textures: { top: "bworld:grass_top", bottom: "bworld:dirt", "side": "bworld:grass_side" }, has_collision: false, drop_table: "bworld:dirt", - - on_interact(world, tile) { + /*on_interact(world, tile) { const [player] = world.get_tag("player")!; const player_inventory = player.get(PlayerComponent)!.player_inventory; const item = player_inventory.container.get_item(player_inventory.hotbar_selected); @@ -17,5 +17,5 @@ EverythingRegistry.register("blocks", "bworld:grass", { } else if (item?.type_id === "bworld:furnace") { // world.dimension.add_block(world, { x: tile.x, y: tile.y, id: "bworld:furnace", tickable: true }); } - }, + },*/ }); diff --git a/client/components/dimension.ts b/client/components/dimension.ts index 3c79ed8..c2a6f9f 100644 --- a/client/components/dimension.ts +++ b/client/components/dimension.ts @@ -9,13 +9,19 @@ import { PlayerComponent } from "../player.ts"; import { gl, Texture } from "../renderer/mod.ts"; import { Camera } from "./camera.ts"; -export interface Block { +export interface BlockData { + id: string; x: number; y: number; z: number; + data: T; +} + +export interface Block { id: string; - data?: T; - tickable?: boolean; + x: number; + y: number; + z: number; } export const CHUNK_SIZE = 16; @@ -26,6 +32,7 @@ export interface Chunk { x: number; z: number; blocks: Int16Array; + blocks_data: BlockData[]; generated: boolean; dirty: boolean; opaque_vertex_buffer?: WebGLBuffer; @@ -47,7 +54,14 @@ export class Dimension extends Component { } add_chunk(x: number, z: number) { - const chunk = { x, z, blocks: new Int16Array(CHUNK_AREA * CHUNK_HEIGHT), dirty: true, generated: false }; + const chunk = { + x, + z, + blocks: new Int16Array(CHUNK_AREA * CHUNK_HEIGHT), + blocks_data: [], + dirty: true, + generated: false, + }; this.chunks.push(chunk); return chunk; } @@ -98,6 +112,32 @@ export class Dimension extends Component { return chunk.blocks[index]; } + add_block_data(block_data: BlockData) { + const block_chunk_x = Math.floor(block_data.x / CHUNK_SIZE); + const block_chunk_z = Math.floor(block_data.z / CHUNK_SIZE); + let chunk = this.get_chunk(block_chunk_x, block_chunk_z); + if (!chunk) { + chunk = this.add_chunk(block_chunk_x, block_chunk_z); + } + + chunk.blocks_data.push(block_data); + } + + get_block_data(x: number, y: number, z: number) { + const chunk_x = Math.floor(x / CHUNK_SIZE); + const chunk_z = Math.floor(z / CHUNK_SIZE); + + const chunk = this.get_chunk(chunk_x, chunk_z); + + if (!chunk) { + return undefined; + } + + return chunk.blocks_data.find((block_data) => + block_data.x === x && block_data.y === y && block_data.z === z + ) as BlockData; + } + break_block(x: number, y: number, z: number) { const block_chunk_x = Math.floor(x / CHUNK_SIZE); const block_chunk_z = Math.floor(z / CHUNK_SIZE); @@ -145,9 +185,9 @@ export class Dimension extends Component { } } - // if (block_info?.on_create) { - // block_info?.on_create(this, block); - // } + if (block_info?.on_break) { + block_info.on_break(this, { x, y, z, id: block_info.id }); + } } index_to_xyz(index: number) { diff --git a/client/inventory.ts b/client/inventory.ts index 4f1bbe1..16193f7 100644 --- a/client/inventory.ts +++ b/client/inventory.ts @@ -44,7 +44,16 @@ export class ContainerSlot { return this.#item_stack?.type_id; } - get amount() { + set amount(new_amount: number) { + if (this.#item_stack) { + this.#item_stack.amount = new_amount; + if (this.#item_stack.amount <= 0) { + this.#item_stack = undefined; + } + } + } + + get amount(): number | undefined { return this.#item_stack?.amount; } diff --git a/client/systems/dimension_logic.ts b/client/systems/dimension_logic.ts index 800b83d..7053f3a 100644 --- a/client/systems/dimension_logic.ts +++ b/client/systems/dimension_logic.ts @@ -1,18 +1,12 @@ import { System } from "$/common/ecs/mod.ts"; import { ClientWorld } from "../client_world.ts"; import { Dimension } from "../components/dimension.ts"; -import { Camera, screen_to_world } from "../components/camera.ts"; -import { InputManager } from "../input_manager.ts"; -import { canvas } from "../renderer/mod.ts"; -import { TICK_DELTA, TILE_SIZE } from "$/common/constants.ts"; +import { TICK_DELTA } from "$/common/constants.ts"; import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts"; -import { Position } from "$/common/components/position.ts"; -import { distance_point_rectangle } from "../../common/utils.ts"; export class DimensionLogicSystem extends System { update(world: ClientWorld, delta: number): void { - /*const dimension_entity = world.get_entities().values().find((ent) => ent.get(Dimension)); - const dimension = dimension_entity!.get(Dimension)!; + const dimension = world.dimension; dimension.second_timer += delta; dimension.tick_timer += delta; @@ -23,74 +17,26 @@ export class DimensionLogicSystem extends System { if (dimension.tick_timer >= TICK_DELTA) { this.handle_tick(world, dimension); } - - const [player] = world.get_tag("player")!; - const player_position = player.get(Position)!; - const camera = player.get(Camera)!; - - const mouse = InputManager.get_mouse_position(); - - const world_mouse = screen_to_world( - mouse.x, - mouse.y, - camera, - canvas.width, - canvas.height, - ); - - const tile_x = Math.floor(world_mouse.x / TILE_SIZE); - const tile_y = Math.floor(world_mouse.y / TILE_SIZE); - - const tile = dimension.tiles.findLast((tile) => tile.x === tile_x && tile.y === tile_y); - - if (tile) { - const tile_info = EverythingRegistry.get("blocks", tile.id); - - if (!tile_info) { - return; - } - - const distance_to_player = distance_point_rectangle( - player_position.x + (72 / 2), - player_position.y + (72 / 2), - tile.x * TILE_SIZE, - tile.y * TILE_SIZE, - TILE_SIZE, - TILE_SIZE, - ); - if (distance_to_player > TILE_SIZE * 2) { - return; - } - - if (tile_info.on_interact || tile_info.on_click) { - if (tile_info.on_interact && InputManager.is_mouse_pressed(2)) { - InputManager.consume_mouse(2); - tile_info.on_interact(world, tile); - } - if (tile_info.on_click && InputManager.is_mouse_pressed(0)) { - InputManager.consume_mouse(0); - tile_info.on_click(world, tile); - } - } - }*/ } handle_second(world: ClientWorld, dimension: Dimension) { - const tickables = dimension.blocks.filter((t) => t.tickable); - for (const tickable of tickables) { - const tile_info = EverythingRegistry.get("blocks", tickable.id); - if (tile_info && tile_info.on_second) { - tile_info.on_second(world, tickable, dimension.second_timer); + for (const chunk of dimension.chunks) { + for (const tickable of chunk.blocks_data) { + const tile_info = EverythingRegistry.get("blocks", tickable.id); + if (tile_info && tile_info.on_second) { + tile_info.on_second(world.dimension, tickable, dimension.second_timer); + } } } dimension.second_timer = 0; } handle_tick(world: ClientWorld, dimension: Dimension) { - const tickables = dimension.blocks.filter((t) => t.tickable); - for (const tickable of tickables) { - const tile_info = EverythingRegistry.get("blocks", tickable.id); - if (tile_info && tile_info.on_tick) { - tile_info.on_tick(world, tickable, dimension.tick_timer); + for (const chunk of dimension.chunks) { + for (const tickable of chunk.blocks_data) { + const tile_info = EverythingRegistry.get("blocks", tickable.id); + if (tile_info && tile_info.on_tick) { + tile_info.on_tick(world.dimension, tickable, dimension.tick_timer); + } } } dimension.tick_timer = 0; diff --git a/client/systems/player_controls.ts b/client/systems/player_controls.ts index 1cfb856..c8837f8 100644 --- a/client/systems/player_controls.ts +++ b/client/systems/player_controls.ts @@ -8,6 +8,7 @@ import { Position } from "../../common/components/position.ts"; import { PlayerComponent } from "../player.ts"; import { GuiPlayerInventory } from "../gui/gui_player_inventory.ts"; import { CollisionCuboid } from "../components/collision.ts"; +import { BlockRegistry, EverythingRegistry, ItemRegistry } from "$/common/everything_registry.ts"; export class PlayerControlsSystem extends System { constructor() { @@ -96,28 +97,44 @@ export class PlayerControlsSystem extends System { InputManager.set_mouse_grabbed(player_component.screens.length === 0); const block = world.dimension.get_looked_block(world.dimension, camera); - if (block) { + if (block && player_component.screens.length === 0) { if (InputManager.is_mouse_pressed(0)) { world.dimension.break_block(block.x, block.y, block.z); } else if (InputManager.is_mouse_pressed(2)) { - const inventory = player_component.player_inventory; - const hotbar_slot = inventory.container.get_slot(inventory.hotbar_selected); - if (hotbar_slot.has_item()) { - const FACE_OFFSETS = { - top: { x: 0, y: 1, z: 0 }, - bottom: { x: 0, y: -1, z: 0 }, - north: { x: 0, y: 0, z: -1 }, - south: { x: 0, y: 0, z: 1 }, - west: { x: -1, y: 0, z: 0 }, - east: { x: 1, y: 0, z: 0 }, - }; - const offset = FACE_OFFSETS[block.face]; - world.dimension.add_block({ - x: block.x + offset.x, - y: block.y + offset.y, - z: block.z + offset.z, - id: "bworld:glass", + // interact if possible + const block_info = EverythingRegistry.get_by_id("blocks", block.block); + if (block_info && block_info.on_interact) { + block_info.on_interact(world.dimension, { + x: block.x, + y: block.y, + z: block.z, + id: block_info.id, }); + } else { + const inventory = player_component.player_inventory; + const hotbar_slot = inventory.container.get_slot(inventory.hotbar_selected); + if (hotbar_slot && hotbar_slot.has_item()) { + const item = hotbar_slot.get_item()!; + const item_info = EverythingRegistry.get("items", item.type_id); + if (item_info && item_info.block_id) { + const FACE_OFFSETS = { + top: { x: 0, y: 1, z: 0 }, + bottom: { x: 0, y: -1, z: 0 }, + north: { x: 0, y: 0, z: -1 }, + south: { x: 0, y: 0, z: 1 }, + west: { x: -1, y: 0, z: 0 }, + east: { x: 1, y: 0, z: 0 }, + }; + const offset = FACE_OFFSETS[block.face]; + world.dimension.add_block({ + x: block.x + offset.x, + y: block.y + offset.y, + z: block.z + offset.z, + id: item_info.block_id, + }); + hotbar_slot.amount! -= 1; + } + } } } } diff --git a/common/everything_registry.ts b/common/everything_registry.ts index 7e6caa6..15ffcd1 100644 --- a/common/everything_registry.ts +++ b/common/everything_registry.ts @@ -62,7 +62,7 @@ interface TextureFront { side: string; } -export interface BlockRegistry { +export interface BlockRegistry { id: string; textures: string | TextureSideTopBottom | TextureFront; transparent?: boolean; @@ -71,15 +71,21 @@ export interface BlockRegistry { has_collision: boolean; drop_table?: string; - on_create?(dimension: Dimension, block: Block): void; - on_click?(dimension: Dimension, block: Block): void; - on_interact?(dimension: Dimension, block: Block): void; - on_tick?(dimension: Dimension, block: Block, tick_delta: number): void; - on_second?(dimension: Dimension, block: Block, second_delta: number): void; + on_create?(dimension: Dimension, block: Block): void; + on_break?(dimension: Dimension, block: Block): void; + on_click?(dimension: Dimension, block: Block): void; + on_interact?(dimension: Dimension, block: Block): void; + on_tick?(dimension: Dimension, block: Block, tick_delta: number): void; + on_second?(dimension: Dimension, block: Block, second_delta: number): void; } export interface ItemRegistry { texture_id: string | ((item: ItemStack) => string); + block_id?: string; + + place?(dimension: Dimension, block: Block): void; + on_create?(item: ItemStack): void; + get_lore?(item: ItemStack): string; } diff --git a/common/utils.ts b/common/utils.ts index da4238b..1bddf62 100644 --- a/common/utils.ts +++ b/common/utils.ts @@ -46,11 +46,13 @@ export function distance_point_point(ax: number, ay: number, az: number, bx: num } export function register_block_item(block: BlockRegistry) { + // TODO: handle block textures let texture_id = "bworld:missing"; if (typeof block.textures === "string") { texture_id = block.textures; } EverythingRegistry.register("items", block.id, { texture_id, + block_id: block.id, }); }