Changed userscript functionality

We now are checking for the GM_info object used by userscripts, and using location.href to run the script in the page context if it's found.
This commit is contained in:
FlamedDogo99 2024-06-28 09:50:06 -06:00
parent cdec31ab74
commit ef03fcb4b2

View File

@ -6,58 +6,65 @@
// @downloadURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js
// @license Apache License 2.0 - http://www.apache.org/licenses/
// @match https://eaglercraft.com/mc/*
// @version 3.0.5b
// @version 3.0.6
// @updateURL https://raw.githubusercontent.com/FlamedDogo99/EaglerMobile/main/eaglermobile.user.js
// @run-at document-start
// @grant none
// ==/UserScript==
// Removed brainless unsafeWindow
console.log("Eagler Mobile v3.0.5b")
// TODO: remove the mobile check is implement the dynamic enabling and disabling of individual features
function isMobile() {
console.log("Eagler Mobile v3.0.6");
// Check for object defined by most userscript applications, and run the script in the page context if so
if (typeof GM_info !== "undefined") {
location.href = "javascript:(" + encodeURI(main) + ")();";
} else {
main();
}
// TODO: remove the mobile check and implement the dynamic enabling and disabling of individual features
function main() {
function isMobile() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
if(!isMobile()) {
}
if(!isMobile()) {
alert("WARNING: This script was created for mobile, and may break functionality in non-mobile browsers!");
}
// TODO: consolidate all of these into a single object?
window.crouchLock = false; // Used for crouch mobile control
window.sprintLock = false; // Used for sprint mobile control
window.keyboardFix = false; // keyboardFix ? "Standard Keyboard" : "Compatibility Mode"
window.inputFix = false; // If true, Duplicate Mode
window.blockNextInput = false; // Used for Duplicate Mode
window.hiddenInputFocused = false; // Used for keyboard display on mobile
window.canvasTouchMode = 0; // Used for canvas touch handling
/*
}
// TODO: consolidate all of these into a single object?
window.crouchLock = false; // Used for crouch mobile control
window.sprintLock = false; // Used for sprint mobile control
window.keyboardFix = false; // keyboardFix ? "Standard Keyboard" : "Compatibility Mode"
window.inputFix = false; // If true, Duplicate Mode
window.blockNextInput = false; // Used for Duplicate Mode
window.hiddenInputFocused = false; // Used for keyboard display on mobile
window.canvasTouchMode = 0; // Used for canvas touch handling
/*
0 Idle
1 Touch initiated
2 Primary touch
3 Secondary touch
4 Scroll
5 Finished
*/
window.canvasTouchStartX = null;
window.canvasTouchStartY = null;
window.canvasTouchPreviousX = null;
window.canvasTouchPreviousY = null;
window.canvasPrimaryID = null;
window.buttonTouchStartX = null;
*/
window.canvasTouchStartX = null;
window.canvasTouchStartY = null;
window.canvasTouchPreviousX = null;
window.canvasTouchPreviousY = null;
window.canvasPrimaryID = null;
window.buttonTouchStartX = null;
// charCodeAt is designed for unicode characters, and doesn't match the behavior of the keyCodes used by KeyboardEvents, thus necessitating this function
String.prototype.toKeyCode = function() {
// charCodeAt is designed for unicode characters, and doesn't match the behavior of the keyCodes used by KeyboardEvents, thus necessitating this function
String.prototype.toKeyCode = function() {
const keyCodeList = {"0": 48, "1": 49, "2": 50, "3": 51, "4": 52, "5": 53, "6": 54, "7": 55, "8": 56, "9": 57, "backspace": 8, "tab": 9, "enter": 13, "shift": 16, "ctrl": 17, "alt": 18, "pause_break": 19, "caps_lock": 20, "escape": 27, " ": 32, "page_up": 33, "page_down": 34, "end": 35, "home": 36, "left_arrow": 37, "up_arrow": 38, "right_arrow": 39, "down_arrow": 40, "insert": 45, "delete": 46, "a": 65, "b": 66, "c": 67, "d": 68, "e": 69, "f": 70, "g": 71, "h": 72, "i": 73, "j": 74, "k": 75, "l": 76, "m": 77, "n": 78, "o": 79, "p": 80, "q": 81, "r": 82, "s": 83, "t": 84, "u": 85, "v": 86, "w": 87, "x": 88, "y": 89, "z": 90, "left_window_key": 91, "right_window_key": 92, "select_key": 93, "numpad_0": 96, "numpad_1": 97, "numpad_2": 98, "numpad_3": 99, "numpad_4": 100, "numpad_5": 101, "numpad_6": 102, "numpad_7": 103, "numpad_8": 104, "numpad_9": 105, "*": 106, "+": 107, "-": 109, ".": 110, "/": 111, "f1": 112, "f2": 113, "f3": 114, "f4": 115, "f5": 116, "f6": 117, "f7": 118, "f8": 119, "f9": 120, "f10": 121, "f11": 122, "f12": 123, "num_lock": 144, "scroll_lock": 145, ";": 186, "=": 187, ",": 188, "-": 189, ".": 190, "/": 191, "\u0060": 192, "[": 219, "\u005C": 220, "]": 221, "\u0022": 222};
return keyCodeList[this];
}
// Overrides the addEventListener behavior to all code injection on keydown event listeners. This function has thrown TypeErrors on some Android devices because fn is not recognized as a function
// This is used by Compatibility Mode to block invalid keyEvents
const _addEventListener = EventTarget.prototype.addEventListener;
Object.defineProperty(EventTarget.prototype, "addEventListener", {
}
// Overrides the addEventListener behavior to all code injection on keydown event listeners. This function has thrown TypeErrors on some Android devices because fn is not recognized as a function
// This is used by Compatibility Mode to block invalid keyEvents
const _addEventListener = EventTarget.prototype.addEventListener;
Object.defineProperty(EventTarget.prototype, "addEventListener", {
value: function (type, fn, ...rest) {
if(type == 'keydown') { // Check if a keydown event is being added
_addEventListener.call(this, type, function(...args) {
@ -70,21 +77,21 @@ Object.defineProperty(EventTarget.prototype, "addEventListener", {
_addEventListener.call(this, type, fn, ...rest);
}
}
});
// Overrides preventDefault, because on some (Android) devices you couldn't type into hiddenInput
const _preventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function(shouldBypass) {
});
// Overrides preventDefault, because on some (Android) devices you couldn't type into hiddenInput
const _preventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function(shouldBypass) {
if(document.activeElement.id != "hiddenInput" || shouldBypass) { // activeElement is what element is currently focused
this._preventDefault = _preventDefault;
this._preventDefault();
}
}
// Key and mouse events
// Note: the client must have the key, keyCode, and which parameters defined or it will crash
// Note: for text inputs, the client only reads from the "key" paramater
// * an exception to this appears to be the shift and backspace key
// Note: for inGame inputs, the client only reads from the "keyCode character"
function keyEvent(name, state) {
}
// Key and mouse events
// Note: the client must have the key, keyCode, and which parameters defined or it will crash
// Note: for text inputs, the client only reads from the "key" paramater
// * an exception to this appears to be the shift and backspace key
// Note: for inGame inputs, the client only reads from the "keyCode character"
function keyEvent(name, state) {
const charCode = name.toKeyCode();
let evt = new KeyboardEvent(state, {
"key": name,
@ -92,8 +99,8 @@ function keyEvent(name, state) {
"which": charCode
});
window.dispatchEvent(evt);
}
function mouseEvent(number, state, element, event = {"clientX": 0, "clientY" : 0, "screenX": 0, "screenY": 0}) {
}
function mouseEvent(number, state, element, event = {"clientX": 0, "clientY" : 0, "screenX": 0, "screenY": 0}) {
element.dispatchEvent(new PointerEvent(state, {
"button": number,
"buttons": number,
@ -102,76 +109,76 @@ function mouseEvent(number, state, element, event = {"clientX": 0, "clientY" : 0
"screenX": event.screenX,
"screenY": event.screenY
}));
}
function wheelEvent(element, delta) {
}
function wheelEvent(element, delta) {
element.dispatchEvent(new WheelEvent("wheel", {
"wheelDeltaY": delta
}));
}
function setButtonVisibility(pointerLocked) {
}
function setButtonVisibility(pointerLocked) {
let inGameStyle = document.getElementById('inGameStyle');
let inMenuStyle = document.getElementById('inMenuStyle');
inGameStyle.disabled = pointerLocked;
inMenuStyle.disabled = !pointerLocked;
}
// POINTERLOCK
// When requestpointerlock is called, this dispatches an event, saves the requested element to window.fakelock, and unhides the touch controls
window.fakelock = null;
}
// POINTERLOCK
// When requestpointerlock is called, this dispatches an event, saves the requested element to window.fakelock, and unhides the touch controls
window.fakelock = null;
Object.defineProperty(Element.prototype, "requestPointerLock", {
Object.defineProperty(Element.prototype, "requestPointerLock", {
value: function() {
window.fakelock = this
document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(true);
return true
}
});
});
// Makes pointerLockElement return window.fakelock
Object.defineProperty(Document.prototype, "pointerLockElement", {
// Makes pointerLockElement return window.fakelock
Object.defineProperty(Document.prototype, "pointerLockElement", {
get: function() {
return window.fakelock;
}
});
// When exitPointerLock is called, this dispatches an event, clears the
Object.defineProperty(Document.prototype, "exitPointerLock", {
});
// When exitPointerLock is called, this dispatches an event, clears the
Object.defineProperty(Document.prototype, "exitPointerLock", {
value: function() {
window.fakelock = null
document.dispatchEvent(new Event('pointerlockchange'));
setButtonVisibility(false);
return true
}
});
});
// FULLSCREEN
window.fakefull = null;
// Stops the client from crashing when fullscreen is requested
Object.defineProperty(Element.prototype, "requestFullscreen", {
// FULLSCREEN
window.fakefull = null;
// Stops the client from crashing when fullscreen is requested
Object.defineProperty(Element.prototype, "requestFullscreen", {
value: function() {
window.fakefull = this
document.dispatchEvent(new Event('fullscreenchange'));
return true
}
});
Object.defineProperty(document, "fullscreenElement", {
});
Object.defineProperty(document, "fullscreenElement", {
get: function() {
return window.fakefull;
}
});
Object.defineProperty(Document.prototype, "exitFullscreen", {
});
Object.defineProperty(Document.prototype, "exitFullscreen", {
value: function() {
window.fakefull = null
document.dispatchEvent(new Event('fullscreenchange'));
return true
}
});
});
// FILE UPLOADING
// Safari doesn't recognize the element.click() used to display the file uploader as an action performed by the user, so it ignores it.
// This hijacks the element.createElement() function to add the file upload to the DOM, so the user can manually press the button again.
const _createElement = document.createElement;
document.createElement = function(type, ignore) {
// FILE UPLOADING
// Safari doesn't recognize the element.click() used to display the file uploader as an action performed by the user, so it ignores it.
// This hijacks the element.createElement() function to add the file upload to the DOM, so the user can manually press the button again.
const _createElement = document.createElement;
document.createElement = function(type, ignore) {
this._createElement = _createElement;
var element = this._createElement(type);
if(type == "input" && !ignore) { // We set the ingore flag to true when we create the hiddenInput
@ -190,28 +197,28 @@ document.createElement = function(type, ignore) {
document.body.appendChild(element);
}
return element;
}
}
// Lazy way to hide touch controls through CSS.
let inGameStyle = document.createElement("style");
inGameStyle.id = "inGameStyle";
inGameStyle.textContent = `
// Lazy way to hide touch controls through CSS.
let inGameStyle = document.createElement("style");
inGameStyle.id = "inGameStyle";
inGameStyle.textContent = `
.inGame {
display: none;
}`;
document.documentElement.appendChild(inGameStyle);
document.documentElement.appendChild(inGameStyle);
let inMenuStyle = document.createElement("style");
inMenuStyle.id = "inMenuStyle";
inMenuStyle.textContent = `
let inMenuStyle = document.createElement("style");
inMenuStyle.id = "inMenuStyle";
inMenuStyle.textContent = `
.inMenu {
display: none;
}`;
document.documentElement.appendChild(inMenuStyle);
document.documentElement.appendChild(inMenuStyle);
// The canvas is created by the client after it finishes unzipping and loading. When the canvas is created, this applies any necessary event listeners and creates buttons
function waitForElm(selector) {
// The canvas is created by the client after it finishes unzipping and loading. When the canvas is created, this applies any necessary event listeners and creates buttons
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
@ -227,8 +234,8 @@ function waitForElm(selector) {
subtree: true
});
});
}
function createTouchButton(buttonClass, buttonDisplay, elementName) {
}
function createTouchButton(buttonClass, buttonDisplay, elementName) {
var touchButton = document.createElement(elementName ?? 'button', true);
touchButton.classList.add(buttonClass);
touchButton.classList.add(buttonDisplay);
@ -236,11 +243,11 @@ function createTouchButton(buttonClass, buttonDisplay, elementName) {
touchButton.addEventListener("touchmove", function(e){e.preventDefault()}, false);
touchButton.addEventListener("contextmenu", function(e){e.preventDefault()});
return touchButton;
}
}
waitForElm('canvas').then(() => {insertCanvasElements()});
function insertCanvasElements() {
waitForElm('canvas').then(() => {insertCanvasElements()});
function insertCanvasElements() {
// Translates touchmove events to mousemove events when inGame, and touchmove events to wheele events when inMenu
var canvas = document.querySelector('canvas');
canvas.addEventListener("touchstart", function(e) {
@ -644,10 +651,10 @@ function insertCanvasElements() {
keyEvent("3", "keyup");
}, false);
document.body.appendChild(coordinatesButton);
}
// CSS for touch screen buttons, along with fixing iOS's issues with 100vh ignoring the naviagtion bar, and actually disabling zoom because safari ignores user-scalable=no :(
let customStyle = document.createElement("style");
customStyle.textContent = `
}
// CSS for touch screen buttons, along with fixing iOS's issues with 100vh ignoring the naviagtion bar, and actually disabling zoom because safari ignores user-scalable=no :(
let customStyle = document.createElement("style");
customStyle.textContent = `
.mobileControl, .mobileControl:active, .mobileControl.active{
position: absolute;
width: 10vh;
@ -862,4 +869,5 @@ customStyle.textContent = `
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAFy2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS41LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6ZXhpZj0iaHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8iCiAgICB4bWxuczpwaG90b3Nob3A9Imh0dHA6Ly9ucy5hZG9iZS5jb20vcGhvdG9zaG9wLzEuMC8iCiAgICB4bWxuczp0aWZmPSJodHRwOi8vbnMuYWRvYmUuY29tL3RpZmYvMS4wLyIKICAgIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIKICAgIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIgogICAgeG1sbnM6c3RFdnQ9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZUV2ZW50IyIKICAgZXhpZjpDb2xvclNwYWNlPSIxIgogICBleGlmOlBpeGVsWERpbWVuc2lvbj0iMTgiCiAgIGV4aWY6UGl4ZWxZRGltZW5zaW9uPSIxOCIKICAgcGhvdG9zaG9wOkNvbG9yTW9kZT0iMyIKICAgcGhvdG9zaG9wOklDQ1Byb2ZpbGU9InNSR0IgSUVDNjE5NjYtMi4xIgogICB0aWZmOkltYWdlTGVuZ3RoPSIxOCIKICAgdGlmZjpJbWFnZVdpZHRoPSIxOCIKICAgdGlmZjpSZXNvbHV0aW9uVW5pdD0iMiIKICAgdGlmZjpYUmVzb2x1dGlvbj0iNzIvMSIKICAgdGlmZjpZUmVzb2x1dGlvbj0iNzIvMSIKICAgeG1wOk1ldGFkYXRhRGF0ZT0iMjAyNC0wNi0wMVQxOTo0Njo0NS0wNTowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMjQtMDYtMDFUMTk6NDY6NDUtMDU6MDAiPgogICA8eG1wTU06SGlzdG9yeT4KICAgIDxyZGY6U2VxPgogICAgIDxyZGY6bGkKICAgICAgeG1wTU06YWN0aW9uPSJwcm9kdWNlZCIKICAgICAgeG1wTU06c29mdHdhcmVBZ2VudD0iQWZmaW5pdHkgUGhvdG8gMiAyLjUuMSIKICAgICAgeG1wTU06d2hlbj0iMjAyNC0wNS0zMVQwOTozMzoxNi0wNTowMCIvPgogICAgIDxyZGY6bGkKICAgICAgeG1wTU06YWN0aW9uPSJwcm9kdWNlZCIKICAgICAgeG1wTU06c29mdHdhcmVBZ2VudD0iQWZmaW5pdHkgUGhvdG8gMiAyLjUuMSIKICAgICAgeG1wTU06d2hlbj0iMjAyNC0wNS0zMVQwOTo1MTo0My0wNTowMCIvPgogICAgIDxyZGY6bGkKICAgICAgc3RFdnQ6YWN0aW9uPSJwcm9kdWNlZCIKICAgICAgc3RFdnQ6c29mdHdhcmVBZ2VudD0iQWZmaW5pdHkgUGhvdG8gMiAyLjUuMSIKICAgICAgc3RFdnQ6d2hlbj0iMjAyNC0wNi0wMVQxOTo0Njo0NS0wNTowMCIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+3ivAWwAAAYBpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAACiRdZHPK0RRFMc/ZvyK0SgWFhaThpWRHzWxUUZCSRqjDDYz1/xQM+P13pNkq2wVJTZ+LfgL2CprpYiUrGdNbJie8+ZNjWTO7Z77ud97zunec8EVyaisUd0L2Zyph8dDvvnogq8uTy1VuKnHH1OGNjIzM0VF+3yUWLH7gF2rcty/1ricMBRU1QsPK003hSeEp9ZNzeY94VaVji0LXwh363JB4Qdbjzuctznl8LfNeiQ8Cq5mYV/qF8d/sUrrWWF5Of5sZk2V7mO/xJPIzc3K2iGzHYMw44TwMckYowTpY0h8kAD99MiOCvm9xfxpViVXidfYQGeFFGlMukVdk+oJWZOiJ2Rk2LD7/7evRnKg36nuCUHNq2W9d0LdLhR2LOvrxLIKp+B+getcOX/1GAY/RN8pa/4j8G7B5U1Zi+/D1Ta0PWsxPVaU3DJdySS8nUNTFFruoGHR6VnpnLMniGzKV93CwSF0Sbx36QfytWex+zpwggAAAAlwSFlzAAALEwAACxMBAJqcGAAAAM9JREFUOI2t1DEKwjAYhuG34mF6ja4iUicDIjjXScSDFIReIc4ijr1Cu/USJkeoi6lVm9TUfksgJA/fX0pgpATPtf7XCQwipRwkCCGaRrVBqqryQsIwbLCJ2fRFPu9MHOc6czzsyfP8a3/qAwDM5guiKPKHDABwud6s55yjFUX5hmRZ1tmmFwJYb7bOJibW0dptpDyjtbK2cUImWisAJ2KFiqL8GXBCfWN0pfnY5nf3adG+EwB1HC8RYuXVwCRJdih1f42WpqdBULsRjPAePQBKokYW6r1DQwAAAABJRU5ErkJggg==");
}
`;
document.documentElement.appendChild(customStyle);
document.documentElement.appendChild(customStyle);
}