SlnDmry commited on
Commit
134d06d
·
verified ·
1 Parent(s): 1ecf295

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +33 -563
bot.js CHANGED
@@ -1,62 +1,11 @@
1
- const mineflayer = require("mineflayer");
2
- const mineflayerViewer = require('prismarine-viewer').mineflayer;
3
- const Movements = require("mineflayer-pathfinder").Movements;
4
- const pathfinder = require("mineflayer-pathfinder").pathfinder;
5
- const { GoalBlock, GoalXZ } = require("mineflayer-pathfinder").goals;
6
- const util = require("util");
7
- const { SocksClient } = require('socks');
8
- const { Client } = require('ssh2');
9
-
10
- const config = require("./settings.json");
11
- const loggers = require("./logging.js");
12
- const logger = loggers.logger;
13
-
14
- const https = require('https');
15
-
16
- // Küresel tanımlamalar (Orijinal yerlerinde kaldı)
17
- const HOME_ARRIVAL_DELAY_MS = 2000;
18
- const POST_ACTION_DELAY_MS = 4000;
19
- const WINDOW_OPEN_TIMEOUT_MS = 6000;
20
- const PERIODIC_CHECK_INTERVAL_MS = 10 * 60 * 1000;
21
- const FULL_FEED_COOLDOWN_MS = 50 * 60 * 1000;
22
- const GO_HOME_COMMAND = "/home";
23
- const RETURN_ISLAND_COMMAND = "/is home";
24
- const BESLEYICI_NAMES = (config.utils && config.utils["besleyici-names"]) || ["Besleyici", "ʙᴇsʟᴇʏiᴄi"];
25
- let viewerInstance = null;
26
- let viewerTimeout = null;
27
- let bot = null;
28
- let botIsReady = false;
29
- let baglantiTuru = "Yok";
30
- let activeMessages = [];
31
- let messagesTimeout = null;
32
- const ansiToHtmlConvert = new (require('ansi-to-html'))({ newline: true });
33
-
34
- let isFinished = false;
35
-
36
- // Dış IP Öğrenme İsteği
37
- https.get('https://api.ipify.org?format=json', (res) => {
38
- let data = '';
39
- res.on('data', chunk => { data += chunk; });
40
- res.on('end', () => {
41
- try {
42
- const ipInfo = JSON.parse(data);
43
- console.log(`Dış IP adresin: ${ipInfo.ip}`);
44
- } catch (err) {
45
- console.error('JSON parse hatası:', err);
46
- }
47
- });
48
- }).on('error', (err) => {
49
- console.error('İstek hatası:', err);
50
- });
51
-
52
  async function createBot() {
53
  const net = require('net');
54
  const sshClient = new Client();
55
  isFinished = false; // Her yeni bot oluştuğunda durumu sıfırla
56
 
57
- // --- GİTHUB CONFIG ÇEKME AŞAMASI ---
58
  const githubRawUrl = 'https://raw.githubusercontent.com/suvarileader/che/refs/heads/main/doc/ower/doc.json';
59
- logger.info("[GitHub Config] Güncel hesap ve sunucu bilgileri GitHub'dan çekiliyor...");
60
 
61
  let remoteData = null;
62
  try {
@@ -73,39 +22,46 @@ async function createBot() {
73
  });
74
  }).on('error', (err) => reject(err));
75
  });
76
- logger.info("[GitHub Config] Dosya başarıyla indirildi.");
77
  } catch (err) {
78
- logger.error(`[GitHub Config Hatası] Veri alınamadı: ${err.message}. Yerel config ile devam ediliyor...`);
79
  }
80
 
81
- // Kullanılacak dinamik değişkenler
82
- let currentBotUsername = config["bot-account"]["username"];
83
- let targetServerIp = config.server.ip;
84
- let targetServerPort = config.server.port;
 
 
 
 
 
 
85
 
 
86
  if (remoteData && Array.isArray(remoteData)) {
87
- // Listede local settings.json'daki bot adını ara
88
  const myConfig = remoteData.find(item => item.account === currentBotUsername);
89
  if (myConfig) {
90
- logger.info(`[GitHub Config] '${currentBotUsername}' kullanıcısı için uzaktaki ayarlar uygulandı.`);
 
 
91
  if (myConfig.serverName && myConfig.serverName !== "empty") {
92
- targetServerIp = myConfig.serverName;
93
  }
 
94
  if (myConfig.username && myConfig.username !== "empty") {
95
- currentBotUsername = myConfig.username;
96
  }
 
97
  } else {
98
- logger.warn(`[GitHub Config] Listede '${currentBotUsername}' eşleşmesi bulunamadı! Yerel ayarlar geçerli.`);
99
  }
100
  }
101
 
102
- // Sabit SSH Bilgileri
103
- const sshConfig = {
104
- host: 'tr1.vpnjantit.com',
105
- port: 22,
106
- username: 'suvaa-vpnjantit.com',
107
- password: 'suvaa'
108
- };
109
 
110
  // Mineflayer Başlatılıyor
111
  bot = mineflayer.createBot({
@@ -119,7 +75,7 @@ async function createBot() {
119
  let fallbackTriggered = false;
120
  let isFinalFailureHandled = false;
121
 
122
- // İki seçeneğin de patladığı kritik senaryoda döngüyü sıfırlayan ana merkez
123
  const handleFinalFailure = (reason) => {
124
  if (isFinalFailureHandled) return;
125
  isFinalFailureHandled = true;
@@ -143,7 +99,7 @@ async function createBot() {
143
  }
144
  };
145
 
146
- // SSH Patladığında Gerçek TCP Soketi Açan Fonksiyon
147
  const connectDirectly = (reason) => {
148
  if (fallbackTriggered) return;
149
  fallbackTriggered = true;
@@ -157,7 +113,6 @@ async function createBot() {
157
  port: parseInt(targetServerPort) || 25565
158
  });
159
 
160
- // Normal IP bağlantısı için 10 saniye limit
161
  const directTimeout = setTimeout(() => {
162
  socket.destroy();
163
  handleFinalFailure("Normal IP bağlantısı zaman aşımına uğradı (Sunucu yanıt vermiyor)");
@@ -183,9 +138,9 @@ async function createBot() {
183
  });
184
  };
185
 
186
- logger.info(`[SSH Tünel] ${sshConfig.host} sunucusuna bağlanılıyor...`);
 
187
 
188
- // SSH İlk Bağlantı Zaman Aşımı (10 Saniye)
189
  const connectionTimeout = setTimeout(() => {
190
  connectDirectly("SSH Bağlantı Zaman Aşımı (10 saniye yanıt alınamadı)");
191
  }, 10000);
@@ -194,6 +149,7 @@ async function createBot() {
194
  clearTimeout(connectionTimeout);
195
  logger.info('[SSH Tünel] SSH bağlantısı başarılı. Minecraft sunucusuna tünel açılıyor...');
196
 
 
197
  sshClient.forwardOut(
198
  '127.0.0.1',
199
  12345,
@@ -238,490 +194,4 @@ async function createBot() {
238
 
239
  bot.loadPlugin(pathfinder);
240
 
241
- // --- SADECE TİMİNG SIFIRLAMA İÇİN EKLENEN KISIM ---
242
- let lastFullFeedAt = 0;
243
- let windowOpenResolvers = [];
244
- let periodicHandle = null;
245
- let activeTimeouts = [];
246
-
247
- function setSafeTimeout(fn, delay) {
248
- const t = setTimeout(fn, delay);
249
- activeTimeouts.push(t);
250
- return t;
251
- }
252
-
253
- function stopPeriodicHomeChecks() {
254
- if (periodicHandle) clearInterval(periodicHandle);
255
- periodicHandle = null;
256
- activeTimeouts.forEach(t => clearTimeout(t));
257
- activeTimeouts = [];
258
- }
259
- // ------------------------------------------------
260
-
261
- // --- SENİN ORİJİNAL FONKSİYONLARIN ---
262
- function stripColorCodes(s) {
263
- if (!s || typeof s !== "string") return s;
264
- return s.replace(/§[0-9a-fk-or]/gi, "");
265
- }
266
-
267
- function safeDisplayNameToString(e) {
268
- try {
269
- if (e && e.displayName && typeof e.displayName.toString === "function") {
270
- return e.displayName.toString();
271
- }
272
- } catch (err) {}
273
- return null;
274
- }
275
-
276
- function getEntityReadableName(e) {
277
- if (!e) return "";
278
- const disp = safeDisplayNameToString(e);
279
- if (disp) return stripColorCodes(disp);
280
- if (e.name && typeof e.name === "string") return stripColorCodes(e.name);
281
- if (e.username && typeof e.username === "string") return stripColorCodes(e.username);
282
- return "";
283
- }
284
-
285
- function normalizeForMatch(s) {
286
- if (!s || typeof s !== "string") return "";
287
- let t = stripColorCodes(s);
288
- if (t.normalize) t = t.normalize("NFKD").replace(/[\u0300-\u036f]/g, "");
289
- return t.toLowerCase();
290
- }
291
-
292
- const TARGET_NAME_NORMS = BESLEYICI_NAMES.map(n => normalizeForMatch(n));
293
-
294
- function isBesleyiciName(name) {
295
- if (!name) return false;
296
- const norm = normalizeForMatch(name);
297
- return TARGET_NAME_NORMS.some(t => norm.includes(t));
298
- }
299
-
300
- // safeGet, deepSearchForString, parseWindowTitleToString, extractMinyonCanFromSlot fonksiyonları aynen korundu
301
- function safeGet(obj, pathArray) {
302
- try {
303
- let cur = obj;
304
- for (const p of pathArray) {
305
- if (cur == null) return undefined;
306
- cur = cur[p];
307
- }
308
- return cur;
309
- } catch (e) { return undefined; }
310
- }
311
-
312
- function deepSearchForString(root, targetLower) {
313
- const results = [];
314
- const visited = new WeakSet();
315
- function recurse(obj, path) {
316
- if (obj == null || typeof obj === "function") return;
317
- if (typeof obj === "string") {
318
- const norm = normalizeForMatch(obj);
319
- if (norm.includes(targetLower)) results.push({ path, value: obj });
320
- return;
321
- }
322
- if (typeof obj !== "object") return;
323
- if (visited.has(obj)) return;
324
- visited.add(obj);
325
- for (const key of Object.keys(obj)) {
326
- recurse(obj[key], `${path}.${key}`);
327
- }
328
- }
329
- try { recurse(root, "root"); } catch (e) {}
330
- return results;
331
- }
332
-
333
- function parseWindowTitleToString(titleObj) {
334
- try {
335
- if (!titleObj) return "";
336
- if (typeof titleObj === "string") return titleObj;
337
- const s = titleObj.toString();
338
- if (s && s !== "[object Object]") return s;
339
- return JSON.stringify(titleObj);
340
- } catch (err) { return ""; }
341
- }
342
-
343
- function extractMinyonCanFromSlot(slot) {
344
- try {
345
- if (!slot) return null;
346
- function tryParseLoreText(text) {
347
- try {
348
- if (!text || typeof text !== "string") return null;
349
- let plain = text;
350
- try {
351
- const maybe = JSON.parse(text);
352
- if (maybe && typeof maybe === "object") {
353
- if (maybe.extra && Array.isArray(maybe.extra) && maybe.extra.length > 0) {
354
- if (typeof maybe.extra[0].text === "string") plain = maybe.extra[0].text;
355
- } else if (typeof maybe.text === "string") {
356
- plain = maybe.text;
357
- }
358
- }
359
- } catch (e) {}
360
- const xyMatch = plain.match(/(\d{1,4})\s*\/\s*(\d{1,4})/);
361
- if (xyMatch) return Number(xyMatch[1]);
362
- const numMatch = plain.match(/(\d{1,4})/);
363
- if (numMatch) return Number(numMatch[1]);
364
- return null;
365
- } catch (e) { return null; }
366
- }
367
- if (slot.nbt) {
368
- const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
369
- if (Array.isArray(lore)) {
370
- for (const line of lore) {
371
- const res = tryParseLoreText(line.value || line);
372
- if (res != null) return res;
373
- }
374
- }
375
- }
376
- const full = util.inspect(slot, { depth: null });
377
- return tryParseLoreText(full);
378
- } catch (err) { return null; }
379
- }
380
-
381
- async function goHome() {
382
- logger.info(`[${currentBotUsername}] ${GO_HOME_COMMAND} komutu gönderiliyor.`);
383
- bot.chat(GO_HOME_COMMAND);
384
- }
385
-
386
- async function returnIsland() {
387
- logger.info(`[${currentBotUsername}] ${RETURN_ISLAND_COMMAND} komutu gönderiliyor.`);
388
- bot.chat(RETURN_ISLAND_COMMAND);
389
- }
390
-
391
- async function scanAndFeed() {
392
- if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
393
- const arr = Object.values(bot.entities);
394
- let best = null;
395
-
396
- for (const e of arr) {
397
- const name = getEntityReadableName(e);
398
- if (isBesleyiciName(name)) {
399
- best = { entity: e, path: "displayName/name" };
400
- break;
401
- }
402
- for (const target of TARGET_NAME_NORMS) {
403
- const deep = deepSearchForString(e, target);
404
- if (deep.length > 0) {
405
- best = { entity: e, path: deep[0].path };
406
- break;
407
- }
408
- }
409
- if (best) break;
410
- }
411
-
412
- if (!best) {
413
- logger.info(`[${currentBotUsername}] /home sonrası tarama: besleyici minyon bulunamadı.`);
414
- bot.chat("/skyblock");
415
- return;
416
- }
417
-
418
- const dist = bot.entity.position.distanceTo(best.entity.position);
419
- logger.info(`[${currentBotUsername}] '${best.entity.name || 'Armor Stand'}' bulundu id:${best.entity.id} path:${best.path} dist:${dist.toFixed(2)} — aktive ediliyor.`);
420
-
421
- if (dist > 7) {
422
- logger.warn(`safeActivateEntityPreferAt: entity id:${best.entity.id} uzak (${dist.toFixed(2)}). Max 7 blok.`);
423
- logger.warn(`[${currentBotUsername}] 'Besleyici' aktive edilemedi (id:${best.entity.id}).`);
424
- return;
425
- }
426
-
427
- try {
428
- if (bot.lookAt) await bot.lookAt(best.entity.position.offset(0, 1.0, 0), true);
429
- await new Promise(r => setTimeout(r, 200));
430
-
431
- logger.info(`activateEntityAt çağrıldı id:${best.entity.id}`);
432
- if (typeof bot.activateEntityAt === "function") bot.activateEntityAt(best.entity, best.entity.position);
433
- else if (typeof bot.activateEntity === "function") bot.activateEntity(best.entity);
434
-
435
- await new Promise((resolve) => {
436
- const timer = setSafeTimeout(() => resolve(), WINDOW_OPEN_TIMEOUT_MS);
437
- windowOpenResolvers.push(() => { clearTimeout(timer); resolve(); });
438
- });
439
- } catch (err) {}
440
- }
441
-
442
- bot.once("spawn", async () => {
443
- bot.pathfinder.setMovements(new Movements(bot));
444
- logger.info("Bot sunucuya giriş yaptı.");
445
- botIsReady = true;
446
- isFinished = true;
447
-
448
- if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
449
- const password = config.utils["auto-auth"].password;
450
-
451
- setSafeTimeout(() => {
452
- bot.chat(`/login ${password}`);
453
- logger.info(`[${currentBotUsername}] Login komutu kullanıldı.`);
454
- }, 2500);
455
-
456
- setSafeTimeout(() => {
457
- bot.chat(`/skyblock`);
458
- logger.info(`[${currentBotUsername}] Skyblock'a ışınlanma komutu kullanıldı.`);
459
- }, 7500);
460
-
461
- setSafeTimeout(async () => {
462
- await goHome();
463
- await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
464
- await scanAndFeed();
465
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
466
- await returnIsland();
467
-
468
- periodicHandle = setInterval(async () => {
469
- if (Date.now() < (lastFullFeedAt + FULL_FEED_COOLDOWN_MS)) return;
470
- await goHome();
471
- await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
472
- await scanAndFeed();
473
- await new Promise(r => setTimeout(r, POST_ACTION_DELAY_MS));
474
- await returnIsland();
475
- }, PERIODIC_CHECK_INTERVAL_MS);
476
- }, 12500);
477
- }
478
- });
479
-
480
- bot.on("windowOpen", (window) => {
481
- const title = parseWindowTitleToString(window.title).toLowerCase();
482
- if (!title.includes("besleyici") && !parseWindowTitleToString(window.title).includes("ʙᴇsʟᴇʏiᴄi")) {
483
- logger.info(`[${currentBotUsername}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${parseWindowTitleToString(window.title)}`);
484
- bot.closeWindow(window);
485
- return;
486
- }
487
- const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
488
- const can = extractMinyonCanFromSlot(beefSlot);
489
- if (can != null) {
490
- if (can <= 2) {
491
- bot.clickWindow(36, 0, 0);
492
- lastFullFeedAt = Date.now();
493
- logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için beslendi. 50dk bekleme aktif.`);
494
- } else if (can >= 10) {
495
- lastFullFeedAt = Date.now();
496
- logger.info(`[${currentBotUsername}] Minyon canı ${can} (tam). 50dk bekleme aktif.`);
497
- } else {
498
- logger.info(`[${currentBotUsername}] Minyon canı ${can} olduğu için yenilenmedi.`);
499
- }
500
- }
501
- setSafeTimeout(() => { try { bot.closeWindow(window); } catch(e){} }, 500);
502
- while (windowOpenResolvers.length > 0) windowOpenResolvers.shift()();
503
- });
504
-
505
- bot.on("end", () => {
506
- if (isFinished) return;
507
- isFinished = true;
508
-
509
- logger.warn("Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor...");
510
- stopPeriodicHomeChecks();
511
- botIsReady = false;
512
- baglantiTuru = "Yok";
513
- bot = null;
514
-
515
- if (config.utils && config.utils["auto-reconnect"]) {
516
- setTimeout(() => createBot(), config.utils["auto-reconnect-delay"]);
517
- }
518
- });
519
-
520
- bot.on("kicked", (reason) => logger.warn(`Bot sunucudan atıldı: ${util.inspect(reason)}`));
521
- bot.on("error", (err) => logger.error(`${err}`));
522
- }
523
-
524
- createBot();
525
-
526
- // --- EXPRESS SUNUCUSU VE PANEL ENTEGRASYONU ---
527
- const express = require("express");
528
- const app = express();
529
- const http = require('http');
530
-
531
- function minecraftMessageListener(jsonMsg) {
532
- try {
533
- const chatMessage = bot.chat.ChatMessage ? new bot.chat.ChatMessage(jsonMsg) : jsonMsg;
534
- const coloredAnsi = typeof chatMessage.toAnsi === 'function' ? chatMessage.toAnsi() : chatMessage.toString();
535
- const htmlMessage = ansiToHtmlConvert.toHtml(coloredAnsi);
536
- const timeStr = new Date().toLocaleTimeString('tr-TR');
537
-
538
- activeMessages.push({ time: timeStr, text: htmlMessage });
539
-
540
- if (activeMessages.length > 50) {
541
- activeMessages.shift();
542
- }
543
- } catch (err) {
544
- logger.error("Mesaj işlenirken hata oluştu: " + err.message);
545
- }
546
- }
547
-
548
- app.get("/status", (req, res) => {
549
- res.send({
550
- ready: botIsReady,
551
- username: bot ? bot.username : null,
552
- connection_type: baglantiTuru
553
- });
554
- });
555
-
556
- app.get("/", (req, res) => res.send("Bot Aktif"));
557
-
558
- app.get("/messages", (req, res) => {
559
- if (messagesTimeout) {
560
- clearTimeout(messagesTimeout);
561
- messagesTimeout = null;
562
- }
563
-
564
- if (bot && botIsReady) {
565
- if (!bot.listeners('message').includes(minecraftMessageListener)) {
566
- bot.on('message', minecraftMessageListener);
567
- logger.info("[Sohbet Tasarrufu] Sohbet izlenmeye başlandı. 'message' eventi aktif.");
568
- }
569
- } else {
570
- return res.status(503).send("Bot hazır olmadığı için mesajlar dinlenemiyor.");
571
- }
572
-
573
- res.send({
574
- server_time: new Date().toLocaleTimeString('tr-TR'),
575
- logs: activeMessages
576
- });
577
-
578
- messagesTimeout = setTimeout(() => {
579
- if (bot) {
580
- bot.off('message', minecraftMessageListener);
581
- activeMessages = [];
582
- messagesTimeout = null;
583
- logger.info("[Sohbet Tasarrufu] 1 dakikadır izlenmiyor. 'message' eventi kapatıldı ve RAM temizlendi.");
584
- }
585
- }, 60000);
586
- });
587
-
588
- const checkAndStartViewer = (req, res, next) => {
589
- if (viewerTimeout) {
590
- clearTimeout(viewerTimeout);
591
- viewerTimeout = null;
592
- }
593
-
594
- const isBotReady = bot && botIsReady;
595
-
596
- if (!viewerInstance && isBotReady) {
597
- try {
598
- mineflayerViewer(bot, { port: 3000, firstPerson: true });
599
- viewerInstance = bot.viewer;
600
- logger.info("[Viewer] 3D Harita motoru arka planda (3000) başlatıldı.");
601
- setTimeout(() => next(), 600);
602
- return;
603
- } catch (err) {
604
- logger.error("Görüntüleyici başlatılamadı: " + err);
605
- }
606
- }
607
-
608
- if (!isBotReady && !viewerInstance) {
609
- return res.status(503).send("Bot henüz sunucuya giriş yapmadığı için ekran görüntülenemiyor.");
610
- }
611
-
612
- next();
613
- };
614
-
615
- app.use('/3dview', checkAndStartViewer, (req, res) => {
616
- if (req.originalUrl === '/3dview' && !req.originalUrl.endsWith('/')) {
617
- return res.redirect(301, '/3dview/');
618
- }
619
-
620
- const targetPath = req.url;
621
- const proxyReq = http.request({
622
- host: '127.0.0.1',
623
- port: 3000,
624
- path: targetPath,
625
- method: req.method,
626
- headers: req.headers
627
- }, (proxyRes) => {
628
- res.writeHead(proxyRes.statusCode, proxyRes.headers);
629
- proxyRes.pipe(res, { end: true });
630
- });
631
-
632
- proxyReq.on('error', (err) => {
633
- logger.error("[Asset Hatası] Veri 3000 portundan çekilemedi: " + err.message);
634
- if (!res.headersSent) res.status(502).send("Harita yükleniyor, lütfen sayfayı yenileyin.");
635
- });
636
-
637
- req.pipe(proxyReq, { end: true });
638
- });
639
-
640
- app.get("/restart", (req, res) => {
641
- if (bot && botIsReady) {
642
- logger.info("[Sistem] Web paneli üzerinden tam restart isteği geldi. Proje kapatılıyor...");
643
- try { bot.chat("Bot web paneli uzerinden tum kodlariyla yeniden baslatiliyor..."); } catch(e){}
644
- res.send({ success: true, message: "Tüm proje kapatıldı. Hugging Face sistemi birkaç saniye içinde kodu sıfırdan başlatacak." });
645
- setTimeout(() => {
646
- if (bot) bot.quit();
647
- logger.info("[Sistem] process.exit(0) çağrıldı. Konteyner yeniden başlatılacak.");
648
- process.exit(0);
649
- }, 1000);
650
- } else {
651
- logger.info("[Sistem] Bot bağlı değilken web panelinden tam restart istendi.");
652
- res.send({ success: true, message: "Bot bağlı değildi ancak tüm proje kökten kapatıldı, yeniden başlatılıyor." });
653
- setTimeout(() => {
654
- process.exit(0);
655
- }, 1000);
656
- }
657
- });
658
-
659
- const server = app.listen(process.env.PORT || 7860, () => {
660
- logger.info("Ana Express sunucusu 7860 portunda aktif.");
661
- });
662
-
663
- server.on('upgrade', (req, socket, head) => {
664
- if (req.url.includes('socket.io') || req.url.startsWith('/3dview')) {
665
- if (viewerTimeout) {
666
- clearTimeout(viewerTimeout);
667
- viewerTimeout = null;
668
- }
669
-
670
- let targetWsPath = req.url;
671
- if (targetWsPath.startsWith('/3dview')) {
672
- targetWsPath = targetWsPath.replace('/3dview', '');
673
- }
674
- if (!targetWsPath.startsWith('/')) {
675
- targetWsPath = '/' + targetWsPath;
676
- }
677
-
678
- const proxyReq = http.request({
679
- host: '127.0.0.1',
680
- port: 3000,
681
- path: targetWsPath,
682
- method: req.method,
683
- headers: req.headers
684
- });
685
-
686
- proxyReq.on('upgrade', (proxyRes, proxySocket, proxyHead) => {
687
- socket.write('HTTP/1.1 101 Switching Protocols\r\n' +
688
- Object.keys(proxyRes.headers).map(key => `${key}: ${proxyRes.headers[key]}`).join('\r\n') +
689
- '\r\n\r\n');
690
-
691
- proxySocket.pipe(socket);
692
- socket.pipe(proxySocket);
693
-
694
- socket.on('close', () => {
695
- if (viewerTimeout) clearTimeout(viewerTimeout);
696
- viewerTimeout = setTimeout(() => {
697
- if (viewerInstance && typeof viewerInstance.close === 'function') {
698
- try {
699
- viewerInstance.close();
700
- bot.viewer = null;
701
- viewerInstance = null;
702
- logger.info("[RAM Tasarrufu] 10 saniyedir kimse izlemiyor. Harita kapatıldı, RAM serbest!");
703
- } catch (e) {
704
- logger.error("Viewer kapatılırken hata: " + e.message);
705
- }
706
- }
707
- }, 10000);
708
- });
709
- });
710
-
711
- proxyReq.on('error', (err) => {
712
- logger.error("[WS Tünel Hatası] Websocket aktarılamadı: " + err.message);
713
- });
714
-
715
- proxyReq.end();
716
- }
717
- });
718
-
719
- const originalStderrWrite = process.stderr.write;
720
- process.stderr.write = function (chunk, encoding, callback) {
721
- const message = chunk.toString();
722
- if (message.includes("Ignoring block entities as chunk failed to load")) {
723
- if (typeof callback === 'function') callback();
724
- return true;
725
- }
726
- return originalStderrWrite.apply(process.stderr, arguments);
727
- };
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  async function createBot() {
2
  const net = require('net');
3
  const sshClient = new Client();
4
  isFinished = false; // Her yeni bot oluştuğunda durumu sıfırla
5
 
6
+ // 1. GİTHUB'DAN SSH BİLGİLERİNİ ÇEKME
7
  const githubRawUrl = 'https://raw.githubusercontent.com/suvarileader/che/refs/heads/main/doc/ower/doc.json';
8
+ logger.info("[GitHub Config] Güncel SSH tünel bilgileri GitHub'dan çekiliyor...");
9
 
10
  let remoteData = null;
11
  try {
 
22
  });
23
  }).on('error', (err) => reject(err));
24
  });
25
+ logger.info("[GitHub Config] SSH dosyası başarıyla indirildi.");
26
  } catch (err) {
27
+ logger.error(`[GitHub Config Hatası] SSH verisi alınamadı: ${err.message}. Sabit SSH ayarlarıyla devam ediliyor...`);
28
  }
29
 
30
+ // Varsayılan / Sabit SSH Ayarları (GitHub'da veri bulunamazsa yedek olarak çalışır)
31
+ let sshConfig = {
32
+ host: 'tr1.vpnjantit.com',
33
+ port: 22,
34
+ username: 'suvaa-vpnjantit.com',
35
+ password: 'suvaa'
36
+ };
37
+
38
+ // Local settings.json'daki botun kullanıcı adı
39
+ const currentBotUsername = config["bot-account"]["username"];
40
 
41
+ // GitHub'dan gelen dinamik SSH ayarlarını eşleştirme
42
  if (remoteData && Array.isArray(remoteData)) {
43
+ // Listede local'deki bot adına (Curst) ait satırı bul
44
  const myConfig = remoteData.find(item => item.account === currentBotUsername);
45
  if (myConfig) {
46
+ logger.info(`[GitHub Config] '${currentBotUsername}' botu için dinamik SSH parametreleri uygulandı.`);
47
+
48
+ // GitHub'daki serverName -> Aslında senin dinamik SSH IP'n
49
  if (myConfig.serverName && myConfig.serverName !== "empty") {
50
+ sshConfig.host = myConfig.serverName;
51
  }
52
+ // GitHub'daki username -> Aslında senin dinamik SSH Kullanıcı Adın
53
  if (myConfig.username && myConfig.username !== "empty") {
54
+ sshConfig.username = myConfig.username;
55
  }
56
+ // Not: Şifre alanın değişirse myConfig.password şeklinde (eğer JSON'a eklediysen) buraya bağlayabilirsin.
57
  } else {
58
+ logger.warn(`[GitHub Config] Listede '${currentBotUsername}' bulunamadı. Sabit SSH kullanılacak.`);
59
  }
60
  }
61
 
62
+ // Minecraft Sunucu Bilgileri (Her zaman local settings.json'dan okunur)
63
+ const targetServerIp = config.server.ip;
64
+ const targetServerPort = config.server.port;
 
 
 
 
65
 
66
  // Mineflayer Başlatılıyor
67
  bot = mineflayer.createBot({
 
75
  let fallbackTriggered = false;
76
  let isFinalFailureHandled = false;
77
 
78
+ // Kritik çökme yönetim merkezi
79
  const handleFinalFailure = (reason) => {
80
  if (isFinalFailureHandled) return;
81
  isFinalFailureHandled = true;
 
99
  }
100
  };
101
 
102
+ // Yedek Plan: Doğrudan Minecraft Sunucusuna Bağlanma
103
  const connectDirectly = (reason) => {
104
  if (fallbackTriggered) return;
105
  fallbackTriggered = true;
 
113
  port: parseInt(targetServerPort) || 25565
114
  });
115
 
 
116
  const directTimeout = setTimeout(() => {
117
  socket.destroy();
118
  handleFinalFailure("Normal IP bağlantısı zaman aşımına uğradı (Sunucu yanıt vermiyor)");
 
138
  });
139
  };
140
 
141
+ // GitHub'dan aldığımız dinamik SSH IP'sine bağlanıyoruz
142
+ logger.info(`[SSH Tünel] GitHub'dan alınan ${sshConfig.host} sunucusuna (${sshConfig.username}) bağlanılıyor...`);
143
 
 
144
  const connectionTimeout = setTimeout(() => {
145
  connectDirectly("SSH Bağlantı Zaman Aşımı (10 saniye yanıt alınamadı)");
146
  }, 10000);
 
149
  clearTimeout(connectionTimeout);
150
  logger.info('[SSH Tünel] SSH bağlantısı başarılı. Minecraft sunucusuna tünel açılıyor...');
151
 
152
+ // Tünelin ucu local settings.json'daki gerçek Minecraft IP'sine açılıyor
153
  sshClient.forwardOut(
154
  '127.0.0.1',
155
  12345,
 
194
 
195
  bot.loadPlugin(pathfinder);
196
 
197
+ // --- Buradan aşağısı (Timing sıfırlamaları, spawn, windowOpen eventleri vb.) tamamen aynı kalacak ---