Update Grepolis_Data_Sender.js

This commit is contained in:
2025-07-31 15:17:12 +00:00
parent a90e637640
commit cc2f189543

View File

@@ -1,97 +1,179 @@
// ==UserScript== // ==UserScript==
// @name Grepolis Data Sender (Deep Scan Edition) // @name Grepolis Data Sender (Deep Scan v4.8 — Fixed Town ID)
// @namespace http://tampermonkey.net/ // @namespace http://tampermonkey.net/
// @version 3.1 // @version 4.8
// @description Full diagnostics + HTTPS endpoint for secure data transmission // @description Sends town stats and merges marketplace offers into correct town (robust ID detection)
// @author Dimitrios // @author Dimitrios
// @match https://*.grepolis.com/game/* // @match https://*.grepolis.com/game/*
// @grant unsafeWindow // @grant unsafeWindow
// @updateURL https://your-gitea-domain.com/dimitrios/grepolis-scripts/raw/branch-name/Grepolis-Data-Sender.user.js
// @downloadURL https://your-gitea-domain.com/dimitrios/grepolis-scripts/raw/branch-name/Grepolis-Data-Sender.user.js
// ==/UserScript== // ==/UserScript==
(function () { (function () {
'use strict'; 'use strict';
console.log("🔍 [DeepScan] Initializing Grepolis data sender..."); console.log("🧠 DeepScan v4.8 initialized...");
const uw = typeof unsafeWindow !== "undefined"
? (console.log("✅ [DeepScan] unsafeWindow available"), unsafeWindow)
: typeof wrappedJSObject !== "undefined"
? (console.log("✅ [DeepScan] wrappedJSObject fallback"), wrappedJSObject)
: (console.log("⚠️ [DeepScan] Using default window"), window);
function collectAndSendData() { const uw = typeof unsafeWindow !== "undefined" ? unsafeWindow : window;
let latestBasicPayload = null;
// 🔄 Send town snapshot and cache
function sendBasicStats() {
try { try {
console.log("🚀 [DeepScan] Collecting town data..."); const towns = uw.ITowns?.towns || {};
const player = uw.Game?.player_name || "unknown"; const player = uw.Game?.player_name || "unknown";
const player_id = uw.Game?.player_id || "unknown"; const player_id = uw.Game?.player_id || "unknown";
const towns = uw.ITowns?.towns || {};
const townEntries = Object.values(towns);
console.log(`📊 [DeepScan] Found ${townEntries.length} towns in ITowns.towns`);
if (townEntries.length === 0) { const stats = Object.values(towns).map(town => {
console.warn("⚠️ [DeepScan] Town data structure is present but empty"); const res = town.resources();
return;
}
const stats = townEntries.map(town => {
try {
const resources = town.resources();
const buildings = town.buildings()?.attributes ?? {}; const buildings = town.buildings()?.attributes ?? {};
const marketLevel = typeof town.getMarketplaceLevel === "function"
? town.getMarketplaceLevel()
: buildings.market || null;
return { return {
town_id: town.id, town_id: town.id,
town_name: town.name, town_name: town.name,
wood: resources.wood, wood: res.wood,
stone: resources.stone, stone: res.stone,
iron: resources.iron, iron: res.iron,
population: resources.population, population: res.population,
points: town.getPoints(), points: town.getPoints(),
buildings: buildings buildings,
market: { level: marketLevel }
}; };
} catch (innerErr) { });
console.error("💥 [DeepScan] Error in town parsing:", innerErr);
return null;
}
}).filter(Boolean);
const payload = { latestBasicPayload = {
type: "basic",
timestamp: new Date().toISOString(),
player, player,
player_id, player_id,
timestamp: new Date().toISOString(),
towns: stats towns: stats
}; };
console.log("📤 [DeepScan] Dispatching payload to grepo.haunter-pets.top:", payload);
fetch("https://grepo.haunter-pets.top/api/grepolis-data", { fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
method: "POST", method: "POST",
headers: { "Content-Type": "application/json" }, headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload) body: JSON.stringify(latestBasicPayload)
}) })
.then(r => r.text()) .then(res => res.text())
.then(txt => console.log("✅ [DeepScan] Server response:", txt)) .then(txt => console.log("✅ Basic stats sent:", txt))
.catch(err => console.error("❌ [DeepScan] Data send failed:", err)); .catch(err => console.error("❌ Failed to send basic stats:", err));
} catch (e) { } catch (e) {
console.error("💥 [DeepScan] Fatal error:", e); console.error("💥 Error collecting basic stats:", e);
} }
} }
function waitUntilDataReady() { // 📄 Parse marketplace trade offers
console.log("🕰️ [DeepScan] Checking if town data is ready..."); function parseMarketOffers() {
const townsObj = uw.ITowns?.towns; const rows = document.querySelectorAll(".js-tutorial-market-offers-table tbody tr");
const offers = [];
if (townsObj && Object.keys(townsObj).length > 0) { rows.forEach(row => {
console.log("🎯 [DeepScan] Towns are ready — beginning dispatch"); const cells = row.querySelectorAll("td");
collectAndSendData(); if (cells.length < 10) return;
setInterval(collectAndSendData, 30000);
const extractType = (td) => {
const icon = td.querySelector("span");
if (!icon) return "";
if (icon.classList.contains("market_wood_icon")) return "wood";
if (icon.classList.contains("market_stone_icon")) return "stone";
if (icon.classList.contains("market_iron_icon")) return "iron";
return "";
};
offers.push({
offer_id: row.dataset.offerId || null,
give_type: extractType(cells[0]),
give_amount: cells[1]?.textContent.trim() || "",
get_amount: cells[4]?.textContent.trim() || "",
get_type: extractType(cells[5]),
duration: cells[7]?.textContent.trim() || "",
player: cells[8]?.querySelector(".gp_player_link")?.textContent.trim() || "unknown"
});
});
return offers;
}
// 🧬 Merge trades into correct town object
function sendMergedMarketStats() {
try {
const offers = parseMarketOffers();
if (offers.length === 0) {
console.warn("⚠️ No marketplace offers detected");
return;
}
const townId =
uw.Game?.townId ||
uw.ITowns?.getCurrentTown()?.id ||
uw.current_town_id ||
"unknown";
console.log("🏙️ Active Town ID:", townId);
console.log("📋 Available Town IDs:", latestBasicPayload?.towns?.map(t => t.town_id));
if (!latestBasicPayload || !latestBasicPayload.towns) {
console.warn("🚫 Basic stats not yet initialized");
return;
}
const town = latestBasicPayload.towns.find(t => String(t.town_id) === String(townId));
if (!town) {
console.warn(`🧭 No matching town found for ID ${townId}`);
return;
}
town.market.offers = offers;
latestBasicPayload.timestamp = new Date().toISOString();
fetch("https://grepo.haunter-pets.top/api/grepolis-data", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(latestBasicPayload)
})
.then(res => res.text())
.then(txt => console.log("✅ Merged trades sent:", txt))
.catch(err => console.error("❌ Failed to send merged data:", err));
} catch (err) {
console.error("💥 Error during marketplace merge:", err);
}
}
// 👁️ Watch for marketplace panel opening
function monitorMarketplace() {
const observer = new MutationObserver(() => {
const panel = document.querySelector('.marketplace.all_offers');
if (panel && panel.offsetParent !== null) {
console.log("👁️ Marketplace opened — merging trades");
observer.disconnect();
sendMergedMarketStats();
setInterval(sendMergedMarketStats, 30000);
}
});
observer.observe(document.body, { childList: true, subtree: true });
}
// 🕓 Start script after town data is ready
function waitForTowns() {
const towns = uw.ITowns?.towns;
if (towns && Object.keys(towns).length > 0) {
console.log("🧭 Towns ready — starting DeepScan");
sendBasicStats();
setInterval(sendBasicStats, 30000);
monitorMarketplace();
} else { } else {
console.log("⏳ [DeepScan] Towns not ready yet — retrying in 1s"); console.log("⏳ Waiting for town data...");
setTimeout(waitUntilDataReady, 1000); setTimeout(waitForTowns, 1000);
} }
} }
window.addEventListener("load", () => { window.addEventListener("load", () => {
console.log("🌐 [DeepScan] Window loaded — monitoring town readiness"); console.log("🚀 Game page loaded — DeepScan v4.8 booting...");
waitUntilDataReady(); waitForTowns();
}); });
})(); })();