pw-js-api
Version:
A PixelWalker Library, aims to be minimal with support for browsers.
352 lines • 33.5 kB
JavaScript
"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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