From ade2d457082de8dd6cda2258c44286d0f4688d90 Mon Sep 17 00:00:00 2001 From: peshomir <80340328+peshomir@users.noreply.github.com> Date: Tue, 8 Jul 2025 17:53:39 +0300 Subject: [PATCH] Add automatic error reporting --- patches/patches.js | 13 ++++++--- src/gameScriptUtils.js | 60 ++++++++++++++++++++++++++++-------------- 2 files changed, 49 insertions(+), 24 deletions(-) diff --git a/patches/patches.js b/patches/patches.js index 6d896ec..d3fd905 100644 --- a/patches/patches.js +++ b/patches/patches.js @@ -2,6 +2,15 @@ import assets from '../assets.js'; import ModUtils from '../modUtils.js'; export default (/** @type {ModUtils} */ modUtils) => { + + // Disable built-in Territorial.io error reporting + modUtils.insertCode( + `window.removeEventListener("error", err); + msg = e.lineno + " " + e.colno + "|" + getStack(e); /* here */`, + `__fx.utils.reportError(e, msg); + return alert("Error:\\n" + e.filename + " " + e.lineno + " " + e.colno + " " + e.message);` + ) + modUtils.waitForMinification(() => applyPatches(modUtils)) } //export const requiredVariables = ["game", "playerId", "playerData", "rawPlayerNames", "gIsSingleplayer", "playerTerritories"]; @@ -301,10 +310,6 @@ canvas.font=aY.g0.g1(1,fontSize),canvas.fillStyle="rgba("+gR+","+tD+","+hj+",0.6 replaceRawCode(`,this.hostnameIsValid=0<=window.location.hostname.toLowerCase().indexOf("territorial.io"),`, `,this.hostnameIsValid=true,`) - // Disable built-in Territorial.io error reporting - replaceOne(/window\.addEventListener\("error",function (\w+)\((\w+)\){/g, - '$& window.removeEventListener("error", $1); return alert("Error:\\n" + $2.filename + " " + $2.lineno + " " + $2.colno + " " + $2.message);'); - console.log('Removing ads...'); // Remove ads replace('//api.adinplay.com/libs/aiptag/pub/TRT/territorial.io/tag.min.js', ''); diff --git a/src/gameScriptUtils.js b/src/gameScriptUtils.js index e8f9b9a..2179389 100644 --- a/src/gameScriptUtils.js +++ b/src/gameScriptUtils.js @@ -1,23 +1,43 @@ import { getSettings } from "./settings.js"; import { getVar } from "./gameInterface.js"; -const utils = new (function() { - this.getMaxTroops = function(playerTerritories, playerID) { return (playerTerritories[playerID]*150).toString(); }; - this.getDensity = function(playerID, playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories")) { - if (getSettings().densityDisplayStyle === "percentage") return (((playerBalances[playerID] / ((playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID]) * 150)) * 100).toFixed(1) + "%"); - else return (playerBalances[playerID] / (playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID])).toFixed(1); - }; - this.isPointInRectangle = function(x, y, rectangleStartX, rectangleStartY, width, height) { - return x >= rectangleStartX && x <= rectangleStartX + width && y >= rectangleStartY && y <= rectangleStartY + height; - }; - /** @param {CanvasRenderingContext2D} canvas @param {string} text */ - this.fillTextMultiline = function(canvas, text, x, y, maxWidth) { - const lineHeight = parseInt(canvas.font.split(" ").find(part => part.endsWith("px")).slice(0, -2)); - text.split("\n").forEach((line, index) => canvas.fillText(line, x, y + index * lineHeight, maxWidth)); - } - this.textStyleBasedOnDensity = function(playerID) { - const playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories"); - return `hsl(${playerBalances[playerID] / (playerTerritories[playerID] * 1.5)}, 100%, 50%, 1)`; - } -}); -export default utils \ No newline at end of file +// Example usage from game script: __fx.utils.getMaxTroops(...) + +function getMaxTroops(playerTerritories, playerID) { + return (playerTerritories[playerID] * 150).toString(); +}; +function getDensity(playerID, playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories")) { + if (getSettings().densityDisplayStyle === "percentage") return (((playerBalances[playerID] / ((playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID]) * 150)) * 100).toFixed(1) + "%"); + else return (playerBalances[playerID] / (playerTerritories[playerID] === 0 ? 1 : playerTerritories[playerID])).toFixed(1); +}; +function isPointInRectangle(x, y, rectangleStartX, rectangleStartY, width, height) { + return x >= rectangleStartX && x <= rectangleStartX + width && y >= rectangleStartY && y <= rectangleStartY + height; +}; +/** @param {CanvasRenderingContext2D} canvas @param {string} text */ +function fillTextMultiline(canvas, text, x, y, maxWidth) { + const lineHeight = parseInt(canvas.font.split(" ").find(part => part.endsWith("px")).slice(0, -2)); + text.split("\n").forEach((line, index) => canvas.fillText(line, x, y + index * lineHeight, maxWidth)); +} +function textStyleBasedOnDensity(playerID) { + const playerBalances = getVar("playerBalances"), playerTerritories = getVar("playerTerritories"); + return `hsl(${playerBalances[playerID] / (playerTerritories[playerID] * 1.5)}, 100%, 50%, 1)`; +} +function reportError(e, message) { + message = e.filename + " " + e.lineno + " " + e.colno + " " + e.message + "\n" + message; + fetch("https://fx.peshomir.workers.dev/stats/errors", { + body: JSON.stringify({ + message, + context: { + swState: navigator.serviceWorker?.controller?.state, + location: window.location.toString(), + userAgent: navigator.userAgent, + dictionary, + buildTimestamp, + scripts: Array.from(document.scripts).map(s => s.src) + } + }), + method: "POST" + }).catch(e => alert("Failed to report error: " + e)); +} + +export default { getMaxTroops, getDensity, isPointInRectangle, fillTextMultiline, textStyleBasedOnDensity, reportError } \ No newline at end of file