Spaces:
Paused
Paused
Update bot.js
Browse files
bot.js
CHANGED
|
@@ -44,19 +44,13 @@ const CIFTCI_SELL_ALL_SLOT = 45;
|
|
| 44 |
const CIFTCI_COMMAND = "/çiftçi menü";
|
| 45 |
const CIFTCI_WINDOW_TIMEOUT_MS = 6000;
|
| 46 |
const CIFTCI_LORE_FALLBACK_KEYWORDS = ["hepsini sat"];
|
| 47 |
-
// Menü açıldıktan sonra sunucunun içeriği (lore/slot) tam yerleştirmesi için
|
| 48 |
-
// beklenecek süre, tıklamadan önce. Ardından art arda birkaç kez tıklanır.
|
| 49 |
const CIFTCI_CLICK_DELAY_AFTER_OPEN_MS = 1000;
|
| 50 |
const CIFTCI_CLICK_REPEAT_COUNT = 3;
|
| 51 |
const CIFTCI_CLICK_REPEAT_GAP_MS = 350;
|
| 52 |
|
| 53 |
-
|
| 54 |
-
const
|
| 55 |
|
| 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 |
-
// --- ÇİFTÇİ FİLTRE / STORAGE INFO TARAMA AYARLARI ---
|
| 60 |
const CIFTCI_FILTER_MODES = [
|
| 61 |
"Standart",
|
| 62 |
"Favoriler",
|
|
@@ -65,14 +59,14 @@ const CIFTCI_FILTER_MODES = [
|
|
| 65 |
"Satışı açık olanlar",
|
| 66 |
"Toplaması açık olanlar"
|
| 67 |
];
|
| 68 |
-
const CIFTCI_TARGET_FILTER_INDEX = 3;
|
| 69 |
const CIFTCI_ACTIVE_FILTER_COLOR = "#FCF988";
|
| 70 |
const CIFTCI_FILTER_ITEM_NAME_KEYWORD = "Filtre";
|
| 71 |
-
const CIFTCI_FILTER_STEP_WAIT_MS = 1000;
|
| 72 |
-
const CIFTCI_FILTER_RETRY_WAIT_MS = 1000;
|
| 73 |
-
const CIFTCI_FILTER_MAX_RETRIES = 10;
|
| 74 |
-
const STORAGE_SCAN_INTERVAL_MS = 15 * 60 * 1000;
|
| 75 |
-
const STORAGE_TRACKED_ITEMS = ["diamond", "emerald", "iron_block"];
|
| 76 |
|
| 77 |
// --- SİPARİŞ (ORDER) SİSTEMİ AYARLARI ---
|
| 78 |
const ORDER_COMMAND_PREFIX = "/order";
|
|
@@ -81,8 +75,11 @@ const ORDER_WINDOW_SETTLE_DELAY_MS = 500;
|
|
| 81 |
const ORDER_AFTER_SELECT_DELAY_MS = 500;
|
| 82 |
const ORDER_IS_GO_SECOND_DELAY_MS = 5000;
|
| 83 |
const ORDER_ALLOWED_ITEMS = ["diamond", "emerald"];
|
| 84 |
-
const ORDER_LIST_TITLE_KEYWORD = "ѕiᴘᴀʀişʟᴇʀ";
|
| 85 |
-
const ORDER_DELIVERY_TITLE_KEYWORD = "ᴛᴇѕʟiᴍ ᴇᴛᴍᴇ";
|
|
|
|
|
|
|
|
|
|
| 86 |
|
| 87 |
let storageInfoCache = {
|
| 88 |
diamond: null,
|
|
@@ -92,23 +89,18 @@ let storageInfoCache = {
|
|
| 92 |
};
|
| 93 |
let storageScanIntervalHandle = null;
|
| 94 |
|
| 95 |
-
// Çiftçi penceresinin şu an hangi amaçla açık olduğunu tutan bayrak.
|
| 96 |
-
// "sell" -> hepsini-sat akışı, "scan" -> storage bilgisi tarama akışı, "order" -> sipariş akışı.
|
| 97 |
let ciftciWindowPurpose = "sell";
|
| 98 |
|
| 99 |
-
|
| 100 |
-
const
|
| 101 |
-
const
|
| 102 |
-
const FAILOVER_HOME_ARRIVAL_DELAY_MS = 4000; // yedek hesapta /is go sonrası varış beklemesi
|
| 103 |
const FAILOVER_LOGIN_DELAY_MS = 2500;
|
| 104 |
const FAILOVER_SKYBLOCK_DELAY_MS = 7500;
|
| 105 |
const FAILOVER_ISGO_DELAY_MS = 12500;
|
| 106 |
-
const FAILOVER_RECHECK_INTERVAL_MS = 20 * 1000;
|
| 107 |
-
const FAILOVER_MAX_WAIT_MS = 60 * 60 * 1000;
|
| 108 |
-
const FAILOVER_SPAWN_TIMEOUT_MS = 30 * 1000;
|
| 109 |
|
| 110 |
-
// İzlenen (KAZICI_NAMES ile eşleşmeyen, başka hesaptan konan) kazıcı minyonların
|
| 111 |
-
// skin texture hash'i. Bu skin + elde iron_pickaxe olan armor stand'ler izlenir.
|
| 112 |
const WATCHED_KAZICI_SKIN_HASHES = new Set([
|
| 113 |
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDQ4ODcwY2E3N2FhNjk5ZDAxNzA5M2I4Mjc3OWQwYTU5OGRjNGYzZjQ5ZDM1MTUzMmFlNGQ5NjMzZGNjMmE1YSJ9fX0=",
|
| 114 |
]);
|
|
@@ -123,7 +115,6 @@ let messagesTimeout = null;
|
|
| 123 |
let isListeningChat = false;
|
| 124 |
const ansiToHtmlConvert = new (require('ansi-to-html'))({ newline: true });
|
| 125 |
|
| 126 |
-
// --- GÜVENLİ BAĞLANTI DEĞİŞKENLERİ ---
|
| 127 |
let isConnecting = false;
|
| 128 |
let isDestroying = false;
|
| 129 |
let reconnectTimeout = null;
|
|
@@ -132,45 +123,37 @@ let currentStream = null;
|
|
| 132 |
let currentSocket = null;
|
| 133 |
let windowOpenResolvers = [];
|
| 134 |
|
| 135 |
-
// --- PANEL METRİKLERİ ---
|
| 136 |
let botUptimeStart = null;
|
| 137 |
let lastFullFeedTimeStr = "Henüz besleme yapılmadı";
|
| 138 |
let lastCheckTimeStr = "Henüz kontrol yapılmadı";
|
| 139 |
let nextScheduledCheckTimeStr = "Botun spawn olması bekleniyor...";
|
| 140 |
|
| 141 |
-
// --- KAZICI PANEL METRİKLERİ (bağımsız) ---
|
| 142 |
let lastKaziciCheckTimeStr = "Henüz kazıcı kontrolü yapılmadı";
|
| 143 |
let nextKaziciTimeStr = "Botun spawn olması bekleniyor...";
|
| 144 |
let nextKaziciAtMs = null;
|
| 145 |
|
| 146 |
-
// --- ÇİFTÇİ PANEL METRİKLERİ (bağımsız) ---
|
| 147 |
let lastCiftciSellTimeStr = "Henüz çiftçi satışı yapılmadı";
|
| 148 |
let nextCiftciTimeStr = "Botun spawn olması bekleniyor...";
|
| 149 |
let nextCiftciAtMs = null;
|
| 150 |
|
| 151 |
-
// --- SİPARİŞ (ORDER) PANEL METRİKLERİ ---
|
| 152 |
let lastOrderTimeStr = "Henüz sipariş işlemi yapılmadı";
|
| 153 |
|
| 154 |
-
|
| 155 |
-
let
|
| 156 |
-
let
|
| 157 |
-
let
|
| 158 |
-
let
|
| 159 |
-
let isMainCycleRunning = false; // Besleyici (goToIsland->besle) ana döngüsü sürüyor mu
|
| 160 |
|
| 161 |
-
|
| 162 |
-
let poseTracker = new Map(); // entityId -> { poseKey, lastChangeAt, uuid }
|
| 163 |
let stallCheckIntervalHandle = null;
|
| 164 |
-
let failoverModeActive = false;
|
| 165 |
-
let failoverBot = null;
|
| 166 |
-
let failoverInProgress = false;
|
| 167 |
|
| 168 |
-
// --- DİNAMİK IP VE KONUM BİLGİLERİ ---
|
| 169 |
let activeConnectionIp = "Bilinmiyor";
|
| 170 |
let activeConnectionLocation = "Bilinmiyor";
|
| 171 |
let localExternalIp = "Bilinmiyor";
|
| 172 |
|
| 173 |
-
// --- DİNAMİK ZAMANLAYICI KONTROLÜ ---
|
| 174 |
let periodicTimeoutHandle = null;
|
| 175 |
let activeTimeouts = [];
|
| 176 |
|
|
@@ -180,7 +163,6 @@ function setSafeTimeout(fn, delay) {
|
|
| 180 |
return t;
|
| 181 |
}
|
| 182 |
|
| 183 |
-
// --- ÖNCELİKLİ GUI KİLİDİ (MUTEX) ---
|
| 184 |
class PriorityGuiMutex {
|
| 185 |
constructor() {
|
| 186 |
this._locked = false;
|
|
@@ -275,7 +257,6 @@ function stopPeriodicHomeChecks() {
|
|
| 275 |
nextCiftciTimeStr = "Zamanlama durduruldu.";
|
| 276 |
}
|
| 277 |
|
| 278 |
-
// --- MANUEL DURDURMA/BAŞLATMA KONTROLÜ ---
|
| 279 |
let manualStopRequested = false;
|
| 280 |
|
| 281 |
async function getIpLocation(ip) {
|
|
@@ -324,14 +305,6 @@ https.get('https://api.ipify.org?format=json', (res) => {
|
|
| 324 |
});
|
| 325 |
}).on('error', () => {});
|
| 326 |
|
| 327 |
-
// =====================================================================
|
| 328 |
-
// KAZICI FAILOVER (YEDEK HESAP) YARDIMCI FONKSİYONLARI
|
| 329 |
-
// Bunlar module-level (createBot() dışında) çünkü bot bağlantısı kesilip
|
| 330 |
-
// yeniden kurulduğunda bile (createBot() tekrar çağrıldığında) hayatta
|
| 331 |
-
// kalmaları gerekiyor.
|
| 332 |
-
// =====================================================================
|
| 333 |
-
|
| 334 |
-
// Entity'nin skin texture değerini (player_head equipment'inden) çıkarır.
|
| 335 |
function getEntitySkinHash(entity) {
|
| 336 |
try {
|
| 337 |
const equipment = entity.equipment || [];
|
|
@@ -351,7 +324,6 @@ function getEntitySkinHash(entity) {
|
|
| 351 |
return null;
|
| 352 |
}
|
| 353 |
|
| 354 |
-
// Entity'nin elinde (equipment[0] = main hand) iron_pickaxe olup olmadığını kontrol eder.
|
| 355 |
function hasIronPickaxeEquipped(entity) {
|
| 356 |
try {
|
| 357 |
const equipment = entity.equipment || [];
|
|
@@ -362,7 +334,6 @@ function hasIronPickaxeEquipped(entity) {
|
|
| 362 |
}
|
| 363 |
}
|
| 364 |
|
| 365 |
-
// Skin + iron_pickaxe ikisi birden tutuyorsa bu entity izlenen kazıcı minyondur.
|
| 366 |
function isWatchedKaziciEntity(entity) {
|
| 367 |
if (!entity || entity.name !== "armor_stand") return false;
|
| 368 |
const skinHash = getEntitySkinHash(entity);
|
|
@@ -370,7 +341,6 @@ function isWatchedKaziciEntity(entity) {
|
|
| 370 |
return hasIronPickaxeEquipped(entity);
|
| 371 |
}
|
| 372 |
|
| 373 |
-
// metadata içindeki pose (kol/kafa açıları) + pozisyonu birleştirip bir imza çıkarır.
|
| 374 |
function getPoseKey(entity) {
|
| 375 |
try {
|
| 376 |
const md = entity.metadata || [];
|
|
@@ -389,8 +359,6 @@ function getPoseKey(entity) {
|
|
| 389 |
}
|
| 390 |
}
|
| 391 |
|
| 392 |
-
// bot.on('entityMoved', ...) ve bot.on('entitySpawn', ...) içinden çağrılır.
|
| 393 |
-
// İzlenen kazıcı minyonun pose'unu takip eder.
|
| 394 |
function trackKaziciPoseIfWatched(entity) {
|
| 395 |
if (!entity) return;
|
| 396 |
if (!isWatchedKaziciEntity(entity)) return;
|
|
@@ -408,10 +376,8 @@ function trackKaziciPoseIfWatched(entity) {
|
|
| 408 |
prev.poseKey = poseKey;
|
| 409 |
prev.lastChangeAt = Date.now();
|
| 410 |
}
|
| 411 |
-
// poseKey aynıysa lastChangeAt GÜNCELLENMEZ -> hareketsizlik süresi büyümeye devam eder.
|
| 412 |
}
|
| 413 |
|
| 414 |
-
// Artık dünyada olmayan entity kayıtlarını temizler.
|
| 415 |
function pruneStaleTrackedEntities() {
|
| 416 |
if (!bot || !bot.entities) return;
|
| 417 |
for (const id of poseTracker.keys()) {
|
|
@@ -452,9 +418,6 @@ function stopStallWatcher() {
|
|
| 452 |
poseTracker.clear();
|
| 453 |
}
|
| 454 |
|
| 455 |
-
// Ana hesabı geçici düşürüp yedek hesabı (kullaniciadi1) devreye alan, izlenen
|
| 456 |
-
// kazıcı minyonlar tekrar hareket edene kadar bekleyen, sonra ana hesabı
|
| 457 |
-
// yeniden bağlayan tam akış.
|
| 458 |
async function triggerFailoverSequence() {
|
| 459 |
if (failoverInProgress) return;
|
| 460 |
failoverInProgress = true;
|
|
@@ -465,7 +428,7 @@ async function triggerFailoverSequence() {
|
|
| 465 |
|
| 466 |
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.`);
|
| 467 |
|
| 468 |
-
manualStopRequested = true;
|
| 469 |
stopPeriodicHomeChecks();
|
| 470 |
safeDestroyAllConnections();
|
| 471 |
|
|
@@ -484,9 +447,6 @@ async function triggerFailoverSequence() {
|
|
| 484 |
failoverInProgress = false;
|
| 485 |
}
|
| 486 |
|
| 487 |
-
// Yedek hesapla ayrı bir mineflayer bot'u başlatır: /login, /skyblock, /is go
|
| 488 |
-
// atar (ana hesaptaki ile AYNI gecikme süreleriyle), sonra izlenen minyonların
|
| 489 |
-
// hareketine bakar. Hareket geri gelince bağlantıyı kapatıp resolve eder.
|
| 490 |
function runBackupAccountAndWaitForRecovery(backupUsername) {
|
| 491 |
return new Promise((resolve) => {
|
| 492 |
const backupPoseTracker = new Map();
|
|
@@ -549,7 +509,6 @@ function runBackupAccountAndWaitForRecovery(backupUsername) {
|
|
| 549 |
logger.info(`[Failover - Yedek Hesap] ${GO_ISLAND_COMMAND} gönderildi, izlenen minyonların tekrar hareket etmesi bekleniyor...`);
|
| 550 |
}, FAILOVER_ISGO_DELAY_MS);
|
| 551 |
|
| 552 |
-
// Adaya varış + izleme başlatma
|
| 553 |
setTimeout(() => {
|
| 554 |
recheckHandle = setInterval(() => {
|
| 555 |
try {
|
|
@@ -566,7 +525,7 @@ function runBackupAccountAndWaitForRecovery(backupUsername) {
|
|
| 566 |
|
| 567 |
if (!prev) {
|
| 568 |
backupPoseTracker.set(e.id, { poseKey, lastChangeAt: Date.now() });
|
| 569 |
-
allRecovered = false;
|
| 570 |
continue;
|
| 571 |
}
|
| 572 |
|
|
@@ -574,7 +533,7 @@ function runBackupAccountAndWaitForRecovery(backupUsername) {
|
|
| 574 |
prev.poseKey = poseKey;
|
| 575 |
prev.lastChangeAt = Date.now();
|
| 576 |
} else if (Date.now() - prev.lastChangeAt < STALL_TIMEOUT_MS) {
|
| 577 |
-
//
|
| 578 |
} else {
|
| 579 |
allRecovered = false;
|
| 580 |
}
|
|
@@ -605,7 +564,6 @@ function runBackupAccountAndWaitForRecovery(backupUsername) {
|
|
| 605 |
}
|
| 606 |
});
|
| 607 |
|
| 608 |
-
// Güvenlik: sonsuza kadar beklemesin
|
| 609 |
safetyTimeoutHandle = setTimeout(() => {
|
| 610 |
logger.warn(`[Failover - Yedek Hesap] Azami bekleme süresi (${formatDurationMs(FAILOVER_MAX_WAIT_MS)}) doldu, ana hesaba geri dönülüyor.`);
|
| 611 |
finish();
|
|
@@ -967,72 +925,68 @@ async function createBot() {
|
|
| 967 |
} catch (e) { return undefined; }
|
| 968 |
};
|
| 969 |
|
| 970 |
-
|
| 971 |
-
|
| 972 |
-
|
| 973 |
-
|
| 974 |
-
|
| 975 |
-
|
| 976 |
-
} catch (e) { return undefined; }
|
| 977 |
-
}
|
| 978 |
-
|
| 979 |
-
// {type,value} tarzı NBT-benzeri sarmalayıcıyı açar
|
| 980 |
-
function nbtUnwrap(node) {
|
| 981 |
-
if (node && typeof node === "object" && "type" in node && "value" in node) {
|
| 982 |
-
return node.value;
|
| 983 |
}
|
| 984 |
-
return node;
|
| 985 |
-
};
|
| 986 |
|
| 987 |
-
|
| 988 |
-
|
| 989 |
-
|
| 990 |
-
|
| 991 |
-
|
| 992 |
-
|
| 993 |
-
if (typeof node === "object") {
|
| 994 |
-
if ("type" in node && "value" in node) {
|
| 995 |
-
const t = node.type, v = node.value;
|
| 996 |
-
if (t === "string") return typeof v === "string" ? v : "";
|
| 997 |
-
if (t === "list" || t === "compound") return flattenTextComponent(v);
|
| 998 |
-
return ""; // byte/int vs. metin değil
|
| 999 |
-
}
|
| 1000 |
-
let out = "";
|
| 1001 |
-
if ("text" in node) out += flattenTextComponent(node.text);
|
| 1002 |
-
if ("extra" in node) out += flattenTextComponent(node.extra);
|
| 1003 |
-
return out;
|
| 1004 |
-
}
|
| 1005 |
-
return "";
|
| 1006 |
-
};
|
| 1007 |
|
| 1008 |
-
|
| 1009 |
-
|
| 1010 |
-
|
| 1011 |
-
|
| 1012 |
|
| 1013 |
-
function walk(node) {
|
| 1014 |
-
if (node == null) return;
|
| 1015 |
-
if (typeof node === "string") { text += node; return; }
|
| 1016 |
-
if (Array.isArray(node)) { node.forEach(walk); return; }
|
| 1017 |
if (typeof node === "object") {
|
| 1018 |
if ("type" in node && "value" in node) {
|
| 1019 |
const t = node.type, v = node.value;
|
| 1020 |
-
if (t === "string")
|
| 1021 |
-
if (t === "list" || t === "compound")
|
| 1022 |
-
return;
|
| 1023 |
}
|
| 1024 |
-
|
| 1025 |
-
|
| 1026 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1027 |
}
|
| 1028 |
-
if ("text" in node) walk(node.text);
|
| 1029 |
-
if ("extra" in node) walk(node.extra);
|
| 1030 |
}
|
| 1031 |
-
}
|
| 1032 |
|
| 1033 |
-
|
| 1034 |
-
|
| 1035 |
-
};
|
| 1036 |
|
| 1037 |
function deepSearchForString(root, targetVariantsList) {
|
| 1038 |
const results = [];
|
|
@@ -1106,8 +1060,7 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1106 |
const texts = [];
|
| 1107 |
try {
|
| 1108 |
if (!slot) return texts;
|
| 1109 |
-
|
| 1110 |
-
// Yeni format: components
|
| 1111 |
const customNameData = getComponentData(slot, "custom_name");
|
| 1112 |
if (customNameData !== undefined) {
|
| 1113 |
const nameTxt = flattenTextComponent(customNameData);
|
|
@@ -1121,8 +1074,7 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1121 |
}
|
| 1122 |
}
|
| 1123 |
if (texts.length > 0) return texts;
|
| 1124 |
-
|
| 1125 |
-
// Eski format: nbt (fallback)
|
| 1126 |
function extractPlain(raw) {
|
| 1127 |
if (!raw || typeof raw !== "string") return null;
|
| 1128 |
try {
|
|
@@ -1137,12 +1089,12 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1137 |
} catch (e) {}
|
| 1138 |
return raw;
|
| 1139 |
}
|
| 1140 |
-
|
| 1141 |
if (slot.nbt) {
|
| 1142 |
const name = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
|
| 1143 |
const plainName = extractPlain(name);
|
| 1144 |
if (plainName) texts.push(plainName);
|
| 1145 |
-
|
| 1146 |
const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
|
| 1147 |
if (Array.isArray(lore)) {
|
| 1148 |
for (const line of lore) {
|
|
@@ -1151,7 +1103,7 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1151 |
}
|
| 1152 |
}
|
| 1153 |
}
|
| 1154 |
-
|
| 1155 |
if (texts.length === 0) {
|
| 1156 |
texts.push(util.inspect(slot, { depth: null }));
|
| 1157 |
}
|
|
@@ -1194,12 +1146,10 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1194 |
}
|
| 1195 |
}
|
| 1196 |
|
| 1197 |
-
// --- SENDMONEY: /money oku, bakiyeden 1000 eksiğini ilgili nick'e /pay ile gönder ---
|
| 1198 |
const MONEY_BALANCE_REGEX = /bakiyen:\s*([\d.,]+)\s*TL/i;
|
| 1199 |
const MONEY_RESPONSE_TIMEOUT_MS = 8000;
|
| 1200 |
|
| 1201 |
function parseBalanceToAdjustedAmount(rawBalanceStr) {
|
| 1202 |
-
// "444,626.89" -> virgülleri kaldır -> "444626.89" -> noktadan öncesini al -> "444626"
|
| 1203 |
const noCommas = rawBalanceStr.replace(/,/g, "");
|
| 1204 |
const beforeDot = noCommas.split(".")[0];
|
| 1205 |
const intValue = parseInt(beforeDot, 10);
|
|
@@ -1281,22 +1231,21 @@ function parseComponentLoreLine(lineNode) {
|
|
| 1281 |
if (!bot || !botIsReady) return;
|
| 1282 |
try {
|
| 1283 |
const moves = ['forward', 'left', 'right', 'jump'];
|
| 1284 |
-
|
| 1285 |
-
const moveCount = Math.floor(Math.random() * 4) + 2;
|
| 1286 |
-
|
| 1287 |
for (let i = 0; i < moveCount; i++) {
|
| 1288 |
const move = moves[Math.floor(Math.random() * moves.length)];
|
| 1289 |
const duration = 150 + Math.floor(Math.random() * 500);
|
| 1290 |
-
|
| 1291 |
bot.setControlState(move, true);
|
| 1292 |
await new Promise(r => setTimeout(r, duration));
|
| 1293 |
bot.setControlState(move, false);
|
| 1294 |
-
|
| 1295 |
await new Promise(r => setTimeout(r, 100 + Math.random() * 300));
|
| 1296 |
-
|
| 1297 |
}
|
| 1298 |
-
|
| 1299 |
-
// Rastgele kafa hareketi
|
| 1300 |
await bot.look(
|
| 1301 |
bot.entity.yaw + ((Math.random() - 0.5) * 1.5),
|
| 1302 |
bot.entity.pitch + ((Math.random() - 0.5) * 0.3),
|
|
@@ -1752,24 +1701,18 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1752 |
}
|
| 1753 |
}
|
| 1754 |
|
| 1755 |
-
// =====================================================================
|
| 1756 |
-
// ÇİFTÇİ FİLTRE NAVİGASYONU + STORAGE INFO TARAMA
|
| 1757 |
-
// =====================================================================
|
| 1758 |
-
|
| 1759 |
function stripColorAndGetLoreLines(window) {
|
| 1760 |
if (!window || !Array.isArray(window.slots)) return null;
|
| 1761 |
for (const slot of window.slots) {
|
| 1762 |
if (!slot) continue;
|
| 1763 |
-
|
| 1764 |
let nameTxt = "";
|
| 1765 |
-
|
| 1766 |
-
// Yeni format: components
|
| 1767 |
const customNameData = getComponentData(slot, "custom_name");
|
| 1768 |
if (customNameData !== undefined) {
|
| 1769 |
nameTxt = flattenTextComponent(customNameData);
|
| 1770 |
}
|
| 1771 |
-
|
| 1772 |
-
// Eski format: nbt (fallback)
|
| 1773 |
if (!nameTxt && slot.nbt) {
|
| 1774 |
const nameRaw = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
|
| 1775 |
try {
|
|
@@ -1778,7 +1721,7 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1778 |
else if (maybe && maybe.text) nameTxt = maybe.text;
|
| 1779 |
} catch (e) { nameTxt = nameRaw || ""; }
|
| 1780 |
}
|
| 1781 |
-
|
| 1782 |
if (nameTxt.includes(CIFTCI_FILTER_ITEM_NAME_KEYWORD)) {
|
| 1783 |
return { slot, index: window.slots.indexOf(slot) };
|
| 1784 |
}
|
|
@@ -1788,8 +1731,7 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1788 |
|
| 1789 |
function getFilterItemLoreEntries(filterSlot) {
|
| 1790 |
const entries = [];
|
| 1791 |
-
|
| 1792 |
-
// Yeni format: components
|
| 1793 |
const loreData = getComponentData(filterSlot, "lore");
|
| 1794 |
if (Array.isArray(loreData)) {
|
| 1795 |
for (const line of loreData) {
|
|
@@ -1797,8 +1739,7 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1797 |
}
|
| 1798 |
if (entries.length > 0) return entries;
|
| 1799 |
}
|
| 1800 |
-
|
| 1801 |
-
// Eski format: nbt (fallback)
|
| 1802 |
try {
|
| 1803 |
const lore = safeGet(filterSlot.nbt, ["value", "display", "value", "Lore", "value"]);
|
| 1804 |
if (!Array.isArray(lore)) return entries;
|
|
@@ -1834,7 +1775,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1834 |
);
|
| 1835 |
if (match) return i;
|
| 1836 |
}
|
| 1837 |
-
// fallback: sadece renkle bulmayı dene
|
| 1838 |
const colorMatch = loreEntries.find(e => e.color === CIFTCI_ACTIVE_FILTER_COLOR);
|
| 1839 |
if (colorMatch) {
|
| 1840 |
for (let i = 0; i < CIFTCI_FILTER_MODES.length; i++) {
|
|
@@ -1845,7 +1785,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1845 |
}
|
| 1846 |
|
| 1847 |
async function waitForFilterItem(maxRetries) {
|
| 1848 |
-
// window açıldıktan sonra Filtre item'ı gözükene kadar bekler
|
| 1849 |
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
| 1850 |
await new Promise(r => setTimeout(r, attempt === 0 ? CIFTCI_FILTER_STEP_WAIT_MS : CIFTCI_FILTER_RETRY_WAIT_MS));
|
| 1851 |
if (!bot || !bot.currentWindow) return null;
|
|
@@ -1917,11 +1856,11 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1917 |
}
|
| 1918 |
|
| 1919 |
const total = CIFTCI_FILTER_MODES.length;
|
| 1920 |
-
const forwardDist = (CIFTCI_TARGET_FILTER_INDEX - currentIndex + total) % total;
|
| 1921 |
-
const backwardDist = (currentIndex - CIFTCI_TARGET_FILTER_INDEX + total) % total;
|
| 1922 |
|
| 1923 |
const useLeftClick = forwardDist <= backwardDist;
|
| 1924 |
-
const mouseButton = useLeftClick ? 0 : 1;
|
| 1925 |
|
| 1926 |
logger.info(`[Çiftçi Filtre] Mevcut: "${CIFTCI_FILTER_MODES[currentIndex]}" -> Hedef: "${CIFTCI_FILTER_MODES[CIFTCI_TARGET_FILTER_INDEX]}". ${useLeftClick ? "Sol tık (aşağı)" : "Sağ tık (yukarı)"} kullanılacak.`);
|
| 1927 |
|
|
@@ -1931,8 +1870,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 1931 |
logger.error(`[Çiftçi Filtre] Tıklama hatası: ${e && e.message ? e.message : e}`);
|
| 1932 |
return false;
|
| 1933 |
}
|
| 1934 |
-
|
| 1935 |
-
// bir sonraki turda waitForFilterItem zaten bekleyecek
|
| 1936 |
}
|
| 1937 |
|
| 1938 |
logger.warn("[Çiftçi Filtre] Azami deneme sayısına ulaşıldı, Jeneratör materyallerine geçilemedi.");
|
|
@@ -2033,16 +1970,6 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 2033 |
|
| 2034 |
// =====================================================================
|
| 2035 |
// SİPARİŞ (ORDER) SİSTEMİ
|
| 2036 |
-
// Akış:
|
| 2037 |
-
// 1) Çiftçi menüsü -> Jeneratör materyalleri filtresine geç (varsa zaten oradadır)
|
| 2038 |
-
// 2) İstenen item'ın (diamond/emerald) slotuna shift+sağ tık -> envanter dolana kadar item verir
|
| 2039 |
-
// 3) Menüyü kapat
|
| 2040 |
-
// 4) antiBotMove -> /is go -> 5sn bekle -> /is go
|
| 2041 |
-
// 5) /order <nick> gönder
|
| 2042 |
-
// 6) windowOpen bekle, +500ms sonra güncel pencereyi oku
|
| 2043 |
-
// 7) Lore'da nick geçen slotu bul -> sol tık ile seç
|
| 2044 |
-
// 8) +500ms sonra pencere boşsa envanterdeki item'ları shift+sol tık ile order'a aktar
|
| 2045 |
-
// 9) Pencereyi kapat
|
| 2046 |
// =====================================================================
|
| 2047 |
|
| 2048 |
async function waitForNextWindowOpen(timeoutMs) {
|
|
@@ -2075,7 +2002,7 @@ function activateEntityAtNoLook(entity, position) {
|
|
| 2075 |
return -1;
|
| 2076 |
}
|
| 2077 |
|
| 2078 |
-
async function processOrderCore(itemInternalName, nick) {
|
| 2079 |
if (!bot || !botIsReady) return { success: false, message: "Bot hazır değil." };
|
| 2080 |
if (!guiMutex.isLocked()) {
|
| 2081 |
logger.error("[GÜVENLİK İHLALİ] processOrderCore kilitsiz çağrıldı! İşlem iptal ediliyor.");
|
|
@@ -2137,6 +2064,22 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2137 |
logger.error(`[Sipariş] Shift+sağ tık hatası: ${e && e.message ? e.message : e}`);
|
| 2138 |
}
|
| 2139 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2140 |
// --- 3) Menüyü kapat ---
|
| 2141 |
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2142 |
// ÖNEMLİ: purpose burada "sell"e ÇEVRİLMEZ! /order akışı (Siparişler +
|
|
@@ -2194,25 +2137,54 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2194 |
}
|
| 2195 |
|
| 2196 |
logger.info(`[Sipariş] '${nick}' içeren item bulundu (idx:${targetSlotIndex}), sol tık gönderiliyor...`);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2197 |
try {
|
| 2198 |
await bot.clickWindow(targetSlotIndex, 0, 0);
|
| 2199 |
} catch (e) {
|
| 2200 |
logger.error(`[Sipariş] Slot seçim tıklaması hatası: ${e && e.message ? e.message : e}`);
|
| 2201 |
}
|
| 2202 |
-
// --- 8) +500ms sonra pencere tekrar okunur (Teslim Etme penceresi bu olmalı) ---
|
| 2203 |
-
await new Promise(r => setTimeout(r, ORDER_AFTER_SELECT_DELAY_MS));
|
| 2204 |
|
| 2205 |
-
|
| 2206 |
-
|
|
|
|
|
|
|
|
|
|
| 2207 |
ciftciWindowPurpose = "sell";
|
| 2208 |
-
return { success: false, message: "
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2209 |
}
|
| 2210 |
|
| 2211 |
-
// Teslim Etme penceresi her zaman boş açılıyor, bu yüzden dolu/boş kontrolü
|
| 2212 |
-
// yapmadan direkt envanterdeki item'ları shift+sol tık ile aktarıyoruz.
|
| 2213 |
const currentTitle = parseWindowTitleToString(bot.currentWindow.title);
|
| 2214 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2215 |
|
|
|
|
| 2216 |
let transferredCount = 0;
|
| 2217 |
let keepGoing = true;
|
| 2218 |
let safetyCounter = 0;
|
|
@@ -2221,12 +2193,17 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2221 |
|
| 2222 |
while (keepGoing && safetyCounter < 40) {
|
| 2223 |
safetyCounter++;
|
| 2224 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2225 |
|
| 2226 |
const invItem = bot.inventory.items().find(it => it && it.name === itemInternalName);
|
| 2227 |
if (!invItem) { keepGoing = false; break; }
|
| 2228 |
|
| 2229 |
-
// Aynı slot art arda takılıp kalıyorsa (item bir türlü taşınmıyorsa) döngüyü durdur.
|
| 2230 |
if (stuckSlot === invItem.slot) {
|
| 2231 |
stuckSlotRepeatCount++;
|
| 2232 |
if (stuckSlotRepeatCount >= 3) {
|
|
@@ -2243,10 +2220,9 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2243 |
await bot.clickWindow(invItem.slot, 0, 1); // mouseButton=0 (sol), mode=1 (shift)
|
| 2244 |
await new Promise(r => setTimeout(r, 250));
|
| 2245 |
|
| 2246 |
-
// Gerçekten taşınmış mı doğrula: aynı slotta hâlâ aynı item duruyor mu?
|
| 2247 |
const stillThere = bot.inventory.items().find(it => it && it.slot === invItem.slot && it.name === itemInternalName);
|
| 2248 |
if (!stillThere) {
|
| 2249 |
-
transferredCount++;
|
| 2250 |
} else {
|
| 2251 |
logger.warn(`[Sipariş] Slot ${invItem.slot} tıklandı ama item hâlâ envanterde, taşınmamış olabilir.`);
|
| 2252 |
}
|
|
@@ -2259,18 +2235,25 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2259 |
if (safetyCounter >= 40) {
|
| 2260 |
logger.warn(`[Sipariş] Güvenlik limitine (40 deneme) ulaşıldı. Teslim Etme kutusu dolu/limitli olabilir, transfer yarım kalmış olabilir.`);
|
| 2261 |
}
|
| 2262 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2263 |
|
| 2264 |
// --- 9) Pencereyi kapat ---
|
| 2265 |
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2266 |
ciftciWindowPurpose = "sell"; // akış tamamen bitti, artık normal davranışa dön
|
| 2267 |
|
| 2268 |
return {
|
| 2269 |
-
success:
|
| 2270 |
-
message: "Sipariş işlemi tamamlandı.",
|
| 2271 |
item: itemInternalName,
|
| 2272 |
nick,
|
| 2273 |
-
|
|
|
|
|
|
|
| 2274 |
};
|
| 2275 |
}
|
| 2276 |
|
|
@@ -2298,7 +2281,6 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2298 |
scanStorageInfo();
|
| 2299 |
}, STORAGE_SCAN_INTERVAL_MS);
|
| 2300 |
logger.info(`[Storage Tarama] Bağımsız döngü başlatıldı (her ${formatDurationMs(STORAGE_SCAN_INTERVAL_MS)}).`);
|
| 2301 |
-
// ilk taramayı biraz gecikmeli başlat ki spawn sonrası diğer işler önce otursun
|
| 2302 |
setSafeTimeout(() => { scanStorageInfo(); }, 30 * 1000);
|
| 2303 |
}
|
| 2304 |
|
|
@@ -2453,14 +2435,9 @@ async function processOrderCore(itemInternalName, nick) {
|
|
| 2453 |
const isCiftciWindow = !isBesleyiciWindow && !isKaziciWindow &&
|
| 2454 |
(matchesAnyName(titleRaw, TARGET_CIFTCI_NORMS) || windowMatchesLoreKeyword(window, CIFTCI_LORE_FALLBACK_KEYWORDS));
|
| 2455 |
|
| 2456 |
-
// Sipariş (/order) penceresi çiftçi/kazıcı/besleyici isimleriyle eşleşmez,
|
| 2457 |
-
// bu yüzden ayrıca ele alınır: ciftciWindowPurpose "order" ise otomatik
|
| 2458 |
-
// tıklama/kapatma yapılmaz, sadece resolver tetiklenir ve processOrderCore
|
| 2459 |
-
// kendi akışını (500ms bekleme + güncel pencere okuma) yönetir.
|
| 2460 |
if (!isBesleyiciWindow && !isKaziciWindow && !isCiftciWindow) {
|
| 2461 |
if (ciftciWindowPurpose === "order") {
|
| 2462 |
logger.info(`[${currentBotUsername}] Sipariş (/order) penceresi açıldı: ${titleRaw}`);
|
| 2463 |
-
// otomatik kapatma yapma, processOrderCore yönetecek
|
| 2464 |
} else {
|
| 2465 |
logger.info(`[${currentBotUsername}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${titleRaw}`);
|
| 2466 |
try { bot.closeWindow(window); } catch(e){}
|
|
@@ -2670,7 +2647,6 @@ function triggerSafeReconnect() {
|
|
| 2670 |
}, delay);
|
| 2671 |
}
|
| 2672 |
|
| 2673 |
-
// --- MANUEL BOT KONTROLÜ (stop/start/restart) ---
|
| 2674 |
let pendingHardRestartTimeout = null;
|
| 2675 |
|
| 2676 |
function stopBotHard(reason) {
|
|
@@ -2874,7 +2850,6 @@ app.get("/storageInfo", (req, res) => {
|
|
| 2874 |
});
|
| 2875 |
});
|
| 2876 |
|
| 2877 |
-
// --- MANUEL BOT KONTROLÜ ENDPOINT'LERİ ---
|
| 2878 |
app.get("/bot/stop", (req, res) => {
|
| 2879 |
stopBotHard("Web paneli üzerinden /bot/stop isteği");
|
| 2880 |
res.send({ success: true, message: "Bot durduruldu. Tekrar başlatmak için /bot/start kullan." });
|
|
@@ -3254,4 +3229,4 @@ process.stderr.write = function (chunk, encoding, callback) {
|
|
| 3254 |
return true;
|
| 3255 |
}
|
| 3256 |
return originalStderrWrite.apply(process.stderr, arguments);
|
| 3257 |
-
};
|
|
|
|
| 44 |
const CIFTCI_COMMAND = "/çiftçi menü";
|
| 45 |
const CIFTCI_WINDOW_TIMEOUT_MS = 6000;
|
| 46 |
const CIFTCI_LORE_FALLBACK_KEYWORDS = ["hepsini sat"];
|
|
|
|
|
|
|
| 47 |
const CIFTCI_CLICK_DELAY_AFTER_OPEN_MS = 1000;
|
| 48 |
const CIFTCI_CLICK_REPEAT_COUNT = 3;
|
| 49 |
const CIFTCI_CLICK_REPEAT_GAP_MS = 350;
|
| 50 |
|
| 51 |
+
const KAZICI_CYCLE_INTERVAL_MS = 5 * 60 * 1000;
|
| 52 |
+
const CIFTCI_CYCLE_INTERVAL_MS = 60 * 1000;
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
const CIFTCI_FILTER_MODES = [
|
| 55 |
"Standart",
|
| 56 |
"Favoriler",
|
|
|
|
| 59 |
"Satışı açık olanlar",
|
| 60 |
"Toplaması açık olanlar"
|
| 61 |
];
|
| 62 |
+
const CIFTCI_TARGET_FILTER_INDEX = 3;
|
| 63 |
const CIFTCI_ACTIVE_FILTER_COLOR = "#FCF988";
|
| 64 |
const CIFTCI_FILTER_ITEM_NAME_KEYWORD = "Filtre";
|
| 65 |
+
const CIFTCI_FILTER_STEP_WAIT_MS = 1000;
|
| 66 |
+
const CIFTCI_FILTER_RETRY_WAIT_MS = 1000;
|
| 67 |
+
const CIFTCI_FILTER_MAX_RETRIES = 10;
|
| 68 |
+
const STORAGE_SCAN_INTERVAL_MS = 15 * 60 * 1000;
|
| 69 |
+
const STORAGE_TRACKED_ITEMS = ["diamond", "emerald", "iron_block"];
|
| 70 |
|
| 71 |
// --- SİPARİŞ (ORDER) SİSTEMİ AYARLARI ---
|
| 72 |
const ORDER_COMMAND_PREFIX = "/order";
|
|
|
|
| 75 |
const ORDER_AFTER_SELECT_DELAY_MS = 500;
|
| 76 |
const ORDER_IS_GO_SECOND_DELAY_MS = 5000;
|
| 77 |
const ORDER_ALLOWED_ITEMS = ["diamond", "emerald"];
|
| 78 |
+
const ORDER_LIST_TITLE_KEYWORD = "ѕiᴘᴀʀişʟᴇʀ";
|
| 79 |
+
const ORDER_DELIVERY_TITLE_KEYWORD = "ᴛᴇѕʟiᴍ ᴇᴛᴍᴇ";
|
| 80 |
+
// Nick seçildikten sonra Teslim Etme penceresinin gerçekten açılmasını beklemek için
|
| 81 |
+
// kullanılan zaman aşımı (sabit sleep yerine).
|
| 82 |
+
const ORDER_DELIVERY_WINDOW_WAIT_MS = 8000;
|
| 83 |
|
| 84 |
let storageInfoCache = {
|
| 85 |
diamond: null,
|
|
|
|
| 89 |
};
|
| 90 |
let storageScanIntervalHandle = null;
|
| 91 |
|
|
|
|
|
|
|
| 92 |
let ciftciWindowPurpose = "sell";
|
| 93 |
|
| 94 |
+
const STALL_CHECK_INTERVAL_MS = 15 * 1000;
|
| 95 |
+
const STALL_TIMEOUT_MS = 60 * 1000;
|
| 96 |
+
const FAILOVER_HOME_ARRIVAL_DELAY_MS = 4000;
|
|
|
|
| 97 |
const FAILOVER_LOGIN_DELAY_MS = 2500;
|
| 98 |
const FAILOVER_SKYBLOCK_DELAY_MS = 7500;
|
| 99 |
const FAILOVER_ISGO_DELAY_MS = 12500;
|
| 100 |
+
const FAILOVER_RECHECK_INTERVAL_MS = 20 * 1000;
|
| 101 |
+
const FAILOVER_MAX_WAIT_MS = 60 * 60 * 1000;
|
| 102 |
+
const FAILOVER_SPAWN_TIMEOUT_MS = 30 * 1000;
|
| 103 |
|
|
|
|
|
|
|
| 104 |
const WATCHED_KAZICI_SKIN_HASHES = new Set([
|
| 105 |
"eyJ0ZXh0dXJlcyI6eyJTS0lOIjp7InVybCI6Imh0dHA6Ly90ZXh0dXJlcy5taW5lY3JhZnQubmV0L3RleHR1cmUvNDQ4ODcwY2E3N2FhNjk5ZDAxNzA5M2I4Mjc3OWQwYTU5OGRjNGYzZjQ5ZDM1MTUzMmFlNGQ5NjMzZGNjMmE1YSJ9fX0=",
|
| 106 |
]);
|
|
|
|
| 115 |
let isListeningChat = false;
|
| 116 |
const ansiToHtmlConvert = new (require('ansi-to-html'))({ newline: true });
|
| 117 |
|
|
|
|
| 118 |
let isConnecting = false;
|
| 119 |
let isDestroying = false;
|
| 120 |
let reconnectTimeout = null;
|
|
|
|
| 123 |
let currentSocket = null;
|
| 124 |
let windowOpenResolvers = [];
|
| 125 |
|
|
|
|
| 126 |
let botUptimeStart = null;
|
| 127 |
let lastFullFeedTimeStr = "Henüz besleme yapılmadı";
|
| 128 |
let lastCheckTimeStr = "Henüz kontrol yapılmadı";
|
| 129 |
let nextScheduledCheckTimeStr = "Botun spawn olması bekleniyor...";
|
| 130 |
|
|
|
|
| 131 |
let lastKaziciCheckTimeStr = "Henüz kazıcı kontrolü yapılmadı";
|
| 132 |
let nextKaziciTimeStr = "Botun spawn olması bekleniyor...";
|
| 133 |
let nextKaziciAtMs = null;
|
| 134 |
|
|
|
|
| 135 |
let lastCiftciSellTimeStr = "Henüz çiftçi satışı yapılmadı";
|
| 136 |
let nextCiftciTimeStr = "Botun spawn olması bekleniyor...";
|
| 137 |
let nextCiftciAtMs = null;
|
| 138 |
|
|
|
|
| 139 |
let lastOrderTimeStr = "Henüz sipariş işlemi yapılmadı";
|
| 140 |
|
| 141 |
+
let lastCheckAtMs = null;
|
| 142 |
+
let nextScheduledCheckAtMs = null;
|
| 143 |
+
let kaziciIntervalHandle = null;
|
| 144 |
+
let ciftciIntervalHandle = null;
|
| 145 |
+
let isMainCycleRunning = false;
|
|
|
|
| 146 |
|
| 147 |
+
let poseTracker = new Map();
|
|
|
|
| 148 |
let stallCheckIntervalHandle = null;
|
| 149 |
+
let failoverModeActive = false;
|
| 150 |
+
let failoverBot = null;
|
| 151 |
+
let failoverInProgress = false;
|
| 152 |
|
|
|
|
| 153 |
let activeConnectionIp = "Bilinmiyor";
|
| 154 |
let activeConnectionLocation = "Bilinmiyor";
|
| 155 |
let localExternalIp = "Bilinmiyor";
|
| 156 |
|
|
|
|
| 157 |
let periodicTimeoutHandle = null;
|
| 158 |
let activeTimeouts = [];
|
| 159 |
|
|
|
|
| 163 |
return t;
|
| 164 |
}
|
| 165 |
|
|
|
|
| 166 |
class PriorityGuiMutex {
|
| 167 |
constructor() {
|
| 168 |
this._locked = false;
|
|
|
|
| 257 |
nextCiftciTimeStr = "Zamanlama durduruldu.";
|
| 258 |
}
|
| 259 |
|
|
|
|
| 260 |
let manualStopRequested = false;
|
| 261 |
|
| 262 |
async function getIpLocation(ip) {
|
|
|
|
| 305 |
});
|
| 306 |
}).on('error', () => {});
|
| 307 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 308 |
function getEntitySkinHash(entity) {
|
| 309 |
try {
|
| 310 |
const equipment = entity.equipment || [];
|
|
|
|
| 324 |
return null;
|
| 325 |
}
|
| 326 |
|
|
|
|
| 327 |
function hasIronPickaxeEquipped(entity) {
|
| 328 |
try {
|
| 329 |
const equipment = entity.equipment || [];
|
|
|
|
| 334 |
}
|
| 335 |
}
|
| 336 |
|
|
|
|
| 337 |
function isWatchedKaziciEntity(entity) {
|
| 338 |
if (!entity || entity.name !== "armor_stand") return false;
|
| 339 |
const skinHash = getEntitySkinHash(entity);
|
|
|
|
| 341 |
return hasIronPickaxeEquipped(entity);
|
| 342 |
}
|
| 343 |
|
|
|
|
| 344 |
function getPoseKey(entity) {
|
| 345 |
try {
|
| 346 |
const md = entity.metadata || [];
|
|
|
|
| 359 |
}
|
| 360 |
}
|
| 361 |
|
|
|
|
|
|
|
| 362 |
function trackKaziciPoseIfWatched(entity) {
|
| 363 |
if (!entity) return;
|
| 364 |
if (!isWatchedKaziciEntity(entity)) return;
|
|
|
|
| 376 |
prev.poseKey = poseKey;
|
| 377 |
prev.lastChangeAt = Date.now();
|
| 378 |
}
|
|
|
|
| 379 |
}
|
| 380 |
|
|
|
|
| 381 |
function pruneStaleTrackedEntities() {
|
| 382 |
if (!bot || !bot.entities) return;
|
| 383 |
for (const id of poseTracker.keys()) {
|
|
|
|
| 418 |
poseTracker.clear();
|
| 419 |
}
|
| 420 |
|
|
|
|
|
|
|
|
|
|
| 421 |
async function triggerFailoverSequence() {
|
| 422 |
if (failoverInProgress) return;
|
| 423 |
failoverInProgress = true;
|
|
|
|
| 428 |
|
| 429 |
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.`);
|
| 430 |
|
| 431 |
+
manualStopRequested = true;
|
| 432 |
stopPeriodicHomeChecks();
|
| 433 |
safeDestroyAllConnections();
|
| 434 |
|
|
|
|
| 447 |
failoverInProgress = false;
|
| 448 |
}
|
| 449 |
|
|
|
|
|
|
|
|
|
|
| 450 |
function runBackupAccountAndWaitForRecovery(backupUsername) {
|
| 451 |
return new Promise((resolve) => {
|
| 452 |
const backupPoseTracker = new Map();
|
|
|
|
| 509 |
logger.info(`[Failover - Yedek Hesap] ${GO_ISLAND_COMMAND} gönderildi, izlenen minyonların tekrar hareket etmesi bekleniyor...`);
|
| 510 |
}, FAILOVER_ISGO_DELAY_MS);
|
| 511 |
|
|
|
|
| 512 |
setTimeout(() => {
|
| 513 |
recheckHandle = setInterval(() => {
|
| 514 |
try {
|
|
|
|
| 525 |
|
| 526 |
if (!prev) {
|
| 527 |
backupPoseTracker.set(e.id, { poseKey, lastChangeAt: Date.now() });
|
| 528 |
+
allRecovered = false;
|
| 529 |
continue;
|
| 530 |
}
|
| 531 |
|
|
|
|
| 533 |
prev.poseKey = poseKey;
|
| 534 |
prev.lastChangeAt = Date.now();
|
| 535 |
} else if (Date.now() - prev.lastChangeAt < STALL_TIMEOUT_MS) {
|
| 536 |
+
// ok
|
| 537 |
} else {
|
| 538 |
allRecovered = false;
|
| 539 |
}
|
|
|
|
| 564 |
}
|
| 565 |
});
|
| 566 |
|
|
|
|
| 567 |
safetyTimeoutHandle = setTimeout(() => {
|
| 568 |
logger.warn(`[Failover - Yedek Hesap] Azami bekleme süresi (${formatDurationMs(FAILOVER_MAX_WAIT_MS)}) doldu, ana hesaba geri dönülüyor.`);
|
| 569 |
finish();
|
|
|
|
| 925 |
} catch (e) { return undefined; }
|
| 926 |
};
|
| 927 |
|
| 928 |
+
function getComponentData(slot, type) {
|
| 929 |
+
try {
|
| 930 |
+
if (!slot || !Array.isArray(slot.components)) return undefined;
|
| 931 |
+
const comp = slot.components.find(c => c && c.type === type);
|
| 932 |
+
return comp ? comp.data : undefined;
|
| 933 |
+
} catch (e) { return undefined; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 934 |
}
|
|
|
|
|
|
|
| 935 |
|
| 936 |
+
function nbtUnwrap(node) {
|
| 937 |
+
if (node && typeof node === "object" && "type" in node && "value" in node) {
|
| 938 |
+
return node.value;
|
| 939 |
+
}
|
| 940 |
+
return node;
|
| 941 |
+
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 942 |
|
| 943 |
+
function flattenTextComponent(node) {
|
| 944 |
+
if (node == null) return "";
|
| 945 |
+
if (typeof node === "string") return node;
|
| 946 |
+
if (Array.isArray(node)) return node.map(flattenTextComponent).join("");
|
| 947 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 948 |
if (typeof node === "object") {
|
| 949 |
if ("type" in node && "value" in node) {
|
| 950 |
const t = node.type, v = node.value;
|
| 951 |
+
if (t === "string") return typeof v === "string" ? v : "";
|
| 952 |
+
if (t === "list" || t === "compound") return flattenTextComponent(v);
|
| 953 |
+
return "";
|
| 954 |
}
|
| 955 |
+
let out = "";
|
| 956 |
+
if ("text" in node) out += flattenTextComponent(node.text);
|
| 957 |
+
if ("extra" in node) out += flattenTextComponent(node.extra);
|
| 958 |
+
return out;
|
| 959 |
+
}
|
| 960 |
+
return "";
|
| 961 |
+
};
|
| 962 |
+
|
| 963 |
+
function parseComponentLoreLine(lineNode) {
|
| 964 |
+
let text = "";
|
| 965 |
+
let color = null;
|
| 966 |
+
|
| 967 |
+
function walk(node) {
|
| 968 |
+
if (node == null) return;
|
| 969 |
+
if (typeof node === "string") { text += node; return; }
|
| 970 |
+
if (Array.isArray(node)) { node.forEach(walk); return; }
|
| 971 |
+
if (typeof node === "object") {
|
| 972 |
+
if ("type" in node && "value" in node) {
|
| 973 |
+
const t = node.type, v = node.value;
|
| 974 |
+
if (t === "string") { text += (typeof v === "string" ? v : ""); return; }
|
| 975 |
+
if (t === "list" || t === "compound") { walk(v); return; }
|
| 976 |
+
return;
|
| 977 |
+
}
|
| 978 |
+
if ("color" in node) {
|
| 979 |
+
const colVal = nbtUnwrap(node.color);
|
| 980 |
+
if (color == null && typeof colVal === "string") color = colVal;
|
| 981 |
+
}
|
| 982 |
+
if ("text" in node) walk(node.text);
|
| 983 |
+
if ("extra" in node) walk(node.extra);
|
| 984 |
}
|
|
|
|
|
|
|
| 985 |
}
|
|
|
|
| 986 |
|
| 987 |
+
walk(lineNode);
|
| 988 |
+
return { text: text.trim(), color };
|
| 989 |
+
};
|
| 990 |
|
| 991 |
function deepSearchForString(root, targetVariantsList) {
|
| 992 |
const results = [];
|
|
|
|
| 1060 |
const texts = [];
|
| 1061 |
try {
|
| 1062 |
if (!slot) return texts;
|
| 1063 |
+
|
|
|
|
| 1064 |
const customNameData = getComponentData(slot, "custom_name");
|
| 1065 |
if (customNameData !== undefined) {
|
| 1066 |
const nameTxt = flattenTextComponent(customNameData);
|
|
|
|
| 1074 |
}
|
| 1075 |
}
|
| 1076 |
if (texts.length > 0) return texts;
|
| 1077 |
+
|
|
|
|
| 1078 |
function extractPlain(raw) {
|
| 1079 |
if (!raw || typeof raw !== "string") return null;
|
| 1080 |
try {
|
|
|
|
| 1089 |
} catch (e) {}
|
| 1090 |
return raw;
|
| 1091 |
}
|
| 1092 |
+
|
| 1093 |
if (slot.nbt) {
|
| 1094 |
const name = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
|
| 1095 |
const plainName = extractPlain(name);
|
| 1096 |
if (plainName) texts.push(plainName);
|
| 1097 |
+
|
| 1098 |
const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
|
| 1099 |
if (Array.isArray(lore)) {
|
| 1100 |
for (const line of lore) {
|
|
|
|
| 1103 |
}
|
| 1104 |
}
|
| 1105 |
}
|
| 1106 |
+
|
| 1107 |
if (texts.length === 0) {
|
| 1108 |
texts.push(util.inspect(slot, { depth: null }));
|
| 1109 |
}
|
|
|
|
| 1146 |
}
|
| 1147 |
}
|
| 1148 |
|
|
|
|
| 1149 |
const MONEY_BALANCE_REGEX = /bakiyen:\s*([\d.,]+)\s*TL/i;
|
| 1150 |
const MONEY_RESPONSE_TIMEOUT_MS = 8000;
|
| 1151 |
|
| 1152 |
function parseBalanceToAdjustedAmount(rawBalanceStr) {
|
|
|
|
| 1153 |
const noCommas = rawBalanceStr.replace(/,/g, "");
|
| 1154 |
const beforeDot = noCommas.split(".")[0];
|
| 1155 |
const intValue = parseInt(beforeDot, 10);
|
|
|
|
| 1231 |
if (!bot || !botIsReady) return;
|
| 1232 |
try {
|
| 1233 |
const moves = ['forward', 'left', 'right', 'jump'];
|
| 1234 |
+
|
| 1235 |
+
const moveCount = Math.floor(Math.random() * 4) + 2;
|
| 1236 |
+
|
| 1237 |
for (let i = 0; i < moveCount; i++) {
|
| 1238 |
const move = moves[Math.floor(Math.random() * moves.length)];
|
| 1239 |
const duration = 150 + Math.floor(Math.random() * 500);
|
| 1240 |
+
|
| 1241 |
bot.setControlState(move, true);
|
| 1242 |
await new Promise(r => setTimeout(r, duration));
|
| 1243 |
bot.setControlState(move, false);
|
| 1244 |
+
|
| 1245 |
await new Promise(r => setTimeout(r, 100 + Math.random() * 300));
|
| 1246 |
+
|
| 1247 |
}
|
| 1248 |
+
|
|
|
|
| 1249 |
await bot.look(
|
| 1250 |
bot.entity.yaw + ((Math.random() - 0.5) * 1.5),
|
| 1251 |
bot.entity.pitch + ((Math.random() - 0.5) * 0.3),
|
|
|
|
| 1701 |
}
|
| 1702 |
}
|
| 1703 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1704 |
function stripColorAndGetLoreLines(window) {
|
| 1705 |
if (!window || !Array.isArray(window.slots)) return null;
|
| 1706 |
for (const slot of window.slots) {
|
| 1707 |
if (!slot) continue;
|
| 1708 |
+
|
| 1709 |
let nameTxt = "";
|
| 1710 |
+
|
|
|
|
| 1711 |
const customNameData = getComponentData(slot, "custom_name");
|
| 1712 |
if (customNameData !== undefined) {
|
| 1713 |
nameTxt = flattenTextComponent(customNameData);
|
| 1714 |
}
|
| 1715 |
+
|
|
|
|
| 1716 |
if (!nameTxt && slot.nbt) {
|
| 1717 |
const nameRaw = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
|
| 1718 |
try {
|
|
|
|
| 1721 |
else if (maybe && maybe.text) nameTxt = maybe.text;
|
| 1722 |
} catch (e) { nameTxt = nameRaw || ""; }
|
| 1723 |
}
|
| 1724 |
+
|
| 1725 |
if (nameTxt.includes(CIFTCI_FILTER_ITEM_NAME_KEYWORD)) {
|
| 1726 |
return { slot, index: window.slots.indexOf(slot) };
|
| 1727 |
}
|
|
|
|
| 1731 |
|
| 1732 |
function getFilterItemLoreEntries(filterSlot) {
|
| 1733 |
const entries = [];
|
| 1734 |
+
|
|
|
|
| 1735 |
const loreData = getComponentData(filterSlot, "lore");
|
| 1736 |
if (Array.isArray(loreData)) {
|
| 1737 |
for (const line of loreData) {
|
|
|
|
| 1739 |
}
|
| 1740 |
if (entries.length > 0) return entries;
|
| 1741 |
}
|
| 1742 |
+
|
|
|
|
| 1743 |
try {
|
| 1744 |
const lore = safeGet(filterSlot.nbt, ["value", "display", "value", "Lore", "value"]);
|
| 1745 |
if (!Array.isArray(lore)) return entries;
|
|
|
|
| 1775 |
);
|
| 1776 |
if (match) return i;
|
| 1777 |
}
|
|
|
|
| 1778 |
const colorMatch = loreEntries.find(e => e.color === CIFTCI_ACTIVE_FILTER_COLOR);
|
| 1779 |
if (colorMatch) {
|
| 1780 |
for (let i = 0; i < CIFTCI_FILTER_MODES.length; i++) {
|
|
|
|
| 1785 |
}
|
| 1786 |
|
| 1787 |
async function waitForFilterItem(maxRetries) {
|
|
|
|
| 1788 |
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
| 1789 |
await new Promise(r => setTimeout(r, attempt === 0 ? CIFTCI_FILTER_STEP_WAIT_MS : CIFTCI_FILTER_RETRY_WAIT_MS));
|
| 1790 |
if (!bot || !bot.currentWindow) return null;
|
|
|
|
| 1856 |
}
|
| 1857 |
|
| 1858 |
const total = CIFTCI_FILTER_MODES.length;
|
| 1859 |
+
const forwardDist = (CIFTCI_TARGET_FILTER_INDEX - currentIndex + total) % total;
|
| 1860 |
+
const backwardDist = (currentIndex - CIFTCI_TARGET_FILTER_INDEX + total) % total;
|
| 1861 |
|
| 1862 |
const useLeftClick = forwardDist <= backwardDist;
|
| 1863 |
+
const mouseButton = useLeftClick ? 0 : 1;
|
| 1864 |
|
| 1865 |
logger.info(`[Çiftçi Filtre] Mevcut: "${CIFTCI_FILTER_MODES[currentIndex]}" -> Hedef: "${CIFTCI_FILTER_MODES[CIFTCI_TARGET_FILTER_INDEX]}". ${useLeftClick ? "Sol tık (aşağı)" : "Sağ tık (yukarı)"} kullanılacak.`);
|
| 1866 |
|
|
|
|
| 1870 |
logger.error(`[Çiftçi Filtre] Tıklama hatası: ${e && e.message ? e.message : e}`);
|
| 1871 |
return false;
|
| 1872 |
}
|
|
|
|
|
|
|
| 1873 |
}
|
| 1874 |
|
| 1875 |
logger.warn("[Çiftçi Filtre] Azami deneme sayısına ulaşıldı, Jeneratör materyallerine geçilemedi.");
|
|
|
|
| 1970 |
|
| 1971 |
// =====================================================================
|
| 1972 |
// SİPARİŞ (ORDER) SİSTEMİ
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1973 |
// =====================================================================
|
| 1974 |
|
| 1975 |
async function waitForNextWindowOpen(timeoutMs) {
|
|
|
|
| 2002 |
return -1;
|
| 2003 |
}
|
| 2004 |
|
| 2005 |
+
async function processOrderCore(itemInternalName, nick) {
|
| 2006 |
if (!bot || !botIsReady) return { success: false, message: "Bot hazır değil." };
|
| 2007 |
if (!guiMutex.isLocked()) {
|
| 2008 |
logger.error("[GÜVENLİK İHLALİ] processOrderCore kilitsiz çağrıldı! İşlem iptal ediliyor.");
|
|
|
|
| 2064 |
logger.error(`[Sipariş] Shift+sağ tık hatası: ${e && e.message ? e.message : e}`);
|
| 2065 |
}
|
| 2066 |
|
| 2067 |
+
// --- YENİ: Çiftçiden gerçekten item alınmış mı doğrula ---
|
| 2068 |
+
// clickWindow hata fırlatmasa bile sunucu isteği görmezden gelmiş olabilir.
|
| 2069 |
+
// Envanterde ilgili item yoksa devam etmenin anlamı yok (Teslim Etme'ye zaten
|
| 2070 |
+
// aktarılacak bir şey olmaz), bu yüzden burada erkenden kontrol edip
|
| 2071 |
+
// anlamlı bir hata dönüyoruz.
|
| 2072 |
+
const itemsAfterWithdraw = bot.inventory.items().filter(it => it && it.name === itemInternalName);
|
| 2073 |
+
const withdrawnCount = itemsAfterWithdraw.reduce((sum, it) => sum + (it.count || 0), 0);
|
| 2074 |
+
logger.info(`[Sipariş] Çiftçiden çekildikten sonra envanterde '${itemInternalName}': ${withdrawnCount} adet.`);
|
| 2075 |
+
|
| 2076 |
+
if (withdrawnCount === 0) {
|
| 2077 |
+
logger.warn(`[Sipariş] Çiftçi menüsünden '${itemInternalName}' envantere aktarılamadı (0 adet). İşlem iptal ediliyor.`);
|
| 2078 |
+
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2079 |
+
ciftciWindowPurpose = "sell";
|
| 2080 |
+
return { success: false, message: `Çiftçiden '${itemInternalName}' alınamadı (envanterde 0 adet). Depoda yeterli stok olmayabilir ya da tıklama sunucu tarafından işlenmedi.` };
|
| 2081 |
+
}
|
| 2082 |
+
|
| 2083 |
// --- 3) Menüyü kapat ---
|
| 2084 |
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2085 |
// ÖNEMLİ: purpose burada "sell"e ÇEVRİLMEZ! /order akışı (Siparişler +
|
|
|
|
| 2137 |
}
|
| 2138 |
|
| 2139 |
logger.info(`[Sipariş] '${nick}' içeren item bulundu (idx:${targetSlotIndex}), sol tık gönderiliyor...`);
|
| 2140 |
+
|
| 2141 |
+
// --- YENİ: nick'e tıkladıktan sonra sabit 500ms yerine GERÇEK yeni
|
| 2142 |
+
// pencere açılışını (Teslim Etme) bekliyoruz. Bu, mevcut buğun ana
|
| 2143 |
+
// sebebiydi: sunucu 500ms'den geç yanıt verirse eski (Siparişler)
|
| 2144 |
+
// penceresine göre hesaplanmış slotlara tıklanıyor ve hiçbir şey
|
| 2145 |
+
// taşınmıyordu (sunucu paketi reddetmediği için hata da görünmüyordu).
|
| 2146 |
+
const windowBeforeSelect = bot.currentWindow;
|
| 2147 |
try {
|
| 2148 |
await bot.clickWindow(targetSlotIndex, 0, 0);
|
| 2149 |
} catch (e) {
|
| 2150 |
logger.error(`[Sipariş] Slot seçim tıklaması hatası: ${e && e.message ? e.message : e}`);
|
| 2151 |
}
|
|
|
|
|
|
|
| 2152 |
|
| 2153 |
+
// --- 8) Teslim Etme penceresinin gerçekten açılmasını bekle ---
|
| 2154 |
+
const deliveryOpened = await waitForNextWindowOpen(ORDER_DELIVERY_WINDOW_WAIT_MS);
|
| 2155 |
+
|
| 2156 |
+
if (!deliveryOpened || !bot.currentWindow) {
|
| 2157 |
+
logger.warn("[Sipariş] Teslim Etme penceresi zaman aşımına uğradı ya da açılmadı, işlem yarım kalmış olabilir.");
|
| 2158 |
ciftciWindowPurpose = "sell";
|
| 2159 |
+
return { success: false, message: "Teslim Etme penceresi açılmadı (zaman aşımı)." };
|
| 2160 |
+
}
|
| 2161 |
+
|
| 2162 |
+
// Pencere objesinin gerçekten DEĞİŞTİĞİNİ doğrula (bazı sunucular aynı id'yi
|
| 2163 |
+
// update edip windowOpen yerine sadece slot update gönderebilir; bu durumda
|
| 2164 |
+
// en azından title kontrolüyle devam ediyoruz).
|
| 2165 |
+
if (bot.currentWindow === windowBeforeSelect) {
|
| 2166 |
+
logger.warn("[Sipariş] windowOpen tetiklendi ama pencere referansı değişmedi, dikkatli devam ediliyor.");
|
| 2167 |
}
|
| 2168 |
|
|
|
|
|
|
|
| 2169 |
const currentTitle = parseWindowTitleToString(bot.currentWindow.title);
|
| 2170 |
+
const looksLikeDelivery = matchesAnyName(currentTitle, normalizeVariants(ORDER_DELIVERY_TITLE_KEYWORD));
|
| 2171 |
+
logger.info(`[Sipariş] Yeni pencere açıldı: "${currentTitle}" (Teslim Etme eşleşmesi: ${looksLikeDelivery}). Envanterdeki '${itemInternalName}' item'ları aktarılıyor...`);
|
| 2172 |
+
|
| 2173 |
+
if (!looksLikeDelivery) {
|
| 2174 |
+
logger.warn(`[Sipariş] Açılan pencere Teslim Etme'ye benzemiyor, yine de mevcut pencereye aktarım denenecek: "${currentTitle}"`);
|
| 2175 |
+
}
|
| 2176 |
+
|
| 2177 |
+
// Ek güvenlik: envanterde gerçekten aktarılacak item var mı, tekrar kontrol et
|
| 2178 |
+
// (nick seçme / /is go arasında item'lar herhangi bir sebeple kaybolmuş olabilir).
|
| 2179 |
+
const invCheckBeforeTransfer = bot.inventory.items().filter(it => it && it.name === itemInternalName);
|
| 2180 |
+
if (invCheckBeforeTransfer.length === 0) {
|
| 2181 |
+
logger.warn(`[Sipariş] Aktarım öncesi envanterde '${itemInternalName}' bulunamadı, aktarım atlanıyor.`);
|
| 2182 |
+
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2183 |
+
ciftciWindowPurpose = "sell";
|
| 2184 |
+
return { success: false, message: `Envanterde '${itemInternalName}' kalmamış, Teslim Etme'ye aktarılacak item yok.` };
|
| 2185 |
+
}
|
| 2186 |
|
| 2187 |
+
const windowAtTransferStart = bot.currentWindow;
|
| 2188 |
let transferredCount = 0;
|
| 2189 |
let keepGoing = true;
|
| 2190 |
let safetyCounter = 0;
|
|
|
|
| 2193 |
|
| 2194 |
while (keepGoing && safetyCounter < 40) {
|
| 2195 |
safetyCounter++;
|
| 2196 |
+
|
| 2197 |
+
// Pencere döngü sırasında değişti/kapandıysa (ör. sunucu Teslim Etme'yi
|
| 2198 |
+
// kapattıysa) devam etmenin bir anlamı yok, güvenle çık.
|
| 2199 |
+
if (!bot.currentWindow || bot.currentWindow !== windowAtTransferStart) {
|
| 2200 |
+
logger.warn("[Sipariş] Aktarım sırasında pencere değişti/kapandı, döngü durduruluyor.");
|
| 2201 |
+
break;
|
| 2202 |
+
}
|
| 2203 |
|
| 2204 |
const invItem = bot.inventory.items().find(it => it && it.name === itemInternalName);
|
| 2205 |
if (!invItem) { keepGoing = false; break; }
|
| 2206 |
|
|
|
|
| 2207 |
if (stuckSlot === invItem.slot) {
|
| 2208 |
stuckSlotRepeatCount++;
|
| 2209 |
if (stuckSlotRepeatCount >= 3) {
|
|
|
|
| 2220 |
await bot.clickWindow(invItem.slot, 0, 1); // mouseButton=0 (sol), mode=1 (shift)
|
| 2221 |
await new Promise(r => setTimeout(r, 250));
|
| 2222 |
|
|
|
|
| 2223 |
const stillThere = bot.inventory.items().find(it => it && it.slot === invItem.slot && it.name === itemInternalName);
|
| 2224 |
if (!stillThere) {
|
| 2225 |
+
transferredCount++;
|
| 2226 |
} else {
|
| 2227 |
logger.warn(`[Sipariş] Slot ${invItem.slot} tıklandı ama item hâlâ envanterde, taşınmamış olabilir.`);
|
| 2228 |
}
|
|
|
|
| 2235 |
if (safetyCounter >= 40) {
|
| 2236 |
logger.warn(`[Sipariş] Güvenlik limitine (40 deneme) ulaşıldı. Teslim Etme kutusu dolu/limitli olabilir, transfer yarım kalmış olabilir.`);
|
| 2237 |
}
|
| 2238 |
+
|
| 2239 |
+
const remainingAfterTransfer = bot.inventory.items()
|
| 2240 |
+
.filter(it => it && it.name === itemInternalName)
|
| 2241 |
+
.reduce((sum, it) => sum + (it.count || 0), 0);
|
| 2242 |
+
|
| 2243 |
+
logger.info(`[Sipariş] Envanterden Teslim Etme'ye aktarım turu tamamlandı (${transferredCount} yığın gönderildi, envanterde kalan: ${remainingAfterTransfer}).`);
|
| 2244 |
|
| 2245 |
// --- 9) Pencereyi kapat ---
|
| 2246 |
try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
|
| 2247 |
ciftciWindowPurpose = "sell"; // akış tamamen bitti, artık normal davranışa dön
|
| 2248 |
|
| 2249 |
return {
|
| 2250 |
+
success: transferredCount > 0,
|
| 2251 |
+
message: transferredCount > 0 ? "Sipariş işlemi tamamlandı." : "Hiçbir yığın Teslim Etme'ye aktarılamadı.",
|
| 2252 |
item: itemInternalName,
|
| 2253 |
nick,
|
| 2254 |
+
withdrawn_from_ciftci: withdrawnCount,
|
| 2255 |
+
inventory_transferred_batches: transferredCount,
|
| 2256 |
+
remaining_in_inventory: remainingAfterTransfer
|
| 2257 |
};
|
| 2258 |
}
|
| 2259 |
|
|
|
|
| 2281 |
scanStorageInfo();
|
| 2282 |
}, STORAGE_SCAN_INTERVAL_MS);
|
| 2283 |
logger.info(`[Storage Tarama] Bağımsız döngü başlatıldı (her ${formatDurationMs(STORAGE_SCAN_INTERVAL_MS)}).`);
|
|
|
|
| 2284 |
setSafeTimeout(() => { scanStorageInfo(); }, 30 * 1000);
|
| 2285 |
}
|
| 2286 |
|
|
|
|
| 2435 |
const isCiftciWindow = !isBesleyiciWindow && !isKaziciWindow &&
|
| 2436 |
(matchesAnyName(titleRaw, TARGET_CIFTCI_NORMS) || windowMatchesLoreKeyword(window, CIFTCI_LORE_FALLBACK_KEYWORDS));
|
| 2437 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2438 |
if (!isBesleyiciWindow && !isKaziciWindow && !isCiftciWindow) {
|
| 2439 |
if (ciftciWindowPurpose === "order") {
|
| 2440 |
logger.info(`[${currentBotUsername}] Sipariş (/order) penceresi açıldı: ${titleRaw}`);
|
|
|
|
| 2441 |
} else {
|
| 2442 |
logger.info(`[${currentBotUsername}] Bi chest açıldı ama window title ı uyuşmadığı için kapatıldı. ${titleRaw}`);
|
| 2443 |
try { bot.closeWindow(window); } catch(e){}
|
|
|
|
| 2647 |
}, delay);
|
| 2648 |
}
|
| 2649 |
|
|
|
|
| 2650 |
let pendingHardRestartTimeout = null;
|
| 2651 |
|
| 2652 |
function stopBotHard(reason) {
|
|
|
|
| 2850 |
});
|
| 2851 |
});
|
| 2852 |
|
|
|
|
| 2853 |
app.get("/bot/stop", (req, res) => {
|
| 2854 |
stopBotHard("Web paneli üzerinden /bot/stop isteği");
|
| 2855 |
res.send({ success: true, message: "Bot durduruldu. Tekrar başlatmak için /bot/start kullan." });
|
|
|
|
| 3229 |
return true;
|
| 3230 |
}
|
| 3231 |
return originalStderrWrite.apply(process.stderr, arguments);
|
| 3232 |
+
};
|