Sploop.io All Skins Unlocked

Unlocks ALL skins in the game! Select any skins you want!

Install this script?
Author's suggested script

You may also like Dsync Client [Sploop.io].

Install this script
// ==UserScript==
// @name Sploop.io All Skins Unlocked
// @author Murka
// @description Unlocks ALL skins in the game! Select any skins you want!
// @icon https://sploop.io/img/ui/favicon.png
// @version 0.2
// @match *://sploop.io/*
// @run-at document-start
// @grant none
// @noframes
// @license MIT
// @namespace https://greasyfork.org/users/919633
// ==/UserScript==
/* jshint esversion:8 */

/*
    Author: Murka
    Github: https://github.com/Murka007
    Discord: https://discord.gg/sG9cyfGPj5
    Greasyfork: https://greasyfork.org/en/users/919633

    Description:
    - Your not purchased skins will not be shown in the `SKINS` tab
    - You can select any skins you want by using `SHOP` tab
    - It is impossible to make selected skins to show everyone
    - Script can stop working after update, if you will have any issues, report about it in my DISCORD
*/

(function() {
    "use strict";

    const log = console.log;

    function createHook(target, prop, setter) {
        if (!window.hooks) {
            window.hooks = {
                setter: [],
                getter: []
            };
        }
        window.hooks.setter.push(setter);

        const symbol = Symbol(prop);
        Object.defineProperty(target, prop, {
            get() {
                return this[symbol];
            },
            set(value) {
                for (const setter of window.hooks.setter) {
                    setter(this, symbol, value);
                }
            },
            configurable: true
        })
    }

    function inGame() {
        const homepage = document.querySelector("#homepage");
        return homepage && homepage.style.display !== "flex";
    }

    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }

    const storage = {
        get(key) {
            const value = localStorage.getItem(key);
            return value === null ? null : JSON.parse(value);
        },
        set(key, value) {
            localStorage.setItem(key, JSON.stringify(value));
        }
    };

    // it might change in the next update
    // jn - skin
    // jo - accessory
    // jq - back

    const INDEX = {
        SKIN: 16,
        ACCESSORY: 17,
        BACK: 19
    };

    const KEY = {
        SKIN: null,
        ACCESSORY: null,
        BACK: null
    };

    function defineProperty(target, prop, value) {
        Object.defineProperty(target, prop, {
            get() {
                return value;
            },
            set() {
                return true;
            },
            configurable: true,
            writeable: false
        })
    }

    // Dragon skin, Mask accessory and Dragon Wings by Default, why not?
    const settings = (function() {
        function createSettings() {
            const settings = {};
            settings.skin = 27;
            settings.accessory = 30;
            settings.back = 2;
            return settings;
        }

        const defaultSettings = createSettings();
        const settings = Object.assign({}, defaultSettings, storage.get("selectedSkins"));
        for (const key in settings) {
            if (!defaultSettings.hasOwnProperty(key)) {
                delete settings[key];
            }
        }

        storage.set("selectedSkins", settings);
        return settings;
    })();

    const myPlayer = {
        id: null,
        data: null
    };

    window.WebSocket = new Proxy(WebSocket, {
        construct(target, args) {
            const socket = new target(...args);
            socket.addEventListener("message", function(event) {
                try {
                    const data = JSON.parse(event.data);
                    if (data[0] === 35) {
                        myPlayer.id = data[1];
                    }
                } catch(err) {}
            })
            return socket;
        }
    })

    function getDefault() {
        return {
            skin: storage.get("skin") || 0,
            accessory: storage.get("accessory") || 0,
            back: storage.get("back") || 0
        };
    }

    createHook(Object.prototype, "i", async function(that, symbol, value) {
        that[symbol] = value;
        if (myPlayer.id === value) {
            myPlayer.data = that;
            await sleep(0);

            const skinData = storage.get("selectedSkins");
            const Default = getDefault();

            const keys = Object.keys(that);
            if (!KEY.SKIN) KEY.SKIN = keys[INDEX.SKIN];
            if (!KEY.ACCESSORY) KEY.ACCESSORY = keys[INDEX.ACCESSORY];
            if (!KEY.BACK) KEY.BACK = keys[INDEX.BACK];

            const current = {
                skin: that[KEY.SKIN] || 0,
                accessory: that[KEY.ACCESSORY] || 0,
                back: that[KEY.BACK] || 0
            };

            // Skin will not change if you are not logged into your account
            // And also you can't even select any skins without account, except default one
            defineProperty(that, KEY.SKIN, skinData.skin || Default.skin);
            defineProperty(that, KEY.ACCESSORY, skinData.accessory || Default.accessory);
            defineProperty(that, KEY.BACK, skinData.back || Default.back);
        }
    });

    // We need to reset our skins on death/change server
    function resetSkins() {
        if (myPlayer.data === null) return;
        const { skin, accessory, back } = getDefault();
        defineProperty(myPlayer.data, KEY.SKIN, skin);
        defineProperty(myPlayer.data, KEY.ACCESSORY, accessory);
        defineProperty(myPlayer.data, KEY.BACK, back);
    }

    window.addEventListener("load", function() {

        const changeServer = document.querySelector("#change-server");
        const mainContent = document.querySelector("#main-content");
        const homepage = document.querySelector("#homepage");

        // Attach click event handler to make users select their skins
        new MutationObserver(mutations => {
            for (const mutation of mutations) {
                for (const node of mutation.addedNodes) {
                    try {
                        if (node.classList.contains("skins-line")) {
                            for (const button of node.children) {
                                button.addEventListener("click", function() {
                                    const [ match, type, id ] = button.src.match(/(skin|accessory|back)(\d+)/);
                                    settings[type] = Number(id);
                                    storage.set("selectedSkins", settings);
                                })
                            }
                        }
                    } catch(err){}
                }
            }
        }).observe(mainContent, { childList: true, subtree: true });

        // Reset myPlayer if user has changed server
        changeServer.addEventListener("click", resetSkins);

        // Also reset if player died
        new MutationObserver(mutations => {
            for (const mutation of mutations) {
                if (mutation.target.style.display === "flex") {
                    resetSkins();
                }
            }
        }).observe(homepage, { attributes: true, attributeFilter: ["style"] });
    })

})();