diff --git a/GrepolisRemoteControl.user.js b/GrepolisRemoteControl.user.js index 03acd87..f27bd63 100644 --- a/GrepolisRemoteControl.user.js +++ b/GrepolisRemoteControl.user.js @@ -1,7 +1,7 @@ // ==UserScript== // @name Grepolis Remote Control // @namespace http://tampermonkey.net/ -// @version 3.6.3 +// @version 3.6.4 // @description Polls grepo.haunter-pets.top for remote commands and executes them in-game (Multi-Player) // @author Dimitrios // @match https://*.grepolis.com/game/* @@ -817,106 +817,118 @@ // Auto Bandit Camp: if enabled, attack/claim when ready if (farmSettings.bandit_camp_enabled) { try { - // Try to get the collection — it's only loaded if the camp UI was opened. - // If not found, actively fetch it from the game server. - let spotModel = uw.MM.getOnlyCollectionByName('PlayerAttackSpot')?.models?.[0]; + const player_id = uw.Game?.player_id; + const currentTownId = uw.Game?.town_id; + if (!player_id || !currentTownId) { + log('⚔️ Bandit Camp: No player_id or town_id found in Game globals.'); + } else { + // Build hash param — it's embedded in the page URL or game globals + const hash = uw.Game?.csrf_token || uw.Game?.h || uw.Game?.hash || ''; - if (!spotModel) { - // Log available collections once for diagnostics - try { - const allColls = uw.MM.getAllCollections ? uw.MM.getAllCollections() : null; - if (allColls) { - const names = Object.keys(allColls).filter(k => k.toLowerCase().includes('attack') || k.toLowerCase().includes('spot') || k.toLowerCase().includes('bandit')); - if (names.length) log(`⚔️ Bandit: Possible collection names: ${names.join(', ')}`); - } - } catch(e) {} - - // Actively fetch the spot state from the game server - log('⚔️ Bandit Camp: Collection not in memory — fetching from server...'); - try { - const player_id = uw.Game?.player_id; - const currentTownId = uw.Game?.town_id; - if (player_id && currentTownId) { - await new Promise((resolve) => { - uw.gpAjax.ajaxPost('frontend_bridge', 'get_own', { - model_url: `PlayerAttackSpot/${player_id}`, - town_id: currentTownId, - nl_init: true - }); - setTimeout(resolve, 2000); // wait 2s for the model to load - }); - spotModel = uw.MM.getOnlyCollectionByName('PlayerAttackSpot')?.models?.[0]; - } - } catch(e) { - log(`⚔️ Bandit fetch error: ${e.message}`); - } - } - - if (spotModel) { - const spotId = spotModel.id || spotModel.attributes.id; - const nowTs = Math.floor(Date.now() / 1000); - const townId = spotModel.attributes.town_id; - - // Debug log every cycle - log(`⚔️ Bandit Monitor -> Cooldown in: ${Math.max(0, spotModel.attributes.cooldown_at - nowTs)}s | Reward: ${spotModel.attributes.reward_available} | TownID: ${townId}`); - - if (spotModel.attributes.reward_available) { - log('⚔️ Bandit Camp: Reward available! Waiting before claiming...'); - await sleep(randInt(8000, 24000)); - uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { - model_url: `PlayerAttackSpot/${spotId}`, - action_name: 'useReward', + // Direct fetch of the PlayerAttackSpot model state + const url = `/game/frontend_bridge?town_id=${currentTownId}&action=execute&h=${hash}`; + const body = new URLSearchParams({ + json: JSON.stringify({ + model_url: `PlayerAttackSpot/${player_id}`, + action_name: 'get_state', captcha: null, arguments: {}, - town_id: townId, + town_id: currentTownId, nl_init: true - }); - log('⚔️ Bandit Camp: Reward claimed!'); - } else if (spotModel.attributes.cooldown_at <= nowTs) { - // Check if troops are still marching back - let hasMovements = false; - try { - const movements = uw.MM.getOnlyCollectionByName('MovementCommand')?.models || []; - hasMovements = movements.length > 0; - } catch (e) {} + }) + }); - if (!hasMovements) { - const town = uw.ITowns?.getTown?.(townId) || uw.ITowns?.towns?.[townId]; - if (town) { - const myUnits = town.units() || {}; - const allowedUnits = ['sword', 'slinger', 'archer', 'hoplite', 'rider', 'chariot', 'catapult']; - const sendUnits = {}; - let totalUnits = 0; - for (let u of allowedUnits) { - if ((myUnits[u] || 0) > 0) { - sendUnits[u] = myUnits[u]; - totalUnits += myUnits[u]; + const resp = await fetch(url, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', + 'X-Requested-With': 'XMLHttpRequest' + }, + body: body.toString() + }); + + let spotData = null; + if (resp.ok) { + try { + const raw = await resp.json(); + // Try to find the spot data in the response + spotData = raw?.data?.PlayerAttackSpot?.[player_id] + || raw?.data?.player_attack_spot + || raw?.PlayerAttackSpot + || (Array.isArray(raw?.data) ? raw.data[0] : null) + || raw; + if (spotData?.cooldown_at === undefined) spotData = null; + } catch(e) {} + } + + // Fallback: try the MM collection (works if camp was opened once) + if (!spotData) { + const mmModel = uw.MM.getOnlyCollectionByName('PlayerAttackSpot')?.models?.[0]; + if (mmModel) spotData = mmModel.attributes; + } + + if (!spotData) { + log(`⚔️ Bandit Camp: Could not load spot data. hash=${hash ? 'found' : 'MISSING'}. Try opening the camp window in-game once.`); + } else { + const nowTs = Math.floor(Date.now() / 1000); + const spotId = spotData.id || player_id; + const townId = spotData.town_id || currentTownId; + + log(`⚔️ Bandit Monitor -> Cooldown in: ${Math.max(0, spotData.cooldown_at - nowTs)}s | Reward: ${spotData.reward_available} | Level: ${spotData.level}`); + + if (spotData.reward_available) { + log('⚔️ Bandit Camp: Reward available! Waiting before claiming...'); + await sleep(randInt(8000, 24000)); + uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { + model_url: `PlayerAttackSpot/${spotId}`, + action_name: 'useReward', + captcha: null, + arguments: {}, + town_id: townId, + nl_init: true + }); + log('⚔️ Bandit Camp: Reward claimed!'); + } else if (spotData.cooldown_at <= nowTs) { + let hasMovements = false; + try { + const movements = uw.MM.getOnlyCollectionByName('MovementCommand')?.models || []; + hasMovements = movements.length > 0; + } catch (e) {} + + if (!hasMovements) { + const town = uw.ITowns?.getTown?.(townId) || uw.ITowns?.towns?.[townId]; + if (town) { + const myUnits = town.units() || {}; + const allowedUnits = ['sword', 'slinger', 'archer', 'hoplite', 'rider', 'chariot', 'catapult']; + const sendUnits = {}; + let totalUnits = 0; + for (let u of allowedUnits) { + if ((myUnits[u] || 0) > 0) { + sendUnits[u] = myUnits[u]; + totalUnits += myUnits[u]; + } + } + if (totalUnits > 0) { + log(`⚔️ Bandit Camp: Attacking with ${totalUnits} units...`); + await sleep(randInt(8000, 24000)); + uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { + model_url: `PlayerAttackSpot/${spotId}`, + action_name: 'attack', + captcha: null, + arguments: sendUnits, + town_id: townId, + nl_init: true + }); + log('⚔️ Bandit Camp: Attack sent!'); + } else { + log('⚔️ Bandit Camp: No units available.'); } } - if (totalUnits > 0) { - log(`⚔️ Bandit Camp: Cooldown over! Attacking with ${totalUnits} units...`); - await sleep(randInt(8000, 24000)); - uw.gpAjax.ajaxPost('frontend_bridge', 'execute', { - model_url: `PlayerAttackSpot/${spotId}`, - action_name: 'attack', - captcha: null, - arguments: sendUnits, - town_id: townId, - nl_init: true - }); - log('⚔️ Bandit Camp: Attack sent!'); - } else { - log('⚔️ Bandit Camp: No units available to send.'); - } } else { - log(`⚔️ Bandit Camp: Town ${townId} not found in local state.`); + log('⚔️ Bandit Camp: Troops still returning — waiting...'); } - } else { - log('⚔️ Bandit Camp: Troops still marching — waiting for them to return...'); } } - } else { - log('⚔️ Bandit Camp: PlayerAttackSpot collection not found in memory. Is the camp open in-game?'); } } catch (e) { log(`⚔️ Bandit camp error: ${e.message}`); @@ -924,6 +936,7 @@ } + if (cmdData.sync_requested) { log('Sync requested by server — pushing state immediately'); pushState();