TT Session Stats

FPS, Ping, Time info

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.

Tendrás que 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.

Tendrás que instalar una extensión como Tampermonkey antes de poder 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)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

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

// ==UserScript==
// @name         TT Session Stats
// @namespace    http://tampermonkey.net/
// @version      1.1
// @description  FPS, Ping, Time info
// @author       Aurelion-X9
// @match        https://tanktrouble.com/*
// @match        https://*.tanktrouble.com/*
// @run-at       document-start
// @grant        none
// ==/UserScript==

(function() {
    'use strict';

    let pings = [];
    let start = Date.now();
    let lastF = performance.now();
    let fTimes = [];
    let curPing = 0;
    let lastServerId = null;

    const div = document.createElement('div');
    div.id = 'tt-stats';
    div.innerHTML = '<span id="sf">FPS:--</span> <span id="sp">Ping:...</span> <span id="st">Time:0:00:00</span>';
    div.style.cssText = 'position:fixed;bottom:8px;left:8px;z-index:2147483647;background:rgba(0,0,0,0.85);color:#fff;padding:6px 12px;border-radius:6px;font:12px monospace;display:flex;gap:12px;pointer-events:none;';

    function init() {
        if (document.body && !document.getElementById('tt-stats')) {
            document.body.appendChild(div);
        }
    }
    init();
    setTimeout(init, 50);
    setTimeout(init, 200);
    setTimeout(init, 500);
    setTimeout(init, 1000);

    // Get current selected server ID
    function getCurrentServerId() {
        try {
            if (typeof Cookies !== 'undefined') {
                return Cookies.get('multiplayerserverid');
            }
            if (typeof ClientManager !== 'undefined' && ClientManager.getSelectedServer) {
                return ClientManager.getSelectedServer();
            }
        } catch(e) {}
        return null;
    }

    // Use TT's actual server ping measurement
    function measurePing() {
        try {
            if (typeof ClientManager === 'undefined') return;
            
            // Method 1: Get stats for all servers, use current one
            if (ClientManager.getAvailableServerStats) {
                const currentServer = getCurrentServerId();
                
                ClientManager.getAvailableServerStats(function(success, serverId, latency, gameCount, playerCount, message) {
                    if (success && latency > 0) {
                        // If this is our current server, use it
                        if (currentServer && serverId === currentServer) {
                            pings.push(latency);
                            if (pings.length > 10) pings.shift();
                            curPing = median();
                            lastServerId = serverId;
                        } else if (!lastServerId) {
                            // Use first available server's ping if we don't have one
                            pings.push(latency);
                            if (pings.length > 10) pings.shift();
                            curPing = median();
                        }
                    }
                });
            }
            
            // Method 2: Check if ClientManager has direct latency property
            if (ClientManager._latency) {
                pings.push(ClientManager._latency);
                curPing = median();
            }
            if (ClientManager.latency) {
                pings.push(ClientManager.latency);
                curPing = median();
            }
            
        } catch(e) {}
    }

    // Also try to read ping from UI if available
    function getPingFromUI() {
        try {
            // Check settings dropdown for ping text
            const settingsSelect = document.querySelector('#settings select option:not([disabled])');
            if (settingsSelect) {
                const desc = settingsSelect.getAttribute('data-description');
                if (desc) {
                    const match = desc.match(/(\d+)\s*ms/);
                    if (match) return parseInt(match[1]);
                }
            }
        } catch(e) {}
        return 0;
    }

    function median() {
        if (!pings.length) return curPing;
        const s = pings.slice().sort((a,b) => a-b);
        return s[Math.floor(s.length / 2)];
    }

    function fps() {
        const now = performance.now();
        const d = now - lastF;
        lastF = now;
        if (d > 0 && d < 500) {
            fTimes.push(d);
            if (fTimes.length > 30) fTimes.shift();
        }
        requestAnimationFrame(fps);
    }

    function getFPS() {
        try {
            if (typeof GameManager !== 'undefined' && GameManager.getGame) {
                const g = GameManager.getGame();
                if (g && g.time && g.time.fps > 0) return Math.round(g.time.fps);
            }
        } catch(e) {}
        if (!fTimes.length) return 0;
        return Math.round(1000 / (fTimes.reduce((a,b) => a+b, 0) / fTimes.length));
    }

    function fmt(ms) {
        const s = Math.floor(ms/1000);
        return Math.floor(s/3600) + ':' + String(Math.floor((s%3600)/60)).padStart(2,'0') + ':' + String(s%60).padStart(2,'0');
    }

    // Wait for ClientManager to be ready
    function waitForClientManager(callback) {
        let attempts = 0;
        const check = setInterval(function() {
            attempts++;
            if (typeof ClientManager !== 'undefined') {
                clearInterval(check);
                callback();
            } else if (attempts > 50) {
                clearInterval(check);
            }
        }, 200);
    }

    waitForClientManager(function() {
        // Start tracking
        fps();
        
        // Measure ping
        measurePing();
        setInterval(measurePing, 2000);
        
        // Also check UI periodically
        setInterval(function() {
            if (curPing === 0) {
                const uiPing = getPingFromUI();
                if (uiPing > 0) {
                    curPing = uiPing;
                }
            }
        }, 1000);
        
        // Update display
        setInterval(function() {
            const f = document.getElementById('sf');
            const p = document.getElementById('sp');
            const t = document.getElementById('st');
            
            if (f) {
                const v = getFPS();
                f.textContent = 'FPS:' + (v || '--');
                f.style.color = v > 100 ? '#4CAF50' : v > 60 ? '#FFC107' : '#f44336';
            }
            if (p) {
                p.textContent = 'Ping:' + (curPing > 0 ? curPing + 'ms' : '...');
                p.style.color = curPing > 0 && curPing < 80 ? '#4CAF50' : curPing > 0 && curPing < 150 ? '#FFC107' : '#f44336';
            }
            if (t) t.textContent = 'Time:' + fmt(Date.now() - start);
        }, 100);
    });
})();