Suvarii commited on
Commit
2b59478
·
verified ·
1 Parent(s): 9160511

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +337 -317
bot.js CHANGED
@@ -1,23 +1,32 @@
1
  const mineflayer = require("mineflayer");
2
  const Movements = require("mineflayer-pathfinder").Movements;
3
  const pathfinder = require("mineflayer-pathfinder").pathfinder;
4
- const { GoalBlock, GoalXZ, GoalNear } = require("mineflayer-pathfinder").goals;
5
  const util = require("util");
6
 
7
  const config = require("./settings.json");
8
-
9
  const loggers = require("./logging.js");
10
  const logger = loggers.logger;
11
 
12
- // --- AYARLAR (İstersen buradan değiştir) ---
13
- const HOME_ARRIVAL_DELAY_MS = 1500; // /home sonrası bekleme (ışınlanma tamamlanması için)
14
- const POST_ACTION_DELAY_MS = 1500; // besleme/işlem sonrası kısa bekleme (panel kapandıktan sonra dönmeden önce)
15
- const WINDOW_OPEN_TIMEOUT_MS = 500; // panel açılmasını bekleme süresi (ms)
16
- const PERIODIC_CHECK_INTERVAL_MS = 10 * 60 * 1000; // 10 dakika
17
- // ------------------------------------------------
 
 
18
 
19
- // Besleyici adı ayarı: settings.json içinde "utils": { "besleyici-name": "Besleyici x" } şeklinde tanımla
20
- const BESLEYICI_NAME_CONFIG = (config.utils && config.utils["besleyici-name"]) ? config.utils["besleyici-name"] : "Besleyici";
 
 
 
 
 
 
 
 
21
 
22
  function createBot() {
23
  const bot = mineflayer.createBot({
@@ -30,6 +39,13 @@ function createBot() {
30
 
31
  bot.loadPlugin(pathfinder);
32
 
 
 
 
 
 
 
 
33
  // --- Yardımcı fonksiyonlar ---
34
  function stripColorCodes(s) {
35
  if (!s || typeof s !== "string") return s;
@@ -61,13 +77,12 @@ function createBot() {
61
  return t.toLowerCase();
62
  }
63
 
64
- // normalize edilmiş hedef adı (ayar üzerinden değiştirilebilir)
65
- const TARGET_NAME_NORM = normalizeForMatch(BESLEYICI_NAME_CONFIG);
66
 
67
  function isBesleyiciName(name) {
68
  if (!name) return false;
69
  const norm = normalizeForMatch(name);
70
- return norm.includes(TARGET_NAME_NORM);
71
  }
72
 
73
  function safeGet(obj, pathArray) {
@@ -88,7 +103,7 @@ function createBot() {
88
  }
89
  }
90
 
91
- // Basit derin arama (sadece tespit için)
92
  function deepSearchForString(root, targetLower) {
93
  const results = [];
94
  const visited = new WeakSet();
@@ -165,7 +180,6 @@ function createBot() {
165
  return results;
166
  }
167
 
168
- // window.title parse yardımcı
169
  function parseWindowTitleToString(titleObj) {
170
  try {
171
  if (!titleObj) return "";
@@ -199,107 +213,45 @@ function createBot() {
199
  }
200
  }
201
 
202
- // --- Güvenli activate (öncelikle activateEntityAt kullanır, retry ve lookAt içerir) ---
203
- async function safeActivateEntityPreferAt(entity, options = {}) {
204
- const maxRetries = options.maxRetries ?? 3;
205
- const retryDelay = options.retryDelay ?? 250;
206
- const requireLook = options.requireLook ?? true;
207
- const maxDistance = options.maxDistance ?? 7;
208
-
209
- if (!entity) {
210
- logger.warn("safeActivateEntityPreferAt: entity yok");
211
- return false;
212
- }
213
-
214
  try {
215
- if (entity.position && bot.entity && bot.entity.position) {
216
- const dist = entity.position.distanceTo(bot.entity.position);
217
- if (dist > maxDistance) {
218
- logger.warn(`safeActivateEntityPreferAt: entity id:${entity.id} uzak (${dist.toFixed(2)}). Max ${maxDistance} blok.`);
219
- return false;
220
- }
221
- }
222
-
223
- if (requireLook && entity.position && bot.lookAt) {
224
- try {
225
- const lookPos = (typeof entity.position.offset === "function")
226
- ? entity.position.offset(0, 1.5, 0)
227
- : { x: entity.position.x, y: entity.position.y + 1.5, z: entity.position.z };
228
- await bot.lookAt(lookPos, true);
229
- await new Promise(r => setTimeout(r, 180));
230
- } catch (e) {}
231
- }
232
 
233
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
234
  try {
235
- if (typeof bot.activateEntityAt === "function") {
236
- try {
237
- bot.activateEntityAt(entity, entity.position);
238
- logger.info(`safeActivateEntityPreferAt: activateEntityAt çağrıldı id:${entity.id} attempt:${attempt}`);
239
- return true;
240
- } catch (err) {
241
- logger.warn(`safeActivateEntityPreferAt: activateEntityAt hata id:${entity.id} attempt:${attempt} err:${err && err.message ? err.message : err}`);
 
 
 
 
 
 
242
  }
 
 
 
 
 
243
  }
244
-
245
- if (typeof bot.activateEntity === "function") {
246
- try {
247
- bot.activateEntity(entity);
248
- logger.info(`safeActivateEntityPreferAt: activateEntity çağrıldı id:${entity.id} attempt:${attempt}`);
249
- return true;
250
- } catch (err) {
251
- logger.warn(`safeActivateEntityPreferAt: activateEntity hata id:${entity.id} attempt:${attempt} err:${err && err.message ? err.message : err}`);
252
- }
253
  }
254
-
255
- logger.warn("safeActivateEntityPreferAt: bot.activateEntityAt/activateEntity bulunamadı.");
256
- return false;
257
- } catch (err) {
258
- logger.warn(`safeActivateEntityPreferAt: deneme başarısız id:${entity.id} attempt:${attempt} err:${err && err.message ? err.message : err}`);
259
- await new Promise(r => setTimeout(r, retryDelay));
260
- }
261
- }
262
-
263
- logger.error(`safeActivateEntityPreferAt: tüm denemeler başarısız id:${entity.id}`);
264
- return false;
265
- } catch (err) {
266
- logger.error(`safeActivateEntityPreferAt hata: ${err && err.stack ? err.stack : err}`);
267
- return false;
268
- }
269
- }
270
-
271
- // --- windowOpen bekleyici mekanizması ---
272
- let windowOpenResolvers = [];
273
- function waitForWindowOpenOrTimeout(timeoutMs) {
274
- return new Promise((resolve) => {
275
- try {
276
- if (bot.currentWindow && bot.currentWindow.type) {
277
- resolve({ opened: true });
278
- return;
279
  }
280
- } catch (e) {}
281
-
282
- const timer = setTimeout(() => {
283
- const idx = windowOpenResolvers.indexOf(resolver);
284
- if (idx !== -1) windowOpenResolvers.splice(idx, 1);
285
- resolve({ opened: false, timedOut: true });
286
- }, timeoutMs);
287
-
288
- function resolver() {
289
- clearTimeout(timer);
290
- resolve({ opened: true, timedOut: false });
291
  }
292
 
293
- windowOpenResolvers.push(resolver);
294
- });
295
- }
296
-
297
- // --- Geliştirilmiş minyon canı çıkarma yardımcı fonksiyonu (custom_data.display.Lore string JSON formatını destekler) ---
298
- function extractMinyonCanFromSlot(slot) {
299
- try {
300
- if (!slot) return null;
301
-
302
- // 1) Eğer slot.nbt varsa önce oradan dene (çeşitli yollar)
303
  if (slot.nbt) {
304
  try {
305
  const candidates = [
@@ -307,7 +259,6 @@ function createBot() {
307
  ["value", "display", "value", "Lore"],
308
  ["value", "display", "value"],
309
  ];
310
-
311
  for (const path of candidates) {
312
  let cur = slot.nbt;
313
  let ok = true;
@@ -316,7 +267,6 @@ function createBot() {
316
  cur = cur[p];
317
  }
318
  if (!ok) continue;
319
-
320
  if (Array.isArray(cur) && cur.length > 0) {
321
  const tryIndices = [1, cur.length - 1, 0];
322
  for (const idx of tryIndices) {
@@ -347,7 +297,7 @@ function createBot() {
347
  } catch (e) {}
348
  }
349
 
350
- // 2) components içinde custom_data veya lore varsa kontrol et
351
  try {
352
  if (Array.isArray(slot.components)) {
353
  for (const c of slot.components) {
@@ -364,7 +314,6 @@ function createBot() {
364
  if (parsed != null) return parsed;
365
  }
366
  }
367
-
368
  if (c.type === "lore" && Array.isArray(c.data)) {
369
  for (const entry of c.data) {
370
  const text = safeGet(entry, ["value", "text", "value"]) || safeGet(entry, ["value", "extra", "value", 0, "value", "text", "value"]) || (entry && entry.toString && entry.toString());
@@ -376,7 +325,7 @@ function createBot() {
376
  }
377
  } catch (e) {}
378
 
379
- // 3) componentMap içinde 'custom_data' veya 'lore' anahtarlarını kontrol et
380
  try {
381
  if (slot.componentMap && typeof slot.componentMap === "object") {
382
  const getFromMap = (m, key) => {
@@ -385,7 +334,6 @@ function createBot() {
385
  return m[key];
386
  } catch (e) { return null; }
387
  };
388
-
389
  const loreComp = getFromMap(slot.componentMap, "custom_data") || getFromMap(slot.componentMap, "lore");
390
  if (loreComp) {
391
  const data = loreComp.data || loreComp;
@@ -406,11 +354,13 @@ function createBot() {
406
  }
407
  } catch (e) {}
408
 
409
- // 4) Fallback: tüm slot inspect'ini regex ile tara
410
  try {
411
  const full = util.inspect(slot, { depth: null, maxArrayLength: null });
412
- const parsed = tryParseLoreText(full);
413
- if (parsed != null) return parsed;
 
 
414
  } catch (e) {}
415
 
416
  return null;
@@ -420,186 +370,211 @@ function createBot() {
420
  }
421
  }
422
 
423
- // yardımcı: lore/text içinden X/Y veya ilk sayıyı çek
424
- function tryParseLoreText(text) {
425
- try {
426
- if (!text || typeof text !== "string") return null;
 
 
 
427
 
428
- // Eğer text JSON string ise parse etmeye çalış
429
- let plain = text;
430
- try {
431
- const maybe = JSON.parse(text);
432
- if (maybe && typeof maybe === "object") {
433
- if (maybe.extra && Array.isArray(maybe.extra) && maybe.extra.length > 0) {
434
- if (typeof maybe.extra[0].text === "string") plain = maybe.extra[0].text;
435
- else plain = JSON.stringify(maybe.extra);
436
- } else if (typeof maybe.text === "string") {
437
- plain = maybe.text;
438
- } else {
439
- plain = JSON.stringify(maybe);
440
- }
 
 
 
 
 
441
  }
442
- } catch (e) {
443
- // JSON değilse olduğu gibi kullan
444
  }
445
 
446
- // X/Y formatı ara
447
- const xyMatch = plain.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
448
- if (xyMatch) {
449
- const x = Number(xyMatch[1]);
450
- if (!Number.isNaN(x)) return x;
 
 
 
451
  }
452
 
453
- // İlk sayı
454
- const numMatch = plain.match(/(\d{1,4})/);
455
- if (numMatch) {
456
- const n = Number(numMatch[1]);
457
- if (!Number.isNaN(n)) return n;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
458
  }
459
 
460
- return null;
461
- } catch (e) {
462
- return null;
 
 
463
  }
464
  }
465
 
466
- // --- HOME kontrol mekanizması ---
467
- let isPerformingHomeCheck = false; // aynı anda birden fazla çalışmasın
468
- let pendingHomeScan = false; // sadece bizim tetiklediğimiz /home sonrası tarama yap
 
 
 
 
 
 
469
 
470
- async function performHomeCheck() {
471
- if (isPerformingHomeCheck) return;
472
- isPerformingHomeCheck = true;
473
- pendingHomeScan = true;
 
474
 
475
- try {
476
- // 1) Git /home (log geri eklendi)
477
- try {
478
- logger.info(`[${config["bot-account"]["username"]}] /home komutu gönderiliyor.`);
479
- bot.chat("/home");
480
- } catch (e) {
481
- logger.warn("performHomeCheck: /home gönderilemedi: " + (e && e.message ? e.message : e));
482
  }
483
 
484
- // 2) Bekle (ışınlanma için)
485
- await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
 
486
 
487
- // Home'a varış logu
488
- logger.info(`[${config["bot-account"]["username"]}] /home sonrası tarama başlıyor.`);
 
 
 
 
 
 
 
489
 
490
- if (!pendingHomeScan) {
491
- isPerformingHomeCheck = false;
 
 
 
 
 
 
 
 
 
 
 
 
492
  return;
493
  }
494
 
495
- // 3) Tarama ve besleme mantığı (kısa ve sessiz)
496
  const arr = Object.values(bot.entities);
497
  if (!arr || arr.length === 0) {
498
  logger.info(`[${config["bot-account"]["username"]}] /home sonrası: entity bulunamadı.`);
499
- } else {
500
- // Hedef adı ayardan geliyor
501
- const targetNorm = TARGET_NAME_NORM;
502
- let found = null;
503
- let foundPath = null;
504
 
505
- // displayName kontrolü
506
- for (const e of arr) {
507
- const name = getEntityReadableName(e);
508
- if (isBesleyiciName(name)) {
509
- found = e;
510
- foundPath = "displayName/name";
511
- break;
512
- }
 
513
  }
 
514
 
515
- // metadata yol kontrolü
516
- if (!found) {
517
- for (const e of arr) {
518
- const candidate = safeGet(e, ["metadata", 2, "value", "extra", "value", "value", 0]);
519
- if (candidate) {
520
- let candidateStr = null;
521
- try {
522
- if (typeof candidate === "string") candidateStr = candidate;
523
- else if (candidate && typeof candidate.toString === "function") candidateStr = candidate.toString();
524
- else candidateStr = util.inspect(candidate, { depth: 1 });
525
- } catch (err) {
526
- candidateStr = String(candidate);
527
- }
528
- if (normalizeForMatch(candidateStr).includes(targetNorm)) {
529
- found = e;
530
- foundPath = "metadata[2].value.extra.value.value[0]";
531
- break;
532
- }
533
  }
534
- }
535
- }
536
-
537
- // genel derin arama (son çare)
538
- if (!found) {
539
- for (const e of arr) {
540
- const matches = deepSearchForString(e, targetNorm);
541
- if (matches && matches.length > 0) {
542
  found = e;
543
- foundPath = matches[0].path;
544
  break;
545
  }
546
  }
547
  }
 
548
 
549
- if (found) {
550
- const readable = getEntityReadableName(found);
551
- const dist = (found.position && bot.entity && bot.entity.position) ? found.position.distanceTo(bot.entity.position).toFixed(2) : "n/a";
552
- logger.info(`[${config["bot-account"]["username"]}] '${BESLEYICI_NAME_CONFIG}' bulundu id:${found.id} path:${foundPath} dist:${dist} — aktive ediliyor.`);
553
-
554
- // 4) Güvenli şekilde activate et (activateEntityAt öncelikli) ve panel açılmasını bekle (veya timeout)
555
- const activated = await safeActivateEntityPreferAt(found, { maxRetries: 4, retryDelay: 300, requireLook: true, maxDistance: 7 });
556
- if (!activated) {
557
- logger.warn(`[${config["bot-account"]["username"]}] '${BESLEYICI_NAME_CONFIG}' aktive edilemedi (id:${found.id}).`);
558
- } else {
559
- // Activate başarılıysa panel açılmasını bekle; windowOpen handler paneli işleyip kapattıktan sonra resolver'lar çağrılacak
560
- const waitResult = await waitForWindowOpenOrTimeout(WINDOW_OPEN_TIMEOUT_MS);
561
- if (waitResult.opened) {
562
- // windowOpen handler'ı paneli işleyip kapattıktan sonra buraya gelecek
563
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
564
- } else {
565
- // timeout oldu; panel açılmadı veya açılma gecikti
566
- logger.warn(`[${config["bot-account"]["username"]}] Panel açılmadı veya timeout oldu; devam ediliyor.`);
567
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
568
- }
569
  }
570
- } else {
571
- logger.info(`[${config["bot-account"]["username"]}] /home sonrası tarama: '${BESLEYICI_NAME_CONFIG}' minyon bulunamadı.`);
572
  }
573
  }
574
 
575
- // 5) Dönüş: /is home (dönüşte tarama yapmaması için pendingHomeScan false yapıyoruz)
576
- pendingHomeScan = false;
577
- try {
578
- bot.chat("/is home");
579
- } catch (e) {
580
- logger.warn("performHomeCheck: /is home gönderilemedi: " + (e && e.message ? e.message : e));
581
  }
582
- } catch (err) {
583
- logger.error("performHomeCheck hata: " + (err && err.stack ? err.stack : err));
584
- } finally {
585
- isPerformingHomeCheck = false;
586
- pendingHomeScan = false;
587
- }
588
- }
589
 
590
- // Periyodik planlayıcı
591
- let periodicHandle = null;
592
- function startPeriodicHomeChecks() {
593
- if (periodicHandle) return;
594
- periodicHandle = setInterval(() => {
595
- performHomeCheck().catch(() => {});
596
- }, PERIODIC_CHECK_INTERVAL_MS);
597
- }
598
 
599
- function stopPeriodicHomeChecks() {
600
- if (!periodicHandle) return;
601
- clearInterval(periodicHandle);
602
- periodicHandle = null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
603
  }
604
 
605
  // --- Bot olayları ve ana mantık ---
@@ -609,28 +584,34 @@ function createBot() {
609
  bot.settings.colorsEnabled = false;
610
  logger.info("Bot sunucuya giriş yaptı.");
611
 
612
- if (config.utils["auto-auth"].enabled) {
613
- let password = config.utils["auto-auth"].password;
 
 
614
  setTimeout(() => {
615
  bot.chat(`/login ${password}`);
616
  logger.info(`[${config["bot-account"]["username"]}] Login komutu kullanıldı.`);
617
  }, 500);
618
 
619
- setTimeout(async () => {
620
  bot.chat(`/skyblock`);
621
  logger.info(`[${config["bot-account"]["username"]}] Skyblock'a ışınlanma komutu kullanıldı.`);
622
  }, 5000);
623
 
624
- // İlk girişte home'a gidip kontrol et, sonra adaya dön
625
  setTimeout(async () => {
626
- performHomeCheck().catch(() => {});
 
 
 
627
  startPeriodicHomeChecks();
628
  }, 10000);
629
  } else {
630
  startPeriodicHomeChecks();
631
  }
632
 
633
- if (config.utils["chat-messages"].enabled) {
 
634
  logger.info("Started chat-messages module");
635
  let messages = config.utils["chat-messages"]["messages"];
636
  if (config.utils["chat-messages"].repeat) {
@@ -647,16 +628,16 @@ function createBot() {
647
  }
648
 
649
  const pos = config.position;
650
- if (config.position.enabled) {
651
  logger.info(`Starting moving to target location (${pos.x}, ${pos.y}, ${pos.z})`);
652
  bot.pathfinder.setGoal(new GoalBlock(pos.x, pos.y, pos.z));
653
  }
654
 
655
- if (config.utils["anti-afk"].enabled) {
656
  if (config.utils["anti-afk"].sneak) bot.setControlState("sneak", true);
657
  if (config.utils["anti-afk"].jump) bot.setControlState("jump", true);
658
 
659
- if (config.utils["anti-afk"]["hit"].enabled) {
660
  let delay = config.utils["anti-afk"]["hit"]["delay"];
661
  let attackMobs = config.utils["anti-afk"]["hit"]["attack-mobs"];
662
  setInterval(() => {
@@ -684,7 +665,7 @@ function createBot() {
684
  }, 100);
685
  }
686
 
687
- if (config.utils["anti-afk"]["circle-walk"].enabled) {
688
  let radius = config.utils["anti-afk"]["circle-walk"]["radius"];
689
  setInterval(() => {
690
  circleWalk(bot, radius);
@@ -693,7 +674,7 @@ function createBot() {
693
  }
694
  });
695
 
696
- // windowClose listener: panel kapandığında bekleyenleri çözer
697
  bot.on("windowClose", (window) => {
698
  try {
699
  while (windowOpenResolvers.length > 0) {
@@ -703,11 +684,10 @@ function createBot() {
703
  } catch (e) {}
704
  });
705
 
706
- // Güvenli windowOpen handler: minimal log (gereksiz başlık/beefSlots logları kaldırıldı)
707
  bot.on("windowOpen", function (window) {
708
  try {
709
- let titleStr = parseWindowTitleToString(window.title);
710
-
711
  const panelMatch = (titleStr && (titleStr.toLowerCase().includes("besleyici") || titleStr.includes("ʙᴇsʟᴇʏiᴄi")));
712
  if (!panelMatch) {
713
  try { bot.closeWindow(window); } catch (e) {}
@@ -721,24 +701,36 @@ function createBot() {
721
  }
722
 
723
  const beefSlots = window.slots.filter(xx => xx?.name && xx?.name === "cooked_beef");
 
 
 
 
 
 
 
 
 
 
724
 
725
- if (beefSlots.length > 0) {
726
- const beefSlot = beefSlots[0];
727
-
728
- // Minyon canını güvenli şekilde çıkar
729
- const minyoncani = extractMinyonCanFromSlot(beefSlot);
730
 
731
- if (minyoncani == null) {
732
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı okunamadı (null).`);
733
- } else if (minyoncani <= 2) {
734
- bot.clickWindow(36, 0, 0);
735
- logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için besleyici minyon beslendi.`);
736
- bot.closeWindow(window);
 
 
 
 
 
 
 
737
  } else {
738
  logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için yenilenmedi.`);
739
- bot.closeWindow(window);
740
  }
741
- } else {
742
  try { bot.closeWindow(window); } catch (e) {}
743
  }
744
 
@@ -761,18 +753,18 @@ function createBot() {
761
  });
762
 
763
  bot.on("chat", (username, message) => {
764
- if (config.utils["chat-log"]) logger.info(`<${username}> ${message}`);
765
  });
766
 
767
  bot.on("goal_reached", () => {
768
- if (config.position.enabled) logger.info(`Bot arrived to target location. ${bot.entity.position}`);
769
  });
770
 
771
  bot.on("death", () => {
772
  logger.warn(`Bot has been died and was respawned at ${bot.entity.position}`);
773
  });
774
 
775
- if (config.utils["auto-reconnect"]) {
776
  bot.on("end", () => {
777
  setTimeout(() => createBot(), config.utils["auto-reconnect-delay"]);
778
  });
@@ -784,15 +776,15 @@ function createBot() {
784
  const parsed = JSON.parse(reason);
785
  reasonText = parsed.text || parsed.extra?.[0]?.text || "";
786
  reasonText = reasonText?.replace(/§./g, "");
787
- logger.warn(`Bot sunucudan atıldı.Sebep: ${reasonText}`);
788
  } catch {
789
- logger.warn(`Bot sunucudan atıldı.Sebep: Bulunamadı.`);
790
  }
791
  });
792
 
793
- bot.on("error", (err) => logger.error(`${err.message}`));
794
 
795
- // Manuel dump için process mesajı (opsiyonel)
796
  process.on("message", (msg) => {
797
  try {
798
  if (!msg) return;
@@ -802,42 +794,70 @@ function createBot() {
802
  }
803
  } catch (e) {}
804
  });
805
- }
806
 
807
- // circleWalk fonksiyonu (orijinal)
808
- function circleWalk(bot, radius) {
809
- return new Promise(() => {
810
- const pos = bot.entity.position;
811
- const x = pos.x;
812
- const y = pos.y;
813
- const z = pos.z;
814
-
815
- const points = [
816
- [x + radius, y, z],
817
- [x, y, z + radius],
818
- [x - radius, y, z],
819
- [x, y, z - radius],
820
- ];
821
-
822
- let i = 0;
823
- setTimeout(() => {
824
- if (i === points.length) i = 0;
825
- const defaultMove = new Movements(bot);
826
- bot.pathfinder.setMovements(defaultMove);
827
- bot.pathfinder.setGoal(new GoalXZ(points[i][0], points[i][2]));
828
- i++;
829
- }, 1000);
830
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
831
  }
832
 
 
833
  createBot();
834
 
835
  const express = require("express");
836
  const app = express();
837
  const port = process.env.PORT || 7860;
838
-
839
  app.get("/", (req, res) => res.send("Pinglendi"));
840
-
841
  app.listen(port, () => logger.info(`Bot bu adres üzerinde çalışıyor: http://localhost:${port}`));
842
 
843
  process.on("uncaughtException", function (err) {
 
1
  const mineflayer = require("mineflayer");
2
  const Movements = require("mineflayer-pathfinder").Movements;
3
  const pathfinder = require("mineflayer-pathfinder").pathfinder;
4
+ const { GoalBlock, GoalXZ } = require("mineflayer-pathfinder").goals;
5
  const util = require("util");
6
 
7
  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 = 5000; // /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 = 2500; // panel açılma timeout (ms)
15
+
16
+ // Periyodik kontrol aralığı (30dk 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 30 dakika. İstersen 29 dakika yapmak için burayı 29 * 60 * 1000 yap.
22
+ const FULL_FEED_COOLDOWN_MS = 30 * 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", "Feeder"];
29
+ // ------------------------------------------------
30
 
31
  function createBot() {
32
  const bot = mineflayer.createBot({
 
39
 
40
  bot.loadPlugin(pathfinder);
41
 
42
+ // --- Durum / zamanlayıcı değişkenleri ---
43
+ // Son tam besleme (veya panelde can 10 görüldüğü zaman) zaman damgası (ms)
44
+ let lastFullFeedAt = 0;
45
+
46
+ // windowOpen bekleyici resolver listesi (mevcut mantığı korumak için)
47
+ let windowOpenResolvers = [];
48
+
49
  // --- Yardımcı fonksiyonlar ---
50
  function stripColorCodes(s) {
51
  if (!s || typeof s !== "string") return s;
 
77
  return t.toLowerCase();
78
  }
79
 
80
+ const TARGET_NAME_NORMS = BESLEYICI_NAMES.map(n => normalizeForMatch(n));
 
81
 
82
  function isBesleyiciName(name) {
83
  if (!name) return false;
84
  const norm = normalizeForMatch(name);
85
+ return TARGET_NAME_NORMS.some(t => norm.includes(t));
86
  }
87
 
88
  function safeGet(obj, pathArray) {
 
103
  }
104
  }
105
 
106
+ // Deep search sadece fallback olarak kullanılacak
107
  function deepSearchForString(root, targetLower) {
108
  const results = [];
109
  const visited = new WeakSet();
 
180
  return results;
181
  }
182
 
 
183
  function parseWindowTitleToString(titleObj) {
184
  try {
185
  if (!titleObj) return "";
 
213
  }
214
  }
215
 
216
+ // --- Minyon canı çıkarma (geliştirilmiş, çeşitli yolları dener) ---
217
+ function extractMinyonCanFromSlot(slot) {
 
 
 
 
 
 
 
 
 
 
218
  try {
219
+ if (!slot) return null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
220
 
221
+ function tryParseLoreText(text) {
222
  try {
223
+ if (!text || typeof text !== "string") return null;
224
+ let plain = text;
225
+ try {
226
+ const maybe = JSON.parse(text);
227
+ if (maybe && typeof maybe === "object") {
228
+ if (maybe.extra && Array.isArray(maybe.extra) && maybe.extra.length > 0) {
229
+ if (typeof maybe.extra[0].text === "string") plain = maybe.extra[0].text;
230
+ else plain = JSON.stringify(maybe.extra);
231
+ } else if (typeof maybe.text === "string") {
232
+ plain = maybe.text;
233
+ } else {
234
+ plain = JSON.stringify(maybe);
235
+ }
236
  }
237
+ } catch (e) {}
238
+ const xyMatch = plain.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
239
+ if (xyMatch) {
240
+ const x = Number(xyMatch[1]);
241
+ if (!Number.isNaN(x)) return x;
242
  }
243
+ const numMatch = plain.match(/(\d{1,4})/);
244
+ if (numMatch) {
245
+ const n = Number(numMatch[1]);
246
+ if (!Number.isNaN(n)) return n;
 
 
 
 
 
247
  }
248
+ return null;
249
+ } catch (e) {
250
+ return null;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
 
 
 
 
 
 
 
 
 
 
 
252
  }
253
 
254
+ // 1) slot.nbt yolları
 
 
 
 
 
 
 
 
 
255
  if (slot.nbt) {
256
  try {
257
  const candidates = [
 
259
  ["value", "display", "value", "Lore"],
260
  ["value", "display", "value"],
261
  ];
 
262
  for (const path of candidates) {
263
  let cur = slot.nbt;
264
  let ok = true;
 
267
  cur = cur[p];
268
  }
269
  if (!ok) continue;
 
270
  if (Array.isArray(cur) && cur.length > 0) {
271
  const tryIndices = [1, cur.length - 1, 0];
272
  for (const idx of tryIndices) {
 
297
  } catch (e) {}
298
  }
299
 
300
+ // 2) components içinde custom_data veya lore
301
  try {
302
  if (Array.isArray(slot.components)) {
303
  for (const c of slot.components) {
 
314
  if (parsed != null) return parsed;
315
  }
316
  }
 
317
  if (c.type === "lore" && Array.isArray(c.data)) {
318
  for (const entry of c.data) {
319
  const text = safeGet(entry, ["value", "text", "value"]) || safeGet(entry, ["value", "extra", "value", 0, "value", "text", "value"]) || (entry && entry.toString && entry.toString());
 
325
  }
326
  } catch (e) {}
327
 
328
+ // 3) componentMap kontrolü
329
  try {
330
  if (slot.componentMap && typeof slot.componentMap === "object") {
331
  const getFromMap = (m, key) => {
 
334
  return m[key];
335
  } catch (e) { return null; }
336
  };
 
337
  const loreComp = getFromMap(slot.componentMap, "custom_data") || getFromMap(slot.componentMap, "lore");
338
  if (loreComp) {
339
  const data = loreComp.data || loreComp;
 
354
  }
355
  } catch (e) {}
356
 
357
+ // 4) fallback: inspect tüm slot
358
  try {
359
  const full = util.inspect(slot, { depth: null, maxArrayLength: null });
360
+ const xyMatch = full.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
361
+ if (xyMatch) return Number(xyMatch[1]);
362
+ const numMatch = full.match(/(\d{1,4})/);
363
+ if (numMatch) return Number(numMatch[1]);
364
  } catch (e) {}
365
 
366
  return null;
 
370
  }
371
  }
372
 
373
+ // --- Activate API detection (startup) ---
374
+ let hasActivateAt = false;
375
+ let hasActivate = false;
376
+ function detectActivateApis() {
377
+ hasActivateAt = typeof bot.activateEntityAt === "function";
378
+ hasActivate = typeof bot.activateEntity === "function";
379
+ }
380
 
381
+ // safe activate: prefer activateEntityAt, minimal logging
382
+ async function safeActivateEntityPreferAt(entity, options = {}) {
383
+ const maxRetries = options.maxRetries ?? 3;
384
+ const retryDelay = options.retryDelay ?? 250;
385
+ const requireLook = options.requireLook ?? true;
386
+ const maxDistance = options.maxDistance ?? 7;
387
+
388
+ if (!entity) {
389
+ logger.warn("safeActivateEntityPreferAt: entity yok");
390
+ return false;
391
+ }
392
+
393
+ try {
394
+ if (entity.position && bot.entity && bot.entity.position) {
395
+ const dist = entity.position.distanceTo(bot.entity.position);
396
+ if (dist > maxDistance) {
397
+ logger.warn(`safeActivateEntityPreferAt: entity id:${entity.id} uzak (${dist.toFixed(2)}). Max ${maxDistance} blok.`);
398
+ return false;
399
  }
 
 
400
  }
401
 
402
+ if (requireLook && entity.position && bot.lookAt) {
403
+ try {
404
+ const lookPos = (typeof entity.position.offset === "function")
405
+ ? entity.position.offset(0, 1.5, 0)
406
+ : { x: entity.position.x, y: entity.position.y + 1.5, z: entity.position.z };
407
+ await bot.lookAt(lookPos, true);
408
+ await new Promise(r => setTimeout(r, 180));
409
+ } catch (e) {}
410
  }
411
 
412
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
413
+ try {
414
+ if (hasActivateAt) {
415
+ try {
416
+ bot.activateEntityAt(entity, entity.position);
417
+ logger.info(`activateEntityAt çağrıldı id:${entity.id}`);
418
+ return true;
419
+ } catch (err) {
420
+ // retry silently
421
+ }
422
+ }
423
+ if (hasActivate) {
424
+ try {
425
+ bot.activateEntity(entity);
426
+ logger.info(`activateEntity çağrıldı id:${entity.id}`);
427
+ return true;
428
+ } catch (err) {
429
+ // retry silently
430
+ }
431
+ }
432
+ } catch (err) {
433
+ // swallow and retry
434
+ }
435
+ await new Promise(r => setTimeout(r, retryDelay));
436
  }
437
 
438
+ logger.warn(`safeActivateEntityPreferAt: tüm denemeler başarısız id:${entity.id}`);
439
+ return false;
440
+ } catch (err) {
441
+ logger.error(`safeActivateEntityPreferAt hata: ${err && err.stack ? err.stack : err}`);
442
+ return false;
443
  }
444
  }
445
 
446
+ // windowOpen wait helper (mevcut resolver mantığını koruyor)
447
+ function waitForWindowOpenOrTimeout(timeoutMs) {
448
+ return new Promise((resolve) => {
449
+ try {
450
+ if (bot.currentWindow && bot.currentWindow.type) {
451
+ resolve({ opened: true });
452
+ return;
453
+ }
454
+ } catch (e) {}
455
 
456
+ const timer = setTimeout(() => {
457
+ const idx = windowOpenResolvers.indexOf(resolver);
458
+ if (idx !== -1) windowOpenResolvers.splice(idx, 1);
459
+ resolve({ opened: false, timedOut: true });
460
+ }, timeoutMs);
461
 
462
+ function resolver() {
463
+ clearTimeout(timer);
464
+ resolve({ opened: true, timedOut: false });
 
 
 
 
465
  }
466
 
467
+ windowOpenResolvers.push(resolver);
468
+ });
469
+ }
470
 
471
+ // --- GO / SCAN / RETURN helpers ---
472
+ async function goHome() {
473
+ try {
474
+ logger.info(`[${config["bot-account"]["username"]}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
475
+ bot.chat(GO_HOME_COMMAND);
476
+ } catch (e) {
477
+ logger.warn("goHome: komut gönderilemedi: " + (e && e.message ? e.message : e));
478
+ }
479
+ }
480
 
481
+ async function returnIsland() {
482
+ try {
483
+ bot.chat(RETURN_ISLAND_COMMAND);
484
+ } catch (e) {
485
+ logger.warn("returnIsland: komut gönderilemedi: " + (e && e.message ? e.message : e));
486
+ }
487
+ }
488
+
489
+ // Scan & feed mantığı (aynı işleyiş korunuyor)
490
+ async function scanAndFeed() {
491
+ try {
492
+ // Eğer son tam beslemeden (veya can 10 görüldüğünden) henüz FULL_FEED_COOLDOWN_MS geçmediyse atla
493
+ if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) {
494
+ // sessizce atla; log spam olmasın
495
  return;
496
  }
497
 
 
498
  const arr = Object.values(bot.entities);
499
  if (!arr || arr.length === 0) {
500
  logger.info(`[${config["bot-account"]["username"]}] /home sonrası: entity bulunamadı.`);
501
+ return;
502
+ }
 
 
 
503
 
504
+ // 1) quick checks
505
+ let found = null;
506
+ let foundPath = null;
507
+ for (const e of arr) {
508
+ const name = getEntityReadableName(e);
509
+ if (isBesleyiciName(name)) {
510
+ found = e;
511
+ foundPath = "displayName/name";
512
+ break;
513
  }
514
+ }
515
 
516
+ // 2) metadata quick path
517
+ if (!found) {
518
+ for (const e of arr) {
519
+ const candidate = safeGet(e, ["metadata", 2, "value", "extra", "value", "value", 0]);
520
+ if (candidate) {
521
+ let candidateStr = null;
522
+ try {
523
+ if (typeof candidate === "string") candidateStr = candidate;
524
+ else if (candidate && typeof candidate.toString === "function") candidateStr = candidate.toString();
525
+ else candidateStr = util.inspect(candidate, { depth: 1 });
526
+ } catch (err) {
527
+ candidateStr = String(candidate);
 
 
 
 
 
 
528
  }
529
+ if (TARGET_NAME_NORMS.some(t => normalizeForMatch(candidateStr).includes(t))) {
 
 
 
 
 
 
 
530
  found = e;
531
+ foundPath = "metadata[2].value.extra.value.value[0]";
532
  break;
533
  }
534
  }
535
  }
536
+ }
537
 
538
+ // 3) deep search only if still not found
539
+ if (!found) {
540
+ for (const e of arr) {
541
+ const matches = deepSearchForString(e, TARGET_NAME_NORMS[0]);
542
+ if (matches && matches.length > 0) {
543
+ found = e;
544
+ foundPath = matches[0].path;
545
+ break;
 
 
 
 
 
 
 
 
 
 
 
 
546
  }
 
 
547
  }
548
  }
549
 
550
+ if (!found) {
551
+ logger.info(`[${config["bot-account"]["username"]}] /home sonrası tarama: besleyici minyon bulunamadı.`);
552
+ return;
 
 
 
553
  }
 
 
 
 
 
 
 
554
 
555
+ const readable = getEntityReadableName(found);
556
+ const dist = (found.position && bot.entity && bot.entity.position) ? found.position.distanceTo(bot.entity.position).toFixed(2) : "n/a";
557
+ logger.info(`[${config["bot-account"]["username"]}] '${readable || BESLEYICI_NAMES[0]}' bulundu id:${found.id} path:${foundPath} dist:${dist} — aktive ediliyor.`);
 
 
 
 
 
558
 
559
+ detectActivateApis();
560
+
561
+ const activated = await safeActivateEntityPreferAt(found, { maxRetries: 4, retryDelay: 300, requireLook: true, maxDistance: 7 });
562
+ if (!activated) {
563
+ logger.warn(`[${config["bot-account"]["username"]}] '${BESLEYICI_NAMES[0]}' aktive edilemedi (id:${found.id}).`);
564
+ return;
565
+ }
566
+
567
+ // wait for windowOpen (handler will process and set lastFullFeedAt if needed)
568
+ const waitResult = await waitForWindowOpenOrTimeout(WINDOW_OPEN_TIMEOUT_MS);
569
+ if (waitResult.opened) {
570
+ await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
571
+ } else {
572
+ logger.warn(`[${config["bot-account"]["username"]}] Panel açılmadı veya timeout oldu; devam ediliyor.`);
573
+ await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
574
+ }
575
+ } catch (err) {
576
+ logger.error("scanAndFeed hata: " + (err && err.stack ? err.stack : err));
577
+ }
578
  }
579
 
580
  // --- Bot olayları ve ana mantık ---
 
584
  bot.settings.colorsEnabled = false;
585
  logger.info("Bot sunucuya giriş yaptı.");
586
 
587
+ detectActivateApis();
588
+
589
+ if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
590
+ const password = config.utils["auto-auth"].password;
591
  setTimeout(() => {
592
  bot.chat(`/login ${password}`);
593
  logger.info(`[${config["bot-account"]["username"]}] Login komutu kullanıldı.`);
594
  }, 500);
595
 
596
+ setTimeout(() => {
597
  bot.chat(`/skyblock`);
598
  logger.info(`[${config["bot-account"]["username"]}] Skyblock'a ışınlanma komutu kullanıldı.`);
599
  }, 5000);
600
 
601
+ // İlk döngü: goHome -> scanAndFeed -> returnIsland
602
  setTimeout(async () => {
603
+ await goHome();
604
+ await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
605
+ await scanAndFeed();
606
+ await returnIsland();
607
  startPeriodicHomeChecks();
608
  }, 10000);
609
  } else {
610
  startPeriodicHomeChecks();
611
  }
612
 
613
+ // chat-messages, position, anti-afk mantığı aynen korunuyor
614
+ if (config.utils && config.utils["chat-messages"] && config.utils["chat-messages"].enabled) {
615
  logger.info("Started chat-messages module");
616
  let messages = config.utils["chat-messages"]["messages"];
617
  if (config.utils["chat-messages"].repeat) {
 
628
  }
629
 
630
  const pos = config.position;
631
+ if (config.position && config.position.enabled) {
632
  logger.info(`Starting moving to target location (${pos.x}, ${pos.y}, ${pos.z})`);
633
  bot.pathfinder.setGoal(new GoalBlock(pos.x, pos.y, pos.z));
634
  }
635
 
636
+ if (config.utils && config.utils["anti-afk"] && config.utils["anti-afk"].enabled) {
637
  if (config.utils["anti-afk"].sneak) bot.setControlState("sneak", true);
638
  if (config.utils["anti-afk"].jump) bot.setControlState("jump", true);
639
 
640
+ if (config.utils["anti-afk"]["hit"] && config.utils["anti-afk"]["hit"].enabled) {
641
  let delay = config.utils["anti-afk"]["hit"]["delay"];
642
  let attackMobs = config.utils["anti-afk"]["hit"]["attack-mobs"];
643
  setInterval(() => {
 
665
  }, 100);
666
  }
667
 
668
+ if (config.utils["anti-afk"]["circle-walk"] && config.utils["anti-afk"]["circle-walk"].enabled) {
669
  let radius = config.utils["anti-afk"]["circle-walk"]["radius"];
670
  setInterval(() => {
671
  circleWalk(bot, radius);
 
674
  }
675
  });
676
 
677
+ // windowClose: resolver'ları çözer
678
  bot.on("windowClose", (window) => {
679
  try {
680
  while (windowOpenResolvers.length > 0) {
 
684
  } catch (e) {}
685
  });
686
 
687
+ // windowOpen: minimal log, tek satır sonuç; burada lastFullFeedAt ayarlanır
688
  bot.on("windowOpen", function (window) {
689
  try {
690
+ const titleStr = parseWindowTitleToString(window.title);
 
691
  const panelMatch = (titleStr && (titleStr.toLowerCase().includes("besleyici") || titleStr.includes("ʙᴇsʟᴇʏiᴄi")));
692
  if (!panelMatch) {
693
  try { bot.closeWindow(window); } catch (e) {}
 
701
  }
702
 
703
  const beefSlots = window.slots.filter(xx => xx?.name && xx?.name === "cooked_beef");
704
+ if (beefSlots.length === 0) {
705
+ try { bot.closeWindow(window); } catch (e) {}
706
+ try {
707
+ while (windowOpenResolvers.length > 0) {
708
+ const r = windowOpenResolvers.shift();
709
+ try { r(); } catch (e) {}
710
+ }
711
+ } catch (e) {}
712
+ return;
713
+ }
714
 
715
+ const beefSlot = beefSlots[0];
716
+ const minyoncani = extractMinyonCanFromSlot(beefSlot);
 
 
 
717
 
718
+ if (minyoncani == null) {
719
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı okunamadı (null).`);
720
+ } else if (minyoncani <= 2) {
721
+ // Besleme yapıldı
722
+ bot.clickWindow(36, 0, 0);
723
+ lastFullFeedAt = Date.now(); // besleme yapıldığı an 30dk bekle
724
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için besleyici ile beslendi. 30dk bekleme aktif.`);
725
+ try { bot.closeWindow(window); } catch (e) {}
726
+ } else {
727
+ // Eğer can 10 ise veya yüksekse, 30dk bekleme kuralını tetikle
728
+ if (minyoncani >= 10) {
729
+ lastFullFeedAt = Date.now();
730
+ logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} (tam). 30dk bekleme aktif.`);
731
  } else {
732
  logger.info(`[${config["bot-account"]["username"]}] Minyon canı ${minyoncani} olduğu için yenilenmedi.`);
 
733
  }
 
734
  try { bot.closeWindow(window); } catch (e) {}
735
  }
736
 
 
753
  });
754
 
755
  bot.on("chat", (username, message) => {
756
+ if (config.utils && config.utils["chat-log"]) logger.info(`<${username}> ${message}`);
757
  });
758
 
759
  bot.on("goal_reached", () => {
760
+ if (config.position && config.position.enabled) logger.info(`Bot arrived to target location. ${bot.entity.position}`);
761
  });
762
 
763
  bot.on("death", () => {
764
  logger.warn(`Bot has been died and was respawned at ${bot.entity.position}`);
765
  });
766
 
767
+ if (config.utils && config.utils["auto-reconnect"]) {
768
  bot.on("end", () => {
769
  setTimeout(() => createBot(), config.utils["auto-reconnect-delay"]);
770
  });
 
776
  const parsed = JSON.parse(reason);
777
  reasonText = parsed.text || parsed.extra?.[0]?.text || "";
778
  reasonText = reasonText?.replace(/§./g, "");
779
+ logger.warn(`Bot sunucudan atıldı. Sebep: ${reasonText}`);
780
  } catch {
781
+ logger.warn(`Bot sunucudan atıldı. Sebep: Bulunamadı.`);
782
  }
783
  });
784
 
785
+ bot.on("error", (err) => logger.error(`${err && err.message ? err.message : err}`));
786
 
787
+ // process message dump helper
788
  process.on("message", (msg) => {
789
  try {
790
  if (!msg) return;
 
794
  }
795
  } catch (e) {}
796
  });
 
797
 
798
+ // --- Periyodik kontrol başlatma/durdurma ---
799
+ let periodicHandle = null;
800
+ function startPeriodicHomeChecks() {
801
+ if (periodicHandle) return;
802
+ periodicHandle = setInterval(() => {
803
+ (async () => {
804
+ try {
805
+ // Eğer son tam beslemeden (veya can 10 görüldüğünden) henüz FULL_FEED_COOLDOWN_MS geçmediyse atla
806
+ if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) {
807
+ return;
808
+ }
809
+ await goHome();
810
+ await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
811
+ await scanAndFeed();
812
+ await returnIsland();
813
+ } catch (e) {}
814
+ })();
815
+ }, PERIODIC_CHECK_INTERVAL_MS);
816
+ }
817
+
818
+ function stopPeriodicHomeChecks() {
819
+ if (!periodicHandle) return;
820
+ clearInterval(periodicHandle);
821
+ periodicHandle = null;
822
+ }
823
+
824
+ // circleWalk fonksiyonu (orijinal)
825
+ function circleWalk(botRef, radius) {
826
+ return new Promise(() => {
827
+ const pos = botRef.entity.position;
828
+ const x = pos.x;
829
+ const y = pos.y;
830
+ const z = pos.z;
831
+
832
+ const points = [
833
+ [x + radius, y, z],
834
+ [x, y, z + radius],
835
+ [x - radius, y, z],
836
+ [x, y, z - radius],
837
+ ];
838
+
839
+ let i = 0;
840
+ setTimeout(() => {
841
+ if (i === points.length) i = 0;
842
+ const defaultMove = new Movements(botRef);
843
+ botRef.pathfinder.setMovements(defaultMove);
844
+ botRef.pathfinder.setGoal(new GoalXZ(points[i][0], points[i][2]));
845
+ i++;
846
+ }, 1000);
847
+ });
848
+ }
849
+
850
+ // startPeriodicHomeChecks çağrısı spawn içinde veya auto-auth sonrası yapılıyor
851
+ // createBot fonksiyonu sonu
852
  }
853
 
854
+ // create bot ve küçük web ping
855
  createBot();
856
 
857
  const express = require("express");
858
  const app = express();
859
  const port = process.env.PORT || 7860;
 
860
  app.get("/", (req, res) => res.send("Pinglendi"));
 
861
  app.listen(port, () => logger.info(`Bot bu adres üzerinde çalışıyor: http://localhost:${port}`));
862
 
863
  process.on("uncaughtException", function (err) {