Suvarii commited on
Commit
db237fd
·
verified ·
1 Parent(s): 7d3e319

Update bot.js

Browse files
Files changed (1) hide show
  1. bot.js +453 -25
bot.js CHANGED
@@ -56,6 +56,36 @@ 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
  // --- 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
@@ -176,7 +206,8 @@ let botActions = {
176
  goToIslandManual: null,
177
  sendSkyblockManual: null,
178
  antiBotMove: null,
179
- sendMoneyToNick: null
 
180
  };
181
 
182
  function formatDurationMs(ms) {
@@ -217,6 +248,11 @@ function stopPeriodicHomeChecks() {
217
  ciftciIntervalHandle = null;
218
  logger.info("[Çiftçi Periyodik] Döngü zamanlayıcısı durduruldu.");
219
  }
 
 
 
 
 
220
 
221
  nextScheduledCheckAtMs = null;
222
  nextKaziciAtMs = null;
@@ -915,8 +951,75 @@ async function createBot() {
915
  }
916
  return cur;
917
  } catch (e) { return undefined; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
918
  }
919
 
 
 
 
 
920
  function deepSearchForString(root, targetVariantsList) {
921
  const results = [];
922
  const visited = new WeakSet();
@@ -989,7 +1092,23 @@ async function createBot() {
989
  const texts = [];
990
  try {
991
  if (!slot) return texts;
992
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
993
  function extractPlain(raw) {
994
  if (!raw || typeof raw !== "string") return null;
995
  try {
@@ -1004,12 +1123,12 @@ async function createBot() {
1004
  } catch (e) {}
1005
  return raw;
1006
  }
1007
-
1008
  if (slot.nbt) {
1009
  const name = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
1010
  const plainName = extractPlain(name);
1011
  if (plainName) texts.push(plainName);
1012
-
1013
  const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
1014
  if (Array.isArray(lore)) {
1015
  for (const line of lore) {
@@ -1018,13 +1137,13 @@ async function createBot() {
1018
  }
1019
  }
1020
  }
1021
-
1022
  if (texts.length === 0) {
1023
  texts.push(util.inspect(slot, { depth: null }));
1024
  }
1025
  } catch (err) {}
1026
  return texts;
1027
- }
1028
 
1029
  function windowMatchesLoreKeyword(window, keywords) {
1030
  try {
@@ -1543,6 +1662,8 @@ function activateEntityAtNoLook(entity, position) {
1543
  return;
1544
  }
1545
 
 
 
1546
  logger.info(`[${currentBotUsername}] Çiftçi (Hepsini Sat) menüsü açılıyor (${CIFTCI_COMMAND})...`);
1547
 
1548
  if (bot.currentWindow != null) {
@@ -1617,6 +1738,288 @@ function activateEntityAtNoLook(entity, position) {
1617
  }
1618
  }
1619
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1620
  function startKaziciPeriodic() {
1621
  if (kaziciIntervalHandle) return;
1622
 
@@ -1697,9 +2100,11 @@ function activateEntityAtNoLook(entity, position) {
1697
  botActions.sendSkyblockManual = sendSkyblockCommand;
1698
  botActions.antiBotMove = antiBotMove;
1699
  botActions.sendMoneyToNick = sendMoneyToNick;
 
1700
 
1701
  startKaziciPeriodic();
1702
  startCiftciPeriodic();
 
1703
  startStallWatcher();
1704
 
1705
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
@@ -1784,30 +2189,35 @@ function activateEntityAtNoLook(entity, position) {
1784
  try { bot.closeWindow(window); } catch(e){}
1785
 
1786
  } else if (isCiftciWindow) {
1787
- try {
1788
- 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...`);
1789
- await new Promise(r => setTimeout(r, CIFTCI_CLICK_DELAY_AFTER_OPEN_MS));
 
 
 
 
1790
 
1791
- for (let i = 0; i < CIFTCI_CLICK_REPEAT_COUNT; i++) {
1792
- if (!bot || !botIsReady) break;
1793
- try {
1794
- await bot.clickWindow(CIFTCI_SELL_ALL_SLOT, 0, 0);
1795
- logger.info(`[${currentBotUsername}] Çiftçi hepsini-sat tıklaması gönderildi (${i + 1}/${CIFTCI_CLICK_REPEAT_COUNT}).`);
1796
- } catch (clickErr) {
1797
- logger.error(`[Çiftçi Arayüz Hatası] Tıklama #${i + 1} sunucu tarafından onaylanmadı: ${clickErr && clickErr.message ? clickErr.message : clickErr}`);
1798
- }
1799
- if (i < CIFTCI_CLICK_REPEAT_COUNT - 1) {
1800
- await new Promise(r => setTimeout(r, CIFTCI_CLICK_REPEAT_GAP_MS));
 
1801
  }
 
 
 
 
1802
  }
1803
 
1804
- await new Promise(r => setTimeout(r, KAZICI_ACTION_SETTLE_DELAY_MS));
1805
- } catch (e) {
1806
- logger.error(`[Çiftçi Arayüz Hatası] Hepsini-sat tıklama turu sırasında beklenmeyen hata: ${e && e.message ? e.message : e}`);
1807
  }
1808
 
1809
- try { bot.closeWindow(window); } catch(e){}
1810
-
1811
  } else {
1812
  const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
1813
  const can = extractMinyonCanFromSlot(beefSlot);
@@ -1887,6 +2297,7 @@ function activateEntityAtNoLook(entity, position) {
1887
  botActions.sendSkyblockManual = null;
1888
  botActions.antiBotMove = null;
1889
  botActions.sendMoneyToNick = null;
 
1890
 
1891
  safeDestroyAllConnections();
1892
 
@@ -2162,6 +2573,15 @@ app.get("/status", (req, res) => {
2162
  });
2163
  });
2164
 
 
 
 
 
 
 
 
 
 
2165
  // --- MANUEL BOT KONTROLÜ ENDPOINT'LERİ ---
2166
  app.get("/bot/stop", (req, res) => {
2167
  stopBotHard("Web paneli üzerinden /bot/stop isteği");
@@ -2197,6 +2617,14 @@ app.get("/bot/ciftci-satis", (req, res) => {
2197
  botActions.openCiftciAndSellAllManual().catch(e => logger.error(`[/bot/ciftci-satis Hatası] ${e && e.stack ? e.stack : e}`));
2198
  });
2199
 
 
 
 
 
 
 
 
 
2200
  app.get("/bot/besleyici-kontrol", (req, res) => {
2201
  if (!bot || !botIsReady || !botActions.scanAndFeedManual) {
2202
  return res.status(503).send({ success: false, message: "Bot hazır değil." });
@@ -2514,4 +2942,4 @@ process.stderr.write = function (chunk, encoding, callback) {
2514
  return true;
2515
  }
2516
  return originalStderrWrite.apply(process.stderr, arguments);
2517
- };
 
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",
63
+ "Depo dolumuna göre",
64
+ "Jeneratör materyalleri",
65
+ "Satışı açık olanlar",
66
+ "Toplaması açık olanlar"
67
+ ];
68
+ const CIFTCI_TARGET_FILTER_INDEX = 3; // "Jeneratör materyalleri"
69
+ const CIFTCI_ACTIVE_FILTER_COLOR = "#FCF988";
70
+ const CIFTCI_FILTER_ITEM_NAME_KEYWORD = "Filtre";
71
+ const CIFTCI_FILTER_STEP_WAIT_MS = 1000; // her tık sonrası ilk bekleme
72
+ const CIFTCI_FILTER_RETRY_WAIT_MS = 1000; // item gözükmezse ek bekleme
73
+ const CIFTCI_FILTER_MAX_RETRIES = 10; // güvenlik limiti
74
+ const STORAGE_SCAN_INTERVAL_MS = 15 * 60 * 1000; // 15 dakika
75
+ const STORAGE_TRACKED_ITEMS = ["diamond", "emerald", "iron_block"]; // internal name eşleşmesi
76
+
77
+ let storageInfoCache = {
78
+ diamond: null,
79
+ emerald: null,
80
+ iron_block: null,
81
+ lastUpdated: null
82
+ };
83
+ let storageScanIntervalHandle = null;
84
+
85
+ // Çiftçi penceresinin şu an hangi amaçla açık olduğunu tutan bayrak.
86
+ // "sell" -> hepsini-sat akışı, "scan" -> storage bilgisi tarama akışı.
87
+ let ciftciWindowPurpose = "sell";
88
+
89
  // --- KAZICI FAILOVER (YEDEK HESAP) AYARLARI ---
90
  const STALL_CHECK_INTERVAL_MS = 15 * 1000; // pose kontrolü ne sıklıkla yapılsın
91
  const STALL_TIMEOUT_MS = 60 * 1000; // bu süre hareketsiz kalırsa "durdu" say
 
206
  goToIslandManual: null,
207
  sendSkyblockManual: null,
208
  antiBotMove: null,
209
+ sendMoneyToNick: null,
210
+ scanStorageInfoManual: null
211
  };
212
 
213
  function formatDurationMs(ms) {
 
248
  ciftciIntervalHandle = null;
249
  logger.info("[Çiftçi Periyodik] Döngü zamanlayıcısı durduruldu.");
250
  }
251
+ if (storageScanIntervalHandle) {
252
+ clearInterval(storageScanIntervalHandle);
253
+ storageScanIntervalHandle = null;
254
+ logger.info("[Storage Tarama] Döngü zamanlayıcısı durduruldu.");
255
+ }
256
 
257
  nextScheduledCheckAtMs = null;
258
  nextKaziciAtMs = null;
 
951
  }
952
  return cur;
953
  } catch (e) { return undefined; }
954
+ };
955
+
956
+ // components dizisinden belirli tipteki component'in data'sını bulur
957
+ function getComponentData(slot, type) {
958
+ try {
959
+ if (!slot || !Array.isArray(slot.components)) return undefined;
960
+ const comp = slot.components.find(c => c && c.type === type);
961
+ return comp ? comp.data : undefined;
962
+ } catch (e) { return undefined; }
963
+ }
964
+
965
+ // {type,value} tarzı NBT-benzeri sarmalayıcıyı açar
966
+ function nbtUnwrap(node) {
967
+ if (node && typeof node === "object" && "type" in node && "value" in node) {
968
+ return node.value;
969
+ }
970
+ return node;
971
+ };
972
+
973
+ // Yeni "components" formatındaki text-component ağacını düz metne çevirir
974
+ function flattenTextComponent(node) {
975
+ if (node == null) return "";
976
+ if (typeof node === "string") return node;
977
+ if (Array.isArray(node)) return node.map(flattenTextComponent).join("");
978
+
979
+ if (typeof node === "object") {
980
+ if ("type" in node && "value" in node) {
981
+ const t = node.type, v = node.value;
982
+ if (t === "string") return typeof v === "string" ? v : "";
983
+ if (t === "list" || t === "compound") return flattenTextComponent(v);
984
+ return ""; // byte/int vs. metin değil
985
+ }
986
+ let out = "";
987
+ if ("text" in node) out += flattenTextComponent(node.text);
988
+ if ("extra" in node) out += flattenTextComponent(node.extra);
989
+ return out;
990
+ }
991
+ return "";
992
+ };
993
+
994
+ // Tek bir lore satırı node'unu {text, color} olarak parse eder (yeni format)
995
+ function parseComponentLoreLine(lineNode) {
996
+ let text = "";
997
+ let color = null;
998
+
999
+ function walk(node) {
1000
+ if (node == null) return;
1001
+ if (typeof node === "string") { text += node; return; }
1002
+ if (Array.isArray(node)) { node.forEach(walk); return; }
1003
+ if (typeof node === "object") {
1004
+ if ("type" in node && "value" in node) {
1005
+ const t = node.type, v = node.value;
1006
+ if (t === "string") { text += (typeof v === "string" ? v : ""); return; }
1007
+ if (t === "list" || t === "compound") { walk(v); return; }
1008
+ return;
1009
+ }
1010
+ if ("color" in node) {
1011
+ const colVal = nbtUnwrap(node.color);
1012
+ if (color == null && typeof colVal === "string") color = colVal;
1013
+ }
1014
+ if ("text" in node) walk(node.text);
1015
+ if ("extra" in node) walk(node.extra);
1016
+ }
1017
  }
1018
 
1019
+ walk(lineNode);
1020
+ return { text: text.trim(), color };
1021
+ };
1022
+
1023
  function deepSearchForString(root, targetVariantsList) {
1024
  const results = [];
1025
  const visited = new WeakSet();
 
1092
  const texts = [];
1093
  try {
1094
  if (!slot) return texts;
1095
+
1096
+ // Yeni format: components
1097
+ const customNameData = getComponentData(slot, "custom_name");
1098
+ if (customNameData !== undefined) {
1099
+ const nameTxt = flattenTextComponent(customNameData);
1100
+ if (nameTxt) texts.push(nameTxt);
1101
+ }
1102
+ const loreData = getComponentData(slot, "lore");
1103
+ if (Array.isArray(loreData)) {
1104
+ for (const line of loreData) {
1105
+ const { text } = parseComponentLoreLine(line);
1106
+ if (text) texts.push(text);
1107
+ }
1108
+ }
1109
+ if (texts.length > 0) return texts;
1110
+
1111
+ // Eski format: nbt (fallback)
1112
  function extractPlain(raw) {
1113
  if (!raw || typeof raw !== "string") return null;
1114
  try {
 
1123
  } catch (e) {}
1124
  return raw;
1125
  }
1126
+
1127
  if (slot.nbt) {
1128
  const name = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
1129
  const plainName = extractPlain(name);
1130
  if (plainName) texts.push(plainName);
1131
+
1132
  const lore = safeGet(slot.nbt, ["value", "display", "value", "Lore", "value"]);
1133
  if (Array.isArray(lore)) {
1134
  for (const line of lore) {
 
1137
  }
1138
  }
1139
  }
1140
+
1141
  if (texts.length === 0) {
1142
  texts.push(util.inspect(slot, { depth: null }));
1143
  }
1144
  } catch (err) {}
1145
  return texts;
1146
+ };
1147
 
1148
  function windowMatchesLoreKeyword(window, keywords) {
1149
  try {
 
1662
  return;
1663
  }
1664
 
1665
+ ciftciWindowPurpose = "sell";
1666
+
1667
  logger.info(`[${currentBotUsername}] Çiftçi (Hepsini Sat) menüsü açılıyor (${CIFTCI_COMMAND})...`);
1668
 
1669
  if (bot.currentWindow != null) {
 
1738
  }
1739
  }
1740
 
1741
+ // =====================================================================
1742
+ // ÇİFTÇİ FİLTRE NAVİGASYONU + STORAGE INFO TARAMA
1743
+ // =====================================================================
1744
+
1745
+ function stripColorAndGetLoreLines(window) {
1746
+ if (!window || !Array.isArray(window.slots)) return null;
1747
+ for (const slot of window.slots) {
1748
+ if (!slot) continue;
1749
+
1750
+ let nameTxt = "";
1751
+
1752
+ // Yeni format: components
1753
+ const customNameData = getComponentData(slot, "custom_name");
1754
+ if (customNameData !== undefined) {
1755
+ nameTxt = flattenTextComponent(customNameData);
1756
+ }
1757
+
1758
+ // Eski format: nbt (fallback)
1759
+ if (!nameTxt && slot.nbt) {
1760
+ const nameRaw = safeGet(slot.nbt, ["value", "display", "value", "Name", "value"]);
1761
+ try {
1762
+ const maybe = JSON.parse(nameRaw);
1763
+ if (maybe && maybe.extra) nameTxt = maybe.extra.map(x => x.text || "").join("");
1764
+ else if (maybe && maybe.text) nameTxt = maybe.text;
1765
+ } catch (e) { nameTxt = nameRaw || ""; }
1766
+ }
1767
+
1768
+ if (nameTxt.includes(CIFTCI_FILTER_ITEM_NAME_KEYWORD)) {
1769
+ return { slot, index: window.slots.indexOf(slot) };
1770
+ }
1771
+ }
1772
+ return null;
1773
+ };
1774
+
1775
+ function getFilterItemLoreEntries(filterSlot) {
1776
+ const entries = [];
1777
+
1778
+ // Yeni format: components
1779
+ const loreData = getComponentData(filterSlot, "lore");
1780
+ if (Array.isArray(loreData)) {
1781
+ for (const line of loreData) {
1782
+ entries.push(parseComponentLoreLine(line));
1783
+ }
1784
+ if (entries.length > 0) return entries;
1785
+ }
1786
+
1787
+ // Eski format: nbt (fallback)
1788
+ try {
1789
+ const lore = safeGet(filterSlot.nbt, ["value", "display", "value", "Lore", "value"]);
1790
+ if (!Array.isArray(lore)) return entries;
1791
+ for (const line of lore) {
1792
+ const raw = line.value || line;
1793
+ let plain = "";
1794
+ let color = null;
1795
+ try {
1796
+ const maybe = JSON.parse(raw);
1797
+ if (maybe && Array.isArray(maybe.extra)) {
1798
+ for (const part of maybe.extra) {
1799
+ if (part.text) plain += part.text;
1800
+ if (part.color && !color) color = part.color;
1801
+ }
1802
+ } else if (maybe && maybe.text) {
1803
+ plain = maybe.text;
1804
+ }
1805
+ } catch (e) {
1806
+ plain = raw;
1807
+ }
1808
+ entries.push({ text: plain.trim(), color });
1809
+ }
1810
+ } catch (e) {}
1811
+ return entries;
1812
+ };
1813
+
1814
+ function findCurrentFilterIndex(loreEntries) {
1815
+ for (let i = 0; i < CIFTCI_FILTER_MODES.length; i++) {
1816
+ const modeName = CIFTCI_FILTER_MODES[i];
1817
+ const match = loreEntries.find(e =>
1818
+ e.text.includes(modeName) &&
1819
+ (e.text.includes("»") || e.color === CIFTCI_ACTIVE_FILTER_COLOR)
1820
+ );
1821
+ if (match) return i;
1822
+ }
1823
+ // fallback: sadece renkle bulmayı dene
1824
+ const colorMatch = loreEntries.find(e => e.color === CIFTCI_ACTIVE_FILTER_COLOR);
1825
+ if (colorMatch) {
1826
+ for (let i = 0; i < CIFTCI_FILTER_MODES.length; i++) {
1827
+ if (colorMatch.text.includes(CIFTCI_FILTER_MODES[i])) return i;
1828
+ }
1829
+ }
1830
+ return -1;
1831
+ }
1832
+
1833
+ async function waitForFilterItem(maxRetries) {
1834
+ // window açıldıktan sonra Filtre item'ı gözükene kadar bekler
1835
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
1836
+ await new Promise(r => setTimeout(r, attempt === 0 ? CIFTCI_FILTER_STEP_WAIT_MS : CIFTCI_FILTER_RETRY_WAIT_MS));
1837
+ if (!bot || !bot.currentWindow) return null;
1838
+ const found = stripColorAndGetLoreLines(bot.currentWindow);
1839
+ if (found) return found;
1840
+ }
1841
+ return null;
1842
+ }
1843
+
1844
+ function extractStorageItemInfo(window, internalName) {
1845
+ if (!window || !Array.isArray(window.slots)) return null;
1846
+ const slot = window.slots.find(s => s && s.name === internalName);
1847
+ if (!slot) return null;
1848
+
1849
+ const texts = getItemDisplayTexts(slot);
1850
+ const joined = texts.join(" | ");
1851
+
1852
+ function grab(label) {
1853
+ const re = new RegExp(label.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") + "\\s*:?\\s*([\\d.,%~]+)", "i");
1854
+ const m = joined.match(re);
1855
+ return m ? m[1] : null;
1856
+ }
1857
+
1858
+ return {
1859
+ depo: grab("Depo"),
1860
+ limit: grab("Limit"),
1861
+ dolulukOrani: grab("Doluluk Oranı"),
1862
+ birimFiyati: grab("Birim Fiyatı"),
1863
+ anlikNetKazanc: grab("Anlık Net Kazanç"),
1864
+ dakikalikUretim: grab("Dakikalık üretim"),
1865
+ saatlikUretim: grab("Saatlik üretim"),
1866
+ gunlukUretim: grab("Günlük üretim")
1867
+ };
1868
+ }
1869
+
1870
+ async function navigateCiftciFilterToGenerator() {
1871
+ if (!bot || !bot.currentWindow) return false;
1872
+
1873
+ let attempts = 0;
1874
+ while (attempts < CIFTCI_FILTER_MAX_RETRIES) {
1875
+ attempts++;
1876
+
1877
+ const foundItem = await waitForFilterItem(CIFTCI_FILTER_MAX_RETRIES);
1878
+ if (!foundItem) {
1879
+ logger.warn("[Çiftçi Filtre] Filtre item'ı bulunamadı, deneme durduruldu.");
1880
+ return false;
1881
+ }
1882
+
1883
+ const loreEntries = getFilterItemLoreEntries(foundItem.slot);
1884
+ const currentIndex = findCurrentFilterIndex(loreEntries);
1885
+
1886
+ if (currentIndex === -1) {
1887
+ logger.warn("[Çiftçi Filtre] Mevcut filtre modu tespit edilemedi.");
1888
+ return false;
1889
+ }
1890
+
1891
+ if (currentIndex === CIFTCI_TARGET_FILTER_INDEX) {
1892
+ logger.info("[Çiftçi Filtre] Jeneratör materyalleri moduna ulaşıldı.");
1893
+ return true;
1894
+ }
1895
+
1896
+ const total = CIFTCI_FILTER_MODES.length;
1897
+ const forwardDist = (CIFTCI_TARGET_FILTER_INDEX - currentIndex + total) % total; // sol tık (aşağı)
1898
+ const backwardDist = (currentIndex - CIFTCI_TARGET_FILTER_INDEX + total) % total; // sağ tık (yukarı)
1899
+
1900
+ const useLeftClick = forwardDist <= backwardDist;
1901
+ const mouseButton = useLeftClick ? 0 : 1; // 0 = left, 1 = right
1902
+
1903
+ 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.`);
1904
+
1905
+ try {
1906
+ await bot.clickWindow(foundItem.index, mouseButton, 0);
1907
+ } catch (e) {
1908
+ logger.error(`[Çiftçi Filtre] Tıklama hatası: ${e && e.message ? e.message : e}`);
1909
+ return false;
1910
+ }
1911
+
1912
+ // bir sonraki turda waitForFilterItem zaten bekleyecek
1913
+ }
1914
+
1915
+ logger.warn("[Çiftçi Filtre] Azami deneme sayısına ulaşıldı, Jeneratör materyallerine geçilemedi.");
1916
+ return false;
1917
+ }
1918
+
1919
+ async function scanStorageInfoCore() {
1920
+ if (!bot || !botIsReady) return;
1921
+ if (!guiMutex.isLocked()) {
1922
+ logger.error("[GÜVENLİK İHLALİ] scanStorageInfoCore kilitsiz çağrıldı! İşlem iptal ediliyor.");
1923
+ return;
1924
+ }
1925
+
1926
+ ciftciWindowPurpose = "scan";
1927
+ logger.info(`[${currentBotUsername}] Storage bilgisi taraması başlıyor: çiftçi menüsü (${CIFTCI_COMMAND}) açılıyor...`);
1928
+
1929
+ if (bot.currentWindow != null) {
1930
+ try { bot.closeWindow(bot.currentWindow); } catch (e) {}
1931
+ await new Promise(r => setTimeout(r, 300));
1932
+ }
1933
+
1934
+ let windowOpened = false;
1935
+
1936
+ await new Promise((resolve) => {
1937
+ let timeoutHandle = null;
1938
+ const cleanFinish = () => {
1939
+ clearTimeout(timeoutHandle);
1940
+ windowOpenResolvers = [];
1941
+ resolve();
1942
+ };
1943
+
1944
+ windowOpenResolvers.push(() => {
1945
+ windowOpened = true;
1946
+ cleanFinish();
1947
+ });
1948
+
1949
+ timeoutHandle = setTimeout(() => {
1950
+ logger.warn("[Storage Tarama] Menü açılamadı (zaman aşımı).");
1951
+ cleanFinish();
1952
+ }, CIFTCI_WINDOW_TIMEOUT_MS);
1953
+
1954
+ try { bot.chat(CIFTCI_COMMAND); } catch (e) {}
1955
+ });
1956
+
1957
+ if (!windowOpened || !bot.currentWindow) {
1958
+ logger.warn("[Storage Tarama] Menü açılmadığı için tarama atlandı.");
1959
+ ciftciWindowPurpose = "sell";
1960
+ return;
1961
+ }
1962
+
1963
+ const reached = await navigateCiftciFilterToGenerator();
1964
+
1965
+ if (reached && bot.currentWindow) {
1966
+ const newCache = {
1967
+ diamond: extractStorageItemInfo(bot.currentWindow, "diamond"),
1968
+ emerald: extractStorageItemInfo(bot.currentWindow, "emerald"),
1969
+ iron_block: extractStorageItemInfo(bot.currentWindow, "iron_block"),
1970
+ lastUpdated: getExtendedDateTimeString()
1971
+ };
1972
+ storageInfoCache = newCache;
1973
+ logger.info(`[Storage Tarama] Bilgiler güncellendi: ${JSON.stringify(newCache)}`);
1974
+ } else {
1975
+ logger.warn("[Storage Tarama] Jeneratör materyallerine ulaşılamadığı için veri güncellenmedi.");
1976
+ }
1977
+
1978
+ try { if (bot.currentWindow) bot.closeWindow(bot.currentWindow); } catch (e) {}
1979
+ ciftciWindowPurpose = "sell";
1980
+ }
1981
+
1982
+ async function scanStorageInfo() {
1983
+ if (!guiMutex.tryAcquire()) {
1984
+ logger.info("[Storage Tarama] Başka bir GUI işlemi sürüyor, bu tur atlanıyor.");
1985
+ return;
1986
+ }
1987
+ try {
1988
+ await scanStorageInfoCore();
1989
+ } catch (err) {
1990
+ logger.error(`[scanStorageInfo Hatası] ${err && err.stack ? err.stack : err}`);
1991
+ ciftciWindowPurpose = "sell";
1992
+ } finally {
1993
+ guiMutex.release();
1994
+ }
1995
+ };
1996
+
1997
+ async function scanStorageInfoManual() {
1998
+ logger.info("[Storage Tarama - Manuel] Panelden istek geldi, sırasını bekliyor (öncelikli)...");
1999
+ await guiMutex.acquire();
2000
+ try {
2001
+ logger.info("[Storage Tarama - Manuel] Kilit alındı, tarama başlıyor.");
2002
+ await scanStorageInfoCore();
2003
+ } catch (err) {
2004
+ logger.error(`[scanStorageInfoManual Hatası] ${err && err.stack ? err.stack : err}`);
2005
+ ciftciWindowPurpose = "sell";
2006
+ } finally {
2007
+ guiMutex.release();
2008
+ }
2009
+ };
2010
+
2011
+ function startStorageScanPeriodic() {
2012
+ if (storageScanIntervalHandle) return;
2013
+ storageScanIntervalHandle = setInterval(() => {
2014
+ if (!bot || !botIsReady) return;
2015
+ if (manualStopRequested || isDestroying) return;
2016
+ scanStorageInfo();
2017
+ }, STORAGE_SCAN_INTERVAL_MS);
2018
+ logger.info(`[Storage Tarama] Bağımsız döngü başlatıldı (her ${formatDurationMs(STORAGE_SCAN_INTERVAL_MS)}).`);
2019
+ // ilk taramayı biraz gecikmeli başlat ki spawn sonrası diğer işler önce otursun
2020
+ setSafeTimeout(() => { scanStorageInfo(); }, 30 * 1000);
2021
+ }
2022
+
2023
  function startKaziciPeriodic() {
2024
  if (kaziciIntervalHandle) return;
2025
 
 
2100
  botActions.sendSkyblockManual = sendSkyblockCommand;
2101
  botActions.antiBotMove = antiBotMove;
2102
  botActions.sendMoneyToNick = sendMoneyToNick;
2103
+ botActions.scanStorageInfoManual = scanStorageInfoManual;
2104
 
2105
  startKaziciPeriodic();
2106
  startCiftciPeriodic();
2107
+ startStorageScanPeriodic();
2108
  startStallWatcher();
2109
 
2110
  if (config.utils && config.utils["auto-auth"] && config.utils["auto-auth"].enabled) {
 
2189
  try { bot.closeWindow(window); } catch(e){}
2190
 
2191
  } else if (isCiftciWindow) {
2192
+ if (ciftciWindowPurpose === "scan") {
2193
+ // Storage tarama modu: burada otomatik tıklama/kapatma yapma,
2194
+ // scanStorageInfoCore kendi akışını yönetiyor. Sadece resolver'ı tetikle.
2195
+ } else {
2196
+ try {
2197
+ 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...`);
2198
+ await new Promise(r => setTimeout(r, CIFTCI_CLICK_DELAY_AFTER_OPEN_MS));
2199
 
2200
+ for (let i = 0; i < CIFTCI_CLICK_REPEAT_COUNT; i++) {
2201
+ if (!bot || !botIsReady) break;
2202
+ try {
2203
+ await bot.clickWindow(CIFTCI_SELL_ALL_SLOT, 0, 0);
2204
+ logger.info(`[${currentBotUsername}] Çiftçi hepsini-sat tıklaması gönderildi (${i + 1}/${CIFTCI_CLICK_REPEAT_COUNT}).`);
2205
+ } catch (clickErr) {
2206
+ logger.error(`[Çiftçi Arayüz Hatası] Tıklama #${i + 1} sunucu tarafından onaylanmadı: ${clickErr && clickErr.message ? clickErr.message : clickErr}`);
2207
+ }
2208
+ if (i < CIFTCI_CLICK_REPEAT_COUNT - 1) {
2209
+ await new Promise(r => setTimeout(r, CIFTCI_CLICK_REPEAT_GAP_MS));
2210
+ }
2211
  }
2212
+
2213
+ await new Promise(r => setTimeout(r, KAZICI_ACTION_SETTLE_DELAY_MS));
2214
+ } catch (e) {
2215
+ logger.error(`[Çiftçi Arayüz Hatası] Hepsini-sat tıklama turu sırasında beklenmeyen hata: ${e && e.message ? e.message : e}`);
2216
  }
2217
 
2218
+ try { bot.closeWindow(window); } catch(e){}
 
 
2219
  }
2220
 
 
 
2221
  } else {
2222
  const beefSlot = window.slots.find(s => s?.name === "cooked_beef");
2223
  const can = extractMinyonCanFromSlot(beefSlot);
 
2297
  botActions.sendSkyblockManual = null;
2298
  botActions.antiBotMove = null;
2299
  botActions.sendMoneyToNick = null;
2300
+ botActions.scanStorageInfoManual = null;
2301
 
2302
  safeDestroyAllConnections();
2303
 
 
2573
  });
2574
  });
2575
 
2576
+ app.get("/storageInfo", (req, res) => {
2577
+ res.send({
2578
+ diamond: storageInfoCache.diamond,
2579
+ emerald: storageInfoCache.emerald,
2580
+ iron_block: storageInfoCache.iron_block,
2581
+ lastUpdated: storageInfoCache.lastUpdated
2582
+ });
2583
+ });
2584
+
2585
  // --- MANUEL BOT KONTROLÜ ENDPOINT'LERİ ---
2586
  app.get("/bot/stop", (req, res) => {
2587
  stopBotHard("Web paneli üzerinden /bot/stop isteği");
 
2617
  botActions.openCiftciAndSellAllManual().catch(e => logger.error(`[/bot/ciftci-satis Hatası] ${e && e.stack ? e.stack : e}`));
2618
  });
2619
 
2620
+ app.get("/bot/checkFarmer", (req, res) => {
2621
+ if (!bot || !botIsReady || !botActions.scanStorageInfoManual) {
2622
+ return res.status(503).send({ success: false, message: "Bot hazır değil." });
2623
+ }
2624
+ res.send({ success: true, message: "Çiftçi depo/storage kontrolü öncelikli olarak kuyruğa alındı, işleniyor." });
2625
+ botActions.scanStorageInfoManual().catch(e => logger.error(`[/bot/checkFarmer Hatası] ${e && e.stack ? e.stack : e}`));
2626
+ });
2627
+
2628
  app.get("/bot/besleyici-kontrol", (req, res) => {
2629
  if (!bot || !botIsReady || !botActions.scanAndFeedManual) {
2630
  return res.status(503).send({ success: false, message: "Bot hazır değil." });
 
2942
  return true;
2943
  }
2944
  return originalStderrWrite.apply(process.stderr, arguments);
2945
+ };