<!DOCTYPE html>



<!--

This file is from ${date}, there is no official eagler download link anymore, check the websites and discords of your favorite eagler servers for new versions

Be aware that some server owners are lazy and do not update their client regularly

Compile it yourself here: https://gitlab.com/lax1dude/eaglercraftx-1.8/

-->













<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="EaglercraftX 1.8 Offline" />
<meta name="keywords" content="eaglercraft, eaglercraftx, minecraft, 1.8, 1.8.8" />
<title>EaglercraftX 1.8</title>
<meta property="og:locale" content="en-US" />
<meta property="og:type" content="website" />
<meta property="og:title" content="EaglercraftX 1.8 Offline" />
<meta property="og:description" content="this file is not a website, whoever uploaded it to this URL is a dumbass" />
<script type="text/javascript">
function initAPI(version) {
  var ModAPI = {};
  ModAPI.events = {};
  ModAPI.events.types = ["event"];
  ModAPI.events.listeners = { "event": [] };
  ModAPI.globals = {};
  ModAPI.version = version;

  ModAPI.addEventListener = function AddEventListener(name, callback) {
    if (!callback) {
      throw new Error("Invalid callback!");
    }
    if (ModAPI.events.types.includes(name)) {
      if (!Array.isArray(ModAPI.events.listeners[name])) {
        ModAPI.events.listeners[name] = [];
      }
      ModAPI.events.listeners[name].push(callback);
      console.log("Added new event listener.");
    } else {
      throw new Error("This event does not exist!");
    }
  };

  ModAPI.removeEventListener = function removeEventListener(name, func, slow) {
    if (!func) {
      throw new Error("Invalid callback!");
    }
    if (!Array.isArray(ModAPI.events.listeners[name])) {
      ModAPI.events.listeners[name] = [];
    }
    var targetArr = ModAPI.events.listeners[name];
    if (!slow) {
      if (targetArr.indexOf(func) !== -1) {
        targetArr.splice(targetArr.indexOf(func), 1);
        console.log("Removed event listener.");
      }
    } else {
      var functionString = func.toString();
      targetArr.forEach((f, i) => {
        if (f.toString() === functionString) {
          targetArr.splice(i, 1);
          console.log("Removed event listener.");
        }
      });
    }
  };

  ModAPI.events.newEvent = function newEvent(name) {
    ModAPI.events.types.push(name);
  };

  ModAPI.events.callEvent = function callEvent(name, data) {
    if (
      !ModAPI.events.types.includes(name) ||
      !Array.isArray(ModAPI.events.listeners[name])
    ) {
      if (!Array.isArray(ModAPI.events.listeners[name])) {
        if (ModAPI.events.types.includes(name)) {
          ModAPI.events.listeners.event.forEach((func) => {
            func({ event: name, data: data });
          });
          return;
        }
        return;
      }
      console.error(
        "The ModAPI has been called with an invalid event name: " + name
      );
      console.error("Please report this bug to the repo.");
      return;
    }
    ModAPI.events.listeners[name].forEach((func) => {
      func(data);
    });
    ModAPI.events.listeners.event.forEach((func) => {
      func({ event: name, data: data });
    });

    ModAPI.globals._initUpdate();
  };

  ModAPI.updateComponent = function updateComponent(component) {
    if (
      typeof component !== "string" ||
      ModAPI[component] === null ||
      ModAPI[component] === undefined
    ) {
      return;
    }
    if (!ModAPI.globals || !ModAPI.globals.onGlobalsUpdate) {
      return;
    }
    if (!ModAPI.globals.toUpdate) {
      ModAPI.globals.toUpdate = [];
    }
    if (ModAPI.globals.toUpdate.indexOf(component) === -1) {
      ModAPI.globals.toUpdate.push(component);
    }
  };

  ModAPI.require = function require(component) {
    if (typeof component !== "string") {
      return;
    }
    if (!ModAPI.globals || !ModAPI.globals.onRequire) {
      return;
    }
    ModAPI.globals.onRequire(component);
  };

  ModAPI.globals._initUpdate = function _initUpdate() {
    if (!ModAPI.globals.toUpdate) {
      ModAPI.globals.toUpdate = [];
    }
    ModAPI.globals.toUpdate.forEach((id) => {
      ModAPI.globals.onGlobalsUpdate(id);
    });
    ModAPI.globals.toUpdate = [];
  };

  window.ModAPI = ModAPI;
}
</script>
<script type="text/javascript">
function promisifyIDBRequest(request) {
  return new Promise((resolve, reject) => {
    request.onsuccess = () => resolve(request.result);
    request.onerror = () => reject(request.error);
  });
}
function loadLoader() {
  window.ModLoader = async function ModLoader(ModsArr) {
    if (!window.eaglerMLoaderMainRun) {
      var searchParams = new URLSearchParams(location.search);
      searchParams.getAll("Mod").forEach((ModToAdd) => {
        console.log(
          "EaglerML: Adding Mod to loadlist from search params: " + ModToAdd
        );
        ModsArr.push(ModToAdd);
      });
      if (
        !!eaglercraftXOpts &&
        !!eaglercraftXOpts.Mods &&
        Array.isArray(eaglercraftXOpts.Mods)
      ) {
        eaglercraftXOpts.Mods.forEach((ModToAdd) => {
          console.log(
            "EaglerML: Adding Mod to loadlist from eaglercraftXOpts: " +
            ModToAdd
          );
          ModsArr.push(ModToAdd);
        });
      }

      //Reverse engineer eaglercraftx virtual file system to gain external access to mod store WITHOUT messing with java teavm nonsense
      var StoreId = null;
      var decoder = new TextDecoder("utf-8");
      console.log("EaglerML: Searching in iDB");
      try {
        var dbs = await indexedDB.databases();
        for (let i=0; i<dbs.length; i++) {
          const db = dbs[i];
          if (db.name.endsWith("resourcePacks")) {
            StoreId = db.name;
            if (StoreId) {
              var database = await promisifyIDBRequest(indexedDB.open(StoreId));
              var storeIsValid = !!database.objectStoreNames[0];
              if (!storeIsValid) {
                break;
              }
              var key = database.objectStoreNames[0].length === 0 ? "filesystem" : database.objectStoreNames[0];
              var transaction = database.transaction([key], "readwrite");
              var objectStore = transaction.objectStore("filesystem");
              var object = await promisifyIDBRequest(objectStore.get(["mods.txt"]));
              if (!object) {
                break;
              }
              var mods = decoder.decode(object.data);
              if (mods.length === 0) {
                break;
              }
              var modsArr = mods.split("|");
              for (var modFilePath of modsArr) {
                if (modFilePath.length === 0) {
                  break;
                }
                var modUrl = null;
                if (modFilePath.startsWith("web@")) {
                  modUrl = modFilePath.replace("web@", "");
                } else {
                  var modFile = await promisifyIDBRequest(objectStore.get(["mods/" + modFilePath]));
                  if (!modFile) {
                    break;
                  }
                  var modData = decoder.decode(modFile.data);
                  var modBlob = new Blob([modData], {
                      type: 'text/javascript'
                  });
                  modUrl = URL.createObjectURL(modBlob);
                }
                if (!modUrl) {
                  break;
                }
                ModsArr.push(modUrl);
                console.log("Loaded iDB mod: "+modFilePath);
              }
            }
          }
        }
      } catch (error) {
        console.error(error);
      }

      window.eaglerMLoaderMainRun = true;
    }
    if (window.noLoadMods === true) {
      ModsArr.splice(0, ModsArr.length);
    }
    function checkModsLoaded(totalLoaded, identifier) {
      console.log(
        "EaglerML: Checking if Mods are finished :: " +
        totalLoaded +
        "/" +
        ModsArr.length
      );
      if (totalLoaded >= ModsArr.length) {
        clearInterval(identifier);
        window.ModGracePeriod = false;
        if (
          window.eaglerMLoaderMainRun &&
          ModAPI &&
          ModAPI.events &&
          ModAPI.events.callEvent
        ) {
          ModAPI.events.callEvent("load", {});
        }
        console.log(
          "EaglerML: Checking if Mods are finished :: All Mods loaded! Grace period off."
        );
      }
    }
    function methodB(currentMod) {
      try {
        console.log("EaglerML: Loading " + currentMod + " via method B.");
        var script = document.createElement("script");
        script.src = currentMod;
        script.setAttribute("data-Mod", currentMod);
        script.setAttribute("data-isMod", true);
        script.onerror = () => {
          console.log(
            "EaglerML: Failed to load " + currentMod + " via method B!"
          );
          script.remove();
          totalLoaded++;
        };
        script.onload = () => {
          console.log(
            "EaglerML: Successfully loaded " + currentMod + " via method B."
          );
          totalLoaded++;
        };
        document.body.appendChild(script);
      } catch (error) {
        console.log(
          "EaglerML: Oh no! The Mod " + currentMod + " failed to load!"
        );
        totalLoaded++;
      }
    }
    window.ModGracePeriod = true;
    var totalLoaded = 0;
    var loaderCheckInterval = null;
    ModsArr.forEach((c) => {
      let currentMod = c;
      console.log("EaglerML: Starting " + currentMod);
      try {
        var req = new XMLHttpRequest();
        req.open("GET", currentMod);
        req.onload = function xhrLoadHandler() {
          console.log("EaglerML: Loading " + currentMod + " via method A.");
          var script = document.createElement("script");
          try {
            script.src =
              "data:text/javascript," + encodeURIComponent(req.responseText);
          } catch (error) {
            methodB(currentMod);
            return;
          }
          script.setAttribute("data-Mod", currentMod);
          script.setAttribute("data-isMod", true);
          script.onerror = () => {
            console.log(
              "EaglerML: Failed to load " + currentMod + " via method A!"
            );
            script.remove();
            totalLoaded++;
          };
          script.onload = () => {
            console.log(
              "EaglerML: Successfully loaded " + currentMod + " via method A."
            );
            totalLoaded++;
          };
          document.body.appendChild(script);
        };
        req.onerror = function xhrErrorHandler() {
          methodB(currentMod);
        };
        req.send();
      } catch (error) {
        methodB(currentMod);
      }
    });
    loaderCheckInterval = setInterval(() => {
      checkModsLoaded(totalLoaded, loaderCheckInterval);
    }, 500);
    console.log(
      "EaglerML: Starting to load " + ModsArr.length + " Mods..."
    );
    window.returnTotalLoadedMods = function returnTotalLoadedMods() {
      return totalLoaded
    }
  };
}
</script>
<script type="text/javascript">
function displayGui() {
  function gui() {
    if (document.querySelector("#eaglerpl_gui")) {
      document.querySelector("#eaglerpl_gui").remove();
    }
    localStorage.setItem(
      "ml::Mods",
      localStorage.getItem("ml::Mods") || "[]"
    );
    try {
      localStorage.setItem(
        "ml::Mods",
        JSON.stringify(JSON.parse(localStorage.getItem("ml::Mods")))
      );
    } catch (error) {
      localStorage.setItem("ml::Mods", "[]");
    }
    var Mods = JSON.parse(localStorage.getItem("ml::Mods"));
    var container = document.createElement("div");
    container.id = "eaglerpl_gui";
    container.style = `width:100%; height: 100%; position: fixed; top: 0; left: 0; z-index: 10; color: white; font-family: Minecraftia, sans-serif; overflow-y: scroll; overflow-x: hidden; background-image: url(data:image/png;base64,UklGRhoBAABXRUJQVlA4TA0BAAAvn8AnAIWjtpEECdnA2N0DsTROy7xUqfrWw0jbyLkJKTz0+I20jTT/Bo89e1YR/Wfktm0Y+wNKLobT7QP/n/B7Z/naW26QHoTpHB7LFouyKHlzeHxfCStSuj9KdbC8z1IJ5iWiyQed48vtYJ+lUu0t4VwranS1XMIutSiLYlbb8G54uf2p3VPSfRZtSrlsPFjOzZZrd/us3B3uK+HcHJQql+xbLMrS/WqNpm6DeZ/VIPVYaN/KzUbp91nd9xl5pYu50dU2W417nbdTj5l2Ne92uM9qXNpyf6+oXkabHKXaZ1HS4Iaqpim+1KIJ+0M49/LjNbTGP5mrrMZEuc7Uzcb1ViOJ6TuOt4NGJs+zDgA=); background-color: rgb(60,60,60); background-blend-mode: multiply; background-size: 64px;`;
    var title = document.createElement("h1");
    title.style = "text-shadow: 0px 0px 4px;";
    title.innerHTML = "Mod Manager";
    var closeButton = document.createElement("a");
    closeButton.style = `margin-left: 2rem; color: red;`;
    closeButton.href = "javascript:void(0)";
    closeButton.addEventListener("click", () => {
      document.querySelector("#eaglerpl_gui").remove();
    });
    closeButton.innerHTML = "[X]";
    title.appendChild(closeButton);
    container.appendChild(title);

    var warningPoster = document.createElement("p");
    warningPoster.style = "font-size: 0.8rem; color: orangered;";
    warningPoster.innerHTML =
      "Warning: Installing Mods gives them full control over the game. Be cautious when installing them.<br>Mods that have been removed also need a reload to stop running in the background.";
    container.appendChild(warningPoster);

    var tipPoster = document.createElement("p");
    tipPoster.style = "font-size: 0.8rem; color: yellow;";
    tipPoster.innerHTML =
      "Tip: if the mods say that they failed loading, try refreshing the gui";
    container.appendChild(tipPoster);

    var table = document.createElement("table");
    table.style = "table-layout: fixed; width: 100%";
    var headerRow = document.createElement("tr");
    headerRow.style = "background: rgb(50,50,50);";
    var urlBox = document.createElement("th");
    urlBox.style = "text-align: center;";
    urlBox.innerHTML = "URL";
    headerRow.appendChild(urlBox);
    var statusBox = document.createElement("th");
    statusBox.style = "text-align: center; width: 15%;";
    statusBox.innerHTML = "Status";
    headerRow.appendChild(statusBox);
    table.appendChild(headerRow);

    Mods.forEach((url) => {
      var row = document.createElement("tr");
      row.style = `box-shadow: 0px 2px 0px grey;`;
      var urlBox = document.createElement("td");
      urlBox.style = "user-select: text;";
      var textWrapper = document.createElement("div");
      textWrapper.style = `max-width: 100%; overflow-wrap: anywhere; max-height: 3rem; overflow-y: scroll;`;
      textWrapper.innerText = url;
      urlBox.append(textWrapper);
      row.appendChild(urlBox);
      var statusBox = document.createElement("td");
      statusBox.innerHTML = ((curl) => {
        var targs = document.querySelectorAll("script[data-Mod]");
        for (let i = 0; i < targs.length; i++) {
          const elem = targs[i];
          if (elem.getAttribute("data-Mod") === curl) {
            return "LOADED";
          }
        }
        return "FAILED";
      })(url);
      switch (statusBox.innerHTML) {
        case "LOADED":
          statusBox.style = "background-color: green; text-align: center;";
          break;
        case "FAILED":
          statusBox.style = "background-color: dimgrey; text-align: center;";
          break;
        default:
          break;
      }
      var binBtn = document.createElement("button");
      binBtn.style =
        "background: transparent; text-align: center; color: yellow; cursor: pointer; font-family: 'Minecraftia', sans-serif; text-decoration: underline; border: 0; margin-left: 1rem; font-size: 1rem;";
      binBtn.innerHTML = "[X]";
      binBtn.addEventListener("click", () => {
        if (!window.confirm("Delete Mod?") || Mods.indexOf(url) === -1) {
          return;
        }
        Mods.splice(Mods.indexOf(url), 1);
        localStorage.setItem("ml::Mods", JSON.stringify(Mods));
        gui();
      });
      statusBox.appendChild(binBtn);
      row.appendChild(statusBox);
      table.appendChild(row);
    });

    var addBtn = document.createElement("button");
    addBtn.style =
      "background: transparent; text-align: center; color: yellow; cursor: pointer; font-family: 'Minecraftia', sans-serif; text-decoration: underline; border: 0; margin-right: 1rem;  font-size: 1rem;";
    addBtn.innerHTML = "Add new";
    addBtn.addEventListener("click", () => {
      var newMod = window.prompt("URL of Mod: ", "http://example.com/example.js");
      if (!newMod) {
        return; //User pressed cancel
      }
      Mods.push(
        newMod
      );
      localStorage.setItem("ml::Mods", JSON.stringify(Mods));
      if(window.ModLoader){
        ModLoader([newMod]);
      }
      gui();
    });

    var uploadBtn = document.createElement("button");
    uploadBtn.style =
      "background: transparent; text-align: center; color: yellow; cursor: pointer; font-family: 'Minecraftia', sans-serif; text-decoration: underline; border: 0;  font-size: 1rem;";
    uploadBtn.innerHTML = "Upload...";
    uploadBtn.addEventListener("click", function uploadBtnListener() {
      var filePicker = document.createElement("input");
      filePicker.type = "file";
      filePicker.accept = ".js";
      filePicker.addEventListener("input", function onInput() {
        if (filePicker.files[0]) {
          var reader = new FileReader();
          reader.addEventListener("load", function onModRead() {
            var newMod = reader.result.replace(";base64", `;fs=${encodeURIComponent(filePicker.files[0].name) || "unknown"};base64`);
            Mods.push(newMod);
            localStorage.setItem("ml::Mods", JSON.stringify(Mods));
            if(window.ModLoader){
              ModLoader([newMod]);
            }
            gui();
          });
          reader.readAsDataURL(filePicker.files[0]);
        }
      });
      filePicker.click();
    });

    container.appendChild(table);
    container.appendChild(addBtn);
    container.appendChild(uploadBtn);

    var notice = document.createElement("a");
    notice.innerHTML = "Refresh GUI";
    notice.href = "javascript:void(0)";
    notice.addEventListener("click", function reloadListener() {
      setTimeout(gui, 500);
      this.remove();
    });
    notice.style =
      "color: yellow; display: block; margin-top: 2rem; width: 0; white-space: nowrap;";
    container.appendChild(notice);
    ModAPI.events.callEvent("gui", {});
    document.body.appendChild(container);
  }
  gui();
}
</script>
<script type="text/javascript">
"use strict";
const relayId = Math.floor(Math.random() * 3);

// %%%%%%%%% launch options %%%%%%%%%%%%

window.eaglercraftXOpts = {
	container: "game_frame",
	worldsDB: "worlds",
	relays: [
		{ addr: "wss://relay.deev.is/", comment: "lax1dude relay #1", primary: relayId == 0 },
		{ addr: "wss://relay.lax1dude.net/", comment: "lax1dude relay #2", primary: relayId == 1 },
		{ addr: "wss://relay.shhnowisnottheti.me/", comment: "ayunami relay #1", primary: relayId == 2 }
	]
};

// %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

</script>
<script type="text/javascript">
"use strict";
if(typeof window !== "undefined") window.eaglercraftXClientScriptElement = document.currentScript;
${classes_js}
</script>
<script type="text/javascript">
"use strict";
	window.eaglercraftXOpts.assetsURI = ${assets_epk};

	var launchInterval = -1;
	var launchCounter = 1;
	var launchCountdownNumberElement = null;
	var launchCountdownProgressElement = null;

	function launchTick() {
		launchCountdownNumberElement.innerText = "" + Math.floor(6.0 - launchCounter * 0.06);
		launchCountdownProgressElement.style.width = "" + launchCounter + "%";
		if(++launchCounter > 100) {
			clearInterval(launchInterval);
			setTimeout(() => { document.getElementById("launch_countdown_screen").remove(); main(); }, 50);
		}
	}

	window.addEventListener("load", () => {
		launchCountdownNumberElement = document.getElementById("launchCountdownNumber");
		launchCountdownProgressElement = document.getElementById("launchCountdownProgress");
		launchInterval = setInterval(launchTick, 50);
	});
		function safeLaunch() {
			window.noLoadMods = true;
			clearInterval(launchInterval);
			setTimeout(() => { document.getElementById("launch_countdown_screen").remove(); main(); }, 50);
		}
</script>
<link type="image/png" rel="shortcut icon" href="data:image/png;base64, " />
</head>
<body style="margin:0px;width:100vw;height:100vh;overflow:hidden;" id="game_frame">
<div style="margin:0px;width:100%;height:100%;font-family:sans-serif;display:flex;align-items:center;user-select:none;" id="launch_countdown_screen">
<div style="margin:auto;text-align:center;">
<h1>This file is from <span style="color:#AA0000;">${date}</span></h1>
<h2>Game will launch in <span id="launchCountdownNumber">5</span>...</h2>
<div style="border:2px solid black;width:100%;height:15px;padding:1px;margin-bottom:20vh;"><div id="launchCountdownProgress" style="background-color:#555555;width:0%;height:100%;"></div></div>
<a href="javascript:void(0)" onclick="safeLaunch()"><code>[load without mods]</code></a>
</div>
</div>
</body>
</html>
