The West - Custom World Order (Lightning Fast + UI Input)

Arrange worlds in custom order within "Lumile tale" section + add editable input in corner

// ==UserScript==
// @name         The West - Custom World Order (Lightning Fast + UI Input)
// @namespace    https://www.the-west.ro/
// @author honeydew (Texas)
// @version      3.1
// @description  Arrange worlds in custom order within "Lumile tale" section + add editable input in corner
// @match        https://www.the-west.ro/*
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    // 🎯 Load from localStorage or default to empty
    let PREFERRED_ORDER = JSON.parse(localStorage.getItem("preferredWorldOrder") || "[]");

    const ALL_WORLDS_ID = "allWorlds";
    const LUMILE_TALE_TEXT = "Lumile tale";

    let isProcessing = false;

    function getWorldNumber(worldElement) {
        const match = worldElement.id?.match(/world_(\d+)/);
        return match ? parseInt(match[1], 10) : null;
    }

    function arrangeWorldsInOrder() {
        if (isProcessing) return false;
        isProcessing = true;

        try {
            const allWorlds = document.getElementById(ALL_WORLDS_ID);
            if (!allWorlds || allWorlds.offsetParent === null) return false;

            const lumileTaleRow = Array.from(allWorlds.querySelectorAll(".worlds-row"))
                .find(row => row.querySelector("h2")?.textContent?.includes(LUMILE_TALE_TEXT));

            if (!lumileTaleRow) return false;

            const content = lumileTaleRow.querySelector(".row-content");
            if (!content) return false;

            const worldElements = Array.from(content.querySelectorAll('[id^="world_"]'));
            if (worldElements.length === 0) return false;

            const orderedWorlds = [];
            const remainingWorlds = [];
            const worldMap = new Map();

            worldElements.forEach(element => {
                const worldNum = getWorldNumber(element);
                if (worldNum !== null) {
                    worldMap.set(worldNum, element);
                }
            });

            PREFERRED_ORDER.forEach(worldNum => {
                if (worldMap.has(worldNum)) {
                    orderedWorlds.push(worldMap.get(worldNum));
                    worldMap.delete(worldNum);
                }
            });

            worldElements.forEach(element => {
                const worldNum = getWorldNumber(element);
                if (worldNum !== null && worldMap.has(worldNum)) {
                    remainingWorlds.push(element);
                }
            });

            const newOrder = [...orderedWorlds, ...remainingWorlds];
            const currentOrder = Array.from(content.children).filter(child =>
                child.id && child.id.startsWith('world_')
            );

            let needsReordering = false;
            if (newOrder.length === currentOrder.length) {
                for (let i = 0; i < newOrder.length; i++) {
                    if (newOrder[i] !== currentOrder[i]) {
                        needsReordering = true;
                        break;
                    }
                }
            } else {
                needsReordering = true;
            }

            if (needsReordering) {
                const referenceElement = Array.from(content.children)
                    .find(child => !child.id || !child.id.startsWith('world_'));

                newOrder.forEach((worldElement, index) => {
                    if (index === 0) {
                        content.insertBefore(worldElement, referenceElement || content.firstChild);
                    } else {
                        const previousWorld = newOrder[index - 1];
                        content.insertBefore(worldElement, previousWorld.nextSibling);
                    }
                });

                const orderedNumbers = orderedWorlds.map(el => getWorldNumber(el)).filter(n => n !== null);
                const remainingNumbers = remainingWorlds.map(el => getWorldNumber(el)).filter(n => n !== null);

                console.log(`[⚡] Worlds reordered! Priority: [${orderedNumbers.join(', ')}], Others: [${remainingNumbers.join(', ')}]`);
                return true;
            }

            return false;
        } finally {
            isProcessing = false;
        }
    }

    function instantArrangeWorlds() {
        requestAnimationFrame(() => {
            arrangeWorldsInOrder();
        });
    }

    const observer = new MutationObserver((mutations) => {
        let shouldCheck = false;

        for (const mutation of mutations) {
            if (mutation.type === 'childList') {
                for (const node of mutation.addedNodes) {
                    if (node.nodeType === 1) {
                        if (node.id === ALL_WORLDS_ID ||
                            node.querySelector?.(`#${ALL_WORLDS_ID}`) ||
                            node.id?.startsWith('world_') ||
                            node.querySelector?.('[id^="world_"]') ||
                            node.classList?.contains('worlds-row') ||
                            node.classList?.contains('row-content')) {
                            shouldCheck = true;
                            break;
                        }
                    }
                }
            } else if (mutation.type === 'attributes') {
                const target = mutation.target;
                if (target.id === ALL_WORLDS_ID ||
                    target.querySelector?.(`#${ALL_WORLDS_ID}`) ||
                    (mutation.attributeName === 'style' && target.style?.display !== 'none')) {
                    shouldCheck = true;
                }
            }

            if (shouldCheck) break;
        }

        if (shouldCheck) {
            instantArrangeWorlds();
        }
    });

    observer.observe(document.body, {
        childList: true,
        subtree: true,
        attributes: true,
        attributeFilter: ['style', 'class']
    });

    const events = ['click', 'keydown', 'focus', 'mousedown'];
    events.forEach(eventType => {
        document.addEventListener(eventType, (e) => {
            const target = e.target;
            if (target.closest?.('.menulink') ||
                target.closest?.('[data-menu]') ||
                target.closest?.('.ui-dialog') ||
                target.id?.includes('world') ||
                target.className?.includes('world')) {
                setTimeout(instantArrangeWorlds, 50);
                setTimeout(instantArrangeWorlds, 150);
            }
        }, true);
    });

    let checkCount = 0;
    const periodicCheck = () => {
        checkCount++;
        const allWorlds = document.getElementById(ALL_WORLDS_ID);
        if (allWorlds && allWorlds.offsetParent !== null) {
            const content = allWorlds.querySelector('.worlds-row h2')?.textContent?.includes(LUMILE_TALE_TEXT)
                ? allWorlds.querySelector('.worlds-row .row-content')
                : null;

            if (content) {
                const firstWorldElement = content.querySelector('[id^="world_"]');
                if (firstWorldElement) {
                    const firstWorldNum = getWorldNumber(firstWorldElement);
                    if (PREFERRED_ORDER.length > 0 &&
                        (!PREFERRED_ORDER.includes(firstWorldNum) || firstWorldNum !== PREFERRED_ORDER[0])) {
                        const hasPriorityWorlds = PREFERRED_ORDER.some(num =>
                            content.querySelector(`#world_${num}`)
                        );
                        if (hasPriorityWorlds) {
                            instantArrangeWorlds();
                        }
                    }
                }
            }
        }

        const delay = Math.min(100 + (checkCount * 10), 500);
        setTimeout(periodicCheck, delay);
    };

    function createCornerInputUI() {
        const wrapper = document.createElement('div');
        wrapper.style.position = 'fixed';
        wrapper.style.top = '10px';
        wrapper.style.right = '10px';
        wrapper.style.background = 'rgba(0,0,0,0.75)';
        wrapper.style.padding = '8px';
        wrapper.style.borderRadius = '6px';
        wrapper.style.zIndex = '9999';
        wrapper.style.fontSize = '12px';
        wrapper.style.color = 'white';
        wrapper.style.fontFamily = 'monospace';

        const label = document.createElement('label');
        label.textContent = 'World order:';
        label.style.marginRight = '4px';

        const input = document.createElement('input');
        input.type = 'text';
        input.value = PREFERRED_ORDER.join(', ');
        input.style.width = '160px';
        input.style.marginRight = '4px';
        input.style.borderRadius = '4px';
        input.style.border = 'none';
        input.style.padding = '2px 4px';

        const button = document.createElement('button');
        button.textContent = 'Save';
        button.style.cursor = 'pointer';
        button.style.border = 'none';
        button.style.padding = '2px 6px';
        button.style.borderRadius = '4px';
        button.style.background = '#4CAF50';
        button.style.color = 'white';

        button.onclick = () => {
            const newValue = input.value.trim();
            updatePreferredOrder(newValue);
            localStorage.setItem("preferredWorldOrder", JSON.stringify(PREFERRED_ORDER));
            instantArrangeWorlds();
        };

        wrapper.appendChild(label);
        wrapper.appendChild(input);
        wrapper.appendChild(button);
        document.body.appendChild(wrapper);
    }

    function updatePreferredOrder(input) {
        const list = input.split(',')
            .map(str => parseInt(str.trim(), 10))
            .filter(num => !isNaN(num));

        if (list.length > 0) {
            PREFERRED_ORDER = list;
            console.log(`[⚙️] Updated preferred world order: [${PREFERRED_ORDER.join(', ')}]`);
        } else {
            console.warn('[⚠️] Invalid input. Could not update world order.');
        }
    }

    function initialize() {
        console.log(`[⚡] Custom World Order script loaded! Priority order: [${PREFERRED_ORDER.join(', ')}]`);
        setTimeout(instantArrangeWorlds, 100);
        setTimeout(periodicCheck, 200);
        createCornerInputUI();

        let lastUrl = location.href;
        setInterval(() => {
            if (location.href !== lastUrl) {
                lastUrl = location.href;
                setTimeout(instantArrangeWorlds, 300);
            }
        }, 1000);
    }

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

    setTimeout(initialize, 50);
})();

QingJ © 2025

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