From 95b38b1212ef830adc17f2f5e87be2dc62b36696 Mon Sep 17 00:00:00 2001 From: haunter Date: Sun, 26 Apr 2026 02:02:50 +0300 Subject: [PATCH] revert and farm fix --- GrepolisRemoteControl.user.js | 174 ++++++++++++---------------------- routes/api.py | 24 +++++ templates/farm.html | 21 ++++ 3 files changed, 103 insertions(+), 116 deletions(-) diff --git a/GrepolisRemoteControl.user.js b/GrepolisRemoteControl.user.js index e41e8a9..c2df43f 100644 --- a/GrepolisRemoteControl.user.js +++ b/GrepolisRemoteControl.user.js @@ -786,105 +786,6 @@ await sleep(500); return { ok: true, msg: `Market offer posted: ${offer} ${offer_type} => ${demand} ${demand_type}` }; } - // ---------------------------------------------------------------- - // Execute: Scan Market (On-Demand) - // ---------------------------------------------------------------- - async function executeScanMarket(cmd) { - const { town_id } = cmd; - - await sleep(randInt(1500, 3000)); - if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; - - return new Promise((resolve) => { - let intercepted = false; - let timeoutId; - - const origAjaxPost = uw.gpAjax.ajaxPost.bind(uw.gpAjax); - - // Handle BOTH Grepolis callback styles: - // Style A: ajaxPost(ctrl, action, params, loader, {success, error}) - // Style B: ajaxPost(ctrl, action, params, loader, fnSuccess, fnError) - uw.gpAjax.ajaxPost = function(controller, action, params, loader, cbSuccessOrObj, cbError) { - const handleResp = function(resp) { - log(`[Market intercept] ctrl:${controller} action:${action} has_offers:${!!(resp && resp.offers)}`); - if (!intercepted && resp && resp.offers) { - intercepted = true; - clearTimeout(timeoutId); - uw.gpAjax.ajaxPost = origAjaxPost; - fetch(`${BASE_URL}/api/market_data?player_id=${uw.Game.player_id}`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify(resp) - }) - .then(() => resolve({ ok: true, msg: `Market scanned: ${resp.offers.length} offers` })) - .catch(e => resolve({ ok: false, msg: 'Upload failed: ' + e })); - } - }; - - if (cbSuccessOrObj && typeof cbSuccessOrObj === 'object') { - // Style A — object with success/error keys - const origSuccess = cbSuccessOrObj.success; - return origAjaxPost(controller, action, params, loader, { - success: function(resp) { handleResp(resp); if (origSuccess) origSuccess(resp); }, - error: cbSuccessOrObj.error - }); - } else { - // Style B — separate function args - return origAjaxPost(controller, action, params, loader, - function(resp) { handleResp(resp); if (typeof cbSuccessOrObj === 'function') cbSuccessOrObj(resp); }, - cbError - ); - } - }; - - // Trigger getData through frontend_bridge - origAjaxPost('frontend_bridge', 'execute', { - model_url: 'BuildingMarket', - action_name: 'getData', - arguments: { - limit: 20, offset: 0, - demand_type: 'all_but_gold', offer_type: 'all_but_gold', - max_ratio: 3, max_delivery_time: 172800, - visibility: 2, order_by: 'ratio', order_direction: 'desc' - }, - town_id: town_id, - nl_init: true - }); - - // Timeout after 15 seconds - timeoutId = setTimeout(() => { - if (!intercepted) { - uw.gpAjax.ajaxPost = origAjaxPost; - resolve({ ok: false, msg: 'Market scan timed out' }); - } - }, 15000); - }); - } - - // ---------------------------------------------------------------- - // Execute: Accept Market Offer - // ---------------------------------------------------------------- - async function executeAcceptMarketOffer(cmd) { - const { town_id, payload } = cmd; - const { offer_id, amount } = payload; - - const reactionMs = randInt(800, 2000); - log(`Waiting ${reactionMs}ms before accepting offer...`); - await sleep(reactionMs); - - if (paused) return { ok: false, msg: 'Aborted due to pause/captcha' }; - - uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { - model_url: 'BuildingMarket', - action_name: 'acceptOffer', - arguments: { offer_id, amount }, - town_id: town_id, - nl_init: true - }); - - await sleep(500); - return { ok: true, msg: `Accepted market offer ${offer_id} for amount ${amount}` }; - } // ---------------------------------------------------------------- // Execute: Research (Academy) @@ -935,8 +836,6 @@ // Build queue, Recruit queue and Market queue are independent const buildCmd = cmdData.build; const recruitCmd = cmdData.recruit; - const scanMarketCmd = cmdData.scan_market; - const acceptMarketCmd = cmdData.accept_market_offer; const marketCmd = cmdData.market; const researchCmd = cmdData.research; const farmCmd = cmdData.farm; @@ -962,8 +861,6 @@ if (cmd.type === 'build') result = await executeBuild(cmd); else if (cmd.type === 'recruit') result = await executeRecruit(cmd); else if (cmd.type === 'market_offer') result = await executeMarketOffer(cmd); - else if (cmd.type === 'scan_market') result = await executeScanMarket(cmd); - else if (cmd.type === 'accept_market_offer') result = await executeAcceptMarketOffer(cmd); else if (cmd.type === 'research') result = await executeResearch(cmd); else if (cmd.type === 'farm_loot') result = await executeFarmLoot(cmd); else if (cmd.type === 'farm_upgrade') result = await executeFarmUpgrade(cmd); @@ -980,8 +877,6 @@ await execute(buildCmd); await execute(recruitCmd); await execute(marketCmd); - await execute(scanMarketCmd); - await execute(acceptMarketCmd); await execute(researchCmd); await execute(farmCmd); await execute(farmUpgradeCmd); @@ -990,17 +885,64 @@ const farmSettings = cmdData.farm_settings || {}; if (farmSettings.enabled && !farmCmd) { const nowTs = Math.floor(Date.now() / 1000); - // Check if ANY farm relation is ready (no need to iterate per-town) - const hasFarms = (() => { - try { - const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation'); - return coll?.models?.some(r => r.attributes.relation_status === 1 && (r.attributes.lootable_at || 0) <= nowTs); - } catch (e) { return false; } - })(); - if (hasFarms) { - log('⚡ Auto-farm: ready farms detected, triggering loot...'); - await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } }); - pushState(); + // Check if ANY farm relation is ready + let readyFarms = []; + try { + const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation'); + readyFarms = coll?.models?.filter(r => + r.attributes.relation_status === 1 && + (r.attributes.lootable_at || 0) <= nowTs + ) || []; + } catch (e) { /* silent */ } + + if (readyFarms.length > 0) { + // Check if the CURRENT town's warehouse is full (>95%) + let allFull = true; + let claimedAny = false; + + // Iterate over all towns that have ready farms + const towns = Object.values(uw.ITowns?.towns || {}); + for (const town of towns) { + const storage = town.resources?.()?.storage || town.get?.('storage') || 0; + const wood = town.resources?.()?.wood || town.get?.('wood') || 0; + const stone = town.resources?.()?.stone || town.get?.('stone') || 0; + const iron = town.resources?.()?.iron || town.get?.('iron') || 0; + if (!storage) continue; + + const maxRes = Math.max(wood, stone, iron); + const pct = maxRes / storage; + + if (pct < 0.95) { + // This town has room — loot using its town_id context + allFull = false; + log(`⚡ Auto-farm: looting into town ${town.get?.('name')} (${Math.round(pct*100)}% full)`); + await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } }); + claimedAny = true; + pushState(); + break; // one loot pass is enough per poll cycle + } + } + + if (allFull) { + log('⚠️ Auto-farm: ALL warehouses are full (>95%) — skipping loot this cycle'); + // Report full status to backend so farm.html can show notice + try { + await fetch(`${BASE_URL}/api/farm_status?player_id=${uw.Game.player_id}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ warehouse_full: true }) + }); + } catch(e) {} + } else if (claimedAny) { + // Clear the full flag + try { + await fetch(`${BASE_URL}/api/farm_status?player_id=${uw.Game.player_id}`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ warehouse_full: false }) + }); + } catch(e) {} + } } } } diff --git a/routes/api.py b/routes/api.py index 4ae1cd4..9da1e85 100644 --- a/routes/api.py +++ b/routes/api.py @@ -231,3 +231,27 @@ def upload_market_data(): conn.commit() conn.close() return jsonify({'ok': True}) + +# ------------------------------------------------------------------ +# POST/GET /api/farm_status — TM reports warehouse_full; dashboard reads it +# ------------------------------------------------------------------ +@api.route('/api/farm_status', methods=['POST', 'GET']) +def farm_status(): + player_id = request.args.get('player_id') + if not player_id: + return jsonify({'error': 'no player_id'}), 400 + kv_key = f'farm_status_{player_id}' + conn = get_db() + if request.method == 'POST': + data = request.get_json(silent=True) or {} + conn.execute(''' + INSERT INTO kv_store (key, value, updated_at) VALUES (?, ?, ?) + ON CONFLICT(key) DO UPDATE SET value=excluded.value, updated_at=excluded.updated_at + ''', (kv_key, json.dumps(data), datetime.utcnow().isoformat())) + conn.commit() + conn.close() + return jsonify({'ok': True}) + else: + row = conn.execute('SELECT value FROM kv_store WHERE key=?', (kv_key,)).fetchone() + conn.close() + return jsonify(json.loads(row['value']) if row else {'warehouse_full': False}) diff --git a/templates/farm.html b/templates/farm.html index 5abb4f6..22c2734 100644 --- a/templates/farm.html +++ b/templates/farm.html @@ -242,6 +242,15 @@
+ + +

⚙️ Ρυθμίσεις

@@ -505,12 +514,24 @@ }); } + // -- Warehouse full notice -- + async function checkWarehouseStatus() { + try { + const res = await fetch(`/api/farm_status?player_id=${PLAYER_ID}`); + const data = await res.json(); + const banner = document.getElementById('warehouse-full-banner'); + if (banner) banner.style.display = data.warehouse_full ? 'flex' : 'none'; + } catch(e) {} + } + // -- Boot -- loadSettings(); loadFarmData(); checkOnline(); + checkWarehouseStatus(); setInterval(loadFarmData, 15000); setInterval(checkOnline, 20000); + setInterval(checkWarehouseStatus, 20000);