// ==UserScript== // @name BlitzRhythm Editor Mod Loader // @name:zh 闪韵灵境谱面编辑器 模组加载器 // @namespace cipher-editor-mods-loader // @version 1.0.0 // @description A BlitzRhythm Editor Mod Loader // @description:zh 一款《闪韵灵境》谱面编辑器的Mod加载器 // @author Moyuer // @author:zh 如梦Nya // @license MIT // @grant unsafeWindow // @grant GM_xmlhttpRequest // @connect githubusercontent.com // @match https://cipher-editor-cn.picovr.com/* // @match https://cipher-editor-va.picovr.com/* // @icon https://cipher-editor-va.picovr.com/favicon.ico // @require https://code.jquery.com/jquery-3.6.0.min.js // @downloadURL none // ==/UserScript== let htmlSrc = "https://raw.githubusercontent.com/CMoyuer/BlitzRhythm-Editor-Mod-Loader/main/ModLoaderDrawer/dist/index.html" if (GM_info.script.namespace.endsWith("-dev")) htmlSrc = "http://127.0.0.1" /** @type {HTMLElement} */ let modloaderBox /** @type {HTMLElement} */ let divMask /** @type {HTMLElement} */ let iframe function initModloaderBox() { if (modloaderBox) return modloaderBox = document.createElement("div") modloaderBox.style = "position:absolute;width:100%;height:100%;top:0;left:0;z-index:9001;pointer-events:none;" divMask = document.createElement("div") divMask.style = "width:100%;height:100%;background-color:#00000050;display:none;pointer-events:auto;" divMask.onclick = hideIframe modloaderBox.append(divMask) iframe = document.createElement("iframe") modloaderBox.id = "modloaderIframe" iframe.style = "box-shadow: 0 0 10px 0 black;border:none;width:360px;height:100vh;position:fixed;right:0;top:0;bottom:0;transform:translateX(100%);z-index:9999;transition: transform 0.3s ease-in-out;pointer-events: auto;" GM_xmlhttpRequest({ url: htmlSrc + "?t=" + new Date().getTime(), method: "GET", onload: res => { iframe.srcdoc = res.response }, onerror: res => { console.error(res) } }) modloaderBox.append(iframe) document.body.append(modloaderBox) } function showIframe() { divMask.style.display = "block" iframe.style.transform = "translateX(0)" } function hideIframe() { divMask.style.display = "none" iframe.style.transform = "translateX(100%)" } function initShowButton() { let btnShow = document.createElement("div") btnShow.id = "btnModLoaderShow" btnShow.innerHTML = "M" btnShow.style = "position:absolute;transform:translate(-50%, -50%);left:calc(100vw - 50px);top:calc(100vh - 50px);width:50px;height: 50px;background-color:#2196F3;border-radius:25px;z-index:9000;font-size:1.5em;line-height:50px;text-align:center;color:white;font-family:Roboto,Helvetica,Arial,sans-serif;box-shadow: 0 0 6px 0 gray;user-select:none;" let info = { handle: 0, mousedown: false, dragging: false, canClick: true, rawPos: [0, 0], position: [0, 0], } function getMoveDistance() { return Math.abs(info.position[0] - info.rawPos[0]) + Math.abs(info.position[1] - info.rawPos[1]) } btnShow.onmousedown = res => { btnShow.style.backgroundColor = "#1769AA" info.canClick = true info.mousedown = true info.handle = setTimeout(() => { btnShow.style.boxShadow = "0 0 6px 2px white" info.dragging = true info.handle = 0 }, 100) if (btnShow.style.left && btnShow.style.left.startsWith("calc")) btnShow.style.left = btnShow.offsetLeft + "px" if (btnShow.style.top && btnShow.style.top.startsWith("calc")) btnShow.style.top = btnShow.offsetTop + "px" info.rawPos = [btnShow.offsetLeft, btnShow.offsetTop] info.position = [res.clientX, res.clientY] } btnShow.onmousemove = res => { if (!info.dragging) return let x = res.clientX let y = res.clientY let deltaX = x - info.position[0] let deltaY = y - info.position[1] let left = parseInt(btnShow.style.left || 0) let top = parseInt(btnShow.style.top || 0) btnShow.style.left = left + deltaX + 'px' btnShow.style.top = top + deltaY + 'px' info.position = [x, y] } btnShow.onmouseup = btnShow.onmouseleave = () => { btnShow.style.backgroundColor = "#2196F3" btnShow.style.boxShadow = "0 0 6px 0 gray" if (info.handle > 0) { clearTimeout(info.handle) info.handle = 0 } info.canClick = !info.dragging info.mousedown = false info.dragging = false } btnShow.onclick = () => { if (!info.canClick) return showIframe() } window.onresize = () => { let left = parseInt(btnShow.style.left || 0) let top = parseInt(btnShow.style.top || 0) if (window.innerWidth < left + 50) btnShow.style.left = "calc(100vw - 50px)" if (window.innerHeight < top + 50) btnShow.style.top = "calc(100vh - 50px)" } document.body.appendChild(btnShow) } (function () { 'use strict' initModloaderBox() let handle = setInterval(() => { if (!unsafeWindow.modloader) return unsafeWindow.modloader.drawer = { methods: { show: showIframe, hide: hideIframe } } initShowButton() clearInterval(handle) }, 100) })();