This commit is contained in:
ZXMushroom63 2025-03-17 17:53:41 +08:00
commit f21266f57f
9 changed files with 204 additions and 51 deletions

32
backgroundLogger.js Normal file
View File

@ -0,0 +1,32 @@
var backgroundLogs = document.createElement("div");
backgroundLogs.style = `
color: lime;
opacity: 0.1;
font-family: monospace;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
pointer-events: none;
overflow: none;
user-select: none;
`;
const bgLogsList = [];
document.documentElement.appendChild(backgroundLogs);
var dirty = true;
function backgroundLog(text, unSuppress) {
var linesExcess = backgroundLogs.scrollHeight - window.innerHeight;
for (i = 0; i < linesExcess; i++) {
bgLogsList.shift();
}
bgLogsList.push(text);
dirty = true;
if (!unSuppress) {
return;
}
dirty = false;
backgroundLogs.innerText = bgLogsList.join("\n");
}
backgroundLog("Awaiting input...");

View File

@ -99,7 +99,10 @@ The ModAPI object has the following methods:
- Gets the frames per second of the game - Gets the frames per second of the game
- `promisify(asyncJavaMethod: Method | Constructor) : PromisifiedJavaRunner` - `promisify(asyncJavaMethod: Method | Constructor) : PromisifiedJavaRunner`
- Allows running java methods that are @Async/@Async dependent. - Allows running java methods that are @Async/@Async dependent.
- More [PromisifyDocumentation](promisify.md) - More: [PromisifyDocumentation](promisify.md)
- `addCredit(category: String, contributor: String, contents: String)`
- Lets you easily add credits to Eaglercraft's credits.txt
- eg: `ModAPI.addCredit("My Cool Mod", "Username", " - Coded the mod\n - Wrote somne credits")`
## Handling strings, numbers and booleans to and from java. ## Handling strings, numbers and booleans to and from java.

View File

@ -11,3 +11,7 @@ Methods:
- `ModAPI.meta.icon(iconURL: String)` - `ModAPI.meta.icon(iconURL: String)`
- Sets the icon of the mod. - Sets the icon of the mod.
- It can be extremely low res, it will not appear blurry. - It can be extremely low res, it will not appear blurry.
- `ModAPI.meta.version(versionCode: String)`
- Sets the version of the mod. Appended after the title.
- `ModAPI.meta.config(configFn: Function)`
- Once the client is fully loaded, creates a button in the mod manager GUI that runs the specified function when pressed.

View File

@ -31,7 +31,7 @@ var asyncDownloadRemoteURI = ModAPI.promisify(ModAPI.hooks.methods.nlevi_Platfor
console.log(typeof asyncDownloadRemoteURI); //Logs function console.log(typeof asyncDownloadRemoteURI); //Logs function
``` ```
When it is called, like any other asyncronoush function, it returns a `Promise` object. When it is called, like any other asyncronous function, it returns a `Promise` object.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
You can replace the argument with any other method or constructor, including non asynchronous ones. You can replace the argument with any other method or constructor, including non asynchronous ones.

View File

@ -90,8 +90,12 @@
>Choose .html file...</label >Choose .html file...</label
> >
<br /> <br />
<span><label>Minify:&nbsp;</label><input type="checkbox" oninput="globalThis.doShronk = this.checked"> <span>
&nbsp;&nbsp;&nbsp;<label>EaglerForge:&nbsp;</label><input checked type="checkbox" oninput="globalThis.doEaglerforge = this.checked"> <label>Minify:&nbsp;</label><input type="checkbox" oninput="globalThis.doShronk = this.checked">
&nbsp;&nbsp;&nbsp;
<label>MinifyExtras:&nbsp;</label><input type="checkbox" oninput="globalThis.doShronkPlus = this.checked">
&nbsp;&nbsp;&nbsp;
<label>EaglerForge:&nbsp;</label><input checked type="checkbox" oninput="globalThis.doEaglerforge = this.checked">
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code id="status">Awaiting input...</code></span> &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<code id="status">Awaiting input...</code></span>
<br /><br /> <br /><br />
<button class="btn btn-primary" id="giveme">Make modded client</button> <button class="btn btn-primary" id="giveme">Make modded client</button>
@ -163,6 +167,7 @@
`; `;
var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`; var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`;
</script> </script>
<script src="backgroundLogger.js"></script>
<script src="patches.js"></script> <script src="patches.js"></script>
<script src="injector.minify.js"></script> <script src="injector.minify.js"></script>
<script src="injector.js"></script> <script src="injector.js"></script>

View File

@ -1,4 +1,4 @@
globalThis.ModAPIVersion = "v2.7"; globalThis.ModAPIVersion = "v2.7.3";
globalThis.doEaglerforge = true; globalThis.doEaglerforge = true;
document.querySelector("title").innerText = `EaglerForge Injector ${ModAPIVersion}`; document.querySelector("title").innerText = `EaglerForge Injector ${ModAPIVersion}`;
document.querySelector("h1").innerText = `EaglerForge Injector ${ModAPIVersion}`; document.querySelector("h1").innerText = `EaglerForge Injector ${ModAPIVersion}`;
@ -8,6 +8,7 @@ function wait(ms) {
}); });
} }
function _status(x) { function _status(x) {
backgroundLog(x, true);
document.querySelector("#status").innerText = x; document.querySelector("#status").innerText = x;
} }
function entriesToStaticVariableProxy(entries, prefix, clinitList) { function entriesToStaticVariableProxy(entries, prefix, clinitList) {
@ -77,6 +78,7 @@ async function processClasses(string) {
if (!confirm("The minify step is extremely slow, especially on lower-end devices, and can take upwards of 15 minutes.")) { if (!confirm("The minify step is extremely slow, especially on lower-end devices, and can take upwards of 15 minutes.")) {
return; return;
} }
backgroundLog("[MINIFY] Minify warning bypassed.");
} }
_status("Beginning patch process..."); _status("Beginning patch process...");
await wait(50); await wait(50);
@ -101,6 +103,7 @@ var main;(function(){`
"var main;\n(function() {", "var main;\n(function() {",
modapi_preinit + "var main;\n(function() {" modapi_preinit + "var main;\n(function() {"
); );
backgroundLog("[JSPATCH] Adding pre-init script");
patchedFile = patchedFile.replace( patchedFile = patchedFile.replace(
/function \$rt_metadata\(data\)( ?){/gm, /function \$rt_metadata\(data\)( ?){/gm,
`function $rt_metadata(data) { `function $rt_metadata(data) {
@ -108,20 +111,21 @@ var main;(function(){`
ModAPI.hooks._rippedData.push(data); ModAPI.hooks._rippedData.push(data);
/*/EaglerForge Client Patch/*/` /*/EaglerForge Client Patch/*/`
); );
backgroundLog("[JSPATCH] Redirecting $rt_metadata to ModAPI.hooks._rippedData");
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
`return thread != null && thread.isResuming()`, `return thread != null && thread.isResuming()`,
(match) => { (match) => {
return freezeCallstack + match; return freezeCallstack + match;
} }
); );
backgroundLog("[JSPATCH] Freeze-callstack patch on TeaVMThread.isResuming()");
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
`return thread != null && thread.isSuspending();`, `return thread != null && thread.isSuspending();`,
(match) => { (match) => {
return freezeCallstack + match; return freezeCallstack + match;
} }
); );
backgroundLog("[JSPATCH] Freeze-callstack patch on TeaVMThread.isSuspending()");
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
`return $rt_currentNativeThread;`, `return $rt_currentNativeThread;`,
@ -132,12 +136,12 @@ var main;(function(){`
); );
} }
); );
backgroundLog("[JSPATCH] Freeze-callstack patch thread getter");
patchedFile = patchedFile.replaceAll("function TeaVMThread(", "globalThis.ModAPI.hooks.TeaVMThread = TeaVMThread;\nfunction TeaVMThread("); patchedFile = patchedFile.replaceAll("function TeaVMThread(", "globalThis.ModAPI.hooks.TeaVMThread = TeaVMThread;\nfunction TeaVMThread(");
_status("Getting clinit list..."); _status("Getting clinit list...");
var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x => x[0].replaceAll("function ", "").replaceAll("(", "").trim()); var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x => x[0].replaceAll("function ", "").replaceAll("(", "").trim());
console.log(clinitList);
_status("Extracting constructors and methods..."); _status("Extracting constructors and methods...");
await wait(50); await wait(50);
@ -158,6 +162,8 @@ var main;(function(){`
} }
); );
backgroundLog("-> Extract contructor 1");
const extractInternalConstructorRegex = const extractInternalConstructorRegex =
/^\s*function (\S*?)__init_\d*?\(\$this/gm; //same as extract constructor regex, but only allow $this as first argument /^\s*function (\S*?)__init_\d*?\(\$this/gm; //same as extract constructor regex, but only allow $this as first argument
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
@ -172,6 +178,8 @@ var main;(function(){`
} }
); );
backgroundLog("-> Extract contructor 2");
const extractInstanceMethodRegex = const extractInstanceMethodRegex =
/^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm /^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm
const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm
@ -198,6 +206,10 @@ var main;(function(){`
); );
} }
); );
backgroundLog("-> Extract instance methods");
backgroundLog("-> Expose instance methods");
var staticVariables = [ var staticVariables = [
...patchedFile.matchAll(/var \S+?_\S+?_\S+? = /gm), ...patchedFile.matchAll(/var \S+?_\S+?_\S+? = /gm),
].flatMap((x) => { ].flatMap((x) => {
@ -205,6 +217,7 @@ var main;(function(){`
}).filter(x => { }).filter(x => {
return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$")) return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$"))
}); });
backgroundLog("-> Extract static variables");
//Also stores classes from $rt_classWithoutFields(0) //Also stores classes from $rt_classWithoutFields(0)
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, /var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
@ -240,6 +253,7 @@ var main;(function(){`
); );
//Edge cases. sigh //Edge cases. sigh
//Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() { //Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() {
backgroundLog("-> Expose static variables");
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
@ -307,10 +321,13 @@ var main;(function(){`
\<script id="libserverside"\>{"._|_libserverside_|_."}\<\/script\> \<script id="libserverside"\>{"._|_libserverside_|_."}\<\/script\>
\<script id="__eaglerforgeinjector_installation_flag__"\>console.log("Thank you for using EaglerForge!");\<\/script\>` \<script id="__eaglerforgeinjector_installation_flag__"\>console.log("Thank you for using EaglerForge!");\<\/script\>`
); );
patchedFile = patchedFile.replace(`<title>EaglercraftX 1.8</title>`, `<title>EFI ${globalThis.ModAPIVersion}</title>`); backgroundLog("[HTML] Injecting script files");
patchedFile = patchedFile.replace(`<title>EaglercraftX`, `<title>EFI ${globalThis.ModAPIVersion} on`);
backgroundLog("[HTML] Injecting title");
patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => { patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => {
return match.replace("main();", "main();ModAPI.hooks._postInit();"); return match.replace("main();", "main();ModAPI.hooks._postInit();");
}); });
backgroundLog("[HTML] Injecting main function");
_status("Done, awaiting input..."); _status("Done, awaiting input...");
await wait(50); await wait(50);
@ -334,7 +351,8 @@ document.querySelector("#giveme").addEventListener("click", () => {
if (globalThis.doEaglerforge) { if (globalThis.doEaglerforge) {
if (string.includes("__eaglerforgeinjector_installation_flag__")) { if (string.includes("__eaglerforgeinjector_installation_flag__")) {
return alert("this file already has eaglerforge injected in it, you nonce.\nif you're trying to update, you need a vanilla file."); backgroundLog("Detected input containing EFI installation flag.", true);
return alert("this file already has EaglerForge injected in it, you nonce.\nif you're trying to update, you need a vanilla file.");
} }
patchedFile = await processClasses(patchedFile); patchedFile = await processClasses(patchedFile);
} else if (globalThis.doShronk) { } else if (globalThis.doShronk) {
@ -344,6 +362,7 @@ document.querySelector("#giveme").addEventListener("click", () => {
patchedFile.replace(`{"._|_libserverside_|_."}`, ""); patchedFile.replace(`{"._|_libserverside_|_."}`, "");
var blob = new Blob([patchedFile], { type: file.type }); var blob = new Blob([patchedFile], { type: file.type });
saveAs(blob, "processed." + fileType); saveAs(blob, "processed." + fileType);
backgroundLog("Saving file...", true);
}); });
}); });

View File

@ -1,23 +1,17 @@
// Babel plugin to transform functions and calls const MINIFY = function () {
const ASYNC_PLUGIN_1 = function ({ types: t }) {
return { return {
visitor: { visitor: {
FunctionDeclaration(path) { Identifier(path) {
console.log(path); if (path.node.name === "$ptr") {
path.node.async = true; path.node.name = "r";
},
ArrowFunctionExpression(path) {
console.log(path);
path.node.async = true;
},
CallExpression(path) {
console.log(path);
if (path.parent.type !== 'AwaitExpression') {
path.replaceWith(
t.awaitExpression(path.node)
);
} }
} if (path.node.name === "$tmp") {
path.node.name = "m";
}
if (path.node.name === "$thread") {
path.node.name = "t";
}
},
} }
}; };
}; };
@ -31,7 +25,7 @@ async function shronk(input) {
inputHtml = `<script>${input}</script>`; inputHtml = `<script>${input}</script>`;
} }
_status("[ASYNC_PLUGIN_1] Parsing html..."); _status("[MINIFY] Parsing html...");
await wait(50); await wait(50);
const parser = new DOMParser(); const parser = new DOMParser();
const doc = parser.parseFromString(inputHtml, 'text/html'); const doc = parser.parseFromString(inputHtml, 'text/html');
@ -40,18 +34,20 @@ async function shronk(input) {
for (let i = 0; i < scriptTags.length; i++) { for (let i = 0; i < scriptTags.length; i++) {
const scriptTag = scriptTags[i]; const scriptTag = scriptTags[i];
const code = scriptTag.textContent; const code = scriptTag.textContent;
_status("[ASYNC_PLUGIN_1] Transpiling script #" + (i + 1) + " of length " + Math.round(code.length / 1000) + "k..."); _status("[MINIFY] Transpiling script #" + (i + 1) + " of length " + Math.round(code.length / 1000) + "k...");
await wait(150); await wait(150);
const output = Babel.transform(code, { const output = Babel.transform(code, {
plugins: [] plugins: globalThis.doShronkPlus ? [
MINIFY()
] : []
}); });
scriptTag.textContent = output.code; scriptTag.textContent = output.code;
await wait(10); await wait(10);
} }
_status("[ASYNC_PLUGIN_1] Job complete!"); _status("[MINIFY] Job complete!");
await wait(50); await wait(50);
if (isHtml) { if (isHtml) {

View File

@ -10,7 +10,9 @@ globalThis.modapi_guikit = "(" + (() => {
"hey you should check out https://github.com/ZXMushroom63/scratch-gui", "hey you should check out https://github.com/ZXMushroom63/scratch-gui",
"99% of people stop gambling before they win big.", "99% of people stop gambling before they win big.",
"Now with free estradiol!", "Now with free estradiol!",
"Now with H.I.V (Hyper Injected Virtual-debugger)" "Now with H.I.V (Hyper Injected Virtual-debugger)",
"asdasd",
"Star us on GitHub to support us! https://github.com/EaglerForge/EaglerForgeInjector"
]; ];
var gui = `<div id="modapi_gui_container"> var gui = `<div id="modapi_gui_container">
<header> <header>
@ -185,6 +187,7 @@ globalThis.modapi_guikit = "(" + (() => {
document.querySelector("#modapi_gui_container").remove(); document.querySelector("#modapi_gui_container").remove();
} }
var element = document.createElement("div"); var element = document.createElement("div");
element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]); element.innerHTML = gui.replace("{splash_msg}", splashes[Math.floor(Math.random() * splashes.length)]);
@ -245,15 +248,28 @@ globalThis.modapi_guikit = "(" + (() => {
spacer.classList.add("nothing"); spacer.classList.add("nothing");
var controls = document.createElement("td"); var controls = document.createElement("td");
var button = document.createElement("button"); var deleteBtn = document.createElement("button");
button.innerText = "Delete"; deleteBtn.innerText = "Delete";
button.style.height = "3rem"; deleteBtn.style.height = "3rem";
button.addEventListener("click", async () => { deleteBtn.addEventListener("click", async () => {
await removeMod(i); await removeMod(i);
window.modapi_displayModGui(); window.modapi_displayModGui();
}); });
button.classList.add("button"); deleteBtn.classList.add("button");
controls.appendChild(button); controls.appendChild(deleteBtn);
if (typeof ModAPI.meta._configMap[hash] === "function") {
var configBtn = document.createElement("button");
configBtn.innerText = "Config";
configBtn.style.height = "3rem";
configBtn.style.marginLeft = "1rem";
configBtn.addEventListener("click", async () => {
ModAPI.meta._configMap[hash]();
});
configBtn.classList.add("button");
controls.appendChild(configBtn);
}
tr.appendChild(mod); tr.appendChild(mod);
tr.appendChild(spacer); tr.appendChild(spacer);
tr.appendChild(controls); tr.appendChild(controls);

View File

@ -3,6 +3,7 @@ globalThis.modapi_postinit = "(" + (() => {
//This script cannot contain backticks, escape characters, or backslashes in order to inject into the dedicated server code. //This script cannot contain backticks, escape characters, or backslashes in order to inject into the dedicated server code.
var startedModLoader = false; var startedModLoader = false;
var BACKSLASH = String.fromCharCode(92); var BACKSLASH = String.fromCharCode(92);
var LF = String.fromCharCode(10);
var STRIP_COMMENTS = new RegExp(atob("KChcL1wvLiokKXwoXC9cKltcc1xTXSo/XCpcLykp"), "gm"); var STRIP_COMMENTS = new RegExp(atob("KChcL1wvLiokKXwoXC9cKltcc1xTXSo/XCpcLykp"), "gm");
var ARGUMENT_NAMES = new RegExp(atob("KFteXHMsXSsp"), "g"); var ARGUMENT_NAMES = new RegExp(atob("KFteXHMsXSsp"), "g");
@ -21,17 +22,66 @@ globalThis.modapi_postinit = "(" + (() => {
ModAPI.meta = {}; ModAPI.meta = {};
ModAPI.meta._titleMap = {}; ModAPI.meta._titleMap = {};
ModAPI.meta._descriptionMap = {}; ModAPI.meta._descriptionMap = {};
ModAPI.meta._configMap = {};
ModAPI.meta._developerMap = {}; ModAPI.meta._developerMap = {};
ModAPI.meta._iconMap = {}; ModAPI.meta._iconMap = {};
ModAPI.meta._versionMap = {}; ModAPI.meta._versionMap = {};
const credits = {};
ModAPI.addCredit = function (category, name, contents) {
if (!credits[category]) {
credits[category] = [];
}
credits[category].push(LF + LF + " " + name + ": " + LF + LF + contents);
}
function getCreditsString() {
return Object.entries(credits).map((entry) => {
return " "+entry[0] + LF + " " + (new Array(entry[0].length)).fill("~").join("") + entry[1].join("") + LF + LF + LF;
}).join("");
}
ModAPI.array = {}; ModAPI.array = {};
ModAPI.version = "__modapi_version_code__"; ModAPI.version = "__modapi_version_code__";
ModAPI.flavour = "injector"; ModAPI.flavour = "injector";
ModAPI.GNU = "terry pratchett"; ModAPI.GNU = "terry pratchett";
ModAPI.credits = ["ZXMushroom63", "radmanplays", "Murturtle", "OtterCodes101", "TheIdiotPlays", "OeildeLynx31", "Stpv22"];
ModAPI.addCredit("EaglerForge Devs", "ZXMushroom63",
" - Built the original PluginAPI for EaglerReborn" + LF +
" - Built EaglerForgeInjector as a procedural replacement for EaglerForge clients" + LF +
" - Made the mod loader and gui loader" + LF +
" - Added singleplayer support" + LF +
" - Made the AsyncSink corelib");
ModAPI.addCredit("EaglerForge Devs", "radmanplays",
" - Ported and maintained EaglerReborn's PluginAPI to modern version of eaglercrafts (u22+)" + LF +
" - Rebranded PluginAPI to ModAPI" + LF +
" - Added various new features to ModAPI" + LF +
" - Made the worldedit mod + a few other mods");
ModAPI.addCredit("EaglerForge Devs", "LeahOnBrainrot / OtterCodes101 / OtterDev",
" - Created EaglerReborn" + LF +
" - EaglerForge developer" + LF +
" - Helped update the client to newer versions" + LF +
" - Made signed clients work" + LF +
" - Maintainer nowadays" + LF +
" - Various bug fixes for EaglerForgeInjector");
ModAPI.addCredit("EaglerForge Devs", "Murturtle",
" - Added the render event to EaglerForgeInjector" + LF +
" - Added pi optimiser to the injector (now removed)");
ModAPI.addCredit("EaglerForge Devs", "TheIdiotPlays",
" - Made the mod manager GUI");
ModAPI.addCredit("EaglerForge Devs", "OeildeLynx31",
" - Work on the worldedit mod");
ModAPI.addCredit("EaglerForge Devs", "Stpv22",
" - Made the mod gui open before the client starts");
function limitSize(x, n) { function limitSize(x, n) {
if (!x) {
return "";
}
if (x.length > n) { if (x.length > n) {
return x.substring(0, n) + "…"; return x.substring(0, n) + "…";
} else { } else {
@ -41,12 +91,12 @@ globalThis.modapi_postinit = "(" + (() => {
function arraysAreSame(arr1, arr2) { function arraysAreSame(arr1, arr2) {
if (!arr1 || !arr2) if (!arr1 || !arr2)
return false; return false;
if(arr1 === arr2) if (arr1 === arr2)
return true; return true;
if (arr1.length !== arr2.length) if (arr1.length !== arr2.length)
return false; return false;
for (var i = 0, l=arr1.length; i < l; i++) { for (var i = 0, l = arr1.length; i < l; i++) {
if (arr1[i] instanceof Array && arr2[i] instanceof Array) { if (arr1[i] instanceof Array && arr2[i] instanceof Array) {
if (!arr1[i].equals(arr2[i])) if (!arr1[i].equals(arr2[i]))
return false; return false;
@ -115,6 +165,18 @@ globalThis.modapi_postinit = "(" + (() => {
} }
ModAPI.meta._descriptionMap[document.currentScript.getAttribute("data-hash")] = limitSize(desc, 160); ModAPI.meta._descriptionMap[document.currentScript.getAttribute("data-hash")] = limitSize(desc, 160);
} }
ModAPI.meta.config = function (conf) {
if (typeof conf !== "function") {
return console.log("[ModAPIMeta] Config value was not a function");
}
if (!document.currentScript || document.currentScript.getAttribute("data-isMod") !== "true") {
return console.log("[ModAPIMeta] Cannot set meta for non-mod script.");
}
if (!document.currentScript.hasAttribute("data-hash")) {
return console.log("[ModAPIMeta] Script does not have a hashcode.");
}
ModAPI.meta._configMap[document.currentScript.getAttribute("data-hash")] = conf;
}
ModAPI.meta.version = function (ver) { ModAPI.meta.version = function (ver) {
if (!document.currentScript || document.currentScript.getAttribute("data-isMod") !== "true") { if (!document.currentScript || document.currentScript.getAttribute("data-isMod") !== "true") {
return console.log("[ModAPIMeta] Cannot set meta for non-mod script."); return console.log("[ModAPIMeta] Cannot set meta for non-mod script.");
@ -343,7 +405,7 @@ globalThis.modapi_postinit = "(" + (() => {
"getConstructorByArgs": function (...argNames) { "getConstructorByArgs": function (...argNames) {
if (!argumentCache) { if (!argumentCache) {
argumentCache = []; argumentCache = [];
this.internalConstructors.forEach(x=>{ this.internalConstructors.forEach(x => {
argumentCache.push(getParamNames(x).slice(1).map(y => y.substring(1))); argumentCache.push(getParamNames(x).slice(1).map(y => y.substring(1)));
}); });
} }
@ -771,7 +833,7 @@ globalThis.modapi_postinit = "(" + (() => {
if (!object) { if (!object) {
return null; return null;
} }
if (prop in object) { if ((prop in object) && Object.keys(object).includes(prop)) {
return prop; return prop;
} }
var possibleKeys = Object.keys(object).filter(x => { return x.startsWith(prop) }); var possibleKeys = Object.keys(object).filter(x => { return x.startsWith(prop) });
@ -780,7 +842,7 @@ globalThis.modapi_postinit = "(" + (() => {
}) })
return possibleKeys.sort((a, b) => { return possibleKeys.sort((a, b) => {
return a.length - b.length; return a.length - b.length;
})[0] || null; })[0] || prop;
} }
ModAPI.util.modifyFunction = function (fn, patcherFn) { ModAPI.util.modifyFunction = function (fn, patcherFn) {
@ -821,6 +883,22 @@ globalThis.modapi_postinit = "(" + (() => {
return originalUpdate.apply(this, args); return originalUpdate.apply(this, args);
}; };
const getCreditsName = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.EagRuntime", "getResourceString");
const originalGetCredits = ModAPI.hooks.methods[getCreditsName];
ModAPI.hooks.methods[getCreditsName] = function ($path) {
if (!$path) {
return originalGetCredits.apply(this, [$path]);
}
if (ModAPI.util.ustr($path).toLowerCase().endsWith("credits.txt")) {
var out = originalGetCredits.apply(this, [$path]);
out = ModAPI.util.ustr(out);
out = getCreditsString() + out;
out = ModAPI.util.str(out);
return out;
}
return originalGetCredits.apply(this, [$path]);
};
const initMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.Minecraft", "startGame"); const initMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.Minecraft", "startGame");
const originalInit = ModAPI.hooks.methods[initMethodName]; const originalInit = ModAPI.hooks.methods[initMethodName];
ModAPI.hooks.methods[initMethodName] = function (...args) { ModAPI.hooks.methods[initMethodName] = function (...args) {
@ -1105,7 +1183,7 @@ globalThis.modapi_postinit = "(" + (() => {
} }
ModAPI.keygen.entity = function (entity) { ModAPI.keygen.entity = function (entity) {
var hashMap = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.entity.EntityList").staticVariables.idToClassMapping).getCorrective(); var hashMap = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.entity.EntityList").staticVariables.idToClassMapping).getCorrective();
var values = hashMap.keys.getRef().data.filter(x=>hashMap.get(x)); var values = hashMap.keys.getRef().data.filter(x => hashMap.get(x));
return qhash(entity, values, 127); return qhash(entity, values, 127);
} }
}).toString() + ")();"; }).toString() + ")();";