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<GatewayClient> {
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<number, AttachedModule> = new Map<number, AttachedModule>();
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<WebSocket> {
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);
}
});
}