@rustwirebot/rustplus.js 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +351 -0
  3. package/camera.js +425 -0
  4. package/cli/index.js +308 -0
  5. package/cli/pair.html +49 -0
  6. package/docs/API.md +101 -0
  7. package/docs/DownloadBundle.md +7 -0
  8. package/docs/PairingFlow.md +19 -0
  9. package/donate.md +10 -0
  10. package/examples/10_shoot_autoturret.js +100 -0
  11. package/examples/1_send_team_chat.js +16 -0
  12. package/examples/2_turn_smart_switch_on.js +21 -0
  13. package/examples/3_turn_smart_switch_off.js +21 -0
  14. package/examples/4_entity_changed_broadcasts.js +58 -0
  15. package/examples/5_download_map_jpeg.js +22 -0
  16. package/examples/6_async_requests.js +35 -0
  17. package/examples/7_render_camera.js +34 -0
  18. package/examples/8_move_ptz_camera.js +56 -0
  19. package/examples/9_zoom_ptz_camera.js +37 -0
  20. package/package.json +48 -0
  21. package/rustplus.js +380 -0
  22. package/rustplus.js.svg +34 -0
  23. package/rustplus.proto +431 -0
  24. package/vendor/push-receiver/LICENSE +21 -0
  25. package/vendor/push-receiver/NOTICE.md +32 -0
  26. package/vendor/push-receiver/android/fcm.js +134 -0
  27. package/vendor/push-receiver/client.js +216 -0
  28. package/vendor/push-receiver/constants.js +53 -0
  29. package/vendor/push-receiver/fcm/index.js +52 -0
  30. package/vendor/push-receiver/fcm/server-key/index.js +67 -0
  31. package/vendor/push-receiver/gcm/android_checkin.proto +96 -0
  32. package/vendor/push-receiver/gcm/checkin.proto +155 -0
  33. package/vendor/push-receiver/gcm/index.js +128 -0
  34. package/vendor/push-receiver/index.js +17 -0
  35. package/vendor/push-receiver/mcs.proto +328 -0
  36. package/vendor/push-receiver/parser.js +276 -0
  37. package/vendor/push-receiver/register/index.js +18 -0
  38. package/vendor/push-receiver/utils/base64/index.js +15 -0
  39. package/vendor/push-receiver/utils/decrypt/index.js +23 -0
  40. package/vendor/push-receiver/utils/http-request/index.js +43 -0
  41. package/vendor/push-receiver/utils/request/index.js +27 -0
  42. package/vendor/push-receiver/utils/timeout/index.js +7 -0
package/camera.js ADDED
@@ -0,0 +1,425 @@
1
+ "use strict";
2
+
3
+ const { EventEmitter } = require("events");
4
+ const Jimp = require("jimp");
5
+
6
+ class Camera extends EventEmitter {
7
+
8
+ /**
9
+ * These represent the possible buttons that can be sent to the server.
10
+ */
11
+ static Buttons = {
12
+ NONE: 0,
13
+ FORWARD: 2,
14
+ BACKWARD: 4,
15
+ LEFT: 8,
16
+ RIGHT: 16,
17
+ JUMP: 32,
18
+ DUCK: 64,
19
+ SPRINT: 128,
20
+ USE: 256,
21
+ FIRE_PRIMARY: 1024,
22
+ FIRE_SECONDARY: 2048,
23
+ RELOAD: 8192,
24
+ FIRE_THIRD: 134217728,
25
+ }
26
+
27
+ /**
28
+ * These represent the possible control flags that can be sent to the server.
29
+ * For example, Static CCTV cameras will not support movement.
30
+ */
31
+ static ControlFlags = {
32
+ NONE: 0,
33
+ MOVEMENT: 1,
34
+ MOUSE: 2,
35
+ SPRINT_AND_DUCK: 4,
36
+ FIRE: 8,
37
+ RELOAD: 16,
38
+ CROSSHAIR: 32,
39
+ }
40
+
41
+ /**
42
+ * @param rustplus An existing RustPlus instance
43
+ * @param identifier Camera Identifier, such as OILRIG1 (or custom name)
44
+ *
45
+ * Events emitted by the Camera class instance
46
+ * - subscribing: When we are subscribing to the Camera.
47
+ * - subscribed: When we are subscribed to the Camera.
48
+ * - unsubscribing: When we are unsubscribing from the Camera.
49
+ * - unsubscribed: When we are unsubscribed from the Camera.
50
+ * - render: When a camera frame has been rendered. A png image buffer will be provided.
51
+ */
52
+ constructor(rustplus, identifier) {
53
+
54
+ super();
55
+
56
+ this.rustplus = rustplus;
57
+ this.identifier = identifier;
58
+ this.isSubscribed = false;
59
+
60
+ this.cameraRays = [];
61
+ this.cameraSubscribeInfo = null;
62
+ this.subscribeInterval = null;
63
+
64
+ // listen to camera message broadcasts
65
+ this.rustplus.on('message', async (message) => {
66
+ await this._onMessage(message);
67
+ });
68
+
69
+ // unsubscribe when rustplus is disconnected (to prevent hanging due to intervals still running)
70
+ this.rustplus.on('disconnected', async () => {
71
+ if(this.isSubscribed){
72
+ await this.unsubscribe();
73
+ }
74
+ });
75
+
76
+ }
77
+
78
+ async _onMessage(message) {
79
+
80
+ // do nothing if not subscribed
81
+ if(!this.isSubscribed){
82
+ return;
83
+ }
84
+
85
+ if(message.broadcast && message.broadcast.cameraRays){
86
+ await this._onCameraRays(message.broadcast.cameraRays);
87
+ }
88
+
89
+ }
90
+
91
+ async _onCameraRays(cameraRays) {
92
+
93
+ // do nothing if not subscribed
94
+ if(!this.isSubscribed){
95
+ return;
96
+ }
97
+
98
+ // add new camera rays to cache
99
+ this.cameraRays.push(cameraRays);
100
+
101
+ // wait until we have enough camera rays to render an image
102
+ if(this.cameraRays.length > 10){
103
+
104
+ // remove first oldest rayData
105
+ this.cameraRays.shift();
106
+
107
+ // render to png
108
+ const frame = await this._renderCameraFrame(this.cameraRays, this.cameraSubscribeInfo.width, this.cameraSubscribeInfo.height);
109
+
110
+ // fire callback
111
+ await this._onRender(frame);
112
+
113
+ }
114
+
115
+ }
116
+
117
+ async _onRender(image) {
118
+
119
+ // do nothing if not subscribed
120
+ if(!this.isSubscribed){
121
+ return;
122
+ }
123
+
124
+ this.emit('render', image);
125
+
126
+ }
127
+
128
+ /**
129
+ * Render a camera frame to a PNG image buffer
130
+ * @param frames the frame data to render. This will be an array of camera rays from the server.
131
+ * @param width the width of the frame
132
+ * @param height the height of the frame
133
+ */
134
+ async _renderCameraFrame(frames, width, height) {
135
+
136
+ // First we populate the samplePositionBuffer with the positions of each sample
137
+ const samplePositionBuffer = new Int16Array(width * height * 2);
138
+ for (let w = 0, _ = 0; _ < height; _++)
139
+ for (let g = 0; g < width; g++) {
140
+ samplePositionBuffer[w] = g;
141
+ samplePositionBuffer[++w] = _;
142
+ w++;
143
+ }
144
+
145
+ for (let B = new IndexGenerator(1337), R = width * height - 1; R >= 1; R--) {
146
+ let C = 2 * R,
147
+ I = 2 * B.nextInt(R + 1),
148
+ P = samplePositionBuffer[C],
149
+ k = samplePositionBuffer[C + 1],
150
+ A = samplePositionBuffer[I],
151
+ F = samplePositionBuffer[I + 1];
152
+ samplePositionBuffer[I] = P;
153
+ samplePositionBuffer[I + 1] = k;
154
+ samplePositionBuffer[C] = A;
155
+ samplePositionBuffer[C + 1] = F;
156
+ }
157
+
158
+ // Create the output buffer
159
+ const output = new Array(width * height);
160
+ // Loop through each frame
161
+ for (let frame of frames) {
162
+
163
+ // Reset some look back and pointer variables
164
+ let sampleOffset = 2 * frame.sampleOffset;
165
+ let dataPointer = 0;
166
+ let rayLookback = new Array(64);
167
+ for (let r = 0; r < 64; r++) rayLookback[r] = [0, 0, 0];
168
+
169
+ const rayData = frame.rayData;
170
+
171
+ // Loop through the ray data
172
+ while (true) {
173
+ if (dataPointer >= rayData.length - 1)
174
+ break;
175
+
176
+ // Get the first byte and set some variables
177
+ let t, r, i, n = rayData[dataPointer++];
178
+
179
+ // Ray Decoding Logic
180
+ if (255 === n) {
181
+ let l = rayData[dataPointer++],
182
+ o = rayData[dataPointer++],
183
+ s = rayData[dataPointer++],
184
+ u = (3 * (((t = (l << 2) | (o >> 6)) / 128) | 0) + 5 * (((r = 63 & o) / 16) | 0) + 7 * (i = s)) & 63,
185
+ f = rayLookback[u];
186
+ f[0] = t;
187
+ f[1] = r;
188
+ f[2] = i;
189
+ } else {
190
+ let c = 192 & n;
191
+
192
+ if (0 === c) {
193
+ let h = 63 & n, y = rayLookback[h];
194
+ t = y[0];
195
+ r = y[1];
196
+ i = y[2];
197
+ } else if (64 === c) {
198
+ let p = 63 & n,
199
+ v = rayLookback[p],
200
+ b = v[0],
201
+ w = v[1],
202
+ _ = v[2],
203
+ g = rayData[dataPointer++];
204
+ t = b + ((g >> 3) - 15);
205
+ r = w + ((7 & g) - 3);
206
+ i = _;
207
+ } else if (128 === c) {
208
+ let R = 63 & n,
209
+ C = rayLookback[R],
210
+ I = C[0],
211
+ P = C[1],
212
+ k = C[2];
213
+ t = I + (rayData[dataPointer++] - 127);
214
+ r = P;
215
+ i = k;
216
+ } else {
217
+ let A = rayData[dataPointer++],
218
+ F = rayData[dataPointer++],
219
+ D = (3 * (((t = (A << 2) | (F >> 6)) / 128) | 0) + 5 * (((r = 63 & F) / 16) | 0) + 7 * (i = 63 & n)) & 63,
220
+ E = rayLookback[D];
221
+ E[0] = t;
222
+ E[1] = r;
223
+ E[2] = i;
224
+ }
225
+ }
226
+
227
+ sampleOffset %= 2 * width * height;
228
+ const index = samplePositionBuffer[sampleOffset++] + samplePositionBuffer[sampleOffset++] * width;
229
+ output[index] = [t / 1023, r / 63, i];
230
+ }
231
+ }
232
+
233
+ const colours = [
234
+ [0.5, 0.5, 0.5], [0.8, 0.7, 0.7], [0.3, 0.7, 1], [0.6, 0.6, 0.6],
235
+ [0.7, 0.7, 0.7], [0.8, 0.6, 0.4], [1, 0.4, 0.4], [1, 0.1, 0.1],
236
+ ];
237
+
238
+ const image = new Jimp(width, height);
239
+
240
+ for (let i = 0; i < output.length; i++) {
241
+ let ray = output[i];
242
+ if (!ray) {
243
+ continue;
244
+ }
245
+
246
+ let distance = ray[0]
247
+ let alignment = ray[1]
248
+ let material = ray[2]
249
+
250
+ let target_colour;
251
+
252
+ if (distance === 1 && alignment === 0 && material === 0) {
253
+ target_colour = [208, 230, 252];
254
+ } else {
255
+ let colour = colours[material];
256
+ target_colour = [(alignment * colour[0] * 255), (alignment * colour[1] * 255), (alignment * colour[2] * 255)]
257
+ }
258
+
259
+ let x = i % width;
260
+ let y = height - 1 - Math.floor(i / width);
261
+ image.setPixelColor(Jimp.rgbaToInt(target_colour[0], target_colour[1], target_colour[2], 255), x, y);
262
+ }
263
+
264
+ // return png buffer
265
+ return image.getBufferAsync(Jimp.MIME_PNG);
266
+
267
+ }
268
+
269
+ async _subscribe() {
270
+
271
+ // subscribe to camera
272
+ const response = await this.rustplus.sendRequestAsync({
273
+ cameraSubscribe: {
274
+ cameraId: this.identifier,
275
+ },
276
+ });
277
+
278
+ // update camera subscribe info
279
+ this.cameraSubscribeInfo = response.cameraSubscribeInfo;
280
+ this.isSubscribed = true;
281
+
282
+ }
283
+
284
+ async subscribe() {
285
+
286
+ this.emit('subscribing');
287
+
288
+ // subscribe to camera
289
+ await this._subscribe();
290
+
291
+ this.emit('subscribed');
292
+
293
+ // automatically resubscribe to the camera every 10 seconds
294
+ this.subscribeInterval = setInterval(async () => {
295
+ if(this.isSubscribed){
296
+ await this._subscribe();
297
+ }
298
+ }, 10_000);
299
+
300
+ }
301
+
302
+ async unsubscribe() {
303
+
304
+ this.emit('unsubscribing');
305
+
306
+ this.isSubscribed = false;
307
+
308
+ // stop automatically resubscribing
309
+ clearInterval(this.subscribeInterval);
310
+
311
+ // release memory
312
+ this.cameraRays = [];
313
+ this.cameraSubscribeInfo = null;
314
+ this.subscribeInterval = null;
315
+
316
+ // unsubscribe from camera on server (if connected)
317
+ if(this.rustplus.isConnected()){
318
+ try {
319
+ await this.rustplus.sendRequestAsync({
320
+ cameraUnsubscribe: {
321
+
322
+ },
323
+ });
324
+ } catch (error) {
325
+ // ignore errors unsubscribing from camera
326
+ }
327
+ }
328
+
329
+ this.emit('unsubscribed');
330
+
331
+ }
332
+
333
+ /**
334
+ * Sends camera movement to the server (mouse movement)
335
+ * @param buttons The buttons that are currently pressed
336
+ * @param x The x delta of the mouse movement
337
+ * @param y The y delta of the mouse movement
338
+ */
339
+ async move(buttons, x, y) {
340
+ return await this.rustplus.sendRequestAsync({
341
+ cameraInput: {
342
+ buttons: buttons,
343
+ mouseDelta: {
344
+ x: x,
345
+ y: y,
346
+ }
347
+ },
348
+ });
349
+ }
350
+
351
+ /**
352
+ * Zooms a PTZ camera in by 1 level.
353
+ * PTZ cameras have 4 zoom levels.
354
+ * If the PTZ camera is already at max zoom (level 4), it zooms out as far as it can (level 1).
355
+ */
356
+ async zoom() {
357
+
358
+ // press left mouse button to zoom in
359
+ await this.move(Camera.Buttons.FIRE_PRIMARY, 0, 0);
360
+
361
+ // release all mouse buttons
362
+ await this.move(Camera.Buttons.NONE, 0, 0);
363
+
364
+ }
365
+
366
+ /**
367
+ * Shoots a PTZ controllable Auto Turret.
368
+ */
369
+ async shoot() {
370
+
371
+ // press left mouse button to shoot
372
+ await this.move(Camera.Buttons.FIRE_PRIMARY, 0, 0);
373
+
374
+ // release all mouse buttons
375
+ await this.move(Camera.Buttons.NONE, 0, 0);
376
+
377
+ }
378
+
379
+ /**
380
+ * Reloads a PTZ controllable Auto Turret
381
+ */
382
+ async reload() {
383
+
384
+ // press reload button to reload turret
385
+ await this.move(Camera.Buttons.RELOAD, 0, 0);
386
+
387
+ // release all mouse buttons
388
+ await this.move(Camera.Buttons.NONE, 0, 0);
389
+
390
+ }
391
+
392
+ /**
393
+ * Check if camera is an auto turret
394
+ * @returns {boolean}
395
+ */
396
+ isAutoTurret() {
397
+ const crosshairControlFlag = Camera.ControlFlags.CROSSHAIR;
398
+ return (this.cameraSubscribeInfo?.controlFlags & crosshairControlFlag) === crosshairControlFlag;
399
+ }
400
+
401
+ }
402
+
403
+ class IndexGenerator {
404
+
405
+ constructor(e) {
406
+ this.state = 0 | e;
407
+ this.nextState();
408
+ }
409
+
410
+ nextInt(e) {
411
+ let t = ((this.nextState() * (0 | e)) / 4294967295) | 0;
412
+ if (t < 0) t = e + t - 1;
413
+ return 0 | t;
414
+ }
415
+
416
+ nextState() {
417
+ let e = this.state, t = e;
418
+ e = ((e = ((e = (e ^ ((e << 13) | 0)) | 0) ^ ((e >>> 17) | 0)) | 0) ^ ((e << 5) | 0)) | 0;
419
+ this.state = e;
420
+ return t >= 0 ? t : 4294967295 + t - 1;
421
+ }
422
+
423
+ }
424
+
425
+ module.exports = Camera;