Server actually ticks
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { Alea, create_noise_2d, create_noise_3d, NoiseFunction2D, NoiseFunction3D } from "@paulaboks/rng";
|
||||
import { AIR, CHUNK_AREA, CHUNK_HEIGHT, CHUNK_SIZE } from "$/common/constants.ts";
|
||||
import { AIR, CHUNK_AREA, CHUNK_HEIGHT, CHUNK_SIZE, ID_MASK } from "$/common/constants.ts";
|
||||
import type { FeatureChunk } from "$/common/mod_api/worldgen.ts";
|
||||
import type { OreJson } from "$/common/mod_data.ts";
|
||||
|
||||
@@ -323,6 +323,8 @@ export function generate_raw_chunk(
|
||||
seed: string,
|
||||
block_ids: Record<string, number>,
|
||||
worldgen?: WorldgenSetup,
|
||||
// the value to store for each numeric id, with its default states. just the id when missing
|
||||
default_values?: number[],
|
||||
): RawChunk {
|
||||
const blocks = new Uint32Array(CHUNK_SIZE * CHUNK_SIZE * CHUNK_HEIGHT);
|
||||
const spills: number[] = [];
|
||||
@@ -333,6 +335,7 @@ export function generate_raw_chunk(
|
||||
if (y < 0 || y >= CHUNK_HEIGHT) {
|
||||
return;
|
||||
}
|
||||
nid = default_values?.[nid] ?? nid;
|
||||
const block_chunk_x = Math.floor(x / CHUNK_SIZE);
|
||||
const block_chunk_z = Math.floor(z / CHUNK_SIZE);
|
||||
if (block_chunk_x !== chunk_x || block_chunk_z !== chunk_z) {
|
||||
@@ -364,7 +367,7 @@ export function generate_raw_chunk(
|
||||
);
|
||||
|
||||
if (worldgen) {
|
||||
generate_ores(blocks, chunk_x, chunk_z, seed, block_ids, worldgen.ores);
|
||||
generate_ores(blocks, chunk_x, chunk_z, seed, block_ids, worldgen.ores, default_values);
|
||||
generate_features(blocks, heights, biomes, set, chunk_x, chunk_z, seed, block_ids, worldgen.features);
|
||||
}
|
||||
|
||||
@@ -379,6 +382,7 @@ function generate_ores(
|
||||
seed: string,
|
||||
block_ids: Record<string, number>,
|
||||
ores: OreJson[],
|
||||
default_values: number[] | undefined,
|
||||
) {
|
||||
const usable = ores
|
||||
.map((ore) => ({ ...ore, nid: block_ids[ore.id], replaces_nid: block_ids[ore.replaces] }))
|
||||
@@ -392,7 +396,7 @@ function generate_ores(
|
||||
for (let lz = 0; lz < CHUNK_SIZE; lz++) {
|
||||
for (let lx = 0; lx < CHUNK_SIZE; lx++) {
|
||||
const index = y * CHUNK_AREA + lz * CHUNK_SIZE + lx;
|
||||
const current = blocks[index];
|
||||
const current = blocks[index] & ID_MASK;
|
||||
if (current === AIR) {
|
||||
continue;
|
||||
}
|
||||
@@ -404,7 +408,7 @@ function generate_ores(
|
||||
const wx = chunk_x * CHUNK_SIZE + lx;
|
||||
const wz = chunk_z * CHUNK_SIZE + lz;
|
||||
if (noises[i](wx * ore.scale, y * ore.scale, wz * ore.scale) > ore.threshold) {
|
||||
blocks[index] = ore.nid;
|
||||
blocks[index] = default_values?.[ore.nid] ?? ore.nid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -452,7 +456,7 @@ function generate_features(
|
||||
if (y < 0 || y >= CHUNK_HEIGHT) {
|
||||
return undefined;
|
||||
}
|
||||
const nid = blocks[y * CHUNK_AREA + local(x, z, "get_block")];
|
||||
const nid = blocks[y * CHUNK_AREA + local(x, z, "get_block")] & ID_MASK;
|
||||
return nid === AIR ? "bworld:air" : ids_by_nid[nid];
|
||||
},
|
||||
set_block(x, y, z, id) {
|
||||
|
||||
+7
-3
@@ -19,8 +19,8 @@ export interface PlayerInfo {
|
||||
pitch: number;
|
||||
}
|
||||
|
||||
// x, y, z, block id
|
||||
export type BlockChange = [number, number, number, string];
|
||||
// x, y, z, block id, and its state bits when they aren't 0
|
||||
export type BlockChange = [number, number, number, string, number?];
|
||||
|
||||
// the containers a client can see and click. "screen" is whatever the open server screen shows
|
||||
export type ContainerKey = "inventory" | "crafting" | "screen";
|
||||
@@ -53,6 +53,10 @@ export type ClientMessage =
|
||||
| { type: "ready" }
|
||||
| { type: "move"; x: number; y: number; z: number; yaw: number; pitch: number }
|
||||
| { type: "break_block"; x: number; y: number; z: number }
|
||||
// the player started hitting a block, for on_click
|
||||
| { type: "hit_block"; x: number; y: number; z: number }
|
||||
// right click without looking at a block, for items' on_use
|
||||
| { type: "use_item" }
|
||||
// right click on a block: interact with it, or place the held block against `face`
|
||||
| { type: "use_block"; x: number; y: number; z: number; face: Faces }
|
||||
| { type: "select_slot"; slot: number }
|
||||
@@ -88,7 +92,7 @@ export type ServerMessage =
|
||||
| { type: "player_leave"; id: string }
|
||||
| { type: "player_move"; id: string; x: number; y: number; z: number; yaw: number; pitch: number }
|
||||
// also sent to the player who caused it, which corrects anything their client predicted wrong
|
||||
| { type: "set_block"; x: number; y: number; z: number; id: string }
|
||||
| { type: "set_block"; x: number; y: number; z: number; id: string; state?: number }
|
||||
| { type: "chat"; from?: string; text: string }
|
||||
| { type: "teleport"; x: number; y: number; z: number }
|
||||
| { type: "container"; container: ContainerKey; items: (ItemData | null)[] }
|
||||
|
||||
+15
-1
@@ -79,7 +79,21 @@ export function set_state_value(value: number, block_info: BlockRegistry, name:
|
||||
|
||||
state_bits = (state_bits & ~s.mask) | (new_value << s.shift);
|
||||
|
||||
return (state_bits << 16) | id;
|
||||
// >>> 0 keeps it unsigned when the top state bit is set
|
||||
return ((state_bits << 16) | id) >>> 0;
|
||||
}
|
||||
|
||||
// a block's numeric id with its states at their defaults, what placing it should store
|
||||
export function default_block_value(nid: number, block_info: BlockRegistry | undefined): number {
|
||||
let value = nid;
|
||||
for (const state of block_info?.states ?? []) {
|
||||
value = set_state_value(value, block_info!, state.name, state.default) ?? value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function block_value(nid: number, state: number): number {
|
||||
return ((state << STATE_SHIFT) | nid) >>> 0;
|
||||
}
|
||||
|
||||
function compile_block_states(block_info: BlockRegistry) {
|
||||
|
||||
Reference in New Issue
Block a user