Update bot.js
Browse files
bot.js
CHANGED
|
@@ -56,6 +56,23 @@ const KAZICI_CYCLE_INTERVAL_MS = 5 * 60 * 1000; // 5 dakika
|
|
| 56 |
// --- ÇİFTÇİ PERİYODİK DÖNGÜ AYARLARI (bağımsız, 1 dakikada bir) ---
|
| 57 |
const CIFTCI_CYCLE_INTERVAL_MS = 60 * 1000; // 1 dakika
|
| 58 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 59 |
let viewerInstance = null;
|
| 60 |
let viewerTimeout = null;
|
| 61 |
let bot = null;
|
|
@@ -98,6 +115,13 @@ let kaziciIntervalHandle = null; // Kazıcı bağımsız döngü zamanlayıcı
|
|
| 98 |
let ciftciIntervalHandle = null; // Çiftçi bağımsız döngü zamanlayıcısı (1 dk)
|
| 99 |
let isMainCycleRunning = false; // Besleyici (goToIsland->besle) ana döngüsü sürüyor mu
|
| 100 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 101 |
// --- DİNAMİK IP VE KONUM BİLGİLERİ ---
|
| 102 |
let activeConnectionIp = "Bilinmiyor";
|
| 103 |
let activeConnectionLocation = "Bilinmiyor";
|
|
@@ -114,20 +138,10 @@ function setSafeTimeout(fn, delay) {
|
|
| 114 |
}
|
| 115 |
|
| 116 |
// --- ÖNCELİKLİ GUI KİLİDİ (MUTEX) ---
|
| 117 |
-
// Besleyici, kazıcı ve çiftçi menüleri hepsi aynı windowOpen/tıklama mekanizmasını
|
| 118 |
-
// paylaştığı için ASLA aynı anda çalışmamalılar. Bu kilit ikisi arasında ayrım yapar:
|
| 119 |
-
// - tryAcquire(): periyodik/otomatik döngüler için. Kilit doluysa BEKLEMEZ, hemen
|
| 120 |
-
// false döner ve o tur sessizce atlanır (bir sonraki periyotta tekrar dener).
|
| 121 |
-
// - acquire(): Express panelinden (manuel) gelen istekler için. Kilit doluysa
|
| 122 |
-
// KUYRUĞA GİRER ve önceliklidir — mevcut işlem bitince, kuyrukta bekleyen varsa
|
| 123 |
-
// bile (ki otomatik döngüler hiç kuyruğa girmediği için pratikte tek bekleyen
|
| 124 |
-
// genelde manuel istek olur) ilk manuel istek işi devralır. Böylece kullanıcı
|
| 125 |
-
// panelden bir istek yaptığında, o sırada süren otomatik bir işlem varsa önce
|
| 126 |
-
// o tamamlanır, hemen ardından kullanıcının isteği en öncelikli şekilde işlenir.
|
| 127 |
class PriorityGuiMutex {
|
| 128 |
constructor() {
|
| 129 |
this._locked = false;
|
| 130 |
-
this._waiters = [];
|
| 131 |
}
|
| 132 |
isLocked() { return this._locked; }
|
| 133 |
tryAcquire() {
|
|
@@ -147,7 +161,6 @@ class PriorityGuiMutex {
|
|
| 147 |
release() {
|
| 148 |
if (this._waiters.length > 0) {
|
| 149 |
const next = this._waiters.shift();
|
| 150 |
-
// Kilit devrediliyor (locked=true kalır), bir sonraki bekleyen devralır.
|
| 151 |
next();
|
| 152 |
} else {
|
| 153 |
this._locked = false;
|
|
@@ -156,22 +169,15 @@ class PriorityGuiMutex {
|
|
| 156 |
}
|
| 157 |
const guiMutex = new PriorityGuiMutex();
|
| 158 |
|
| 159 |
-
// Express panelinden diğer bot fonksiyonlarına erişim için (createBot() closure'ı
|
| 160 |
-
// dışından çağrılabilmeleri için köprü). Bot her (yeniden) bağlandığında doldurulur.
|
| 161 |
let botActions = {
|
| 162 |
scanAndFeedManual: null,
|
| 163 |
scanAndCollectMinersManual: null,
|
| 164 |
openCiftciAndSellAllManual: null,
|
| 165 |
goToIslandManual: null,
|
| 166 |
sendSkyblockManual: null,
|
|
|
|
| 167 |
};
|
| 168 |
|
| 169 |
-
// --- ORTAK SÜRE FORMATLAMA FONKSİYONU ---
|
| 170 |
-
// Tüm loglardaki "X dk sonra", "Y saat sonra" gibi elle yazılmış ifadelerin yerine
|
| 171 |
-
// bu fonksiyon kullanılır. Böylece yukarıdaki ayar sabitleri (KAZICI_CYCLE_INTERVAL_MS,
|
| 172 |
-
// CIFTCI_CYCLE_INTERVAL_MS, DEFAULT_CHECK_INTERVAL_MS, vb.) değiştirildiğinde,
|
| 173 |
-
// loglara yansıyan süre ifadeleri OTOMATİK olarak güncellenir; elle metin
|
| 174 |
-
// değiştirmeye gerek kalmaz.
|
| 175 |
function formatDurationMs(ms) {
|
| 176 |
if (ms == null || isNaN(ms) || ms < 0) return "0 saniye";
|
| 177 |
let totalSeconds = Math.round(ms / 1000);
|
|
@@ -267,6 +273,295 @@ https.get('https://api.ipify.org?format=json', (res) => {
|
|
| 267 |
});
|
| 268 |
}).on('error', () => {});
|
| 269 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 270 |
async function createBot() {
|
| 271 |
if (isConnecting) {
|
| 272 |
logger.warn("[Sistem] Zaten aktif bir bağlantı süreci yürütülüyor. Mükerrer istek engellendi.");
|
|
@@ -765,7 +1060,36 @@ async function createBot() {
|
|
| 765 |
}
|
| 766 |
}
|
| 767 |
|
| 768 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 769 |
function scheduleNextCheck(delayMs) {
|
| 770 |
if (periodicTimeoutHandle) {
|
| 771 |
clearTimeout(periodicTimeoutHandle);
|
|
@@ -782,9 +1106,6 @@ async function createBot() {
|
|
| 782 |
await goToIsland();
|
| 783 |
await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
|
| 784 |
await scanAndFeed();
|
| 785 |
-
// NOT: Kazıcı ve çiftçi toplama artık BURADA çağrılmıyor. Her ikisi de
|
| 786 |
-
// besleyiciden tamamen bağımsız kendi zamanlayıcılarında çalışır
|
| 787 |
-
// (bkz. startKaziciPeriodic / startCiftciPeriodic).
|
| 788 |
} catch (err) {
|
| 789 |
logger.error(`[Planlayıcı Hatası] Periyodik döngüde beklenmeyen hata: ${err && err.stack ? err.stack : err}`);
|
| 790 |
try { scheduleNextCheck(DEFAULT_CHECK_INTERVAL_MS); } catch (e2) {}
|
|
@@ -806,7 +1127,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 806 |
});
|
| 807 |
}
|
| 808 |
|
| 809 |
-
// --- BESLEYİCİ (scanAndFeedCore = asıl mantık, kilit içermez) ---
|
| 810 |
async function scanAndFeedCore() {
|
| 811 |
if (!bot || !botIsReady) return;
|
| 812 |
if (!guiMutex.isLocked()) {
|
|
@@ -919,15 +1239,9 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 919 |
});
|
| 920 |
}
|
| 921 |
|
| 922 |
-
// Kilit meşgulken (kazıcı/çiftçi turu sürerken) besleyicinin bu kısa süreliğine
|
| 923 |
-
// beklemesi için yeniden deneme aralığı. Gerçek besleme zamanlamasını bozmaz,
|
| 924 |
-
// sadece kilidin boşalmasını birkaç kez kontrol eder.
|
| 925 |
const FEED_LOCK_RETRY_DELAY_MS = 15 * 1000;
|
| 926 |
-
const FEED_LOCK_MAX_RETRIES = 8;
|
| 927 |
|
| 928 |
-
// Periyodik (otomatik) kullanım: kilit doluysa hemen pes etmez, kısa aralıklarla
|
| 929 |
-
// yeniden dener (kazıcı/çiftçi turu birkaç saniye içinde biter). Sonuçta kilidi
|
| 930 |
-
// hâlâ alamazsa, döngünün tamamen ölmemesi için normal aralıkla tekrar planlar.
|
| 931 |
async function scanAndFeed(retryCount) {
|
| 932 |
retryCount = retryCount || 0;
|
| 933 |
if (!guiMutex.tryAcquire()) {
|
|
@@ -950,8 +1264,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 950 |
}
|
| 951 |
}
|
| 952 |
|
| 953 |
-
// Manuel (Express panelinden) kullanım: kilit doluysa ÖNCELİKLİ olarak kuyruğa
|
| 954 |
-
// girer, mevcut işlem bitince hemen devralır.
|
| 955 |
async function scanAndFeedManual() {
|
| 956 |
logger.info("[Besleyici - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 957 |
await guiMutex.acquire();
|
|
@@ -965,7 +1277,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 965 |
}
|
| 966 |
}
|
| 967 |
|
| 968 |
-
// --- KAZICI MİNYON DEPO AKTARIMI ---
|
| 969 |
async function activateEntityAndAwaitWindow(entity, labelForLogs) {
|
| 970 |
if (!bot || !botIsReady || !entity || !entity.position) {
|
| 971 |
return { success: false, reason: "Bot veya entity hazır değil" };
|
|
@@ -1063,8 +1374,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1063 |
return matches;
|
| 1064 |
}
|
| 1065 |
|
| 1066 |
-
// scanAndCollectMinersCore: asıl mantık, kilit İÇERMEZ (dışarıdan kilitlenmiş
|
| 1067 |
-
// olarak çağrılması beklenir).
|
| 1068 |
async function scanAndCollectMinersCore() {
|
| 1069 |
if (!bot || !botIsReady) return;
|
| 1070 |
if (!guiMutex.isLocked()) {
|
|
@@ -1115,7 +1424,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1115 |
logger.info(`[${currentBotUsername}] Kazıcı minyon depo aktarım turu tamamlandı.`);
|
| 1116 |
}
|
| 1117 |
|
| 1118 |
-
// Tekil/periyodik kullanım (kendi başına çağrılırsa kilidi kendisi alır)
|
| 1119 |
async function scanAndCollectMiners() {
|
| 1120 |
if (!guiMutex.tryAcquire()) {
|
| 1121 |
logger.warn("[Kazıcı Toplama] Zaten bir GUI işlemi sürüyor (besleyici/kazıcı/çiftçi). Bu tur atlanıyor.");
|
|
@@ -1130,7 +1438,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1130 |
}
|
| 1131 |
}
|
| 1132 |
|
| 1133 |
-
// Manuel (Express panelinden) kullanım: öncelikli kuyruk.
|
| 1134 |
async function scanAndCollectMinersManual() {
|
| 1135 |
logger.info("[Kazıcı Toplama - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 1136 |
await guiMutex.acquire();
|
|
@@ -1145,11 +1452,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1145 |
}
|
| 1146 |
}
|
| 1147 |
|
| 1148 |
-
// --- ÇİFTÇİ (HEPSİNİ SAT) MENÜSÜ ---
|
| 1149 |
-
// openCiftciAndSellAllCore: asıl mantık, kilit İÇERMEZ (dışarıdan kilitli çağrılır).
|
| 1150 |
-
// NOT: Asıl "hepsini sat" tıklaması artık burada DEĞİL, windowOpen olayında,
|
| 1151 |
-
// pencere açıldıktan CIFTCI_CLICK_DELAY_AFTER_OPEN_MS kadar bekledikten sonra
|
| 1152 |
-
// ve CIFTCI_CLICK_REPEAT_COUNT kez tekrar tıklanarak yapılıyor (bkz. windowOpen).
|
| 1153 |
async function openCiftciAndSellAllCore() {
|
| 1154 |
if (!bot || !botIsReady) return;
|
| 1155 |
if (!guiMutex.isLocked()) {
|
|
@@ -1165,10 +1467,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1165 |
await new Promise(r => setTimeout(r, 300));
|
| 1166 |
}
|
| 1167 |
|
| 1168 |
-
// Komut yalnızca BİR KEZ gönderilir. Eskiden birkaç saniyede bir tekrar
|
| 1169 |
-
// gönderiliyordu; bu, sunucunun aynı komutu art arda işleyip menüyü birden
|
| 1170 |
-
// fazla kez açmasına (ve dolayısıyla tıklama/satış tutarsızlıklarına) yol
|
| 1171 |
-
// açabiliyordu. Şimdi sadece pencerenin açılmasını timeout süresince bekliyoruz.
|
| 1172 |
let timedOut = false;
|
| 1173 |
|
| 1174 |
await new Promise((resolve) => {
|
|
@@ -1207,7 +1505,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1207 |
}
|
| 1208 |
}
|
| 1209 |
|
| 1210 |
-
// Tekil/periyodik kullanım.
|
| 1211 |
async function openCiftciAndSellAll() {
|
| 1212 |
if (!guiMutex.tryAcquire()) {
|
| 1213 |
logger.warn("[Çiftçi] Zaten bir GUI işlemi sürüyor (besleyici/kazıcı/çiftçi). Bu tur atlanıyor.");
|
|
@@ -1222,7 +1519,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1222 |
}
|
| 1223 |
}
|
| 1224 |
|
| 1225 |
-
// Manuel (Express panelinden) kullanım: öncelikli kuyruk.
|
| 1226 |
async function openCiftciAndSellAllManual() {
|
| 1227 |
logger.info("[Çiftçi - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 1228 |
await guiMutex.acquire();
|
|
@@ -1237,11 +1533,8 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1237 |
}
|
| 1238 |
}
|
| 1239 |
|
| 1240 |
-
// --- KAZICI BAĞIMSIZ PERİYODİK DÖNGÜ (5 dakikada bir) ---
|
| 1241 |
-
// Besleyici ve çiftçi durumundan hiçbir şekilde etkilenmez. Sadece paylaşılan
|
| 1242 |
-
// guiMutex ile çakışmayı önler; kilit doluysa bu turu sessizce atlar.
|
| 1243 |
function startKaziciPeriodic() {
|
| 1244 |
-
if (kaziciIntervalHandle) return;
|
| 1245 |
|
| 1246 |
const runCycle = async () => {
|
| 1247 |
if (!bot || !botIsReady) return;
|
|
@@ -1272,9 +1565,8 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1272 |
logger.info(`[Kazıcı Periyodik] Bağımsız döngü başlatıldı (her ${formatDurationMs(KAZICI_CYCLE_INTERVAL_MS)}).`);
|
| 1273 |
}
|
| 1274 |
|
| 1275 |
-
// --- ÇİFTÇİ BAĞIMSIZ PERİYODİK DÖNGÜ (1 dakikada bir) ---
|
| 1276 |
function startCiftciPeriodic() {
|
| 1277 |
-
if (ciftciIntervalHandle) return;
|
| 1278 |
|
| 1279 |
const runCycle = async () => {
|
| 1280 |
if (!bot || !botIsReady) return;
|
|
@@ -1314,17 +1606,16 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1314 |
botIsReady = true;
|
| 1315 |
botUptimeStart = Date.now();
|
| 1316 |
|
| 1317 |
-
// Express panelinin bu bot örneğine erişebilmesi için köprüyü doldur.
|
| 1318 |
botActions.scanAndFeedManual = scanAndFeedManual;
|
| 1319 |
botActions.scanAndCollectMinersManual = scanAndCollectMinersManual;
|
| 1320 |
botActions.openCiftciAndSellAllManual = openCiftciAndSellAllManual;
|
| 1321 |
botActions.goToIslandManual = goToIsland;
|
| 1322 |
botActions.sendSkyblockManual = sendSkyblockCommand;
|
|
|
|
| 1323 |
|
| 1324 |
-
// Kazıcı ve Çiftçi bağımsız döngülerini başlat (birbirlerinden ve besleyiciden
|
| 1325 |
-
// bağımsız zamanlayıcılar; sadece guiMutex ile çakışma önlenir).
|
| 1326 |
startKaziciPeriodic();
|
| 1327 |
startCiftciPeriodic();
|
|
|
|
| 1328 |
|
| 1329 |
if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
|
| 1330 |
const password = config.utils["auto-auth"].password;
|
|
@@ -1351,7 +1642,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1351 |
}
|
| 1352 |
}, 7500);
|
| 1353 |
|
| 1354 |
-
// İlk çalıştırma: Girişten 12.5 saniye sonra ilk besleyici kontrolünü yap
|
| 1355 |
setSafeTimeout(async () => {
|
| 1356 |
if (!bot || !botIsReady) return;
|
| 1357 |
isMainCycleRunning = true;
|
|
@@ -1359,8 +1649,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1359 |
await goToIsland();
|
| 1360 |
await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
|
| 1361 |
await scanAndFeed();
|
| 1362 |
-
// NOT: Kazıcı ve çiftçi toplama burada da çağrılmıyor; kendi bağımsız
|
| 1363 |
-
// döngüleri zaten spawn olur olmaz başladı.
|
| 1364 |
} catch (err) {
|
| 1365 |
logger.error(`[Spawn Hatası] İlk kontrol döngüsünde beklenmeyen hata: ${err && err.stack ? err.stack : err}`);
|
| 1366 |
try { scheduleNextCheck(DEFAULT_CHECK_INTERVAL_MS); } catch (e2) {}
|
|
@@ -1374,6 +1662,14 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1374 |
}
|
| 1375 |
});
|
| 1376 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1377 |
bot.on("windowOpen", async (window) => {
|
| 1378 |
if (!bot) return;
|
| 1379 |
try {
|
|
@@ -1403,11 +1699,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1403 |
try { bot.closeWindow(window); } catch(e){}
|
| 1404 |
|
| 1405 |
} else if (isCiftciWindow) {
|
| 1406 |
-
// Pencere açılır açılmaz hemen tıklamak yerine, sunucunun menü içeriğini
|
| 1407 |
-
// (lore/slot verisini) tam yerleştirmesi için önce kısa bir süre beklenir,
|
| 1408 |
-
// ardından "hepsini sat" slotuna birkaç kez art arda tıklanır. Bu, bazen
|
| 1409 |
-
// satışın hiç gerçekleşmemesi sorununu (erken tıklama nedeniyle sunucunun
|
| 1410 |
-
// isteği görmezden gelmesi) engellemek içindir.
|
| 1411 |
try {
|
| 1412 |
logger.info(`[${currentBotUsername}] Çiftçi (Hepsini Sat) menüsü açıldı. ${formatDurationMs(CIFTCI_CLICK_DELAY_AFTER_OPEN_MS)} bekleniyor, sonra slot ${CIFTCI_SELL_ALL_SLOT}'e ${CIFTCI_CLICK_REPEAT_COUNT} kez tıklanacak...`);
|
| 1413 |
await new Promise(r => setTimeout(r, CIFTCI_CLICK_DELAY_AFTER_OPEN_MS));
|
|
@@ -1492,6 +1783,7 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1492 |
try {
|
| 1493 |
logger.warn(manualStopRequested ? "Bağlantı koptu. Manuel durdurma istendiği için yeniden bağlanılmayacak." : "Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor ve YENİDEN BAĞLANMA SÜRECİ BAŞLIYOR...");
|
| 1494 |
stopPeriodicHomeChecks();
|
|
|
|
| 1495 |
lastCheckAtMs = null;
|
| 1496 |
botIsReady = false;
|
| 1497 |
baglantiTuru = "Yok";
|
|
@@ -1778,7 +2070,8 @@ app.get("/status", (req, res) => {
|
|
| 1778 |
next_ciftci_sell: nextCiftciTimeStr,
|
| 1779 |
gui_lock_busy: guiMutex.isLocked(),
|
| 1780 |
manually_stopped: manualStopRequested,
|
| 1781 |
-
is_connecting: isConnecting
|
|
|
|
| 1782 |
});
|
| 1783 |
});
|
| 1784 |
|
|
@@ -1801,12 +2094,6 @@ app.get("/bot/restart", (req, res) => {
|
|
| 1801 |
res.send({ success: true, message: "Bot tamamen sıfırdan yeniden başlatılıyor (soket/SSH dahil)." });
|
| 1802 |
});
|
| 1803 |
|
| 1804 |
-
// --- YENİ: MANUEL GUI/AKSİYON TETİKLEME ENDPOINT'LERİ ---
|
| 1805 |
-
// Bu endpoint'ler istek geldiği anda hemen yanıt döner (fire-and-forget), asıl
|
| 1806 |
-
// işlem arka planda ÖNCELİKLİ olarak (guiMutex.acquire ile kuyruğa öncelikli
|
| 1807 |
-
// girerek) yürütülür. O sırada otomatik bir döngü (besleyici, kazıcı veya çiftçi)
|
| 1808 |
-
// zaten çalışıyorsa, önce o tamamlanır, HEMEN ARDINDAN bu istek işlenir.
|
| 1809 |
-
|
| 1810 |
app.get("/bot/kazici-kontrol", (req, res) => {
|
| 1811 |
if (!bot || !botIsReady || !botActions.scanAndCollectMinersManual) {
|
| 1812 |
return res.status(503).send({ success: false, message: "Bot hazır değil." });
|
|
@@ -1847,6 +2134,40 @@ app.get("/bot/is-go", (req, res) => {
|
|
| 1847 |
res.send({ success: true, message: `${GO_ISLAND_COMMAND} komutu gönderildi.` });
|
| 1848 |
});
|
| 1849 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1850 |
app.get("/", (req, res) => res.send("Bot Aktif"));
|
| 1851 |
|
| 1852 |
app.get("/messages", (req, res) => {
|
|
|
|
| 56 |
// --- ÇİFTÇİ PERİYODİK DÖNGÜ AYARLARI (bağımsız, 1 dakikada bir) ---
|
| 57 |
const CIFTCI_CYCLE_INTERVAL_MS = 60 * 1000; // 1 dakika
|
| 58 |
|
| 59 |
+
// --- KAZICI FAILOVER (YEDEK HESAP) AYARLARI ---
|
| 60 |
+
const STALL_CHECK_INTERVAL_MS = 15 * 1000; // pose kontrolü ne sıklıkla yapılsın
|
| 61 |
+
const STALL_TIMEOUT_MS = 60 * 1000; // bu süre hareketsiz kalırsa "durdu" say
|
| 62 |
+
const FAILOVER_HOME_ARRIVAL_DELAY_MS = 4000; // yedek hesapta /is go sonrası varış beklemesi
|
| 63 |
+
const FAILOVER_LOGIN_DELAY_MS = 2500;
|
| 64 |
+
const FAILOVER_SKYBLOCK_DELAY_MS = 7500;
|
| 65 |
+
const FAILOVER_ISGO_DELAY_MS = 12500;
|
| 66 |
+
const FAILOVER_RECHECK_INTERVAL_MS = 20 * 1000; // yedek hesapta minyonları tekrar kontrol aralığı
|
| 67 |
+
const FAILOVER_MAX_WAIT_MS = 60 * 60 * 1000; // güvenlik: 1 saatte hâlâ aktifleşmediyse pes et, ana hesaba dön
|
| 68 |
+
const FAILOVER_SPAWN_TIMEOUT_MS = 30 * 1000; // yedek hesap 30 sn içinde spawn olmazsa vazgeç
|
| 69 |
+
|
| 70 |
+
// İzlenen (KAZICI_NAMES ile eşleşmeyen, başka hesaptan konan) kazıcı minyonların
|
| 71 |
+
// skin texture hash'i. Bu skin + elde iron_pickaxe olan armor stand'ler izlenir.
|
| 72 |
+
const WATCHED_KAZICI_SKIN_HASHES = new Set([
|
| 73 |
+
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDQ4ODcwY2E3N2FhNjk5ZDAxNzA5M2I4Mjc3OWQwYTU5OGRjNGYzZjQ5ZDM1MTUzMmFlNGQ5NjMzZGNjMmE1YSJ9fX0=",
|
| 74 |
+
]);
|
| 75 |
+
|
| 76 |
let viewerInstance = null;
|
| 77 |
let viewerTimeout = null;
|
| 78 |
let bot = null;
|
|
|
|
| 115 |
let ciftciIntervalHandle = null; // Çiftçi bağımsız döngü zamanlayıcısı (1 dk)
|
| 116 |
let isMainCycleRunning = false; // Besleyici (goToIsland->besle) ana döngüsü sürüyor mu
|
| 117 |
|
| 118 |
+
// --- KAZICI FAILOVER (YEDEK HESAP) DURUM DEĞİŞKENLERİ ---
|
| 119 |
+
let poseTracker = new Map(); // entityId -> { poseKey, lastChangeAt, uuid }
|
| 120 |
+
let stallCheckIntervalHandle = null;
|
| 121 |
+
let failoverModeActive = false; // true iken ana botun periyodik işlemleri fiilen durur (bot=null olduğu için)
|
| 122 |
+
let failoverBot = null; // yedek hesabın mineflayer instance'ı
|
| 123 |
+
let failoverInProgress = false; // aynı anda 2 kez tetiklenmesin diye kilit
|
| 124 |
+
|
| 125 |
// --- DİNAMİK IP VE KONUM BİLGİLERİ ---
|
| 126 |
let activeConnectionIp = "Bilinmiyor";
|
| 127 |
let activeConnectionLocation = "Bilinmiyor";
|
|
|
|
| 138 |
}
|
| 139 |
|
| 140 |
// --- ÖNCELİKLİ GUI KİLİDİ (MUTEX) ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 141 |
class PriorityGuiMutex {
|
| 142 |
constructor() {
|
| 143 |
this._locked = false;
|
| 144 |
+
this._waiters = [];
|
| 145 |
}
|
| 146 |
isLocked() { return this._locked; }
|
| 147 |
tryAcquire() {
|
|
|
|
| 161 |
release() {
|
| 162 |
if (this._waiters.length > 0) {
|
| 163 |
const next = this._waiters.shift();
|
|
|
|
| 164 |
next();
|
| 165 |
} else {
|
| 166 |
this._locked = false;
|
|
|
|
| 169 |
}
|
| 170 |
const guiMutex = new PriorityGuiMutex();
|
| 171 |
|
|
|
|
|
|
|
| 172 |
let botActions = {
|
| 173 |
scanAndFeedManual: null,
|
| 174 |
scanAndCollectMinersManual: null,
|
| 175 |
openCiftciAndSellAllManual: null,
|
| 176 |
goToIslandManual: null,
|
| 177 |
sendSkyblockManual: null,
|
| 178 |
+
antiBotMove: null
|
| 179 |
};
|
| 180 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 181 |
function formatDurationMs(ms) {
|
| 182 |
if (ms == null || isNaN(ms) || ms < 0) return "0 saniye";
|
| 183 |
let totalSeconds = Math.round(ms / 1000);
|
|
|
|
| 273 |
});
|
| 274 |
}).on('error', () => {});
|
| 275 |
|
| 276 |
+
// =====================================================================
|
| 277 |
+
// KAZICI FAILOVER (YEDEK HESAP) YARDIMCI FONKSİYONLARI
|
| 278 |
+
// Bunlar module-level (createBot() dışında) çünkü bot bağlantısı kesilip
|
| 279 |
+
// yeniden kurulduğunda bile (createBot() tekrar çağrıldığında) hayatta
|
| 280 |
+
// kalmaları gerekiyor.
|
| 281 |
+
// =====================================================================
|
| 282 |
+
|
| 283 |
+
// Entity'nin skin texture değerini (player_head equipment'inden) çıkarır.
|
| 284 |
+
function getEntitySkinHash(entity) {
|
| 285 |
+
try {
|
| 286 |
+
const equipment = entity.equipment || [];
|
| 287 |
+
for (const item of equipment) {
|
| 288 |
+
if (item && item.name === "player_head" && item.components) {
|
| 289 |
+
for (const comp of item.components) {
|
| 290 |
+
if (comp && comp.type === "profile" && comp.data && Array.isArray(comp.data.properties)) {
|
| 291 |
+
const texProp = comp.data.properties.find(p => p.name === "textures");
|
| 292 |
+
if (texProp && texProp.value) {
|
| 293 |
+
return texProp.value;
|
| 294 |
+
}
|
| 295 |
+
}
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
}
|
| 299 |
+
} catch (e) {}
|
| 300 |
+
return null;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
// Entity'nin elinde (equipment[0] = main hand) iron_pickaxe olup olmadığını kontrol eder.
|
| 304 |
+
function hasIronPickaxeEquipped(entity) {
|
| 305 |
+
try {
|
| 306 |
+
const equipment = entity.equipment || [];
|
| 307 |
+
const mainHand = equipment[0];
|
| 308 |
+
return !!(mainHand && mainHand.name === "iron_pickaxe");
|
| 309 |
+
} catch (e) {
|
| 310 |
+
return false;
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
// Skin + iron_pickaxe ikisi birden tutuyorsa bu entity izlenen kazıcı minyondur.
|
| 315 |
+
function isWatchedKaziciEntity(entity) {
|
| 316 |
+
if (!entity || entity.name !== "armor_stand") return false;
|
| 317 |
+
const skinHash = getEntitySkinHash(entity);
|
| 318 |
+
if (!skinHash || !WATCHED_KAZICI_SKIN_HASHES.has(skinHash)) return false;
|
| 319 |
+
return hasIronPickaxeEquipped(entity);
|
| 320 |
+
}
|
| 321 |
+
|
| 322 |
+
// metadata içindeki pose (kol/kafa açıları) + pozisyonu birleştirip bir imza çıkarır.
|
| 323 |
+
function getPoseKey(entity) {
|
| 324 |
+
try {
|
| 325 |
+
const md = entity.metadata || [];
|
| 326 |
+
const parts = [];
|
| 327 |
+
for (const m of md) {
|
| 328 |
+
if (m && typeof m === "object" && "pitch" in m && "yaw" in m && "roll" in m) {
|
| 329 |
+
parts.push(`${m.pitch.toFixed(2)},${m.yaw.toFixed(2)},${m.roll.toFixed(2)}`);
|
| 330 |
+
}
|
| 331 |
+
}
|
| 332 |
+
if (entity.position) {
|
| 333 |
+
parts.push(`${entity.position.x.toFixed(2)}_${entity.position.y.toFixed(2)}_${entity.position.z.toFixed(2)}`);
|
| 334 |
+
}
|
| 335 |
+
return parts.join("|");
|
| 336 |
+
} catch (e) {
|
| 337 |
+
return null;
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
// bot.on('entityMoved', ...) ve bot.on('entitySpawn', ...) içinden çağrılır.
|
| 342 |
+
// İzlenen kazıcı minyonun pose'unu takip eder.
|
| 343 |
+
function trackKaziciPoseIfWatched(entity) {
|
| 344 |
+
if (!entity) return;
|
| 345 |
+
if (!isWatchedKaziciEntity(entity)) return;
|
| 346 |
+
|
| 347 |
+
const poseKey = getPoseKey(entity);
|
| 348 |
+
if (poseKey == null) return;
|
| 349 |
+
|
| 350 |
+
const prev = poseTracker.get(entity.id);
|
| 351 |
+
if (!prev) {
|
| 352 |
+
poseTracker.set(entity.id, { poseKey, lastChangeAt: Date.now(), uuid: entity.uuid });
|
| 353 |
+
return;
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
if (prev.poseKey !== poseKey) {
|
| 357 |
+
prev.poseKey = poseKey;
|
| 358 |
+
prev.lastChangeAt = Date.now();
|
| 359 |
+
}
|
| 360 |
+
// poseKey aynıysa lastChangeAt GÜNCELLENMEZ -> hareketsizlik süresi büyümeye devam eder.
|
| 361 |
+
}
|
| 362 |
+
|
| 363 |
+
// Artık dünyada olmayan entity kayıtlarını temizler.
|
| 364 |
+
function pruneStaleTrackedEntities() {
|
| 365 |
+
if (!bot || !bot.entities) return;
|
| 366 |
+
for (const id of poseTracker.keys()) {
|
| 367 |
+
if (!bot.entities[id]) poseTracker.delete(id);
|
| 368 |
+
}
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
function startStallWatcher() {
|
| 372 |
+
if (stallCheckIntervalHandle) return;
|
| 373 |
+
stallCheckIntervalHandle = setInterval(() => {
|
| 374 |
+
if (!bot || !botIsReady || failoverModeActive) return;
|
| 375 |
+
pruneStaleTrackedEntities();
|
| 376 |
+
|
| 377 |
+
const now = Date.now();
|
| 378 |
+
let anyStalled = false;
|
| 379 |
+
for (const [id, info] of poseTracker.entries()) {
|
| 380 |
+
if (now - info.lastChangeAt >= STALL_TIMEOUT_MS) {
|
| 381 |
+
anyStalled = true;
|
| 382 |
+
logger.warn(`[Failover] İzlenen kazıcı minyon (entityId:${id}) ${formatDurationMs(now - info.lastChangeAt)} boyunca hareketsiz.`);
|
| 383 |
+
}
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
if (anyStalled && !failoverInProgress) {
|
| 387 |
+
triggerFailoverSequence().catch(err => {
|
| 388 |
+
logger.error(`[Failover Hatası] ${err && err.stack ? err.stack : err}`);
|
| 389 |
+
failoverInProgress = false;
|
| 390 |
+
});
|
| 391 |
+
}
|
| 392 |
+
}, STALL_CHECK_INTERVAL_MS);
|
| 393 |
+
logger.info("[Failover] Pose izleme döngüsü başlatıldı.");
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
function stopStallWatcher() {
|
| 397 |
+
if (stallCheckIntervalHandle) {
|
| 398 |
+
clearInterval(stallCheckIntervalHandle);
|
| 399 |
+
stallCheckIntervalHandle = null;
|
| 400 |
+
}
|
| 401 |
+
poseTracker.clear();
|
| 402 |
+
}
|
| 403 |
+
|
| 404 |
+
// Ana hesabı geçici düşürüp yedek hesabı (kullaniciadi1) devreye alan, izlenen
|
| 405 |
+
// kazıcı minyonlar tekrar hareket edene kadar bekleyen, sonra ana hesabı
|
| 406 |
+
// yeniden bağlayan tam akış.
|
| 407 |
+
async function triggerFailoverSequence() {
|
| 408 |
+
if (failoverInProgress) return;
|
| 409 |
+
failoverInProgress = true;
|
| 410 |
+
failoverModeActive = true;
|
| 411 |
+
|
| 412 |
+
const mainUsername = config["bot-account"]["username"];
|
| 413 |
+
const backupUsername = `${mainUsername}1`;
|
| 414 |
+
|
| 415 |
+
logger.warn(`[Failover] İzlenen kazıcı(lar) durdu. Ana hesap (${mainUsername}) geçici olarak düşürülüp yedek hesap (${backupUsername}) devreye alınıyor.`);
|
| 416 |
+
|
| 417 |
+
manualStopRequested = true; // mevcut auto-reconnect mantığını geçici olarak devre dışı bırakır
|
| 418 |
+
stopPeriodicHomeChecks();
|
| 419 |
+
safeDestroyAllConnections();
|
| 420 |
+
|
| 421 |
+
try {
|
| 422 |
+
await runBackupAccountAndWaitForRecovery(backupUsername);
|
| 423 |
+
} catch (err) {
|
| 424 |
+
logger.error(`[Failover] Yedek hesap akışında hata: ${err && err.stack ? err.stack : err}`);
|
| 425 |
+
}
|
| 426 |
+
|
| 427 |
+
logger.info(`[Failover] İzlenen kazıcı(lar) tekrar aktif (ya da azami bekleme süresi doldu). Ana hesap (${mainUsername}) yeniden bağlanıyor.`);
|
| 428 |
+
manualStopRequested = false;
|
| 429 |
+
failoverModeActive = false;
|
| 430 |
+
poseTracker.clear();
|
| 431 |
+
createBot();
|
| 432 |
+
|
| 433 |
+
failoverInProgress = false;
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
// Yedek hesapla ayrı bir mineflayer bot'u başlatır: /login, /skyblock, /is go
|
| 437 |
+
// atar (ana hesaptaki ile AYNI gecikme süreleriyle), sonra izlenen minyonların
|
| 438 |
+
// hareketine bakar. Hareket geri gelince bağlantıyı kapatıp resolve eder.
|
| 439 |
+
function runBackupAccountAndWaitForRecovery(backupUsername) {
|
| 440 |
+
return new Promise((resolve) => {
|
| 441 |
+
const backupPoseTracker = new Map();
|
| 442 |
+
let recheckHandle = null;
|
| 443 |
+
let safetyTimeoutHandle = null;
|
| 444 |
+
let spawnTimeoutHandle = null;
|
| 445 |
+
let finished = false;
|
| 446 |
+
|
| 447 |
+
const finish = () => {
|
| 448 |
+
if (finished) return;
|
| 449 |
+
finished = true;
|
| 450 |
+
if (recheckHandle) clearInterval(recheckHandle);
|
| 451 |
+
if (safetyTimeoutHandle) clearTimeout(safetyTimeoutHandle);
|
| 452 |
+
if (spawnTimeoutHandle) clearTimeout(spawnTimeoutHandle);
|
| 453 |
+
try {
|
| 454 |
+
if (failoverBot) {
|
| 455 |
+
failoverBot.removeAllListeners();
|
| 456 |
+
failoverBot.quit();
|
| 457 |
+
}
|
| 458 |
+
} catch (e) {}
|
| 459 |
+
failoverBot = null;
|
| 460 |
+
resolve();
|
| 461 |
+
};
|
| 462 |
+
|
| 463 |
+
try {
|
| 464 |
+
failoverBot = mineflayer.createBot({
|
| 465 |
+
username: backupUsername,
|
| 466 |
+
auth: config["bot-account"]["type"],
|
| 467 |
+
host: config.server.ip,
|
| 468 |
+
port: config.server.port,
|
| 469 |
+
version: config.server.version,
|
| 470 |
+
});
|
| 471 |
+
} catch (err) {
|
| 472 |
+
logger.error(`[Failover - Yedek Hesap] Bot oluşturulamadı: ${err && err.message ? err.message : err}`);
|
| 473 |
+
finish();
|
| 474 |
+
return;
|
| 475 |
+
}
|
| 476 |
+
|
| 477 |
+
spawnTimeoutHandle = setTimeout(() => {
|
| 478 |
+
logger.error(`[Failover - Yedek Hesap] ${backupUsername} ${formatDurationMs(FAILOVER_SPAWN_TIMEOUT_MS)} içinde spawn olamadı, vazgeçiliyor (bir sonraki kontrolde tekrar denenecek).`);
|
| 479 |
+
finish();
|
| 480 |
+
}, FAILOVER_SPAWN_TIMEOUT_MS);
|
| 481 |
+
|
| 482 |
+
failoverBot.once("spawn", () => {
|
| 483 |
+
clearTimeout(spawnTimeoutHandle);
|
| 484 |
+
logger.info(`[Failover - Yedek Hesap] ${backupUsername} sunucuya girdi.`);
|
| 485 |
+
|
| 486 |
+
setTimeout(() => {
|
| 487 |
+
try { failoverBot.chat(`/login ${config.utils["auto-auth"].password}`); } catch (e) {}
|
| 488 |
+
logger.info(`[Failover - Yedek Hesap] ${backupUsername} Login komutu kullanıldı.`);
|
| 489 |
+
}, FAILOVER_LOGIN_DELAY_MS);
|
| 490 |
+
|
| 491 |
+
setTimeout(() => {
|
| 492 |
+
try { failoverBot.chat("/skyblock"); } catch (e) {}
|
| 493 |
+
logger.info(`[Failover - Yedek Hesap] ${backupUsername} Skyblock'a ışınlanma komutu kullanıldı.`);
|
| 494 |
+
}, FAILOVER_SKYBLOCK_DELAY_MS);
|
| 495 |
+
|
| 496 |
+
setTimeout(() => {
|
| 497 |
+
try { failoverBot.chat(GO_ISLAND_COMMAND); } catch (e) {}
|
| 498 |
+
logger.info(`[Failover - Yedek Hesap] ${GO_ISLAND_COMMAND} gönderildi, izlenen minyonların tekrar hareket etmesi bekleniyor...`);
|
| 499 |
+
}, FAILOVER_ISGO_DELAY_MS);
|
| 500 |
+
|
| 501 |
+
// Adaya varış + izleme başlatma
|
| 502 |
+
setTimeout(() => {
|
| 503 |
+
recheckHandle = setInterval(() => {
|
| 504 |
+
try {
|
| 505 |
+
const arr = Object.values(failoverBot.entities || {});
|
| 506 |
+
let allRecovered = true;
|
| 507 |
+
let sawAnyWatched = false;
|
| 508 |
+
|
| 509 |
+
for (const e of arr) {
|
| 510 |
+
if (!isWatchedKaziciEntity(e)) continue;
|
| 511 |
+
|
| 512 |
+
sawAnyWatched = true;
|
| 513 |
+
const poseKey = getPoseKey(e);
|
| 514 |
+
const prev = backupPoseTracker.get(e.id);
|
| 515 |
+
|
| 516 |
+
if (!prev) {
|
| 517 |
+
backupPoseTracker.set(e.id, { poseKey, lastChangeAt: Date.now() });
|
| 518 |
+
allRecovered = false; // henüz yeterince veri yok, bir tur daha bekle
|
| 519 |
+
continue;
|
| 520 |
+
}
|
| 521 |
+
|
| 522 |
+
if (prev.poseKey !== poseKey) {
|
| 523 |
+
prev.poseKey = poseKey;
|
| 524 |
+
prev.lastChangeAt = Date.now();
|
| 525 |
+
} else if (Date.now() - prev.lastChangeAt < STALL_TIMEOUT_MS) {
|
| 526 |
+
// son 1 dk içinde bir değişiklik olmuş demek ki hareket ediyor
|
| 527 |
+
} else {
|
| 528 |
+
allRecovered = false;
|
| 529 |
+
}
|
| 530 |
+
}
|
| 531 |
+
|
| 532 |
+
if (sawAnyWatched && allRecovered) {
|
| 533 |
+
logger.info("[Failover - Yedek Hesap] İzlenen minyonlar tekrar hareket ediyor. Yedek hesaptan çıkılıyor.");
|
| 534 |
+
finish();
|
| 535 |
+
}
|
| 536 |
+
} catch (e) {}
|
| 537 |
+
}, FAILOVER_RECHECK_INTERVAL_MS);
|
| 538 |
+
}, FAILOVER_HOME_ARRIVAL_DELAY_MS + FAILOVER_ISGO_DELAY_MS);
|
| 539 |
+
});
|
| 540 |
+
|
| 541 |
+
failoverBot.on("error", (err) => {
|
| 542 |
+
logger.error(`[Failover - Yedek Hesap] Hata: ${err && err.message ? err.message : err}`);
|
| 543 |
+
});
|
| 544 |
+
|
| 545 |
+
failoverBot.on("kicked", (reason) => {
|
| 546 |
+
logger.warn(`[Failover - Yedek Hesap] Sunucudan atıldı: ${util.inspect(reason)}`);
|
| 547 |
+
finish();
|
| 548 |
+
});
|
| 549 |
+
|
| 550 |
+
failoverBot.on("end", () => {
|
| 551 |
+
if (!finished) {
|
| 552 |
+
logger.warn("[Failover - Yedek Hesap] Bağlantı beklenmedik şekilde koptu.");
|
| 553 |
+
finish();
|
| 554 |
+
}
|
| 555 |
+
});
|
| 556 |
+
|
| 557 |
+
// Güvenlik: sonsuza kadar beklemesin
|
| 558 |
+
safetyTimeoutHandle = setTimeout(() => {
|
| 559 |
+
logger.warn(`[Failover - Yedek Hesap] Azami bekleme süresi (${formatDurationMs(FAILOVER_MAX_WAIT_MS)}) doldu, ana hesaba geri dönülüyor.`);
|
| 560 |
+
finish();
|
| 561 |
+
}, FAILOVER_MAX_WAIT_MS);
|
| 562 |
+
});
|
| 563 |
+
}
|
| 564 |
+
|
| 565 |
async function createBot() {
|
| 566 |
if (isConnecting) {
|
| 567 |
logger.warn("[Sistem] Zaten aktif bir bağlantı süreci yürütülüyor. Mükerrer istek engellendi.");
|
|
|
|
| 1060 |
}
|
| 1061 |
}
|
| 1062 |
|
| 1063 |
+
async function antiBotMove() {
|
| 1064 |
+
if (!bot || !botIsReady) return;
|
| 1065 |
+
try {
|
| 1066 |
+
const moves = ['forward', 'left', 'right', 'jump'];
|
| 1067 |
+
|
| 1068 |
+
const moveCount = Math.floor(Math.random() * 4) + 2; // 2-5 hareket
|
| 1069 |
+
|
| 1070 |
+
for (let i = 0; i < moveCount; i++) {
|
| 1071 |
+
const move = moves[Math.floor(Math.random() * moves.length)];
|
| 1072 |
+
const duration = 150 + Math.floor(Math.random() * 500);
|
| 1073 |
+
|
| 1074 |
+
bot.setControlState(move, true);
|
| 1075 |
+
await new Promise(r => setTimeout(r, duration));
|
| 1076 |
+
bot.setControlState(move, false);
|
| 1077 |
+
|
| 1078 |
+
await new Promise(r => setTimeout(r, 100 + Math.random() * 300));
|
| 1079 |
+
|
| 1080 |
+
}
|
| 1081 |
+
|
| 1082 |
+
// Rastgele kafa hareketi
|
| 1083 |
+
await bot.look(
|
| 1084 |
+
bot.entity.yaw + ((Math.random() - 0.5) * 1.5),
|
| 1085 |
+
bot.entity.pitch + ((Math.random() - 0.5) * 0.3),
|
| 1086 |
+
true
|
| 1087 |
+
);
|
| 1088 |
+
} catch (err) {
|
| 1089 |
+
logger.error(`[antiBotMove Hatası] Komut gönderilemedi: ${err && err.message ? err.message : err}`);
|
| 1090 |
+
}
|
| 1091 |
+
};
|
| 1092 |
+
|
| 1093 |
function scheduleNextCheck(delayMs) {
|
| 1094 |
if (periodicTimeoutHandle) {
|
| 1095 |
clearTimeout(periodicTimeoutHandle);
|
|
|
|
| 1106 |
await goToIsland();
|
| 1107 |
await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
|
| 1108 |
await scanAndFeed();
|
|
|
|
|
|
|
|
|
|
| 1109 |
} catch (err) {
|
| 1110 |
logger.error(`[Planlayıcı Hatası] Periyodik döngüde beklenmeyen hata: ${err && err.stack ? err.stack : err}`);
|
| 1111 |
try { scheduleNextCheck(DEFAULT_CHECK_INTERVAL_MS); } catch (e2) {}
|
|
|
|
| 1127 |
});
|
| 1128 |
}
|
| 1129 |
|
|
|
|
| 1130 |
async function scanAndFeedCore() {
|
| 1131 |
if (!bot || !botIsReady) return;
|
| 1132 |
if (!guiMutex.isLocked()) {
|
|
|
|
| 1239 |
});
|
| 1240 |
}
|
| 1241 |
|
|
|
|
|
|
|
|
|
|
| 1242 |
const FEED_LOCK_RETRY_DELAY_MS = 15 * 1000;
|
| 1243 |
+
const FEED_LOCK_MAX_RETRIES = 8;
|
| 1244 |
|
|
|
|
|
|
|
|
|
|
| 1245 |
async function scanAndFeed(retryCount) {
|
| 1246 |
retryCount = retryCount || 0;
|
| 1247 |
if (!guiMutex.tryAcquire()) {
|
|
|
|
| 1264 |
}
|
| 1265 |
}
|
| 1266 |
|
|
|
|
|
|
|
| 1267 |
async function scanAndFeedManual() {
|
| 1268 |
logger.info("[Besleyici - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 1269 |
await guiMutex.acquire();
|
|
|
|
| 1277 |
}
|
| 1278 |
}
|
| 1279 |
|
|
|
|
| 1280 |
async function activateEntityAndAwaitWindow(entity, labelForLogs) {
|
| 1281 |
if (!bot || !botIsReady || !entity || !entity.position) {
|
| 1282 |
return { success: false, reason: "Bot veya entity hazır değil" };
|
|
|
|
| 1374 |
return matches;
|
| 1375 |
}
|
| 1376 |
|
|
|
|
|
|
|
| 1377 |
async function scanAndCollectMinersCore() {
|
| 1378 |
if (!bot || !botIsReady) return;
|
| 1379 |
if (!guiMutex.isLocked()) {
|
|
|
|
| 1424 |
logger.info(`[${currentBotUsername}] Kazıcı minyon depo aktarım turu tamamlandı.`);
|
| 1425 |
}
|
| 1426 |
|
|
|
|
| 1427 |
async function scanAndCollectMiners() {
|
| 1428 |
if (!guiMutex.tryAcquire()) {
|
| 1429 |
logger.warn("[Kazıcı Toplama] Zaten bir GUI işlemi sürüyor (besleyici/kazıcı/çiftçi). Bu tur atlanıyor.");
|
|
|
|
| 1438 |
}
|
| 1439 |
}
|
| 1440 |
|
|
|
|
| 1441 |
async function scanAndCollectMinersManual() {
|
| 1442 |
logger.info("[Kazıcı Toplama - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 1443 |
await guiMutex.acquire();
|
|
|
|
| 1452 |
}
|
| 1453 |
}
|
| 1454 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1455 |
async function openCiftciAndSellAllCore() {
|
| 1456 |
if (!bot || !botIsReady) return;
|
| 1457 |
if (!guiMutex.isLocked()) {
|
|
|
|
| 1467 |
await new Promise(r => setTimeout(r, 300));
|
| 1468 |
}
|
| 1469 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1470 |
let timedOut = false;
|
| 1471 |
|
| 1472 |
await new Promise((resolve) => {
|
|
|
|
| 1505 |
}
|
| 1506 |
}
|
| 1507 |
|
|
|
|
| 1508 |
async function openCiftciAndSellAll() {
|
| 1509 |
if (!guiMutex.tryAcquire()) {
|
| 1510 |
logger.warn("[Çiftçi] Zaten bir GUI işlemi sürüyor (besleyici/kazıcı/çiftçi). Bu tur atlanıyor.");
|
|
|
|
| 1519 |
}
|
| 1520 |
}
|
| 1521 |
|
|
|
|
| 1522 |
async function openCiftciAndSellAllManual() {
|
| 1523 |
logger.info("[Çiftçi - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
|
| 1524 |
await guiMutex.acquire();
|
|
|
|
| 1533 |
}
|
| 1534 |
}
|
| 1535 |
|
|
|
|
|
|
|
|
|
|
| 1536 |
function startKaziciPeriodic() {
|
| 1537 |
+
if (kaziciIntervalHandle) return;
|
| 1538 |
|
| 1539 |
const runCycle = async () => {
|
| 1540 |
if (!bot || !botIsReady) return;
|
|
|
|
| 1565 |
logger.info(`[Kazıcı Periyodik] Bağımsız döngü başlatıldı (her ${formatDurationMs(KAZICI_CYCLE_INTERVAL_MS)}).`);
|
| 1566 |
}
|
| 1567 |
|
|
|
|
| 1568 |
function startCiftciPeriodic() {
|
| 1569 |
+
if (ciftciIntervalHandle) return;
|
| 1570 |
|
| 1571 |
const runCycle = async () => {
|
| 1572 |
if (!bot || !botIsReady) return;
|
|
|
|
| 1606 |
botIsReady = true;
|
| 1607 |
botUptimeStart = Date.now();
|
| 1608 |
|
|
|
|
| 1609 |
botActions.scanAndFeedManual = scanAndFeedManual;
|
| 1610 |
botActions.scanAndCollectMinersManual = scanAndCollectMinersManual;
|
| 1611 |
botActions.openCiftciAndSellAllManual = openCiftciAndSellAllManual;
|
| 1612 |
botActions.goToIslandManual = goToIsland;
|
| 1613 |
botActions.sendSkyblockManual = sendSkyblockCommand;
|
| 1614 |
+
botActions.antiBotMove = antiBotMove();
|
| 1615 |
|
|
|
|
|
|
|
| 1616 |
startKaziciPeriodic();
|
| 1617 |
startCiftciPeriodic();
|
| 1618 |
+
startStallWatcher();
|
| 1619 |
|
| 1620 |
if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
|
| 1621 |
const password = config.utils["auto-auth"].password;
|
|
|
|
| 1642 |
}
|
| 1643 |
}, 7500);
|
| 1644 |
|
|
|
|
| 1645 |
setSafeTimeout(async () => {
|
| 1646 |
if (!bot || !botIsReady) return;
|
| 1647 |
isMainCycleRunning = true;
|
|
|
|
| 1649 |
await goToIsland();
|
| 1650 |
await new Promise(r => setTimeout(r, HOME_ARRIVAL_DELAY_MS));
|
| 1651 |
await scanAndFeed();
|
|
|
|
|
|
|
| 1652 |
} catch (err) {
|
| 1653 |
logger.error(`[Spawn Hatası] İlk kontrol döngüsünde beklenmeyen hata: ${err && err.stack ? err.stack : err}`);
|
| 1654 |
try { scheduleNextCheck(DEFAULT_CHECK_INTERVAL_MS); } catch (e2) {}
|
|
|
|
| 1662 |
}
|
| 1663 |
});
|
| 1664 |
|
| 1665 |
+
bot.on("entityMoved", (entity) => {
|
| 1666 |
+
try { trackKaziciPoseIfWatched(entity); } catch (e) {}
|
| 1667 |
+
});
|
| 1668 |
+
|
| 1669 |
+
bot.on("entitySpawn", (entity) => {
|
| 1670 |
+
try { trackKaziciPoseIfWatched(entity); } catch (e) {}
|
| 1671 |
+
});
|
| 1672 |
+
|
| 1673 |
bot.on("windowOpen", async (window) => {
|
| 1674 |
if (!bot) return;
|
| 1675 |
try {
|
|
|
|
| 1699 |
try { bot.closeWindow(window); } catch(e){}
|
| 1700 |
|
| 1701 |
} else if (isCiftciWindow) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1702 |
try {
|
| 1703 |
logger.info(`[${currentBotUsername}] Çiftçi (Hepsini Sat) menüsü açıldı. ${formatDurationMs(CIFTCI_CLICK_DELAY_AFTER_OPEN_MS)} bekleniyor, sonra slot ${CIFTCI_SELL_ALL_SLOT}'e ${CIFTCI_CLICK_REPEAT_COUNT} kez tıklanacak...`);
|
| 1704 |
await new Promise(r => setTimeout(r, CIFTCI_CLICK_DELAY_AFTER_OPEN_MS));
|
|
|
|
| 1783 |
try {
|
| 1784 |
logger.warn(manualStopRequested ? "Bağlantı koptu. Manuel durdurma istendiği için yeniden bağlanılmayacak." : "Bağlantı koptu. Tüm zamanlayıcılar sıfırlanıyor ve YENİDEN BAĞLANMA SÜRECİ BAŞLIYOR...");
|
| 1785 |
stopPeriodicHomeChecks();
|
| 1786 |
+
stopStallWatcher();
|
| 1787 |
lastCheckAtMs = null;
|
| 1788 |
botIsReady = false;
|
| 1789 |
baglantiTuru = "Yok";
|
|
|
|
| 2070 |
next_ciftci_sell: nextCiftciTimeStr,
|
| 2071 |
gui_lock_busy: guiMutex.isLocked(),
|
| 2072 |
manually_stopped: manualStopRequested,
|
| 2073 |
+
is_connecting: isConnecting,
|
| 2074 |
+
failover_mode_active: failoverModeActive
|
| 2075 |
});
|
| 2076 |
});
|
| 2077 |
|
|
|
|
| 2094 |
res.send({ success: true, message: "Bot tamamen sıfırdan yeniden başlatılıyor (soket/SSH dahil)." });
|
| 2095 |
});
|
| 2096 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2097 |
app.get("/bot/kazici-kontrol", (req, res) => {
|
| 2098 |
if (!bot || !botIsReady || !botActions.scanAndCollectMinersManual) {
|
| 2099 |
return res.status(503).send({ success: false, message: "Bot hazır değil." });
|
|
|
|
| 2134 |
res.send({ success: true, message: `${GO_ISLAND_COMMAND} komutu gönderildi.` });
|
| 2135 |
});
|
| 2136 |
|
| 2137 |
+
app.get("/bot/sendmsg", (req, res) => {
|
| 2138 |
+
if (!bot || !botIsReady) {
|
| 2139 |
+
return res.status(503).send({ success: false, message: "Bot hazır değil." });
|
| 2140 |
+
}
|
| 2141 |
+
|
| 2142 |
+
const message = req.query.message;
|
| 2143 |
+
if (!message || typeof message !== "string" || message.trim().length === 0) {
|
| 2144 |
+
return res.status(400).send({ success: false, message: "message query parametresi zorunlu." });
|
| 2145 |
+
}
|
| 2146 |
+
|
| 2147 |
+
try {
|
| 2148 |
+
bot.chat(message);
|
| 2149 |
+
logger.info(`[${bot.username}] /sendmsg üzerinden chat mesajı gönderildi: ${message}`);
|
| 2150 |
+
res.send({ success: true, message: "Mesaj gönderildi.", sent: message });
|
| 2151 |
+
} catch (err) {
|
| 2152 |
+
logger.error(`[/bot/sendmsg Hatası] ${err && err.message ? err.message : err}`);
|
| 2153 |
+
res.status(500).send({ success: false, message: "Mesaj gönderilirken hata oluştu." });
|
| 2154 |
+
}
|
| 2155 |
+
});
|
| 2156 |
+
|
| 2157 |
+
app.get("/bot/antibotmove", (req, res) => {
|
| 2158 |
+
if (!bot || !botIsReady) {
|
| 2159 |
+
return res.status(503).send({ success: false, message: "Bot hazır değil." });
|
| 2160 |
+
}
|
| 2161 |
+
|
| 2162 |
+
try {
|
| 2163 |
+
botActions.antiBotMove().catch(e => logger.error(`[/bot/antibotmove Hatası] ${e && e.stack ? e.stack : e}`));
|
| 2164 |
+
res.send({ success: true, message: "Anti Bot Yürüyüşü Yapıldı."});
|
| 2165 |
+
} catch (err) {
|
| 2166 |
+
logger.error(`[/bot/antibotmove Hatası] ${err && err.message ? err.message : err}`);
|
| 2167 |
+
res.status(500).send({ success: false, message: "Anti Bot Move sırasında hata oluştu." });
|
| 2168 |
+
}
|
| 2169 |
+
});
|
| 2170 |
+
|
| 2171 |
app.get("/", (req, res) => res.send("Bot Aktif"));
|
| 2172 |
|
| 2173 |
app.get("/messages", (req, res) => {
|