@takaro/modules 0.0.30 → 0.1.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/dist/dto/gameEvents.d.ts +2 -6
  2. package/dist/dto/gameEvents.d.ts.map +1 -1
  3. package/dist/dto/gameEvents.js +10 -2
  4. package/dist/dto/gameEvents.js.map +1 -1
  5. package/dist/modules/dailyRewards/index.d.ts.map +1 -1
  6. package/dist/modules/dailyRewards/index.js +0 -1
  7. package/dist/modules/dailyRewards/index.js.map +1 -1
  8. package/dist/modules/geoBlock/index.d.ts.map +1 -1
  9. package/dist/modules/geoBlock/index.js +0 -2
  10. package/dist/modules/geoBlock/index.js.map +1 -1
  11. package/dist/modules/gimme/commands/gimme.js +1 -1
  12. package/dist/modules/gimme/commands/gimme.js.map +1 -1
  13. package/dist/modules/highPingKicker/cronJobs/Ping check.js +19 -14
  14. package/dist/modules/highPingKicker/cronJobs/Ping check.js.map +1 -1
  15. package/dist/modules/highPingKicker/index.js +1 -1
  16. package/dist/modules/playerOnboarding/commands/starterkit.js +2 -2
  17. package/dist/modules/playerOnboarding/commands/starterkit.js.map +1 -1
  18. package/dist/modules/teleports/commands/settp.js +1 -0
  19. package/dist/modules/teleports/commands/settp.js.map +1 -1
  20. package/dist/modules/teleports/commands/setwaypoint.js +1 -0
  21. package/dist/modules/teleports/commands/setwaypoint.js.map +1 -1
  22. package/dist/modules/teleports/commands/teleport.js +2 -0
  23. package/dist/modules/teleports/commands/teleport.js.map +1 -1
  24. package/dist/modules/teleports/commands/teleportwaypoint.js +1 -0
  25. package/dist/modules/teleports/commands/teleportwaypoint.js.map +1 -1
  26. package/dist/modules/teleports/index.js +1 -1
  27. package/dist/modules.json +9 -9
  28. package/package.json +1 -1
  29. package/src/__tests__/economy/claim.integration.test.ts +6 -6
  30. package/src/__tests__/economy/economyUtils.integration.test.ts +1 -1
  31. package/src/__tests__/highPingKicker.integration.test.ts +618 -0
  32. package/src/__tests__/modulePermission.integration.test.ts +14 -15
  33. package/src/__tests__/serverMessages.integration.test.ts +0 -1
  34. package/src/__tests__/teleports/listtp.integration.test.ts +0 -1
  35. package/src/__tests__/teleports/teleport.integration.test.ts +44 -0
  36. package/src/__tests__/teleports/waypoints.integration.test.ts +104 -27
  37. package/src/dto/gameEvents.ts +8 -8
  38. package/src/modules/dailyRewards/index.ts +0 -1
  39. package/src/modules/geoBlock/index.ts +0 -2
  40. package/src/modules/gimme/commands/gimme.js +1 -1
  41. package/src/modules/highPingKicker/cronJobs/Ping check.js +19 -17
  42. package/src/modules/highPingKicker/index.ts +1 -1
  43. package/src/modules/playerOnboarding/commands/starterkit.js +2 -2
  44. package/src/modules/teleports/commands/settp.js +2 -1
  45. package/src/modules/teleports/commands/setwaypoint.js +1 -0
  46. package/src/modules/teleports/commands/teleport.js +2 -0
  47. package/src/modules/teleports/commands/teleportwaypoint.js +1 -0
  48. package/src/modules/teleports/index.ts +1 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takaro/modules",
3
- "version": "0.0.30",
3
+ "version": "0.1.0",
4
4
  "description": "Built-in modules for Takaro",
5
5
  "main": "dist/main.js",
6
6
  "types": "dist/main.d.ts",
@@ -11,7 +11,7 @@ const tests = [
11
11
  setup: shopSetup,
12
12
  name: 'Can claim an order happy path',
13
13
  test: async function () {
14
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
14
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
15
15
  listingId: this.setupData.listing100.id,
16
16
  amount: 1,
17
17
  });
@@ -47,7 +47,7 @@ const tests = [
47
47
  setup: shopSetup,
48
48
  name: 'Handles double-claiming an order',
49
49
  test: async function () {
50
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
50
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
51
51
  listingId: this.setupData.listing100.id,
52
52
  amount: 1,
53
53
  });
@@ -76,11 +76,11 @@ const tests = [
76
76
  setup: shopSetup,
77
77
  name: 'Only claims the first order by default',
78
78
  test: async function () {
79
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
79
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
80
80
  listingId: this.setupData.listing100.id,
81
81
  amount: 1,
82
82
  });
83
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
83
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
84
84
  listingId: this.setupData.listing33.id,
85
85
  amount: 1,
86
86
  });
@@ -111,11 +111,11 @@ const tests = [
111
111
  setup: shopSetup,
112
112
  name: 'Can claim all orders in one go',
113
113
  test: async function () {
114
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
114
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
115
115
  listingId: this.setupData.listing100.id,
116
116
  amount: 1,
117
117
  });
118
- await this.setupData.userClient.shopOrder.shopOrderControllerCreate({
118
+ await this.setupData.client1.shopOrder.shopOrderControllerCreate({
119
119
  listingId: this.setupData.listing33.id,
120
120
  amount: 1,
121
121
  });
@@ -114,7 +114,7 @@ const tests = [
114
114
  expect((await events).length).to.be.eq(6);
115
115
  for (const message of messages) {
116
116
  expect(message).to.match(
117
- /(Richest players\:|1\. .+ - 4000 test coin|2\. .+ - 3000 test coin|3\. .+ - 2000 test coin|4\. .+ - 1000 test coin|5\. .+ - 0 test coin)/,
117
+ /(Richest players\:|1\. .+ - 9000 test coin|2\. .+ - 8000 test coin|3\. .+ - 7000 test coin|4\. .+ - 6000 test coin|5\. .+ - 5000 test coin)/,
118
118
  );
119
119
  }
120
120
  },
@@ -0,0 +1,618 @@
1
+ import { IntegrationTest, expect, IModuleTestsSetupData, modulesTestSetup, EventsAwaiter } from '@takaro/test';
2
+ import { GameEvents } from '../dto/index.js';
3
+ import { describe } from 'node:test';
4
+
5
+ const group = 'High Ping Kicker';
6
+
7
+ const tests = [
8
+ new IntegrationTest<IModuleTestsSetupData>({
9
+ group,
10
+ snapshot: false,
11
+ setup: modulesTestSetup,
12
+ name: 'Should warn players with high ping using default configuration',
13
+ test: async function () {
14
+ // Install module with default configuration (pingThreshold: 200, warningsBeforeKick: 3)
15
+ await this.client.module.moduleInstallationsControllerInstallModule({
16
+ gameServerId: this.setupData.gameserver.id,
17
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
18
+ });
19
+
20
+ // Set player ping to be above threshold
21
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
22
+ command: 'setPlayerData 0 {"ping": 250}',
23
+ });
24
+
25
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
26
+
27
+ // Trigger the cron job
28
+ await this.client.cronjob.cronJobControllerTrigger({
29
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
30
+ gameServerId: this.setupData.gameserver.id,
31
+ moduleId: this.setupData.highPingKickerModule.id,
32
+ });
33
+
34
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Wait for event processing
35
+
36
+ expect((await events).length).to.be.eq(1);
37
+ expect((await events)[0].data.meta.msg).to.match(/Your ping \(250\) is too high\. Warning 1\/3/);
38
+ },
39
+ }),
40
+
41
+ new IntegrationTest<IModuleTestsSetupData>({
42
+ group,
43
+ snapshot: false,
44
+ setup: modulesTestSetup,
45
+ name: 'Should kick player after reaching warning threshold',
46
+ test: async function () {
47
+ // Install module with default configuration
48
+ await this.client.module.moduleInstallationsControllerInstallModule({
49
+ gameServerId: this.setupData.gameserver.id,
50
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
51
+ });
52
+
53
+ // Set player ping to be above threshold
54
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
55
+ command: 'setPlayerData 0 {"ping": 300}',
56
+ });
57
+
58
+ // First warning
59
+ const events1 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
60
+ await this.client.cronjob.cronJobControllerTrigger({
61
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
62
+ gameServerId: this.setupData.gameserver.id,
63
+ moduleId: this.setupData.highPingKickerModule.id,
64
+ });
65
+ expect((await events1).length).to.be.eq(1);
66
+ expect((await events1)[0].data.meta.msg).to.match(/Your ping \(300\) is too high\. Warning 1\/3/);
67
+
68
+ // Second warning
69
+ const events2 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
70
+ await this.client.cronjob.cronJobControllerTrigger({
71
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
72
+ gameServerId: this.setupData.gameserver.id,
73
+ moduleId: this.setupData.highPingKickerModule.id,
74
+ });
75
+ expect((await events2).length).to.be.eq(1);
76
+ expect((await events2)[0].data.meta.msg).to.match(/Your ping \(300\) is too high\. Warning 2\/3/);
77
+
78
+ // Third warning should trigger kick
79
+ const kickEvent = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.PLAYER_DISCONNECTED);
80
+ await this.client.cronjob.cronJobControllerTrigger({
81
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
82
+ gameServerId: this.setupData.gameserver.id,
83
+ moduleId: this.setupData.highPingKickerModule.id,
84
+ });
85
+
86
+ expect((await kickEvent).length).to.be.eq(1);
87
+ },
88
+ }),
89
+
90
+ new IntegrationTest<IModuleTestsSetupData>({
91
+ group,
92
+ snapshot: false,
93
+ setup: modulesTestSetup,
94
+ name: 'Should respect custom configuration values',
95
+ test: async function () {
96
+ // Install module with custom configuration (lower threshold and fewer warnings)
97
+ await this.client.module.moduleInstallationsControllerInstallModule({
98
+ gameServerId: this.setupData.gameserver.id,
99
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
100
+ userConfig: JSON.stringify({
101
+ pingThreshold: 100,
102
+ warningsBeforeKick: 2,
103
+ }),
104
+ });
105
+
106
+ // Set player ping to be above custom threshold
107
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
108
+ command: 'setPlayerData 0 {"ping": 150}',
109
+ });
110
+
111
+ // First warning
112
+ const events1 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
113
+ await this.client.cronjob.cronJobControllerTrigger({
114
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
115
+ gameServerId: this.setupData.gameserver.id,
116
+ moduleId: this.setupData.highPingKickerModule.id,
117
+ });
118
+ expect((await events1).length).to.be.eq(1);
119
+ expect((await events1)[0].data.meta.msg).to.match(/Your ping \(150\) is too high\. Warning 1\/2/);
120
+
121
+ // Second warning should trigger kick
122
+ const kickEvent = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.PLAYER_DISCONNECTED);
123
+ await this.client.cronjob.cronJobControllerTrigger({
124
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
125
+ gameServerId: this.setupData.gameserver.id,
126
+ moduleId: this.setupData.highPingKickerModule.id,
127
+ });
128
+
129
+ expect((await kickEvent).length).to.be.eq(1);
130
+ },
131
+ }),
132
+
133
+ new IntegrationTest<IModuleTestsSetupData>({
134
+ group,
135
+ snapshot: false,
136
+ setup: modulesTestSetup,
137
+ name: 'Should not warn players with ping below threshold',
138
+ test: async function () {
139
+ // Install module with default configuration
140
+ await this.client.module.moduleInstallationsControllerInstallModule({
141
+ gameServerId: this.setupData.gameserver.id,
142
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
143
+ });
144
+
145
+ // Set player ping to be below threshold
146
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
147
+ command: 'setPlayerData 0 {"ping": 50}',
148
+ });
149
+
150
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 1);
151
+
152
+ // Trigger the cron job
153
+ await this.client.cronjob.cronJobControllerTrigger({
154
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
155
+ gameServerId: this.setupData.gameserver.id,
156
+ moduleId: this.setupData.highPingKickerModule.id,
157
+ });
158
+
159
+ // Should timeout without receiving any events
160
+ try {
161
+ await events;
162
+ expect.fail('Should not have received any warning messages');
163
+ } catch (error: any) {
164
+ // Expected timeout
165
+ expect(error.message).to.include('timed out');
166
+ }
167
+ },
168
+ }),
169
+
170
+ new IntegrationTest<IModuleTestsSetupData>({
171
+ group,
172
+ snapshot: false,
173
+ setup: modulesTestSetup,
174
+ name: 'Should handle multiple players with different ping values correctly',
175
+ test: async function () {
176
+ // Install module with default configuration
177
+ await this.client.module.moduleInstallationsControllerInstallModule({
178
+ gameServerId: this.setupData.gameserver.id,
179
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
180
+ });
181
+
182
+ // Set different ping values for different players
183
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
184
+ command: 'setPlayerData 0 {"ping": 250}',
185
+ });
186
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
187
+ command: 'setPlayerData 1 {"ping": 50}',
188
+ });
189
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
190
+ command: 'setPlayerData 2 {"ping": 300}',
191
+ });
192
+
193
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 2);
194
+
195
+ // Trigger the cron job
196
+ await this.client.cronjob.cronJobControllerTrigger({
197
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
198
+ gameServerId: this.setupData.gameserver.id,
199
+ moduleId: this.setupData.highPingKickerModule.id,
200
+ });
201
+
202
+ // Should receive warnings for players 0 and 2, but not player 1
203
+ const receivedEvents = await events;
204
+ expect(receivedEvents.length).to.be.eq(2);
205
+
206
+ const messages = receivedEvents.map((e) => e.data.meta.msg);
207
+ expect(messages).to.satisfy((msgs: string[]) => msgs.some((msg) => msg.includes('Your ping (250) is too high')));
208
+ expect(messages).to.satisfy((msgs: string[]) => msgs.some((msg) => msg.includes('Your ping (300) is too high')));
209
+ },
210
+ }),
211
+
212
+ new IntegrationTest<IModuleTestsSetupData>({
213
+ group,
214
+ snapshot: false,
215
+ setup: modulesTestSetup,
216
+ name: 'Should reset warnings after player is kicked',
217
+ test: async function () {
218
+ // Install module with configuration for quick kick (1 warning before kick)
219
+ await this.client.module.moduleInstallationsControllerInstallModule({
220
+ gameServerId: this.setupData.gameserver.id,
221
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
222
+ userConfig: JSON.stringify({
223
+ pingThreshold: 200,
224
+ warningsBeforeKick: 1,
225
+ }),
226
+ });
227
+
228
+ // Set player ping to be above threshold
229
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
230
+ command: 'setPlayerData 0 {"ping": 250}',
231
+ });
232
+
233
+ // First trigger should kick the player
234
+ const kickEvent = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.PLAYER_DISCONNECTED);
235
+ await this.client.cronjob.cronJobControllerTrigger({
236
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
237
+ gameServerId: this.setupData.gameserver.id,
238
+ moduleId: this.setupData.highPingKickerModule.id,
239
+ });
240
+ expect((await kickEvent).length).to.be.eq(1);
241
+
242
+ // Reconnect the player by setting online status
243
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
244
+ command: 'setPlayerData 0 {"online": true}',
245
+ });
246
+
247
+ // Keep high ping
248
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
249
+ command: 'setPlayerData 0 {"ping": 250}',
250
+ });
251
+
252
+ // Next trigger should kick again (warnings were reset)
253
+ const kickEvent2 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.PLAYER_DISCONNECTED);
254
+ await this.client.cronjob.cronJobControllerTrigger({
255
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
256
+ gameServerId: this.setupData.gameserver.id,
257
+ moduleId: this.setupData.highPingKickerModule.id,
258
+ });
259
+ expect((await kickEvent2).length).to.be.eq(1);
260
+ },
261
+ }),
262
+
263
+ new IntegrationTest<IModuleTestsSetupData>({
264
+ group,
265
+ snapshot: false,
266
+ setup: modulesTestSetup,
267
+ name: 'Should handle edge case of zero warnings before kick',
268
+ test: async function () {
269
+ // Install module with configuration for immediate kick (0 warnings)
270
+ await this.client.module.moduleInstallationsControllerInstallModule({
271
+ gameServerId: this.setupData.gameserver.id,
272
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
273
+ userConfig: JSON.stringify({
274
+ pingThreshold: 200,
275
+ warningsBeforeKick: 0,
276
+ }),
277
+ });
278
+
279
+ // Set player ping to be above threshold
280
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
281
+ command: 'setPlayerData 0 {"ping": 250}',
282
+ });
283
+
284
+ // Should immediately kick without warning
285
+ const kickEvent = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.PLAYER_DISCONNECTED);
286
+ await this.client.cronjob.cronJobControllerTrigger({
287
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
288
+ gameServerId: this.setupData.gameserver.id,
289
+ moduleId: this.setupData.highPingKickerModule.id,
290
+ });
291
+
292
+ expect((await kickEvent).length).to.be.eq(1);
293
+ },
294
+ }),
295
+ new IntegrationTest<IModuleTestsSetupData>({
296
+ group,
297
+ snapshot: false,
298
+ setup: modulesTestSetup,
299
+ name: 'Should handle ping exactly at threshold (boundary condition)',
300
+ test: async function () {
301
+ // Install module with default configuration
302
+ await this.client.module.moduleInstallationsControllerInstallModule({
303
+ gameServerId: this.setupData.gameserver.id,
304
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
305
+ });
306
+
307
+ // Set player ping exactly at threshold (should not trigger warning)
308
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
309
+ command: 'setPlayerData 0 {"ping": 200}',
310
+ });
311
+
312
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 1);
313
+
314
+ // Trigger the cron job
315
+ await this.client.cronjob.cronJobControllerTrigger({
316
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
317
+ gameServerId: this.setupData.gameserver.id,
318
+ moduleId: this.setupData.highPingKickerModule.id,
319
+ });
320
+
321
+ // Should timeout without receiving any events (ping = threshold should not warn)
322
+ try {
323
+ await events;
324
+ expect.fail('Should not have received any warning messages for ping exactly at threshold');
325
+ } catch (error: any) {
326
+ // Expected timeout
327
+ expect(error.message).to.include('timed out');
328
+ }
329
+ },
330
+ }),
331
+
332
+ new IntegrationTest<IModuleTestsSetupData>({
333
+ group,
334
+ snapshot: false,
335
+ setup: modulesTestSetup,
336
+ name: 'Should warn for ping just above threshold (boundary condition)',
337
+ test: async function () {
338
+ // Install module with default configuration
339
+ await this.client.module.moduleInstallationsControllerInstallModule({
340
+ gameServerId: this.setupData.gameserver.id,
341
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
342
+ });
343
+
344
+ // Set player ping just above threshold
345
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
346
+ command: 'setPlayerData 0 {"ping": 201}',
347
+ });
348
+
349
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
350
+
351
+ // Trigger the cron job
352
+ await this.client.cronjob.cronJobControllerTrigger({
353
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
354
+ gameServerId: this.setupData.gameserver.id,
355
+ moduleId: this.setupData.highPingKickerModule.id,
356
+ });
357
+
358
+ expect((await events).length).to.be.eq(1);
359
+ expect((await events)[0].data.meta.msg).to.match(/Your ping \(201\) is too high\. Warning 1\/3/);
360
+ },
361
+ }),
362
+
363
+ new IntegrationTest<IModuleTestsSetupData>({
364
+ group,
365
+ snapshot: false,
366
+ setup: modulesTestSetup,
367
+ name: 'Should handle very high ping values correctly',
368
+ test: async function () {
369
+ // Install module with default configuration
370
+ await this.client.module.moduleInstallationsControllerInstallModule({
371
+ gameServerId: this.setupData.gameserver.id,
372
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
373
+ });
374
+
375
+ // Set extremely high ping
376
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
377
+ command: 'setPlayerData 0 {"ping": 9999}',
378
+ });
379
+
380
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
381
+
382
+ // Trigger the cron job
383
+ await this.client.cronjob.cronJobControllerTrigger({
384
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
385
+ gameServerId: this.setupData.gameserver.id,
386
+ moduleId: this.setupData.highPingKickerModule.id,
387
+ });
388
+
389
+ expect((await events).length).to.be.eq(1);
390
+ expect((await events)[0].data.meta.msg).to.match(/Your ping \(9999\) is too high\. Warning 1\/3/);
391
+ },
392
+ }),
393
+
394
+ new IntegrationTest<IModuleTestsSetupData>({
395
+ group,
396
+ snapshot: false,
397
+ setup: modulesTestSetup,
398
+ name: 'Should handle offline players correctly',
399
+ test: async function () {
400
+ // Install module with default configuration
401
+ await this.client.module.moduleInstallationsControllerInstallModule({
402
+ gameServerId: this.setupData.gameserver.id,
403
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
404
+ });
405
+
406
+ // Set player offline but with high ping
407
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
408
+ command: 'setPlayerData 0 {"ping": 300, "online": false}',
409
+ });
410
+
411
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 1);
412
+
413
+ // Trigger the cron job
414
+ await this.client.cronjob.cronJobControllerTrigger({
415
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
416
+ gameServerId: this.setupData.gameserver.id,
417
+ moduleId: this.setupData.highPingKickerModule.id,
418
+ });
419
+
420
+ // Should timeout as offline players shouldn't be checked
421
+ try {
422
+ await events;
423
+ expect.fail('Should not have received any warning messages for offline players');
424
+ } catch (error: any) {
425
+ // Expected timeout
426
+ expect(error.message).to.include('timed out');
427
+ }
428
+ },
429
+ }),
430
+
431
+ new IntegrationTest<IModuleTestsSetupData>({
432
+ group,
433
+ snapshot: false,
434
+ setup: modulesTestSetup,
435
+ name: 'Should handle ping fluctuation correctly',
436
+ test: async function () {
437
+ // Install module with default configuration
438
+ await this.client.module.moduleInstallationsControllerInstallModule({
439
+ gameServerId: this.setupData.gameserver.id,
440
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
441
+ });
442
+
443
+ // Set high ping
444
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
445
+ command: 'setPlayerData 0 {"ping": 300}',
446
+ });
447
+
448
+ // First warning
449
+ const events1 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
450
+ await this.client.cronjob.cronJobControllerTrigger({
451
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
452
+ gameServerId: this.setupData.gameserver.id,
453
+ moduleId: this.setupData.highPingKickerModule.id,
454
+ });
455
+ expect((await events1).length).to.be.eq(1);
456
+
457
+ // Lower ping temporarily
458
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
459
+ command: 'setPlayerData 0 {"ping": 50}',
460
+ });
461
+
462
+ // Should not warn or kick
463
+ const events2 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 1);
464
+ await this.client.cronjob.cronJobControllerTrigger({
465
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
466
+ gameServerId: this.setupData.gameserver.id,
467
+ moduleId: this.setupData.highPingKickerModule.id,
468
+ });
469
+
470
+ try {
471
+ await events2;
472
+ expect.fail('Should not have received warning for good ping');
473
+ } catch (error: any) {
474
+ expect(error.message).to.include('timed out');
475
+ }
476
+
477
+ // Raise ping again
478
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
479
+ command: 'setPlayerData 0 {"ping": 350}',
480
+ });
481
+
482
+ // Should continue from previous warning count
483
+ const events3 = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
484
+ await this.client.cronjob.cronJobControllerTrigger({
485
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
486
+ gameServerId: this.setupData.gameserver.id,
487
+ moduleId: this.setupData.highPingKickerModule.id,
488
+ });
489
+ expect((await events3).length).to.be.eq(1);
490
+ expect((await events3)[0].data.meta.msg).to.match(/Warning 2\/3/);
491
+ },
492
+ }),
493
+
494
+ new IntegrationTest<IModuleTestsSetupData>({
495
+ group,
496
+ snapshot: false,
497
+ setup: modulesTestSetup,
498
+ name: 'Should handle extreme configuration values',
499
+ test: async function () {
500
+ // Install module with extreme configuration (very low threshold, high warning count)
501
+ await this.client.module.moduleInstallationsControllerInstallModule({
502
+ gameServerId: this.setupData.gameserver.id,
503
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
504
+ userConfig: JSON.stringify({
505
+ pingThreshold: 1,
506
+ warningsBeforeKick: 10,
507
+ }),
508
+ });
509
+
510
+ // Set moderate ping that would be above extremely low threshold
511
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
512
+ command: 'setPlayerData 0 {"ping": 50}',
513
+ });
514
+
515
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE);
516
+
517
+ // Trigger the cron job
518
+ await this.client.cronjob.cronJobControllerTrigger({
519
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
520
+ gameServerId: this.setupData.gameserver.id,
521
+ moduleId: this.setupData.highPingKickerModule.id,
522
+ });
523
+
524
+ expect((await events).length).to.be.eq(1);
525
+ expect((await events)[0].data.meta.msg).to.match(/Your ping \(50\) is too high\. Warning 1\/10/);
526
+ },
527
+ }),
528
+
529
+ new IntegrationTest<IModuleTestsSetupData>({
530
+ group,
531
+ snapshot: false,
532
+ setup: modulesTestSetup,
533
+ name: 'Should handle concurrent ping changes during warning period',
534
+ test: async function () {
535
+ // Install module with custom configuration
536
+ await this.client.module.moduleInstallationsControllerInstallModule({
537
+ gameServerId: this.setupData.gameserver.id,
538
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
539
+ userConfig: JSON.stringify({
540
+ pingThreshold: 200,
541
+ warningsBeforeKick: 2,
542
+ }),
543
+ });
544
+
545
+ // Set high ping for multiple players simultaneously
546
+ await Promise.all([
547
+ this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
548
+ command: 'setPlayerData 0 {"ping": 250}',
549
+ }),
550
+ this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
551
+ command: 'setPlayerData 1 {"ping": 260}',
552
+ }),
553
+ this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
554
+ command: 'setPlayerData 2 {"ping": 270}',
555
+ }),
556
+ ]);
557
+
558
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 3);
559
+
560
+ // Trigger the cron job
561
+ await this.client.cronjob.cronJobControllerTrigger({
562
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
563
+ gameServerId: this.setupData.gameserver.id,
564
+ moduleId: this.setupData.highPingKickerModule.id,
565
+ });
566
+
567
+ const receivedEvents = await events;
568
+ expect(receivedEvents.length).to.be.eq(3);
569
+
570
+ // All should get warning 1
571
+ receivedEvents.forEach((event) => {
572
+ expect(event.data.meta.msg).to.match(/Warning 1\/2/);
573
+ });
574
+ },
575
+ }),
576
+
577
+ new IntegrationTest<IModuleTestsSetupData>({
578
+ group,
579
+ snapshot: false,
580
+ setup: modulesTestSetup,
581
+ name: 'Should handle player with missing ping data gracefully',
582
+ test: async function () {
583
+ // Install module with default configuration
584
+ await this.client.module.moduleInstallationsControllerInstallModule({
585
+ gameServerId: this.setupData.gameserver.id,
586
+ versionId: this.setupData.highPingKickerModule.latestVersion.id,
587
+ });
588
+
589
+ // Don't set any ping data for player 0, but ensure they're online
590
+ await this.client.gameserver.gameServerControllerExecuteCommand(this.setupData.gameserver.id, {
591
+ command: 'setPlayerData 0 {"online": true}',
592
+ });
593
+
594
+ const events = (await new EventsAwaiter().connect(this.client)).waitForEvents(GameEvents.CHAT_MESSAGE, 1);
595
+
596
+ // Trigger the cron job
597
+ await this.client.cronjob.cronJobControllerTrigger({
598
+ cronjobId: this.setupData.highPingKickerModule.latestVersion.cronJobs[0].id,
599
+ gameServerId: this.setupData.gameserver.id,
600
+ moduleId: this.setupData.highPingKickerModule.id,
601
+ });
602
+
603
+ // Should timeout as undefined/null ping should not trigger warnings
604
+ try {
605
+ await events;
606
+ expect.fail('Should not have received warning for undefined ping');
607
+ } catch (error: any) {
608
+ expect(error.message).to.include('timed out');
609
+ }
610
+ },
611
+ }),
612
+ ];
613
+
614
+ describe(group, function () {
615
+ tests.forEach((test) => {
616
+ test.run();
617
+ });
618
+ });