This commit is contained in:
2026-03-12 22:41:27 -03:00
parent d18942196b
commit c154356e93
17 changed files with 287 additions and 128 deletions
+72 -17
View File
@@ -4,7 +4,7 @@ import { AssetManager } from "../assets.ts";
import { ClientWorld } from "../client_world.ts";
import { Texture } from "../renderer/mod.ts";
export interface Tile<T = unknown> {
export interface Block<T = unknown> {
x: number;
y: number;
z: number;
@@ -13,35 +13,90 @@ export interface Tile<T = unknown> {
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<TileRegistry>("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<TileRegistry>("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<TileRegistry>("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<TileRegistry>("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];
}
}
+2 -2
View File
@@ -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);
+27 -27
View File
@@ -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 });
}
}
}
}
+6 -1
View File
@@ -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) {
+60 -36
View File
@@ -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);
}
}
+5 -5
View File
@@ -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<TileRegistry>("tiles", tile.id);
const tile_info = EverythingRegistry.get<TileRegistry>("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<TileRegistry>("tiles", tickable.id);
const tile_info = EverythingRegistry.get<TileRegistry>("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<TileRegistry>("tiles", tickable.id);
const tile_info = EverythingRegistry.get<TileRegistry>("blocks", tickable.id);
if (tile_info && tile_info.on_tick) {
tile_info.on_tick(world, tickable, dimension.tick_timer);
}
+40 -8
View File
@@ -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<TileRegistry>("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<TileRegistry>("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,
);
}
}
+1 -1
View File
@@ -7,7 +7,7 @@ interface TileChestData {
inventory: Inventory;
}
EverythingRegistry.register<TileRegistry<TileChestData>>("tiles", "bworld:chest", {
EverythingRegistry.register<TileRegistry<TileChestData>>("blocks", "bworld:chest", {
texture_id: "bworld:chest",
has_collision: false,
+4 -4
View File
@@ -125,22 +125,22 @@ function create_crop_tile(crop_id: string) {
}
EverythingRegistry.register<TileRegistry<TileCropData>>(
"tiles",
"blocks",
"bworld:tomato_crop",
create_crop_tile("bworld:tomato"),
);
EverythingRegistry.register<TileRegistry<TileCropData>>(
"tiles",
"blocks",
"bworld:carrot_crop",
create_crop_tile("bworld:carrot"),
);
EverythingRegistry.register<TileRegistry<TileCropData>>(
"tiles",
"blocks",
"bworld:potato_crop",
create_crop_tile("bworld:potato"),
);
EverythingRegistry.register<TileRegistry<TileCropData>>(
"tiles",
"blocks",
"bworld:pumpkin_crop",
create_crop_tile("bworld:pumpkin"),
);
+7 -7
View File
@@ -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<TileRegistry>("tiles", "bworld:dirt", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:dirt", {
texture_id: "bworld:dirt",
has_collision: false,
@@ -16,7 +16,7 @@ EverythingRegistry.register<TileRegistry>("tiles", "bworld:dirt", {
},
});
EverythingRegistry.register<TileRegistry>("tiles", "bworld:hoed_dirt", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:hoed_dirt", {
texture_id: "bworld:hoed_dirt",
has_collision: false,
@@ -50,7 +50,7 @@ EverythingRegistry.register<TileRegistry>("tiles", "bworld:hoed_dirt", {
},
});
EverythingRegistry.register<TileRegistry>("tiles", "bworld:hoed_watered_dirt", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:hoed_watered_dirt", {
texture_id: "bworld:hoed_watered_dirt",
has_collision: false,
@@ -75,19 +75,19 @@ EverythingRegistry.register<TileRegistry>("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);
}
+1 -1
View File
@@ -66,7 +66,7 @@ interface TileChestData {
fuel: number;
}
EverythingRegistry.register<TileRegistry<TileChestData>>("tiles", "bworld:furnace", {
EverythingRegistry.register<TileRegistry<TileChestData>>("blocks", "bworld:furnace", {
texture_id: "bworld:furnace",
has_collision: false,
+3 -3
View File
@@ -1,7 +1,7 @@
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
import { PlayerComponent } from "../player.ts";
EverythingRegistry.register<TileRegistry>("tiles", "bworld:grass", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:grass", {
texture_id: "bworld:grass",
has_collision: false,
@@ -12,9 +12,9 @@ EverythingRegistry.register<TileRegistry>("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 });
}
},
});
+1
View File
@@ -5,3 +5,4 @@ import "./crops.ts";
import "./water.ts";
import "./chest.ts";
import "./furnace.ts";
import "./stone.ts";
+6
View File
@@ -0,0 +1,6 @@
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
EverythingRegistry.register<TileRegistry>("blocks", "bworld:stone", {
texture_id: "bworld:stone",
has_collision: true,
});
+1 -1
View File
@@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t
import { ItemStack } from "../inventory.ts";
import { PlayerComponent } from "../player.ts";
EverythingRegistry.register<TileRegistry>("tiles", "bworld:tree", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:tree", {
texture_id: "bworld:tree",
has_collision: false,
+1 -1
View File
@@ -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<TileRegistry>("tiles", "bworld:water", {
EverythingRegistry.register<TileRegistry>("blocks", "bworld:water", {
texture_id: "bworld:water",
has_collision: true,
+50 -14
View File
@@ -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<string, unknown>();
static #key_to_id = new Map<string, Map<string, number>>();
static #id_to_value = new Map<string, unknown[]>();
static register<T>(registry_name: string, key: string, value: T) {
this.#registries.set(`${registry_name}__${key}`, value);
static register<T>(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<T>(registry_name: string, key: string): T {
return this.#registries.get(`${registry_name}__${key}`) as T;
static get<T>(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<T>(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<T>(registry: string, id: number): T | undefined {
return this.#id_to_value.get(registry)?.[id] as T;
}
static get_registry<T>(registry: string): T[] {
return this.#id_to_value.get(registry) as T[];
}
}
export interface TileRegistry<T = unknown | undefined> {
texture_id: string | ((tile: Tile<T>) => string);
texture_id: string | ((tile: Block<T>) => string);
has_collision: boolean;
on_create?(world: ClientWorld, tile: Tile<T>): void;
on_click?(world: ClientWorld, tile: Tile<T>): void;
on_interact?(world: ClientWorld, tile: Tile<T>): void;
on_tick?(world: ClientWorld, tile: Tile<T>, tick_delta: number): void;
on_second?(world: ClientWorld, tile: Tile<T>, second_delta: number): void;
on_create?(world: ClientWorld, tile: Block<T>): void;
on_click?(world: ClientWorld, tile: Block<T>): void;
on_interact?(world: ClientWorld, tile: Block<T>): void;
on_tick?(world: ClientWorld, tile: Block<T>, tick_delta: number): void;
on_second?(world: ClientWorld, tile: Block<T>, second_delta: number): void;
}
export interface ItemRegistry<T = unknown | undefined> {