2024-04-18 23:18:49 +01:00
// ==UserScript==
2024-04-26 17:34:34 +01:00
// @name MultiProbe
2024-04-18 23:18:49 +01:00
// @namespace https://*.angusnicneven.com/*
2024-05-27 12:56:49 +01:00
// @version 20240527.1
2024-04-18 23:18:49 +01:00
// @description Probe with friends!
// @author tgpholly
// @match https://*.angusnicneven.com/*
2024-05-27 12:56:49 +01:00
// @match https://*.heavenonline.xyz/*
2024-04-18 23:18:49 +01:00
// @icon https://www.google.com/s2/favicons?sz=64&domain=angusnicneven.com
// @grant none
// ==/UserScript==
let continueRunningScript = true ;
if ( ! window . TE _ACTIVE ) {
if ( window . location . href . includes ( "www." ) ) {
window . location . href = window . location . href . replace ( "www." , "" ) ;
continueRunningScript = false ;
}
let didWeNukeIt = false ;
function nukeCC ( ) {
if ( didWeNukeIt ) {
return ;
}
try {
const doWeHaveCC = document . getElementById ( "cursor-container" ) ;
if ( doWeHaveCC ) {
doWeHaveCC . remove ( ) ;
didWeNukeIt = true ;
}
} catch ( e ) { }
}
setInterval ( nukeCC , 1000 ) ;
}
2024-05-07 21:46:52 +01:00
const windowLocation = window . location . href ;
2024-05-06 15:41:26 +01:00
window . multiprobe _debug = false ;
2024-05-27 12:56:49 +01:00
const SITE _DEFAULT _CURSOR = {
"localhost" : "https://angusnicneven.com/cursor/rrw.png" ,
"angusnicneven.com" : "https://angusnicneven.com/cursor/rrw.png" ,
"heavenonline.xyz" : "https://heavenonline.xyz/core/cursor/frame1.png"
} ;
2024-05-07 22:17:30 +01:00
console . log ( "[MP] MultiProbe init" ) ;
2024-04-18 23:18:49 +01:00
( function ( ) {
'use strict' ;
2024-04-26 10:21:27 +01:00
// Make sure to change the userscript version too!!!!!!!!!!
2024-05-27 12:59:31 +01:00
const USERSCRIPT _VERSION _RAW = "20240527.1" ;
2024-04-26 10:21:27 +01:00
const USERSCRIPT _VERSION = parseInt ( USERSCRIPT _VERSION _RAW . replace ( "." , "" ) ) ;
2024-04-26 03:01:06 +01:00
2024-04-18 23:18:49 +01:00
if ( ! continueRunningScript ) {
return ;
}
// This is a minified version of the code at https://git.eusv.net/tgpholly/bufferStuff/releases/tag/1.5.0 + FunkyArray
class BrowserBuffer { constructor ( dataOrSize ) { if ( typeof dataOrSize === "number" ) { this . buffer = new Uint8Array ( dataOrSize ) } else if ( typeof dataOrSize === "object" ) { this . buffer = new Uint8Array ( dataOrSize ) } else { this . buffer = new Uint8Array ( 0 ) } this . dataView = new DataView ( this . buffer . buffer ) } static allocUnsafe ( size ) { return this . alloc ( size ) } static allocUnsafeSlow ( size ) { return this . alloc ( size ) } static alloc ( size ) { return new BrowserBuffer ( size ) } static concat ( buffers , totalLength ) { let joinedArrays ; if ( totalLength !== undefined ) { joinedArrays = new Uint8Array ( totalLength ) } else { let arraysLength = 0 ; for ( const buffer of buffers ) { arraysLength += buffer . length } joinedArrays = new Uint8Array ( arraysLength ) } let offset = 0 ; for ( const buffer of buffers ) { joinedArrays . set ( buffer . buffer , offset ) ; offset += buffer . length } return new BrowserBuffer ( joinedArrays ) } static from ( data ) { if ( typeof data === "string" ) { throw new Error ( "BrowserBuffer does not currently support creating buffers from strings." ) } return new BrowserBuffer ( data ) } static of ( ) { } static isBuffer ( ) { } static isEncoding ( ) { } static byteLength ( ) { } static copyBytesFrom ( ) { } static compare ( ) { } get length ( ) { return this . buffer . length } checkRanged ( value , valueName , lowRange , highRange ) { if ( value < lowRange || value > highRange ) { throw new Error ( ` The value of " ${ valueName } " is out of range. It must be >= ${ lowRange } and <= ${ highRange } . Received ${ value } ` ) } } checkValue ( value , low , high ) { this . checkRanged ( value , "value" , low , high ) } checkOffset ( offset ) { if ( offset ) { this . checkRanged ( offset , "offset" , 0 , this . buffer . length - 1 ) } } writeInt8 ( value , offset ) { this . checkValue ( value , - 128 , 127 ) ; this . checkOffset ( offset ) ; this . dataView . setInt8 ( offset , value ) ; return this } writeUInt8 ( value , offset ) { this . checkValue ( value , 0 , 255 ) ; this . checkOffset ( offset ) ; this . dataView . setUint8 ( offset , value ) ; return this } writeInt16LE ( value , offset ) { this . checkValue ( value , - 32768 , 32767 ) ; this . checkOffset ( offset ) ; this . dataView . setInt16 ( offset , value , true ) ; return this } writeUInt16LE ( value , offset ) { this . checkValue ( value , 0 , 65535 ) ; this . checkOffset ( offset ) ; this . dataView . setUint16 ( offset , value , true ) ; return this } writeInt32LE ( value , offset ) { this . checkValue ( value , - 2147483648 , 2147483647 ) ; this . checkOffset ( offset ) ; this . dataView . setInt32 ( offset , value , true ) ; return this } writeUInt32LE ( value , offset ) { this . checkValue ( value , 0 , 4294967295 ) ; this . checkOffset ( offset ) ; this . dataView . setUint32 ( offset , value , true ) ; return this } writeBigInt64LE ( value , offset ) { if ( typeof value === "number" ) { value = BigInt ( value ) } this . checkValue ( value , - 9223372036854775808 n , 9223372036854775808 n ) ; this . checkOffset ( offset ) ; this . dataView . setBigInt64 ( offset , value , true ) ; return this } writeBigUint64LE ( value , offset ) { if ( typeof value === "number" ) { value = BigInt ( value ) } this . checkValue ( value , 0 n , 18446744073709551616 n ) ; this . checkOffset ( offset ) ; this . dataView . setBigUint64 ( offset , value , true ) ; return this } writeFloatLE ( value , offset ) { this . checkOffset ( offset ) ; this . dataView . setFloat32 ( offset , value , true ) ; return this } writeDoubleLE ( value , offset ) { this . checkOffset ( offset ) ; this . dataView . setFloat64 ( offset , value , true ) ; return this } writeInt16BE ( value , offset ) { this . checkValue ( value , - 32768 , 32767 ) ; this . checkOffset ( offset ) ; this . dataView . setInt16 ( offset , value , false ) ; return this } writeUInt16BE ( value , offset ) { this . checkValue ( value , 0 , 65535 ) ; this . checkOffset ( offset ) ; this . dataView . setUint16 ( offset , value , false ) ; return this } writeInt32BE ( value , offset ) { this . checkValue ( value , - 2147483648 , 2147483647 ) ; this . checkOffset ( offset ) ; this . dataView . setInt32 ( offset , value , false ) ; return this } writeUInt32BE ( value , offset ) { this . checkValue ( value , 0 , 4294967295 ) ; this . checkOffset ( offset ) ; this . dataView . setUint32 ( offset , value , false ) ; return this } writeBigInt64BE ( value , offset ) { if ( typeof value === "number" ) { value = BigInt ( value ) } this . checkValue ( value , - ( 2 n * * 63 n ) , 2 n * * 63 n ) ; this . checkOffset ( offset ) ; this . dataView . setBigInt64 ( offset , value , false ) ; return this } writeBigUint64BE ( value , offset ) { if ( typeof value === "number" ) { value = BigInt ( value ) } this . checkValue ( value , 0 n , 2 n * * 64 n ) ; this . checkOffset ( offset ) ; this . dataView . setBigUint64 ( offset , value , false ) ; return this } writeFloatBE ( value , offset ) { this . checkOffset ( offset ) ; this . dataView . setFloat32 ( offset , value , false ) ; return this } writeDouble
const MessageType = {
KeepAlive : 0 ,
ClientDetails : 1 ,
CursorPos : 2 ,
ClientJoined : 3 ,
Clients : 4 ,
ClientLeft : 5 ,
2024-04-25 02:37:37 +01:00
Ping : 6 ,
2024-05-27 12:56:49 +01:00
GroupData : 7 ,
HonkShoe : 8
2024-04-18 23:18:49 +01:00
} ;
2024-05-02 16:50:05 +01:00
let cursorImageI = window . getComputedStyle ( document . body ) . cursor ;
2024-05-27 12:56:49 +01:00
const cssCursor = ` ${ cursorImageI === "auto" || ! cursorImageI . includes ( "url" ) ? ` url( ${ SITE _DEFAULT _CURSOR [ window . location . href . split ( "//" ) [ 1 ] . split ( "/" ) [ 0 ] . split ( ":" ) [ 0 ] ] } ) 11 11, auto ` : cursorImageI } ` ;
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Injecting custom styles..." ) ;
2024-04-18 23:18:49 +01:00
const styles = document . createElement ( "style" ) ;
styles . innerHTML = `
2024-05-02 16:50:05 +01:00
html {
2024-05-27 12:56:49 +01:00
cursor : $ { cssCursor } ;
2024-05-02 16:50:05 +01:00
}
2024-04-18 23:18:49 +01:00
# otherCursors {
position : absolute ;
top : 0 px ;
left : 0 px ;
width : 100 % ;
height : 100 % ;
z - index : 999999999 ;
pointer - events : none ;
overflow : hidden ;
2024-05-07 21:46:52 +01:00
text - shadow : none ! important ;
font - family : Arial , sans - serif ;
2024-04-18 23:18:49 +01:00
}
2024-04-26 16:52:58 +01:00
# otherCursors img {
image - rendering : pixelated ;
}
2024-04-18 23:18:49 +01:00
@ keyframes ping {
0 % {
scale : 0 ;
opacity : 1 ;
}
100 % {
scale : 2 ;
opacity : 0 ;
}
}
. ping {
opacity : 0 ;
position : absolute ;
animation : ping 2 s linear ;
animation - iteration - count : 1 ;
image - rendering : pixelated ;
background : url ( "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAXVJREFUeJztm8ESwyAIRLX//8/2EjKKmhhFUeDN9NbK7kIybaPerSU0vs9PVbGwUGI4hDb/3meypumcsfDtEhsuGCsv8Pw5Us2UiwXnUvEDnaxOTrQmiXaKRRLjk7qVTRVVEKMCA7WglppX4bjusptmLCJc7uF1pIae5HDXl6ePWKqHu+s18DTMKTK7AAHTNJ5gHiDXepJ5gEzzieaBYe0nmwdePfwWijkKCd0HPnuRZB6oerJLACGx+0DRm01AhOTuA5lH9ROgPgBAw/gDiVf1E2ABcAvYAU3XP3B7Vj8BFgC3AG4sAG4B3FgA3AK4sQC4BeyCpm+D9mswxgLgFrATGu4D9qcoRn0AGMmXgT0ZakXiFNjT4a9ImoJuLxJCsD1Co5w8Bar3CqreLap6v/DSHeM7BdG9Xd4OTPQWdfzTwHZkJhGB0qdY87XmVTiu213Tjs2NfBiRBOGcnoOTmKxbdzHhR2dLVDv5xOmHp59ovVMv0/UHCfuPGCq5foYAAAAASUVORK5CYII=" ) ;
width : 64 px ;
height : 64 px ;
2024-04-20 17:25:16 +01:00
z - index : - 1 ! important ;
2024-04-18 23:18:49 +01:00
}
2024-04-24 00:06:42 +01:00
2024-05-27 12:56:49 +01:00
. eepy {
position : absolute ;
top : 0 ;
right : 0 ;
width : 64 px ;
height : 64 px ;
image - rendering : pixelated ;
background : url ( "data:image/webp;base64,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" ) ;
z - index : 1 ;
transform : translate ( 60 px , - 60 px ) ;
}
2024-04-24 00:06:42 +01:00
. grouphidden {
right : - 12 rem ! important ;
}
. groupui {
position : fixed ;
top : 2 rem ;
right : 0 px ;
height : 25 rem ;
width : 12 rem ;
background - color : black ;
color : white ;
z - index : 9999998 ;
2024-05-07 21:46:52 +01:00
text - shadow : none ! important ;
font - family : Arial , sans - serif ;
font - size : unset ! important ;
2024-04-24 00:06:42 +01:00
}
. groupui - popper {
position : absolute ;
top : 0 px ;
left : - 1 rem ;
width : 1 rem ;
height : 100 % ;
opacity : 0.25 ;
background - color : black ;
border : 1 px solid white ;
color : white ;
}
. groupui - title {
position : absolute ;
top : 0 px ;
left : 0 px ;
width : 100 % ;
text - align : center ;
height : 2 rem ;
line - height : 2 rem ;
background - color : rgba ( 255 , 255 , 255 , 0.1 ) ;
2024-05-07 21:52:46 +01:00
overflow : hidden ;
2024-04-24 00:06:42 +01:00
}
. groupui - scrollbox {
position : absolute ;
top : 2 rem ;
left : 0 px ;
width : 100 % ;
height : calc ( 100 % - 2 rem ) ;
overflow - y : scroll ;
2024-05-07 21:46:52 +01:00
font - family : Arial , sans - serif ;
font - size : unset ! important ;
2024-04-24 00:06:42 +01:00
}
. groupui - user {
position : relative ;
width : 100 % ;
height : 2 rem ;
background - color : rgba ( 255 , 255 , 255 , 0.2 ) ;
}
. groupui - user : nth - child ( 2 n ) {
background - color : rgba ( 255 , 255 , 255 , 0.15 ) ;
}
. groupui - user p {
position : absolute ;
line - height : 2 rem ;
margin : 0 ;
margin - left : . 5 rem ;
}
. groupui - user . buttons {
position : absolute ;
height : 100 % ;
top : 0 px ;
right : 0 px ;
margin - right : . 5 rem ;
}
. groupui - user . buttons button {
margin - left : . 5 rem ;
margin - top : . 2 rem ;
}
2024-04-25 10:12:17 +01:00
kbd {
background - color : # eee ;
border - radius : 3 px ;
border : 1 px solid # b4b4b4 ;
box - shadow : 0 1 px 1 px rgba ( 0 , 0 , 0 , 0.2 ) , 0 2 px 0 0 rgba ( 255 , 255 , 255 , 0.7 ) inset ;
color : # 333 ;
display : inline - block ;
font - size : 0.85 em ;
font - weight : 700 ;
line - height : 1 ;
padding : 2 px 4 px ;
white - space : nowrap ;
2024-05-07 21:46:52 +01:00
font - family : Arial , sans - serif ;
font - size : unset ! important ;
2024-04-25 10:12:17 +01:00
}
2024-04-26 03:01:06 +01:00
. mplink , . mplink : visited {
color : # d2738a ;
}
. mplink : hover {
color : # c1b492 ;
}
2024-04-18 23:18:49 +01:00
` .split(" \n ").join("").split(" \r ").join("").split(" \t ").join("");
2024-05-02 16:50:05 +01:00
2024-04-18 23:18:49 +01:00
document . head . appendChild ( styles ) ;
2024-04-26 03:01:06 +01:00
if ( ! localStorage [ "mpconnectonload" ] ) {
localStorage [ "mpconnectonload" ] = true ;
}
2024-05-02 16:33:50 +01:00
2024-05-07 21:46:52 +01:00
let marginComputedStyle = window . getComputedStyle ( document . body ) ;
const bodyMarginTop = parseInt ( marginComputedStyle . marginTop . replace ( "px" , "" ) ) ;
const bodyMarginLeft = parseInt ( marginComputedStyle . marginLeft . replace ( "px" , "" ) ) ;
const bodyMarginRight = parseInt ( marginComputedStyle . marginRight . replace ( "px" , "" ) ) ;
2024-05-02 16:50:05 +01:00
2024-04-18 23:18:49 +01:00
const otherCursors = document . createElement ( "div" ) ;
2024-05-07 21:46:52 +01:00
otherCursors . style . top = ` - ${ ( ( window . scrollY + document . body . getBoundingClientRect ( ) . top ) - bodyMarginTop ) } px ` ;
2024-04-18 23:18:49 +01:00
otherCursors . id = "otherCursors" ;
document . body . appendChild ( otherCursors ) ;
2024-04-19 12:03:38 +01:00
2024-04-24 00:06:42 +01:00
const groupUIBase = document . createElement ( "div" ) ;
groupUIBase . style = "display:none" ;
groupUIBase . classList . add ( "groupui" ) ;
groupUIBase . classList . add ( "grouphidden" ) ;
const groupPopper = document . createElement ( "button" ) ;
groupPopper . classList . add ( "groupui-popper" ) ;
groupPopper . onclick = ( ) => {
groupUIBase . classList . toggle ( "grouphidden" ) ;
groupPopper . innerText = groupUIBase . classList . contains ( "grouphidden" ) ? "<" : ">" ;
} ;
groupPopper . innerText = "<" ;
groupUIBase . appendChild ( groupPopper ) ;
const groupTitle = document . createElement ( "div" ) ;
groupTitle . classList . add ( "groupui-title" ) ;
groupTitle . innerText = "GROUP_NAME" ;
groupUIBase . appendChild ( groupTitle ) ;
const groupUsers = document . createElement ( "div" ) ;
groupUsers . classList . add ( "groupui-scrollbox" ) ;
groupUIBase . appendChild ( groupUsers ) ;
document . body . appendChild ( groupUIBase ) ;
function createGroupUser ( username , location ) {
const user = document . createElement ( "div" ) ;
user . classList . add ( "groupui-user" ) ;
const usernameBox = document . createElement ( "p" ) ;
usernameBox . innerText = username ;
user . appendChild ( usernameBox ) ;
const buttonBox = document . createElement ( "div" ) ;
buttonBox . classList . add ( "buttons" ) ;
user . appendChild ( buttonBox ) ;
2024-04-26 03:01:06 +01:00
/ * c o n s t f o l l o w B u t t o n = d o c u m e n t . c r e a t e E l e m e n t ( " b u t t o n " ) ;
2024-04-24 00:06:42 +01:00
followButton . innerText = "F" ;
2024-04-26 03:01:06 +01:00
buttonBox . appendChild ( followButton ) ; * /
2024-04-24 00:06:42 +01:00
const gotoButton = document . createElement ( "button" ) ;
2024-04-26 03:01:06 +01:00
gotoButton . innerText = "Go To" ;
2024-04-25 02:37:37 +01:00
gotoButton . onclick = ( ) => window . location . href = location ;
2024-04-24 00:06:42 +01:00
buttonBox . appendChild ( gotoButton ) ;
groupUsers . appendChild ( user ) ;
}
2024-04-25 02:37:37 +01:00
let clientWidth = document . body . getBoundingClientRect ( ) . width ;
2024-04-20 17:20:23 +01:00
2024-04-19 12:03:38 +01:00
setInterval ( ( ) => {
2024-04-20 17:20:23 +01:00
if ( document . body . scrollHeight > window . innerHeight ) {
2024-05-27 12:56:49 +01:00
otherCursors . style = ` width: ${ clientWidth = ( document . body . getBoundingClientRect ( ) . width + bodyMarginRight + bodyMarginLeft ) } px;height: ${ document . body . scrollHeight } px;top:- ${ ( ( window . scrollY + document . body . getBoundingClientRect ( ) . top ) - bodyMarginTop ) } px;cursor: ${ cssCursor } ; ` ;
2024-04-20 17:20:23 +01:00
} else {
2024-05-27 12:56:49 +01:00
otherCursors . style = ` width: ${ clientWidth = ( document . body . getBoundingClientRect ( ) . width + bodyMarginRight + bodyMarginLeft ) } px;height: ${ window . innerHeight } px;top:- ${ ( ( window . scrollY + document . body . getBoundingClientRect ( ) . top ) - bodyMarginTop ) } px;cursor: ${ cssCursor } ; ` ;
2024-04-20 17:20:23 +01:00
}
2024-04-19 12:03:38 +01:00
} , 1000 ) ;
2024-04-26 03:01:06 +01:00
2024-04-26 17:34:34 +01:00
let needsToUpdate = false ;
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Checking for new versions..." ) ;
2024-05-07 21:46:52 +01:00
const versionFetchAddress = windowLocation . replace ( "127.0.0.1" , "localhost" ) . includes ( "//localhost:" ) ? "http://localhost:38194/api/version" : "https://multiprobe.eusv.net/api/version" ;
2024-04-26 10:38:46 +01:00
fetch ( versionFetchAddress , { method : "post" } ) . then ( response => {
2024-04-26 10:21:27 +01:00
response . text ( ) . then ( versionNumberRaw => {
const versionNumber = parseInt ( versionNumberRaw ) ;
if ( versionNumber > USERSCRIPT _VERSION ) {
// We're out of date >:(
2024-04-26 17:34:34 +01:00
needsToUpdate = true ;
2024-04-26 10:21:27 +01:00
createUpdateDialog ( ` ${ versionNumberRaw . slice ( 0 , versionNumberRaw . length - 1 ) } . ${ versionNumberRaw . slice ( - 1 ) } ` ) ;
2024-05-07 22:17:30 +01:00
console . log ( "[MP] We're out of date :(" ) ;
} else {
console . log ( "[MP] We're up to date!" ) ;
2024-04-26 03:01:06 +01:00
}
} ) ;
2024-04-26 10:21:27 +01:00
} ) ;
2024-04-18 23:18:49 +01:00
2024-05-27 12:56:49 +01:00
const keepAlivePacket = createWriter ( Endian . LE , 1 ) . writeUByte ( MessageType . KeepAlive ) . toBuffer ( ) ;
2024-04-18 23:18:49 +01:00
let remoteClients = new FunkyArray ( ) ;
let ws ;
let ready = false ;
let currentMouseX = 0 ;
let currentMouseY = 0 ;
let oldMouseX = 0 ;
let oldMouseY = 0 ;
let lastSendTime = 0 ;
class RemoteClient {
2024-05-27 12:56:49 +01:00
constructor ( name , startAfk , isSelfCursor = false ) {
2024-04-18 23:18:49 +01:00
this . name = name ;
this . element = document . createElement ( "div" ) ;
this . element . style . position = "absolute" ;
this . element . style . transform = ` translate(-50%, -50%) ` ;
const image = new Image ( ) ;
let cursorImage = window . getComputedStyle ( document . body ) . cursor . replace ( "url(" , "" ) . split ( '"' ) . join ( "" ) . split ( "'" ) . join ( "" ) . split ( ")" ) [ 0 ] ;
if ( cursorImage === "auto" ) {
cursorImage = "https://angusnicneven.com/cursor/rrw.png" ;
}
image . src = cursorImage ;
2024-04-20 17:20:23 +01:00
this . probeImage = image ;
2024-04-18 23:18:49 +01:00
this . element . appendChild ( image ) ;
const clientName = document . createElement ( "div" ) ;
2024-04-20 17:20:23 +01:00
clientName . style = "position:absolute;left:100%;top:100%;background-color:black;padding:4px 8px;color:white;font-size:12px;font-family:Arial,sans-serif;" ;
2024-04-18 23:18:49 +01:00
clientName . innerText = name ;
this . element . appendChild ( clientName ) ;
2024-05-27 12:56:49 +01:00
if ( ! isSelfCursor ) {
this . eepy = document . createElement ( "div" ) ;
this . eepy . className = "eepy" ;
this . eepy . style = startAfk ? "" : "display:none" ;
this . element . appendChild ( this . eepy ) ;
}
2024-04-18 23:18:49 +01:00
otherCursors . appendChild ( this . element ) ;
this . targetX = 0 ;
this . targetY = 0 ;
this . actualX = 0 ;
this . actualY = 0 ;
this . oldActualX = 0 ;
this . oldActualY = 0 ;
2024-04-20 17:20:23 +01:00
this . hasBeenMoved = false ;
this . element . visibility = "hidden" ;
2024-04-18 23:18:49 +01:00
}
2024-05-27 12:56:49 +01:00
setAfk ( afkState ) {
this . eepy . style = afkState ? "" : "display:none" ;
}
2024-04-18 23:18:49 +01:00
rawSetPos ( x , y ) {
2024-04-20 17:20:23 +01:00
if ( ! this . hasBeenMoved ) {
this . element . visibility = "" ;
2024-04-20 17:34:32 +01:00
this . hasBeenMoved = true ;
2024-04-20 17:20:23 +01:00
}
this . targetX = Math . round ( x * clientWidth ) ;
2024-04-18 23:18:49 +01:00
this . targetY = y ;
}
2024-04-19 00:18:12 +01:00
rawSetPosInit ( x , y ) {
2024-04-20 17:20:23 +01:00
if ( ! this . hasBeenMoved ) {
this . element . visibility = "" ;
2024-04-20 17:34:32 +01:00
this . hasBeenMoved = true ;
2024-04-20 17:20:23 +01:00
}
this . actualX = this . targetX = Math . round ( x * clientWidth ) ;
2024-04-19 00:18:12 +01:00
this . actualY = this . targetY = y ;
}
2024-04-18 23:18:49 +01:00
updateCursor ( ) {
const x = Math . round ( this . actualX ) ;
const y = Math . round ( this . actualY ) ;
if ( y !== this . oldActualY ) {
this . element . style . top = ` ${ y } px ` ;
this . oldActualY = y ;
}
if ( x !== this . oldActualX ) {
this . element . style . left = ` ${ x } px ` ;
this . oldActualX = x ;
}
}
}
2024-04-20 17:20:23 +01:00
let selfCursor ;
2024-04-18 23:18:49 +01:00
function createPing ( x , y ) {
const pingDiv = document . createElement ( "div" ) ;
pingDiv . className = "ping" ;
pingDiv . style . top = ` ${ y } px ` ;
pingDiv . style . left = ` ${ x } px ` ;
otherCursors . appendChild ( pingDiv ) ;
2024-04-19 09:44:26 +01:00
setTimeout ( ( ) => pingDiv . remove ( ) , 2000 ) ;
2024-04-18 23:18:49 +01:00
}
function removeClient ( id ) {
if ( remoteClients . has ( id ) ) {
const client = remoteClients . get ( id ) ;
remoteClients . remove ( id ) ;
client . element . remove ( ) ;
}
}
2024-05-27 12:56:49 +01:00
let isAfkLocal = false ;
let lastSendAfkState = false
window . onfocus = ( e ) => {
isAfkLocal = false ;
}
window . onblur = ( e ) => {
isAfkLocal = true ;
}
2024-04-18 23:18:49 +01:00
let rawMouseX = 0 ;
let rawMouseY = 0 ;
window . onmousemove = ( e ) => {
2024-05-02 16:33:50 +01:00
currentMouseX = ( rawMouseX = e . clientX ) + window . scrollX ;
currentMouseY = ( rawMouseY = e . clientY ) + window . scrollY ;
2024-04-20 17:20:23 +01:00
if ( selfCursor ) {
selfCursor . rawSetPosInit ( currentMouseX / clientWidth , currentMouseY ) ;
selfCursor . updateCursor ( ) ;
}
2024-04-18 23:18:49 +01:00
}
window . onscroll = ( ) => {
2024-05-02 16:33:50 +01:00
currentMouseX = rawMouseX + window . scrollX ;
currentMouseY = rawMouseY + window . scrollY ;
2024-04-20 17:20:23 +01:00
if ( selfCursor ) {
selfCursor . rawSetPosInit ( currentMouseX / clientWidth , currentMouseY ) ;
selfCursor . updateCursor ( ) ;
}
2024-04-18 23:18:49 +01:00
}
2024-05-27 12:56:49 +01:00
function log ( type , text ) {
const d = new Date ( ) ;
console . log ( ` [hNET] [ ${ String ( d . getHours ( ) ) . padStart ( 2 , "0" ) } : ${ String ( d . getMinutes ( ) ) . padStart ( 2 , "0" ) } : ${ String ( d . getSeconds ( ) ) . padStart ( 2 , "0" ) } . ${ String ( d . getMilliseconds ( ) ) . padStart ( 4 , "0" ) } ] [ ${ type } ] ${ text } ` ) ;
}
2024-05-06 15:41:26 +01:00
2024-04-20 17:20:23 +01:00
let allowedPings = 10 ;
2024-04-18 23:18:49 +01:00
window . onkeypress = ( e ) => {
if ( e . key === "p" ) {
if ( ws && ready ) {
2024-04-20 17:20:23 +01:00
if ( allowedPings > 0 ) {
allowedPings -- ;
2024-05-27 12:56:49 +01:00
ws . send ( createWriter ( Endian . LE , 9 ) . writeUByte ( MessageType . Ping ) . writeFloat ( ( rawMouseX + window . scrollX - 32 ) / clientWidth ) . writeInt ( rawMouseY + window . scrollY - 32 ) . toBuffer ( ) ) ;
2024-04-20 17:20:23 +01:00
}
2024-04-18 23:18:49 +01:00
}
2024-04-20 17:34:32 +01:00
} else if ( e . key === "n" ) {
if ( ws && ready && selfCursor ) {
localStorage [ "t00mp_cursorStyle" ] = selfCursor . element . style . visibility = selfCursor . element . style . visibility === "hidden" ? "" : "hidden" ;
}
2024-04-26 17:34:34 +01:00
} else if ( e . key === "g" ) {
if ( ws && ready && selfCursor ) {
groupPopper . click ( ) ;
}
2024-04-18 23:18:49 +01:00
}
}
2024-05-07 21:46:52 +01:00
window . onkeydown = ( e ) => {
if ( ! windowContainer && e . key === "F1" ) {
localStorage [ "mpshowfirsttime" ] = "true" ;
createFirstTimeDialog ( ) ;
}
} ;
2024-04-18 23:18:49 +01:00
function lerp ( value1 , value2 , amount ) {
return value1 + ( value2 - value1 ) * amount ;
}
let timeLastFrame = performance . now ( ) ;
let frameDeltaTime = 0 ;
2024-04-20 17:20:23 +01:00
let timeSinceLastPingReset = performance . now ( ) ;
2024-05-08 01:02:18 +01:00
try {
function animate ( ) {
frameDeltaTime = ( performance . now ( ) - timeLastFrame ) * 0.001 ;
if ( ws && ready ) {
if ( currentMouseX !== oldMouseX || currentMouseY !== oldMouseY ) {
if ( ( performance . now ( ) - lastSendTime ) >= 41 ) {
lastSendTime = performance . now ( ) ;
oldMouseX = currentMouseX ;
oldMouseY = currentMouseY ;
2024-05-27 12:56:49 +01:00
ws . send ( createWriter ( Endian . LE , 9 ) . writeUByte ( MessageType . CursorPos ) . writeFloat ( oldMouseX / clientWidth ) . writeInt ( currentMouseY ) . toBuffer ( ) ) ;
2024-05-08 01:02:18 +01:00
}
2024-04-18 23:18:49 +01:00
}
2024-05-27 12:56:49 +01:00
if ( isAfkLocal !== lastSendAfkState ) {
lastSendAfkState = isAfkLocal ;
ws . send ( createWriter ( Endian . LE , 2 ) . writeUByte ( MessageType . HonkShoe ) . writeBool ( isAfkLocal ) . toBuffer ( ) ) ;
}
2024-04-18 23:18:49 +01:00
}
2024-05-08 01:02:18 +01:00
if ( ( performance . now ( ) - timeSinceLastPingReset ) >= 1000 ) {
allowedPings = 10 ;
timeSinceLastPingReset = performance . now ( ) ;
}
remoteClients . forEach ( remoteUser => {
remoteUser . actualX = lerp ( remoteUser . actualX , remoteUser . targetX , 20 * frameDeltaTime ) ;
remoteUser . actualY = lerp ( remoteUser . actualY , remoteUser . targetY , 20 * frameDeltaTime ) ;
remoteUser . updateCursor ( ) ;
} ) ;
requestAnimationFrame ( animate ) ;
timeLastFrame = performance . now ( ) ;
2024-04-18 23:18:49 +01:00
}
2024-05-08 01:02:18 +01:00
animate ( ) ;
} catch ( e ) {
console . error ( e ) ;
2024-04-18 23:18:49 +01:00
}
2024-04-25 10:12:17 +01:00
let windowContainer = null ;
function doConnect ( apiKey ) {
const Buffer = getBufferClass ( ) ;
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Connecting to realtime server..." ) ;
2024-05-07 21:46:52 +01:00
ws = new WebSocket ( windowLocation . includes ( "//localhost:" ) ? "ws://localhost:38195" : "wss://ws.eusv.net/t00mp" ) ;
2024-04-25 10:12:17 +01:00
let keepAliveInterval ;
ws . onopen = ( ) => {
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Connected! Authenticating..." ) ;
2024-04-25 10:12:17 +01:00
otherCursors . innerHTML = "" ;
2024-05-27 12:56:49 +01:00
selfCursor = new RemoteClient ( localStorage [ "t00mp_username" ] , false , true ) ;
2024-04-25 10:12:17 +01:00
selfCursor . probeImage . style . visibility = "hidden" ;
selfCursor . element . style . visibility = localStorage [ "t00mp_cursorStyle" ] ? ? "hidden" ;
selfCursor . hasBeenMoved = true ;
2024-05-27 12:56:49 +01:00
const currentPage = windowLocation . split ( "/" ) . slice ( 2 ) . join ( "/" ) ;
2024-04-25 10:12:17 +01:00
ws . send ( createWriter ( Endian . LE , 4 + apiKey . length + currentPage . length )
2024-05-27 12:56:49 +01:00
. writeUByte ( MessageType . ClientDetails )
2024-04-25 10:12:17 +01:00
. writeShortString ( apiKey )
. writeString ( currentPage )
. toBuffer ( ) ) ;
keepAliveInterval = setInterval ( ( ) => {
ws . send ( keepAlivePacket ) ;
} , 5000 ) ;
}
function onMessage ( buf ) {
const reader = createReader ( Endian . LE , Buffer . from ( buf ) ) ;
switch ( reader . readByte ( ) ) {
case MessageType . Clients :
{
const clientCount = reader . readUShort ( ) ;
for ( let i = 0 ; i < clientCount ; i ++ ) {
const clientId = reader . readUInt ( ) ;
const clientName = reader . readShortString ( ) ;
const clientX = reader . readFloat ( ) ;
const clientY = reader . readInt ( ) ;
2024-05-27 12:56:49 +01:00
const isAfk = reader . readBool ( ) ;
remoteClients . set ( clientId , new RemoteClient ( clientName , isAfk ) ) . rawSetPosInit ( clientX , clientY ) ;
2024-04-25 10:12:17 +01:00
}
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
log ( "RECV" , ` Initial client packet, got ${ clientCount } clients. ` ) ;
}
2024-04-25 10:12:17 +01:00
ready = true ;
if ( windowContainer ) {
windowContainer . remove ( ) ;
windowContainer = null ;
}
2024-04-26 17:34:34 +01:00
if ( ! needsToUpdate ) {
createFirstTimeDialog ( ) ;
}
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Authenticated!" ) ;
2024-04-25 10:12:17 +01:00
break ;
}
case MessageType . ClientJoined :
{
const clientId = reader . readUInt ( ) ;
const clientName = reader . readShortString ( ) ;
2024-05-27 12:56:49 +01:00
remoteClients . set ( clientId , new RemoteClient ( clientName , false ) ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` New client joined page: ${ clientName } ID= ${ clientId } ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-25 10:12:17 +01:00
break ;
}
case MessageType . CursorPos :
{
const clientId = reader . readUInt ( ) ;
if ( remoteClients . has ( clientId ) ) {
const cursorX = reader . readFloat ( ) ;
const cursorY = reader . readInt ( ) ;
remoteClients . get ( clientId ) . rawSetPos ( cursorX , cursorY ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` Cursor position update for ${ clientId } , X= ${ cursorX } , Y= ${ cursorY } ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-25 10:12:17 +01:00
}
break ;
}
case MessageType . ClientLeft :
2024-04-18 23:18:49 +01:00
{
const clientId = reader . readUInt ( ) ;
removeClient ( clientId ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` Client ${ clientId } left or switched pages ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-25 10:12:17 +01:00
break ;
2024-04-18 23:18:49 +01:00
}
case MessageType . Ping :
{
const cursorX = reader . readFloat ( ) ;
const cursorY = reader . readInt ( ) ;
2024-04-20 17:20:23 +01:00
createPing ( cursorX * clientWidth , cursorY ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` Got a ping, X= ${ cursorX } , Y= ${ cursorY } ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-25 10:12:17 +01:00
break ;
}
case MessageType . GroupData :
{
2024-04-26 03:01:06 +01:00
groupUIBase . style = "" ;
groupUsers . innerHTML = "" ;
groupTitle . innerText = reader . readShortString ( ) ;
2024-05-27 12:56:49 +01:00
const groupUserCount = reader . readUShort ( ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` Server sent group information for " ${ groupTitle . innerText } " ( ${ groupUserCount } clients) ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-26 03:01:06 +01:00
for ( let i = 0 ; i < groupUserCount ; i ++ ) {
const groupUsername = reader . readShortString ( ) ;
const groupUserLocation = reader . readString ( ) ;
2024-05-06 15:41:26 +01:00
if ( window . multiprobe _debug ) {
2024-05-27 12:56:49 +01:00
log ( "RECV" , ` [GROUP USER] USERNAME= ${ groupUsername } , LOCATION= ${ groupUserLocation } ` ) ;
2024-05-06 15:41:26 +01:00
}
2024-04-26 03:01:06 +01:00
createGroupUser ( groupUsername , groupUserLocation ) ;
}
2024-04-25 10:12:17 +01:00
break ;
2024-04-18 23:18:49 +01:00
}
2024-05-27 12:56:49 +01:00
case MessageType . HonkShoe :
{
const clientId = reader . readUInt ( ) ;
const isAfk = reader . readBool ( ) ;
if ( remoteClients . has ( clientId ) ) {
remoteClients . get ( clientId ) . setAfk ( isAfk ) ;
if ( window . multiprobe _debug ) {
if ( isAfk ) {
log ( "RECV" , ` Client ${ clientId } went afk ` ) ;
} else {
log ( "RECV" , ` Client ${ clientId } is no longer afk ` ) ;
}
}
}
break ;
}
2024-04-18 23:18:49 +01:00
}
}
ws . onmessage = ( e ) => {
e . data . arrayBuffer ( ) . then ( onMessage ) ;
}
function onCloseAndError ( ) {
if ( keepAliveInterval ) {
clearInterval ( keepAliveInterval ) ;
keepAliveInterval = undefined ;
}
ws = undefined ;
ready = false ;
2024-04-25 02:37:37 +01:00
setTimeout ( ( ) => doConnect ( localStorage [ "mpapikey" ] ) , 5000 ) ;
2024-04-18 23:18:49 +01:00
}
ws . onclose = onCloseAndError ;
2024-05-08 01:02:18 +01:00
ws . onerror = ( e ) => {
console . error ( e ) ;
}
2024-04-18 23:18:49 +01:00
}
2024-04-25 10:12:17 +01:00
function createOnlineDialog ( ) {
const bg = document . createElement ( "div" ) ;
windowContainer = bg ;
2024-05-07 21:46:52 +01:00
bg . style = "z-index:1000000000;position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:rgba(0,0,0,0.5);text-shadow: none!important;font-family: Arial,sans-serif;font-size: unset !important;" ;
2024-04-25 10:12:17 +01:00
const dialog = document . createElement ( "div" ) ;
dialog . style = "position:absolute;top:50%;left:50%;min-width:15rem;background-color:#343434;padding:1rem;transform:translate(-50%,-50%);text-align:center;color:white" ;
bg . appendChild ( dialog ) ;
const title = document . createElement ( "h4" ) ;
title . innerText = "MultiProbe" ;
title . style . marginBottom = "0px" ;
dialog . appendChild ( title ) ;
const subtitle = document . createElement ( "h5" ) ;
subtitle . innerText = ` Logged in as ${ localStorage [ "t00mp_username" ] } ` ;
subtitle . style . marginTop = ".5rem" ;
dialog . appendChild ( subtitle ) ;
const buttons = document . createElement ( "div" ) ;
buttons . style . marginTop = "1rem" ;
2024-04-26 03:01:06 +01:00
const disconnectButton = document . createElement ( "button" ) ;
disconnectButton . innerText = localStorage [ "mpconnectonload" ] === "true" ? "Disconnect" : "Connect" ;
disconnectButton . onclick = ( ) => {
if ( localStorage [ "mpconnectonload" ] === "true" ) {
localStorage [ "mpconnectonload" ] = false ;
if ( ws ) {
ws . close ( ) ;
}
} else {
localStorage [ "mpconnectonload" ] = true ;
doConnect ( localStorage [ "mpapikey" ] ) ;
}
disconnectButton . innerText = localStorage [ "mpconnectonload" ] === "true" ? "Disconnect" : "Connect" ;
} ;
buttons . appendChild ( disconnectButton ) ;
const manageAccountLink = document . createElement ( "a" ) ;
manageAccountLink . style . display = "none" ;
manageAccountLink . href = "https://multiprobe.eusv.net/" ;
manageAccountLink . target = "_blank" ;
buttons . appendChild ( manageAccountLink ) ;
const manageAccount = document . createElement ( "button" ) ;
manageAccount . style . marginLeft = "1rem" ;
manageAccount . innerText = "Manage Account" ;
manageAccount . onclick = ( ) => {
manageAccountLink . click ( ) ;
}
buttons . appendChild ( manageAccount ) ;
const closeButton = document . createElement ( "button" ) ;
closeButton . innerText = "Close" ;
closeButton . onclick = ( ) => {
bg . remove ( ) ;
windowContainer = null ;
} ;
closeButton . style . marginLeft = "1rem" ;
buttons . appendChild ( closeButton ) ;
2024-04-25 10:12:17 +01:00
dialog . appendChild ( buttons ) ;
document . body . appendChild ( bg ) ;
}
2024-04-26 10:21:27 +01:00
function createUpdateDialog ( versionNumber ) {
const bg = document . createElement ( "div" ) ;
2024-05-07 21:46:52 +01:00
bg . style = "z-index:1000000000;position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:rgba(0,0,0,0.5);text-shadow: none!important;font-family: Arial,sans-serif;font-size: unset !important;" ;
2024-04-26 10:21:27 +01:00
const dialog = document . createElement ( "div" ) ;
dialog . style = "position:absolute;top:50%;left:50%;min-width:15rem;background-color:#343434;padding:1rem;transform:translate(-50%,-50%);text-align:center;color:white" ;
bg . appendChild ( dialog ) ;
const title = document . createElement ( "h4" ) ;
title . innerText = "An update is available!" ;
title . style . marginBottom = "0px" ;
dialog . appendChild ( title ) ;
const updateText = document . createElement ( "p" ) ;
updateText . innerHTML = ` <a class="mplink" href="https://git.eusv.net/tgpholly/t00-multiuser/raw/branch/master/client/Terminal-00-Multiuser.user.js? ${ Date . now ( ) } ">Please click here to update to the latest version.</a><br>This takes less than a few seconds to do and ensures you can continue to use MultiProbe.<br><br>Current Version: ${ USERSCRIPT _VERSION _RAW } <br>New Version: ${ versionNumber } ` ;
dialog . appendChild ( updateText ) ;
const buttons = document . createElement ( "div" ) ;
buttons . style . marginTop = "1rem" ;
const gotIt = document . createElement ( "button" ) ;
gotIt . onclick = ( ) => {
bg . remove ( ) ;
}
gotIt . innerText = "Later" ;
buttons . appendChild ( gotIt ) ;
dialog . appendChild ( buttons ) ;
document . body . appendChild ( bg ) ;
}
2024-04-25 10:12:17 +01:00
function createFirstTimeDialog ( ) {
if ( localStorage [ "mpshowfirsttime" ] && localStorage [ "mpshowfirsttime" ] === "false" ) {
return ;
}
const bg = document . createElement ( "div" ) ;
windowContainer = bg ;
2024-05-07 21:46:52 +01:00
bg . style = "z-index:1000000000;position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:rgba(0,0,0,0.5);text-shadow: none!important;font-family: Arial,sans-serif;font-size: unset !important;" ;
2024-04-25 10:12:17 +01:00
const dialog = document . createElement ( "div" ) ;
dialog . style = "position:absolute;top:50%;left:50%;min-width:15rem;background-color:#343434;padding:1rem;transform:translate(-50%,-50%);text-align:center;color:white" ;
bg . appendChild ( dialog ) ;
const title = document . createElement ( "h4" ) ;
title . innerText = "Welcome to MultiProbe!" ;
title . style . marginBottom = "0px" ;
dialog . appendChild ( title ) ;
const actionList = document . createElement ( "ul" ) ;
actionList . style . textAlign = "start" ;
dialog . appendChild ( actionList ) ;
const pingLI = document . createElement ( "li" ) ;
pingLI . innerHTML = "You can create a \"ping\" at your cursor position by pressing <kbd>P</kbd>" ;
actionList . appendChild ( pingLI ) ;
const nameLI = document . createElement ( "li" ) ;
nameLI . innerHTML = "You can show/hide your own name for screenshots by pressing <kbd>N</kbd>" ;
actionList . appendChild ( nameLI ) ;
2024-04-26 17:34:34 +01:00
const groupLI = document . createElement ( "li" ) ;
groupLI . innerHTML = "You can show/hide the party sidebar if you are in one by pressing <kbd>G</kbd>" ;
actionList . appendChild ( groupLI ) ;
2024-05-07 21:46:52 +01:00
const helpTip = document . createElement ( "li" ) ;
helpTip . innerHTML = "If you press <kbd>F1</kbd> you can open this help again." ;
actionList . appendChild ( helpTip ) ;
2024-04-25 10:12:17 +01:00
const buttons = document . createElement ( "div" ) ;
buttons . style . marginTop = "1rem" ;
const gotIt = document . createElement ( "button" ) ;
gotIt . onclick = ( ) => {
localStorage [ "mpshowfirsttime" ] = "false" ;
bg . remove ( ) ;
windowContainer = null ;
}
gotIt . innerText = "Got It" ;
buttons . appendChild ( gotIt ) ;
dialog . appendChild ( buttons ) ;
document . body . appendChild ( bg ) ;
}
2024-04-25 02:37:37 +01:00
function createLoginDialog ( ) {
2024-04-18 23:18:49 +01:00
const bg = document . createElement ( "div" ) ;
2024-04-25 10:12:17 +01:00
windowContainer = bg ;
2024-05-07 21:46:52 +01:00
bg . style = "z-index:1000000000;position:fixed;top:0px;left:0px;width:100%;height:100%;background-color:rgba(0,0,0,0.5);text-shadow: none!important;font-family: Arial,sans-serif;font-size: unset !important;" ;
2024-04-18 23:18:49 +01:00
const dialog = document . createElement ( "div" ) ;
2024-04-25 02:37:37 +01:00
dialog . style = "position:absolute;top:50%;left:50%;width:15rem;background-color:#343434;padding-bottom:1rem;transform:translate(-50%,-50%);text-align:center;color:white" ;
2024-04-18 23:18:49 +01:00
bg . appendChild ( dialog ) ;
const title = document . createElement ( "h4" ) ;
2024-04-25 02:37:37 +01:00
title . innerText = "MultiProbe" ;
2024-04-26 03:01:06 +01:00
title . style . marginBottom = ".5rem" ;
2024-04-18 23:18:49 +01:00
dialog . appendChild ( title ) ;
2024-04-26 03:01:06 +01:00
const manageAccountLink = document . createElement ( "a" ) ;
manageAccountLink . className = "mplink" ;
manageAccountLink . href = "https://multiprobe.eusv.net/" ;
manageAccountLink . innerHTML = "Click here to create an account<br><br>" ;
manageAccountLink . target = "_blank" ;
manageAccountLink . style . marginLeft = manageAccountLink . style . marginRight = ".5rem" ;
dialog . appendChild ( manageAccountLink ) ;
2024-04-25 02:37:37 +01:00
const loginForm = document . createElement ( "form" ) ;
dialog . appendChild ( loginForm ) ;
2024-04-18 23:18:49 +01:00
const username = document . createElement ( "input" ) ;
username . placeholder = "Enter Username" ;
username . maxLength = 32 ;
username . style . width = "12rem" ;
2024-04-25 02:37:37 +01:00
username . name = "username" ;
loginForm . appendChild ( username ) ;
const password = document . createElement ( "input" ) ;
password . type = "password" ;
password . style . marginTop = ".5rem" ;
password . placeholder = "Enter Password" ;
password . style . width = "12rem" ;
password . name = "password" ;
loginForm . appendChild ( password ) ;
2024-04-18 23:18:49 +01:00
const buttons = document . createElement ( "div" ) ;
buttons . style . marginTop = "1rem" ;
2024-04-25 02:37:37 +01:00
loginForm . appendChild ( buttons ) ;
2024-04-18 23:18:49 +01:00
const submitButton = document . createElement ( "button" ) ;
2024-04-25 02:37:37 +01:00
submitButton . innerText = "Connect" ;
submitButton . type = "submit" ;
2024-04-18 23:18:49 +01:00
buttons . appendChild ( submitButton ) ;
const doNotButton = document . createElement ( "button" ) ;
doNotButton . innerText = "Close" ;
doNotButton . onclick = ( ) => bg . remove ( ) ;
doNotButton . style . marginLeft = "1rem" ;
buttons . appendChild ( doNotButton ) ;
2024-04-25 02:37:37 +01:00
loginForm . onsubmit = ( e ) => {
e . preventDefault ( ) ;
username . disabled = true ;
password . disabled = true ;
submitButton . disabled = true ;
doNotButton . disabled = true ;
2024-04-25 10:12:17 +01:00
title . innerText = "Authenticating..." ;
2024-05-07 21:46:52 +01:00
fetch ( windowLocation . replace ( "127.0.0.1" , "localhost" ) . includes ( "//localhost:" ) ? "http://localhost:38194/api/login" : "https://multiprobe.eusv.net/api/login" , {
2024-04-25 02:37:37 +01:00
method : "POST" ,
body : ` username= ${ encodeURIComponent ( username . value ) } &password= ${ encodeURIComponent ( password . value ) } ` ,
headers : {
"Content-Type" : "application/x-www-form-urlencoded"
}
} ) . then ( res => {
if ( res . status === 200 ) {
res . text ( ) . then ( apiKey => {
2024-04-25 10:12:17 +01:00
title . innerText = "Connecting to realtime server..." ;
2024-04-25 02:37:37 +01:00
localStorage [ "t00mp_username" ] = username . value ;
localStorage [ "mpapikey" ] = apiKey ;
doConnect ( apiKey ) ;
} ) ;
} else {
2024-04-25 10:12:17 +01:00
title . innerText = "Incorrect Login" ;
2024-04-25 02:37:37 +01:00
username . disabled = false ;
password . disabled = false ;
submitButton . disabled = false ;
doNotButton . disabled = false ;
}
} ) . catch ( err => {
console . error ( err ) ;
username . disabled = false ;
password . disabled = false ;
submitButton . disabled = false ;
doNotButton . disabled = false ;
} ) ;
}
2024-04-18 23:18:49 +01:00
document . body . appendChild ( bg ) ;
}
const openMenuButton = document . createElement ( "button" ) ;
2024-05-07 21:46:52 +01:00
openMenuButton . style = "opacity:0.25;position:fixed;top:0px;right:0px;z-index:9999999;margin:4px;background-color:black;color:white;border:1px solid white;text-shadow: none!important;font-family: Arial,sans-serif;font-size: unset !important;" ;
2024-04-25 02:37:37 +01:00
openMenuButton . innerText = "MultiProbe Menu" ;
2024-04-25 10:12:17 +01:00
openMenuButton . onclick = ( ) => {
2024-04-26 03:01:06 +01:00
if ( ws || localStorage [ "mpapikey" ] ) {
2024-04-25 10:12:17 +01:00
createOnlineDialog ( ) ;
} else {
createLoginDialog ( ) ;
}
} ;
2024-04-18 23:18:49 +01:00
document . body . appendChild ( openMenuButton ) ;
2024-04-26 03:01:06 +01:00
if ( localStorage [ "mpapikey" ] && localStorage [ "mpapikey" ] !== "" && localStorage [ "mpconnectonload" ] === "true" ) {
2024-04-25 02:37:37 +01:00
doConnect ( localStorage [ "mpapikey" ] ) ;
2024-04-18 23:18:49 +01:00
}
2024-05-07 22:17:30 +01:00
console . log ( "[MP] Init complete." ) ;
2024-04-18 23:18:49 +01:00
} ) ( ) ;