Torn Framework

Framework with proper script communication

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         Torn Framework
// @version      2.1
// @namespace    http://tampermonkey.net/
// @description  Framework with proper script communication
// @author
// @match        https://www.torn.com/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        unsafeWindow
// @run-at document-body
// ==/UserScript==

(function () {
    'use strict';

    console.log('=== TORN FRAMEWORK VERSION STARTING ===');

    // Use unsafeWindow to ensure global access
    const globalWindow = typeof unsafeWindow !== 'undefined' ? unsafeWindow : window;

    // Prevent multiple instances
    if (globalWindow.TornFramework) {
        console.log('WARNING: TornFramework already exists!', globalWindow.TornFramework);
        return;
    }

    // Global framework object
    globalWindow.TornFramework = {
        version: '2.1-FIXED',
        modules: new Map(),
        initialized: false,
        debug: true
    };

    console.log('Framework object created on globalWindow:', globalWindow.TornFramework);

    // Settings
    let settings = {
        consoleEnabled: GM_getValue('consoleEnabled', true),
        menuVisible: GM_getValue('menuVisible', false)
    };

    function saveSettings() {
        Object.keys(settings).forEach(key => {
            GM_setValue(key, settings[key]);
        });
    }

    // =========================
    // LOGGING SYSTEM
    // =========================
    const logDiv = document.createElement("div");
    logDiv.id = 'torn-framework-console';
    logDiv.style.cssText = `
        position: fixed;
        bottom: 0;
        left: 0;
        width: 450px;
        max-height: 300px;
        overflow-y: auto;
        background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(20,20,20,0.95));
        color: white;
        font-size: 11px;
        z-index: 999999;
        padding: 12px;
        border-radius: 0 12px 0 0;
        font-family: 'Consolas', 'Monaco', monospace;
        border: 2px solid #37b24d;
        box-shadow: 0 4px 20px rgba(55,178,77,0.3);
        backdrop-filter: blur(10px);
        display: ${settings.consoleEnabled ? 'block' : 'none'};
    `;
    document.body.appendChild(logDiv);

    function log(msg, type = 'info', module = 'FRAMEWORK') {
        try {
            const timestamp = new Date().toLocaleTimeString();
            const p = document.createElement("div");

            const colors = {
                'error': '#ff6b6b',
                'success': '#51cf66',
                'warning': '#ffd43b',
                'info': '#74c0fc',
                'debug': '#9775fa'
            };

            p.style.cssText = `
                color: ${colors[type] || '#ccc'};
                padding: 3px 0;
                border-bottom: 1px solid rgba(255,255,255,0.1);
                font-size: 10px;
                line-height: 1.3;
            `;

            const moduleColor = module === 'FRAMEWORK' ? '#37b24d' : '#f59f00';
            p.innerHTML = `<span style="color: #666;">[${timestamp}]</span> <span style="color: ${moduleColor}; font-weight: bold;">[${module}]</span> ${msg}`;

            logDiv.appendChild(p);
            logDiv.scrollTop = logDiv.scrollHeight;

            // Limit to 100 logs
            while (logDiv.children.length > 100) {
                logDiv.removeChild(logDiv.firstChild);
            }

            console.log(`[TornFramework:${module}] ${msg}`);
        } catch (error) {
            console.error('Framework logging failed:', error);
        }
    }

    globalWindow.TornFramework.log = log;
    log('Framework logging system initialized', 'success');

    // =========================
    // MAIN MENU SYSTEM
    // =========================
    const modMenu = document.createElement("div");
    modMenu.id = 'torn-framework-menu';
    modMenu.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        width: 420px;
        max-height: 85vh;
        overflow-y: auto;
        background: linear-gradient(135deg, rgba(0,0,0,0.95), rgba(20,20,20,0.95));
        color: white;
        font-size: 12px;
        z-index: 1000000;
        padding: 20px;
        border-radius: 12px;
        font-family: 'Segoe UI', Arial, sans-serif;
        border: 2px solid #37b24d;
        box-shadow: 0 8px 32px rgba(55,178,77,0.4);
        backdrop-filter: blur(10px);
        display: none;
    `;

    modMenu.innerHTML = `
        <div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px; border-bottom: 2px solid #37b24d; padding-bottom: 15px;">
            <h3 style="margin: 0; color: #37b24d; text-shadow: 0 2px 4px rgba(0,0,0,0.5);">Torn Framework v${globalWindow.TornFramework.version}</h3>
            <button id="closeMenu" style="background: linear-gradient(45deg, #f03e3e, #c92a2a); border: none; color: white; padding: 6px 10px; border-radius: 6px; cursor: pointer; font-size: 12px;">✕</button>
        </div>

        <!-- FRAMEWORK STATUS -->
        <div style="margin-bottom: 15px; padding: 12px; background: linear-gradient(45deg, rgba(55,178,77,0.1), rgba(116,184,22,0.1)); border-radius: 8px; border: 1px solid #37b24d;">
            <div style="display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 8px; font-size: 10px; margin-bottom: 8px;">
                <div>Modules: <span id="moduleCount">0</span></div>
                <div>Active: <span id="activeCount">0</span></div>
                <div>Uptime: <span id="uptimeDisplay">0s</span></div>
            </div>
            <div id="moduleList" style="max-height: 80px; overflow-y: auto; font-size: 9px; color: #ccc;"></div>
        </div>

        <!-- FRAMEWORK SETTINGS -->
        <div style="margin-bottom: 15px; border: 1px solid #37b24d; padding: 12px; border-radius: 8px;">
            <h4 style="margin: 0 0 12px 0; color: #37b24d;">Framework Settings</h4>
            <label style="display: flex; align-items: center; cursor: pointer; margin-bottom: 8px;">
                <input type="checkbox" id="consoleEnabled" ${settings.consoleEnabled ? 'checked' : ''}>
                <span style="margin-left: 8px;">Debug Console</span>
            </label>
        </div>

        <!-- MODULE SECTIONS WILL BE INJECTED HERE -->
        <div id="moduleMenuSections"></div>
    `;
    document.body.appendChild(modMenu);

    // Menu toggle button
    const menuBtn = document.createElement("button");
    menuBtn.innerHTML = "⚙️";
    menuBtn.style.cssText = `
        position: fixed;
        top: 10px;
        right: 10px;
        z-index: 999999;
        background: linear-gradient(135deg, #37b24d, #51cf66);
        color: white;
        border: none;
        padding: 12px 14px;
        border-radius: 50%;
        cursor: pointer;
        font-size: 16px;
        box-shadow: 0 4px 16px rgba(55,178,77,0.4);
        transition: all 0.3s ease;
    `;
    menuBtn.onclick = () => {
        const isVisible = modMenu.style.display !== 'none';
        modMenu.style.display = isVisible ? 'none' : 'block';
        menuBtn.style.right = isVisible ? '10px' : '440px';
        if (!isVisible) updateFrameworkStatus();
        settings.menuVisible = !isVisible;
        saveSettings();
    };
    document.body.appendChild(menuBtn);

    // =========================
    // MODULE MANAGEMENT
    // =========================
    globalWindow.TornFramework.registerModule = function (moduleConfig) {
        const {
            name,
            version = '1.0',
            description = '',
            menuSection = null,
            initialize = null,
            cleanup = null,
            isActive = () => false
        } = moduleConfig;

        log(`Module registration attempt: ${name}`, 'info');

        if (!name) {
            log('Module registration failed: name is required', 'error');
            return false;
        }

        if (globalWindow.TornFramework.modules.has(name)) {
            log(`Module ${name} already registered, updating...`, 'warning');
        }

        const module = { name, version, description, menuSection, initialize, cleanup, isActive, registered: Date.now() };
        globalWindow.TornFramework.modules.set(name, module);
        log(`Module registered: ${name} v${version}`, 'success');

        if (menuSection) addModuleMenuSection(name, menuSection);

        if (initialize && typeof initialize === 'function') {
            try {
                initialize();
                log(`Module ${name} initialized`, 'success');
            } catch (error) {
                log(`Module ${name} initialization failed: ${error.message}`, 'error');
            }
        }

        updateFrameworkStatus();
        return true;
    };

    function addModuleMenuSection(moduleName, sectionHTML) {
        const container = document.getElementById('moduleMenuSections');
        if (!container) return;

        const existing = document.getElementById(`module-${moduleName}`);
        if (existing) existing.remove();

        const section = document.createElement('div');
        section.id = `module-${moduleName}`;
        section.style.cssText = 'margin-bottom: 15px; border: 1px solid #f59f00; padding: 12px; border-radius: 8px;';
        section.innerHTML = sectionHTML;

        container.appendChild(section);
        log(`Menu section added for module: ${moduleName}`, 'debug');
    }

    function updateFrameworkStatus() {
        try {
            const moduleCount = globalWindow.TornFramework.modules.size;
            const activeCount = Array.from(globalWindow.TornFramework.modules.values())
                .filter(module => module.isActive()).length;
            const uptime = Math.floor((Date.now() - globalWindow.TornFramework.startTime) / 1000);

            document.getElementById('moduleCount').textContent = moduleCount;
            document.getElementById('activeCount').textContent = activeCount;
            document.getElementById('uptimeDisplay').textContent = `${uptime}s`;

            const moduleList = document.getElementById('moduleList');
            if (moduleList) {
                const moduleInfo = Array.from(globalWindow.TornFramework.modules.values())
                    .map(module => {
                        const status = module.isActive() ? '🟢' : '🔴';
                        return `${status} ${module.name} v${module.version}`;
                    }).join('<br>');
                moduleList.innerHTML = moduleInfo || 'No modules loaded';
            }
        } catch (error) {
            log(`Status update failed: ${error.message}`, 'error');
        }
    }

    // =========================
    // SETTINGS EVENTS
    // =========================
    function setupFrameworkEvents() {
        document.getElementById('closeMenu').onclick = () => {
            modMenu.style.display = 'none';
            menuBtn.style.right = '10px';
            settings.menuVisible = false;
            saveSettings();
        };

        document.getElementById('consoleEnabled').onchange = function () {
            settings.consoleEnabled = this.checked;
            logDiv.style.display = settings.consoleEnabled ? 'block' : 'none';
            saveSettings();
        };
    }

    // =========================
    // INITIALIZATION
    // =========================
    function initFramework() {
        if (globalWindow.TornFramework.initialized) return;

        log('Initializing Torn Framework...', 'success');

        globalWindow.TornFramework.startTime = Date.now();
        globalWindow.TornFramework.initialized = true;

        setupFrameworkEvents();

        if (settings.menuVisible) {
            modMenu.style.display = 'block';
            menuBtn.style.right = '440px';
        }

        log('Framework ready! Modules can now register.', 'success');
        updateFrameworkStatus();

        // Periodically update status
        setInterval(updateFrameworkStatus, 5000);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => {
            log('DOM loaded, initializing framework');
            setTimeout(initFramework, 500);
        });
    } else {
        log('DOM already loaded, initializing framework');
        setTimeout(initFramework, 500);
    }

    log('Framework script completed loading');
})();