Server authority
This commit is contained in:
@@ -1,44 +0,0 @@
|
||||
import { System } from "$/common/ecs/mod.ts";
|
||||
import { ClientWorld } from "../client_world.ts";
|
||||
import { Dimension } from "../components/dimension.ts";
|
||||
import { TICK_DELTA } from "$/common/constants.ts";
|
||||
import { BlockRegistry, EverythingRegistry } from "$/common/everything_registry.ts";
|
||||
|
||||
export class DimensionLogicSystem extends System {
|
||||
update(world: ClientWorld, delta: number): void {
|
||||
const dimension = world.dimension;
|
||||
|
||||
dimension.second_timer += delta;
|
||||
dimension.tick_timer += delta;
|
||||
|
||||
if (dimension.second_timer >= 1) {
|
||||
this.handle_second(world, dimension);
|
||||
}
|
||||
if (dimension.tick_timer >= TICK_DELTA) {
|
||||
this.handle_tick(world, dimension);
|
||||
}
|
||||
}
|
||||
handle_second(world: ClientWorld, dimension: Dimension) {
|
||||
for (const chunk of dimension.chunks.values()) {
|
||||
for (const tickable of chunk.blocks_data) {
|
||||
const tile_info = EverythingRegistry.get<BlockRegistry>("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) {
|
||||
for (const chunk of dimension.chunks.values()) {
|
||||
for (const tickable of chunk.blocks_data) {
|
||||
const tile_info = EverythingRegistry.get<BlockRegistry>("blocks", tickable.id);
|
||||
if (tile_info && tile_info.on_tick) {
|
||||
tile_info.on_tick(world.dimension, tickable, dimension.tick_timer);
|
||||
}
|
||||
}
|
||||
}
|
||||
dimension.tick_timer = 0;
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,10 @@ import { System } from "$/common/ecs/mod.ts";
|
||||
import { Position } from "$/common/components/position.ts";
|
||||
import { ClientWorld } from "../client_world.ts";
|
||||
import { Camera } from "../components/camera.ts";
|
||||
import { Container, ItemStack } from "$/common/inventory.ts";
|
||||
import { PlayerComponent } from "../player.ts";
|
||||
import { GuiContainer } from "../gui/gui_container.ts";
|
||||
import { show_fatal_error } from "../fatal.ts";
|
||||
|
||||
const MOVE_SEND_INTERVAL = 1 / 10;
|
||||
const REMOTE_PLAYER_SMOOTHING = 12;
|
||||
@@ -11,9 +15,9 @@ export class NetworkSystem extends System {
|
||||
|
||||
update(world: ClientWorld, delta: number): void {
|
||||
const connection = world.connection;
|
||||
if (!connection) {
|
||||
return;
|
||||
}
|
||||
const [local_player] = world.get_tag("player")!;
|
||||
const player_component = local_player.get(PlayerComponent)!;
|
||||
const inventories = player_component.inventories;
|
||||
|
||||
for (const message of connection.incoming) {
|
||||
switch (message.type) {
|
||||
@@ -41,13 +45,47 @@ export class NetworkSystem extends System {
|
||||
case "chat":
|
||||
world.add_chat(message.from ? `<${message.from}> ${message.text}` : message.text);
|
||||
break;
|
||||
case "container": {
|
||||
let container = message.container === "screen"
|
||||
? inventories.screen
|
||||
: inventories[message.container];
|
||||
if (message.container === "screen" && container?.size !== message.items.length) {
|
||||
container = inventories.screen = new Container(message.items.length);
|
||||
}
|
||||
container?.load(message.items);
|
||||
break;
|
||||
}
|
||||
case "cursor":
|
||||
inventories.cursor.item = message.item ? ItemStack.from_data(message.item) : undefined;
|
||||
break;
|
||||
case "open_screen": {
|
||||
// replace anything open locally without telling the server, it just opened this one
|
||||
player_component.screens.length = 0;
|
||||
const size = Math.max(0, ...message.layout.slots.map((slot) => slot.index + 1));
|
||||
inventories.screen = new Container(size);
|
||||
player_component.screens.push(
|
||||
new GuiContainer(inventories, (m) => connection.send(m), message.layout, message.properties),
|
||||
);
|
||||
break;
|
||||
}
|
||||
case "screen_properties": {
|
||||
const screen = player_component.screens.at(-1);
|
||||
if (screen instanceof GuiContainer) {
|
||||
screen.properties = message.properties;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "close_screen":
|
||||
// closed by the server (the block broke), it already put everything back
|
||||
player_component.screens = player_component.screens.filter((s) => !(s instanceof GuiContainer));
|
||||
inventories.screen = undefined;
|
||||
break;
|
||||
}
|
||||
}
|
||||
connection.incoming.length = 0;
|
||||
|
||||
if (connection.closed) {
|
||||
world.add_chat("Lost connection to the server");
|
||||
world.connection = undefined;
|
||||
show_fatal_error("Lost connection to the server");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ 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";
|
||||
import { AIR, FACE_OFFSETS } from "$/common/constants.ts";
|
||||
import { ClientMessage } from "$/common/protocol.ts";
|
||||
import { GuiChat } from "../gui/gui_chat.ts";
|
||||
import { GuiInventoryScreen } from "../gui/gui_screen.ts";
|
||||
|
||||
@@ -24,6 +26,7 @@ export class PlayerControlsSystem extends System {
|
||||
const player_component = player.get(PlayerComponent)!;
|
||||
const position = player.get(Position)!;
|
||||
const camera = player.get(Camera)!;
|
||||
const send = (message: ClientMessage) => world.connection.send(message);
|
||||
|
||||
if (player_component.screens.length === 0) {
|
||||
let input_x = 0;
|
||||
@@ -71,7 +74,7 @@ export class PlayerControlsSystem extends System {
|
||||
|
||||
if (InputManager.is_key_pressed(controls.open_inventory)) {
|
||||
if (player_component.screens.length === 0) {
|
||||
player_component.screens.push(new GuiPlayerInventory(player_component.player_inventory));
|
||||
player_component.screens.push(new GuiPlayerInventory(player_component.inventories, send));
|
||||
} else if (player_component.screens.at(-1) instanceof GuiInventoryScreen) {
|
||||
player_component.pop_screen();
|
||||
}
|
||||
@@ -119,10 +122,9 @@ export class PlayerControlsSystem extends System {
|
||||
}
|
||||
|
||||
const block = world.dimension.get_looked_block(world.dimension, camera);
|
||||
const holding_item = player_component.player_inventory.container.get_item(
|
||||
player_component.player_inventory.hotbar_selected,
|
||||
);
|
||||
const holding_item_info = EverythingRegistry.get<ItemRegistry>("items", holding_item?.type_id ?? "");
|
||||
const inventories = player_component.inventories;
|
||||
const hotbar_slot = inventories.inventory.get_slot(inventories.hotbar_selected);
|
||||
const holding_item_info = EverythingRegistry.get<ItemRegistry>("items", hotbar_slot.type_id ?? "");
|
||||
|
||||
if (block && player_component.screens.length === 0) {
|
||||
const block_info = EverythingRegistry.get_by_id<BlockRegistry>("blocks", block.block)!;
|
||||
@@ -135,47 +137,24 @@ export class PlayerControlsSystem extends System {
|
||||
}
|
||||
player_component.break_progress += delta * multiplier;
|
||||
if (player_component.break_progress >= player_component.break_progress_max) {
|
||||
const drop_item = !block_info.requires_tool ||
|
||||
holding_item_info?.tool_type === block_info.tool_to_break;
|
||||
world.dimension.break_block(block.x, block.y, block.z, drop_item);
|
||||
world.dimension.sync_block(block.x, block.y, block.z);
|
||||
// show it right away, the server decides drops and corrects us if it disagrees
|
||||
world.dimension.break_block(block.x, block.y, block.z);
|
||||
send({ type: "break_block", x: block.x, y: block.y, z: block.z });
|
||||
player_component.break_progress_max = 0;
|
||||
player_component.break_progress = 0;
|
||||
}
|
||||
} else if (InputManager.is_mouse_pressed(2)) {
|
||||
// interact if possible
|
||||
const interacted = block_info?.on_interact?.(world.dimension, {
|
||||
x: block.x,
|
||||
y: block.y,
|
||||
z: block.z,
|
||||
id: block_info.id,
|
||||
});
|
||||
if (!interacted) {
|
||||
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<ItemRegistry>("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,
|
||||
});
|
||||
world.dimension.sync_block(block.x + offset.x, block.y + offset.y, block.z + offset.z);
|
||||
hotbar_slot.amount! -= 1;
|
||||
}
|
||||
}
|
||||
send({ type: "use_block", x: block.x, y: block.y, z: block.z, face: block.face });
|
||||
|
||||
// guess that it places the held block, unless the block does something when used
|
||||
const offset = FACE_OFFSETS[block.face];
|
||||
const target = { x: block.x + offset.x, y: block.y + offset.y, z: block.z + offset.z };
|
||||
const target_id = world.dimension.get_block(target.x, target.y, target.z);
|
||||
const replaceable = target_id === AIR ||
|
||||
EverythingRegistry.get_by_id<BlockRegistry>("blocks", target_id)?.id === "bworld:water";
|
||||
if (!block_info.interactive && holding_item_info?.block_id && replaceable) {
|
||||
world.dimension.add_block({ ...target, id: holding_item_info.block_id });
|
||||
hotbar_slot.amount = hotbar_slot.amount! - 1;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -185,32 +164,32 @@ export class PlayerControlsSystem extends System {
|
||||
}
|
||||
|
||||
if (player_component.screens.length === 0) {
|
||||
const player_inventory = player_component.player_inventory;
|
||||
const previous = inventories.hotbar_selected;
|
||||
const scroll = InputManager.get_wheel_delta();
|
||||
if (scroll > 0) {
|
||||
player_inventory.hotbar_selected = Math.min(8, player_inventory.hotbar_selected + 1);
|
||||
inventories.hotbar_selected = Math.min(8, inventories.hotbar_selected + 1);
|
||||
} else if (scroll < 0) {
|
||||
player_inventory.hotbar_selected = Math.max(0, player_inventory.hotbar_selected - 1);
|
||||
inventories.hotbar_selected = Math.max(0, inventories.hotbar_selected - 1);
|
||||
}
|
||||
|
||||
if (InputManager.is_key_pressed(controls.hotbar_1)) {
|
||||
player_inventory.hotbar_selected = 0;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_2)) {
|
||||
player_inventory.hotbar_selected = 1;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_3)) {
|
||||
player_inventory.hotbar_selected = 2;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_4)) {
|
||||
player_inventory.hotbar_selected = 3;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_5)) {
|
||||
player_inventory.hotbar_selected = 4;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_6)) {
|
||||
player_inventory.hotbar_selected = 5;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_7)) {
|
||||
player_inventory.hotbar_selected = 6;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_8)) {
|
||||
player_inventory.hotbar_selected = 7;
|
||||
} else if (InputManager.is_key_pressed(controls.hotbar_9)) {
|
||||
player_inventory.hotbar_selected = 8;
|
||||
const hotbar_keys = [
|
||||
controls.hotbar_1,
|
||||
controls.hotbar_2,
|
||||
controls.hotbar_3,
|
||||
controls.hotbar_4,
|
||||
controls.hotbar_5,
|
||||
controls.hotbar_6,
|
||||
controls.hotbar_7,
|
||||
controls.hotbar_8,
|
||||
controls.hotbar_9,
|
||||
];
|
||||
const pressed = hotbar_keys.findIndex((key) => InputManager.is_key_pressed(key));
|
||||
if (pressed !== -1) {
|
||||
inventories.hotbar_selected = pressed;
|
||||
}
|
||||
|
||||
if (inventories.hotbar_selected !== previous) {
|
||||
send({ type: "select_slot", slot: inventories.hotbar_selected });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ export class RenderSystem extends System {
|
||||
|
||||
const player_component = entity.get(PlayerComponent);
|
||||
if (player_component) {
|
||||
render_player_hotbar(player_component.player_inventory);
|
||||
render_player_hotbar(player_component.inventories);
|
||||
render_player_crosshair();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SLOT_SIZE, TEXTURE_SIZE } from "$/common/constants.ts";
|
||||
import { AssetManager } from "$/client/assets.ts";
|
||||
import { PlayerInventory } from "../../inventory.ts";
|
||||
import { ClientInventories } from "../../inventory.ts";
|
||||
import { draw_item, draw_nine_slice } from "./render_utils.ts";
|
||||
import {
|
||||
canvas,
|
||||
@@ -14,11 +14,11 @@ import {
|
||||
Texture,
|
||||
} from "$/client/renderer/mod.ts";
|
||||
import { PlayerComponent } from "../../player.ts";
|
||||
import { get_sprite_region } from "../../../common/utils.ts";
|
||||
import { get_sprite_region } from "$/client/sprites.ts";
|
||||
|
||||
const PADDING = 10;
|
||||
|
||||
export function render_player_hotbar(player_inventory: PlayerInventory) {
|
||||
export function render_player_hotbar(inventories: ClientInventories) {
|
||||
const ui = AssetManager.instance.get<Texture>("bworld:ui");
|
||||
|
||||
const hotbar_width = PADDING * 2 + SLOT_SIZE * 9;
|
||||
@@ -46,8 +46,8 @@ export function render_player_hotbar(player_inventory: PlayerInventory) {
|
||||
for (let index = 0; index < 9; index += 1) {
|
||||
draw_nine_slice(
|
||||
ui,
|
||||
player_inventory.hotbar_selected === index ? 19 * 16 : 160 + 32,
|
||||
player_inventory.hotbar_selected === index ? 16 : 0,
|
||||
inventories.hotbar_selected === index ? 19 * 16 : 160 + 32,
|
||||
inventories.hotbar_selected === index ? 16 : 0,
|
||||
16,
|
||||
16,
|
||||
4,
|
||||
@@ -62,7 +62,7 @@ export function render_player_hotbar(player_inventory: PlayerInventory) {
|
||||
}
|
||||
|
||||
for (let index = 0; index < 9; index += 1) {
|
||||
const item = player_inventory.container.get_item(index);
|
||||
const item = inventories.inventory.get_item(index);
|
||||
if (item) {
|
||||
draw_item(item, x + PADDING + index * SLOT_SIZE, y + PADDING);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SLOT_SIZE, TEXTURE_SIZE } from "$/common/constants.ts";
|
||||
import { get_sprite_region } from "$/common/utils.ts";
|
||||
import { get_sprite_region } from "$/client/sprites.ts";
|
||||
import { BlockRegistry, EverythingRegistry, ItemRegistry } from "$/common/everything_registry.ts";
|
||||
import { AssetManager } from "$/client/assets.ts";
|
||||
import { ItemStack } from "../../inventory.ts";
|
||||
import { ItemStack } from "$/common/inventory.ts";
|
||||
import { draw_text, draw_texture_region, draw_texture_region_skewed, Texture } from "$/client/renderer/mod.ts";
|
||||
|
||||
export function draw_nine_slice(
|
||||
|
||||
Reference in New Issue
Block a user