ddbot.js-0374 3.2.7 → 4.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.
@@ -0,0 +1,78 @@
1
+ import BaseModule from '../core/module.js';
2
+ class PlayerList extends BaseModule {
3
+ constructor(bot) {
4
+ super(bot, { moduleName: 'PlayerList', offonDisconnect: false });
5
+ this.client = this.bot.bot_client;
6
+ }
7
+ client;
8
+ maxclients = 64;
9
+ playermap = new Map();
10
+ previousMap = new Map();
11
+ snapshotlistener = () => {
12
+ this.previousMap = new Map(this.playermap);
13
+ this.playermap.clear();
14
+ if (!this.client)
15
+ return;
16
+ for (let client_id = 0; client_id < this.maxclients; client_id++) {
17
+ const clientInfo = this.client.SnapshotUnpacker.getObjClientInfo(client_id);
18
+ const playerInfo = this.client.SnapshotUnpacker.getObjPlayerInfo(client_id);
19
+ const character = this.client.SnapshotUnpacker.getObjCharacter(client_id);
20
+ const DDNetCharacter = this.client.SnapshotUnpacker.getObjExDDNetCharacter(client_id);
21
+ if (clientInfo && playerInfo) {
22
+ const playerData = {
23
+ client_id,
24
+ clientInfo,
25
+ playerInfo,
26
+ character: character || null,
27
+ DDNetCharacter: DDNetCharacter || null,
28
+ };
29
+ this.playermap.set(client_id, playerData);
30
+ if (!this.previousMap.has(client_id)) {
31
+ this.emit('player_joined', {
32
+ client_id,
33
+ name: clientInfo.name,
34
+ playerData,
35
+ });
36
+ }
37
+ }
38
+ }
39
+ for (const [client_id, oldData] of this.previousMap) {
40
+ if (!this.playermap.has(client_id)) {
41
+ this.emit('player_left', {
42
+ client_id,
43
+ name: oldData.clientInfo.name,
44
+ playerData: oldData,
45
+ });
46
+ }
47
+ }
48
+ this.previousMap.clear();
49
+ };
50
+ /**
51
+ * Get list of all players
52
+ */
53
+ get list() {
54
+ return [...this.playermap];
55
+ }
56
+ /**
57
+ * Get player by ID
58
+ */
59
+ getPlayer(client_id) {
60
+ return this.playermap.get(client_id) || null;
61
+ }
62
+ /**
63
+ * Get number of online players
64
+ */
65
+ getPlayerCount() {
66
+ return this.playermap.size;
67
+ }
68
+ _start(maxclients = 64) {
69
+ this.maxclients = maxclients;
70
+ this.bot.on('snapshot', this.snapshotlistener);
71
+ }
72
+ _stop() {
73
+ this.bot.off('snapshot', this.snapshotlistener);
74
+ this.playermap.clear();
75
+ this.previousMap.clear();
76
+ }
77
+ }
78
+ export default PlayerList;
@@ -0,0 +1,14 @@
1
+ import BaseModule from '../core/module.js';
2
+ import type { Bot } from '../core/core.js';
3
+ declare class Reconnect extends BaseModule {
4
+ private maxAttempts;
5
+ private randomDelay;
6
+ private currentAttempts;
7
+ private reconnecting;
8
+ constructor(bot: Bot);
9
+ protected _start(maxAttempts?: number, randomDelay?: boolean): void;
10
+ private handleDisconnect;
11
+ private calculateDelay;
12
+ protected _stop(): void;
13
+ }
14
+ export default Reconnect;
@@ -0,0 +1,81 @@
1
+ import BaseModule from '../core/module.js';
2
+ import * as Types from '../types.js';
3
+ class Reconnect extends BaseModule {
4
+ maxAttempts = -1;
5
+ randomDelay = true;
6
+ currentAttempts = 0;
7
+ reconnecting = false;
8
+ constructor(bot) {
9
+ super(bot, { moduleName: 'Reconnect', offonDisconnect: false });
10
+ }
11
+ _start(maxAttempts = -1, randomDelay = true) {
12
+ this.maxAttempts = maxAttempts;
13
+ this.randomDelay = randomDelay;
14
+ this.bot.on('disconnect', this.handleDisconnect);
15
+ }
16
+ handleDisconnect = (reason, connectionInfo) => {
17
+ if (reason === null)
18
+ return;
19
+ if (this.reconnecting)
20
+ return;
21
+ if (!connectionInfo.addr || !connectionInfo.port) {
22
+ this.emit('reconnect_failed', 'No connection info');
23
+ return;
24
+ }
25
+ if (this.maxAttempts !== -1 && this.currentAttempts >= this.maxAttempts) {
26
+ this.emit('reconnect_failed', this.currentAttempts);
27
+ return;
28
+ }
29
+ const delay = this.calculateDelay(reason);
30
+ this.reconnecting = true;
31
+ this.currentAttempts++;
32
+ this.emit('reconnecting', {
33
+ attempt: this.currentAttempts,
34
+ delay,
35
+ reason,
36
+ addr: connectionInfo.addr,
37
+ port: connectionInfo.port,
38
+ });
39
+ setTimeout(async () => {
40
+ try {
41
+ await this.bot.connect(connectionInfo.addr, connectionInfo.port);
42
+ this.currentAttempts = 0;
43
+ this.emit('reconnected', {
44
+ addr: connectionInfo.addr,
45
+ port: connectionInfo.port
46
+ });
47
+ }
48
+ catch (err) {
49
+ this.emit('reconnect_failed', err);
50
+ }
51
+ finally {
52
+ this.reconnecting = false;
53
+ }
54
+ }, delay);
55
+ };
56
+ calculateDelay(reason) {
57
+ let baseDelay = 10000;
58
+ if (reason.startsWith('You have been banned for 5 minutes')) {
59
+ baseDelay = 300000;
60
+ }
61
+ else if (reason.startsWith('You have been banned')) {
62
+ baseDelay = 1000000;
63
+ }
64
+ else if (reason.startsWith('Too many connections')) {
65
+ baseDelay = 20000;
66
+ }
67
+ else if (reason.startsWith('Timed Out')) {
68
+ baseDelay = 500;
69
+ }
70
+ if (this.randomDelay) {
71
+ return baseDelay + Math.random() * 1000;
72
+ }
73
+ return baseDelay;
74
+ }
75
+ _stop() {
76
+ this.bot.off('disconnect', this.handleDisconnect);
77
+ this.reconnecting = false;
78
+ this.currentAttempts = 0;
79
+ }
80
+ }
81
+ export default Reconnect;
@@ -0,0 +1,17 @@
1
+ import BaseModule from '../core/module.js';
2
+ import type { Bot } from '../core/core.js';
3
+ import * as Types from '../types.js';
4
+ declare class Snap extends BaseModule {
5
+ private readonly hammerHitlistener;
6
+ private readonly firelistener;
7
+ constructor(bot: Bot);
8
+ private static areWithinTile;
9
+ private static whoareWithinTile;
10
+ static angleshot(character: Types.SnapshotItemTypes.Character): {
11
+ x: number;
12
+ y: number;
13
+ } | null;
14
+ protected _start(): void;
15
+ protected _stop(): void;
16
+ }
17
+ export default Snap;
@@ -0,0 +1,61 @@
1
+ import BaseModule from '../core/module.js';
2
+ import * as Types from '../types.js';
3
+ class Snap extends BaseModule {
4
+ hammerHitlistener = (hit) => {
5
+ if (this.bot.OwnID === undefined)
6
+ return;
7
+ const ownCharacter = this.bot.bot_client?.SnapshotUnpacker.getObjCharacter(this.bot.OwnID);
8
+ if (!ownCharacter)
9
+ return;
10
+ if (Snap.areWithinTile(hit.common.x, hit.common.y, ownCharacter.character_core.x, ownCharacter.character_core.y)) {
11
+ this.emit('hammerhitme', hit, Snap.whoareWithinTile(hit.common.x, hit.common.y, this.bot.bot_client?.SnapshotUnpacker.AllObjCharacter || [], [this.bot.OwnID]));
12
+ }
13
+ };
14
+ firelistener = (sound) => {
15
+ const list = this.bot.bot_client?.SnapshotUnpacker?.AllObjCharacter || [];
16
+ if (sound.sound_id === 0) {
17
+ this.emit('fire', { common: sound.common }, Snap.whoareWithinTile(sound.common.x, sound.common.y, list));
18
+ }
19
+ };
20
+ constructor(bot) {
21
+ super(bot, { moduleName: 'Snap', offonDisconnect: false });
22
+ }
23
+ static areWithinTile(x1, y1, x2, y2) {
24
+ const TILE = 32 * 1.1;
25
+ const distanceX = Math.abs(x1 - x2);
26
+ const distanceY = Math.abs(y1 - y2);
27
+ return distanceX <= TILE && distanceY <= TILE;
28
+ }
29
+ static whoareWithinTile(x, y, list, ignoreClients = []) {
30
+ for (const character of list) {
31
+ const character_core = character?.character_core;
32
+ if (!character_core)
33
+ continue;
34
+ if (Snap.areWithinTile(x, y, character_core.x, character_core.y)) {
35
+ if (!ignoreClients.includes(character.client_id)) {
36
+ return character.client_id;
37
+ }
38
+ }
39
+ }
40
+ return null;
41
+ }
42
+ static angleshot(character) {
43
+ if (!character || !character.character_core)
44
+ return null;
45
+ const client_angle = character.character_core.angle;
46
+ const angleRad = (client_angle / 256.0) * (Math.PI / 128.0);
47
+ return {
48
+ x: Math.cos(angleRad) * 256,
49
+ y: Math.sin(angleRad) * 256,
50
+ };
51
+ }
52
+ _start() {
53
+ this.bot.on('hammerhit', this.hammerHitlistener);
54
+ this.bot.on('sound_world', this.firelistener);
55
+ }
56
+ _stop() {
57
+ this.bot.off('hammerhit', this.hammerHitlistener);
58
+ this.bot.off('sound_world', this.firelistener);
59
+ }
60
+ }
61
+ export default Snap;
package/lib/types.d.ts ADDED
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Типы из библиотеки teeworlds
3
+ */
4
+ export declare namespace SnapshotItemTypes {
5
+ interface PlayerInput {
6
+ direction: number;
7
+ target_x: number;
8
+ target_y: number;
9
+ jump: number;
10
+ fire: number;
11
+ hook: number;
12
+ player_flags: number;
13
+ wanted_weapon: number;
14
+ next_weapon: number;
15
+ prev_weapon: number;
16
+ }
17
+ interface iOptions {
18
+ identity?: Identity;
19
+ password?: string;
20
+ ddnet_version?: {
21
+ version: number;
22
+ release_version: string;
23
+ };
24
+ timeout?: number;
25
+ NET_VERSION?: string;
26
+ lightweight?: boolean;
27
+ timeout_on_connecting?: boolean;
28
+ }
29
+ interface Projectile {
30
+ x: number;
31
+ y: number;
32
+ vel_x: number;
33
+ vel_y: number;
34
+ type_: number;
35
+ start_tick: number;
36
+ }
37
+ interface Laser {
38
+ x: number;
39
+ y: number;
40
+ from_x: number;
41
+ from_y: number;
42
+ start_tick: number;
43
+ }
44
+ interface Pickup {
45
+ x: number;
46
+ y: number;
47
+ type_: number;
48
+ subtype: number;
49
+ }
50
+ interface Flag {
51
+ x: number;
52
+ y: number;
53
+ team: number;
54
+ }
55
+ interface GameInfo {
56
+ game_flags: number;
57
+ game_state_flags: number;
58
+ round_start_tick: number;
59
+ warmup_timer: number;
60
+ score_limit: number;
61
+ time_limit: number;
62
+ round_num: number;
63
+ round_current: number;
64
+ }
65
+ interface GameData {
66
+ teamscore_red: number;
67
+ teamscore_blue: number;
68
+ flag_carrier_red: number;
69
+ flag_carrier_blue: number;
70
+ }
71
+ interface CharacterCore {
72
+ tick: number;
73
+ x: number;
74
+ y: number;
75
+ vel_x: number;
76
+ vel_y: number;
77
+ angle: number;
78
+ direction: number;
79
+ jumped: number;
80
+ hooked_player: number;
81
+ hook_state: number;
82
+ hook_tick: number;
83
+ hook_x: number;
84
+ hook_y: number;
85
+ hook_dx: number;
86
+ hook_dy: number;
87
+ }
88
+ interface Character {
89
+ character_core: CharacterCore;
90
+ player_flags: number;
91
+ health: number;
92
+ armor: number;
93
+ ammo_count: number;
94
+ weapon: number;
95
+ emote: number;
96
+ attack_tick: number;
97
+ client_id: number;
98
+ }
99
+ interface iMessage {
100
+ team: number;
101
+ client_id: number;
102
+ author?: {
103
+ ClientInfo?: ClientInfo;
104
+ PlayerInfo?: PlayerInfo;
105
+ };
106
+ message: string;
107
+ }
108
+ interface iEmoticon {
109
+ client_id: number;
110
+ emoticon: number;
111
+ author?: {
112
+ ClientInfo?: ClientInfo;
113
+ PlayerInfo?: PlayerInfo;
114
+ };
115
+ }
116
+ interface iKillMsg {
117
+ killer_id: number;
118
+ killer?: {
119
+ ClientInfo?: ClientInfo;
120
+ PlayerInfo?: PlayerInfo;
121
+ };
122
+ victim_id: number;
123
+ victim?: {
124
+ ClientInfo?: ClientInfo;
125
+ PlayerInfo?: PlayerInfo;
126
+ };
127
+ weapon: number;
128
+ special_mode: number;
129
+ }
130
+ interface iKillMsgTeam {
131
+ team: number;
132
+ first: number;
133
+ }
134
+ interface iMapChange {
135
+ map_name: string;
136
+ crc: number;
137
+ size: number;
138
+ }
139
+ interface PlayerInfo {
140
+ local: number;
141
+ client_id: number;
142
+ team: number;
143
+ score: number;
144
+ latency: number;
145
+ }
146
+ interface ClientInfo {
147
+ name: string;
148
+ clan: string;
149
+ country: number;
150
+ skin: string;
151
+ use_custom_color: number;
152
+ color_body: number;
153
+ color_feet: number;
154
+ id: number;
155
+ }
156
+ interface Identity {
157
+ name: string;
158
+ clan: string;
159
+ country: number;
160
+ skin: string;
161
+ use_custom_color: number;
162
+ color_body: number;
163
+ color_feet: number;
164
+ }
165
+ interface SpectatorInfo {
166
+ spectator_id: number;
167
+ x: number;
168
+ y: number;
169
+ }
170
+ interface Common {
171
+ x: number;
172
+ y: number;
173
+ }
174
+ interface Explosion {
175
+ common: Common;
176
+ }
177
+ interface Spawn {
178
+ common: Common;
179
+ }
180
+ interface HammerHit {
181
+ common: Common;
182
+ }
183
+ interface Death {
184
+ common: Common;
185
+ client_id: number;
186
+ }
187
+ interface SoundGlobal {
188
+ common: Common;
189
+ sound_id: number;
190
+ }
191
+ interface SoundWorld {
192
+ common: Common;
193
+ sound_id: number;
194
+ }
195
+ interface DamageInd {
196
+ common: Common;
197
+ angle: number;
198
+ }
199
+ interface MyOwnObject {
200
+ m_Test: number;
201
+ }
202
+ interface DDNetCharacter {
203
+ m_Flags: number;
204
+ m_FreezeEnd: number;
205
+ m_Jumps: number;
206
+ m_TeleCheckpoint: number;
207
+ m_StrongWeakID: number;
208
+ m_JumpedTotal?: number;
209
+ m_NinjaActivationTick?: number;
210
+ m_FreezeStart?: number;
211
+ m_TargetX?: number;
212
+ m_TargetY?: number;
213
+ id: number;
214
+ }
215
+ interface DDNetPlayer {
216
+ m_Flags: number;
217
+ m_AuthLevel: number;
218
+ id: number;
219
+ }
220
+ interface GameInfoEx {
221
+ m_Flags: number;
222
+ m_Version: number;
223
+ m_Flags2: number;
224
+ }
225
+ interface DDNetProjectile {
226
+ m_X: number;
227
+ m_Y: number;
228
+ m_Angle: number;
229
+ m_Data: number;
230
+ m_Type: number;
231
+ m_StartTick: number;
232
+ }
233
+ interface DDNetLaser {
234
+ m_ToX: number;
235
+ m_ToY: number;
236
+ m_FromX: number;
237
+ m_FromY: number;
238
+ m_StartTick: number;
239
+ m_Owner: number;
240
+ m_Type: number;
241
+ }
242
+ }
243
+ export type Item = SnapshotItemTypes.PlayerInput | SnapshotItemTypes.PlayerInfo | SnapshotItemTypes.Projectile | SnapshotItemTypes.Laser | SnapshotItemTypes.Pickup | SnapshotItemTypes.Flag | SnapshotItemTypes.GameInfo | SnapshotItemTypes.GameData | SnapshotItemTypes.CharacterCore | SnapshotItemTypes.Character | SnapshotItemTypes.ClientInfo | SnapshotItemTypes.SpectatorInfo | SnapshotItemTypes.Common | SnapshotItemTypes.Explosion | SnapshotItemTypes.Spawn | SnapshotItemTypes.HammerHit | SnapshotItemTypes.Death | SnapshotItemTypes.SoundGlobal | SnapshotItemTypes.SoundWorld | SnapshotItemTypes.DamageInd;
244
+ export type DDNetItem = SnapshotItemTypes.MyOwnObject | SnapshotItemTypes.DDNetCharacter | SnapshotItemTypes.DDNetPlayer | SnapshotItemTypes.GameInfoEx | SnapshotItemTypes.DDNetProjectile | SnapshotItemTypes.DDNetLaser;
245
+ export type DeltaItem = {
246
+ data: number[];
247
+ parsed: Item | DDNetItem;
248
+ type_id: number;
249
+ id: number;
250
+ key: number;
251
+ };
252
+ export interface ConnectionInfo {
253
+ addr: string;
254
+ port: number;
255
+ }
package/lib/types.js ADDED
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Типы из библиотеки teeworlds
3
+ */
4
+ export {};
package/package.json CHANGED
@@ -1,17 +1,12 @@
1
1
  {
2
2
  "dependencies": {
3
- "chalk": "^4.1.2",
4
- "loger0374": "^0.4.1",
5
3
  "teeworlds": "^2.5.11"
6
4
  },
7
5
  "name": "ddbot.js-0374",
8
- "version": "3.2.7",
6
+ "version": "4.0.0",
9
7
  "description": "ddbot.js — это Node.js проект для автоматизации и управления ботами.",
10
8
  "main": "./index.js",
11
- "scripts": {
12
- "start": "node ./docs/examples/main.js",
13
- "test": "node ./docs/examples/echo-bot.js"
14
- },
9
+ "scripts": {},
15
10
  "repository": {
16
11
  "type": "git",
17
12
  "url": "git+https://github.com/0374flop/ddbot.js.git"
@@ -26,10 +21,12 @@
26
21
  ],
27
22
  "author": "0374flop",
28
23
  "license": "MIT",
29
- "type": "commonjs",
24
+ "type": "module",
30
25
  "bugs": {
31
26
  "url": "https://github.com/0374flop/ddbot.js/issues"
32
27
  },
33
28
  "homepage": "https://github.com/0374flop/ddbot.js#readme",
34
- "types": "ddbot.js-0374.d.ts"
29
+ "devDependencies": {
30
+ "@types/node": "^25.2.3"
31
+ }
35
32
  }