Mervvebulx commited on
Commit
82dafb3
·
verified ·
1 Parent(s): 41d2fe1

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +133 -694
bot.js CHANGED
@@ -8,25 +8,15 @@ const config = require("./settings.json");
8
  const loggers = require("./logging.js");
9
  const logger = loggers.logger;
10
 
11
- // --- AYARLAR (Buradan hızlıca değiştirebilirsin) ---
12
- const HOME_ARRIVAL_DELAY_MS = 1500; // /home sonrası bekleme (ms)
13
- const POST_ACTION_DELAY_MS = 2500; // panel işlem sonrası kısa bekleme (ms)
14
- const WINDOW_OPEN_TIMEOUT_MS = 2600; // panel açılma timeout (ms)
15
-
16
- // Periyodik kontrol aralığı (50dk bekleme bittikten sonra bu aralıkla kontrol et)
17
- // Kullanıcı isteğine göre 10 dakika önerildi: 10 * 60 * 1000
18
  const PERIODIC_CHECK_INTERVAL_MS = 10 * 60 * 1000;
19
-
20
- // Eğer minyon canı 10 ise veya besleme yapıldıysa bekleme süresi (ms).
21
- // Varsayılan 50 dakika. İstersen süreyi değiştirmek için burayı düzenle.
22
  const FULL_FEED_COOLDOWN_MS = 50 * 60 * 1000;
23
-
24
  const GO_HOME_COMMAND = "/home";
25
  const RETURN_ISLAND_COMMAND = "/is home";
26
-
27
- // Besleyici isimleri (array). Birden fazla isim desteklenir.
28
  const BESLEYICI_NAMES = (config.utils && config.utils["besleyici-names"]) || ["Besleyici", "ʙᴇsʟᴇʏiᴄi"];
29
- // ------------------------------------------------
30
 
31
  function createBot() {
32
  const bot = mineflayer.createBot({
@@ -40,14 +30,27 @@ function createBot() {
40
 
41
  bot.loadPlugin(pathfinder);
42
 
43
- // --- Durum / zamanlayıcı değişkenleri ---
44
- // Son tam besleme (veya panelde can 10 görüldüğü zaman) zaman damgası (ms)
45
  let lastFullFeedAt = 0;
46
-
47
- // windowOpen bekleyici resolver listesi (mevcut mantığı korumak için)
48
  let windowOpenResolvers = [];
 
 
49
 
50
- // --- Yardımcı fonksiyonlar ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
51
  function stripColorCodes(s) {
52
  if (!s || typeof s !== "string") return s;
53
  return s.replace(/§[0-9a-fk-or]/gi, "");
@@ -91,93 +94,30 @@ function createBot() {
91
  let cur = obj;
92
  for (const p of pathArray) {
93
  if (cur == null) return undefined;
94
- if (typeof p === "number") {
95
- if (!Array.isArray(cur)) return undefined;
96
- cur = cur[p];
97
- } else {
98
- cur = cur[p];
99
- }
100
  }
101
  return cur;
102
- } catch (e) {
103
- return undefined;
104
- }
105
  }
106
 
107
- // Deep search sadece fallback olarak kullanılacak
108
  function deepSearchForString(root, targetLower) {
109
  const results = [];
110
  const visited = new WeakSet();
111
-
112
  function recurse(obj, path) {
113
- if (obj == null) return;
114
  if (typeof obj === "string") {
115
  const norm = normalizeForMatch(obj);
116
  if (norm.includes(targetLower)) results.push({ path, value: obj });
117
  return;
118
  }
119
- if (typeof obj !== "object") {
120
- try {
121
- const s = obj != null ? obj.toString() : "";
122
- if (typeof s === "string") {
123
- const norm = normalizeForMatch(s);
124
- if (norm.includes(targetLower)) results.push({ path, value: s });
125
- }
126
- } catch (e) {}
127
- return;
128
- }
129
  if (visited.has(obj)) return;
130
  visited.add(obj);
131
-
132
- if (obj.displayName && typeof obj.displayName.toString === "function") {
133
- try {
134
- const s = obj.displayName.toString();
135
- if (typeof s === "string") {
136
- const norm = normalizeForMatch(s);
137
- if (norm.includes(targetLower)) results.push({ path: path + ".displayName", value: s });
138
- }
139
- } catch (e) {}
140
- }
141
-
142
- if (Array.isArray(obj)) {
143
- for (let i = 0; i < obj.length; i++) recurse(obj[i], `${path}[${i}]`);
144
- return;
145
- }
146
-
147
- if (obj instanceof Map) {
148
- let idx = 0;
149
- for (const [k, v] of obj.entries()) {
150
- recurse(k, `${path}.MapKey(${idx})`);
151
- recurse(v, `${path}.MapValue(${idx})`);
152
- idx++;
153
- }
154
- return;
155
- }
156
-
157
  for (const key of Object.keys(obj)) {
158
- try {
159
- const val = obj[key];
160
- if (typeof val === "string") {
161
- const norm = normalizeForMatch(val);
162
- if (norm.includes(targetLower)) results.push({ path: `${path}.${key}`, value: val });
163
- } else if (val && typeof val === "object") {
164
- recurse(val, `${path}.${key}`);
165
- } else {
166
- try {
167
- const s = val != null ? val.toString() : "";
168
- if (typeof s === "string") {
169
- const norm = normalizeForMatch(s);
170
- if (norm.includes(targetLower)) results.push({ path: `${path}.${key}`, value: s });
171
- }
172
- } catch (e) {}
173
- }
174
- } catch (e) {}
175
  }
176
  }
177
-
178
- try {
179
- recurse(root, "root");
180
- } catch (e) {}
181
  return results;
182
  }
183
 
@@ -185,40 +125,15 @@ function createBot() {
185
  try {
186
  if (!titleObj) return "";
187
  if (typeof titleObj === "string") return titleObj;
188
- if (titleObj && typeof titleObj.toString === "function") {
189
- const s = titleObj.toString();
190
- if (s && s !== "[object Object]") return s;
191
- }
192
- if (typeof titleObj === "object") {
193
- if (typeof titleObj.text === "string" && titleObj.text.trim().length > 0) return titleObj.text;
194
- if (Array.isArray(titleObj.extra) && titleObj.extra.length > 0) {
195
- for (const e of titleObj.extra) {
196
- if (!e) continue;
197
- if (typeof e === "string" && e.trim()) return e;
198
- if (e && typeof e.text === "string" && e.text.trim()) return e.text;
199
- try {
200
- const s = e.toString();
201
- if (s && s !== "[object Object]") return s;
202
- } catch (e2) {}
203
- }
204
- }
205
- try {
206
- return JSON.stringify(titleObj);
207
- } catch (e) {
208
- return String(titleObj);
209
- }
210
- }
211
- return String(titleObj);
212
- } catch (err) {
213
- try { return String(titleObj); } catch (e) { return ""; }
214
- }
215
  }
216
 
217
- // --- Minyon canı çıkarma (geliştirilmiş, çeşitli yolları dener) ---
218
  function extractMinyonCanFromSlot(slot) {
219
  try {
220
  if (!slot) return null;
221
-
222
  function tryParseLoreText(text) {
223
  try {
224
  if (!text || typeof text !== "string") return null;
@@ -228,645 +143,169 @@ function createBot() {
228
  if (maybe && typeof maybe === "object") {
229
  if (maybe.extra && Array.isArray(maybe.extra) && maybe.extra.length > 0) {
230
  if (typeof maybe.extra[0].text === "string") plain = maybe.extra[0].text;
231
- else plain = JSON.stringify(maybe.extra);
232
  } else if (typeof maybe.text === "string") {
233
  plain = maybe.text;
234
- } else {
235
- plain = JSON.stringify(maybe);
236
  }
237
  }
238
  } catch (e) {}
239
  const xyMatch = plain.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
240
- if (xyMatch) {
241
- const x = Number(xyMatch[1]);
242
- if (!Number.isNaN(x)) return x;
243
- }
244
  const numMatch = plain.match(/(\d{1,4})/);
245
- if (numMatch) {
246
- const n = Number(numMatch[1]);
247
- if (!Number.isNaN(n)) return n;
248
- }
249
  return null;
250
- } catch (e) {
251
- return null;
252
- }
253
  }
254
-
255
- // 1) slot.nbt yolları
256
  if (slot.nbt) {
257
- try {
258
- const candidates = [
259
- ["value", "display", "value", "Lore", "value"],
260
- ["value", "display", "value", "Lore"],
261
- ["value", "display", "value"],
262
- ];
263
- for (const path of candidates) {
264
- let cur = slot.nbt;
265
- let ok = true;
266
- for (const p of path) {
267
- if (cur == null) { ok = false; break; }
268
- cur = cur[p];
269
- }
270
- if (!ok) continue;
271
- if (Array.isArray(cur) && cur.length > 0) {
272
- const tryIndices = [1, cur.length - 1, 0];
273
- for (const idx of tryIndices) {
274
- const item = cur[idx];
275
- if (!item) continue;
276
- if (typeof item === "string") {
277
- const parsed = tryParseLoreText(item);
278
- if (parsed != null) return parsed;
279
- }
280
- if (item && typeof item.value === "string") {
281
- const parsed = tryParseLoreText(item.value);
282
- if (parsed != null) return parsed;
283
- }
284
- try {
285
- const s = item.toString();
286
- const parsed = tryParseLoreText(s);
287
- if (parsed != null) return parsed;
288
- } catch (e) {}
289
- }
290
- } else if (typeof cur === "string") {
291
- const parsed = tryParseLoreText(cur);
292
- if (parsed != null) return parsed;
293
- } else if (cur && typeof cur.toString === "function") {
294
- const parsed = tryParseLoreText(cur.toString());
295
- if (parsed != null) return parsed;
296
- }
297
- }
298
- } catch (e) {}
299
- }
300
-
301
- // 2) components içinde custom_data veya lore
302
- try {
303
- if (Array.isArray(slot.components)) {
304
- for (const c of slot.components) {
305
- if (!c) continue;
306
- if (c.type === "custom_data" && c.data && c.data.value && c.data.value.display && c.data.value.display.value && c.data.value.display.value.Lore) {
307
- const loreObj = c.data.value.display.value.Lore;
308
- if (loreObj && loreObj.value && Array.isArray(loreObj.value)) {
309
- for (const s of loreObj.value) {
310
- const parsed = tryParseLoreText(String(s));
311
- if (parsed != null) return parsed;
312
- }
313
- } else if (typeof loreObj === "string") {
314
- const parsed = tryParseLoreText(loreObj);
315
- if (parsed != null) return parsed;
316
- }
317
- }
318
- if (c.type === "lore" && Array.isArray(c.data)) {
319
- for (const entry of c.data) {
320
- const text = safeGet(entry, ["value", "text", "value"]) || safeGet(entry, ["value", "extra", "value", 0, "value", "text", "value"]) || (entry && entry.toString && entry.toString());
321
- const parsed = tryParseLoreText(String(text || ""));
322
- if (parsed != null) return parsed;
323
- }
324
- }
325
- }
326
- }
327
- } catch (e) {}
328
-
329
- // 3) componentMap kontrolü
330
- try {
331
- if (slot.componentMap && typeof slot.componentMap === "object") {
332
- const getFromMap = (m, key) => {
333
- try {
334
- if (m.get) return m.get(key);
335
- return m[key];
336
- } catch (e) { return null; }
337
- };
338
- const loreComp = getFromMap(slot.componentMap, "custom_data") || getFromMap(slot.componentMap, "lore");
339
- if (loreComp) {
340
- const data = loreComp.data || loreComp;
341
- if (Array.isArray(data)) {
342
- for (const entry of data) {
343
- const text = safeGet(entry, ["value", "text", "value"]) || entry.toString?.();
344
- const parsed = tryParseLoreText(String(text || ""));
345
- if (parsed != null) return parsed;
346
- }
347
- } else if (data && data.value && Array.isArray(data.value)) {
348
- for (const item of data.value) {
349
- const text = safeGet(item, ["value", "text", "value"]) || item.toString?.();
350
- const parsed = tryParseLoreText(String(text || ""));
351
- if (parsed != null) return parsed;
352
- }
353
- }
354
  }
355
  }
356
- } catch (e) {}
357
-
358
- // 4) fallback: inspect tüm slot
359
- try {
360
- const full = util.inspect(slot, { depth: null, maxArrayLength: null });
361
- const xyMatch = full.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
362
- if (xyMatch) return Number(xyMatch[1]);
363
- const numMatch = full.match(/(\d{1,4})/);
364
- if (numMatch) return Number(numMatch[1]);
365
- } catch (e) {}
366
-
367
- return null;
368
- } catch (err) {
369
- logger.warn("extractMinyonCanFromSlot hata: " + (err && err.message ? err.message : err));
370
- return null;
371
- }
372
- }
373
-
374
- // --- Activate API detection (startup) ---
375
- let hasActivateAt = false;
376
- let hasActivate = false;
377
- function detectActivateApis() {
378
- hasActivateAt = typeof bot.activateEntityAt === "function";
379
- hasActivate = typeof bot.activateEntity === "function";
380
- }
381
-
382
- // safe activate: prefer activateEntityAt, minimal logging
383
- async function safeActivateEntityPreferAt(entity, options = {}) {
384
- const maxRetries = options.maxRetries ?? 3;
385
- const retryDelay = options.retryDelay ?? 250;
386
- const requireLook = options.requireLook ?? true;
387
- const maxDistance = options.maxDistance ?? 7;
388
-
389
- if (!entity) {
390
- logger.warn("safeActivateEntityPreferAt: entity yok");
391
- return false;
392
- }
393
-
394
- try {
395
- if (entity.position && bot.entity && bot.entity.position) {
396
- const dist = entity.position.distanceTo(bot.entity.position);
397
- if (dist > maxDistance) {
398
- logger.warn(`safeActivateEntityPreferAt: entity id:${entity.id} uzak (${dist.toFixed(2)}). Max ${maxDistance} blok.`);
399
- return false;
400
- }
401
- }
402
-
403
- if (requireLook && entity.position && bot.lookAt) {
404
- try {
405
- const lookPos = (typeof entity.position.offset === "function")
406
- ? entity.position.offset(0, 1.5, 0)
407
- : { x: entity.position.x, y: entity.position.y + 1.5, z: entity.position.z };
408
- await bot.lookAt(lookPos, true);
409
- await new Promise(r => setTimeout(r, 180));
410
- } catch (e) {}
411
  }
412
-
413
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
414
- try {
415
- if (hasActivateAt) {
416
- try {
417
- bot.activateEntityAt(entity, entity.position);
418
- logger.info(`activateEntityAt çağrıldı id:${entity.id}`);
419
- return true;
420
- } catch (err) {
421
- // retry silently
422
- }
423
- }
424
- if (hasActivate) {
425
- try {
426
- bot.activateEntity(entity);
427
- logger.info(`activateEntity çağrıldı id:${entity.id}`);
428
- return true;
429
- } catch (err) {
430
- // retry silently
431
- }
432
- }
433
- } catch (err) {
434
- // swallow and retry
435
- }
436
- await new Promise(r => setTimeout(r, retryDelay));
437
- }
438
-
439
- logger.warn(`safeActivateEntityPreferAt: tüm denemeler başarısız id:${entity.id}`);
440
- return false;
441
- } catch (err) {
442
- logger.error(`safeActivateEntityPreferAt hata: ${err && err.stack ? err.stack : err}`);
443
- return false;
444
- }
445
  }
446
 
447
- // windowOpen wait helper (mevcut resolver mantığını koruyor)
448
- function waitForWindowOpenOrTimeout(timeoutMs) {
449
- return new Promise((resolve) => {
450
- try {
451
- if (bot.currentWindow && bot.currentWindow.type) {
452
- resolve({ opened: true });
453
- return;
454
- }
455
- } catch (e) {}
456
-
457
- const timer = setTimeout(() => {
458
- const idx = windowOpenResolvers.indexOf(resolver);
459
- if (idx !== -1) windowOpenResolvers.splice(idx, 1);
460
- resolve({ opened: false, timedOut: true });
461
- }, timeoutMs);
462
-
463
- function resolver() {
464
- clearTimeout(timer);
465
- resolve({ opened: true, timedOut: false });
466
- }
467
-
468
- windowOpenResolvers.push(resolver);
469
- });
470
- }
471
-
472
- // --- GO / SCAN / RETURN helpers ---
473
  async function goHome() {
474
- try {
475
- logger.info(`[${config["bot-account"]["username"]}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
476
- bot.chat(GO_HOME_COMMAND);
477
- } catch (e) {
478
- logger.warn("goHome: komut gönderilemedi: " + (e && e.message ? e.message : e));
479
- }
480
  }
481
 
482
  async function returnIsland() {
483
- try {
484
- bot.chat(RETURN_ISLAND_COMMAND);
485
- } catch (e) {
486
- logger.warn("returnIsland: komut gönderilemedi: " + (e && e.message ? e.message : e));
487
- }
488
  }
489
 
490
- // Scan & feed mantığı (aynı işleyiş korunuyor)
491
  async function scanAndFeed() {
492
- try {
493
- // Eğer son tam beslemeden (veya can 10 görüldüğünden) henüz FULL_FEED_COOLDOWN_MS geçmediyse atla
494
- if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) {
495
- // sessizce atla; log spam olmasın
496
- return;
497
- }
498
-
499
- const arr = Object.values(bot.entities);
500
- if (!arr || arr.length === 0) {
501
- logger.info(`[${config["bot-account"]["username"]}] /home sonrası: entity bulunamadı.`);
502
- return;
503
- }
504
-
505
- // 1) quick checks
506
- let found = null;
507
- let foundPath = null;
508
- for (const e of arr) {
509
- const name = getEntityReadableName(e);
510
- if (isBesleyiciName(name)) {
511
- found = e;
512
- foundPath = "displayName/name";
513
  break;
514
  }
515
  }
 
 
516
 
517
- // 2) metadata quick path
518
- if (!found) {
519
- for (const e of arr) {
520
- const candidate = safeGet(e, ["metadata", 2, "value", "extra", "value", "value", 0]);
521
- if (candidate) {
522
- let candidateStr = null;
523
- try {
524
- if (typeof candidate === "string") candidateStr = candidate;
525
- else if (candidate && typeof candidate.toString === "function") candidateStr = candidate.toString();
526
- else candidateStr = util.inspect(candidate, { depth: 1 });
527
- } catch (err) {
528
- candidateStr = String(candidate);
529
- }
530
- if (TARGET_NAME_NORMS.some(t => normalizeForMatch(candidateStr).includes(t))) {
531
- found = e;
532
- foundPath = "metadata[2].value.extra.value.value[0]";
533
- break;
534
- }
535
- }
536
- }
537
- }
538
-
539
- // 3) deep search only if still not found
540
- if (!found) {
541
- for (const e of arr) {
542
- const matches = deepSearchForString(e, TARGET_NAME_NORMS[0]);
543
- if (matches && matches.length > 0) {
544
- found = e;
545
- foundPath = matches[0].path;
546
- break;
547
- }
548
- }
549
- }
550
-
551
- if (!found) {
552
- logger.info(`[${config["bot-account"]["username"]}] /home sonrası tarama: besleyici minyon bulunamadı.`);
553
- return;
554
- }
555
-
556
- const readable = getEntityReadableName(found);
557
- const dist = (found.position && bot.entity && bot.entity.position) ? found.position.distanceTo(bot.entity.position).toFixed(2) : "n/a";
558
- logger.info(`[${config["bot-account"]["username"]}] '${readable || BESLEYICI_NAMES[0]}' bulundu id:${found.id} path:${foundPath} dist:${dist} — aktive ediliyor.`);
559
 
560
- detectActivateApis();
 
 
561
 
562
- const activated = await safeActivateEntityPreferAt(found, { maxRetries: 4, retryDelay: 300, requireLook: true, maxDistance: 7 });
563
- if (!activated) {
564
- logger.warn(`[${config["bot-account"]["username"]}] '${BESLEYICI_NAMES[0]}' aktive edilemedi (id:${found.id}).`);
565
- return;
566
- }
567
-
568
- // wait for windowOpen (handler will process and set lastFullFeedAt if needed)
569
- const waitResult = await waitForWindowOpenOrTimeout(WINDOW_OPEN_TIMEOUT_MS);
570
- if (waitResult.opened) {
571
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
572
- } else {
573
- logger.warn(`[${config["bot-account"]["username"]}] Panel açılmadı veya timeout oldu; devam ediliyor.`);
574
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
575
- }
576
- } catch (err) {
577
- logger.error("scanAndFeed hata: " + (err && err.stack ? err.stack : err));
578
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
579
  }
580
 
581
- // --- Bot olayları ve ana mantık ---
582
  bot.once("spawn", async () => {
583
- const defaultMove = new Movements(bot);
584
- bot.pathfinder.setMovements(defaultMove);
585
- bot.settings.colorsEnabled = false;
586
  logger.info("Bot sunucuya giriş yaptı.");
587
 
588
- detectActivateApis();
589
-
590
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
591
  const password = config.utils["auto-auth"].password;
592
- setTimeout(() => {
 
593
  bot.chat(`/login ${password}`);
594
  logger.info(`[${config["bot-account"]["username"]}] Login komutu kullanıldı.`);
595
- }, 500);
596
 
597
- setTimeout(() => {
598
  bot.chat(`/skyblock`);
599
  logger.info(`[${config["bot-account"]["username"]}] Skyblock'a ışınlanma komutu kullanıldı.`);
600
- }, 5000);
601
 
602
- // İlk döngü: goHome -> scanAndFeed -> returnIsland
603
- setTimeout(async () => {
604
  await goHome();
605
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
606
  await scanAndFeed();
 
607
  await returnIsland();
608
- startPeriodicHomeChecks();
609
- }, 10000);
610
- } else {
611
- startPeriodicHomeChecks();
612
- }
613
-
614
- // chat-messages, position, anti-afk mantığı aynen korunuyor
615
- if (config.utils && config.utils["chat-messages"] && config.utils["chat-messages"].enabled) {
616
- logger.info("Started chat-messages module");
617
- let messages = config.utils["chat-messages"]["messages"];
618
- if (config.utils["chat-messages"].repeat) {
619
- let delay = config.utils["chat-messages"]["repeat-delay"];
620
- let i = 0;
621
- setInterval(() => {
622
- bot.chat(`${messages[i]}`);
623
- if (i + 1 === messages.length) i = 0;
624
- else i++;
625
- }, delay * 1000);
626
- } else {
627
- messages.forEach((msg) => bot.chat(msg));
628
- }
629
- }
630
-
631
- const pos = config.position;
632
- if (config.position && config.position.enabled) {
633
- logger.info(`Starting moving to target location (${pos.x}, ${pos.y}, ${pos.z})`);
634
- bot.pathfinder.setGoal(new GoalBlock(pos.x, pos.y, pos.z));
635
- }
636
-
637
- if (config.utils && config.utils["anti-afk"] && config.utils["anti-afk"].enabled) {
638
- if (config.utils["anti-afk"].sneak) bot.setControlState("sneak", true);
639
- if (config.utils["anti-afk"].jump) bot.setControlState("jump", true);
640
-
641
- if (config.utils["anti-afk"]["hit"] && config.utils["anti-afk"]["hit"].enabled) {
642
- let delay = config.utils["anti-afk"]["hit"]["delay"];
643
- let attackMobs = config.utils["anti-afk"]["hit"]["attack-mobs"];
644
- setInterval(() => {
645
- if (attackMobs) {
646
- let entity = bot.nearestEntity(
647
- (e) =>
648
- e.type !== "object" &&
649
- e.type !== "player" &&
650
- e.type !== "global" &&
651
- e.type !== "orb" &&
652
- e.type !== "other",
653
- );
654
- if (entity) {
655
- bot.attack(entity);
656
- return;
657
- }
658
- }
659
- bot.swingArm("right", true);
660
- }, delay);
661
- }
662
-
663
- if (config.utils["anti-afk"].rotate) {
664
- setInterval(() => {
665
- bot.look(bot.entity.yaw + 1, bot.entity.pitch, true);
666
- }, 100);
667
- }
668
-
669
- if (config.utils["anti-afk"]["circle-walk"] && config.utils["anti-afk"]["circle-walk"].enabled) {
670
- let radius = config.utils["anti-afk"]["circle-walk"]["radius"];
671
- setInterval(() => {
672
- circleWalk(bot, radius);
673
- }, 30000);
674
- }
675
  }
676
  });
677
 
678
- // windowClose: resolver'ları çözer
679
- bot.on("windowClose", (window) => {
680
- try {
681
- while (windowOpenResolvers.length > 0) {
682
- const r = windowOpenResolvers.shift();
683
- try { r(); } catch (e) {}
684
- }
685
- } catch (e) {}
686
- });
687
-
688
- // windowOpen: minimal log, tek satır sonuç; burada lastFullFeedAt ayarlanır
689
- bot.on("windowOpen", function (window) {
690
- try {
691
- const titleStr = parseWindowTitleToString(window.title);
692
- const panelMatch = (titleStr && (titleStr.toLowerCase().includes("besleyici") || titleStr.includes("ʙᴇsʟᴇʏiᴄi")));
693
- if (!panelMatch) {
694
- try { bot.closeWindow(window); } catch (e) {}
695
- try {
696
- while (windowOpenResolvers.length > 0) {
697
- const r = windowOpenResolvers.shift();
698
- try { r(); } catch (e) {}
699
- }
700
- } catch (e) {}
701
- return;
702
- }
703
-
704
- const beefSlots = window.slots.filter(xx => xx?.name && xx?.name === "cooked_beef");
705
- if (beefSlots.length === 0) {
706
- try { bot.closeWindow(window); } catch (e) {}
707
- try {
708
- while (windowOpenResolvers.length > 0) {
709
- const r = windowOpenResolvers.shift();
710
- try { r(); } catch (e) {}
711
- }
712
- } catch (e) {}
713
- return;
714
- }
715
-
716
- const beefSlot = beefSlots[0];
717
- const minyoncani = extractMinyonCanFromSlot(beefSlot);
718
-
719
- if (minyoncani == null) {
720
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı okunamadı (null).`);
721
- } else if (minyoncani <= 2) {
722
- // Besleme yapıldı
723
  bot.clickWindow(36, 0, 0);
724
- lastFullFeedAt = Date.now(); // besleme yapıldığı an 50dk bekle
725
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için beslendi. ${FULL_FEED_COOLDOWN_MS / 60000}dk bekleme aktif.`);
726
- try { bot.closeWindow(window); } catch (e) {}
 
 
727
  } else {
728
- // Eğer can 10 ise veya yüksekse, 50dk bekleme kuralını tetikle
729
- if (minyoncani >= 10) {
730
- lastFullFeedAt = Date.now();
731
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} (tam). ${FULL_FEED_COOLDOWN_MS / 60000}dk bekleme aktif.`);
732
- } else {
733
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için yenilenmedi.`);
734
- }
735
- try { bot.closeWindow(window); } catch (e) {}
736
  }
737
-
738
- try {
739
- while (windowOpenResolvers.length > 0) {
740
- const r = windowOpenResolvers.shift();
741
- try { r(); } catch (e) {}
742
- }
743
- } catch (e) {}
744
- } catch (err) {
745
- logger.error("windowOpen işlenirken hata: " + (err && err.stack ? err.stack : err));
746
- try { bot.closeWindow(window); } catch (e) {}
747
- try {
748
- while (windowOpenResolvers.length > 0) {
749
- const r = windowOpenResolvers.shift();
750
- try { r(); } catch (e) {}
751
- }
752
- } catch (e) {}
753
  }
 
 
754
  });
755
 
756
- bot.on("chat", (username, message) => {
757
- if (config.utils && config.utils["chat-log"]) logger.info(`<${username}> ${message}`);
758
- });
759
-
760
- bot.on('login', () => { // 1. Ayarları gerçekçi yap
761
- bot._client.write('settings', { locale: 'tr_tr', viewDistance: 10, chatFlags: 0, chatColors: true, skinParts: 127, mainHand: 1 });
762
- });
763
-
764
-
765
- bot.on("goal_reached", () => {
766
- if (config.position && config.position.enabled) logger.info(`Bot arrived to target location. ${bot.entity.position}`);
767
- });
768
-
769
- bot.on("death", () => {
770
- logger.warn(`Bot has been died and was respawned at ${bot.entity.position}`);
771
- });
772
-
773
- if (config.utils && config.utils["auto-reconnect"]) {
774
- bot.on("end", () => {
775
  setTimeout(() => createBot(), config.utils["auto-reconnect-delay"]);
776
- });
777
- }
778
-
779
- bot.on("kicked", (reason) => {
780
- let reasonText = "";
781
- try {
782
- const parsed = JSON.parse(reason);
783
- reasonText = parsed.text || parsed.extra?.[0]?.text || "";
784
- reasonText = reasonText?.replace(/§./g, "");
785
- logger.warn(`Bot sunucudan atıldı. Sebep: ${reasonText}`);
786
- } catch {
787
- logger.warn(`Bot sunucudan atıldı. Sebep: Bulunamadı.`);
788
  }
789
  });
790
 
791
- bot.on("error", (err) => logger.error(`${err && err.message ? err.message : err}`));
792
-
793
- // process message dump helper
794
- process.on("message", (msg) => {
795
- try {
796
- if (!msg) return;
797
- if (msg.type === "dumpEntityById" && msg.id) {
798
- const ent = Object.values(bot.entities).find(e => e && e.id === msg.id);
799
- if (ent) console.log(util.inspect(ent, { depth: 1 }));
800
- }
801
- } catch (e) {}
802
- });
803
-
804
- // --- Periyodik kontrol başlatma/durdurma ---
805
- let periodicHandle = null;
806
- function startPeriodicHomeChecks() {
807
- if (periodicHandle) return;
808
- periodicHandle = setInterval(() => {
809
- (async () => {
810
- try {
811
- // Eğer son tam beslemeden (veya can 10 görüldüğünden) henüz FULL_FEED_COOLDOWN_MS geçmediyse atla
812
- if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) {
813
- return;
814
- }
815
- await goHome();
816
- await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
817
- await scanAndFeed();
818
- await returnIsland();
819
- } catch (e) {}
820
- })();
821
- }, PERIODIC_CHECK_INTERVAL_MS);
822
- }
823
-
824
- function stopPeriodicHomeChecks() {
825
- if (!periodicHandle) return;
826
- clearInterval(periodicHandle);
827
- periodicHandle = null;
828
- }
829
-
830
- // circleWalk fonksiyonu (orijinal)
831
- function circleWalk(botRef, radius) {
832
- return new Promise(() => {
833
- const pos = botRef.entity.position;
834
- const x = pos.x;
835
- const y = pos.y;
836
- const z = pos.z;
837
-
838
- const points = [
839
- [x + radius, y, z],
840
- [x, y, z + radius],
841
- [x - radius, y, z],
842
- [x, y, z - radius],
843
- ];
844
-
845
- let i = 0;
846
- setTimeout(() => {
847
- if (i === points.length) i = 0;
848
- const defaultMove = new Movements(botRef);
849
- botRef.pathfinder.setMovements(defaultMove);
850
- botRef.pathfinder.setGoal(new GoalXZ(points[i][0], points[i][2]));
851
- i++;
852
- }, 1000);
853
- });
854
- }
855
-
856
- // startPeriodicHomeChecks çağrısı spawn içinde veya auto-auth sonrası yapılıyor
857
- // createBot fonksiyonu sonu
858
  }
859
 
860
- // create bot ve küçük web ping
861
  createBot();
862
 
863
  const express = require("express");
864
  const app = express();
865
- const port = process.env.PORT || 7860;
866
- app.get("/", (req, res) => res.send("Pinglendi"));
867
- app.listen(port, () => logger.info(`Bot bu adres üzerinde çalışıyor: http://localhost:${port}`));
868
-
869
- process.on("uncaughtException", function (err) {
870
- logger.error("Hata aldım!");
871
- logger.error(err && err.stack ? err.stack : err);
872
- });
 
8
  const loggers = require("./logging.js");
9
  const logger = loggers.logger;
10
 
11
+ // --- AYARLAR ---
12
+ const HOME_ARRIVAL_DELAY_MS = 2000;
13
+ const POST_ACTION_DELAY_MS = 4000;
14
+ const WINDOW_OPEN_TIMEOUT_MS = 6000;
 
 
 
15
  const PERIODIC_CHECK_INTERVAL_MS = 10 * 60 * 1000;
 
 
 
16
  const FULL_FEED_COOLDOWN_MS = 50 * 60 * 1000;
 
17
  const GO_HOME_COMMAND = "/home";
18
  const RETURN_ISLAND_COMMAND = "/is home";
 
 
19
  const BESLEYICI_NAMES = (config.utils && config.utils["besleyici-names"]) || ["Besleyici", "ʙᴇsʟᴇʏiᴄi"];
 
20
 
21
  function createBot() {
22
  const bot = mineflayer.createBot({
 
30
 
31
  bot.loadPlugin(pathfinder);
32
 
33
+ // --- SADECE TİMİNG SIFIRLAMA İÇİN EKLENEN KISIM ---
 
34
  let lastFullFeedAt = 0;
 
 
35
  let windowOpenResolvers = [];
36
+ let periodicHandle = null;
37
+ let activeTimeouts = [];
38
 
39
+ function setSafeTimeout(fn, delay) {
40
+ const t = setTimeout(fn, delay);
41
+ activeTimeouts.push(t);
42
+ return t;
43
+ }
44
+
45
+ function stopPeriodicHomeChecks() {
46
+ if (periodicHandle) clearInterval(periodicHandle);
47
+ periodicHandle = null;
48
+ activeTimeouts.forEach(t => clearTimeout(t));
49
+ activeTimeouts = [];
50
+ }
51
+ // ------------------------------------------------
52
+
53
+ // --- SENİN ORİJİNAL FONKSİYONLARIN (TAMAMEN AYNI) ---
54
  function stripColorCodes(s) {
55
  if (!s || typeof s !== "string") return s;
56
  return s.replace(/§[0-9a-fk-or]/gi, "");
 
94
  let cur = obj;
95
  for (const p of pathArray) {
96
  if (cur == null) return undefined;
97
+ cur = cur[p];
 
 
 
 
 
98
  }
99
  return cur;
100
+ } catch (e) { return undefined; }
 
 
101
  }
102
 
 
103
  function deepSearchForString(root, targetLower) {
104
  const results = [];
105
  const visited = new WeakSet();
 
106
  function recurse(obj, path) {
107
+ if (obj == null || typeof obj === "function") return;
108
  if (typeof obj === "string") {
109
  const norm = normalizeForMatch(obj);
110
  if (norm.includes(targetLower)) results.push({ path, value: obj });
111
  return;
112
  }
113
+ if (typeof obj !== "object") return;
 
 
 
 
 
 
 
 
 
114
  if (visited.has(obj)) return;
115
  visited.add(obj);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
116
  for (const key of Object.keys(obj)) {
117
+ recurse(obj[key], `${path}.${key}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
118
  }
119
  }
120
+ try { recurse(root, "root"); } catch (e) {}
 
 
 
121
  return results;
122
  }
123
 
 
125
  try {
126
  if (!titleObj) return "";
127
  if (typeof titleObj === "string") return titleObj;
128
+ const s = titleObj.toString();
129
+ if (s && s !== "[object Object]") return s;
130
+ return JSON.stringify(titleObj);
131
+ } catch (err) { return ""; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  }
133
 
 
134
  function extractMinyonCanFromSlot(slot) {
135
  try {
136
  if (!slot) return null;
 
137
  function tryParseLoreText(text) {
138
  try {
139
  if (!text || typeof text !== "string") return null;
 
143
  if (maybe && typeof maybe === "object") {
144
  if (maybe.extra && Array.isArray(maybe.extra) && maybe.extra.length > 0) {
145
  if (typeof maybe.extra[0].text === "string") plain = maybe.extra[0].text;
 
146
  } else if (typeof maybe.text === "string") {
147
  plain = maybe.text;
 
 
148
  }
149
  }
150
  } catch (e) {}
151
  const xyMatch = plain.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
152
+ if (xyMatch) return Number(xyMatch[1]);
 
 
 
153
  const numMatch = plain.match(/(\d{1,4})/);
154
+ if (numMatch) return Number(numMatch[1]);
 
 
 
155
  return null;
156
+ } catch (e) { return null; }
 
 
157
  }
 
 
158
  if (slot.nbt) {
159
+ const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
160
+ if (Array.isArray(lore)) {
161
+ for (const line of lore) {
162
+ const res = tryParseLoreText(line.value || line);
163
+ if (res != null) return res;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
  }
165
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
166
  }
167
+ const full = util.inspect(slot, { depth: null });
168
+ return tryParseLoreText(full);
169
+ } catch (err) { return null; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  }
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  async function goHome() {
173
+ logger.info(`[${config["bot-account"]["username"]}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
174
+ bot.chat(GO_HOME_COMMAND);
 
 
 
 
175
  }
176
 
177
  async function returnIsland() {
178
+ logger.info(`[${config["bot-account"]["username"]}] ${RETURN_ISLAND_COMMAND} komutu gönderiliyor.`);
179
+ bot.chat(RETURN_ISLAND_COMMAND);
 
 
 
180
  }
181
 
 
182
  async function scanAndFeed() {
183
+ if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
184
+ const arr = Object.values(bot.entities);
185
+ let best = null;
186
+
187
+ for (const e of arr) {
188
+ const name = getEntityReadableName(e);
189
+ if (isBesleyiciName(name)) {
190
+ best = { entity: e, path: "displayName/name" };
191
+ break;
192
+ }
193
+ for (const target of TARGET_NAME_NORMS) {
194
+ const deep = deepSearchForString(e, target);
195
+ if (deep.length > 0) {
196
+ best = { entity: e, path: deep[0].path };
 
 
 
 
 
 
 
197
  break;
198
  }
199
  }
200
+ if (best) break;
201
+ }
202
 
203
+ if (!best) {
204
+ logger.info(`[${config["bot-account"]["username"]}] /home sonrası tarama: besleyici minyon bulunamadı.`);
205
+ return;
206
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
207
 
208
+ const dist = bot.entity.position.distanceTo(best.entity.position);
209
+ // SENİN LOGUN: 'Armor Stand' bulundu id:...
210
+ logger.info(`[${config["bot-account"]["username"]}] '${best.entity.name || 'Armor Stand'}' bulundu id:${best.entity.id} path:${best.path} dist:${dist.toFixed(2)} — aktive ediliyor.`);
211
 
212
+ if (dist > 7) {
213
+ logger.warn(`safeActivateEntityPreferAt: entity id:${best.entity.id} uzak (${dist.toFixed(2)}). Max 7 blok.`);
214
+ logger.warn(`[${config["bot-account"]["username"]}] 'Besleyici' aktive edilemedi (id:${best.entity.id}).`);
215
+ return;
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
217
+
218
+ try {
219
+ if (bot.lookAt) await bot.lookAt(best.entity.position.offset(0, 1.0, 0), true);
220
+ await new Promise(r => setTimeout(r, 200));
221
+
222
+ logger.info(`activateEntityAt çağrıldı id:${best.entity.id}`);
223
+ if (typeof bot.activateEntityAt === "function") bot.activateEntityAt(best.entity, best.entity.position);
224
+ else if (typeof bot.activateEntity === "function") bot.activateEntity(best.entity);
225
+
226
+ await new Promise((resolve) => {
227
+ const timer = setTimeout(() => resolve(), WINDOW_OPEN_TIMEOUT_MS);
228
+ windowOpenResolvers.push(() => { clearTimeout(timer); resolve(); });
229
+ });
230
+ } catch (err) {}
231
  }
232
 
 
233
  bot.once("spawn", async () => {
234
+ bot.pathfinder.setMovements(new Movements(bot));
 
 
235
  logger.info("Bot sunucuya giriş yaptı.");
236
 
 
 
237
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
238
  const password = config.utils["auto-auth"].password;
239
+
240
+ setSafeTimeout(() => {
241
  bot.chat(`/login ${password}`);
242
  logger.info(`[${config["bot-account"]["username"]}] Login komutu kullanıldı.`);
243
+ }, 2500);
244
 
245
+ setSafeTimeout(() => {
246
  bot.chat(`/skyblock`);
247
  logger.info(`[${config["bot-account"]["username"]}] Skyblock'a ışınlanma komutu kullanıldı.`);
248
+ }, 7500);
249
 
250
+ setSafeTimeout(async () => {
 
251
  await goHome();
252
  await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
253
  await scanAndFeed();
254
+ await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
255
  await returnIsland();
256
+
257
+ periodicHandle = setInterval(async () => {
258
+ if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
259
+ await goHome();
260
+ await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
261
+ await scanAndFeed();
262
+ await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
263
+ await returnIsland();
264
+ }, PERIODIC_CHECK_INTERVAL_MS);
265
+ }, 12500);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  }
267
  });
268
 
269
+ bot.on("windowOpen", (window) => {
270
+ const title = parseWindowTitleToString(window.title).toLowerCase();
271
+ if (!title.includes("besleyici") && !parseWindowTitleToString(window.title).includes("ʙᴇsʟᴇʏiᴄi")) {
272
+ logger.info(`[${config["bot-account"]["username"]}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${parseWindowTitleToString(window.title)}`);
273
+ bot.closeWindow(window);
274
+ return;
275
+ }
276
+ const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
277
+ const can = extractMinyonCanFromSlot(beefSlot);
278
+ if (can != null) {
279
+ if (can <= 2) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
280
  bot.clickWindow(36, 0, 0);
281
+ lastFullFeedAt = Date.now();
282
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${can} olduğu için beslendi. 50dk bekleme aktif.`);
283
+ } else if (can >= 10) {
284
+ lastFullFeedAt = Date.now();
285
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${can} (tam). 50dk bekleme aktif.`);
286
  } else {
287
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${can} olduğu için yenilenmedi.`);
 
 
 
 
 
 
 
288
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
289
  }
290
+ setSafeTimeout(() => { try { bot.closeWindow(window); } catch(e){} }, 500);
291
+ while (windowOpenResolvers.length > 0) windowOpenResolvers.shift()();
292
  });
293
 
294
+ bot.on("end", () => {
295
+ logger.warn("Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor...");
296
+ stopPeriodicHomeChecks();
297
+ if (config.utils && config.utils["auto-reconnect"]) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
298
  setTimeout(() => createBot(), config.utils["auto-reconnect-delay"]);
 
 
 
 
 
 
 
 
 
 
 
 
299
  }
300
  });
301
 
302
+ bot.on("kicked", (reason) => logger.warn(`Bot sunucudan atıldı: ${util.inspect(reason)}`));
303
+ bot.on("error", (err) => logger.error(`${err}`));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
304
  }
305
 
 
306
  createBot();
307
 
308
  const express = require("express");
309
  const app = express();
310
+ app.get("/", (req, res) => res.send("Bot Aktif"));
311
+ app.listen(process.env.PORT || 7860);