Cool 3d
This commit is contained in:
@@ -4,7 +4,7 @@ import { AssetManager } from "../assets.ts";
|
|||||||
import { ClientWorld } from "../client_world.ts";
|
import { ClientWorld } from "../client_world.ts";
|
||||||
import { Texture } from "../renderer/mod.ts";
|
import { Texture } from "../renderer/mod.ts";
|
||||||
|
|
||||||
export interface Tile<T = unknown> {
|
export interface Block<T = unknown> {
|
||||||
x: number;
|
x: number;
|
||||||
y: number;
|
y: number;
|
||||||
z: number;
|
z: number;
|
||||||
@@ -13,35 +13,90 @@ export interface Tile<T = unknown> {
|
|||||||
tickable?: boolean;
|
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 {
|
export class Dimension extends Component {
|
||||||
image: Texture;
|
image: Texture = AssetManager.instance.get("bworld:textures");
|
||||||
tiles: Tile[];
|
chunks: Chunk[] = [];
|
||||||
second_timer = 0;
|
second_timer = 0;
|
||||||
tick_timer = 0;
|
tick_timer = 0;
|
||||||
|
|
||||||
constructor(tiles: Tile[]) {
|
add_chunk(x: number, z: number) {
|
||||||
super();
|
const chunk = { x, z, blocks: new Int32Array(CHUNK_AREA * CHUNK_HEIGHT) };
|
||||||
this.image = AssetManager.instance.get("bworld:textures");
|
this.chunks.push(chunk);
|
||||||
this.tiles = tiles;
|
return chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
add_tile(world: ClientWorld, tile: Tile) {
|
add_block(world: ClientWorld, block: Block) {
|
||||||
this.tiles.push(tile);
|
const block_chunk_x = Math.floor(block.x / CHUNK_SIDE_SIZE);
|
||||||
const tile_info = EverythingRegistry.get<TileRegistry>("tiles", tile.id);
|
const block_chunk_z = Math.floor(block.z / CHUNK_SIDE_SIZE);
|
||||||
if (tile_info?.on_create) {
|
let chunk = this.chunks.find((chunk) => chunk.x === block_chunk_x && chunk.z === block_chunk_z);
|
||||||
tile_info?.on_create(world, tile);
|
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) {
|
get_block(x: number, y: number, z: number) {
|
||||||
const index = this.tiles.indexOf(tile);
|
const chunk_x = Math.floor(x / CHUNK_SIDE_SIZE);
|
||||||
if (index !== -1) {
|
const chunk_z = Math.floor(z / CHUNK_SIDE_SIZE);
|
||||||
this.tiles.splice(index, 1);
|
|
||||||
|
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) {
|
// if (tile_info?.on_delete) {
|
||||||
// tile_info?.on_delete(world, tile);
|
// 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
@@ -13,10 +13,10 @@ export function start_game(world: ClientWorld) {
|
|||||||
world.clear_entities();
|
world.clear_entities();
|
||||||
|
|
||||||
const dimension = new Entity("dimension");
|
const dimension = new Entity("dimension");
|
||||||
world.dimension = new Dimension([]);
|
world.dimension = new Dimension();
|
||||||
dimension.add(world.dimension);
|
dimension.add(world.dimension);
|
||||||
world.add_entity(dimension);
|
world.add_entity(dimension);
|
||||||
generate(dimension.get(Dimension)!, 20, 20);
|
generate(world, dimension.get(Dimension)!, 32, 32);
|
||||||
|
|
||||||
create_player(world);
|
create_player(world);
|
||||||
|
|
||||||
|
|||||||
+26
-26
@@ -1,47 +1,47 @@
|
|||||||
import { Alea, create_noise_2d } from "@paulaboks/rng";
|
import { Alea, create_noise_2d } from "@paulaboks/rng";
|
||||||
|
|
||||||
import { Dimension } from "./components/dimension.ts";
|
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 height_noise = create_noise_2d(new Alea(seed + "_height"));
|
||||||
const tree_noise = create_noise_2d(new Alea(seed + "_trees"));
|
|
||||||
|
|
||||||
const scale = 0.05;
|
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++) {
|
for (let x = 0; x < width; x++) {
|
||||||
// multi-octave terrain
|
|
||||||
const nx = x * scale;
|
const nx = x * scale;
|
||||||
const nz = z * 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) {
|
for (let y = 0; y <= terrain_height; y++) {
|
||||||
id = "bworld:water";
|
let id = "bworld:stone";
|
||||||
} else if (h < -0.15) {
|
|
||||||
id = "bworld:sand";
|
// simple terrain layers
|
||||||
} else {
|
if (y === terrain_height) {
|
||||||
id = "bworld:grass";
|
id = "bworld:grass";
|
||||||
|
} else if (y > terrain_height - 4) {
|
||||||
|
id = "bworld:dirt";
|
||||||
}
|
}
|
||||||
|
|
||||||
dimension.tiles.push({ x, z, id, y: 0 });
|
dimension.add_block(world, { x, y, z, id });
|
||||||
|
}
|
||||||
// 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",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { mat4 } from "gl-matrix";
|
|||||||
export let gl: WebGLRenderingContext;
|
export let gl: WebGLRenderingContext;
|
||||||
export let canvas: HTMLCanvasElement;
|
export let canvas: HTMLCanvasElement;
|
||||||
|
|
||||||
const MAX_SPRITES = 10000;
|
const MAX_SPRITES = 100000;
|
||||||
const VERTS_PER_SPRITE = 6;
|
const VERTS_PER_SPRITE = 6;
|
||||||
const FLOATS_PER_VERT = 9;
|
const FLOATS_PER_VERT = 9;
|
||||||
|
|
||||||
@@ -101,6 +101,9 @@ export function init_window(canvas_element: HTMLCanvasElement) {
|
|||||||
gl.enable(gl.BLEND);
|
gl.enable(gl.BLEND);
|
||||||
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
|
gl.cullFace(gl.BACK);
|
||||||
|
gl.frontFace(gl.CCW);
|
||||||
|
|
||||||
create_white_texture();
|
create_white_texture();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -165,6 +168,7 @@ export function begin_mode_3d(new_camera: Camera) {
|
|||||||
camera = new_camera;
|
camera = new_camera;
|
||||||
|
|
||||||
gl.enable(gl.DEPTH_TEST);
|
gl.enable(gl.DEPTH_TEST);
|
||||||
|
gl.enable(gl.CULL_FACE);
|
||||||
|
|
||||||
update_camera();
|
update_camera();
|
||||||
}
|
}
|
||||||
@@ -178,6 +182,7 @@ export function end_mode_3d() {
|
|||||||
|
|
||||||
mode3d = false;
|
mode3d = false;
|
||||||
gl.disable(gl.DEPTH_TEST);
|
gl.disable(gl.DEPTH_TEST);
|
||||||
|
gl.disable(gl.CULL_FACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function clear_background(r: number, g: number, b: number, a = 1) {
|
export function clear_background(r: number, g: number, b: number, a = 1) {
|
||||||
|
|||||||
@@ -17,6 +17,12 @@ export function push_cube(
|
|||||||
g = 1,
|
g = 1,
|
||||||
b = 1,
|
b = 1,
|
||||||
a = 1,
|
a = 1,
|
||||||
|
front = true,
|
||||||
|
back = true,
|
||||||
|
left = true,
|
||||||
|
right = true,
|
||||||
|
top = true,
|
||||||
|
bottom = true,
|
||||||
) {
|
) {
|
||||||
if (get_current_texture() !== texture.tex) {
|
if (get_current_texture() !== texture.tex) {
|
||||||
flush_batch();
|
flush_batch();
|
||||||
@@ -32,41 +38,58 @@ export function push_cube(
|
|||||||
const u1 = (sx + sw) / texture.width;
|
const u1 = (sx + sw) / texture.width;
|
||||||
const v1 = (sy + sh) / texture.height;
|
const v1 = (sy + sh) / texture.height;
|
||||||
|
|
||||||
|
// front (+z)
|
||||||
|
if (front) {
|
||||||
push_vertex(x, y, z2, u0, v0, r, g, b, a);
|
push_vertex(x, y, z2, u0, v0, r, g, b, a);
|
||||||
push_vertex(x2, y, z2, u1, 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(x, y2, z2, u0, v1, r, g, b, a);
|
||||||
push_vertex(x2, y, z2, u1, v0, 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(x2, y2, z2, u1, v1, r, g, b, a);
|
||||||
push_vertex(x, y2, z2, u0, v1, r, g, b, a);
|
push_vertex(x, y2, z2, u0, v1, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// back (-z)
|
||||||
|
if (back) {
|
||||||
push_vertex(x2, y, z, u0, v0, 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(x, y, z, u1, v0, r, g, b, a);
|
||||||
push_vertex(x2, y2, z, u0, v1, 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, y, z, u1, v0, r, g, b, a);
|
||||||
push_vertex(x, y2, z, u1, v1, 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(x2, 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, z, u0, v0, r, g, b, a);
|
||||||
push_vertex(x, y, z2, u1, 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, y2, z, u0, v1, r, g, b, a);
|
||||||
push_vertex(x, y, z2, u1, v0, 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, z2, u1, v1, r, g, b, a);
|
||||||
push_vertex(x, y2, z, u0, v1, r, g, b, a);
|
push_vertex(x, y2, z, 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, z2, u0, v0, r, g, b, a);
|
||||||
push_vertex(x2, y, z, u1, 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, y2, z2, u0, v1, r, g, b, a);
|
||||||
push_vertex(x2, y, z, u1, v0, 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, z, u1, v1, r, g, b, a);
|
||||||
push_vertex(x2, y2, z2, u0, v1, r, g, b, a);
|
push_vertex(x2, y2, z2, u0, v1, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// top (+y)
|
||||||
|
if (top) {
|
||||||
push_vertex(x, y2, z2, u0, v0, 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(x2, y2, z2, u1, v0, r, g, b, a);
|
||||||
push_vertex(x, y2, z, u0, v1, 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, z2, u1, v0, r, g, b, a);
|
||||||
push_vertex(x2, y2, z, u1, v1, 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, y2, z, u0, v1, r, g, b, a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// bottom (-y)
|
||||||
|
if (bottom) {
|
||||||
push_vertex(x, y, z, u0, v0, 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(x2, y, z, u1, v0, r, g, b, a);
|
||||||
push_vertex(x, y, z2, u0, v1, r, g, b, a);
|
push_vertex(x, y, z2, u0, v1, r, g, b, a);
|
||||||
@@ -74,3 +97,4 @@ export function push_cube(
|
|||||||
push_vertex(x2, y, z2, u1, v1, 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);
|
push_vertex(x, y, z2, u0, v1, r, g, b, a);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export class DimensionLogicSystem extends System {
|
|||||||
const tile = dimension.tiles.findLast((tile) => tile.x === tile_x && tile.y === tile_y);
|
const tile = dimension.tiles.findLast((tile) => tile.x === tile_x && tile.y === tile_y);
|
||||||
|
|
||||||
if (tile) {
|
if (tile) {
|
||||||
const tile_info = EverythingRegistry.get<TileRegistry>("tiles", tile.id);
|
const tile_info = EverythingRegistry.get<TileRegistry>("blocks", tile.id);
|
||||||
|
|
||||||
if (!tile_info) {
|
if (!tile_info) {
|
||||||
return;
|
return;
|
||||||
@@ -75,9 +75,9 @@ export class DimensionLogicSystem extends System {
|
|||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
handle_second(world: ClientWorld, dimension: Dimension) {
|
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) {
|
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) {
|
if (tile_info && tile_info.on_second) {
|
||||||
tile_info.on_second(world, tickable, dimension.second_timer);
|
tile_info.on_second(world, tickable, dimension.second_timer);
|
||||||
}
|
}
|
||||||
@@ -86,9 +86,9 @@ export class DimensionLogicSystem extends System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handle_tick(world: ClientWorld, dimension: Dimension) {
|
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) {
|
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) {
|
if (tile_info && tile_info.on_tick) {
|
||||||
tile_info.on_tick(world, tickable, dimension.tick_timer);
|
tile_info.on_tick(world, tickable, dimension.tick_timer);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,40 @@
|
|||||||
import { get_sprite_region } from "$/common/utils.ts";
|
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 { TEXTURE_SIZE } from "$/common/constants.ts";
|
||||||
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
|
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
|
||||||
import { push_cube } from "$/client/renderer/mod.ts";
|
import { push_cube } from "$/client/renderer/mod.ts";
|
||||||
|
|
||||||
export function render_dimension(dimension: Dimension /*, camera: Camera*/) {
|
export function render_dimension(dimension: Dimension /*, camera: Camera*/) {
|
||||||
for (const tile of dimension.tiles) {
|
for (const chunk of dimension.chunks) {
|
||||||
let texture_id = tile.id;
|
render_chunk(chunk, dimension);
|
||||||
const tile_info = EverythingRegistry.get<TileRegistry>("tiles", tile.id);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 (tile_info?.texture_id) {
|
||||||
if (typeof tile_info.texture_id === "string") {
|
if (typeof tile_info.texture_id === "string") {
|
||||||
texture_id = tile_info.texture_id;
|
texture_id = tile_info.texture_id;
|
||||||
} else {
|
} 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(
|
push_cube(
|
||||||
dimension.image,
|
dimension.image,
|
||||||
tile.x,
|
wx,
|
||||||
tile.y,
|
y,
|
||||||
tile.z,
|
wz,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
1,
|
1,
|
||||||
@@ -30,6 +52,16 @@ export function render_dimension(dimension: Dimension /*, camera: Camera*/) {
|
|||||||
region.y * TEXTURE_SIZE,
|
region.y * TEXTURE_SIZE,
|
||||||
TEXTURE_SIZE,
|
TEXTURE_SIZE,
|
||||||
TEXTURE_SIZE,
|
TEXTURE_SIZE,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
1,
|
||||||
|
front,
|
||||||
|
back,
|
||||||
|
left,
|
||||||
|
right,
|
||||||
|
top,
|
||||||
|
bottom,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ interface TileChestData {
|
|||||||
inventory: Inventory;
|
inventory: Inventory;
|
||||||
}
|
}
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry<TileChestData>>("tiles", "bworld:chest", {
|
EverythingRegistry.register<TileRegistry<TileChestData>>("blocks", "bworld:chest", {
|
||||||
texture_id: "bworld:chest",
|
texture_id: "bworld:chest",
|
||||||
has_collision: false,
|
has_collision: false,
|
||||||
|
|
||||||
|
|||||||
@@ -125,22 +125,22 @@ function create_crop_tile(crop_id: string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
||||||
"tiles",
|
"blocks",
|
||||||
"bworld:tomato_crop",
|
"bworld:tomato_crop",
|
||||||
create_crop_tile("bworld:tomato"),
|
create_crop_tile("bworld:tomato"),
|
||||||
);
|
);
|
||||||
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
||||||
"tiles",
|
"blocks",
|
||||||
"bworld:carrot_crop",
|
"bworld:carrot_crop",
|
||||||
create_crop_tile("bworld:carrot"),
|
create_crop_tile("bworld:carrot"),
|
||||||
);
|
);
|
||||||
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
||||||
"tiles",
|
"blocks",
|
||||||
"bworld:potato_crop",
|
"bworld:potato_crop",
|
||||||
create_crop_tile("bworld:potato"),
|
create_crop_tile("bworld:potato"),
|
||||||
);
|
);
|
||||||
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
EverythingRegistry.register<TileRegistry<TileCropData>>(
|
||||||
"tiles",
|
"blocks",
|
||||||
"bworld:pumpkin_crop",
|
"bworld:pumpkin_crop",
|
||||||
create_crop_tile("bworld:pumpkin"),
|
create_crop_tile("bworld:pumpkin"),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t
|
|||||||
import { WateringCanData } from "../items/watering_can.ts";
|
import { WateringCanData } from "../items/watering_can.ts";
|
||||||
import { PlayerComponent } from "../player.ts";
|
import { PlayerComponent } from "../player.ts";
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry>("tiles", "bworld:dirt", {
|
EverythingRegistry.register<TileRegistry>("blocks", "bworld:dirt", {
|
||||||
texture_id: "bworld:dirt",
|
texture_id: "bworld:dirt",
|
||||||
has_collision: false,
|
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",
|
texture_id: "bworld:hoed_dirt",
|
||||||
has_collision: false,
|
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",
|
texture_id: "bworld:hoed_watered_dirt",
|
||||||
has_collision: false,
|
has_collision: false,
|
||||||
|
|
||||||
@@ -75,19 +75,19 @@ EverythingRegistry.register<TileRegistry>("tiles", "bworld:hoed_watered_dirt", {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (item.type_id === "bworld:tomato_seeds") {
|
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;
|
item.amount -= 1;
|
||||||
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
||||||
} else if (item.type_id === "bworld:potato_seeds") {
|
} 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;
|
item.amount -= 1;
|
||||||
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
||||||
} else if (item.type_id === "bworld:pumpkin_seeds") {
|
} 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;
|
item.amount -= 1;
|
||||||
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
||||||
} else if (item.type_id === "bworld:carrot_seeds") {
|
} 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;
|
item.amount -= 1;
|
||||||
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
player_inventory.container.set_item(player_inventory.hotbar_selected, item);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ interface TileChestData {
|
|||||||
fuel: number;
|
fuel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry<TileChestData>>("tiles", "bworld:furnace", {
|
EverythingRegistry.register<TileRegistry<TileChestData>>("blocks", "bworld:furnace", {
|
||||||
texture_id: "bworld:furnace",
|
texture_id: "bworld:furnace",
|
||||||
has_collision: false,
|
has_collision: false,
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
|
import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.ts";
|
||||||
import { PlayerComponent } from "../player.ts";
|
import { PlayerComponent } from "../player.ts";
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry>("tiles", "bworld:grass", {
|
EverythingRegistry.register<TileRegistry>("blocks", "bworld:grass", {
|
||||||
texture_id: "bworld:grass",
|
texture_id: "bworld:grass",
|
||||||
has_collision: false,
|
has_collision: false,
|
||||||
|
|
||||||
@@ -12,9 +12,9 @@ EverythingRegistry.register<TileRegistry>("tiles", "bworld:grass", {
|
|||||||
if (item?.type_id === "bworld:hoe") {
|
if (item?.type_id === "bworld:hoe") {
|
||||||
tile.id = "bworld:hoed_dirt";
|
tile.id = "bworld:hoed_dirt";
|
||||||
} else if (item?.type_id === "bworld:chest") {
|
} 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") {
|
} 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 });
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,3 +5,4 @@ import "./crops.ts";
|
|||||||
import "./water.ts";
|
import "./water.ts";
|
||||||
import "./chest.ts";
|
import "./chest.ts";
|
||||||
import "./furnace.ts";
|
import "./furnace.ts";
|
||||||
|
import "./stone.ts";
|
||||||
|
|||||||
@@ -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,
|
||||||
|
});
|
||||||
@@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t
|
|||||||
import { ItemStack } from "../inventory.ts";
|
import { ItemStack } from "../inventory.ts";
|
||||||
import { PlayerComponent } from "../player.ts";
|
import { PlayerComponent } from "../player.ts";
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry>("tiles", "bworld:tree", {
|
EverythingRegistry.register<TileRegistry>("blocks", "bworld:tree", {
|
||||||
texture_id: "bworld:tree",
|
texture_id: "bworld:tree",
|
||||||
has_collision: false,
|
has_collision: false,
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { EverythingRegistry, TileRegistry } from "$/common/everything_registry.t
|
|||||||
import { WateringCanData } from "../items/watering_can.ts";
|
import { WateringCanData } from "../items/watering_can.ts";
|
||||||
import { PlayerComponent } from "../player.ts";
|
import { PlayerComponent } from "../player.ts";
|
||||||
|
|
||||||
EverythingRegistry.register<TileRegistry>("tiles", "bworld:water", {
|
EverythingRegistry.register<TileRegistry>("blocks", "bworld:water", {
|
||||||
texture_id: "bworld:water",
|
texture_id: "bworld:water",
|
||||||
has_collision: true,
|
has_collision: true,
|
||||||
|
|
||||||
|
|||||||
@@ -1,28 +1,64 @@
|
|||||||
import { ClientWorld } from "../client/client_world.ts";
|
import { ClientWorld } from "$/client/client_world.ts";
|
||||||
import { Tile } from "../client/components/dimension.ts";
|
import { Block } from "$/client/components/dimension.ts";
|
||||||
import { ItemStack } from "../client/inventory.ts";
|
import { ItemStack } from "$/client/inventory.ts";
|
||||||
|
|
||||||
export class EverythingRegistry {
|
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) {
|
static register<T>(registry: string, key: string, value: T) {
|
||||||
this.#registries.set(`${registry_name}__${key}`, value);
|
if (!this.#key_to_id.has(registry)) {
|
||||||
|
this.#key_to_id.set(registry, new Map());
|
||||||
|
this.#id_to_value.set(registry, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
static get<T>(registry_name: string, key: string): T {
|
const key_map = this.#key_to_id.get(registry)!;
|
||||||
return this.#registries.get(`${registry_name}__${key}`) as T;
|
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: 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> {
|
export interface TileRegistry<T = unknown | undefined> {
|
||||||
texture_id: string | ((tile: Tile<T>) => string);
|
texture_id: string | ((tile: Block<T>) => string);
|
||||||
has_collision: boolean;
|
has_collision: boolean;
|
||||||
|
|
||||||
on_create?(world: ClientWorld, tile: Tile<T>): void;
|
on_create?(world: ClientWorld, tile: Block<T>): void;
|
||||||
on_click?(world: ClientWorld, tile: Tile<T>): void;
|
on_click?(world: ClientWorld, tile: Block<T>): void;
|
||||||
on_interact?(world: ClientWorld, tile: Tile<T>): void;
|
on_interact?(world: ClientWorld, tile: Block<T>): void;
|
||||||
on_tick?(world: ClientWorld, tile: Tile<T>, tick_delta: number): void;
|
on_tick?(world: ClientWorld, tile: Block<T>, tick_delta: number): void;
|
||||||
on_second?(world: ClientWorld, tile: Tile<T>, second_delta: number): void;
|
on_second?(world: ClientWorld, tile: Block<T>, second_delta: number): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemRegistry<T = unknown | undefined> {
|
export interface ItemRegistry<T = unknown | undefined> {
|
||||||
|
|||||||
Reference in New Issue
Block a user