CarManiac's Improved Color Picker

Extends player appearance editor functionality

ของเมื่อวันที่ 23-09-2024 ดู เวอร์ชันล่าสุด

// ==UserScript==
// @name         CarManiac's Improved Color Picker
// @namespace    http://tampermonkey.net/
// @version      v1.0.0
// @description  Extends player appearance editor functionality
// @author       CarManiac
// @run-at       document-idle
// @license      MIT
// @match        https://hitbox.io/game.html
// @match        https://hitbox.io/game2.html
// @icon         https://www.google.com/s2/favicons?sz=64&domain=hitbox.io
// @grant        none
// ==/UserScript==

const originalSend = window.WebSocket.prototype.send;
let WSS = 0;

window.WebSocket.prototype.send = async function(args) {
    if (this.url.includes("/socket.io/?EIO=3&transport=websocket&sid=")) {
        if (typeof(args) == "string") {
            if (!WSS) {
                WSS = this;
            }
        }
    }
    return originalSend.call(this, args);
}

const savedColors = JSON.parse(localStorage.getItem('savedColors')) || [];
let colorPickerContainer;
let deletionMode = false;

function hexToDecimal(hex) {
    if (hex.startsWith("#")) hex = hex.slice(1);
    return parseInt(hex, 16);
}

function createColorInput() {
    if (colorPickerContainer) return;

    colorPickerContainer = document.createElement("div");
    colorPickerContainer.id = "colorPickerContainer";
    colorPickerContainer.style.cssText = "background-color: rgb(37, 38, 42); border-radius: 7px; color: rgb(235, 235, 235); display: flex; flex-direction: column; font-family: 'Bai Jamjuree', sans-serif; position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); padding: 10px; width: 300px;";

    const crossButton = document.createElement("div");
    crossButton.className = "crossButton";
    crossButton.style.cssText = `
        background-color: rgb(74, 122, 177);
        background-image: url(https://hitbox.io/graphics/ui/close.svg);
        background-position: 50% 50%;
        background-repeat: no-repeat;
        border-radius: 20px;
        color: rgb(235, 235, 235);
        cursor: pointer;
        display: block;
        height: 25.9929px;
        position: absolute;
        right: -9px;
        top: -9px;
        width: 25.9929px;
    `;
    crossButton.addEventListener("click", closeBoth);

    const label = document.createElement("label");
    label.textContent = "Select Color";
    label.style.cssText = "color: rgb(235, 235, 235); font-weight: bold; font-size: 15px; margin-bottom: 10px;";

    const colorInput = document.createElement("input");
    colorInput.type = "color";
    colorInput.style.cssText = "margin-top: 5px; width: 100%;";

    const textBox = document.createElement("input");
    textBox.type = "text";
    textBox.style.cssText = "margin-top: 5px; width: 100%; background-color: rgb(100, 100, 100); color: white; border: 1px solid #ccc; border-radius: 5px; padding: 5px;";
    textBox.placeholder = "Hex (#RRGGBB) or rgb(R, G, B)";

    const buttonContainer = document.createElement("div");
    buttonContainer.style.display = "flex";
    buttonContainer.style.justifyContent = "space-between";
    buttonContainer.style.marginTop = "10px";

    const applyButton = createButton("APPLY COLOR", "margin: 5px;");
    const randomButton = createButton("RANDOM COLOR", "margin: 5px;");
    const saveButton = createButton("SAVE COLOR", "margin: 5px;");

    const feedbackMessage = document.createElement("div");
    feedbackMessage.style.cssText = "margin-top: 10px; color: green; font-size: 15px;";

    const savedColorsContainer = document.createElement("div");
    savedColorsContainer.style.cssText = "margin-top: 10px; padding-top: 10px; border-top: 1px solid #ccc; color: rgb(235, 235, 235);";

    const savedColorsTitle = document.createElement("h4");
    savedColorsTitle.textContent = "Saved Colors";
    savedColorsTitle.style.cssText = "margin-bottom: 10px; font-size: 14px;";

    const savedColorsList = document.createElement("div");
    savedColorsList.style.display = "flex";
    savedColorsList.style.flexWrap = "wrap";
    savedColorsList.style.gap = "10px";

    const deleteButton = createButton("DELETE COLORS", "margin-top: 10px; width: 100px;");

    colorPickerContainer.append(crossButton, label, colorInput, textBox, buttonContainer, saveButton, feedbackMessage, savedColorsContainer);
    buttonContainer.append(applyButton, randomButton);
    savedColorsContainer.append(savedColorsTitle, savedColorsList, deleteButton);

    document.body.appendChild(colorPickerContainer);
    displaySavedColors();

    colorInput.addEventListener("input", () => {
        textBox.value = colorInput.value; // Update text box with color input value
        feedbackMessage.textContent = `Color selected: ${colorInput.value}`;
        feedbackMessage.style.color = "green";
    });

    saveButton.addEventListener("click", () => saveColor(textBox.value.trim(), feedbackMessage, savedColorsList));
    applyButton.addEventListener("click", () => applyColor(textBox.value.trim(), feedbackMessage));
    randomButton.addEventListener("click", () => generateRandomColor(textBox, feedbackMessage));
    deleteButton.addEventListener("click", () => toggleDeletionMode());

    function createButton(text, additionalStyles = "") {
        const button = document.createElement("button");
        button.textContent = text;
        button.style.cssText = `padding: 5px; border: none; font-family: 'Bai Jamjuree', sans-serif; border-radius: 2px; cursor: pointer; color: rgb(235, 235, 235); background-color: rgb(74, 122, 177); ${additionalStyles}`;
        return button;
    }

    function displaySavedColors() {
        savedColorsList.innerHTML = '';
        savedColors.forEach(color => {
            const colorBox = document.createElement("div");
            colorBox.style.cssText = `width: 30px; height: 30px; background-color: ${color}; cursor: pointer; border: 1px solid #ccc; border-radius: 3px;`;
            colorBox.addEventListener("click", () => {
                if (deletionMode) {
                    confirmDeletion(color);
                } else {
                    textBox.value = color;
                    colorInput.value = color; // Update color input with the selected color
                    feedbackMessage.textContent = `Color selected: ${color}`;
                    feedbackMessage.style.color = "green";
                }
            });
            savedColorsList.appendChild(colorBox);
        });
    }

    function saveColor(colorValue, feedback, list) {
        if (colorValue === "") {
            feedback.textContent = "Please enter a color!";
            feedback.style.color = "red";
            return;
        }

        if (!savedColors.includes(colorValue)) {
            savedColors.push(colorValue);
            localStorage.setItem('savedColors', JSON.stringify(savedColors));
            displaySavedColors();
            feedback.textContent = `Color saved: ${colorValue}`;
            feedback.style.color = "green";
        } else {
            feedback.textContent = "Color already saved!";
            feedback.style.color = "orange";
        }
    }

    function applyColor(colorValue, feedback) {
        let decimalValue;

        if (/^#([0-9A-Fa-f]{3}|[0-9A-Fa-f]{6})$/.test(colorValue)) {
            decimalValue = hexToDecimal(colorValue);
        } else {
            feedback.textContent = "Please enter a valid color!";
            feedback.style.color = "red";
            return;
        }

        feedback.textContent = `Color applied successfully: ${colorValue}`;
        feedback.style.color = "green";
        localStorage.setItem("basic_col_1", decimalValue);
        if (WSS) {
            WSS.send(`42[1,[40,{"1": ${decimalValue}}]]`);
        }
    }

    function generateRandomColor(input, feedback) {
        const randomColor = "#" + Math.floor(Math.random() * 16777215).toString(16);
        input.value = randomColor;
        colorInput.value = randomColor; // Update color input
        feedback.textContent = `Random color generated: ${randomColor}`;
        feedback.style.color = "green";
    }

    function toggleDeletionMode() {
        if (deletionMode) {
            deletionMode = false;
            deleteButton.style.backgroundColor = "rgb(74, 122, 177)";
            deleteButton.textContent = "DELETE COLORS";
        } else {
            deletionMode = true;
            deleteButton.style.backgroundColor = "red";
            deleteButton.textContent = "CANCEL DELETE";
        }
    }

    function confirmDeletion(color) {
        const index = savedColors.indexOf(color);
        if (index > -1) {
            savedColors.splice(index, 1);
            localStorage.setItem('savedColors', JSON.stringify(savedColors));
            displaySavedColors();
        }
    }
}

const appearancePageObserver = new MutationObserver(() => {
    const appearancePage = document.querySelector('.cosmeticWindow');
    if (appearancePage) {
        createColorInput();
    } else {
        closeBoth();
    }
});

function checkAppearancePage() {
    appearancePageObserver.observe(document.body, { childList: true, subtree: true });
}

function closeColorPicker() {
    if (colorPickerContainer) {
        colorPickerContainer.remove();
        colorPickerContainer = null;
    }
}

function closeBoth() {
    closeColorPicker();
    const cosmeticWindow = document.querySelector('.cosmeticWindow');
    if (cosmeticWindow) {
        cosmeticWindow.remove();
    }
    const blockerContainer = document.querySelector('.blockerContainer');
    if (blockerContainer) {
        blockerContainer.remove();
    }
}

checkAppearancePage();