import createDebug from "debug"; import { MessagePacket, MessageType, Packet, PacketType, PartPositionsPacket, PlanetPositionsPacket, PlayerLeavePacket, PlayerListPacket, SpawnPlayerPacket, } from "./protocol.ts"; import { appendPacket } from "./packet_ui.ts"; import { global } from "./main.ts"; import { startRender } from "./rendering.ts"; import { addMessage } from "./chat.ts"; const logger = createDebug("hub"); export interface ClientHub { socket: WebSocket; } export function sendPacket(client: ClientHub, packet: Packet) { client.socket.send(JSON.stringify(packet)); appendPacket(packet); } export async function hub_connect( url: string, username: string, ): Promise { logger("connecting to client hub at " + url); let ws = new WebSocket(url); ws.onerror = (e) => { console.error(e); throw e; }; ws.onopen = () => { logger("connected to client hub, sending username and auth details"); let client: ClientHub = { socket: ws, }; let packet: Packet = { t: PacketType.ClientLogin, c: { username, jwt: null, }, }; sendPacket(client, packet); // input document.onkeydown = (e) => { // currently, input packet is sent on any key down. fix that if (e.key == "ArrowUp" || e.key == "w") { global.up = true; } if (e.key == "ArrowDown" || e.key == "s") { global.down = true; } if (e.key == "ArrowLeft" || e.key == "a") { global.left = true; } if (e.key == "ArrowRight" || e.key == "d") { global.right = true; } let input_packet: Packet = { t: PacketType.PlayerInput, c: { up: global.up, down: global.down, left: global.left, right: global.right, }, }; sendPacket(client, input_packet); }; document.onkeyup = (e) => { if (e.key == "ArrowUp" || e.key == "w") { global.up = false; } if (e.key == "ArrowDown" || e.key == "s") { global.down = false; } if (e.key == "ArrowLeft" || e.key == "a") { global.left = false; } if (e.key == "ArrowRight" || e.key == "d") { global.right = false; } let input_packet: Packet = { t: PacketType.PlayerInput, c: { up: global.up, down: global.down, left: global.left, right: global.right, }, }; sendPacket(client, input_packet); }; document.getElementById("chatentry")!.onkeydown = (e) => { if (e.key === "Enter") { let value = (document.getElementById("chatentry")!) .value; if (value.startsWith(".msg")) { let args = value.split(" "); if (args.length < 3) { addMessage("server-error", "Command error"); (document.getElementById("chatentry")!).value = ""; return; } let target = args[1]; let message = args.slice(2).join(" "); let chat_packet: Packet = { t: PacketType.SendMessage, c: { target: target, content: message, }, }; sendPacket(client, chat_packet); addMessage("direct-message", `you -> ${target}: ${message}`); } else { let chat_packet: Packet = { t: PacketType.SendMessage, c: { target: null, content: value, }, }; sendPacket(client, chat_packet); } (document.getElementById("chatentry")!).value = ""; } }; ws.onmessage = (e) => { let packet: Packet = JSON.parse(e.data); appendPacket(packet); if (packet.t == PacketType.SpawnPlayer) { let p = packet.c; if (p.username === username) { global.me = { username: p.username, part_id: p.id, }; logger(`client spawned (username=${p.username} part_id=${p.id})`); startRender(); } else { global.players_map.set(p.id, p.username); global.inverse_players_map.set(p.username, p.id); logger(`player joined (username=${p.username} part_id=${p.id})`); } } else if (packet.t == PacketType.PlayerList) { let p = packet.c; for (let i = 0; i < p.players.length; i++) { global.players_map.set(p.players[i][0], p.players[i][1]); global.inverse_players_map.set(p.players[i][1], p.players[i][0]); } logger(`added ${p.players.length} existing players to player list`); } else if (packet.t == PacketType.PlanetPositions) { let p = packet.c; for (let i = 0; i < p.planets.length; i++) { global.planets_map.set(p.planets[i][0], p.planets[i][1]); } } else if (packet.t == PacketType.PartPositions) { let p = packet.c; for (let i = 0; i < p.parts.length; i++) { global.parts_map.set(p.parts[i][0], p.parts[i][1]); } } else if (packet.t == PacketType.PlayerLeave) { let p = packet.c; let username = global.players_map.get(p.id)!; global.inverse_players_map.delete(username); global.players_map.delete(p.id); logger(`player removed (id=${p.id})`); } else if (packet.t == PacketType.Message) { let p = packet.c; logger( `message type=${p.message_type} actor=${p.actor} content=${p.content}`, ); if (p.message_type == MessageType.Server) { addMessage("server-message", `[SERVER] ${p.content}`); } else if (p.message_type == MessageType.Chat) { addMessage("global-message", `${p.actor}: ${p.content}`); } else if (p.message_type == MessageType.Direct) { // actor is who sent the message. destination is not included in this packet if (p.actor === global.me!.username) { // skip (shown above) } else { addMessage("direct-message", `${p.actor} -> you: ${p.content}`); } } else { addMessage("server-error", `${p.content}`); } } else { logger(`unrecognized packet type ${packet.t}`); } }; return client; }; return null; }