waves/public/assets/g/13eagmob/index.html
2025-04-17 20:43:10 -05:00

660 lines
44 KiB
HTML

<!DOCTYPE html>
<html>
<head>
<title>Eaglercraft Singleplayer</title>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="A version of Eaglercraft with both singleplayer and multiplayer. Based on Minecraft Beta 1.3, you can play singleplayer and multiplayer in any web browser and your worlds will be saved to your browser's local storage. Works on all chromebooks, you can export and import your worlds to make backups or move worlds to a different computer." />
<meta name="keywords" content="minecraft, applet, singleplayer, chromebook, lax1dude, games, eaglercraft, ealgercraft singleplayer, eagler" />
<meta name="author" content="LAX1DUDE" />
<meta property="og:title" content="Eaglercraft Singleplayer" />
<meta property="og:locale" content="en-US" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://media.discordapp.net/attachments/378764518081429506/982903386380853258/screenshot_singleplayer_small.png" />
<meta property="og:description" content="A version of Eaglercraft with both singleplayer and multiplayer. Based on Minecraft Beta 1.3, you can play singleplayer and multiplayer in any web browser and your worlds will be saved to your browser's local storage. Works on all chromebooks, you can export and import your worlds to make backups or move worlds to a different computer." />
<!-- Change this: <meta property="og:url" content="https://g.eags.us/eaglercraft/" /> -->
<script type="text/javascript" src="classes.js"></script>
<script type="text/javascript">
function isMobile() {
try {
document.createEvent("TouchEvent");
return true;
} catch (e) {
return false;
}
}
if(!isMobile()) {
alert("WARNING: This script was created for mobile, and may break functionality in non-mobile browsers!");
}
window.keyboardEnabled = false;
window.crouchLock = false;
window.sprintLock = false;
window.keyboardFix = false; // temporarily set to true until I can figure out whats going wrong with the event listener in charge of switching it
// Used for changing touchmove events to mousemove events
var previousTouchX = null;
var previousTouchY = null;
var startTouchX = null;
// better charCodeAt 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, "`": 192, "[": 219, "\\": 220, "]": 221, "\"": 222};
return keyCodeList[this];
}
// Ignores keydown events that don't have the isValid parameter set to true
const _addEventListener = EventTarget.prototype.addEventListener;
Object.defineProperty(EventTarget.prototype, "addEventListener", {
value: function (type, fn, ...rest) {
if(type == 'keydown') {
_addEventListener.call(this, type, function(...args) {
if(!args[0].isValid && window.keyboardFix) {
return;
}
return fn.apply(this, args);
}, ...rest);
} else {
_addEventListener.call(this, type, fn, ...rest);
}
}
});
// Allows typing in #hiddenInput
const _preventDefault = Event.prototype.preventDefault;
Event.prototype.preventDefault = function() {
if(document.activeElement.id != "hiddenInput") {
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) {
const charCode = name.toKeyCode();
let evt = new KeyboardEvent(state, {
key: name,
keyCode: charCode,
which: charCode
});
evt.isValid = true; // Disables fix for bad keyboard input
window.dispatchEvent(evt);
}
function mouseEvent(number, state, canvas) {
canvas.dispatchEvent(new PointerEvent(state, {"button": number}))
}
function wheelEvent(canvas, delta) {
canvas.dispatchEvent(new WheelEvent("wheel", {
"wheelDeltaY": delta
}));
}
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;
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", {
get: function() {
return window.fakelock;
}
});
// 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", {
value: function() {
window.fakefull = this
document.dispatchEvent(new Event('fullscreenchange'));
return true
}
});
Object.defineProperty(document, "fullscreenElement", {
get: function() {
return window.fakefull;
}
});
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) {
this._createElement = _createElement;
var element = this._createElement(type);
if(type == "input" && !ignore) {
document.querySelectorAll('#fileUpload').forEach(e => e.parentNode.removeChild(e));
element.id = "fileUpload";
element.addEventListener('change', function(e) {
element.hidden = true;
element.style.display = "none";
}, {passive: false, once: true});
window.addEventListener('focus', function(e) {
setTimeout(() => {
element.hidden = true;
element.style.display = "none";
}, 300)
}, { once: true })
document.body.appendChild(element);
}
return element;
}
// 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);
let inMenuStyle = document.createElement("style");
inMenuStyle.id = "inMenuStyle";
inMenuStyle.textContent = `
.inMenu {
display: none;
}`;
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
function waitForElm(selector) {
return new Promise(resolve => {
if (document.querySelector(selector)) {
return resolve(document.querySelector(selector));
}
const observer = new MutationObserver(mutations => {
if (document.querySelector(selector)) {
observer.disconnect();
resolve(document.querySelector(selector));
}
});
observer.observe(document.documentElement, {
childList: true,
subtree: true
});
});
}
function createTouchButton(buttonClass, buttonDisplay, elementName) {
var touchButton = document.createElement(elementName ?? 'button', true);
touchButton.classList.add(buttonClass);
touchButton.classList.add(buttonDisplay);
touchButton.classList.add("mobileControl");
touchButton.addEventListener("touchmove", function(e){e.preventDefault()}, false);
return touchButton;
}
function toggleKeyboard() {
const keyboardInput = document.getElementById('hiddenInput');
if (window.keyboardEnabled) {
window.keyboardEnabled = false;
keyboardInput.blur();
} else {
window.keyboardEnabled = true;
keyboardInput.select();
}
}
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("touchmove", function(e) {
e.preventDefault();
const touch = e.targetTouches[0]; // We can get away with this because every other touch event will be on different elements
if (!previousTouchX) {
previousTouchX = touch.pageX;
previousTouchY = touch.pageY;
}
e.movementX = touch.pageX - previousTouchX;
e.movementY = touch.pageY - previousTouchY;
var evt = window.fakelock ? new MouseEvent("mousemove", {movementX: e.movementX, movementY: e.movementY}) : new WheelEvent("wheel", {"wheelDeltaY": e.movementY});
canvas.dispatchEvent(evt);
previousTouchX = touch.pageX;
previousTouchY = touch.pageY;
}, false);
canvas.addEventListener("touchend", function(e) {
previousTouchX = null;
previousTouchY = null;
}, false)
//Updates button visibility on load
setButtonVisibility(window.fakelock != null);
// Adds all of the touch screen controls
// Theres probably a better way to do this but this works for now
let strafeRightButton = createTouchButton("strafeRightButton", "inGame", "div");
strafeRightButton.classList.add("strafeSize");
strafeRightButton.style.cssText = "left:24vh;bottom:22vh;"
document.body.appendChild(strafeRightButton);
let strafeLeftButton = createTouchButton("strafeLeftButton", "inGame", "div");
strafeLeftButton.classList.add("strafeSize");
strafeLeftButton.style.cssText = "left:5.5vh;bottom:22vh;"
document.body.appendChild(strafeLeftButton);
let forwardButton = createTouchButton("forwardButton", "inGame", "div");
forwardButton.style.cssText = "left:14vh;bottom:22vh;"
forwardButton.addEventListener("touchstart", function(e){
keyEvent("w", "keydown");
strafeRightButton.classList.remove("hide");
strafeLeftButton.classList.remove("hide");
forwardButton.classList.add("active");
}, false);
forwardButton.addEventListener("touchmove", function(e) {
e.preventDefault();
const touch = e.targetTouches[0]; // We can get away with this because every other touch event will be on different elements
if (!startTouchX) {
startTouchX = touch.pageX;
}
let movementX = touch.pageX - startTouchX;
if((movementX * 10) > window.innerHeight) {
strafeRightButton.classList.add("active");
strafeLeftButton.classList.remove("active");
keyEvent("d", "keydown");
keyEvent("a", "keyup");
} else if ((movementX * 10) < (0 - window.innerHeight)) {
strafeLeftButton.classList.add("active");
strafeRightButton.classList.remove("active");
keyEvent("a", "keydown");
keyEvent("d", "keyup");
} else {
strafeRightButton.classList.remove("active");
strafeLeftButton.classList.remove("active");
}
}, false);
forwardButton.addEventListener("touchend", function(e) {
keyEvent("w", "keyup");
keyEvent("d", "keyup");
keyEvent("a", "keyup");
strafeRightButton.classList.remove("active");
strafeLeftButton.classList.remove("active");
strafeRightButton.classList.add("hide");
strafeLeftButton.classList.add("hide");
forwardButton.classList.remove("active");
startTouchX = null;
}, false);
strafeRightButton.classList.add("hide");
strafeLeftButton.classList.add("hide");
document.body.appendChild(forwardButton);
let rightButton = createTouchButton("rightButton", "inGame");
rightButton.style.cssText = "left:24vh;bottom:12vh;"
rightButton.addEventListener("touchstart", function(e){keyEvent("d", "keydown")}, false);
rightButton.addEventListener("touchend", function(e){keyEvent("d", "keyup")}, false);
document.body.appendChild(rightButton);
let leftButton = createTouchButton("leftButton", "inGame");
leftButton.style.cssText = "left: 4vh; bottom:12vh;"
leftButton.addEventListener("touchstart", function(e){keyEvent("a", "keydown")}, false);
leftButton.addEventListener("touchend", function(e){keyEvent("a", "keyup")}, false);
document.body.appendChild(leftButton);
let backButton = createTouchButton("backButton", "inGame");
backButton.style.cssText = "left:14vh;bottom:2vh;"
backButton.addEventListener("touchstart", function(e){keyEvent("s", "keydown")}, false);
backButton.addEventListener("touchend", function(e){keyEvent("s", "keyup")}, false);
document.body.appendChild(backButton);
let jumpButton = createTouchButton("jumpButton", "inGame");
jumpButton.style.cssText = "right:20vh;bottom:20vh;"
jumpButton.addEventListener("touchstart", function(e){keyEvent(" ", "keydown")}, false);
jumpButton.addEventListener("touchend", function(e){keyEvent(" ", "keyup")}, false);
document.body.appendChild(jumpButton);
let crouchButton = createTouchButton("crouchButton", "inGame");
crouchButton.style.cssText = "left:14vh;bottom:12vh;"
crouchButton.addEventListener("touchstart", function(e){
keyEvent("shift", "keydown")
window.crouchLock = window.crouchLock ? null : false
crouchTimer = setTimeout(function(e) {
window.crouchLock = (window.crouchLock != null);
crouchButton.classList.toggle('active');
}, 1000);
}, false);
crouchButton.addEventListener("touchend", function(e) {
if(!window.crouchLock) {
keyEvent("shift", "keyup")
crouchButton.classList.remove('active');
window.crouchLock = false
}
clearTimeout(crouchTimer);
}, false);
document.body.appendChild(crouchButton);
let inventoryButton = createTouchButton("inventoryButton", "inGame");
inventoryButton.classList.add("smallMobileControl");
inventoryButton.style.cssText = "right:19.5vh;bottom:0vh;"
inventoryButton.addEventListener("touchstart", function(e){keyEvent("e", "keydown")}, false);
inventoryButton.addEventListener("touchend", function(e){keyEvent("e", "keyup")}, false);
document.body.appendChild(inventoryButton);
let exitButton = createTouchButton("exitButton", "inMenu");
exitButton.classList.add("smallMobileControl");
exitButton.style.cssText = "top: 0.5vh; margin: auto; left: 1vh; right:8vh;"
exitButton.addEventListener("touchstart", function(e){keyEvent("`", "keydown")}, false);
exitButton.addEventListener("touchend", function(e){keyEvent("`", "keyup")}, false);
document.body.appendChild(exitButton);
// input for keyboard button
let hiddenInput = document.createElement('input', true);
hiddenInput.id = "hiddenInput"
hiddenInput.classList.add("inMenu")
// We are hiding the text input behind button because opacity was causing problems.
hiddenInput.style.cssText = "position:absolute;top: 0vh; margin: auto; left: 8vh; right:0vh;font-size:20px;z-index:-10;color: transparent;text-shadow: 0 0 0 black;";
hiddenInput.value = " " //Allows delete to be detected before input is changed
hiddenInput.addEventListener("input", function(e) {
let inputData = e.data ?? "delete"; // backspace makes null
window.lastKey = inputData
hiddenInput.value = " "; // We need a character to detect deleting
if(window.keyboardFix) {
if(e.inputType == 'insertText') {
let isShift = (inputData.toLowerCase() != inputData);
if(isShift) {
keyEvent("shift", "keydown")
keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup");
keyEvent("shift", "keyup")
} else {
keyEvent(inputData, "keydown");
keyEvent(inputData, "keyup");
}
} else if (e.inputType == 'deleteContentForward' || e.inputType == 'deleteContentBackward') {
keyEvent("backspace", "keydown")
keyEvent("backspace", "keyup")
}
}
}, false);
hiddenInput.addEventListener("keydown", function(e) {
if(!(e.key && e.keyCode && e.which) && !window.keyboardFix) {
console.warn("Switching from keydown to input events due to invalid KeyboardEvent. Some functionality will be lost.")
window.keyboardFix = true;
if(window.lastKey) {
keyEvent(window.lastKey, "keydown")
keyEvent(window.lastKey, "keyup")
}
}
}, false);
document.body.appendChild(hiddenInput);
let keyboardButton = createTouchButton("keyboardButton", "inMenu");
keyboardButton.classList.add("smallMobileControl");
keyboardButton.style.cssText = "top: 0.5vh; margin: auto; left: 6vh; right:0vh;"
keyboardButton.addEventListener("touchstart", function(e){e.preventDefault();hiddenInput.blur()}, false);
keyboardButton.addEventListener("touchend", function(e){e.preventDefault();toggleKeyboard()}, false);
document.body.appendChild(keyboardButton);
let placeButton = createTouchButton("placeButton", "inGame");
placeButton.style.cssText = "right:6vh;bottom:37vh;"
placeButton.addEventListener("touchstart", function(e){mouseEvent(2, "mousedown", canvas)}, false);
placeButton.addEventListener("touchend", function(e){mouseEvent(2, "mouseup", canvas)}, false);
document.body.appendChild(placeButton);
let breakButton = createTouchButton("breakButton", "inGame");
breakButton.style.cssText = "right:19vh;bottom:41vh;"
breakButton.addEventListener("touchstart", function(e){mouseEvent(0, "mousedown", canvas)}, false);
breakButton.addEventListener("touchend", function(e){mouseEvent(0, "mouseup", canvas)}, false);
document.body.appendChild(breakButton);
let selectButton = createTouchButton("selectButton", "inGame");
selectButton.style.cssText = "right:6vh;bottom:49vh;"
selectButton.addEventListener("touchstart", function(e){mouseEvent(1, "mousedown", canvas)}, false);
selectButton.addEventListener("touchend", function(e){mouseEvent(1, "mouseup", canvas)}, false);
document.body.appendChild(selectButton);
let scrollUpButton = createTouchButton("scrollUpButton", "inGame");
scrollUpButton.classList.add("smallMobileControl");
scrollUpButton.style.cssText = "right:6.6vh;bottom:0vh;"
scrollUpButton.addEventListener("touchstart", function(e){wheelEvent(canvas, -10)}, false);
document.body.appendChild(scrollUpButton);
let scrollDownButton = createTouchButton("scrollDownButton", "inGame");
scrollDownButton.classList.add("smallMobileControl");
scrollDownButton.style.cssText = "right:25.8vh;bottom:0vh;"
scrollDownButton.addEventListener("touchstart", function(e){wheelEvent(canvas, 10)}, false);
document.body.appendChild(scrollDownButton);
let throwButton = createTouchButton("throwButton", "inGame");
throwButton.classList.add("smallMobileControl");
throwButton.style.cssText = "right:13vh;bottom:0vh;"
throwButton.addEventListener("touchstart", function(e){keyEvent("q", "keydown")}, false);
throwButton.addEventListener("touchend", function(e){keyEvent("q", "keyup")}, false);
document.body.appendChild(throwButton);
let sprintButton = createTouchButton("sprintButton", "inGame");
sprintButton.style.cssText = "right:19vh;bottom:53vh;"
sprintButton.addEventListener("touchstart", function(e) {
keyEvent("r", "keydown");
window.sprintLock = window.sprintLock ? null : false
sprintTimer = setTimeout(function(e) {
window.sprintLock = (window.sprintLock != null);
sprintButton.classList.toggle('active');
}, 1000);
}, false);
sprintButton.addEventListener("touchend", function(e) {
if(!window.sprintLock) {
keyEvent("r", "keyup");
sprintButton.classList.remove('active');
window.sprintLock = false
}
clearTimeout(sprintTimer);
}, false);
document.body.appendChild(sprintButton);
let pauseButton = createTouchButton("pauseButton", "inGame");
pauseButton.classList.add("smallMobileControl");
pauseButton.style.cssText = "top: 0.5vh; margin: auto; left: 0vh; right: 0vh;"
pauseButton.addEventListener("touchstart", function(e){keyEvent("`", "keydown")}, false);
pauseButton.addEventListener("touchend", function(e){keyEvent("`", "keyup")}, false);
document.body.appendChild(pauseButton);
let chatButton = createTouchButton("chatButton", "inGame");
chatButton.classList.add("smallMobileControl");
chatButton.style.cssText = "top: 0.5vh; margin: auto; left: 0vh; right: 14vh;"
chatButton.addEventListener("touchstart", function(e){keyEvent("t", "keydown")}, false);
document.body.appendChild(chatButton);
let perspectiveButton = createTouchButton("perspectiveButton", "inGame");
perspectiveButton.classList.add("smallMobileControl");
perspectiveButton.style.cssText = "top: 0.5vh; margin: auto; left: 0vh; right: 28vh;"
perspectiveButton.addEventListener("touchstart", function(e) {
keyEvent("f", "keydown");
keyEvent("5", "keydown");
}, false);
perspectiveButton.addEventListener("touchend", function(e) {
keyEvent("f", "keyup");
keyEvent("5", "keyup");
}, false);
document.body.appendChild(perspectiveButton);
let screenshotButton = createTouchButton("screenshotButton", "inGame");
screenshotButton.classList.add("smallMobileControl");
screenshotButton.style.cssText = "top: 0.5vh; margin: auto; left: 28vh; right: 0vh;"
screenshotButton.addEventListener("touchstart", function(e) {
keyEvent("f", "keydown");
keyEvent("2", "keydown");
}, false);
screenshotButton.addEventListener("touchend", function(e) {
keyEvent("f", "keyup");
keyEvent("2", "keyup");
}, false);
document.body.appendChild(screenshotButton);
let coordinatesButton = createTouchButton("coordinatesButton", "inGame");
coordinatesButton.classList.add("smallMobileControl");
coordinatesButton.style.cssText = "top: 0.5vh; margin: auto; left: 14vh; right: 0vh;"
coordinatesButton.addEventListener("touchstart", function(e) {
keyEvent("f", "keydown");
keyEvent("3", "keydown");
}, false);
coordinatesButton.addEventListener("touchend", function(e) {
keyEvent("f", "keyup");
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 = `
.mobileControl {
position: absolute;
width: 9vh;
height: 9vh;
-webkit-user-select: none;
-ms-user-select: none;
user-select: none;
padding:0px;
background-color: transparent;
box-sizing: content-box;
image-rendering: pixelated;
background-size: cover;
outline:none;
box-shadow: none;
border: none;
margin: 1vh;
opacity: 0.5;
}
.mobileControl:active {
opacity: 0.75;
}
.strafeSize {
width: 7.5vh;
height: 7.5vh;
}
.smallMobileControl {
width: 6vh;
height: 6vh;
margin: 1vh 0vh;
}
html, body {
height: -webkit-fill-available !important;
touch-action: pan-x pan-y;
}
.hide {
display: none;
}
#fileUpload {
position: absolute;
left: 0;
right: 100vw;
top: 0;
bottom: 100vh;
width: 100vw;
height: 100vh;
background-color:rgba(255,255,255,0.5);
}
.strafeRightButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAARRJREFUOE+dk0EORTAQhkci2HAEF3ESJ7Rgyw2cwAEkVhI7QhDJe/n7Mk3R0rxu0M7/dWb841RV9SHDmufZdHTbdwCCoO97a5EaOAwDtW1LEtQ0zQnkui4dx/EKBwTLyfNclAZQFEU0juOjGDHLsshLANr3/QdCWUjRdqnZWoO6rqO6rk93pGkqvx9BV3EQBFK4ritZgbIsEyJVrKajA03TdO8RQCYIgAziPqE0LQh/rSxLLQyQJEkojmN6BeFWE+xaFmKNGXE/dDATSBqSfXQ1mwpTy4KQzXtyNoN0Y8EwiNXfzplbG1Ln9r+c/TY2p2ZjYLnWN6HuXPqoKAryPE/EYDMMQzHRWNu2Sa3v++KdYzkezy+eN1EbyruiHgAAAABJRU5ErkJgggAA");
}
.strafeLeftButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAUFJREFUOE+dlDGqhDAQhrMgKhYWHsCLeARP4Lk8hIW9N7CxtbQQrAQLQVFUhPf485gwyWbZfZvGJM58zvz546Oqqh/BxrZtfPnx/EEgEzCO40eQaZpE3/dCggBp21ZLdBxH3Pf9BOP7mHddJ2NegoiA4CAIxL7vVjCqkaCyLKVGqOhVFbYeKRag67p0ECUURaHlJkki4jjW9sIwFMuySH0UCMJCNA7yfV+tj+NQcxP6LxAvhaBZlsntr0FIBoyD1nX904haIwGHYRB1XQveHlUFSJqmAhpRRU8g3gIEN0EEiaJIWQGtaaB5njWfmCCzEvqo5iO0RiBbezYI95E0ZJ7n0pD8+E0/cU2443GF1KlxEJns3W3lcVbQO4DtvRIbFdGv4BsQcuSpAdQ0jWLg3tA4z1NOPc+TT9d11TskY59ifgE9QD9CDm6XPgAAAABJRU5ErkJgggAA");
}
.forwardButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAcZJREFUSEulVEuqwkAQ7OAnoujalRfxCJ4gl/ESHsKFa72BJ3AhIiJk60IwKH6ZR43U0JlMiOH1xsx0T1ldU9PRarUy4sX1evW3aq+jxWJher2ePXg4HGoD+AdOp5PsdjuxwEhuNpsCaLPZlPf7bfcHg0Euf7lcROeZPB6P9tMBb7dbB8IiHEQQvKod1O/3+y/wbDYzw+HQMQaz2+1mwTQjMAwxRz1zBM6y7AuMA9CG7bKQDLFeLpd2OZlMXJ0vRRD4fD67ln0J5vO5ZU9ZkiRxqmjwghRkrLWlrmmaynq9ljiOJYoiud/vMh6PZTQaBS8bGj+fz7wUqPTbA9tGoyGtVssCvV4v+Xw+ollrQqXAmgbZdjodt22MkcfjUcoaditcni+Fz5ZO8VnrLp2PtSu0FJotWEJfBL4RYE2H+MA5xijUNtNsAQZd6YwyrStdEdKWbMkca+0QPqzcy/PtRrZgSZuFnrPW+mfgqrmg87CeBg76uA5gqBauKABzVmAIMbrdbm7IcB/W0wOIjvrpgdQdmwAPMtZ28tsEc90JH4vugMDOxxiZfDH/1RjnLfB0OjUhUCT7/X7wf5CDDRHtdtv+4sK4Rv4PfpOwZeVjdiYAAAAASUVORK5CYIIA");
}
.rightButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAVhJREFUSEudlT2qhTAQhSOICKK1lRtxCS7PRVjYuwaxtbKyFewURUS4j5PHyNy8/OibKpiZb04mmdFrmuYjDLZtm2nL+d1TwSpsmiYJSdNU0NpGnedZjOMovLquP1EUibZtnSqeOAAKk2As+r53xvm+L67r0volSSKWZZFqX4MRoMIJSN+d4KqqZOY8z0WWZV8qbcoBXtf1txS4FBSdBwAchqE4jsOYQFcTgM/z/AZzRwLTN1sCLug1+EkC+AzDIIIg+KuYLkNVrB6bTlAUhUAMmbbGtlJgD08Nx+aGBBz+L7Dusozgsixlg+BV6BTrVMLPWQoX2FRb/r5R433fZanuy3sKtj03Dr47zwV2NYjahY/Appa2Tau7QbhiOhIFmibZazACqEF0k4yAfKKpIrSKbUqe7t0NglLQ7+RpsMtPjk2Au66Tow7DgxscyOI4lkv4wbgv9yP/HwHyemKMQPbVAAAAAElFTkSuQmCC");
}
.leftButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAUdJREFUSEutlTuqhUAMQEcQEUFrt+a6XIa17sDG1sJSsBLsFEVFuJcEMoxhPm8uL5WOycl3YtA0zUcYZN930yfneaCCVdA8z05jncKyLGIcRxFUVYUR933/E4gbAfS+bzs4DEPxPM/LVncGClmWiXVdMVorGAAgHOxKC8AgP5VimibRti0CiqJ4+ZLgsiw/eZ6LYRic0anAOI7FeZ5a8LZtIgAwuIRumoQDSc8ExlLYwCYgB1Pj4PxVCh4xdLeua7SHlE3iFTFBCQhTQRPCHXjVmINt4+UFBpCrFJSFN5ii/Gvz1KyszePp/8u4qaPjckClAJvjOPCCeUVsc6C70riEdBcExitJEmyiLQPdxMjtxsGUFhnptptpddLNM0bsWo3qd+7kFTH9TnyANl253bquk3qQRhRF+A7PXK7rkkdpmqIO6QOQ5AuINXqeGbRlFgAAAABJRU5ErkJgggAA");
}
.backButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAAAXNSR0IArs4c6QAAAXtJREFUSEuVlT3KhEAMhiMsKgt6BC/iETyB59pDWFjrDWxsLSwFK8FCUFZ2RdiPCBky+ca/wBbjxGfeeROzVp7nPxDxfr/lo9trC8F7oK7rbgP7voemacBK03RTXFXVbYjpBYRiKHBd17Cuq8r1fR/meYbn8wnjOGqMx+OhcjGP7yN4WRazYp6MEAx+KK45nK81MHqJ3pyFhJ1aIcFJkpydoe3HcazWmscmsOu6l+CfzweM4NfrtXUFt6JtWyiKAo7g6Dn+wjCEIAiU56h4miawCDwMg1YgtIPACKAi8mtItbiniscV8+KcqUYoqeWHGcHSVK5a7km1JEoVz+QxQfZUm9ReBlOiSbXJWw7Wise7gn95UvWet3TLf11x9OVx1Sa1XMguGK8kBw8OmSzLNlFRFAGCKAh66vHecKEJxqGHs+KoK64MHQm/1G7yJf71yTHKi7cNelRMfyeXps7FpA1clqVKx+nP4/v9bkvP87Tn2KsUjuOAbdtqjXt/DvSA6WCSwboAAAAASUVORK5CYIIA");
}
.jumpButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAARlJREFUOE+dlD2KhVAMhSMIWrkx1+CqXISFtS7C1sLSVrAQFEVFmOFcyH25eXNVJpWS+OXkz6Cu6x8Stq6rfH39HEjQX5BhGG5h4zhS3/cUlGVpFLVt+yp7GIZ0XZeNBQTmgJIkoW3bjEMGywwcw36AzvN0QTrbPM9UVZXhpGlKgGgDaFmWD6jrOkcFQ+I4Nt/u++7AOOkXSPZIQ1AGPtQwJHBAmAy6D9MQXYqGOT2SoKIoiMvxjRGwLMtMKywoz3MzflakQVyWhGqQGb8G/ac0BzRNk52aD3bbbK2IS3gaP8fZqWmQXMq7hfzaI5+ip8PDliPRK0USBgVs+mjNiUAR/wqeVPj8FtQ0jY3BJcOO4/ByoyiyPo77BUACR9z5EdScAAAAAElFTkSuQmCC");
}
.crouchButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAASVJREFUOE+dlDsKhEAMhkcQtPJiVh7AU3kCKwsLKz2ErYWlrWAhKIqKsEsCmc08fLB/pSR++ZPM6FRV9RFMy7Lw19fPDgfZIH3f38KGYRBd1wknz3N01DTNq+qu64rzPGUuQEAKKAgCsa4rBngyr0A5FAfQcRwqSK82TZMoyxI5YRgKgOgC0DzPP1DbtooLgvi+j99u26bAqKgB4jPikCiK0EmapgYMCigg2AxMH6RDeCtFURgwZUYclGWZgHbAiU0Ei+MYRyFBSZLg+smRDoK2wCXJBsL166B/WlNA4zjKrdlgtvkow9YdUQtP66c8uTUdxA/l3YE0ztGVo6eLR0t45YjDwAFJv7R4RcAR/QqeXFzFJaiua5kDNxm07/sl1/M8GaO8L0fuVtxHFTIkAAAAAElFTkSuQmCC");
}
.crouchButton:active {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAStJREFUOE+dlLGKhEAMhiOICqKdYGthaetL2GhlNQ9nZWFh5YtZiIKwRwLJjXHc3bu/WZnJfPknyazXtu0LACAMQ/whHcch3/qD44IgkK26rsFDUJIkjwc/bRRFAVmW/YJw4Rv5vg/neUooQlDiCEFpmsK2bbRhB9sJOIb3nSCdbV1XWJaFOE3TUCKtG6gsy4sLhkRRRGf3fb/AOKnTEWezIV3XkZNhGG4wjBeQMYbaz8XWEPsq8zzfYI+gcRwBr4NOXGKYMYZKIaC+7184XOxIg/Ba6JLlAuV5Dp4G/edqBOLJtrvmgrnqgy6rqroPpF2TT+3n2EeQPZTvBpLjBKRr9M17wxhugoD0HOlnwmBcZ9nv8ALiv4J3brAzWnEcy5I3TRNN9l9lQ/DsD7Mvyc0ay6bsAAAAAElFTkSuQmCC");
}
.inventoryButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAedJREFUOE+tlM1OwkAQx6elTYiCkSMnvKAX38KLr+DRm69hfAIP3jwbE24ceA4+TDBpCMWEFGgMBCgBUlrzXzLLLsVYo3NpOjv72/987Bq1Wi2mf7AgCATFYOB0OiXTNCV6s9mQYRiUyWSkbzKZHDx6uVyS7/vU7Xa3wPl8Ts1mkxgSx7EAAQhfFEUaHH7ECEWGIb6u6+4UAliv16VCAMIwJMuyxAb8Q72qdl8q1MmUkW6j0dCAgADAZYAiVoON+OeD4O/1erpCABEAs237YK14nRcBRUlg/X6f1uv1toYodrvdFikiVQ7CBiiEArVhh05DyhLY6XRoNBpJIMAMTTtRCeBwOCQ057h8KRiB80a5XC61DzXUFAIYF8/o/u6W3t0Penh8ovJJNuErZU2yS+eJOMdxdk1Bygy8ub4iz/+k55dXCfzJd3F6JIZaU+h5Hi0WC/IiS5xUNEMqFAo0Ho81Xz6fp9lspvlQGplypVKJB4MBAci3I20j1DipUAWqQ4yZ+24ecfD+FCSAqKFq2MSDrN5bvi081BgxWAKIOVSvFwYcm9W7zI+BGsfXL1FDBvImfgiQGgNYKWfCzxti8NqgWQbXEO9ZGuMUkcF+UySw1WqJGvzFMIOr1WqrsFqtaiws/sYAYvsC6d7MZCUlFo0AAAAASUVORK5CYIIA");
}
.chatButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAh5JREFUOE99lN8vA0EQx2fjkYY3HvB/8V4kEg8SBJUGVVJU4rfeVRO01bpIT8VviYjEq2tF678g5ZGVmbm9Hy02l9zd7MxnZ747u+Lhsig7OrtBDQkS8BFCkAn/BQiQUrILmvHTfqOfeXEDAkE4397Z5TqQn/BBmMtwtQACTy5vQU8kQTxcFSmJSqncsKAT4AGohBQwrqcBpHQzUiDlUB/gpFL3QSAsX5WGIBUcHJn4K47sWmyONERN4toBfftA6ISQz9q7q4ONRM2UiM2BVtAW50izFT3N2t9fmKTRa7lMhr7REIF2tExDVv3BXtqAlkAbJGIRml9JZmhjxN1ZgXatalk0MTAehs/am73DvHOubrxrmNH2/DSDUjkW+7ZokGfFYo0GQ9PwUXuDhJb9Vaf+YA80B9pgPRIm/9W9QwZdF3LYflCxShQ4FI4QSPWRl6ZsWNrqTIgkW9vPc2nnRtbOiEHDs/P/gNBDUGnxqXHqz80Dg97iNLcvsWtfnrghv7+/YGxhmWA4cPX6sTQ5xtpJgK3DY8B4YWZSEvsANcJRD4mODjeAmiiSu2EnbzKokN6l81gpPVPARCzuBP4GoeKwGe1DnDwy+UwqULWMIHe7fSeepXFuBVUWmvWjAouNIDS8WJyRs6K6PjzXinOVeIr1ZJSSj6UqGHmDU8SC7R70/3NrqnnVqM51oy9FZXRDd7Oxa+C7y9/ZXKGnfI9WP7ZEKinpenUjAAAAAElFTkSuQmCC");
}
.pauseButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAjJJREFUOE9lVO1qE1EQnXkK+6P6FP7oI/gMraIoFIMr1WL9aNEfRWNtS1Li1ti6aYr5sEkXyRrRRC2IFNqCgptIE5/myszcO7tbLwuZPTv3zJmTOxcP+10zMXkB3DJggB5EZIjeERCMMZJCMIX2l/Ki3jdAIqLv5ybPJwmchxkS4RVyV4AIP/QPINiuAB5+6bKI0WD4X0HdkCJwghxhIWgAGJMockQu4ewGlXImYCJq37VGROn2RU3WlqQvwx7S98KbOscZIpc4ffOW7mm+3uRYMHFZMImLQUOiH72IPfo7HKqCmdxtNbRZ9jmeyXm8kZIdRnix0uQ/Br9/6nAH4zhWsy97c7YeQt3f4PiKd0dV1vwNjYvVlph90A2ZaBSLR7Suzt21McJuqUB5cE0xgN1SkTHKL73dE6KvnRZDo3igVa7P39NztFNYZ/zG/IK2y5j9Z17W2tLa5/CdVWSJEGB24YESba++YILZ+4TRQthaW9HD+6oeMil+bNUMndrT3/ZAIkLu4aJWLz/Pc5x7tKhE5ZU8m05Pee890H6MmlVD54A8cstbeqxm+8+WGfaWnujI+E+XtbWtdiREncYOz+No8EeEI0Lv+KcoMgYuTV3kuH/ySwsR5oa4sh9JAUc0HhKRnBNxIjXxAuit4NoiONjviNlERMBpLIqcKr0+UteKXiWaCZBSVDVHgzGE7VAkUsN2yLLvotV9zyinfcF63uQ3g0SN7UEmKWlV1abbp8G1F94/2dEyKXciad8AAAAASUVORK5CYIIA");
}
.exitButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAiBJREFUOE99U11rE1EQnfsvFKwg/QkK+iaIio+KJNAnbUQoRaGgf0NRTFPU3TTJBjfdTZpN/aJtUHwU8anJJlH/y8o5c+92k1bnJXvn48yZMxNzmETZ2aXzQjMikunn6YYgkuZtb/+LGAAZY+TMuaX/IfwzBpBWMxAzHMQZaEyPxkw+rWeRpCPteFWDWIdRRiITC+Qm1KgRybJ5cOtzFKtBxO5mOIiyLBOZjca5RqXVCvPiRl01QYKIlCsVFu1sw6/p1VbEhgSCa3I0IoHSfQVxFtsigBfJRNt1BXKjHfQ77DcbpQyUKw9yEBSiCSkXDP6O7zN/sx3raJ97IcWejVOOEO1/lX4cHoMVFuDg7pRWpHzrGnO2gq6O+SFqM06NrPWG3wi2eFZ43y6tyN3rV/PcN+GuAu2FDTL/lU7owI6MGLm3vk6NcWMa0O01a5vHQxoRrzPQmt22bxkpEOpWHz2eE9aBoSNg69VXtomIFw1Uo27zbc4IHw83NsjCCax6z7/R2Xv5gmD13nslsONvcSe/0ykDa0+f6N3YYggLS7qhOye+Xz97zt9G/yNZmtCrZSjC+mEH33/mWwPIzSuXyO5wwX/j8kWOHySflFHo16jRdKQawVAEQ7JOpqOd9Iu0yMiIeefV+F+bjSe5gAv3d0L4on5kZOxoP9I/kvSTvDM6uCPiai0j+ItvsnU+PJYvLOteYfZ89WqKiZrg/LkONucvWvgqB/7CAfgAAAAASUVORK5CYIIA");
}
.keyboardButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAfdJREFUOE+VVN1KG0EU/ubait7ZC9un6IXP4BvU9qJQJFhsEUGpPkAsWJL+xEjMxhRjEhMXyRqx2lYoRfCmF81uyca3UGKvp5xzZpJsFI3Lwjkz88035+ebUafHdf1w/DHsp6FBv1KKp2isoKC1FghNk2ss4byjH1BEROtj44+6AMapCInwCrk9gAj3j0/gbOSgTr/VOYjQ9yPAzo47nIRTBLTuRhT6waB7IzgmovRtakTEaRO7orR4cKefyG4zJkLUPcpWU6rRrc11P+kUBfHryOMatYIAz2Ze96VnOmXaZTtoi11aTyGZK3Fj1M/DGqPPGw08n53D0PAI/rUv2V61L/BgePTamPCEKaQ+IJmvSAlO6i4TtfwAL97MRyLiUI0UIm03c18+JvBpa0eIvtcqJD+EDR8v5xeQyZYQm5661RIpYXKJVXwuVCW1r26ZjyWi2OJbo2UR5E1RWDkSIrP6Dultl3uhDioFTapt/gnwamkZmWwZsemnbG/67BrZ9Eoc6zt7oP3KK+U16SBsBDg8+30vUU5OPEGm6glRrbjJ9zH0/0phSYzmgg7i53Y9uZP9RJ3bLe0SPd7iO7s1KTYREa5JEfXqb8AkeyLK6zO/BbfqSoiUsCGMjkVVdr1XY4xz3sd1fM3pnC9tN5vMm9QbnH2n+uv5HyQVKCmWNUnHAAAAAElFTkSuQmCC");
}
.placeButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAd5JREFUOE+tlMlqQkEQRfs5gAv10xwQEf1Fd4J+h8PChYi6EKeNOCvqC6fltv2ISQxJgQjd1afq1vCCVqsVmn+w/X5vKYGAm83GxGIxh77dbiYIAhOPx93Zer1+Gfp0OpnVamVGo9EDuNvtTLfbNYKEYWhBADm73+8ROOf42IyCwP6Px+NnhgDb7bbLEMD1ejWJRMI+kJxsNvtlccjOSUZup9OJAIGS5eFwMM1m0zpXKhUHJEN8KBNBJ5NJNEOAOGDJZNI9JBjAVCpl8vl8JEOglASbTqfmcrk8akix+/2+lYhUOfHgeDxaIHflcvlbyQ44HA7Ncrl0QB4L6mdYLBbfBy4WC+tMg3xLp9MOTq2oqW+ZTMZ2nBpGMgQITA3QI78Rr+5rtZoNOBgMnk1Bsg+kATK/EQLqnnqXSiXbacYmkuFsNrOpMyr86Di1ZAtoDIZ8bQ9Zabi5c5Lr9Xo4n88NQG2HXyM1hbNqtfpzU3ygdllDyzwK6I8NgTUFiuAkC6guy0Gyt9utG+xCoeB2V0NNIOwTkDnESctOwTUm2pRcLmfPfD+t36caCkg0/7Ol4vtfGKnwG8TXBjWBJPM9e8ckEQW+IdkBe72ercFfjBk8n8+PDBuNRoTF5W8MkOwDqQTfZInxo/8AAAAASUVORK5CYIIA");
}
.breakButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAeRJREFUOE+tlMmKAjEURVMO4EL9MZcKKn6iO0G/w2HhQkRdiNNCcVbUak7kplNlNU1DP6iFMXXq3vvyEnQ6ndD8Q51OJ0sJBNzv9yaVSjn08/k0QRCYdDrt1na7XeKnr9er2Ww2ZjKZvIHH49H0+30jSBiGFgSQtdfrFYGzfjgcHLxQKJjpdPqtEGC323UKATweD5PJZCyI36iXWty0220HrNfrVp2zzIZerxcBAgGgGFANnI8Dy+VyFoDdarVqZrNZVCFAIFQ2m03MSsoEwwVPuVw28/nc3O/3d4aEPRwOrUU2kBuFKhQmKZM67FJYdsDxeGzW67UFbrdbu6FYLDqVcWVxWCJwtVq5fNhQKpVMPp//yEw2a7Wa+yBOyDCi0AeSEWEDpQEo55GySqXiOk7jiGg0Gn03BcsAdb7URaBqgN9R5eufhI8MF4uFbcLlcokcC/nS8dD0oIr9Kme52WyGy+XSANR0xJsATN1MPE9+l33g+Xy2+5Ms+1Dl5sOdZQHJUeMUbwovak1KsYttNetHoF6kk+TlqwbMmGkM+a05/8jQV8jGRqNhHSl8ZpjibKr8BnHbcAMFssx9RjNU/qT4WckiBzyeoQMOBgN3/fzUxd/WmZLb7fZW2Gq1Ivv58y8FSPUFhmoAc4SumvkAAAAASUVORK5CYIIA");
}
.selectButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAcRJREFUOE+tlMuuAUEQhqsZCWJ4KAsLL0pG4pKQWHgHzMJK2LlFIm5BMCd/SbXumRGccyoRme7O13/VX9Wq0+kE9A9xOByYogS43W4pkUho9O12I6UUJZNJvbbZbGKvPp1OtFqtaDKZPID7/Z6GwyEJJAgCBgGItfv9bsGxjjOsSCn+n06nT4UA9vt98jxPKyiXy9Rutz/6xtn1ev0EIt3BYEC1Wo3S6TRvFItF6vV6dL1eyXEc/Y09rJVKJd5HuhEgFAIohf3Uo263y3ABXi6XRw1R7NFoRJVKhdXg9mw2y3WCUaiTaZhciMwkkLIGjsdjWi6XDETKSDefz78VWq/XrZQt4GKxoGq1qoG5XM5qIXFUlEI1ah6bMhQCiFpKZDIZqwexjvYBAC2FX7PZ1Apns9nTZQG+UhiXO+prmhipIW5AH0oNXddlg9AWpikyPWj4RqMRraHnecF8PicBisu/NsUEHo9Hq4apVCrWadQPCmNdFmDY5UKhwCYgzLmV2cXabreL9qEAw32IKUCYYxc3hubocR+GgYB88zDIebgMxRqI98wcpbdjEjpgAX3f58fxL4F0z+fzQ2Gr1bJY2PwmAJL4ASn3ymSCH/2UAAAAAElFTkSuQmCC");
}
.scrollUpButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAfhJREFUOE+tlL1OAkEUhe8sUAkklHQ2dj6Q0crEwsTCWFlZGJ/Aws7amNBR8Bz8mKBBwmJClp+YEGAJkIU1Z8gZdlnWaPQ27A53vnvO3TujSqWSL/8QrutqiiJwNBqJZVkGvVwuRSkliUTCrA2Hw52lZ7OZDAYDabVaa+BkMpFqtSqE+L6vQQBibbVaheBYR45WpJT+tW17oxDAcrlsFALgeZ4kk0m9Ae9QH1S7LRXqjGXYrVQqISAgAACEgox0Oq0foZCFULTdbocVAogERCqVCglAwb2DQ73mNl4kCEVLEJ1ORxaLxbqHaHa9XtcWYZVJUAGF+IIA3p6fysnVteQtT7LZbKgoLBtgs9mUfr8v4/E4doAIRMIuaATY6/XEz+9/O5FQ+Gp/6Jy7+wetNJPJ6H6ihyGFBGITg5u3qziDT730+PSsoehpo9HYfBRYJvD97TVW5c3lheyCoc8Ry47jyHQ6jYU5q6ScHR9FlHGDsVwoFPxutysA8nRsUzE2BNJm7FcOAnmWObScRwJRCD3L5XJmtFjcWCYQPQwG1HLQg+NEZSiKecXsIiJAzCGSeNgx4HgOnmVs5MXAPB6/SA8J5CZeBFDBQrxh6ITXG3Jw28CJomXcZz8JWoSDYMCyAdZqNd2DvwROyXw+XyssFoshFv78TQDE+AI1+8NkGpdDjwAAAABJRU5ErkJgggAA");
}
.scrollDownButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAfxJREFUOE+tlMtKY0EQhqtzAdEkuPUBxI0PJO4EF4ILn2AYfItZDLhzBrLLIrjxHXIRIoSQEyGcXBgIuSckOfJ1qPYcY4KD1uZ0OtVf/39XdZt8Ph/IN8RoNLIUo8B+vy+xWMyhl8ulGGMkHo+7uV6v9+HW0+lUut2u1Ov1NXA4HEqpVBKFBEFgQQCZW61WETjz5FhFxtiv53lvCgEWCgWnEMBisZBEImEX8Bv1YbXvpaLOWcZusViMAIEAGI/Hbm0qlXJjFOpGbNpoNKIKAZJAJJNJ+2Wjg+NTOx5VnyQMZA4oR0I0m02Zz+frM+SwK5WKtYhVklAG7PbqQn7+urPATCaztR+w7IC1Wk06nY4DDgYDB3v2XuTPw6MFbgs22gC2222bT4FUGTAC4K4wvmfPMKIQ4Ecwv/tvJ+z3/V85zuxJtVp9KwqWAVIt7PqrhPy4uRaFsWhXnBzub1r2fd9WjVZBKdDL8zPLAXgUW2xlUn1nOZvNBq1WSwDq7dCWUagCP1XlMFDvsjbtZDKxSgkUKpCNtf9UtquyArXKmsAiGp0z1Uin0+7ualPTu8QGkD4kSS87Dc44fJdZqA+D5un12zhDBeoifQiwphvpC6OK9Xkjh9cGN0Yt8559JtQiDsKBZQcsl8v2DL4S3JLZbLZWmMvlIiz+/J8ApPEKFYzOZJBKmFAAAAAASUVORK5CYIIA");
}
.throwButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAehJREFUOE+tlLtOAlEQhme5VAK9D2DnG1nZ2VpZG5/Aws7amNBR0PoAFnIxwYQQFhOyXEJCuEOANd/BOeyyG4PRaTZ7Lt/5/5k5xykWi778Q0ynU0NxFDgajSSRSFj0ZrMRx3EkmUzaseFwGHv0YrGQfr8vzWZzB5xMJlKpVEQhvu8bEEDGttttCM44a4wixzFf13X3CgGWSiWrEMB6vZZUKmU28I/6oNpDqaizlrFbLpdDQCAANA0oUjVs5F8PYrzVaoUVAmQBkU6nQwI4kMhkMqFxoKSEaLfbslqtdjkk2bVazVjEqi5iw3w+l5Ozc7NpWn+XXC4XWxgsW2Cj0ZBer2eBgIGiDNjt1aWBXFzfyGliHQuNALvdbuhkChWEfbifZv7u/sFAs9msXY8TchhSqEAmadI4mBIUSk4pHG7q9fq+KFgGSLXG4/GPsDgonRCx7HmezGazo2BAvf5AHp+ejX2UWsv5fN7vdDqCyqDNl9e32GoeDip0MBjschgEetvUUZDDRaiMAA+rTLK10YP3Vm+LNjUtRtgcqkL6MHi9aHA2B++yuavfD4OC9fpFcqhA3aQPAS2hB6lStazPG2t4begQm0Pes2NCLeIgGFi2wGq1anLwl6DCy+Vyp7BQKIRYTP4mAGl8AUQGwWSM9G4HAAAAAElFTkSuQmCC");
}
.sprintButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAAAXNSR0IArs4c6QAAAd1JREFUOE+tlEmKAkEQRSMdwIV6MbeKeEKVciXoORwWLkTUhThtxAFnq/lh/zSzyoaW7gCxDCtf/JjStNvtUP7BDoeDUgyB2+1WEomERd/vdzHGSDKZtL7NZvM29Ol0kvV6LePx+Anc7/fS6/WEkDAMFQQgfI/Hw4PDj3dUkTH6PZlMXgoB7HQ6ViEAt9tNUqmUHsBvqHfVRqVCnU0Z6Xa7XQ8ICAAsAxRRDQ7iNwPBP51OfYUA4gXY8Xi0AvL5vD4jKC2bzeojoCgJbDabyeVyedYQxR4MBpoiUq3VavZwoVAQAOr1uudjIDqRsgWORiNZrVYeMJPJ6LvoYKVSkWq1Kq4PgVxoDLhcLq0CNKnVaikAivEpFovSaDRi0Fwup6mjhp5CAlls1JFQKi2VShIEgReIJRkOh6+mIGUA0a10Oi3X61V2u11MZblc1lq+Sz2W8nw+V+kYFTdlqvsJxo7blIMgCBeLhQDI7Yg24KOmuEAO8bsRQRBatMPw25QJjHaZh9lFlIGGceFQY3bfAjGH7nphVNAkd5d1V78vBq4h1y9WQwJ5iBcBVouBeMNQKa83vIPbBpNhmDLus98YU0QGrqGGFtjv97WofzFsyfl8fipsNpseC39+YgDRvgDSDetkcdqdJgAAAABJRU5ErkJgggAA");
}
.perspectiveButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAgxJREFUOE+VlM9L40AUx9+cF8Gbe1D/ld5F6FXv1h8gHirtaltXXGvU1o2g7ura1IJat61haaz4W7AieE6y2P4ZwrLnkfemM0lNl7JDIJnJy+d93zdvhj1d1/jH/kGQgwMHvBhjtIRzBgw45yIEl/Gxdcc46+oOGILwfV//gBdAcawNIrgCLhMg8Oz6Hoz9PLCnmxqJaDiuCvqfB90oAnDuKfKDIrEEsXJZrSuTQFi+LK3puKr0sVgC/v55hQ89vQpkZDW/NcoqPXdMfipQw3GUg5FYEkKhkILU63XIZVeCTgODTaMoEjxeWeRR0/U8Go+nCHRxbsHQcBgQ9H7sZ9K0tJk/oR/DHi6q9Neatq1iJ+cXQdd3wbJKChYOj8BEZJRisOS91SUBKpSF2fc1k0AN21V1T6eWCCRHNDoVULSTXqT4rcOSAN1Wy9h+QB61Gm3mczrg0daXVFsjyqzbRxVR2qX5s6XIUd0aXV4NKNIX5gNdjbDvxyats/PyEceufbFdlTG2kiEQliTv2WS8o6Ld0i/A75l1UuDYB+iRLO3T2lfliQStz812BP2oWAJULR7Qfmw4vwOGJjK6UqTFox27PH9qiT3ZDSS//hfIOK0KsxGEwS92UFHXjQYAPkUF/uw0wayYQiIW3Dp62ue0AdR7MfMdN8aGxrVvhkqOMsVx5gX5lclziiDMO/DeAFwyISmrQZieAAAAAElFTkSuQmCC");
}
.screenshotButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAcdJREFUOE+llE1LAkEYx585R3Ssg/WVvEbn3g7RoVBRRJFMS0vBsFLXhHzJlyXcjNJKiBA67264+zUiOk88M+64WxAsLgs7M/vMb/7Pf2YeMhr06JJnBayHAgV8CSFsCPsECFBKeQgOY3PyxTil/wIEQfh/0bM8DWBxxAHhXA63FkDg3WAIUrEMZPTUYyIMTRdBbhoZqQ5A6VTRTCBM30rN1HSR+rovJERJ6YTdkt8WQaZUY34KkKFpzIMNXwi+vz4FaG5+AUrphNNhGy4r1flCb32FeWTqOmz6w27sgWIqDtlyg20MeX3osl0zVRW2g1GHGotaKDXEAlsba6yNSi+TMchWWtzsYU9mIEPVYSccYyBrIk7CtqI0BcjrXQUcR1A+HoXcdZODnrstPH6AHu1G4n8U/QfKxcJwVm3z1B7lm4kiDfYOkq5AmUgQzmsyO6fkvlWleGrHqg6+w5Qrj9IhP1w0bwHnE6VRoXgO0KPA0amrXTsO7EOhrXBQt37F7qOhfbiCWMHljsLv5KwgqdPlZiMI6WN1ZkUV+q6ZILdlLhETnpQeZ59dAPGf92zlRjpJ0EReEv6gTF7OpkF286w6xSBkWvB+AJ1TDClYPe7/AAAAAElFTkSuQmCC");
}
.coordinatesButton {
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAeZJREFUOE+VlF1LAkEUhs9cR3RZF9avqyiILgwtxRBJttJawT7NNaHS0pZwM/oOIoKud1fSvxHR9cQ544y7rmANgvNx5pn3vHtm2PtDk0+EpkA2DhzwxxijKRwzYMA5FyE4jd3uP8ZZ98/AEITr46HJXgDFMR9EcAVcHoDA64cXMI5KwN4fmySi7bgq6D8d3agAcN5TNAw0E4krfjGrqT6BMH2ZWsdxvan7rJiOxOHn+4s2j4yOAYKkVXrxjPxUoLbjBJ0EBqjEC8E+wrAhMGdUhIC3e4s86riDPZqNJnwgBEjYUSYNuVKVPgx7vW3QV+vY9kCP52JJBZIBhWIVwuF5OFxPQa5cE2a/NE0CtW23v0RgIZFSENwsG0J200mKz59cCNBTo4blB+SRp9AWk2kfBDfLlk8lVEHunNZFanfmeVeRoxbDa+sBiL4aC1Q1Sto/M2me3dROOVbtp+2SooiWCUCy8ehACMYfXFwB7mdWtcyxDtCj5Y3tAGRzZcmXcr+RhbolQI3KMd3HttOCeEYHXT8gK9ATLRoeeltKl5a4k/0gufMvEIw1LhvCbAThxKfdGnr6oACPojL/cDpg1k0hERPuPj3+MV0AtS5GnufG2NK4tmeow1CmeM56QV4l8p0iCOs9eL/YmiwplUjFQgAAAABJRU5ErkJgggAA");
}
`;
document.documentElement.appendChild(customStyle);
</script>
<script type="text/javascript">
if(document.location.href.startsWith("file:")) {
alert("You're not supposed to 'open' this file in your browser. Please upload this folder to your HTTP(s) server and access it via the internet. This is not a bug, please read the documentation");
}else {
window.addEventListener("load", function(){
window.minecraftOpts = ["game_frame","assets.epk"];
(function(){
var q = window.location.search;
if(typeof q === 'string' && q.startsWith("?")) {
q = new URLSearchParams(q);
var s = q.get("server");
if(s) window.minecraftOpts.push(s);
}
})();
main();
});}
</script>
</head>
<body style="margin:0px;width:100vw;height:100vh;" id="game_frame">
</body>
</html>