revert and farm fix
This commit is contained in:
@@ -786,105 +786,6 @@
|
|||||||
await sleep(500);
|
await sleep(500);
|
||||||
return { ok: true, msg: `Market offer posted: ${offer} ${offer_type} => ${demand} ${demand_type}` };
|
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)
|
// Execute: Research (Academy)
|
||||||
@@ -935,8 +836,6 @@
|
|||||||
// Build queue, Recruit queue and Market queue are independent
|
// Build queue, Recruit queue and Market queue are independent
|
||||||
const buildCmd = cmdData.build;
|
const buildCmd = cmdData.build;
|
||||||
const recruitCmd = cmdData.recruit;
|
const recruitCmd = cmdData.recruit;
|
||||||
const scanMarketCmd = cmdData.scan_market;
|
|
||||||
const acceptMarketCmd = cmdData.accept_market_offer;
|
|
||||||
const marketCmd = cmdData.market;
|
const marketCmd = cmdData.market;
|
||||||
const researchCmd = cmdData.research;
|
const researchCmd = cmdData.research;
|
||||||
const farmCmd = cmdData.farm;
|
const farmCmd = cmdData.farm;
|
||||||
@@ -962,8 +861,6 @@
|
|||||||
if (cmd.type === 'build') result = await executeBuild(cmd);
|
if (cmd.type === 'build') result = await executeBuild(cmd);
|
||||||
else if (cmd.type === 'recruit') result = await executeRecruit(cmd);
|
else if (cmd.type === 'recruit') result = await executeRecruit(cmd);
|
||||||
else if (cmd.type === 'market_offer') result = await executeMarketOffer(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 === 'research') result = await executeResearch(cmd);
|
||||||
else if (cmd.type === 'farm_loot') result = await executeFarmLoot(cmd);
|
else if (cmd.type === 'farm_loot') result = await executeFarmLoot(cmd);
|
||||||
else if (cmd.type === 'farm_upgrade') result = await executeFarmUpgrade(cmd);
|
else if (cmd.type === 'farm_upgrade') result = await executeFarmUpgrade(cmd);
|
||||||
@@ -980,8 +877,6 @@
|
|||||||
await execute(buildCmd);
|
await execute(buildCmd);
|
||||||
await execute(recruitCmd);
|
await execute(recruitCmd);
|
||||||
await execute(marketCmd);
|
await execute(marketCmd);
|
||||||
await execute(scanMarketCmd);
|
|
||||||
await execute(acceptMarketCmd);
|
|
||||||
await execute(researchCmd);
|
await execute(researchCmd);
|
||||||
await execute(farmCmd);
|
await execute(farmCmd);
|
||||||
await execute(farmUpgradeCmd);
|
await execute(farmUpgradeCmd);
|
||||||
@@ -990,17 +885,64 @@
|
|||||||
const farmSettings = cmdData.farm_settings || {};
|
const farmSettings = cmdData.farm_settings || {};
|
||||||
if (farmSettings.enabled && !farmCmd) {
|
if (farmSettings.enabled && !farmCmd) {
|
||||||
const nowTs = Math.floor(Date.now() / 1000);
|
const nowTs = Math.floor(Date.now() / 1000);
|
||||||
// Check if ANY farm relation is ready (no need to iterate per-town)
|
// Check if ANY farm relation is ready
|
||||||
const hasFarms = (() => {
|
let readyFarms = [];
|
||||||
try {
|
try {
|
||||||
const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation');
|
const coll = uw.MM.getOnlyCollectionByName('FarmTownPlayerRelation');
|
||||||
return coll?.models?.some(r => r.attributes.relation_status === 1 && (r.attributes.lootable_at || 0) <= nowTs);
|
readyFarms = coll?.models?.filter(r =>
|
||||||
} catch (e) { return false; }
|
r.attributes.relation_status === 1 &&
|
||||||
})();
|
(r.attributes.lootable_at || 0) <= nowTs
|
||||||
if (hasFarms) {
|
) || [];
|
||||||
log('⚡ Auto-farm: ready farms detected, triggering loot...');
|
} catch (e) { /* silent */ }
|
||||||
await executeFarmLoot({ payload: { loot_option: farmSettings.loot_option } });
|
|
||||||
pushState();
|
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) {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,3 +231,27 @@ def upload_market_data():
|
|||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
return jsonify({'ok': True})
|
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})
|
||||||
|
|||||||
@@ -242,6 +242,15 @@
|
|||||||
<!-- Status banner -->
|
<!-- Status banner -->
|
||||||
<div class="status-bar" id="status-bar"></div>
|
<div class="status-bar" id="status-bar"></div>
|
||||||
|
|
||||||
|
<!-- Warehouse-full notice (hidden by default) -->
|
||||||
|
<div id="warehouse-full-banner" style="display:none; background: linear-gradient(90deg, #5a1a00, #8b2500); border: 1px solid #ff6600; border-radius: 8px; padding: 12px 18px; margin-bottom: 1rem; display: flex; align-items: center; gap: 12px; font-weight: 600;">
|
||||||
|
<span style="font-size: 1.4rem;">📦</span>
|
||||||
|
<span>
|
||||||
|
<strong style="color:#ff9933;">Αποθήκη Γεμάτη!</strong>
|
||||||
|
Όλες οι αποθήκες είναι >95% — το bot παρακάμπτει τη λεηλασία μέχρι να αδειάσει χώρος.
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Control Panel -->
|
<!-- Control Panel -->
|
||||||
<div class="panel">
|
<div class="panel">
|
||||||
<h2>⚙️ Ρυθμίσεις</h2>
|
<h2>⚙️ Ρυθμίσεις</h2>
|
||||||
@@ -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 --
|
// -- Boot --
|
||||||
loadSettings();
|
loadSettings();
|
||||||
loadFarmData();
|
loadFarmData();
|
||||||
checkOnline();
|
checkOnline();
|
||||||
|
checkWarehouseStatus();
|
||||||
setInterval(loadFarmData, 15000);
|
setInterval(loadFarmData, 15000);
|
||||||
setInterval(checkOnline, 20000);
|
setInterval(checkOnline, 20000);
|
||||||
|
setInterval(checkWarehouseStatus, 20000);
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Reference in New Issue
Block a user