// ==UserScript== // @name Ultra Mobs Alert // @namespace http://tampermonkey.net/ // @version 0.3 // @description Show spawn timer, sharing another players. Work In Progress https://discord.gg/4nPjXjVf4t // @author @jmatg1 // @license MIT // @match https://florr.io // @icon https://www.google.com/s2/favicons?sz=64&domain=florr.io // @grant none // @downloadURL none // ==/UserScript== class GUI { constructor() { this.bosses = []; this.menu = document.body.appendChild(document.createElement('div')); this.menu.style.padding = '15px'; this.menu.style.background = '#ffffff3f'; this.menu.style['border-radius'] = '10px'; this.menu.style.display = 'block'; this.menu.style.position = 'absolute'; this.menu.style['pointer-events'] = 'none'; this.menu.style.bottom = '5px'; this.menu.style.right = '5px'; this.table = this.menu.appendChild(document.createElement('table')); this.table.style['font-family'] = 'Ubuntu'; this.table.style['border-collapse'] = 'collapse'; this.table.style.width = `100%`; setInterval(() => { this.updateTable(); }, 60 * 1000) } updateTable(bosses = this.bosses) { console.log(bosses); this.bosses = bosses; while (this.table.rows.length > 0) { this.table.deleteRow(0); } bosses.sort((a, b) => { return new Date(a.date).getTime() - new Date(b.date).getTime(); }); bosses = bosses.filter((x) => { const minutes = Math.floor((Date.now() - new Date(x.date).getTime()) / 1000 / 60); if (minutes > 240) { return false } return true; }); bosses.forEach((x, i) => { const tr = this.table.insertRow(); // Mob const td1 = tr.insertCell(); if (i !== 0) { td1.style['padding-top'] = '5px'; } if (i !== bosses.length - 1) { td1.style['padding-bottom'] = '5px'; } td1.style['padding-right'] = '20px'; td1.appendChild(document.createTextNode(x.name)); // minutes ago const td2 = tr.insertCell(); if (i !== 0) { td2.style['padding-top'] = '5px'; } if (i !== bosses.length - 1) { td2.style['padding-bottom'] = '5px'; } td2.style['pointer-events'] = 'auto'; td2.style.cursor = 'pointer'; td2.appendChild(document.createTextNode(this.toTimeSpanString(x.date))); }); } toTimeSpanString(timestamp) { if (timestamp == null) { return 'N/A'; } let minutes = Math.floor((Date.now() - new Date(timestamp).getTime()) / 1000 / 60); let h = Math.floor(minutes / 60); minutes = minutes % 60; return `${String(h).padStart(2, '0')}:${String(minutes).padStart(2, '0')}`; } } class ServerId { constructor() { this.servers = []; this.url; const nativeWebSocket = window.WebSocket; var totalServers = 17 - 1; var regionName, allServers = []; var _this = this; window.WebSocket = function (...args) { const socket = new nativeWebSocket(...args); _this.url = socket.url return socket; }; for (let i = 0; i <= totalServers; i++) { fetch(`https://api.n.m28.io/endpoint/florrio-map-${i}-green/findEach/`).then((response) => response.json()).then((data) => { this.servers[i] = `${data.servers["vultr-miami"].id} ${data.servers["vultr-frankfurt"].id} ${data.servers["vultr-tokyo"].id}` }); } } getId() { var wssUrl = this.url.slice(6, 9) var codeA = []; var regionName = ''; this.servers.forEach(function callback(x, index) { if (x.includes(wssUrl)) { codeA = x.split(" ") if (wssUrl == codeA[0]) regionName = "NA" else if (wssUrl == codeA[1]) regionName = "EU" else if (wssUrl == codeA[2]) regionName = "AS" } }); return regionName; } } (function () { 'use strict'; const gui = new GUI(); const serv = new ServerId(); let socket = new WebSocket("wss://cyber-glorious-ferry.glitch.me"); socket.onopen = function(e) { console.log("[open] Соединение установлено"); setInterval(() => { socket.send(JSON.stringify({message: "PING", serverName: 'EU'})); }, 60 * 1000) }; socket.onmessage = function(event, isBinary) { const message = JSON.parse(event.data); if (message === "PONG") { return } gui.updateTable(message['EU']); }; socket.onclose = function(event) { if (event.wasClean) { console.log(`[close] Соединение закрыто чисто, код=${event.code} причина=${event.reason}`); } else { console.log('[close] Соединение прервано'); } }; socket.onerror = function(error) { console.log(`[error]`); }; var flag = false; function parseText(text, _this) { if(flag) { return } if(text && text.search(/((An Ultra)|(A Super)) (.*) has spawned!?( somewhere!?)?/i) !== -1) { socket.send(JSON.stringify({message: text, serverName: serv.getId()})); console.warn(JSON.stringify({message: text, serverName: serv.getId()})); flag = true; setTimeout(() => { flag = false; }, 10 * 60 * 1000) } //console.log(text, x, y, a) } function getCompatibleCanvas() { if (typeof (OffscreenCanvasRenderingContext2D) == 'undefined') { return [CanvasRenderingContext2D] } return [OffscreenCanvasRenderingContext2D, CanvasRenderingContext2D]; } for (const { prototype } of getCompatibleCanvas()) { if (prototype.rewriteStrokeText == undefined) { if (false) { prototype.rewriteArc = prototype.arc } prototype.rewriteStrokeText = prototype.strokeText; prototype.rewriteFillText = prototype.fillText; prototype.rewriteMeasureText = prototype.measureText; } else { break } } for (const { prototype } of getCompatibleCanvas()) { //重写字符描边函数 prototype.strokeText = function (text, x, y) { parseText(text, this); return this.rewriteStrokeText(text, x, y); } prototype.fillText = function (text, x, y) { parseText(text, this); return this.rewriteFillText((text), x, y); } prototype.measureText = function (text) { parseText(text, this); return this.rewriteMeasureText((text)); } } })();