diff --git a/README.md b/README.md index 72bfaf1..241ed8e 100644 --- a/README.md +++ b/README.md @@ -329,6 +329,8 @@ SetEntityValue: 1 SetSubscription: 1 TeamInfo: 1 Time: 1 +Camera Subscription: 1 +Camera Movement: 0.01 ``` ## Hey Facepunch! diff --git a/camera.js b/camera.js new file mode 100644 index 0000000..85765d5 --- /dev/null +++ b/camera.js @@ -0,0 +1,425 @@ +"use strict"; + +const { EventEmitter } = require("events"); +const Jimp = require("jimp"); + +class Camera extends EventEmitter { + + /** + * These represent the possible buttons that can be sent to the server. + */ + static Buttons = { + NONE: 0, + FORWARD: 2, + BACKWARD: 4, + LEFT: 8, + RIGHT: 16, + JUMP: 32, + DUCK: 64, + SPRINT: 128, + USE: 256, + FIRE_PRIMARY: 1024, + FIRE_SECONDARY: 2048, + RELOAD: 8192, + FIRE_THIRD: 134217728, + } + + /** + * These represent the possible control flags that can be sent to the server. + * For example, Static CCTV cameras will not support movement. + */ + static ControlFlags = { + NONE: 0, + MOVEMENT: 1, + MOUSE: 2, + SPRINT_AND_DUCK: 4, + FIRE: 8, + RELOAD: 16, + CROSSHAIR: 32, + } + + /** + * @param rustplus An existing RustPlus instance + * @param identifier Camera Identifier, such as OILRIG1 (or custom name) + * + * Events emitted by the Camera class instance + * - subscribing: When we are subscribing to the Camera. + * - subscribed: When we are subscribed to the Camera. + * - unsubscribing: When we are unsubscribing from the Camera. + * - unsubscribed: When we are unsubscribed from the Camera. + * - render: When a camera frame has been rendered. A png image buffer will be provided. + */ + constructor(rustplus, identifier) { + + super(); + + this.rustplus = rustplus; + this.identifier = identifier; + this.isSubscribed = false; + + this.cameraRays = []; + this.cameraSubscribeInfo = null; + this.subscribeInterval = null; + + // listen to camera message broadcasts + this.rustplus.on('message', async (message) => { + await this._onMessage(message); + }); + + // unsubscribe when rustplus is disconnected (to prevent hanging due to intervals still running) + this.rustplus.on('disconnected', async () => { + if(this.isSubscribed){ + await this.unsubscribe(); + } + }); + + } + + async _onMessage(message) { + + // do nothing if not subscribed + if(!this.isSubscribed){ + return; + } + + if(message.broadcast && message.broadcast.cameraRays){ + await this._onCameraRays(message.broadcast.cameraRays); + } + + } + + async _onCameraRays(cameraRays) { + + // do nothing if not subscribed + if(!this.isSubscribed){ + return; + } + + // add new camera rays to cache + this.cameraRays.push(cameraRays); + + // wait until we have enough camera rays to render an image + if(this.cameraRays.length > 10){ + + // remove first oldest rayData + this.cameraRays.shift(); + + // render to png + const frame = await this._renderCameraFrame(this.cameraRays, this.cameraSubscribeInfo.width, this.cameraSubscribeInfo.height); + + // fire callback + await this._onRender(frame); + + } + + } + + async _onRender(image) { + + // do nothing if not subscribed + if(!this.isSubscribed){ + return; + } + + this.emit('render', image); + + } + + /** + * Render a camera frame to a PNG image buffer + * @param frames the frame data to render. This will be an array of camera rays from the server. + * @param width the width of the frame + * @param height the height of the frame + */ + async _renderCameraFrame(frames, width, height) { + + // First we populate the samplePositionBuffer with the positions of each sample + const samplePositionBuffer = new Int16Array(width * height * 2); + for (let w = 0, _ = 0; _ < height; _++) + for (let g = 0; g < width; g++) { + samplePositionBuffer[w] = g; + samplePositionBuffer[++w] = _; + w++; + } + + for (let B = new IndexGenerator(1337), R = width * height - 1; R >= 1; R--) { + let C = 2 * R, + I = 2 * B.nextInt(R + 1), + P = samplePositionBuffer[C], + k = samplePositionBuffer[C + 1], + A = samplePositionBuffer[I], + F = samplePositionBuffer[I + 1]; + samplePositionBuffer[I] = P; + samplePositionBuffer[I + 1] = k; + samplePositionBuffer[C] = A; + samplePositionBuffer[C + 1] = F; + } + + // Create the output buffer + const output = new Array(width * height); + // Loop through each frame + for (let frame of frames) { + + // Reset some look back and pointer variables + let sampleOffset = 2 * frame.sampleOffset; + let dataPointer = 0; + let rayLookback = new Array(64); + for (let r = 0; r < 64; r++) rayLookback[r] = [0, 0, 0]; + + const rayData = frame.rayData; + + // Loop through the ray data + while (true) { + if (dataPointer >= rayData.length - 1) + break; + + // Get the first byte and set some variables + let t, r, i, n = rayData[dataPointer++]; + + // Ray Decoding Logic + if (255 === n) { + let l = rayData[dataPointer++], + o = rayData[dataPointer++], + s = rayData[dataPointer++], + u = (3 * (((t = (l << 2) | (o >> 6)) / 128) | 0) + 5 * (((r = 63 & o) / 16) | 0) + 7 * (i = s)) & 63, + f = rayLookback[u]; + f[0] = t; + f[1] = r; + f[2] = i; + } else { + let c = 192 & n; + + if (0 === c) { + let h = 63 & n, y = rayLookback[h]; + t = y[0]; + r = y[1]; + i = y[2]; + } else if (64 === c) { + let p = 63 & n, + v = rayLookback[p], + b = v[0], + w = v[1], + _ = v[2], + g = rayData[dataPointer++]; + t = b + ((g >> 3) - 15); + r = w + ((7 & g) - 3); + i = _; + } else if (128 === c) { + let R = 63 & n, + C = rayLookback[R], + I = C[0], + P = C[1], + k = C[2]; + t = I + (rayData[dataPointer++] - 127); + r = P; + i = k; + } else { + let A = rayData[dataPointer++], + F = rayData[dataPointer++], + D = (3 * (((t = (A << 2) | (F >> 6)) / 128) | 0) + 5 * (((r = 63 & F) / 16) | 0) + 7 * (i = 63 & n)) & 63, + E = rayLookback[D]; + E[0] = t; + E[1] = r; + E[2] = i; + } + } + + sampleOffset %= 2 * width * height; + const index = samplePositionBuffer[sampleOffset++] + samplePositionBuffer[sampleOffset++] * width; + output[index] = [t / 1023, r / 63, i]; + } + } + + const colours = [ + [0.5, 0.5, 0.5], [0.8, 0.7, 0.7], [0.3, 0.7, 1], [0.6, 0.6, 0.6], + [0.7, 0.7, 0.7], [0.8, 0.6, 0.4], [1, 0.4, 0.4], [1, 0.1, 0.1], + ]; + + const image = new Jimp(width, height); + + for (let i = 0; i < output.length; i++) { + let ray = output[i]; + if (!ray) { + continue; + } + + let distance = ray[0] + let alignment = ray[1] + let material = ray[2] + + let target_colour; + + if (distance === 1 && alignment === 0 && material === 0) { + target_colour = [208, 230, 252]; + } else { + let colour = colours[material]; + target_colour = [(alignment * colour[0] * 255), (alignment * colour[1] * 255), (alignment * colour[2] * 255)] + } + + let x = i % width; + let y = height - 1 - Math.floor(i / width); + image.setPixelColor(Jimp.rgbaToInt(target_colour[0], target_colour[1], target_colour[2], 255), x, y); + } + + // return png buffer + return image.getBufferAsync(Jimp.MIME_PNG); + + } + + async _subscribe() { + + // subscribe to camera + const response = await this.rustplus.sendRequestAsync({ + cameraSubscribe: { + cameraId: this.identifier, + }, + }); + + // update camera subscribe info + this.cameraSubscribeInfo = response.cameraSubscribeInfo; + this.isSubscribed = true; + + } + + async subscribe() { + + this.emit('subscribing'); + + // subscribe to camera + await this._subscribe(); + + this.emit('subscribed'); + + // automatically resubscribe to the camera every 10 seconds + this.subscribeInterval = setInterval(async () => { + if(this.isSubscribed){ + await this._subscribe(); + } + }, 10_000); + + } + + async unsubscribe() { + + this.emit('unsubscribing'); + + this.isSubscribed = false; + + // stop automatically resubscribing + clearInterval(this.subscribeInterval); + + // release memory + this.cameraRays = []; + this.cameraSubscribeInfo = null; + this.subscribeInterval = null; + + // unsubscribe from camera on server (if connected) + if(this.rustplus.isConnected()){ + try { + await this.rustplus.sendRequestAsync({ + cameraUnsubscribe: { + + }, + }); + } catch (error) { + // ignore errors unsubscribing from camera + } + } + + this.emit('unsubscribed'); + + } + + /** + * Sends camera movement to the server (mouse movement) + * @param buttons The buttons that are currently pressed + * @param x The x delta of the mouse movement + * @param y The y delta of the mouse movement + */ + async move(buttons, x, y) { + return await this.rustplus.sendRequestAsync({ + cameraInput: { + buttons: buttons, + mouseDelta: { + x: x, + y: y, + } + }, + }); + } + + /** + * Zooms a PTZ camera in by 1 level. + * PTZ cameras have 4 zoom levels. + * If the PTZ camera is already at max zoom (level 4), it zooms out as far as it can (level 1). + */ + async zoom() { + + // press left mouse button to zoom in + await this.move(Camera.Buttons.FIRE_PRIMARY, 0, 0); + + // release all mouse buttons + await this.move(Camera.Buttons.NONE, 0, 0); + + } + + /** + * Shoots a PTZ controllable Auto Turret. + */ + async shoot() { + + // press left mouse button to shoot + await this.move(Camera.Buttons.FIRE_PRIMARY, 0, 0); + + // release all mouse buttons + await this.move(Camera.Buttons.NONE, 0, 0); + + } + + /** + * Reloads a PTZ controllable Auto Turret + */ + async reload() { + + // press reload button to reload turret + await this.move(Camera.Buttons.RELOAD, 0, 0); + + // release all mouse buttons + await this.move(Camera.Buttons.NONE, 0, 0); + + } + + /** + * Check if camera is an auto turret + * @returns {boolean} + */ + isAutoTurret() { + const crosshairControlFlag = Camera.ControlFlags.CROSSHAIR; + return (this.cameraSubscribeInfo?.controlFlags & crosshairControlFlag) === crosshairControlFlag; + } + +} + +class IndexGenerator { + + constructor(e) { + this.state = 0 | e; + this.nextState(); + } + + nextInt(e) { + let t = ((this.nextState() * (0 | e)) / 4294967295) | 0; + if (t < 0) t = e + t - 1; + return 0 | t; + } + + nextState() { + let e = this.state, t = e; + e = ((e = ((e = (e ^ ((e << 13) | 0)) | 0) ^ ((e >>> 17) | 0)) | 0) ^ ((e << 5) | 0)) | 0; + this.state = e; + return t >= 0 ? t : 4294967295 + t - 1; + } + +} + +module.exports = Camera; \ No newline at end of file diff --git a/examples/10_shoot_autoturret.js b/examples/10_shoot_autoturret.js new file mode 100644 index 0000000..56c0513 --- /dev/null +++ b/examples/10_shoot_autoturret.js @@ -0,0 +1,100 @@ +const RustPlus = require('../rustplus'); +const Camera = require("../camera"); +var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken'); + +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + +rustplus.on('connected', async () => { + + console.log("connected"); + + // get a camera (should be an autoturret for this example) + const turret = rustplus.getCamera("TURRET1"); + + // wait until subscribed to autoturret camera + turret.on('subscribed', async () => { + + // check if camera is an auto turret + if(!turret.isAutoTurret()){ + console.log("Camera is not an auto turret!"); + await rustplus.disconnect(); + return; + } + + console.log("subscribed to autoturret camera"); + await delay(500); + + const shootCount = 3; + const shootDelay = 250; + const moveDelay = 500; + const moveAmount = 5; + + // shoot autoturret + console.log("shooting"); + for(let i = 0; i < shootCount; i++){ + await delay(shootDelay); + await turret.shoot(); + } + + // move autoturret left + console.log("moving left"); + await delay(moveDelay); + await turret.move(Camera.Buttons.NONE, -moveAmount, 0); + + // shoot autoturret + console.log("shooting"); + for(let i = 0; i < shootCount; i++){ + await delay(shootDelay); + await turret.shoot(); + } + + // move autoturret up + console.log("moving up"); + await delay(moveDelay); + await turret.move(Camera.Buttons.NONE, 0, moveAmount); + + // shoot autoturret + console.log("shooting"); + for(let i = 0; i < shootCount; i++){ + await delay(shootDelay); + await turret.shoot(); + } + + // move autoturret right + console.log("moving right"); + await delay(moveDelay); + await turret.move(Camera.Buttons.NONE, moveAmount, 0); + + // shoot autoturret + console.log("shooting"); + for(let i = 0; i < shootCount; i++){ + await delay(shootDelay); + await turret.shoot(); + } + + // move autoturret down + console.log("moving down"); + await delay(moveDelay); + await turret.move(Camera.Buttons.NONE, 0, -moveAmount); + + // shoot autoturret + console.log("shooting"); + for(let i = 0; i < shootCount; i++){ + await delay(shootDelay); + await turret.shoot(); + } + + console.log("disconnecting"); + await rustplus.disconnect(); + + }); + + // subscribe to autoturret camera + await turret.subscribe(); + +}); + +// connect to rust server +rustplus.connect(); \ No newline at end of file diff --git a/examples/7_render_camera.js b/examples/7_render_camera.js new file mode 100644 index 0000000..0a01b52 --- /dev/null +++ b/examples/7_render_camera.js @@ -0,0 +1,34 @@ +const RustPlus = require('@liamcottle/rustplus.js'); +const fs = require("fs"); +var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken'); + +rustplus.on('connected', async () => { + + console.log("connected"); + + // get a camera + const camera = rustplus.getCamera("DOME1"); + + // listen for events when a camera frame has been rendered, you will get a png image buffer + camera.on('render', async (frame) => { + + console.log("on render"); + + // save camera frame to disk + fs.writeFileSync(`camera.png`, frame); + + // unsubscribe from camera to allow others to control it + await camera.unsubscribe(); + + // disconnect from server after a single render + rustplus.disconnect(); + + }); + + // subscribe to camera + await camera.subscribe(); + +}); + +// connect to rust server +rustplus.connect(); \ No newline at end of file diff --git a/examples/8_move_ptz_camera.js b/examples/8_move_ptz_camera.js new file mode 100644 index 0000000..c8ce98d --- /dev/null +++ b/examples/8_move_ptz_camera.js @@ -0,0 +1,56 @@ +const RustPlus = require('../rustplus'); +const Camera = require('../camera'); +var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken'); + +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + +rustplus.on('connected', async () => { + + console.log("connected"); + + // get a camera (must support PTZ) + const camera = rustplus.getCamera("PTZ1"); + + // wait until subscribed to camera + camera.on('subscribed', async () => { + + console.log("subscribed to camera"); + + // move camera up 10 times + for(let i = 0; i < 10; i++){ + await camera.move(Camera.Buttons.NONE, 0, 1); + await delay(100); + } + + // move camera down 10 times + for(let i = 0; i < 10; i++){ + await camera.move(Camera.Buttons.NONE, 0, -1); + await delay(100); + } + + // move camera left 10 times + for(let i = 0; i < 10; i++){ + await camera.move(Camera.Buttons.NONE, -1, 0); + await delay(100); + } + + // move camera right 10 times + for(let i = 0; i < 10; i++){ + await camera.move(Camera.Buttons.NONE, 1, 0); + await delay(100); + } + + console.log("disconnecting"); + await rustplus.disconnect(); + + }); + + // subscribe to camera + await camera.subscribe(); + +}); + +// connect to rust server +rustplus.connect(); \ No newline at end of file diff --git a/examples/9_zoom_ptz_camera.js b/examples/9_zoom_ptz_camera.js new file mode 100644 index 0000000..ff034e2 --- /dev/null +++ b/examples/9_zoom_ptz_camera.js @@ -0,0 +1,37 @@ +const RustPlus = require('../rustplus'); +var rustplus = new RustPlus('ip', 'port', 'playerId', 'playerToken'); + +function delay(time) { + return new Promise(resolve => setTimeout(resolve, time)); +} + +rustplus.on('connected', async () => { + + console.log("connected"); + + // get a camera (must support PTZ) + const camera = rustplus.getCamera("PTZ1"); + + // wait until subscribed to camera + camera.on('subscribed', async () => { + + console.log("subscribed to camera"); + + // zoom camera every 1 second, 8 times + for(let i = 0; i < 8; i++){ + await camera.zoom(); + await delay(1000); + } + + console.log("disconnecting"); + await rustplus.disconnect(); + + }); + + // subscribe to camera + await camera.subscribe(); + +}); + +// connect to rust server +rustplus.connect(); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6284743..4609892 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ "command-line-args": "^5.2.0", "command-line-usage": "^6.1.1", "express": "^4.17.1", + "jimp": "^0.22.7", "protobufjs": "^7.1.2", "push-receiver": "^2.1.0", "uuid": "^9.0.0", @@ -23,6 +24,395 @@ "rustplus": "cli/index.js" } }, + "node_modules/@jimp/bmp": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.7.tgz", + "integrity": "sha512-0cfBPvugURS7G+60vRBL+penDRst8x40alS5Rhn2nlGsgsBHljFDw7+H4o5r6gldw9nv9PR9JA90Wloy7KMZdQ==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/core": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.7.tgz", + "integrity": "sha512-lg4z+pw23v2Gp9LWQur0NqYtnmoNWnyN/Or96elhJgeEJskrDGwROdajortHCCOI1xDnUZSirg8sFvStC8BIlg==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "mkdirp": "^2.1.3", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } + }, + "node_modules/@jimp/custom": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.7.tgz", + "integrity": "sha512-n+1+ZVDNumB1E+sL7KdGKAJ6MbgniX1/v/xOEFEQ46WDZ4cRTqP4+tXjHTuHSlOXiANH+K9zD6qgzqmgO6mCVw==", + "dependencies": { + "@jimp/core": "^0.22.7" + } + }, + "node_modules/@jimp/gif": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.7.tgz", + "integrity": "sha512-PGZMS8sYFnDcqg+t8IT3RaSJLrqB+3GzhI0hU5D4mmSuJ5UO/6Bdgu8nrwh3uFPxw0ZH6h9ozYk88cz0pKEhLQ==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "gifwrap": "^0.9.2", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/jpeg": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.7.tgz", + "integrity": "sha512-ptwWyX/7RPcREy8SpPN/8IlywbwyPXiuXmoHwM6m4iKcyaCmmnfCdZwLNXYliJzFAFLLOWDuOrwO3cZSkH6Czg==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.7.tgz", + "integrity": "sha512-8oXcBTSd/sBmTQATrCxQ1ZBER31Lge8vXzWqNCbC3b1ZvRggCcqnDzRRH1+JiI4i+jPRo3Fi6/sdvEUyQ5LY3g==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.7.tgz", + "integrity": "sha512-M+0I5CKFIpnIQE27j8o8NECBsOFBd4z7C95ydy2UohYopugFq+hSVtMs1D4pQgb0RW1DJPiXD/4PHqb+lzV5mA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.7.tgz", + "integrity": "sha512-zfZKKpOhlyiDeFjGW5JB9K4h/kvbdaAJWUEwmKrvvGar67G3j8dKu46AX0MeWRNZ1yk/lfz+JIa7TzKfxEBf6w==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.7.tgz", + "integrity": "sha512-OXro9pdB0twQjV4LgW0bTEXaX1VgBsTBcFoDAs8q9mtQzD5p3UQmJ+ykCiQ5rTPxNN1Buc44tcCIfp8haB1ZVQ==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.7.tgz", + "integrity": "sha512-GwUxZp4jMA0O0qbknUPDONJAfHFaTRs8kK+jgRtUfgb1Xi96l5RN/PMMDv4owZCUiPVAON80X1BMj7nSQWNVUw==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.7.tgz", + "integrity": "sha512-PVXeQyofGepMoJaQ5XapLwCcZfsOF1IoAotHosh8AOP8niCP/Erm8T6ZWf5tf0sMJiLHQMPUyns186H5isqEMQ==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.7.tgz", + "integrity": "sha512-XXvUU+hPdodtTBSgyUJUnzh7JgKMVlS1GxjcQsjYU8iGr1dbpuazKMTQxc76ChVmy8ue4goi8bGstacWUHpl/Q==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.7.tgz", + "integrity": "sha512-CCNAkmm2OS4QQtNRfQvXqoAMxNE0maSlVEV5DNdioHOUKycy02EJ5hNYR3l0FG+NraQHOuqv9XV37sGRl6QzMA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.7.tgz", + "integrity": "sha512-ndCW5MIGMdh3aBvvgRCO7el9cIPG29kU7xQYlOs5+3JsDk3Vf7X30QGPjzxABOY95qLUNUjf5Qe/p/tqv/vbcw==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.7.tgz", + "integrity": "sha512-boI1QowhZRfb6OF+ZPWtiSJP1GATsTHjd5Oy/lJ+n0L4rp439ZOTB1Elzcgc44O2C1mgZDdybRPQQvYdPF8slA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.7.tgz", + "integrity": "sha512-/jkbgtvQPcKadAEV5ZXyoEpSdd7GEvGs/Ya/f48+LNszc+S24u4UXtuP3QPRJ5FHm0Re1t4uztM7xa6IPklAOA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.7.tgz", + "integrity": "sha512-OB1sdnjzq2rfUHmx9Rvi3SJIDbQAgWFgYEw6KhN3TSVOdrJHvwrQkEnwR9PoUzQg992VIpGcVc9Y1s/SOU2oCA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.7.tgz", + "integrity": "sha512-dX/TqACJ/M5uXDIEJlVPPwietMD6EWUeA/CV4uvhLz9EMjTgHociJ3TWqGCY/70phhIBLbhLcHUVBL/q65ynfQ==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.7.tgz", + "integrity": "sha512-rfKHKJLAtJG7qbB4zYAMcQ9ue3CIFRuAJ3xX0lzCxC0fGvCVuXlcxiAEauBxqaTWqiKMnahqpR3/Ah679K2FKQ==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.7.tgz", + "integrity": "sha512-t8x2jjKDmvUAZB4Wbeagr4D0BvoVCIWquy94mpglvSZ8ujKLt0aQBl3CBEIbXFAoVqNif+G36NtxPHNsjxIXOg==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.7.tgz", + "integrity": "sha512-kx0+cPeinki1IFg9cJy7LC4uVuOEOa8TIrcERioB6PVgJ7EDzCAfatTKULZ+t4uSs2K/lQF97wPYlbiyxs/Hzg==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.7.tgz", + "integrity": "sha512-pg7i0JIYt7x7ag+CoD/yG70Xvwm1sKRfcFjQh954yestiin14uppPgXchAmTBmctecBjLNdsVlqSXbPvU4Jvxw==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.7.tgz", + "integrity": "sha512-Uh3Gb18IY8uXWk6E1bzMopum2GP+xwohbnMIDE0MSWmLaz7LXrfnvgXFba1uRGgn73CJz8UDS4fC1KIJMuxQZA==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.7.tgz", + "integrity": "sha512-3uHUrk5Rl6MCxuoJtHTSeJjSHIxHWqOOgmD2caKIvyxds0Zmofu/Fva+N4V/m80E4q4G2RXNsUplFpFGhUM7hw==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.7.tgz", + "integrity": "sha512-NKEq5VR8U/d0OKf0hxFtrrbMCuNv7by31V+Kwgxb1oTP+j+zZEaww+m3YgEwIwRe7E8/yeDSHa5bJ+CmuyFZjw==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.7.tgz", + "integrity": "sha512-BH4aLwfmnqjRVhdzMIqUns4ycZ6QoHHFR6Qz+X2iSpH5a33xFA4DRbd3Ehtrs4Gk7XiCjWkUyM6wjmH7l/1hNQ==", + "dependencies": { + "@jimp/utils": "^0.22.7" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } + }, + "node_modules/@jimp/plugins": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.7.tgz", + "integrity": "sha512-AJmzTG/sa+CDpvle/UE89hjHR85gnRGSwLuQqPbhlY6GFCmC3uqHRJz9O5I8A4zdi9+e8LsBphuTlKV7RbuXOw==", + "dependencies": { + "@jimp/plugin-blit": "^0.22.7", + "@jimp/plugin-blur": "^0.22.7", + "@jimp/plugin-circle": "^0.22.7", + "@jimp/plugin-color": "^0.22.7", + "@jimp/plugin-contain": "^0.22.7", + "@jimp/plugin-cover": "^0.22.7", + "@jimp/plugin-crop": "^0.22.7", + "@jimp/plugin-displace": "^0.22.7", + "@jimp/plugin-dither": "^0.22.7", + "@jimp/plugin-fisheye": "^0.22.7", + "@jimp/plugin-flip": "^0.22.7", + "@jimp/plugin-gaussian": "^0.22.7", + "@jimp/plugin-invert": "^0.22.7", + "@jimp/plugin-mask": "^0.22.7", + "@jimp/plugin-normalize": "^0.22.7", + "@jimp/plugin-print": "^0.22.7", + "@jimp/plugin-resize": "^0.22.7", + "@jimp/plugin-rotate": "^0.22.7", + "@jimp/plugin-scale": "^0.22.7", + "@jimp/plugin-shadow": "^0.22.7", + "@jimp/plugin-threshold": "^0.22.7", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/png": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.7.tgz", + "integrity": "sha512-LxD3O9FKEwVv+j+HcUV7ez72Miy+823EjhtFZbBYXNp9qjHtHFBpgcSJBftUOCei8OlmmVgULYn9XjyfPsDgGw==", + "dependencies": { + "@jimp/utils": "^0.22.7", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/tiff": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.7.tgz", + "integrity": "sha512-/oE8kLumzBfU1Z6h4TrDXYCGQNc4CjbZQvPssjImEqNLr5vbefpIpoy1fVMpsyuHZHsGovsBhBHxTJaRLO4+Og==", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/types": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.7.tgz", + "integrity": "sha512-1T8BxwDh5HJvBh3tt6HUd8r7ir5Ge3JWATXC8O3Y9QYwOaERjA2+FVhGSjtoo5xCeJvLRjSzEtfZ8heowMBL4w==", + "dependencies": { + "@jimp/bmp": "^0.22.7", + "@jimp/gif": "^0.22.7", + "@jimp/jpeg": "^0.22.7", + "@jimp/png": "^0.22.7", + "@jimp/tiff": "^0.22.7", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.7.tgz", + "integrity": "sha512-4ax4IOWLIERx4yz9y3fNXKvQaPOY23yJF5h4sizxVkQUObkZHWE0kL0TVHodBt3rS8ksdbCL8Jkz4GeNP/Katg==", + "dependencies": { + "regenerator-runtime": "^0.13.3" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -77,6 +467,11 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@tokenizer/token": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz", + "integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==" + }, "node_modules/@types/long": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", @@ -125,6 +520,11 @@ "node": ">=4" } }, + "node_modules/any-base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/any-base/-/any-base-1.1.0.tgz", + "integrity": "sha512-uMgjozySS8adZZYePpaWs8cxB9/kdzmpX6SgJZ+wbz1K5eYk5QMYDVJaZKhxyIHUdnnJkfR7SVgStgH7LkGUyg==" + }, "node_modules/array-back": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", @@ -182,6 +582,25 @@ "proxy-from-env": "^1.1.0" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", @@ -195,6 +614,11 @@ "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, + "node_modules/bmp-js": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/bmp-js/-/bmp-js-0.1.0.tgz", + "integrity": "sha512-vHdS19CnY3hwiNdkaqk93DvjVLfbEcI8mys4UjuWrlX1haDmroo8o4xCzh4wD6DGV6HxRCyauwhHRqMTfERtjw==" + }, "node_modules/body-parser": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", @@ -218,6 +642,37 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-equal": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-0.0.1.tgz", + "integrity": "sha512-RgSV6InVQ9ODPdLWJ5UAqBqJBOg370Nz6ZQtRzpt6nUjc8v0St97uJ4PYC6NztqIScrAXafKM3mZPMygSe1ggA==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -438,6 +893,11 @@ "npm": "1.2.8000 || >= 1.4.16" } }, + "node_modules/dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==" + }, "node_modules/ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", @@ -484,6 +944,11 @@ "node": ">= 0.6" } }, + "node_modules/exif-parser": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/exif-parser/-/exif-parser-0.1.12.tgz", + "integrity": "sha512-c2bQfLNbMzLPmzQuOr8fy0csy84WmwnER81W88DzTp9CYNPJ6yzOj2EZAh9pywYpqHnshVLHQJ8WzldAyfY+Iw==" + }, "node_modules/express": { "version": "4.18.2", "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", @@ -548,6 +1013,22 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, "node_modules/finalhandler": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", @@ -658,6 +1139,24 @@ "assert-plus": "^1.0.0" } }, + "node_modules/gifwrap": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/gifwrap/-/gifwrap-0.9.4.tgz", + "integrity": "sha512-MDMwbhASQuVeD4JKd1fKgNgCRL3fGqMM4WaqpNhWO0JiMOAjbQdumbs4BbBZEy9/M00EHEjKN3HieVhCUlwjeQ==", + "dependencies": { + "image-q": "^4.0.0", + "omggif": "^1.0.10" + } + }, + "node_modules/global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dependencies": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "node_modules/har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", @@ -760,6 +1259,38 @@ "node": ">=0.10.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/image-q": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/image-q/-/image-q-4.0.0.tgz", + "integrity": "sha512-PfJGVgIfKQJuq3s0tTDOKtztksibuUEbJQIYT3by6wctQo+Rdlh7ef4evJ5NCdxY4CfMbvFkocEwbl4BF8RlJw==", + "dependencies": { + "@types/node": "16.9.1" + } + }, + "node_modules/image-q/node_modules/@types/node": { + "version": "16.9.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.9.1.tgz", + "integrity": "sha512-QpLcX9ZSsq3YYUUnD3nFDY8H7wctAhQj/TFKL8Ya8v5fMm3CFXxo8zStsLAl780ltoYoo1WvKUVGBQK+1ifr7g==" + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -787,6 +1318,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-function": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-function/-/is-function-1.0.2.tgz", + "integrity": "sha512-lw7DUp0aWXYg+CBCN+JKkcE0Q2RayZnSvnZBlwgxHBQhqt5pZNVy4Ri7H9GmmXkdu7LUthszM+Tor1u/2iBcpQ==" + }, "node_modules/is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", @@ -803,11 +1339,36 @@ "node": ">=8" } }, + "node_modules/isomorphic-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-3.0.0.tgz", + "integrity": "sha512-qvUtwJ3j6qwsF3jLxkZ72qCgjMysPzDfeV240JHiGZsANBYd+EEuu35v7dfrJ9Up0Ak07D7GGSkGhCHTqg/5wA==", + "dependencies": { + "node-fetch": "^2.6.1", + "whatwg-fetch": "^3.4.1" + } + }, "node_modules/isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==" }, + "node_modules/jimp": { + "version": "0.22.7", + "resolved": "https://registry.npmjs.org/jimp/-/jimp-0.22.7.tgz", + "integrity": "sha512-TJCTJ4ZcFUw6W8XZnR6ajdEu8vSyPi3AuoChs+zLHalXnhAPZgwkzwcXnxey4LNjh1p9dfIUkg8YSQ+q8pBW0A==", + "dependencies": { + "@jimp/custom": "^0.22.7", + "@jimp/plugins": "^0.22.7", + "@jimp/types": "^0.22.7", + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/jpeg-js": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.4.4.tgz", + "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==" + }, "node_modules/jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", @@ -851,6 +1412,21 @@ "marky": "^1.2.2" } }, + "node_modules/load-bmfont": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", + "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==", + "dependencies": { + "buffer-equal": "0.0.1", + "mime": "^1.3.4", + "parse-bmfont-ascii": "^1.0.3", + "parse-bmfont-binary": "^1.0.5", + "parse-bmfont-xml": "^1.1.4", + "phin": "^2.9.1", + "xhr": "^2.0.1", + "xtend": "^4.0.0" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", @@ -922,6 +1498,28 @@ "node": ">= 0.6" } }, + "node_modules/min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha512-9Wy1B3m3f66bPPmU5hdA4DR4PB2OfDU/+GS3yAB7IQozE3tqXaVv2zOjgla7MEGSRv95+ILmOuvhLkOK6wJtCQ==", + "dependencies": { + "dom-walk": "^0.1.0" + } + }, + "node_modules/mkdirp": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-2.1.5.tgz", + "integrity": "sha512-jbjfql+shJtAPrFoKxHOXip4xS+kul9W3OzfzzrqueWK2QMGon2bFH2opl6W9EagBThjEz+iysyi/swOoVfB/w==", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", @@ -935,6 +1533,25 @@ "node": ">= 0.6" } }, + "node_modules/node-fetch": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz", + "integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", @@ -951,6 +1568,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/omggif": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/omggif/-/omggif-1.0.10.tgz", + "integrity": "sha512-LMJTtvgc/nugXj0Vcrrs68Mn2D1r0zf630VNtqtpI1FEO7e+O9FP4gqs9AcnBaSEeoHIPm28u6qgPR0oyEpGSw==" + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -962,6 +1584,35 @@ "node": ">= 0.8" } }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parse-bmfont-ascii": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-ascii/-/parse-bmfont-ascii-1.0.6.tgz", + "integrity": "sha512-U4RrVsUFCleIOBsIGYOMKjn9PavsGOXxbvYGtMOEfnId0SVNsgehXh1DxUdVPLoxd5mvcEtvmKs2Mmf0Mpa1ZA==" + }, + "node_modules/parse-bmfont-binary": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/parse-bmfont-binary/-/parse-bmfont-binary-1.0.6.tgz", + "integrity": "sha512-GxmsRea0wdGdYthjuUeWTMWPqm2+FAd4GI8vCvhgJsFnoGhTrLhXDDupwTo7rXVAgaLIGoVHDZS9p/5XbSqeWA==" + }, + "node_modules/parse-bmfont-xml": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/parse-bmfont-xml/-/parse-bmfont-xml-1.1.4.tgz", + "integrity": "sha512-bjnliEOmGv3y1aMEfREMBJ9tfL3WR0i0CKPj61DnSLaoxWR3nLrsQrEbCId/8rF4NyRF0cCqisSVXyQYWM+mCQ==", + "dependencies": { + "xml-parse-from-string": "^1.0.0", + "xml2js": "^0.4.5" + } + }, + "node_modules/parse-headers": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.5.tgz", + "integrity": "sha512-ft3iAoLOB/MlwbNXgzy43SWGP6sQki2jQvAyBg/zDFAgr9bfNWZIUj42Kw2eJIl8kEi4PbgE6U1Zau/HwI75HA==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -975,11 +1626,63 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==" }, + "node_modules/phin": { + "version": "2.9.3", + "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", + "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==" + }, + "node_modules/pixelmatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", + "integrity": "sha512-J8B6xqiO37sU/gkcMglv6h5Jbd9xNER7aHzpfRdNmV4IbQBzBpe4l9XmbG+xPF/znacgu2jfEw+wHffaq/YkXA==", + "dependencies": { + "pngjs": "^3.0.0" + }, + "bin": { + "pixelmatch": "bin/pixelmatch" + } + }, + "node_modules/pixelmatch/node_modules/pngjs": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-3.4.0.tgz", + "integrity": "sha512-NCrCHhWmnQklfH4MtJMRjZ2a8c80qXeMlQMv2uVp9ISJMTt562SbGd6n2oq0PaPgKm7Z6pL9E2UlLIhC+SHL3w==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/pngjs": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-6.0.0.tgz", + "integrity": "sha512-TRzzuFRRmEoSW/p1KVAmiOgPco2Irlah+bGFCeNfJXxxYGwSw7YwAOAcd7X28K/m5bjBWKsC29KyoMfHbypayg==", + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/protobufjs": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.1.2.tgz", @@ -1129,6 +1832,34 @@ "node": ">= 0.8" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readable-web-to-node-stream": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.2.tgz", + "integrity": "sha512-ePeK6cc1EcKLEhJFt/AebMCLL+GgSKhuygrZ/GLaKZYEecIgIECf4UaUuaByiGtzckwR4ain9VzUh95T1exYGw==", + "dependencies": { + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/reduce-flatten": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/reduce-flatten/-/reduce-flatten-2.0.0.tgz", @@ -1137,6 +1868,11 @@ "node": ">=6" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==" + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -1254,6 +1990,11 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" + }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -1354,6 +2095,30 @@ "node": ">=0.10.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1395,6 +2160,16 @@ "node": ">=8" } }, + "node_modules/timm": { + "version": "1.7.1", + "resolved": "https://registry.npmjs.org/timm/-/timm-1.7.1.tgz", + "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==" + }, + "node_modules/tinycolor2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", + "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1403,6 +2178,22 @@ "node": ">=0.6" } }, + "node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, "node_modules/tough-cookie": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", @@ -1415,6 +2206,11 @@ "node": ">=0.8" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -1472,6 +2268,19 @@ "resolved": "https://registry.npmjs.org/urlsafe-base64/-/urlsafe-base64-1.0.0.tgz", "integrity": "sha512-RtuPeMy7c1UrHwproMZN9gN6kiZ0SvJwRaEzwZY0j9MypEkFqyBaKv176jvlPtg58Zh36bOkS0NFABXMHvvGCA==" }, + "node_modules/utif2": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/utif2/-/utif2-4.0.1.tgz", + "integrity": "sha512-KMaD76dbzK1VjbwsckHJiqDjhP3pbpwyV+FdqkY6XFQenc2o/HS6pjPSYdu4+NQMHf2NLTW+nVP/eFP1CvOYQQ==", + "dependencies": { + "pako": "^1.0.11" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -1509,6 +2318,25 @@ "extsprintf": "^1.2.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-fetch": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.2.tgz", + "integrity": "sha512-bJlen0FcuU/0EMLrdbJ7zOnW6ITZLrZMIarMUVmdKtsGvZna8vxKYaexICWPfZ8qwf9fzNq+UEIZrnSaApt6RA==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/wordwrapjs": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-4.0.1.tgz", @@ -1548,6 +2376,50 @@ "optional": true } } + }, + "node_modules/xhr": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", + "integrity": "sha512-/eCGLb5rxjx5e3mF1A7s+pLlR6CGyqWN91fv1JgER5mVWg1MZmlhBvy9kjcsOdRk8RrIujotWyJamfyrp+WIcA==", + "dependencies": { + "global": "~4.4.0", + "is-function": "^1.0.1", + "parse-headers": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/xml-parse-from-string": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz", + "integrity": "sha512-ErcKwJTF54uRzzNMXq2X5sMIy88zJvfN2DmdoQvy7PAFJ+tPRU6ydWuOKNMyfmOjdyBQTFREi60s0Y0SyI0G0g==" + }, + "node_modules/xml2js": { + "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } } } } diff --git a/package.json b/package.json index 3178985..a2be41a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@liamcottle/rustplus.js", - "version": "2.3.0", + "version": "2.3.1", "description": "Unofficial NodeJS library for controlling Smart Switches in the PC game Rust", "main": "rustplus.js", "bin": { @@ -34,6 +34,7 @@ "command-line-args": "^5.2.0", "command-line-usage": "^6.1.1", "express": "^4.17.1", + "jimp": "^0.22.7", "protobufjs": "^7.1.2", "push-receiver": "^2.1.0", "uuid": "^9.0.0", diff --git a/rustplus.js b/rustplus.js index 492d536..63c0991 100644 --- a/rustplus.js +++ b/rustplus.js @@ -4,6 +4,7 @@ const path = require('path'); const WebSocket = require('ws'); const protobuf = require("protobufjs"); const { EventEmitter } = require('events'); +const Camera = require('./camera'); class RustPlus extends EventEmitter { @@ -119,6 +120,14 @@ class RustPlus extends EventEmitter { } } + /** + * Check if RustPlus is connected to the server. + * @returns {boolean} + */ + isConnected() { + return this.websocket != null; + } + /** * Send a Request to the Rust Server with an optional callback when a Response is received. * @param data this should contain valid data for the AppRequest packet in the rustplus.proto schema file @@ -314,20 +323,59 @@ class RustPlus extends EventEmitter { } /** - * Get CCTV Camera frame - * @param identifier CCTV Camera Identifier, such as OILRIG1 (or custom name) - * @param frame integer that should be incremented for each frame request. Otherwise a cached frame is returned + * Subscribes to a Camera + * @param identifier Camera Identifier, such as OILRIG1 (or custom name) * @param callback */ - getCameraFrame(identifier, frame, callback) { + subscribeToCamera(identifier, callback) { this.sendRequest({ - getCameraFrame: { - identifier: identifier, - frame: frame, + cameraSubscribe: { + cameraId: identifier, }, }, callback); } + /** + * Unsubscribes from a Camera + * @param identifier Camera Identifier + * @param callback + */ + unsubscribeFromCamera(identifier, callback) { + this.sendRequest({ + cameraUnsubscribe: { + + } + }, callback) + } + + /** + * Sends camera input to the server (mouse movement) + * @param buttons The buttons that are currently pressed + * @param x The x delta of the mouse movement + * @param y The y delta of the mouse movement + * @param callback + */ + sendCameraInput(buttons, x, y, callback) { + this.sendRequest({ + cameraInput: { + buttons: buttons, + mouseDelta: { + x: x, + y: y, + } + }, + }, callback); + } + + /** + * Get a camera instance for controlling CCTV Cameras, PTZ Cameras and Auto Turrets + * @param identifier Camera Identifier, such as DOME1, OILRIG1L1, (or a custom camera id) + * @returns {Camera} + */ + getCamera(identifier) { + return new Camera(this, identifier); + } + } module.exports = RustPlus; diff --git a/rustplus.proto b/rustplus.proto index 6005c0c..d893865 100644 --- a/rustplus.proto +++ b/rustplus.proto @@ -1,7 +1,10 @@ syntax = "proto2"; package rustplus; -// This took me a while to craft by hand 😴 +message Vector2 { + optional float x = 1; + optional float y = 2; +} message Vector3 { optional float x = 1; @@ -9,17 +12,6 @@ message Vector3 { optional float z = 3; } -message Half3 { - optional uint32 x = 1; - optional uint32 y = 2; - optional uint32 z = 3; -} - -message Ray { - optional Vector3 origin = 1; - optional Vector3 direction = 2; -} - message Vector4 { optional float x = 1; optional float y = 2; @@ -27,6 +19,12 @@ message Vector4 { optional float w = 4; } +message Half3 { + optional float x = 1; + optional float y = 2; + optional float z = 3; +} + message Color { optional float r = 1; optional float g = 2; @@ -34,9 +32,9 @@ message Color { optional float a = 4; } -message Vector2 { - optional float x = 1; - optional float y = 2; +message Ray { + optional Vector3 origin = 1; + optional Vector3 direction = 2; } message ClanActionResult { @@ -47,7 +45,6 @@ message ClanActionResult { } message ClanInfo { - required int64 clanId = 1; required string name = 2; required int64 created = 3; @@ -60,7 +57,7 @@ message ClanInfo { repeated ClanInfo.Role roles = 10; repeated ClanInfo.Member members = 11; repeated ClanInfo.Invite invites = 12; - repeated int32 maxMemberCount = 13; + optional int32 maxMemberCount = 13; message Role { required int32 roleId = 1; @@ -90,11 +87,9 @@ message ClanInfo { required uint64 recruiter = 2; required int64 timestamp = 3; } - } message ClanLog { - required int64 clanId = 1; repeated ClanLog.Entry logEntries = 2; @@ -106,11 +101,9 @@ message ClanLog { optional string arg3 = 5; optional string arg4 = 6; } - } message ClanInvitations { - repeated ClanInvitations.Invitation invitations = 1; message Invitation { @@ -118,7 +111,6 @@ message ClanInvitations { required uint64 recruiter = 2; required int64 timestamp = 3; } - } enum AppEntityType { @@ -140,11 +132,9 @@ enum AppMarkerType { } message AppRequest { - required uint32 seq = 1; required uint64 playerId = 2; required int32 playerToken = 3; - optional uint32 entityId = 4; optional AppEmpty getInfo = 8; optional AppEmpty getTime = 9; @@ -163,7 +153,9 @@ message AppRequest { optional AppEmpty getClanChat = 23; optional AppSendMessage sendClanMessage = 24; optional AppGetNexusAuth getNexusAuth = 25; - + optional AppCameraSubscribe cameraSubscribe = 30; + optional AppEmpty cameraUnsubscribe = 31; + optional AppCameraInput cameraInput = 32; } message AppMessage { @@ -186,6 +178,7 @@ message AppResponse { optional AppClanInfo clanInfo = 15; optional AppClanChat clanChat = 16; optional AppNexusAuth nexusAuth = 17; + optional AppCameraInfo cameraSubscribeInfo = 20; } message AppBroadcast { @@ -194,10 +187,10 @@ message AppBroadcast { optional AppEntityChanged entityChanged = 6; optional AppClanChanged clanChanged = 7; optional AppNewClanMessage clanMessage = 8; + optional AppCameraRays cameraRays = 10; } message AppEmpty { - } message AppSendMessage { @@ -217,7 +210,6 @@ message AppGetNexusAuth { } message AppSuccess { - } message AppError { @@ -255,7 +247,6 @@ message AppTime { } message AppMap { - required uint32 width = 1; required uint32 height = 2; required bytes jpgImage = 3; @@ -268,7 +259,6 @@ message AppMap { required float x = 2; required float y = 3; } - } message AppEntityInfo { @@ -277,7 +267,6 @@ message AppEntityInfo { } message AppEntityPayload { - optional bool value = 1; repeated AppEntityPayload.Item items = 2; optional int32 capacity = 3; @@ -289,11 +278,9 @@ message AppEntityPayload { required int32 quantity = 2; required bool itemIsBlueprint = 3; } - } message AppTeamInfo { - required uint64 leaderSteamId = 1; repeated AppTeamInfo.Member members = 2; repeated AppTeamInfo.Note mapNotes = 3; @@ -315,7 +302,6 @@ message AppTeamInfo { required float x = 3; required float y = 4; } - } message AppTeamMessage { @@ -331,7 +317,6 @@ message AppTeamChat { } message AppMarker { - required uint32 id = 1; required AppMarkerType type = 2; required float x = 3; @@ -357,7 +342,6 @@ message AppMarker { optional float itemCondition = 8; optional float itemConditionMax = 9; } - } message AppMapMarkers { @@ -406,3 +390,42 @@ message AppNewClanMessage { required int64 clanId = 1; required AppClanMessage message = 2; } + +message AppCameraSubscribe { + required string cameraId = 1; +} + +message AppCameraInput { + required int32 buttons = 1; + required Vector2 mouseDelta = 2; +} + +message AppCameraInfo { + required int32 width = 1; + required int32 height = 2; + required float nearPlane = 3; + required float farPlane = 4; + required int32 controlFlags = 5; +} + +message AppCameraRays { + required float verticalFov = 1; + required int32 sampleOffset = 2; + required bytes rayData = 3; + required float distance = 4; + repeated AppCameraRays.Entity entities = 5; + + enum EntityType { + Tree = 1; + Player = 2; + } + + message Entity { + required uint32 entityId = 1; + required EntityType type = 2; + required Vector3 position = 3; + required Vector3 rotation = 4; + required Vector3 size = 5; + optional string name = 6; + } +}