import { AssetManager } from "./assets.ts"; import { ClientWorld } from "./client_world.ts"; import { InputManager } from "./input_manager.ts"; import { Connection, get_player_name, get_server_url } from "./network.ts"; import { begin_drawing, clear_background, end_drawing, init_font, init_window } from "./renderer/mod.ts"; import { is_stopped, show_fatal_error } from "./fatal.ts"; import { load_client_mods, set_mods_world } from "./mods.ts"; export class ClientLoop { running = false; last_time = 0; world: ClientWorld; frame_count = 0; last_fps_time = 0; constructor(world: ClientWorld) { this.world = world; } start() { document.addEventListener("visibilitychange", () => { if (!document.hidden) { this.last_time = performance.now(); } }); this.running = true; const now = performance.now(); this.last_time = now; this.frame_count = 0; this.last_fps_time = this.last_time; requestAnimationFrame((time) => this.loop(time)); } stop() { this.running = false; } loop(time: number) { if (!this.running || is_stopped()) { return; } const delta = (time - this.last_time) / 1000; begin_drawing(); clear_background(0.69, 0.8, 1, 1.0); this.world.update(delta); end_drawing(); this.frame_count += 1; const now = performance.now(); if (now - this.last_fps_time >= 1000) { const fps = (this.frame_count * 1000) / (now - this.last_fps_time); console.log(`FPS: ${fps.toFixed(2)}`); this.frame_count = 0; this.last_fps_time = now; } InputManager.update(); this.last_time = time; requestAnimationFrame((time) => this.loop(time)); } } const canvas = document.getElementById("game") as HTMLCanvasElement; if (!canvas) { throw Error("Canvas was not found"); } await init_window(canvas); InputManager.initialize(canvas); AssetManager.instance.load("bworld:assets_text", "/assets/ASSETS.md"); AssetManager.instance.load("bworld:textures", "/assets/sprites/textures.png"); AssetManager.instance.load("bworld:textures_info", "/assets/sprites/textures.json"); AssetManager.instance.load("bworld:player", "/assets/sprites/player.png"); AssetManager.instance.load("bworld:roguelike", "/assets/sprites/roguelike.png"); AssetManager.instance.load("bworld:ui", "/assets/sprites/ui.png"); AssetManager.instance.load("bworld:m6x11", "/assets/fonts/m6x11.png"); AssetManager.instance.load("bworld:m6x11_fnt", "/assets/fonts/m6x11.fnt"); await AssetManager.instance.load_all(); init_font(); // the game only runs against a server, it owns the world and everything in it const connection = await Connection.open(get_server_url(), get_player_name()); let mods_loaded = false; if (connection) { console.log(`Connected to ${get_server_url()}`); try { // blocks, items and textures all come from mods, so this happens before anything else await load_client_mods(connection.mods); console.log(`Mods: ${connection.mods.map((mod) => `${mod.id} ${mod.version}`).join(", ") || "none"}`); mods_loaded = true; } catch (e) { console.error(e); show_fatal_error(`Couldn't load the server's mods: ${e instanceof Error ? e.message : e}`); connection.socket.close(); } } if (connection && mods_loaded) { const client_world = new ClientWorld(connection); set_mods_world(client_world); client_world.add_chat("Connected to the server"); const loop = new ClientLoop(client_world); loop.start(); console.log("Game started"); } else if (!connection) { show_fatal_error(`Couldn't connect to the server at ${get_server_url()}`); }