vantiv.io 1.0.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 (48) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +864 -0
  3. package/index.js +13 -0
  4. package/package.json +28 -0
  5. package/src/classes/Actions/Awaiter.js +202 -0
  6. package/src/classes/Actions/Channel.js +73 -0
  7. package/src/classes/Actions/Direct.js +263 -0
  8. package/src/classes/Actions/Inventory.js +156 -0
  9. package/src/classes/Actions/Music.js +278 -0
  10. package/src/classes/Actions/Player.js +377 -0
  11. package/src/classes/Actions/Public.js +66 -0
  12. package/src/classes/Actions/Room.js +333 -0
  13. package/src/classes/Actions/Utils.js +29 -0
  14. package/src/classes/Actions/lib/AudioStreaming.js +447 -0
  15. package/src/classes/Caches/MovementCache.js +357 -0
  16. package/src/classes/Handlers/AxiosErrorHandler.js +68 -0
  17. package/src/classes/Handlers/ErrorHandler.js +65 -0
  18. package/src/classes/Handlers/EventHandlers.js +259 -0
  19. package/src/classes/Handlers/WebSocketHandlers.js +54 -0
  20. package/src/classes/Managers/ChannelManager.js +303 -0
  21. package/src/classes/Managers/DanceFloorManagers.js +509 -0
  22. package/src/classes/Managers/Helpers/CleanupManager.js +130 -0
  23. package/src/classes/Managers/Helpers/LoggerManager.js +171 -0
  24. package/src/classes/Managers/Helpers/MetricsManager.js +83 -0
  25. package/src/classes/Managers/Networking/ConnectionManager.js +259 -0
  26. package/src/classes/Managers/Networking/CooldownManager.js +516 -0
  27. package/src/classes/Managers/Networking/EventsManager.js +64 -0
  28. package/src/classes/Managers/Networking/KeepAliveManager.js +109 -0
  29. package/src/classes/Managers/Networking/MessageHandler.js +110 -0
  30. package/src/classes/Managers/Networking/Request.js +329 -0
  31. package/src/classes/Managers/PermissionManager.js +288 -0
  32. package/src/classes/WebApi/Category/Grab.js +98 -0
  33. package/src/classes/WebApi/Category/Item.js +347 -0
  34. package/src/classes/WebApi/Category/Post.js +154 -0
  35. package/src/classes/WebApi/Category/Room.js +137 -0
  36. package/src/classes/WebApi/Category/User.js +88 -0
  37. package/src/classes/WebApi/webapi.js +52 -0
  38. package/src/constants/TypesConstants.js +89 -0
  39. package/src/constants/WebSocketConstants.js +80 -0
  40. package/src/core/Highrise.js +123 -0
  41. package/src/core/HighriseWebsocket.js +228 -0
  42. package/src/utils/ConvertSvgToPng.js +51 -0
  43. package/src/utils/ModelPool.js +160 -0
  44. package/src/utils/Models.js +128 -0
  45. package/src/utils/versionCheck.js +27 -0
  46. package/src/validators/ConfigValidator.js +205 -0
  47. package/src/validators/ConnectionValidator.js +65 -0
  48. package/typings/index.d.ts +3820 -0
@@ -0,0 +1,357 @@
1
+ class MovementCache {
2
+ constructor() {
3
+ this._activeCache = new Map();
4
+ this._inactiveCache = new Map();
5
+ this._usernameToId = new Map();
6
+ this._changes = new Map();
7
+ this._inactiveThreshold = 30 * 1000;
8
+ this._cleanupInterval = setInterval(() => this._cleanInactive(), 30 * 1000);
9
+ }
10
+
11
+ _cleanInactive() {
12
+ const now = Date.now();
13
+
14
+ for (const [userId, data] of this._inactiveCache) {
15
+ if (now - data.lastSeen > this._inactiveThreshold) {
16
+ this._inactiveCache.delete(userId);
17
+ this._changes.delete(userId);
18
+ this._usernameToId.delete(data.username);
19
+ }
20
+ }
21
+
22
+ for (const [userId, data] of this._activeCache) {
23
+ if (now - data.lastSeen > this._inactiveThreshold) {
24
+ this._inactiveCache.set(userId, data);
25
+ this._activeCache.delete(userId);
26
+ this._changes.delete(userId);
27
+ }
28
+ }
29
+ }
30
+
31
+ _toUint8Array(position) {
32
+ const buffer = new Uint8Array(4);
33
+ buffer[0] = Math.round(position.x);
34
+ buffer[1] = Math.round(position.y);
35
+ buffer[2] = Math.round(position.z);
36
+ buffer[3] = this._facingToByte(position.facing);
37
+ return buffer;
38
+ }
39
+
40
+ _facingToByte(facing) {
41
+ const map = { 'FrontRight': 0, 'FrontLeft': 1, 'BackRight': 2, 'BackLeft': 3 };
42
+ return map[facing] || 0;
43
+ }
44
+
45
+ _byteToFacing(byte) {
46
+ const map = ['FrontRight', 'FrontLeft', 'BackRight', 'BackLeft'];
47
+ return map[byte] || 'FrontRight';
48
+ }
49
+
50
+ _fromUint8Array(buffer) {
51
+ return {
52
+ x: buffer[0],
53
+ y: buffer[1],
54
+ z: buffer[2],
55
+ facing: this._byteToFacing(buffer[3])
56
+ };
57
+ }
58
+
59
+ _hasPositionChanged(userId, newPosition) {
60
+ const oldData = this._activeCache.get(userId);
61
+ if (!oldData) return true;
62
+
63
+ const oldPos = this._fromUint8Array(oldData.position);
64
+ return oldPos.x !== newPosition.x || oldPos.y !== newPosition.y || oldPos.z !== newPosition.z || oldPos.facing !== newPosition.facing;
65
+ }
66
+
67
+ _update(userId, username, position, anchor = null) {
68
+ this._usernameToId.set(username, userId);
69
+
70
+ const hasChanged = this._hasPositionChanged(userId, position);
71
+
72
+ if (hasChanged) {
73
+ const cachedData = {
74
+ position: this._toUint8Array(position),
75
+ anchor: anchor ? { entity_id: anchor.entity_id, anchor_ix: anchor.anchor_ix } : null,
76
+ lastSeen: Date.now(),
77
+ username: username
78
+ };
79
+
80
+ this._activeCache.set(userId, cachedData);
81
+ this._changes.set(userId, cachedData);
82
+ this._inactiveCache.delete(userId);
83
+ return true;
84
+ } else {
85
+ const existing = this._activeCache.get(userId) || this._inactiveCache.get(userId);
86
+ if (existing) {
87
+ existing.lastSeen = Date.now();
88
+ } else {
89
+ this._inactiveCache.set(userId, {
90
+ position: this._toUint8Array(position),
91
+ anchor,
92
+ lastSeen: Date.now(),
93
+ username: username
94
+ });
95
+ }
96
+ return false;
97
+ }
98
+ }
99
+
100
+ _getById(userId) {
101
+ let data = this._activeCache.get(userId) || this._inactiveCache.get(userId);
102
+ if (data) {
103
+ return {
104
+ position: this._fromUint8Array(data.position),
105
+ anchor: data.anchor,
106
+ lastSeen: data.lastSeen,
107
+ username: data.username
108
+ };
109
+ }
110
+ return null;
111
+ }
112
+
113
+ getPlayersInSquare(center, sideLength) {
114
+ const halfSide = sideLength / 2;
115
+
116
+ return this.getPlayersInRectangle({
117
+ c1: { x: center.x - halfSide, z: center.z - halfSide },
118
+ c2: { x: center.x + halfSide, z: center.z - halfSide },
119
+ c3: { x: center.x + halfSide, z: center.z + halfSide },
120
+ c4: { x: center.x - halfSide, z: center.z + halfSide }
121
+ });
122
+ }
123
+
124
+ getPlayersInRectangle({ c1, c2, c3, c4 }) {
125
+ const playersInArea = [];
126
+
127
+ const allUsers = new Map([...this._activeCache, ...this._inactiveCache]);
128
+
129
+ for (const [userId, cachedData] of allUsers) {
130
+ const position = this._fromUint8Array(cachedData.position);
131
+
132
+ if (this._isPointInRectangle(position, { c1, c2, c3, c4 })) {
133
+ playersInArea.push({
134
+ user: {
135
+ id: userId,
136
+ username: cachedData.username
137
+ },
138
+ position: position,
139
+ anchor: cachedData.anchor,
140
+ lastSeen: cachedData.lastSeen
141
+ });
142
+ }
143
+ }
144
+
145
+ return playersInArea;
146
+ }
147
+
148
+ _isPointInRectangle(point, { c1, c2, c3, c4 }) {
149
+ const corners = [c1, c2, c3, c4];
150
+
151
+ let inside = false;
152
+ for (let i = 0, j = corners.length - 1; i < corners.length; j = i++) {
153
+ const xi = corners[i].x, zi = corners[i].z;
154
+ const xj = corners[j].x, zj = corners[j].z;
155
+
156
+ const intersect = ((zi > point.z) !== (zj > point.z)) &&
157
+ (point.x < (xj - xi) * (point.z - zi) / (zj - zi) + xi);
158
+
159
+ if (intersect) inside = !inside;
160
+ }
161
+
162
+ return inside;
163
+ }
164
+
165
+ getPlayersInCircle(center, radius) {
166
+ const playersInArea = [];
167
+ const radiusSquared = radius * radius;
168
+ const allUsers = this._activeCache.size + this._inactiveCache.size > 0 ?
169
+ new Map([...this._activeCache, ...this._inactiveCache]) : new Map();
170
+
171
+ if (allUsers.size === 0) return playersInArea;
172
+
173
+ for (const [userId, cachedData] of allUsers) {
174
+ const pos = this._fromUint8Array(cachedData.position);
175
+ const dx = pos.x - center.x;
176
+ const dz = pos.z - center.z;
177
+ const distSq = dx * dx + dz * dz;
178
+
179
+ if (distSq <= radiusSquared) {
180
+ const distance = Math.sqrt(distSq);
181
+ const roundedDistance = distance % 1 === 0 ? distance : Math.round(distance * 100) / 100;
182
+
183
+ playersInArea.push({
184
+ user: { id: userId, username: cachedData.username },
185
+ position: pos,
186
+ anchor: cachedData.anchor,
187
+ lastSeen: cachedData.lastSeen,
188
+ distance: roundedDistance
189
+ });
190
+ }
191
+ }
192
+
193
+ if (playersInArea.length > 1) {
194
+ playersInArea.sort((a, b) => a.distance - b.distance);
195
+ }
196
+
197
+ return playersInArea;
198
+ }
199
+
200
+ getPlayersInVerticalRange(minY, maxY) {
201
+ const playersInRange = [];
202
+ const allUsers = new Map([...this._activeCache, ...this._inactiveCache]);
203
+
204
+ for (const [userId, cachedData] of allUsers) {
205
+ const position = this._fromUint8Array(cachedData.position);
206
+
207
+ if (position.y >= minY && position.y <= maxY) {
208
+ playersInRange.push({
209
+ user: {
210
+ id: userId,
211
+ username: cachedData.username
212
+ },
213
+ position: position,
214
+ anchor: cachedData.anchor,
215
+ lastSeen: cachedData.lastSeen
216
+ });
217
+ }
218
+ }
219
+
220
+ return playersInRange;
221
+ }
222
+
223
+ getClosestPlayer(point) {
224
+ const allPlayers = this.getPlayersByDistance(point, Infinity);
225
+ return allPlayers.length > 0 ? allPlayers[0] : null;
226
+ }
227
+
228
+ getPlayersByDistance(point, maxDistance = Infinity) {
229
+ if (this._activeCache.size === 0 && this._inactiveCache.size === 0) {
230
+ return [];
231
+ }
232
+
233
+ const playersWithDistance = [];
234
+ const maxDistanceSq = maxDistance * maxDistance;
235
+
236
+ // Pre-calculate for performance
237
+ const pointX = point.x;
238
+ const pointZ = point.z;
239
+
240
+ // Check active cache first (most likely to be relevant)
241
+ for (const [userId, cachedData] of this._activeCache) {
242
+ const pos = this._fromUint8Array(cachedData.position);
243
+ const dx = pos.x - pointX;
244
+ const dz = pos.z - pointZ;
245
+ const distSq = dx * dx + dz * dz;
246
+
247
+ if (distSq <= maxDistanceSq) {
248
+ playersWithDistance.push({
249
+ user: { id: userId, username: cachedData.username },
250
+ position: pos,
251
+ anchor: cachedData.anchor,
252
+ lastSeen: cachedData.lastSeen,
253
+ distance: Math.sqrt(distSq)
254
+ });
255
+ }
256
+ }
257
+
258
+ for (const [userId, cachedData] of this._inactiveCache) {
259
+ const pos = this._fromUint8Array(cachedData.position);
260
+ const dx = pos.x - pointX;
261
+ const dz = pos.z - pointZ;
262
+ const distSq = dx * dx + dz * dz;
263
+
264
+ if (distSq <= maxDistanceSq) {
265
+ playersWithDistance.push({
266
+ user: { id: userId, username: cachedData.username },
267
+ position: pos,
268
+ anchor: cachedData.anchor,
269
+ lastSeen: cachedData.lastSeen,
270
+ distance: Math.sqrt(distSq)
271
+ });
272
+ }
273
+ }
274
+
275
+ if (playersWithDistance.length > 1) {
276
+ playersWithDistance.sort((a, b) => a.distance - b.distance);
277
+ }
278
+
279
+ return playersWithDistance;
280
+ }
281
+
282
+ isPlayerInSquare(userId, center, sideLength) {
283
+ const player = this._getById(userId);
284
+ if (!player) return false;
285
+
286
+ const halfSide = sideLength / 2;
287
+ const corners = {
288
+ c1: { x: center.x - halfSide, z: center.z - halfSide },
289
+ c2: { x: center.x + halfSide, z: center.z - halfSide },
290
+ c3: { x: center.x + halfSide, z: center.z + halfSide },
291
+ c4: { x: center.x - halfSide, z: center.z + halfSide }
292
+ };
293
+
294
+ return this._isPointInRectangle(player.position, corners);
295
+ }
296
+
297
+ isPlayerInRectangle(userId, corners) {
298
+ const player = this._getById(userId);
299
+ if (!player) return false;
300
+
301
+ return this._isPointInRectangle(player.position, corners);
302
+ }
303
+
304
+ getPlayerCountInSquare(center, sideLength) {
305
+ return this.getPlayersInSquare(center, sideLength).length;
306
+ }
307
+
308
+ getPlayerCountInRectangle(corners) {
309
+ return this.getPlayersInRectangle(corners).length;
310
+ }
311
+
312
+ _getByUsername(username) {
313
+ const userId = this._usernameToId.get(username);
314
+ return userId ? this._getById(userId) : null;
315
+ }
316
+
317
+ get(identifier) {
318
+ const byId = this._getById(identifier);
319
+ if (byId) return byId;
320
+ return this._getByUsername(identifier);
321
+ }
322
+
323
+ _remove(userId) {
324
+ const data = this._activeCache.get(userId) || this._inactiveCache.get(userId);
325
+ if (data) {
326
+ this._usernameToId.delete(data.username);
327
+ }
328
+ this._activeCache.delete(userId);
329
+ this._inactiveCache.delete(userId);
330
+ this._changes.delete(userId);
331
+ }
332
+
333
+ getStats() {
334
+ const activeUsers = this._activeCache.size;
335
+ const inactiveUsers = this._inactiveCache.size;
336
+ const memoryUsage = (activeUsers * 120) + (inactiveUsers * 80);
337
+
338
+ return {
339
+ activeUsers,
340
+ inactiveUsers,
341
+ memoryUsage,
342
+ changesProcessed: this._changes.size,
343
+ totalUsers: activeUsers + inactiveUsers
344
+ };
345
+ }
346
+
347
+ destroy() {
348
+ clearInterval(this._cleanupInterval);
349
+ this._activeCache.clear();
350
+ this._inactiveCache.clear();
351
+ this._usernameToId.clear();
352
+ this._changes.clear();
353
+ }
354
+ }
355
+
356
+ module.exports = { MovementCache }
357
+
@@ -0,0 +1,68 @@
1
+ class AxiosErrorHandler {
2
+ static handle(error, logger, method, context = {}) {
3
+ const errorInfo = {
4
+ ...context,
5
+ code: error.code,
6
+ message: error.message
7
+ }
8
+
9
+ if (error.response) {
10
+ errorInfo.status = error.response.status
11
+ errorInfo.statusText = error.response.statusText
12
+ errorInfo.data = error.response.data
13
+
14
+ switch (error.response.status) {
15
+ case 400:
16
+ logger.warn(method, `Bad Request`, errorInfo)
17
+ break
18
+ case 401:
19
+ logger.warn(method, `Unauthorized`, errorInfo)
20
+ break
21
+ case 403:
22
+ logger.warn(method, `Forbidden`, errorInfo)
23
+ break
24
+ case 404:
25
+ logger.warn(method, `Not Found`, errorInfo)
26
+ break
27
+ case 429:
28
+ logger.warn(method, `Rate Limited`, errorInfo)
29
+ break
30
+ case 500:
31
+ logger.error(method, `Server Error`, errorInfo)
32
+ break
33
+ case 502:
34
+ logger.error(method, `Bad Gateway`, errorInfo)
35
+ break
36
+ case 503:
37
+ logger.error(method, `Service Unavailable`, errorInfo)
38
+ break
39
+ default:
40
+ logger.error(method, `HTTP ${error.response.status}`, errorInfo)
41
+ }
42
+ } else if (error.request) {
43
+ logger.error(method, `Network Error - No response received`, errorInfo)
44
+ } else if (error.code === 'ECONNABORTED') {
45
+ logger.error(method, `Request Timeout`, errorInfo)
46
+ } else if (error.code === 'ENOTFOUND') {
47
+ logger.error(method, `DNS Lookup Failed`, errorInfo)
48
+ } else {
49
+ logger.error(method, `Unexpected Error`, errorInfo)
50
+ }
51
+
52
+ return null
53
+ }
54
+
55
+ static isNotFound(error) {
56
+ return error.response && error.response.status === 404
57
+ }
58
+
59
+ static isRateLimited(error) {
60
+ return error.response && error.response.status === 429
61
+ }
62
+
63
+ static isServerError(error) {
64
+ return error.response && error.response.status >= 500
65
+ }
66
+ }
67
+
68
+ module.exports = { AxiosErrorHandler }
@@ -0,0 +1,65 @@
1
+ class ErrorHandler {
2
+ static isConnectionError(error) {
3
+ const connectionErrors = [
4
+ 'ECONNREFUSED', 'ECONNRESET', 'EPIPE', 'ETIMEDOUT',
5
+ 'ENOTFOUND', 'EHOSTUNREACH', 'ENETUNREACH'
6
+ ];
7
+
8
+ return connectionErrors.includes(error.code);
9
+ }
10
+
11
+ static isWebSocketError(error) {
12
+ const wsErrors = [
13
+ 'is not connected',
14
+ 'WebSocket is not open',
15
+ 'readyState',
16
+ 'WebSocket'
17
+ ];
18
+
19
+ return wsErrors.some(msg => error.message.includes(msg));
20
+ }
21
+
22
+ static isRateLimitError(error) {
23
+ return error.response?.status === 429 ||
24
+ error.message?.includes('rate limit') ||
25
+ error.message?.includes('too many requests');
26
+ }
27
+
28
+ static createError(error, context = {}) {
29
+ const enhancedError = new Error(error.message || error);
30
+
31
+ enhancedError.timestamp = Date.now();
32
+ enhancedError.context = context;
33
+ enhancedError.originalError = error;
34
+ enhancedError.code = error.code;
35
+
36
+ if (error.response) {
37
+ enhancedError.status = error.response.status;
38
+ enhancedError.statusText = error.response.statusText;
39
+ enhancedError.data = error.response.data;
40
+ }
41
+
42
+ return enhancedError;
43
+ }
44
+
45
+ static shouldRetry(error, attempt, maxRetries) {
46
+ if (attempt >= maxRetries) return false;
47
+
48
+ // Don't retry these errors
49
+ if (error.code === 'ENOTFOUND') return false;
50
+ if (error.response?.status >= 400 && error.response?.status < 500) return false;
51
+
52
+ // Retry these errors
53
+ if (this.isConnectionError(error)) return true;
54
+ if (this.isRateLimitError(error)) return true;
55
+ if (error.response?.status >= 500) return true;
56
+
57
+ return false;
58
+ }
59
+
60
+ static getRetryDelay(attempt, baseDelay = 100) {
61
+ return Math.min(baseDelay * Math.pow(2, attempt), 5000);
62
+ }
63
+ }
64
+
65
+ module.exports = ErrorHandler;