FaustCore

Adds support for Faust mods

Du musst eine Erweiterung wie Tampermonkey, Greasemonkey oder Violentmonkey installieren, um dieses Skript zu installieren.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

Sie müssten eine Skript Manager Erweiterung installieren damit sie dieses Skript installieren können

(Ich habe schon ein Skript Manager, Lass mich es installieren!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         FaustCore
// @version      2025-02-21
// @description  Adds support for Faust mods
// @author       Faust
// @match        https://esonline.su/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=tampermonkey.net
// @grant        none
// @namespace https://greasyfork.org/users/1437749
// ==/UserScript==

(function() {
"use strict";
var MessageReason;
(function (MessageReason) {
    MessageReason.user_join = "userJoin";
    MessageReason.user_leave = "userLeave";
    MessageReason.node_data = "nodeData";
    MessageReason.time_update = "serverTimecode";
    MessageReason.client_move = "clientMove";
})(MessageReason || (MessageReason = {}));
function getScreenResolution() {
    const resolutions = [
        [1920, 1080],
        [1792, 1008],
        [1664, 936],
        [1536, 864],
        [1408, 792],
        [1280, 720],
        [1152, 648],
        [1024, 576],
        [896, 504],
        [768, 432],
        [640, 360],
        [512, 288],
        [384, 216],
    ];
    const screen_width = window.innerWidth;
    const screen_height = window.innerHeight;
    let selected_resolution;
    for (let index in resolutions) {
        let resolution = resolutions[index];
        if (resolution[0] <= screen_width && resolution[1] <= screen_height) {
            selected_resolution = resolution;
            break;
        }
    }
    if (!selected_resolution) {
        console.error("screen too small " + screen_width + "x" + screen_height);
        selected_resolution = resolutions[resolutions.length - 1];
    }
    return selected_resolution;
}
function display_notification(text) {
    const elements = document.querySelectorAll("#notify");
    if (elements.length > 0 && elements[0].parentElement) {
        elements[0].parentElement.removeChild(elements[0]);
    }
    const text_bubble = document.createElement("div");
    text_bubble.id = "notify";
    text_bubble.innerHTML = text;
    text_bubble.style.animationName = "hide";
    text_bubble.style.animationDelay = "2s";
    text_bubble.style.animationDuration = "0.5s";
    text_bubble.style.animationFillMode = "forwards";
    text_bubble.style.zIndex = "9999";
    document.body.appendChild(text_bubble);
    text_bubble.addEventListener("animationend", () => {
        text_bubble.remove();
    });
}
class AbstractMenuItem {
    constructor() {
        this.is_added = false;
        this.is_hidden = false;
        this.main_div = document.createElement("div");
    }
    addElement() {
        if (this.is_added) {
            return;
        }
        this.main_div = this.composeMainDiv();
        document.body.appendChild(this.main_div);
        this.is_added = true;
    }
    removeElement() {
        if (!this.is_added) {
            return;
        }
        this.main_div.remove();
        this.is_added = false;
    }
    hideElement() {
        if (!this.is_added) {
            return;
        }
        this.main_div.style.display = "none";
        this.is_hidden = true;
    }
    unhideElement() {
        if (!this.is_added) {
            return;
        }
        this.main_div.style.display = "block";
        this.is_hidden = false;
    }
    isShown() {
        return this.is_added;
    }
    isHidden() {
        return this.is_hidden;
    }
}
class MenuButtonsFactory {
    static buildButton(text, on_click) {
        const button = document.createElement("button");
        button.style.borderRadius = "10px";
        button.style.border = "2px solid rgba(3, 55, 170, 0.8)";
        button.style.backgroundColor = "rgba(3, 55, 170, 0.8)";
        button.style.color = "white";
        button.style.padding = "5px 10px";
        button.style.fontSize = "14px";
        button.innerText = text;
        button.addEventListener("mouseenter", () => {
            button.style.backgroundColor = "white";
            button.style.color = "rgba(3, 55, 170, 0.8)";
        });
        button.addEventListener("mouseleave", () => {
            button.style.backgroundColor = "rgba(3, 55, 170, 0.8)";
            button.style.color = "white";
        });
        button.addEventListener("mousedown", on_click);
        return button;
    }
}
class TweakMenu extends AbstractMenuItem {
    constructor() {
        super();
    }
    getScrollableArea(screen_height) {
        const scrollableDiv = document.createElement("div");
        scrollableDiv.style.height = (screen_height / 3).toString() + "px";
        scrollableDiv.style.overflow = "auto";
        scrollableDiv.style.border = "1px solid #ccc";
        scrollableDiv.style.padding = "10px";
        scrollableDiv.style.backgroundColor = "rgba(0, 0, 0, 0.1)";
        scrollableDiv.style.borderRadius = "10px";
        scrollableDiv.style.marginBottom = "20px";
        return scrollableDiv;
    }
    getTweakNameColor(tweak) {
        if (tweak.isEnabled()) {
            return "green";
        }
        return "white";
    }
    buildDivUponTweak() {
        const result = [];
        for (let iter = 0; iter < loaded_tweaks.length; iter++) {
            const entry = document.createElement("div");
            entry.style.display = "flex";
            entry.style.flexDirection = "row";
            entry.style.alignItems = "center";
            entry.style.justifyContent = "flex-start";
            entry.style.borderRadius = "6px";
            entry.style.border = "2px solid rgba(230, 224, 203, 0.6)";
            const checkbox = document.createElement("input");
            checkbox.type = "checkbox";
            checkbox.id = loaded_tweaks[iter].getTweakName();
            checkbox.style.marginLeft = "10px";
            checkbox.style.marginRight = "10px";
            checkbox.checked = loaded_tweaks[iter].isEnabled();
            checkbox.addEventListener("change", (event) => {
                const target = event.target;
                target.checked ? loaded_tweaks[iter].enable() : loaded_tweaks[iter].disable();
            });
            const label = document.createElement("label");
            label.htmlFor = checkbox.id;
            label.innerText = checkbox.id;
            label.style.fontSize = "21px";
            label.style.color = this.getTweakNameColor(loaded_tweaks[iter]);
            entry.appendChild(checkbox);
            entry.appendChild(label);
            result.push(entry);
        }
        return result;
    }
    composeMainDiv() {
        const result = document.createElement("div");
        // resizing
        const resolution = getScreenResolution();
        result.style.position = "fixed";
        result.style.width = (resolution[0] / 2.5).toString() + "px";
        result.style.height = "fit-content";
        // Centering block
        result.style.top = "50%";
        result.style.left = "50%";
        result.style.transform = "translate(-50%, -50%)";
        // Cosmetics
        result.style.padding = "20px";
        result.style.backgroundColor = "rgba(0, 0, 0, 0.75)"; // transparent black
        result.style.borderRadius = "10px";
        result.style.textAlign = "center";
        result.style.backdropFilter = "blur(5px)";
        result.style.zIndex = "9999";
        const window_name = document.createElement("h2");
        window_name.style.color = "white";
        window_name.style.marginBottom = "20px";
        window_name.innerText = "Меню твиков";
        // TODO: add macros for resolution results (or even better, return a struct)
        const scroll_area = this.getScrollableArea(resolution[1]);
        const div_tweaks = this.buildDivUponTweak();
        for (let iter = 0; iter < div_tweaks.length; iter++) {
            scroll_area.appendChild(div_tweaks[iter]);
        }
        result.appendChild(window_name);
        result.appendChild(scroll_area);
        result.appendChild(MenuButtonsFactory.buildButton("Close", () => this.removeElement()));
        return result;
    }
}
class GratitudeMenu extends AbstractMenuItem {
    constructor() {
        super();
    }
    getScrollableArea(screen_height) {
        const scrollableDiv = document.createElement("div");
        scrollableDiv.style.height = (screen_height / 4).toString() + "px";
        scrollableDiv.style.overflow = "auto";
        scrollableDiv.style.border = "1px solid #ccc";
        scrollableDiv.style.padding = "10px";
        scrollableDiv.style.backgroundColor = "rgba(0, 0, 0, 0.1)";
        scrollableDiv.style.borderRadius = "10px";
        scrollableDiv.style.marginBottom = "20px";
        return scrollableDiv;
    }
    composeMainDiv() {
        const result = document.createElement("div");
        // resizing
        const resolution = getScreenResolution();
        result.style.position = "fixed";
        result.style.width = (resolution[0] / 3).toString() + "px";
        result.style.height = "fit-content";
        // Centering block
        result.style.top = "50%";
        result.style.left = "50%";
        result.style.transform = "translate(-50%, -50%)";
        // Cosmetics
        result.style.padding = "20px";
        result.style.backgroundColor = "rgba(0, 0, 0, 0.75)"; // transparent black
        result.style.borderRadius = "10px";
        result.style.textAlign = "center";
        result.style.backdropFilter = "blur(5px)";
        result.style.zIndex = "9999";
        const window_name = document.createElement("h2");
        window_name.style.color = "white";
        window_name.style.marginBottom = "20px";
        window_name.innerText = "Благодарности";
        const scroll_area = this.getScrollableArea(resolution[1]);
        const gratitude_block = document.createElement("div");
        gratitude_block.style.color = "white";
        gratitude_block.style.fontSize = "16px";
        gratitude_block.innerText =
            "Спасибо тебе, игрок, за то что даёшь проекту шанс на жизнь.\nТак же спасибо ребятами ждущим альфа-тест сюжетного твика. Ваша поддержка заставляла проект жить.\n\n Спасибо, TRIOLA.\nСпасибо, makter.";
        result.appendChild(window_name);
        result.appendChild(scroll_area);
        scroll_area.appendChild(gratitude_block);
        result.appendChild(MenuButtonsFactory.buildButton("Close", () => this.removeElement()));
        return result;
    }
}
/// <reference path="./menu_interface.ts" />
/// <reference path="../menu_button_factory.ts" />
/// <reference path="./tweaks_menu.ts" />
/// <reference path="./gratitude_menu.ts" />
class FaustCoreMenu extends AbstractMenuItem {
    constructor() {
        super();
        this.tweak_menu = new TweakMenu();
        this.gratitude_menu = new GratitudeMenu();
    }
    composeMainDiv() {
        const result = document.createElement("div");
        // positioning
        result.style.position = "absolute";
        result.style.left = "50%";
        result.style.top = "5%";
        result.style.transform = "translate(-50%, -50%)";
        // reshaping
        result.style.width = "fit-content";
        result.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
        result.style.color = "white";
        result.style.zIndex = "9990";
        result.style.borderRadius = "10px";
        result.style.textAlign = "center";
        result.style.backdropFilter = "blur(5px)";
        // element positioning
        result.style.display = "flex";
        result.style.flexDirection = "row";
        result.style.alignItems = "center";
        result.style.justifyContent = "flex-start";
        result.style.gap = "20px";
        result.style.padding = "10px";
        const window_name = document.createElement("h2");
        window_name.style.fontWeight = "bold";
        window_name.style.color = "white";
        window_name.innerText = "Faust Core";
        result.appendChild(window_name);
        result.appendChild(MenuButtonsFactory.buildButton("Твики", () => this.tweak_menu.addElement()));
        result.appendChild(MenuButtonsFactory.buildButton("?", () => this.gratitude_menu.addElement()));
        return result;
    }
}
/// <reference path="./menu_windows/faust_core_menu.ts" />
class Application {
    constructor() {
        this.fcore_menu = new FaustCoreMenu();
        this.fcore_menu.addElement();
    }
}
const app = new Application();
const OriginalWebSocket = window.WebSocket; // backup original websocket
var WebsocketListeners;
(function (WebsocketListeners) {
    let receive_listeners = new Map();
    let send_listeners = new Map();
    function addReceiveListener(listener) {
        if (receive_listeners.has(listener.getTweakName())) {
            return false;
        }
        receive_listeners.set(listener.getTweakName(), listener);
        return true;
    }
    WebsocketListeners.addReceiveListener = addReceiveListener;
    function removeReceiveListener(tweak_name) {
        if (typeof tweak_name !== "string") {
            tweak_name = tweak_name.getTweakName();
        }
        receive_listeners.delete(tweak_name);
    }
    WebsocketListeners.removeReceiveListener = removeReceiveListener;
    function addSendListener(listener) {
        if (send_listeners.has(listener.getTweakName())) {
            return false;
        }
        send_listeners.set(listener.getTweakName(), listener);
        return true;
    }
    WebsocketListeners.addSendListener = addSendListener;
    function removeSendListener(tweak_name) {
        if (typeof tweak_name !== "string") {
            tweak_name = tweak_name.getTweakName();
        }
        send_listeners.delete(tweak_name);
    }
    WebsocketListeners.removeSendListener = removeSendListener;
    function triggerReceiveListener(data) {
        for (let [_, value] of receive_listeners) {
            value.processReceivedWebsocketMessage(data);
        }
    }
    WebsocketListeners.triggerReceiveListener = triggerReceiveListener;
    function triggerSendListener(data) {
        for (let [_, value] of send_listeners) {
            value.processSendedWebsocketMessage(data);
        }
    }
    WebsocketListeners.triggerSendListener = triggerSendListener;
})(WebsocketListeners || (WebsocketListeners = {}));
class PatchedWebSocket extends OriginalWebSocket {
    constructor(url, protocols) {
        super(url, protocols);
        // redefining send method
        const originalSend = this.send;
        this.send = (data) => {
            originalSend.call(this, data);
            WebsocketListeners.triggerSendListener(data);
        };
        // redefining accept method
        this.addEventListener("message", (event) => {
            WebsocketListeners.triggerReceiveListener(event.data);
        });
    }
}
// Redefining global websocket with Faust patch
window.WebSocket = PatchedWebSocket;
Object.defineProperties(window.WebSocket, {
    CONNECTING: { value: OriginalWebSocket.CONNECTING },
    OPEN: { value: OriginalWebSocket.OPEN },
    CLOSING: { value: OriginalWebSocket.CLOSING },
    CLOSED: { value: OriginalWebSocket.CLOSED },
});
const loaded_tweaks = [];
class Tweaks {
    constructor() {
        loaded_tweaks.push(this);
    }
    getTweakName() {
        return this.name;
    }
    isServerSide() {
        return this.sever_side;
    }
    isEnabled() {
        return this.is_enabled;
    }
}
/// <reference path="./tweak_interface.ts" />
class PlayerLister extends Tweaks {
    constructor() {
        super();
        this.name = "Отображать меню с игроками на локации";
        this.sever_side = false;
        this.is_enabled = false;
        // Init main div
        this.main_div = this.initPlayerListBlock();
        this.main_div.style.display = "none"; // Hiding window
        document.body.appendChild(this.main_div);
        // sub div will remain empty
        this.player_list_div = document.createElement("div");
        this.player_list_div.style.padding = "20px";
        this.main_div.appendChild(this.player_list_div);
        this.is_dragging = false;
        this.offset_x = 0;
        this.offset_y = 0;
        this.players_on_location = new Map();
    }
    enable() {
        this.is_enabled = true;
        this.main_div.style.display = "block";
        WebsocketListeners.addReceiveListener(this);
        display_notification("Для обновления списка перезайдите на локацию.");
    }
    disable() {
        this.is_enabled = false;
        this.main_div.style.display = "none";
        WebsocketListeners.removeReceiveListener(this);
        // Clearing info
        this.players_on_location.clear();
        this.updatePlayerList();
    }
    /**
     * @brief Parses user json entry from websocket
     *
     * @param user json info
     * @return PlayerInfo: parsed data
     */
    parseSocketUserData(user) {
        const result = {
            id: user.id,
            name: user.name,
            color: user.color,
        };
        return result;
    }
    processReceivedWebsocketMessage(websocket_event_data) {
        try {
            const parsedData = JSON.parse(websocket_event_data);
            switch (parsedData.reason) {
                case MessageReason.user_join:
                    const user = this.parseSocketUserData(parsedData.user);
                    this.players_on_location.set(user.id, user);
                    break;
                case MessageReason.node_data:
                    this.players_on_location.clear();
                    const users = parsedData.users;
                    if (!Array.isArray(users)) {
                        return;
                    }
                    users.forEach((user) => {
                        user = this.parseSocketUserData(user);
                        this.players_on_location.set(user.id, user);
                    });
                    break;
                case MessageReason.user_leave:
                    this.players_on_location.delete(parsedData.id);
                    break;
                default:
                    return;
            }
            this.updatePlayerList();
        }
        catch (error) {
            console.error(error);
        }
    }
    processSendedWebsocketMessage(websocket_event_data) { }
    updatePlayerList() {
        this.player_list_div.innerHTML = ""; // Clearing list
        for (const [key, value] of this.players_on_location) {
            const player_entry = document.createElement("p");
            player_entry.style.color = "#" + value.color;
            player_entry.innerText = key.toString() + " " + value.name;
            // player_entry.style.marginLeft = "10px";
            this.player_list_div.appendChild(player_entry);
        }
    }
    initPlayerListBlock() {
        const movableDiv = document.createElement("div");
        movableDiv.style.position = "fixed";
        movableDiv.style.top = "100px";
        movableDiv.style.left = "100px";
        movableDiv.style.width = "fit-content";
        movableDiv.style.height = "fit-content";
        movableDiv.style.backdropFilter = "blur(5px)";
        movableDiv.style.backgroundColor = "rgba(0, 0, 0, 0.5)";
        movableDiv.style.cursor = "grab";
        movableDiv.style.borderRadius = "10px";
        movableDiv.style.zIndex = "9990";
        const window_name = document.createElement("h3");
        window_name.style.color = "white";
        window_name.innerText = "На локации:";
        window_name.style.marginLeft = "5px";
        window_name.style.marginRight = "5px";
        window_name.style.marginTop = "5px";
        movableDiv.appendChild(window_name);
        // Enabling element moving
        movableDiv.addEventListener("mousedown", (event) => {
            this.is_dragging = true;
            this.offset_x = event.clientX - movableDiv.getBoundingClientRect().left;
            this.offset_y = event.clientY - movableDiv.getBoundingClientRect().top;
            // removing selection while holding
            event.preventDefault();
        });
        document.addEventListener("mousemove", (event) => {
            if (this.is_dragging) {
                movableDiv.style.left = `${event.clientX - this.offset_x}px`;
                movableDiv.style.top = `${event.clientY - this.offset_y}px`;
            }
        });
        document.addEventListener("mouseup", () => {
            this.is_dragging = false;
        });
        // Adding element to page
        document.body.appendChild(movableDiv);
        return movableDiv;
    }
}
//TODO: must be a better way of doing this
const player_lister_tweak = new PlayerLister();
//# sourceMappingURL=main.js.map
})();