import {Logger} from "./logger"; import {decode, encode} from "./serde"; import {global} from "./index"; const logger = new Logger("Gateway"); export interface GatewayClient { //state: State; socket: WebSocket; username: string | null; version: number | null; // @ts-ignore ping_timeout: Timeout | null; // i am aware that these types dont exist // @ts-ignore ping_timeout_left: Timeout; // its fine } /*export interface AttachedModule { module_type: ModuleType, rotation: number, x: number, y: number, children: Attachment[], }*/ export async function gateway_connect(gateway_url: string, username: string): Promise { logger.info("FAST CONNECT - Connecting to gateway socket at " + gateway_url); let ws = await _websocket_connect(gateway_url); logger.debug("[fastconnect] connected to gateway, performing handshake with server"); let client: GatewayClient = { //state: State.Handshake, socket: ws, username: null, version: null, ping_timeout: null, ping_timeout_left: null }; client.socket.addEventListener('message', async (msg) => { let pkt_info = decode(new Uint8Array(await msg.data.arrayBuffer())); let pkt_id = pkt_info[0]; let pkt_data = pkt_info[1]; if (pkt_id == 0) { // not a real message, skip return; } if (client.state == State.Handshake) { if (pkt_id == MessageS2CHello_packetInfo.type) { let pkt = MessageS2CHello.decode(pkt_data); logger.info(`FAST CONNECT - Handshake finished with server with protocol v${pkt.version}, assigned username ${pkt.givenUsername}, switching to state ${pkt.nextState}`); client.state = pkt.nextState; client.username = pkt.givenUsername; client.version = pkt.version; } else if (pkt_id == MessageS2CGoodbye_packetInfo.type) { let pkt = MessageS2CGoodbye.decode(pkt_data); logger.error(`Disconnected by server. Reason: ${pkt.reason}`); client.state = State.Handshake; client.username = null; client.version = null; throw "Disconnected by server"; } else { logger.warn(`server sent unexpected packet ${pkt_id} for state Handshake`); } } else if (client.state == State.Play) { if (pkt_id == MessageS2CGoodbye_packetInfo.type) { let pkt = MessageS2CGoodbye.decode(pkt_data); logger.error(`Disconnected by server. Reason: ${pkt.reason}`); client.state = State.Handshake; client.username = null; client.version = null; throw "Disconnected by server"; } else if (pkt_id == MessageS2CChat_packetInfo.type) { let pkt = MessageS2CChat.decode(pkt_data); logger.info(`CHAT: [${pkt.from}] ${pkt.message}`); } else if (pkt_id == MessageS2CPong_packetInfo.type) { clearTimeout(client.ping_timeout_left); client.ping_timeout_left = setTimeout(ping_timeout_fn, 10 * 1000); } else if (pkt_id == MessageS2CPlayersUpdate_packetInfo.type) { let pkt = MessageS2CPlayersUpdate.decode(pkt_data); global.players = pkt.players; for (let i = 0; i < pkt.players.length; i++) { if (pkt.players[i].username == client.username) { if (global.me !== null) { let x_vel = (global.me.x - pkt.players[i].x) / (1 / 20); let y_vel = (global.me.y - pkt.players[i].y) / (1 / 20); let total_vel = Math.sqrt(x_vel * x_vel + y_vel * y_vel); global.x_vel = x_vel; global.y_vel = y_vel; global.velocity = total_vel; // calc theta global.direction_radians = Math.atan2(global.y_vel, global.x_vel); } global.me = pkt.players[i]; } } } else if (pkt_id == MessageS2CPlanetData_packetInfo.type) { let pkt = MessageS2CPlanetData.decode(pkt_data); global.planets = pkt.planets; } else if (pkt_id == MessageS2CModulesUpdate_packetInfo.type) { let pkt = MessageS2CModulesUpdate.decode(pkt_data); global.modules = pkt.modules; } else if (pkt_id == MessageS2CModuleAdd_packetInfo.type) { let pkt = MessageS2CModuleAdd.decode(pkt_data); let module = { module_type: pkt.module!.moduleType, rotation: pkt.module!.rotation, x: pkt.module!.x, y: pkt.module!.y, children: pkt.module!.children, }; global.tree.set(pkt.module!.id, module); global.clicked = null; } else if (pkt_id == MessageS2CModuleRemove_packetInfo.type) { let pkt = MessageS2CModuleRemove.decode(pkt_data); global.clicked = pkt.module!.id; } else if (pkt_id == MessageS2CModuleTreeUpdate_packetInfo.type) { let pkt = MessageS2CModuleTreeUpdate.decode(pkt_data); let modules: Map = new Map(); pkt.tree.forEach((value: ProtocolAttachedModule) => { modules.set(value.id, { module_type: value.moduleType, rotation: value.rotation, x: value.x, y: value.y, children: value.children, }); }); global.tree = modules; } else { logger.warn(`server sent unexpected packet ${pkt_id} for state Play`); } } }); return client; } let socket: WebSocket | undefined = undefined; function _websocket_connect(url: string): Promise { if (socket && socket.readyState < 2) { // reuse socket connection return Promise.resolve(socket); } return new Promise((resolve, reject) => { socket = new WebSocket(url); socket.onopen = () => { // @ts-ignore if here, guaranteed that `socket` != undefined resolve(socket); } socket.onerror = (err) => { reject(err); } }); }