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.

Version au 02/04/2023. Voir la dernière version.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==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);
        }
    }
})();