GUI COMPLETE

This commit is contained in:
ZXMushroom63 2024-08-31 17:32:03 +08:00
parent 133b6081af
commit fa9e0220b8
4 changed files with 196 additions and 191 deletions

View File

@ -158,6 +158,14 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays
} }
</style> </style>
</div>\`; </div>\`;
async function fileToDataURI(file) {
return new Promise((res, rej) => {
var fr = new FileReader();
fr.addEventListener("error", (e) => { rej(e); });
fr.addEventListener("load", (e) => { res(fr.result); });
fr.readAsDataURL(file);
});
}
window.modapi_displayModGui = async function () { window.modapi_displayModGui = async function () {
if (!getMods) { if (!getMods) {
return; return;
@ -175,14 +183,26 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays
var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); var tbody = document.querySelector("#modapi_gui_container .modTable tbody");
tbody.innerHTML = ""; tbody.innerHTML = "";
modsList.forEach((modtxt, i) => { modsList.forEach((modtxt, i) => {
if (!modtxt) { return }
var tr = document.createElement("tr"); var tr = document.createElement("tr");
var mod = document.createElement("td"); var mod = document.createElement("td");
mod.innerText = modtxt; if (modtxt.length > 125) {
try {
mod.innerText = modtxt.match(/data:text\\/\\S+?;fs=\\S+;/m)[0]
} catch (error) {
mod.innerText = "Unknown Mod.";
}
} else { mod.innerText = modtxt; }
var spacer = document.createElement("td"); var spacer = document.createElement("td");
spacer.appendChild("nothing"); spacer.classList.add("nothing");
var controls = document.createElement("td"); var controls = document.createElement("td");
var button = document.createElement("button"); var button = document.createElement("button");
button.innerText = "Delete";
button.addEventListener("click", async () => {
await removeMod(i);
window.modapi_displayModGui();
});
button.classList.add("button"); button.classList.add("button");
controls.appendChild(button); controls.appendChild(button);
tr.appendChild(mod); tr.appendChild(mod);
@ -190,6 +210,33 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays
tr.appendChild(button); tr.appendChild(button);
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
}
window.modapi_clearmods = async () => {
await resetMods();
window.modapi_displayModGui();
}
window.modapi_addmod = async () => {
var mod = window.prompt("Paste in the URL of the mod you wish to add: ");
if (!mod || mod.length === 0) {
return;
}
await addMod("web@" + mod);
window.modapi_displayModGui();
}
window.modapi_uploadmod = async () => {
var f = document.createElement("input");
f.type = "file";
f.accept = "text/javascript";
f.multiple = true;
f.addEventListener("input", async () => {
if (f.files.length < 1) {
return;
}
for (let i = 0; i < f.files.length; i++) {
await addMod("web@" + (await fileToDataURI(f.files[i])).replaceAll(";base64", ";fs=" + f.files[i].name + ";base64"));
}
window.modapi_displayModGui();
});
f.click();
} }
})();`; })();`;

View File

@ -158,6 +158,14 @@
} }
</style> </style>
</div>`; </div>`;
async function fileToDataURI(file) {
return new Promise((res, rej) => {
var fr = new FileReader();
fr.addEventListener("error", (e) => { rej(e); });
fr.addEventListener("load", (e) => { res(fr.result); });
fr.readAsDataURL(file);
});
}
window.modapi_displayModGui = async function () { window.modapi_displayModGui = async function () {
if (!getMods) { if (!getMods) {
return; return;
@ -175,14 +183,26 @@
var tbody = document.querySelector("#modapi_gui_container .modTable tbody"); var tbody = document.querySelector("#modapi_gui_container .modTable tbody");
tbody.innerHTML = ""; tbody.innerHTML = "";
modsList.forEach((modtxt, i) => { modsList.forEach((modtxt, i) => {
if (!modtxt) { return }
var tr = document.createElement("tr"); var tr = document.createElement("tr");
var mod = document.createElement("td"); var mod = document.createElement("td");
mod.innerText = modtxt; if (modtxt.length > 125) {
try {
mod.innerText = modtxt.match(/data:text\/\S+?;fs=\S+;/m)[0]
} catch (error) {
mod.innerText = "Unknown Mod.";
}
} else { mod.innerText = modtxt; }
var spacer = document.createElement("td"); var spacer = document.createElement("td");
spacer.appendChild("nothing"); spacer.classList.add("nothing");
var controls = document.createElement("td"); var controls = document.createElement("td");
var button = document.createElement("button"); var button = document.createElement("button");
button.innerText = "Delete";
button.addEventListener("click", async () => {
await removeMod(i);
window.modapi_displayModGui();
});
button.classList.add("button"); button.classList.add("button");
controls.appendChild(button); controls.appendChild(button);
tr.appendChild(mod); tr.appendChild(mod);
@ -190,6 +210,33 @@
tr.appendChild(button); tr.appendChild(button);
tbody.appendChild(tr); tbody.appendChild(tr);
}); });
}
window.modapi_clearmods = async () => {
await resetMods();
window.modapi_displayModGui();
}
window.modapi_addmod = async () => {
var mod = window.prompt("Paste in the URL of the mod you wish to add: ");
if (!mod || mod.length === 0) {
return;
}
await addMod("web@" + mod);
window.modapi_displayModGui();
}
window.modapi_uploadmod = async () => {
var f = document.createElement("input");
f.type = "file";
f.accept = "text/javascript";
f.multiple = true;
f.addEventListener("input", async () => {
if (f.files.length < 1) {
return;
}
for (let i = 0; i < f.files.length; i++) {
await addMod("web@" + (await fileToDataURI(f.files[i])).replaceAll(";base64", ";fs=" + f.files[i].name + ";base64"));
}
window.modapi_displayModGui();
});
f.click();
} }
})(); })();

View File

@ -28,8 +28,7 @@ async function getMods() {
const transaction = db.transaction(["filesystem"], "readonly"); const transaction = db.transaction(["filesystem"], "readonly");
const objectStore = transaction.objectStore("filesystem"); const objectStore = transaction.objectStore("filesystem");
const object = await promisifyIDBRequest(objectStore.get("mods.txt")); const object = await promisifyIDBRequest(objectStore.get("mods.txt"));
const decoder = new TextDecoder("utf-8"); return object ? (await object.text()).split("|") : [];
return object ? decoder.decode(object).split("|") : [];
} }
async function saveMods(mods) { async function saveMods(mods) {
@ -46,26 +45,21 @@ async function addMod(mod) {
const mods = await getMods(); const mods = await getMods();
mods.push(mod); mods.push(mod);
await saveMods(mods); await saveMods(mods);
console.log("Mod added: " + mod);
} }
async function removeMod(index) { async function removeMod(index) {
const mods = await getMods(); const mods = await getMods();
if (index >= 0 && index < mods.length) { if (index >= 0 && index < mods.length) {
const removedMod = mods.splice(index, 1); mods.splice(index, 1);
await saveMods(mods); await saveMods(mods);
console.log("Mod removed: " + removedMod);
} else {
console.log("Invalid index");
} }
} }
async function resetMods() { async function resetMods() {
await saveMods([]); await saveMods([]);
console.log("Mods reset");
} }
window.modLoader = async function modLoader(modsArr) { window.modLoader = async function modLoader(modsArr = []) {
if (!window.eaglerMLoaderMainRun) { if (!window.eaglerMLoaderMainRun) {
var searchParams = new URLSearchParams(location.search); var searchParams = new URLSearchParams(location.search);
searchParams.getAll("mod").forEach((modToAdd) => { searchParams.getAll("mod").forEach((modToAdd) => {
@ -94,52 +88,13 @@ window.modLoader = async function modLoader(modsArr) {
}); });
} }
// Reverse engineer eaglercraftx virtual file system to gain external access to mod store WITHOUT messing with java teavm nonsense
var StoreId = "EF_MODS";
var decoder = new TextDecoder("utf-8");
console.log("[EaglerML] Searching in iDB"); console.log("[EaglerML] Searching in iDB");
try { try {
var database = await promisifyIDBRequest(indexedDB.open(StoreId)); var idbMods = await getMods();
var storeIsValid = !!database.objectStoreNames[0]; modsArr.concat(idbMods
if (!storeIsValid) { .filter(x => { return x && x.length > 0 })
throw new Error("Invalid object store"); .flatMap(x => { if (x.startsWith("web@")) { return x.replace("web@", "") } return x })
} );
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) {
throw new Error("No mods.txt found");
}
var mods = decoder.decode(object.data);
if (mods.length === 0) {
throw new Error("No mods found");
}
var modsArr = mods.split("|");
for (var modFilePath of modsArr) {
if (modFilePath.length === 0) {
continue;
}
var modUrl = null;
if (modFilePath.startsWith("web@")) {
modUrl = modFilePath.replace("web@", "");
} else {
var modFile = await promisifyIDBRequest(objectStore.get(["mods/" + modFilePath]));
if (!modFile) {
continue;
}
var modData = decoder.decode(modFile.data);
var modBlob = new Blob([modData], {
type: 'text/javascript'
});
modUrl = URL.createObjectURL(modBlob);
}
if (!modUrl) {
continue;
}
modsArr.push(modUrl);
console.log("Loaded iDB mod: " + modFilePath);
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }

View File

@ -28,8 +28,7 @@ async function getMods() {
const transaction = db.transaction(["filesystem"], "readonly"); const transaction = db.transaction(["filesystem"], "readonly");
const objectStore = transaction.objectStore("filesystem"); const objectStore = transaction.objectStore("filesystem");
const object = await promisifyIDBRequest(objectStore.get("mods.txt")); const object = await promisifyIDBRequest(objectStore.get("mods.txt"));
const decoder = new TextDecoder("utf-8"); return object ? (await object.text()).split("|") : [];
return object ? decoder.decode(object).split("|") : [];
} }
async function saveMods(mods) { async function saveMods(mods) {
@ -46,17 +45,13 @@ async function addMod(mod) {
const mods = await getMods(); const mods = await getMods();
mods.push(mod); mods.push(mod);
await saveMods(mods); await saveMods(mods);
console.log("Mod added: " + mod);
} }
async function removeMod(index) { async function removeMod(index) {
const mods = await getMods(); const mods = await getMods();
if (index >= 0 && index < mods.length) { if (index >= 0 && index < mods.length) {
const removedMod = mods.splice(index, 1); mods.splice(index, 1);
await saveMods(mods); await saveMods(mods);
console.log("Mod removed: " + removedMod);
} else {
console.log("Invalid index");
} }
} }
@ -65,7 +60,7 @@ async function resetMods() {
console.log("Mods reset"); console.log("Mods reset");
} }
window.modLoader = async function modLoader(modsArr) { window.modLoader = async function modLoader(modsArr = []) {
if (!window.eaglerMLoaderMainRun) { if (!window.eaglerMLoaderMainRun) {
var searchParams = new URLSearchParams(location.search); var searchParams = new URLSearchParams(location.search);
searchParams.getAll("mod").forEach((modToAdd) => { searchParams.getAll("mod").forEach((modToAdd) => {
@ -94,52 +89,13 @@ window.modLoader = async function modLoader(modsArr) {
}); });
} }
// Reverse engineer eaglercraftx virtual file system to gain external access to mod store WITHOUT messing with java teavm nonsense
var StoreId = "EF_MODS";
var decoder = new TextDecoder("utf-8");
console.log("[EaglerML] Searching in iDB"); console.log("[EaglerML] Searching in iDB");
try { try {
var database = await promisifyIDBRequest(indexedDB.open(StoreId)); var idbMods = await getMods();
var storeIsValid = !!database.objectStoreNames[0]; modsArr.concat(idbMods
if (!storeIsValid) { .filter(x => { return x && x.length > 0 })
throw new Error("Invalid object store"); .flatMap(x => { if (x.startsWith("web@")) { return x.replace("web@", "") } return x })
} );
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) {
throw new Error("No mods.txt found");
}
var mods = decoder.decode(object.data);
if (mods.length === 0) {
throw new Error("No mods found");
}
var modsArr = mods.split("|");
for (var modFilePath of modsArr) {
if (modFilePath.length === 0) {
continue;
}
var modUrl = null;
if (modFilePath.startsWith("web@")) {
modUrl = modFilePath.replace("web@", "");
} else {
var modFile = await promisifyIDBRequest(objectStore.get(["mods/" + modFilePath]));
if (!modFile) {
continue;
}
var modData = decoder.decode(modFile.data);
var modBlob = new Blob([modData], {
type: 'text/javascript'
});
modUrl = URL.createObjectURL(modBlob);
}
if (!modUrl) {
continue;
}
modsArr.push(modUrl);
console.log("Loaded iDB mod: " + modFilePath);
}
} catch (error) { } catch (error) {
console.error(error); console.error(error);
} }