Improve networking

This commit is contained in:
2026-09-25 00:08:01 -03:00
parent 6458bc0440
commit 2a2ccae9ce
18 changed files with 600 additions and 162 deletions
+19 -65
View File
@@ -1,7 +1,6 @@
import { BlockChange, ClientMessage, PlayerInfo, ServerMessage } from "$/common/protocol.ts";
import type { ModListing } from "$/common/mod_loader.ts";
const CONNECT_TIMEOUT_MS = 3000;
import type { Join, ServerSocket, Welcome } from "./handshake.ts";
export interface RemotePlayer extends PlayerInfo {
// where we draw them, eased towards x/y/z so movement isnt choppy
@@ -12,7 +11,7 @@ export interface RemotePlayer extends PlayerInfo {
}
export class Connection {
socket: WebSocket;
#server: ServerSocket;
id: string;
name: string;
seed: string;
@@ -22,35 +21,31 @@ export class Connection {
selected_slot: number;
players = new Map<string, RemotePlayer>();
// handled by the network system inside the game loop, not whenever the socket feels like it
incoming: ServerMessage[] = [];
closed = false;
constructor(socket: WebSocket, welcome: Extract<ServerMessage, { type: "welcome" }>) {
this.socket = socket;
this.id = welcome.id;
this.name = welcome.name;
constructor(server: ServerSocket, welcome: Welcome, join: Join) {
this.#server = server;
this.id = join.id;
this.name = join.name;
this.seed = welcome.seed;
this.mods = welcome.mods;
this.initial_changes = welcome.changes;
this.spawn = welcome.spawn;
this.selected_slot = welcome.selected_slot;
for (const player of welcome.players) {
this.initial_changes = join.changes;
this.spawn = join.spawn;
this.selected_slot = join.selected_slot;
for (const player of join.players) {
this.add_player(player);
}
}
socket.addEventListener("message", (event) => {
this.incoming.push(JSON.parse(event.data));
});
socket.addEventListener("close", () => {
this.closed = true;
});
// handled by the network system inside the game loop, not whenever the socket feels like it
get incoming(): ServerMessage[] {
return this.#server.messages;
}
get closed() {
return this.#server.closed;
}
send(message: ClientMessage) {
if (this.socket.readyState === WebSocket.OPEN) {
this.socket.send(JSON.stringify(message));
}
this.#server.send(message);
}
add_player(player: PlayerInfo) {
@@ -62,40 +57,6 @@ export class Connection {
color: color_from_name(player.name),
});
}
static open(url: string, name: string): Promise<Connection | undefined> {
return new Promise((resolve) => {
let socket: WebSocket;
try {
socket = new WebSocket(url);
} catch {
resolve(undefined);
return;
}
const timeout = setTimeout(() => {
socket.close();
resolve(undefined);
}, CONNECT_TIMEOUT_MS);
socket.addEventListener("open", () => {
socket.send(JSON.stringify({ type: "hello", name } satisfies ClientMessage));
});
socket.addEventListener("message", (event) => {
const message: ServerMessage = JSON.parse(event.data);
if (message.type === "welcome") {
clearTimeout(timeout);
resolve(new Connection(socket, message));
}
}, { once: true });
socket.addEventListener("error", () => {
clearTimeout(timeout);
resolve(undefined);
});
});
}
}
function color_from_name(name: string): [number, number, number] {
@@ -122,13 +83,6 @@ function color_from_name(name: string): [number, number, number] {
return [r + m, g + m, b + m];
}
export function get_server_url(): string {
const params = new URLSearchParams(location.search);
const server = params.get("server");
const protocol = location.protocol === "https:" ? "wss:" : "ws:";
return `${protocol}//${server ?? location.host}/ws`;
}
export function get_player_name(): string {
return new URLSearchParams(location.search).get("name") ?? "";
}