Greasy Fork镜像 还支持 简体中文。

TriX Executor (BETA) for Territorial.io

BEST EXPLOIT IN GAME1! REMINDER: it is still in a very early stage. report any bugs or issues to the author and please dont judge too harshly at this stage. Join TriX Discord server to receive more updates: https://discord.gg/Zp7cqqZzXX have fun cheating :D

目前為 2025-09-11 提交的版本,檢視 最新版本

// ==UserScript==
// @name         TriX Executor (BETA) for Territorial.io
// @namespace    https://gf.qytechs.cn/en/users/your-username
// @version      Beta-Vela-2024.02.20b
// @description  BEST EXPLOIT IN GAME1! REMINDER: it is still in a very early stage. report any bugs or issues to the author and please dont judge too harshly at this stage. Join TriX Discord server to receive more updates: https://discord.gg/Zp7cqqZzXX have fun cheating :D
// @author       Painsel
// @match        *://territorial.io/*
// @require      https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-javascript.min.js
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        unsafeWindow
// @run-at       document-start
// @license      MIT
// @icon         data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNCAyNCIgZmlsbD0iIzAwYWFmZiI+PHBhdGggZD0iTTE4LjM2IDIyLjA1bC00LjQyLTQuNDJDMTMuNDcgMTcuODcgMTMgMTguMTcgMTMgMTguNUMxMyAyMC45OSAxNS4wMSAyMyAxNy41IDIzaDMuNTRjLTIuNDUtMS40OC00LjQyLTMuNDUtNS45LTUuOTV6TTggMTNjMS42NiAwIDMuMTgtLjU5IDQuMzgtMS42MkwxMCAxMy41VjIybDIuNS0yLjVMMTggMTMuOTZjLjM1LS00OC42NS0xIC44Ny0xLjU1QzE4LjYxIDEzLjQxIDE4IDEyLjM0IDE4IDEyVjBoLTJ2MTJjMCAuMzQtLjAyLjY3LS4wNiAxLS4zMy4xOC0uNjguMy0xLjA0LjM3LTEuNzMgMC0zLjI3LS45My00LjE2LTIuMzZMNiAxMy42VjVINXY4eiIvPjwvc3ZnPg==
// ==/UserScript==

/* global Prism, unsafeWindow */

(function() {
    'use strict';

    let updateConnectionStatus = () => {}; // Will be assigned by the UI

    // --- WebSocket Manager ---
    const webSocketManager = {
        activeSocket: null,
        send: function(data) {
            if (this.activeSocket && this.activeSocket.readyState === WebSocket.OPEN) {
                this.activeSocket.send(data);
                return true;
            }
            console.warn('[TriX] Could not send packet: No active WebSocket connection.');
            return false;
        }
    };

    // --- WebSocket Proxy Setup ---
    const OriginalWebSocket = unsafeWindow.WebSocket;
    let logPacketCallback = () => {};

    unsafeWindow.WebSocket = function(url, protocols) {
        const isGameSocket = url.includes('/s52/');
        if (!isGameSocket) {
            return new OriginalWebSocket(url, protocols);
        }

        console.log(`[TriX] Intercepting WebSocket connection to: ${url}`);
        updateConnectionStatus('connecting', 'Attempting to connect...');
        const ws = new OriginalWebSocket(url, protocols);

        webSocketManager.activeSocket = ws;
        console.log('[TriX] Active game socket registered.');

        ws.addEventListener('open', () => {
            updateConnectionStatus('connected', 'Connection established.');
        });
        ws.addEventListener('close', (event) => {
            if (webSocketManager.activeSocket === ws) {
                webSocketManager.activeSocket = null;
                console.log('[TriX] Active game socket unregistered (connection closed).');
            }
            updateConnectionStatus('disconnected', `Disconnected. Code: ${event.code}`);
        });
        ws.addEventListener('error', () => {
            updateConnectionStatus('error', 'A connection error occurred.');
        });


        const originalSend = ws.send.bind(ws);
        ws.send = function(data) {
            logPacketCallback('send', data);
            return originalSend(data);
        };

        ws.addEventListener('message', (event) => {
            logPacketCallback('receive', event.data);
        });

        return ws;
    };

    // --- Main script logic ---
    function initialize() {
        const shadowHost = document.createElement('div');
        shadowHost.id = 'trix-host';
        document.body.appendChild(shadowHost);
        const shadowRoot = shadowHost.attachShadow({ mode: 'open' });

        const styleElement = document.createElement('style');
        styleElement.textContent = `
            /* PrismJS Theme */
            code[class*="language-"],pre[class*="language-"]{color:#ccc;background:0 0;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;tab-size:4;}pre[class*="language-"]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*="language-"],pre[class*="language-"]{background:#2d2d2d}:not(pre)>code[class*="language-"]{padding:.1em;border-radius:.3em;white-space:normal}.token.comment{color:#999}.token.punctuation{color:#ccc}.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.number,.token.function{color:#f08d49}.token.property,.token.class-name,.token.constant,.token.symbol{color:#f8c555}.token.selector,.token.important,.token.atrule,.token.keyword,.token.builtin{color:#cc99cd}.token.string,.token.char,.token.attr-value,.token.regex,.token.variable{color:#7ec699}.token.operator,.token.entity,.token.url{color:#67cdcc}

            /* --- TriX Executor UI --- */
            @keyframes trix-fade-in { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
            @keyframes trix-slide-in { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }

            #trix-toggle-btn { position: fixed; top: 15px; right: 15px; z-index: 99999; width: 50px; height: 50px; background-color: rgba(30, 30, 34, 0.8); color: #00aaff; border: 2px solid #00aaff; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; font-size: 24px; transition: all 0.3s ease; backdrop-filter: blur(5px); font-family: monospace; box-shadow: 0 0 10px rgba(0, 170, 255, 0.5); }
            #trix-toggle-btn:hover { transform: scale(1.1) rotate(15deg); box-shadow: 0 0 15px #00aaff; }

            #trix-container { position: fixed; top: 80px; right: 15px; width: 450px; min-height: 400px; z-index: 99998; color: #fff; border-radius: 10px; overflow: hidden; box-shadow: 0 5px 25px rgba(0,0,0,0.5); display: flex; flex-direction: column; backdrop-filter: blur(10px); animation: trix-slide-in 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards; resize: both; }
            #trix-container.hidden { display: none; }

            #trix-container[data-theme='dark-knight'] { background-color: rgba(30, 30, 34, 0.9); border: 1px solid #444; }
            #trix-container[data-theme='arctic-light'] { background-color: rgba(240, 240, 255, 0.9); border: 1px solid #ccc; color: #111; }
            #trix-container[data-theme='crimson'] { background-color: rgba(43, 8, 8, 0.9); border: 1px solid #8B0000; color: #f1f1f1; }
            #trix-container[data-theme='arctic-light'] .trix-tab, #trix-container[data-theme='arctic-light'] .trix-status-bar, #trix-container[data-theme='arctic-light'] #trix-packet-log { background: #e0e0e8; }
            #trix-container[data-theme='arctic-light'] .trix-tab.active { background: #f0f0ff; color: #0055aa; }
            #trix-container[data-theme='arctic-light'] .trix-editor-area { background: #f0f0ff; border-color: #aaa; }
            #trix-container[data-theme='crimson'] .trix-tab.active { color: #ff8b8b; }

            #trix-header, #trix-footer { cursor: move; user-select: none; }
            #trix-header { padding: 10px 15px; font-weight: bold; font-size: 16px; display: flex; justify-content: space-between; align-items: center; }
            #trix-container[data-theme='dark-knight'] #trix-header { background-color: rgba(0,0,0,0.3); }
            #trix-container[data-theme='arctic-light'] #trix-header { background-color: rgba(0,0,0,0.1); }
            #trix-container[data-theme='crimson'] #trix-header { background-color: rgba(139, 0, 0, 0.5); }
            .trix-title-3d { color: #E0E4E8; font-family: 'Segoe UI', 'Roboto', sans-serif; font-weight: 900; font-size: 18px; letter-spacing: 1px; text-shadow: 0 0 2px rgba(255, 255, 255, 0.6), 0 0 10px #00aaff, 1px 1px 0 #0f121a, 2px 2px 0 #0f121a, 3px 3px 0 #0f121a, 4px 4px 5px rgba(0, 0, 0, 0.5); }
            .trix-version-tag { font-size: 10px; font-weight: 300; opacity: 0.7; margin-left: 8px; vertical-align: middle; }
            #trix-header-controls { display: flex; align-items: center; gap: 15px; }
            #trix-fps-display { font-size: 12px; font-weight: normal; opacity: 0.7; }
            #trix-close-btn { cursor: pointer; font-size: 20px; font-weight: bold; padding: 0 5px; }
            #trix-close-btn:hover { color: #ff5555; }

            /* NEW: Connection Status */
            #trix-conn-status { width: 12px; height: 12px; border-radius: 50%; transition: background-color 0.5s ease; }
            #trix-conn-status.disconnected { background-color: #dc3545; box-shadow: 0 0 5px #dc3545; }
            #trix-conn-status.connecting { background-color: #ffc107; box-shadow: 0 0 5px #ffc107; animation: trix-pulse 1.5s infinite; }
            #trix-conn-status.connected { background-color: #28a745; box-shadow: 0 0 5px #28a745; }
            @keyframes trix-pulse { 0% { opacity: 1; } 50% { opacity: 0.4; } 100% { opacity: 1; } }

            #trix-content { padding: 0 15px 15px 15px; flex-grow: 1; display: flex; flex-direction: column; }
            .trix-tabs { display: flex; flex-wrap: wrap; border-bottom: 1px solid #555; }
            .trix-tab { background: #2a2a30; padding: 8px 12px; cursor: pointer; border-radius: 5px 5px 0 0; margin-right: 4px; position: relative; transition: background 0.2s; }
            .trix-tab:hover { background: #3a3a42; }
            .trix-tab.active { background: #1e1e22; font-weight: bold; color: #00aaff; }
            .trix-tab-name { padding-right: 15px; }
            .trix-tab-close { position: absolute; top: 50%; right: 5px; transform: translateY(-50%); font-size: 14px; opacity: 0.6; }
            .trix-tab-close:hover { opacity: 1; color: #ff5555; }
            #trix-new-tab-btn { background: none; border: none; color: #00aaff; font-size: 20px; cursor: pointer; padding: 5px 10px; }

            .trix-view { display: flex; flex-direction: column; flex-grow: 1; margin-top: 10px; }
            .trix-editor-area { position: relative; flex-grow: 1; margin-top: -1px; background: #2d2d2d; border: 1px solid #555; border-radius: 0 0 5px 5px; }
            .trix-editor-area textarea, .trix-editor-area pre { margin: 0; padding: 10px; font-family: 'Fira Code', 'Consolas', monospace; font-size: 14px; line-height: 1.5; white-space: pre; word-wrap: normal; width: 100%; height: 100%; box-sizing: border-box; position: absolute; top: 0; left: 0; overflow: auto; }
            .trix-editor-area textarea { z-index: 1; background: transparent; color: inherit; resize: none; border: none; outline: none; -webkit-text-fill-color: transparent; }
            .trix-editor-area pre { z-index: 0; pointer-events: none; }

            .trix-action-bar { display: flex; gap: 10px; margin-top: 10px; }
            .trix-button { background-color: #007bff; color: white; border: none; padding: 8px 12px; cursor: pointer; border-radius: 5px; transition: background-color 0.2s; flex-grow: 1; }
            #trix-execute-btn { background-color: #28a745; }
            .trix-status-bar { margin-top: 10px; padding: 5px; background: rgba(0,0,0,0.2); font-size: 12px; border-radius: 3px; min-height: 1em; }
            .trix-status-success { color: #28a745; }
            .trix-status-error { color: #dc3545; }

            #trix-packet-log-view { flex-grow: 1; display: flex; flex-direction: column; }
            #trix-packet-log { flex-grow: 1; background: #1e1e22; border: 1px solid #555; border-radius: 5px; padding: 10px; overflow-y: auto; font-family: monospace; font-size: 12px; white-space: pre-wrap; word-break: break-all; }
            .packet-item { padding: 2px 0; border-bottom: 1px solid #333; }
            .packet-send { color: #7ec699; }
            .packet-receive { color: #cc99cd; }
            .packet-meta { opacity: 0.6; font-size: 10px; margin-right: 10px; }
            #trix-packet-input { flex-grow: 1; background: #2d2d2d; border: 1px solid #555; color: #ccc; padding: 8px; border-radius: 5px; font-family: monospace; }
            #trix-send-packet-btn, #trix-clear-log-btn { flex-grow: 0 !important; width: 80px; }

            #trix-settings-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.6); z-index: 100000; display: flex; align-items: center; justify-content: center; backdrop-filter: blur(5px); }
            .trix-settings-content { background: #1e1e22; padding: 20px; border-radius: 8px; width: 300px; box-shadow: 0 0 20px rgba(0,0,0,0.5); animation: trix-fade-in 0.3s; }
        `;
        shadowRoot.appendChild(styleElement);

        let state = {
            tabs: [],
            activeTabId: null,
            settings: { theme: 'dark-knight', position: { top: '80px', left: 'auto', right: '15px' }, size: { width: '450px', height: '400px' } }
        };

        const $ = (selector, parent = shadowRoot) => parent.querySelector(selector);
        const debounce = (func, delay) => { let t; return (...a) => { clearTimeout(t); t = setTimeout(() => func.apply(this, a), delay); }; };

        function loadState() {
            const savedState = GM_getValue('trixExecutorState');
            if (savedState) state = { ...state, ...savedState };
            const defaultTabs = [
                { id: 'logger', name: 'Packet Logger', code: null, isPermanent: true },
                { id: Date.now(), name: "Welcome", code: "// Welcome to TriX Executor!\nconsole.log('Hello from TriX!');" }
            ];
            if (!state.tabs || state.tabs.length === 0) state.tabs = defaultTabs;
            if (!state.tabs.find(t => t.id === 'logger')) state.tabs.unshift(defaultTabs[0]);
            if (!state.activeTabId || !state.tabs.find(t => t.id === state.activeTabId)) {
                state.activeTabId = state.tabs[0].id;
            }
        }

        const saveState = debounce(() => {
            const container = $('#trix-container');
            if (container) {
                state.settings.position = { top: container.style.top, left: container.style.left, right: container.style.right, bottom: 'auto' };
                state.settings.size = { width: container.style.width, height: container.style.height };
            }
            GM_setValue('trixExecutorState', state);
        }, 500);

        let ui, editor;

        function createUI() {
            const toggleBtn = document.createElement('div');
            toggleBtn.id = 'trix-toggle-btn'; toggleBtn.title = 'Toggle TriX Executor (BETA)'; toggleBtn.innerHTML = 'X';
            const container = document.createElement('div');
            container.id = 'trix-container'; container.classList.add('hidden');
            container.innerHTML = `
                <div id="trix-header">
                    <div><span class="trix-title-3d">TriX Executor</span><span class="trix-version-tag">(v${GM_info.script.version})</span></div>
                    <div id="trix-header-controls">
                        <span id="trix-conn-status" class="disconnected" title="No connection"></span>
                        <span id="trix-fps-display"></span>
                        <span id="trix-close-btn" title="Close">✖</span>
                    </div>
                </div>
                <div id="trix-content"></div>
                <div id="trix-footer" style="padding:10px; text-align:center; background:rgba(0,0,0,0.2);">
                     <button id="trix-settings-btn" class="trix-button" style="flex-grow:0; padding: 5px 15px;">Settings</button>
                </div>`;
            shadowRoot.append(toggleBtn, container);
            return { toggleBtn, container };
        }

        updateConnectionStatus = function(status, title) {
            const statusIndicator = $('#trix-conn-status');
            if (statusIndicator) {
                statusIndicator.className = ''; // Clear existing classes
                statusIndicator.classList.add(status);
                statusIndicator.title = title;
            }
        };

        function renderTabs() {
            const tabsContainer = $('.trix-tabs');
            if (!tabsContainer) return;
            tabsContainer.innerHTML = '';
            state.tabs.forEach(tab => {
                const tabEl = document.createElement('div');
                tabEl.className = 'trix-tab'; tabEl.dataset.tabId = tab.id;
                if (tab.id === state.activeTabId) tabEl.classList.add('active');
                tabEl.innerHTML = `<span class="trix-tab-name">${tab.name}</span>` + (!tab.isPermanent ? `<span class="trix-tab-close">x</span>` : '');
                tabsContainer.appendChild(tabEl);
            });
            const newTabBtn = document.createElement('button');
            newTabBtn.id = 'trix-new-tab-btn'; newTabBtn.textContent = '+';
            tabsContainer.appendChild(newTabBtn);
            renderEditor();
        }

        function renderActiveView() {
            const content = $('#trix-content');
            const activeTab = state.tabs.find(t => t.id === state.activeTabId);
            content.innerHTML = '';

            if (activeTab.id === 'logger') {
                content.innerHTML = `
                    <div id="trix-packet-log-view" class="trix-view">
                        <div class="trix-tabs"></div>
                        <div id="trix-packet-log"></div>
                        <div class="trix-action-bar">
                             <input type="text" id="trix-packet-input" placeholder="Enter packet data to send...">
                             <button id="trix-send-packet-btn" class="trix-button">Send</button>
                             <button id="trix-clear-log-btn" class="trix-button">Clear</button>
                        </div>
                        <div class="trix-status-bar">Ready.</div>
                    </div>`;
                $('#trix-clear-log-btn').addEventListener('click', () => $('#trix-packet-log').innerHTML = '');
                $('#trix-send-packet-btn').addEventListener('click', sendManualPacket);
                $('#trix-packet-input').addEventListener('keydown', (e) => {
                    if (e.key === 'Enter') sendManualPacket();
                });
                renderTabs();
            } else {
                content.innerHTML = `
                    <div id="trix-injector-container" class="trix-view">
                        <div class="trix-tabs"></div>
                        <div class="trix-editor-area"></div>
                        <div class="trix-action-bar">
                            <button id="trix-execute-btn" class="trix-button">Execute</button>
                            <button id="trix-clear-btn" class="trix-button">Clear</button>
                        </div>
                        <div class="trix-status-bar">Ready.</div>
                    </div>`;
                renderTabs();
            }
        }

        function sendManualPacket() {
            const input = $('#trix-packet-input');
            const statusBar = $('.trix-status-bar');
            if (!input || !statusBar) return;

            const data = input.value;
            if (!data) return;

            const success = webSocketManager.send(data);
            if (success) {
                statusBar.textContent = `Packet sent successfully at ${new Date().toLocaleTimeString()}`;
                statusBar.className = 'trix-status-bar trix-status-success';
                input.value = '';
            } else {
                statusBar.textContent = 'Error: No active WebSocket connection.';
                statusBar.className = 'trix-status-bar trix-status-error';
            }
        }

        function renderEditor() {
            const editorArea = $('.trix-editor-area');
            if (!editorArea) { editor = null; return; }
            const activeTab = state.tabs.find(t => t.id === state.activeTabId);
            if (!activeTab) { editorArea.innerHTML = ''; editor = null; return; }

            editorArea.innerHTML = `
                <textarea spellcheck="false" autocapitalize="off" autocomplete="off" autocorrect="off"></textarea>
                <pre class="language-js"><code></code></pre>`;
            editor = { textarea: $('textarea', editorArea), pre: $('pre', editorArea), code: $('code', editorArea) };
            editor.textarea.value = activeTab.code;
            highlightCode(activeTab.code);
            addEditorEventListeners();
        }

        function highlightCode(code) { if (editor) editor.code.innerHTML = Prism.highlight(code + '\n', Prism.languages.javascript, 'javascript'); }

        function addEditorEventListeners() {
            if (!editor) return;
            editor.textarea.addEventListener('input', () => {
                const activeTab = state.tabs.find(t => t.id === state.activeTabId);
                if (activeTab) { activeTab.code = editor.textarea.value; highlightCode(activeTab.code); saveState(); }
            });
            editor.textarea.addEventListener('scroll', () => { if (editor) { editor.pre.scrollTop = editor.textarea.scrollTop; editor.pre.scrollLeft = editor.textarea.scrollLeft; }});
            editor.textarea.addEventListener('keydown', e => {
                if (e.key === 'Tab') {
                    e.preventDefault(); const s = e.target.selectionStart, end = e.target.selectionEnd;
                    e.target.value = e.target.value.substring(0, s) + '  ' + e.target.value.substring(end);
                    e.target.selectionStart = e.target.selectionEnd = s + 2;
                    editor.textarea.dispatchEvent(new Event('input'));
                }
            });
        }

        function initEventListeners() {
            ui.toggleBtn.addEventListener('click', () => ui.container.classList.toggle('hidden'));
            $('#trix-close-btn').addEventListener('click', () => ui.container.classList.add('hidden'));
            initDraggable(ui.container, [$('#trix-header'), $('#trix-footer')]);
            ui.container.addEventListener('click', handleContainerClick);
            $('#trix-settings-btn').addEventListener('click', showSettingsModal);
            const resizeObserver = new ResizeObserver(debounce(saveState, 500));
            resizeObserver.observe(ui.container);
        }

        function handleContainerClick(e) {
            const target = e.target;
            const tabEl = target.closest('.trix-tab');
            if (tabEl && !target.classList.contains('trix-tab-close')) {
                const tabId = tabEl.dataset.tabId === 'logger' ? 'logger' : parseInt(tabEl.dataset.tabId, 10);
                if (tabId !== state.activeTabId) { state.activeTabId = tabId; renderActiveView(); saveState(); }
            }
            if (target.classList.contains('trix-tab-close')) {
                const tabId = parseInt(tabEl.dataset.tabId, 10);
                state.tabs = state.tabs.filter(t => t.id !== tabId);
                if (state.activeTabId === tabId) state.activeTabId = state.tabs[0].id;
                renderActiveView(); saveState();
            }
            if (target.id === 'trix-new-tab-btn') {
                const newId = Date.now(), newName = `Script ${state.tabs.length}`;
                state.tabs.push({ id: newId, name: newName, code: `// ${newName}` });
                state.activeTabId = newId;
                renderActiveView(); saveState();
            }
            if (target.id === 'trix-execute-btn') executeScript();
            if (target.id === 'trix-clear-btn') {
                 const activeTab = state.tabs.find(t => t.id === state.activeTabId);
                 if (activeTab) { activeTab.code = ''; renderEditor(); saveState(); }
            }
        }
        
        function initDraggable(container, handles) {
            let isDragging = false, offsetX, offsetY;
            handles.forEach(handle => {
                handle.addEventListener('mousedown', e => {
                    if (e.target.closest('#trix-header-controls') || e.target.closest('.trix-title-3d') || e.target.closest('#trix-settings-btn')) return;
                    isDragging = true;
                    offsetX = e.clientX - container.offsetLeft;
                    offsetY = e.clientY - container.offsetTop;
                    container.style.right = 'auto';
                    container.style.bottom = 'auto';
                    document.body.style.userSelect = 'none';
                });
            });

            document.addEventListener('mousemove', e => {
                if (isDragging) {
                    let newTop = e.clientY - offsetY;
                    container.style.left = `${e.clientX - offsetX}px`;
                    container.style.top = `${Math.max(0, newTop)}px`;
                }
            });
            document.addEventListener('mouseup', () => {
                if (isDragging) {
                    isDragging = false;
                    document.body.style.userSelect = '';
                    saveState();
                }
            });
        }

        function executeScript() {
            const statusBar = $('.trix-status-bar');
            if (!statusBar) return;
            const activeTab = state.tabs.find(t => t.id === state.activeTabId);
            if (!activeTab || !activeTab.code) { statusBar.textContent = 'Nothing to execute.'; statusBar.className = 'trix-status-bar'; return; }
            try {
                new Function(activeTab.code)();
                statusBar.textContent = `Success: Executed '${activeTab.name}' at ${new Date().toLocaleTimeString()}`;
                statusBar.className = 'trix-status-bar trix-status-success';
            } catch (error) {
                console.error('TriX Executor Error:', error);
                statusBar.textContent = `Error: ${error.message}`;
                statusBar.className = 'trix-status-bar trix-status-error';
            }
        }

        function showSettingsModal() {
            const modal = document.createElement('div');
            modal.id = 'trix-settings-modal';
            modal.innerHTML = `
                <div class="trix-settings-content">
                    <h3>Settings</h3> <label for="trix-theme-select">Theme:</label>
                    <select id="trix-theme-select">
                        <option value="dark-knight">Dark Knight</option> <option value="arctic-light">Arctic Light</option> <option value="crimson">Crimson</option>
                    </select>
                    <button id="trix-settings-close">Close</button>
                </div>`;
            shadowRoot.appendChild(modal);
            $('#trix-theme-select').value = state.settings.theme;
            $('#trix-theme-select').addEventListener('change', e => { state.settings.theme = e.target.value; applySettings(); saveState(); });
            $('#trix-settings-close').addEventListener('click', () => modal.remove());
            modal.addEventListener('click', e => { if (e.target.id === 'trix-settings-modal') modal.remove(); });
        }

        function applySettings() {
            const container = $('#trix-container');
            container.dataset.theme = state.settings.theme;
            Object.assign(container.style, state.settings.position, state.settings.size);
        }

        logPacketCallback = function(type, data) {
            const logContainer = $('#trix-packet-log');
            if (!logContainer) return;
            const item = document.createElement('div');
            item.className = `packet-item packet-${type}`;
            let formattedData = data;
            if (data instanceof ArrayBuffer) formattedData = `[ArrayBuffer, ${data.byteLength} bytes]`;
            else if (data instanceof Blob) formattedData = `[Blob, ${data.size} bytes, type: ${data.type}]`;
            item.innerHTML = `<span class="packet-meta">[${type.toUpperCase()}]</span> ${formattedData}`;
            logContainer.appendChild(item);
            logContainer.scrollTop = logContainer.scrollHeight;
        };

        loadState();
        ui = createUI();
        applySettings();
        renderActiveView();
        initEventListeners();

        let lastFrameTime = performance.now(), frameCount = 0;
        const fpsDisplay = $('#trix-fps-display');
        function updateFPS(now) {
            frameCount++;
            if (now >= lastFrameTime + 1000) {
                if (fpsDisplay) fpsDisplay.textContent = `FPS: ${frameCount}`;
                lastFrameTime = now;
                frameCount = 0;
            }
            requestAnimationFrame(updateFPS);
        }
        requestAnimationFrame(updateFPS);
    }

    function waitForElement(selector, callback) {
        const maxRetries = 40;
        const retryInterval = 250;
        let retryCount = 0;

        const checkInterval = setInterval(() => {
            const element = document.querySelector(selector);
            if (element) {
                console.log(`[TriX] Target element '${selector}' found. Initializing script.`);
                clearInterval(checkInterval);
                callback();
            } else {
                retryCount++;
                console.log(`[TriX] Target element not found. Retry ${retryCount}/${maxRetries}...`);
                if (retryCount >= maxRetries) {
                    clearInterval(checkInterval);
                    console.error(`[TriX] Failed to find target element '${selector}' after ${maxRetries} retries. Aborting initialization.`);
                }
            }
        }, retryInterval);
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', () => waitForElement('#canvasA', initialize));
    } else {
        waitForElement('#canvasA', initialize);
    }

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址