TriX Executor

A Comprehensive Script Executor for Territorial.io with a modern, Roblox-style UI and smart-loading capabilities.

当前为 2025-07-02 提交的版本,查看 最新版本

// ==UserScript==
// @name         TriX Executor
// @namespace    https://github.com/YourUsername/TriX-Executor
// @version      1.2.3
// @description  A Comprehensive Script Executor for Territorial.io with a modern, Roblox-style UI and smart-loading capabilities.
// @author       You
// @match        *://territorial.io/*
// @match        *://www.territorial.io/*
// @icon         https://i.postimg.cc/0NkRZxDm/image.png
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_listValues
// @grant        GM_deleteValue
// @grant        GM_addValueChangeListener
// @grant        GM.xmlHttpRequest
// @run-at       document-start
// @license      MIT
// ==/UserScript==

/*
 *   _____  ____  _   __  ___________
 *  |_   _||_  _|| | / / |  _  | ___ \
 *    | |    | | | |/ /  | |/' | |_/ /
 *    | |    | | |    \  |  /| |  __/
 *   _| |_  _| |_| |\  \ \ |_/ / |
 *   \___/  \___/\_| \_/  \___/\_|
 *
 *   TriX Executor - v1.2.3 (Drag & Minimize Hotfix)
 *   Logo: https://i.postimg.cc/0NkRZxDm/image.png
 *
 *   Changelog:
 *   - Refactored dragging logic to be more robust against event capture by the game canvas.
 *   - Fixed minimize bug by overriding min-height, allowing the container to shrink correctly.
 */

(function() {
    'use strict';
    console.log('[TriX Executor] Script injected. Waiting for game UI to load...');

    // --- Configuration & Constants ---
    const SCRIPT_PREFIX = 'trix_script_';
    const BROADCAST_CHANNEL = 'trix_broadcast_channel';
    const TAB_ID = `tab_${Date.now().toString(36)}_${Math.random().toString(36).substring(2)}`;
    const GAME_READY_SELECTOR = '#input0';

    // --- UI Module ---
    const UI = {
        isMinimized: false,
        currentScriptName: '',

        init() {
            this.injectCSS();
            this.injectHTML();
            this.attachEventListeners();
            ScriptManager.populateScriptList();
            this.log('TriX Executor v1.2.3 initialized.');
        },

        injectCSS() {
            GM_addStyle(`
                :root {
                    --trix-bg-primary: #1e1e1e;
                    --trix-bg-secondary: #2d2d2d;
                    --trix-bg-tertiary: #3c3c3c;
                    --trix-accent-color: #00aeff;
                    --trix-text-primary: #d4d4d4;
                    --trix-text-secondary: #8c8c8c;
                    --trix-border-color: #4a4a4a;
                }

                #trix-container, #trix-open-btn {
                    font-family: 'Segoe UI', 'Roboto', sans-serif !important;
                }

                #trix-container {
                    position: fixed !important;
                    top: 50px !important;
                    left: 50px !important;
                    width: 600px;
                    height: 400px;
                    background-color: var(--trix-bg-primary);
                    border: 1px solid var(--trix-border-color);
                    box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
                    z-index: 1000000 !important;
                    display: flex !important;
                    flex-direction: column;
                    resize: both;
                    overflow: hidden;
                    min-width: 450px;
                    min-height: 300px;
                }
                #trix-container.hidden {
                    display: none !important;
                }
                /* --- FIX FOR MINIMIZE BUG --- */
                #trix-container.minimized {
                    height: auto !important;
                    min-height: 0 !important; /* Override the base min-height */
                    resize: none !important;
                }
                #trix-container.minimized #trix-body,
                #trix-container.minimized #trix-footer,
                #trix-container.minimized #trix-console {
                    display: none !important;
                }

                #trix-open-btn {
                    position: fixed !important; top: 20px !important; right: 20px !important;
                    z-index: 999999 !important; display: block !important;
                    background-color: var(--trix-accent-color) !important;
                    color: white !important;
                    border: none !important;
                    border-radius: 5px;
                    padding: 10px 15px !important;
                    cursor: pointer !important;
                    box-shadow: 0 0 10px rgba(0, 174, 255, 0.7);
                    font-weight: bold !important;
                    font-size: 14px !important;
                }
                /* (Rest of CSS is identical) */
                #trix-header{background-color:var(--trix-bg-secondary);padding:5px 10px;cursor:move;user-select:none;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--trix-border-color)}#trix-header-title{display:flex;align-items:center;font-weight:700;color:var(--trix-text-primary)}#trix-logo{width:24px;height:24px;margin-right:8px}#trix-window-controls button{background:0 0;border:none;color:var(--trix-text-secondary);font-size:18px;cursor:pointer;margin-left:8px;padding:0 4px;line-height:1}#trix-window-controls button:hover{color:var(--trix-accent-color)}#trix-close-btn:hover{color:#ff5555}#trix-body{flex-grow:1;display:flex;overflow:hidden}#trix-left-panel{width:150px;background-color:var(--trix-bg-secondary);padding:10px 0;display:flex;flex-direction:column;border-right:1px solid var(--trix-border-color)}#trix-script-list-title{padding:0 10px 10px;font-weight:700;color:var(--trix-text-primary);border-bottom:1px solid var(--trix-border-color)}#trix-script-list{flex-grow:1;overflow-y:auto;margin-top:10px}.trix-script-item{padding:8px 10px;cursor:pointer;color:var(--trix-text-secondary);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.trix-script-item:hover{background-color:var(--trix-bg-tertiary);color:var(--trix-text-primary)}.trix-script-item.active{background-color:var(--trix-accent-color);color:var(--trix-bg-primary)!important;font-weight:700}#trix-right-panel{flex-grow:1;display:flex;flex-direction:column}#trix-editor{flex-grow:1;background-color:var(--trix-bg-primary);color:var(--trix-text-primary);border:none;padding:10px;box-sizing:border-box;resize:none;font-family:'Consolas','Monaco',monospace;font-size:14px}#trix-console{height:120px;background-color:var(--trix-bg-secondary);border-top:1px solid var(--trix-border-color);padding:5px;overflow-y:auto;font-size:12px;font-family:'Consolas','Monaco',monospace}#trix-console div{padding:2px 4px;border-bottom:1px solid #333;word-break:break-all}#trix-console .log-error{color:#ff5555}#trix-console .log-warn{color:#e5c07b}#trix-console .log-info{color:#00aeff}#trix-console .log-broadcast{color:#98c379;font-style:italic}#trix-footer{display:flex;gap:10px;padding:10px;background-color:var(--trix-bg-secondary);border-top:1px solid var(--trix-border-color);align-items:center}.trix-button{background-color:var(--trix-bg-tertiary);border:1px solid var(--trix-border-color);color:var(--trix-text-primary);padding:8px 15px;cursor:pointer;transition:background-color .2s}.trix-button:hover{background-color:#555}.trix-button.primary{background-color:var(--trix-accent-color);color:var(--trix-bg-primary);font-weight:700}.trix-button.primary:hover{background-color:#00bfff}.trix-button.danger{background-color:#c0392b}.trix-button.danger:hover{background-color:#e74c3c}
            `);
        },

        injectHTML() { const html = `<div id="trix-container" class="hidden"><div id="trix-header"><div id="trix-header-title"><img id="trix-logo" src="https://i.postimg.cc/0NkRZxDm/image.png" alt="TriX Logo"> <span>TriX Executor</span></div><div id="trix-window-controls"><button id="trix-minimize-btn" title="Minimize">-</button> <button id="trix-close-btn" title="Close">✕</button></div></div><div id="trix-body"><div id="trix-left-panel"><div id="trix-script-list-title">Script List</div><div id="trix-script-list"></div></div><div id="trix-right-panel"><textarea id="trix-editor" placeholder="-- Paste or load a script here..."></textarea><div id="trix-console"></div></div></div><div id="trix-footer"><button id="trix-execute-btn" class="trix-button primary">▶ Execute</button> <button id="trix-clear-btn" class="trix-button">Clear</button> <input type="text" id="trix-save-name" placeholder="Script Name..." class="trix-button" style="flex-grow:1; cursor:text;"> <button id="trix-save-btn" class="trix-button">Save</button> <button id="trix-delete-btn" class="trix-button danger">Delete</button></div></div><button id="trix-open-btn">Open TriX</button>`; document.body.insertAdjacentHTML('beforeend', html); },

        // --- FIX FOR DRAGGING BUG ---
        attachEventListeners() {
            const container = document.getElementById('trix-container');
            const header = document.getElementById('trix-header');

            // Refactored Dragging Logic
            header.addEventListener('mousedown', (e) => {
                if (e.target.closest('#trix-window-controls')) return;

                let isDragging = true;
                const dragOffsetX = e.clientX - container.offsetLeft;
                const dragOffsetY = e.clientY - container.offsetTop;

                const onMouseMove = (moveEvent) => {
                    if (!isDragging) return;
                    // Prevent text selection while dragging
                    moveEvent.preventDefault();
                    container.style.left = `${moveEvent.clientX - dragOffsetX}px`;
                    container.style.top = `${moveEvent.clientY - dragOffsetY}px`;
                };

                const onMouseUp = () => {
                    isDragging = false;
                    document.removeEventListener('mousemove', onMouseMove);
                    document.removeEventListener('mouseup', onMouseUp);
                };

                document.addEventListener('mousemove', onMouseMove);
                document.addEventListener('mouseup', onMouseUp);
            });

            // --- Window Management ---
            document.getElementById('trix-open-btn').addEventListener('click', () => this.togglePanel(true));
            document.getElementById('trix-close-btn').addEventListener('click', () => this.togglePanel(false));
            document.getElementById('trix-minimize-btn').addEventListener('click', () => {
                this.isMinimized = !this.isMinimized;
                container.classList.toggle('minimized', this.isMinimized);
            });

            // --- Script List & Footer Buttons (unchanged) ---
            document.getElementById('trix-script-list').addEventListener('click', (e) => { if (e.target.matches('.trix-script-item')) { const scriptKey = e.target.dataset.scriptKey; ScriptManager.loadScriptToEditor(scriptKey); } });
            document.getElementById('trix-execute-btn').addEventListener('click', () => Executor.execute(document.getElementById('trix-editor').value));
            document.getElementById('trix-clear-btn').addEventListener('click', () => { document.getElementById('trix-editor').value = ''; document.getElementById('trix-save-name').value = ''; this.setActiveScriptItem(null); this.currentScriptName = ''; });
            document.getElementById('trix-save-btn').addEventListener('click', ScriptManager.saveScriptFromEditor);
            document.getElementById('trix-delete-btn').addEventListener('click', ScriptManager.deleteCurrentScript);
        },
        togglePanel(forceShow) { const container = document.getElementById('trix-container'); const openBtn = document.getElementById('trix-open-btn'); const isHidden = container.classList.contains('hidden'); if (forceShow === true || isHidden) { container.classList.remove('hidden'); openBtn.style.display = 'none'; } else { container.classList.add('hidden'); openBtn.style.display = 'block'; } },
        log(message, type = 'log') { const consoleEl = document.getElementById('trix-console'); if (!consoleEl) return; const entry = document.createElement('div'); entry.className = `log-${type}`; entry.textContent = `> ${String(message)}`; consoleEl.prepend(entry); },
        setActiveScriptItem(key) { document.querySelectorAll('.trix-script-item').forEach(item => { item.classList.toggle('active', item.dataset.scriptKey === key); }); }
    };
    const ScriptManager={async saveScriptFromEditor(){const e=document.getElementById("trix-save-name").value.trim(),t=document.getElementById("trix-editor").value;e?t?(await GM_setValue(SCRIPT_PREFIX+e,t),UI.log(`Script '${e}' saved.`,"info"),this.populateScriptList(SCRIPT_PREFIX+e)):UI.log("Cannot save: Editor is empty.","warn"):UI.log("Cannot save: Name is required.","error")},async loadScriptToEditor(e){if(!e)return UI.log("Invalid script key.","error");const t=await GM_getValue(e,""),s=e.replace(SCRIPT_PREFIX,"");document.getElementById("trix-editor").value=t,document.getElementById("trix-save-name").value=s,UI.log(`Loaded script: ${s}`,"info"),UI.currentScriptName=s,UI.setActiveScriptItem(e)},async deleteCurrentScript(){const e=UI.currentScriptName;e&&confirm(`Are you sure you want to delete '${e}'?`)&&(await GM_deleteValue(SCRIPT_PREFIX+e),UI.log(`Script '${e}' deleted.`,"info"),document.getElementById("trix-editor").value="",document.getElementById("trix-save-name").value="",UI.currentScriptName="",this.populateScriptList())},async populateScriptList(e=null){const t=document.getElementById("trix-script-list");t.innerHTML="";const s=(await GM_listValues()).filter(e=>e.startsWith(SCRIPT_PREFIX));s.sort().forEach(e=>{const s=document.createElement("div");s.className="trix-script-item",s.textContent=e.replace(SCRIPT_PREFIX,""),s.dataset.scriptKey=e,t.appendChild(s)}),UI.setActiveScriptItem(e||UI.currentScriptName?SCRIPT_PREFIX+UI.currentScriptName:null)}};
    const Executor={execute(e){if(!e.trim())return void UI.log("Execution skipped: script is empty.","warn");UI.log("Executing script...","info");try{const t=this.createAPI(),s=new Function("TriX",e);s(t)}catch(e){UI.log(`Execution Error: ${e.message}`,"error"),console.error("TriX Executor Error:",e)}},createAPI:()=>({log:(e,t="log")=>{const s="object"==typeof e?JSON.stringify(e):String(e);UI.log(s,t)},broadcast:e=>{MultiTab.broadcast(e)},query:(e,t="text")=>{const s=document.querySelector(e);return s?"html"===t?s.innerHTML:"value"===t?s.value:"element"===t?s:s.textContent:null},queryAll:(e,t="text")=>{const s=document.querySelectorAll(e);return Array.from(s).map(e=>"html"===t?e.innerHTML:"value"===t?e.value:"element"===t?e:e.textContent)}})};
    const MultiTab={init(){GM_addValueChangeListener(BROADCAST_CHANNEL,this.listener)},listener(e,t,s,o){o&&s.senderId!==TAB_ID&&UI.log(`Received broadcast: ${JSON.stringify(s.payload)}`,"broadcast")},broadcast(e){const t={senderId:TAB_ID,timestamp:Date.now(),payload:e};GM_setValue(BROADCAST_CHANNEL,t),UI.log(`Broadcast sent: ${JSON.stringify(e)}`,"broadcast")}};
    function waitForElement(selector, callback) { if (document.querySelector(selector)) { callback(); return; } const observer = new MutationObserver((mutations, obs) => { if (document.querySelector(selector)) { obs.disconnect(); callback(); } }); observer.observe(document.documentElement, { childList: true, subtree: true }); }
    function main() { console.log(`[TriX Executor] Game element '${GAME_READY_SELECTOR}' found! Initializing UI.`); UI.init(); MultiTab.init(); UI.togglePanel(false); }
    waitForElement(GAME_READY_SELECTOR, main);

})();

QingJ © 2025

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