UNPKG

pw-js-api

Version:

A PixelWalker Library, aims to be minimal with support for browsers.

352 lines 33.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const world_pb_js_1 = require("../gen/world_pb.js"); const Constants_js_1 = require("../util/Constants.js"); const Errors_js_1 = require("../util/Errors.js"); const isows_1 = require("isows"); const protobuf_1 = require("@bufbuild/protobuf"); const Queue_js_1 = tslib_1.__importDefault(require("../util/Queue.js")); const Misc_js_1 = require("../util/Misc.js"); const Timeout_js_1 = require("../util/Timeout.js"); class PWGameClient { constructor(api, settings) { var _a, _b, _c, _d, _e; this.totalBucket = new Queue_js_1.default(100, 1000); this.chatBucket = new Queue_js_1.default(10, 1000); this.connectAttempts = { time: -1, count: 0, }; // listen<Event extends keyof WorldEvents>(type: Event) { // type === "" // } /** * For faster performance (even if it seems insignificant), * direct functions are used instead of events which are also inconsistent with browsers/nodejs etc. * * NOTE: the "this" won't be the client itself. You will need to bind yourself if you want to keep this. */ this.callbacks = {}; // private hooks = { // } as Partial<{ [K in keyof P]: Array<(statey: P[K]) => Promisable<K>> }> /** * Poorly documented because I cba */ this.hooks = []; // I can't use instanceof cos of circular reference kms. if (api && "getJoinKey" in api) this.api = api; else if (api) { settings = api; api = undefined; } this.settings = { reconnectable: (_a = settings === null || settings === void 0 ? void 0 : settings.reconnectable) !== null && _a !== void 0 ? _a : true, reconnectCount: (_b = settings === null || settings === void 0 ? void 0 : settings.reconnectCount) !== null && _b !== void 0 ? _b : 5, reconnectInterval: (_c = settings === null || settings === void 0 ? void 0 : settings.reconnectInterval) !== null && _c !== void 0 ? _c : 4000, reconnectTimeGap: (_d = settings === null || settings === void 0 ? void 0 : settings.reconnectTimeGap) !== null && _d !== void 0 ? _d : 10000, handlePackets: (_e = settings === null || settings === void 0 ? void 0 : settings.handlePackets) !== null && _e !== void 0 ? _e : ["PING"], }; } get connected() { var _a; return ((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === isows_1.WebSocket.OPEN; } /** * This will connect to the world. * * (This returns itself for chaining) */ joinWorld(roomId, joinData) { return tslib_1.__awaiter(this, void 0, void 0, function* () { var _a, _b, _c, _d, _e; if (!this.api) throw Error("This can only work if you've used APIClient to join the world in the first place."); if (((_a = this.socket) === null || _a === void 0 ? void 0 : _a.readyState) === isows_1.WebSocket.CONNECTING) throw Error("Already trying to connect."); // if (!this.api.loggedIn) throw Error("API isn't logged in, you must use authenticate first."); const roomType = (_c = (_b = this.api.roomTypes) === null || _b === void 0 ? void 0 : _b[0]) !== null && _c !== void 0 ? _c : yield this.api.getRoomTypes().then(rTypes => rTypes[0]); const joinReq = yield this.api.getJoinKey(roomType, roomId); if (!("token" in joinReq) || joinReq.token.length === 0) throw Error("Unable to secure a join key - is account details valid?"); const connectUrl = `${(_e = (_d = this.api) === null || _d === void 0 ? void 0 : _d.options.endpoints.GameWS) !== null && _e !== void 0 ? _e : Constants_js_1.Endpoint.GameWS}/ws?joinKey=${joinReq.token}` + (joinData === undefined ? "" : "&joinData=" + btoa(JSON.stringify(joinData))); this.prevWorldId = roomId; if ((this.connectAttempts.time + this.settings.reconnectTimeGap) < Date.now()) { this.connectAttempts = { time: Date.now(), count: 0 }; } return new Promise((res, rej) => { var _a; if (this.connectAttempts.count++ > this.settings.reconnectCount) return rej(new Error("Unable to connect due to many attempts.")); const timer = setInterval(() => { if (this.connectAttempts.count++ > this.settings.reconnectCount) return rej(new Error("Unable to (re)connect.")); this.invoke("debug", "Failed to reconnect, retrying."); this.socket = this.createSocket(connectUrl, timer, res, rej); }, (_a = this.settings.reconnectInterval) !== null && _a !== void 0 ? _a : 4000); this.socket = this.createSocket(connectUrl, timer, res, rej); }); }); } /** * INTERNAL */ createSocket(url, timer, res, rej) { const socket = new isows_1.WebSocket(url); socket.binaryType = "arraybuffer"; // For res/rej. let init = false; socket.onmessage = (evt) => { var _a; const rawPacket = (0, protobuf_1.fromBinary)(world_pb_js_1.WorldPacketSchema, evt.data instanceof ArrayBuffer ? new Uint8Array(evt.data) : evt.data); const { packet } = rawPacket; this.invoke("debug", "Received " + packet.case); this.invoke("raw", rawPacket); if (packet.case === undefined) { return this.invoke("unknown", packet.value); } //this.callbacks.raw?.(packet);; let states = {}; // | undefined; if (this.hooks.length) { try { states = {}; for (let i = 0, len = this.hooks.length; i < len; i++) { const res = this.hooks[i](rawPacket); if (typeof res === "object") { const entries = Object.entries(res); for (let j = 0, jen = entries.length; j < jen; j++) { states[entries[j][0]] = entries[j][1]; } } } } catch (err) { this.invoke("debug", "Unable to execute all hooks safely"); // TODO: separate event for error console.error(err); states = {}; } } switch (packet.case) { case "playerInitPacket": if (this.settings.handlePackets.findIndex(v => v === "INIT") !== -1) this.send("playerInitReceived"); if ((_a = packet.value.playerProperties) === null || _a === void 0 ? void 0 : _a.isWorldOwner) { this.totalBucket.tokenLimit = 200; this.chatBucket.tokenLimit = 10; } else { this.totalBucket.tokenLimit = 125; this.chatBucket.tokenLimit = 5; } if (!init) { clearInterval(timer); init = true; res(this); // Give the client the init again as they might could have missed it even by a few milliseconds. return (0, Timeout_js_1.customSetTimeout)(() => { // TODO: deduplicate this part. if (this.hooks.length) { try { states = {}; for (let i = 0, len = this.hooks.length; i < len; i++) { const res = this.hooks[i](rawPacket); if (typeof res === "object") { const entries = Object.entries(res); for (let j = 0, jen = entries.length; j < jen; j++) { states[entries[j][0]] = entries[j][1]; } } } } catch (err) { this.invoke("debug", "Unable to execute all hooks safely"); // TODO: separate event for error console.error(err); states = {}; } } this.invoke(packet.case, packet.value, states); }, 1500); } break; case "ping": if (this.settings.handlePackets.findIndex(v => v === "PING") !== -1) this.send("ping", undefined, true); break; } this.invoke(packet.case, packet.value, states); }; socket.onopen = (evt) => { this.invoke("debug", "Connected successfully, waiting for init packet."); }; socket.onclose = (evt) => { this.invoke("debug", `Server closed connection due to code ${evt.code}, reason: "${evt.reason}".`); if (!init) { clearInterval(timer); rej(new Errors_js_1.AuthError(evt.reason, (evt.code))); } if (this.settings.reconnectable) { if (this.api === undefined) return this.invoke("debug", "Not attempting to reconnect as this game client was created with a join token."); // if (evt.reason === "Failed to preload the world.") { // return this.invoke("debug", "Not attempting to reconnect as the world don't exist."); // } if (this.prevWorldId) { this.invoke("debug", "Attempting to reconnect."); return this.joinWorld(this.prevWorldId).catch(err => { this.invoke("debug", err); }); } else this.invoke("debug", "Warning: Socket closed, attempt to reconnect was made but no previous world id was kept."); } }; return socket; } /** * This is a more direct route if you already have a join key acquired via Pixelwalker's API. * * Useful for those wary of security. */ static joinWorld(joinKey, obj, EndpointURL = Constants_js_1.Endpoint.GameWS) { const connectUrl = `${EndpointURL}/ws?joinKey=${joinKey}` + ((obj === null || obj === void 0 ? void 0 : obj.joinData) === undefined ? "" : "&joinData=" + btoa(JSON.stringify(obj.joinData))); const cli = new PWGameClient(obj === null || obj === void 0 ? void 0 : obj.gameSettings); if ((cli.connectAttempts.time + cli.settings.reconnectTimeGap) < Date.now()) { cli.connectAttempts = { time: Date.now(), count: 0 }; } return new Promise((res, rej) => { var _a; if (cli.connectAttempts.count++ > cli.settings.reconnectCount) return rej(new Error("Unable to connect due to many attempts.")); const timer = setInterval(() => { var _a; (_a = cli.socket) === null || _a === void 0 ? void 0 : _a.close(); if (cli.connectAttempts.count++ > cli.settings.reconnectCount) return rej(new Error("Unable to (re)connect.")); cli.invoke("debug", "Failed to reconnect, retrying."); cli.socket = cli.createSocket(connectUrl, timer, res, rej); }, (_a = cli.settings.reconnectInterval) !== null && _a !== void 0 ? _a : 4000); cli.socket = cli.createSocket(connectUrl, timer, res, rej); }); } /** * This is different to addCallback as all hooks (regardless of the type) will execute first before the callbacks, each hook may modify something or do something in the background * and may pass it to callbacks (via the second parameter in callbacks). If an error occurs while executing one of the hooks, * the execution of hooks will halt for that packet and callbacks will run without the states. * * NOTE: This is permanent, if a hook is added, it can't be removed. */ addHook(hook) { // if (this.callbacks["raw"] === undefined) this.callbacks["raw"] = []; // this.hooks.oldChatMessagesPacket this.hooks.push(hook); // this.callbacks["raw"].unshift(hook); return this; } addCallback(type, ...cbs) { // this.callbacks[type] = cb; if (this.callbacks[type] === undefined) this.callbacks[type] = []; if (cbs.length === 0) return this; this.callbacks[type].push(...cbs); return this; } prependCallback(type, ...cbs) { // this.callbacks[type] = cb; if (this.callbacks[type] === undefined) this.callbacks[type] = []; if (cbs.length === 0) return this; this.callbacks[type].unshift(...cbs); return this; } /** * @param type The type of the event * @param cb It can be the function itself (to remove that specific function). If undefined, it will remove ALL functions from that list, it will return undefined. */ removeCallback(type, cb) { const callbacks = this.callbacks[type]; if (callbacks === undefined || cb === undefined) { callbacks === null || callbacks === void 0 ? void 0 : callbacks.splice(0); return; } else { for (let i = 0, len = callbacks.length; i < len; i++) { if (callbacks[i] === cb) { return callbacks.splice(i, 1)[0]; } } } return; } invoke(type, data, states) { return tslib_1.__awaiter(this, void 0, void 0, function* () { const cbs = this.callbacks[type]; let result = { count: 0, stopped: false }; if (cbs === undefined) return result; for (let i = 0, len = cbs.length; i < len; i++) { const res = yield ((0, Misc_js_1.isCustomPacket)(type) ? cbs[i](data) : cbs[i](data, states)); result.count++; if (typeof res === "object") { const keys = Object.keys(res); for (let j = 0, jen = keys.length; j < jen; j++) { data[keys[j]] = res[keys[j]]; } } if (res === "STOP") { result.stopped = true; return result; } } return result; }); } /** * This assumes that the connection * * @param type Type of the packet. * @param value Value of the packet to send along with, note that some properties are optional. * @param direct If it should skip queue. */ send(type, value, direct = false) { this.invoke("debug", "Sent " + type + " with " + (value === undefined ? "0" : Object.keys(value).length) + " parameters."); const send = () => { var _a; return (_a = this.socket) === null || _a === void 0 ? void 0 : _a.send((0, protobuf_1.toBinary)(world_pb_js_1.WorldPacketSchema, (0, protobuf_1.create)(world_pb_js_1.WorldPacketSchema, { packet: { case: type, value } }))); }; if (direct) return send(); if (type === "playerChatPacket") this.chatBucket.queue(() => { send(); }); else this.totalBucket.queue(() => { send(); }); } /** * By default this will set the game client settings reconnectable to false. * * If reconnect is true, an additionl parameter can be passed which is the amount of time to wait before it attempts to reconnect (DEFAULT: none) */ disconnect(reconnect = false) { var _a, _b; // Accept the possibility that people may try to if (reconnect === true) this.settings.reconnectable = true; else this.settings.reconnectable = false; (_a = this.socket) === null || _a === void 0 ? void 0 : _a.close(); return ((_b = this.socket) === null || _b === void 0 ? void 0 : _b.readyState) === isows_1.WebSocket.CLOSED; } } exports.default = PWGameClient; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiUFdHYW1lQ2xpZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vbGliL2dhbWUvUFdHYW1lQ2xpZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUNBLG9EQUFnSztBQUVoSyx1REFBZ0Q7QUFDaEQsaURBQThDO0FBRTlDLGlDQUFrQztBQUNsQyxpREFBa0U7QUFFbEUsd0VBQXFDO0FBRXJDLDZDQUFpRDtBQUNqRCxtREFBc0Q7QUFJdEQsTUFBcUIsWUFBWTtJQXdCN0IsWUFBWSxHQUErQyxFQUFFLFFBQXNDOztRQWJ6RixnQkFBVyxHQUFHLElBQUksa0JBQUssQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDbkMsZUFBVSxHQUFHLElBQUksa0JBQUssQ0FBQyxFQUFFLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFFakMsb0JBQWUsR0FBRztZQUN4QixJQUFJLEVBQUUsQ0FBQyxDQUFDO1lBQ1IsS0FBSyxFQUFFLENBQUM7U0FDWCxDQUFBO1FBOE9ELHlEQUF5RDtRQUN6RCxrQkFBa0I7UUFDbEIsSUFBSTtRQUVKOzs7OztXQUtHO1FBQ08sY0FBUyxHQUFHLEVBRWlILENBQUM7UUFFeEksb0JBQW9CO1FBRXBCLDJFQUEyRTtRQUUzRTs7V0FFRztRQUNLLFVBQUssR0FBa0MsRUFBRSxDQUFDO1FBM1A5Qyx3REFBd0Q7UUFDeEQsSUFBSSxHQUFHLElBQUksWUFBWSxJQUFJLEdBQUc7WUFBRSxJQUFJLENBQUMsR0FBRyxHQUFHLEdBQUcsQ0FBQzthQUMxQyxJQUFJLEdBQUcsRUFBRSxDQUFDO1lBQ1gsUUFBUSxHQUFHLEdBQUcsQ0FBQztZQUNmLEdBQUcsR0FBRyxTQUFTLENBQUM7UUFDcEIsQ0FBQztRQUVELElBQUksQ0FBQyxRQUFRLEdBQUc7WUFDWixhQUFhLEVBQUUsTUFBQSxRQUFRLGFBQVIsUUFBUSx1QkFBUixRQUFRLENBQUUsYUFBYSxtQ0FBSSxJQUFJO1lBQzlDLGNBQWMsRUFBRSxNQUFBLFFBQVEsYUFBUixR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