Heatmap for Splix.io

Adds a heatmap feature to the minimap in Splix.io, highlighting recently captured territories in white, which fades to black over time.

Versión del día 2/4/2023. Echa un vistazo a la versión más reciente.

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Heatmap for Splix.io
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  Adds a heatmap feature to the minimap in Splix.io, highlighting recently captured territories in white, which fades to black over time.
// @author       fr13ndly
// @license      MIT
// @match        *://splix.io/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=splix.io
// @grant        none
// ==/UserScript==

(function () {
    "use strict";

    const MAX_HEAT_LEVEL = 5;

    class Heatmap {
        constructor() {
            this.isInitialUpdate = true;
            this.heatCells = [];
        }

        update(cells) {
            // HeatCell not found in cells? Remove it.
            for (let i = this.heatCells.length; i > 0; i--) {
                const heatCell = this.heatCells[i - 1];
                const cell = cells.findIndex(
                    (c) => c.x == heatCell.x && c.y == heatCell.y
                );

                if (cell == -1) {
                    this.heatCells.splice(i - 1, 1);
                }
            }
            // Update hot levels
            for (const cell of cells) {
                const heatCell = this.heatCells.find(
                    (c) => c.x == cell.x && c.y == cell.y
                );
                if (heatCell) {
                    if (heatCell.heatLevel > 0) {
                        heatCell.heatLevel--;
                    }
                    continue;
                }
                // Not found - create "hot" cell
                this.heatCells.push({
                    x: cell.x,
                    y: cell.y,
                    heatLevel: this.isInitialUpdate ? 0 : MAX_HEAT_LEVEL,
                });
            }
            this.isInitialUpdate = false;
        }

        get cells() {
            return this.heatCells;
        }
    }

    class HeatmapUtils {
        static getHeatCellColor(heatLevel) {
            const lightness = (100 / MAX_HEAT_LEVEL) * heatLevel;
            return `hsl(0, 0%, ${lightness}%)`;
        }
    }

    var HEATMAPS = {};

    // Setup custom handlers
    window.addEventListener("load", function () {
        window.doConnect = new Proxy(window.doConnect, {
            apply: (target, thisArg, argArray) => {
                const retValue = target.apply(thisArg, argArray);

                // Modify ws.onmessage handler
                if (window.ws) {
                    window.ws.onmessage = new Proxy(window.ws.onmessage, {
                        apply: (target, thisArg, argArray) => {
                            const retValue = target?.apply(thisArg, argArray);

                            heatmapWSMessageHandler.apply(thisArg, argArray);

                            return retValue;
                        },
                    });
                }

                return retValue;
            },
        });
    });

    function heatmapWSMessageHandler(e) {
        const m = new Uint8Array(e.data);

        if (m[0] != receiveAction.MINIMAP) {
            return;
        }

        const part = m[1];
        const z = 20 * part;

        if (!HEATMAPS[part]) {
            HEATMAPS[part] = new Heatmap();
        }

        const currentHeatmap = HEATMAPS[part];
        const partCells = [];

        // Unpack cells
        for (let i = 1; i < m.length; i++) {
            // Process each bit
            for (let b = 0; b < 8; b++) {
                const isBitSet = (m[i] & (1 << b)) !== 0;
                if (isBitSet) {
                    const Q = 8 * (i - 2) + b;
                    const x = (Math.floor(Q / 80) % 80) + z;
                    const y = Q % 80;

                    partCells.push({ x, y });
                }
            }
        }

        // Update heatmap
        currentHeatmap.update(partCells);

        // Clear minimap area
        minimapCtx.clearRect(2 * z, 0, 40, 160);
        minimapCtx.fillStyle = "#000000";

        // Render cells
        for (const heatCell of currentHeatmap.cells) {
            minimapCtx.fillStyle = HeatmapUtils.getHeatCellColor(
                heatCell.heatLevel
            );
            minimapCtx.fillRect(2 * heatCell.x, 2 * heatCell.y, 2, 2);
        }
    }
})();