No more ecs
This commit is contained in:
@@ -0,0 +1,84 @@
|
||||
import { BlockRegistry, EverythingRegistry, ItemRegistry } from "$/common/everything_registry.ts";
|
||||
import { AIR, FACE_OFFSETS } from "$/common/constants.ts";
|
||||
import type { Client } from "./client.ts";
|
||||
import type { BlockHitResult } from "./level/client_level.ts";
|
||||
|
||||
// breaking and using blocks against a server, like minecraft's MultiPlayerGameMode. the client times breaking
|
||||
// and guesses the results so they feel instant, the server decides what really happens
|
||||
export class MultiPlayerGameMode {
|
||||
client: Client;
|
||||
|
||||
// the block being broken, and how far along it is in seconds out of destroy_time
|
||||
destroy_pos: { x: number; y: number; z: number } | undefined;
|
||||
destroy_progress = 0;
|
||||
destroy_time = 0;
|
||||
|
||||
constructor(client: Client) {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
// the click that starts breaking, for mods' on_click
|
||||
start_destroy_block(hit: BlockHitResult) {
|
||||
this.client.connection.send({ type: "hit_block", x: hit.x, y: hit.y, z: hit.z });
|
||||
}
|
||||
|
||||
// called every frame the attack button is held on a block
|
||||
continue_destroy_block(hit: BlockHitResult, delta: number) {
|
||||
const block_info = EverythingRegistry.get_by_id<BlockRegistry>("blocks", hit.block)!;
|
||||
const tool_type = this.#held_item()?.tool_type;
|
||||
|
||||
this.destroy_pos = { x: hit.x, y: hit.y, z: hit.z };
|
||||
this.destroy_time = block_info.toughness ?? 9999;
|
||||
this.destroy_progress += delta * (tool_type === block_info.tool_to_break ? 2 : 1);
|
||||
|
||||
if (this.destroy_progress >= this.destroy_time) {
|
||||
// show it right away, the server decides drops and corrects us if it disagrees
|
||||
this.client.level.break_block(hit.x, hit.y, hit.z);
|
||||
this.client.connection.send({ type: "break_block", x: hit.x, y: hit.y, z: hit.z });
|
||||
this.destroy_progress = 0;
|
||||
this.destroy_time = 0;
|
||||
}
|
||||
}
|
||||
|
||||
stop_destroy_block() {
|
||||
this.destroy_pos = undefined;
|
||||
this.destroy_progress = 0;
|
||||
this.destroy_time = 0;
|
||||
}
|
||||
|
||||
// right click on a block
|
||||
use_item_on(hit: BlockHitResult) {
|
||||
const level = this.client.level;
|
||||
this.client.connection.send({ type: "use_block", x: hit.x, y: hit.y, z: hit.z, face: hit.face });
|
||||
|
||||
// guess that it places the held block, unless the block does something when used
|
||||
const block_info = EverythingRegistry.get_by_id<BlockRegistry>("blocks", hit.block)!;
|
||||
const offset = FACE_OFFSETS[hit.face];
|
||||
const target = { x: hit.x + offset.x, y: hit.y + offset.y, z: hit.z + offset.z };
|
||||
const target_id = level.get_block(target.x, target.y, target.z);
|
||||
const replaceable = target_id === AIR ||
|
||||
EverythingRegistry.get_by_id<BlockRegistry>("blocks", target_id)?.replaceable;
|
||||
const held = this.#held_item();
|
||||
// items with components might do something else on the server, like on_use
|
||||
const place_id = held?.components ? undefined : held?.block_id;
|
||||
if (!block_info.interactive && place_id && replaceable) {
|
||||
level.add_block({ ...target, id: place_id });
|
||||
const slot = this.#held_slot();
|
||||
slot.amount = slot.amount! - 1;
|
||||
}
|
||||
}
|
||||
|
||||
// right click on nothing
|
||||
use_item() {
|
||||
this.client.connection.send({ type: "use_item" });
|
||||
}
|
||||
|
||||
#held_slot() {
|
||||
const inventories = this.client.player.inventories;
|
||||
return inventories.inventory.get_slot(inventories.hotbar_selected);
|
||||
}
|
||||
|
||||
#held_item() {
|
||||
return EverythingRegistry.get<ItemRegistry>("items", this.#held_slot().type_id ?? "");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user