diff --git a/examplemods/minecraft_on_2x_speed.js b/examplemods/minecraft_on_2x_speed.js
deleted file mode 100644
index 131b29e..0000000
--- a/examplemods/minecraft_on_2x_speed.js
+++ /dev/null
@@ -1,5 +0,0 @@
-//Very much WIP, still firguring out how to poke the dedicated server.
-(()=>{
- //PluginAPI.javaClient.$timer.$timerSpeed = 4;
- ModAPI.dedicatedServer.appendCode(`console.log(ModAPI.hooks._rippedStaticProperties[ModAPI.util.getCompiledNameFromPackage("net.lax1dude.eaglercraft.v1_8.sp.server.EaglerIntegratedServerWorker")].currentProcess)`);
-})();
\ No newline at end of file
diff --git a/examplemods/minecraft_on_3x_speed.js b/examplemods/minecraft_on_3x_speed.js
new file mode 100644
index 0000000..5e3269d
--- /dev/null
+++ b/examplemods/minecraft_on_3x_speed.js
@@ -0,0 +1,9 @@
+//Very much WIP, still firguring out how to poke the dedicated server.
+(()=>{
+ PluginAPI.javaClient.$timer.$timerSpeed = 3;
+ ModAPI.dedicatedServer.appendCode(`
+ const original_getCurrentTime = ModAPI.hooks.methods.nms_MinecraftServer_getCurrentTimeMillis;
+ ModAPI.hooks.methods.nms_MinecraftServer_getCurrentTimeMillis = function () {
+ return original_getCurrentTime() * 3n;
+ };`);
+})();
\ No newline at end of file
diff --git a/injector.html b/injector.html
index 1ebca7d..24995b2 100644
--- a/injector.html
+++ b/injector.html
@@ -199,6 +199,7 @@
var modapi_preinit = `globalThis.ModAPI ||= {};
ModAPI.hooks ||= {};
ModAPI.hooks._rippedData ||= [];
+ModAPI.hooks._teavmMethods ||= {};
ModAPI.hooks._rippedConstructors ||= {};
ModAPI.hooks.methods ||= {};
ModAPI.hooks._rippedMethodTypeMap ||= {};
@@ -287,7 +288,7 @@
return ModAPI.hooks.methods[\`${fullName}\`].apply(this, args);
}
ModAPI.hooks._rippedMethodTypeMap[\`${fullName}\`] = \`${
- match.includes("function " + fullName + "($this")
+ match.includes("($this")
? "instance" //Todo: fix static/instance detection
: "static"
}\`;
@@ -298,8 +299,9 @@
}
);
var staticVariables = [...patchedFile.matchAll(/var \S+?_\S+?_\S+? = null;/gm)].flatMap(x => {return x[0]});
- patchedFile = patchedFile.replaceAll(/var \S+?_\S+? = \$rt_classWithoutFields\(\);/gm, function (match) {
- var prefix = match.replace(" = $rt_classWithoutFields();", "");
+ //Todo: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() {
+ patchedFile = patchedFile.replaceAll(/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm, function (match) {
+ var prefix = match.replaceAll(/ = \$rt_classWithoutFields\(\S*?\);/gm, "");
var entries = [];
staticVariables.forEach(entry => {
if (entry.startsWith(prefix)) {
@@ -344,6 +346,12 @@
});`;
return match + proxy;
});
+ patchedFile = patchedFile.replaceAll(/function \$rt_\S+?\(/gm, (match)=>{
+ var name = match.replace("function ", "");
+ name = name.substring(0, name.length - 1);
+ return `ModAPI.hooks._teavmMethods[\`${name}\`]=${name};
+ ` + match;
+ });
patchedFile = patchedFile.replaceAll(/main\(\);\s*?}/gm, (match) => {
return match.replace("main();", "main();ModAPI.hooks._postInit();");
});
@@ -395,68 +403,71 @@
ModAPI.version = "v2.0";
ModAPI.flavour = "injector";
ModAPI.credits = ["ZXMushroom63", "radmanplays", "OtterCodes101", "TheIdiotPlays"];
- ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
- ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
- ModAPI.hooks._rippedData.forEach(block => {
- block.forEach(item => {
- if (typeof item === "function") {
- if (!item.$meta || typeof item.$meta.name !== "string") {
- return;
- }
+ ModAPI.hooks.regenerateClassMap = function () {
+ ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
+ ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
+ ModAPI.hooks._rippedData.forEach(block => {
+ block.forEach(item => {
+ if (typeof item === "function") {
+ if (!item.$meta || typeof item.$meta.name !== "string") {
+ return;
+ }
- var classId = item.$meta.name;
- var compiledName = ModAPI.util.getCompiledNameFromPackage(classId);
-
+ var classId = item.$meta.name;
+ var compiledName = ModAPI.util.getCompiledNameFromPackage(classId);
- if (!ModAPI.hooks._classMap[classId]) {
- ModAPI.hooks._classMap[classId] = {
- "name": classId.split(".")[classId.split(".").length - 1],
- "id": classId,
- "binaryName": item.$meta.binaryName,
- "constructors": [],
- "methods": {},
- "staticMethods": {},
- "staticVariables": {},
- "staticVariableNames": [],
- "class": item,
- "compiledName": compiledName
+
+ if (!ModAPI.hooks._classMap[classId]) {
+ ModAPI.hooks._classMap[classId] = {
+ "name": classId.split(".")[classId.split(".").length - 1],
+ "id": classId,
+ "binaryName": item.$meta.binaryName,
+ "constructors": [],
+ "methods": {},
+ "staticMethods": {},
+ "staticVariables": {},
+ "staticVariableNames": [],
+ "class": item,
+ "compiledName": compiledName
+ }
}
- }
- if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) {
- ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name;
- }
- ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName];
- ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName];
- if (item["$$constructor$$"]) {
- //Class does not have any hand written constructors
- //Eg: class MyClass {}
- ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]);
- } else {
- //Class has hand written constructors, we need to search in the stash
- ModAPI.hooks._rippedConstructorKeys.forEach(constructor => {
- if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) {
- ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]);
+ if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) {
+ ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name;
+ }
+ ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName];
+ ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName];
+ if (item["$$constructor$$"]) {
+ //Class does not have any hand written constructors
+ //Eg: class MyClass {}
+ ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]);
+ } else {
+ //Class has hand written constructors, we need to search in the stash
+ ModAPI.hooks._rippedConstructorKeys.forEach(constructor => {
+ if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) {
+ ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]);
+ }
+ });
+ }
+ ModAPI.hooks._rippedMethodKeys.forEach((method) => {
+ if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) {
+ var targetMethodMap = ModAPI.hooks._classMap[classId].methods;
+ if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") {
+ targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods;
+ }
+ targetMethodMap[method.replace(compiledName + "_", "")] = {
+ method: ModAPI.hooks.methods[method],
+ proxiedMethod: function (...args) {
+ return ModAPI.hooks.methods[method].apply(this, args);
+ },
+ methodName: method
+ };
}
});
}
- ModAPI.hooks._rippedMethodKeys.forEach((method) => {
- if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) {
- var targetMethodMap = ModAPI.hooks._classMap[classId].methods;
- if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") {
- targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods;
- }
- targetMethodMap[method] = {
- method: ModAPI.hooks.methods[method],
- proxiedMethod: function (...args) {
- return ModAPI.hooks.methods[method].apply(this, args);
- },
- methodName: method
- };
- }
- });
- }
+ });
});
- });
+ }
+ ModAPI.hooks.regenerateClassMap();
var reloadDeprecationWarnings = 0;
const TeaVM_to_BaseData_ProxyConf = {
get(target, prop, receiver) {
@@ -496,7 +507,7 @@
return outputValue;
},
set(object, prop, value) {
- object[prop]=value;
+ object[prop] = value;
return true;
}
}
@@ -609,6 +620,7 @@
});
};
ModAPI.events.newEvent("update");
+
ModAPI.require = function (module) {
ModAPI.required.add(module);
};
@@ -625,7 +637,7 @@
console.error(error);
}
}
-
+
ModAPI.util.stringToUint16Array = function stringToUint16Array(str) {
const buffer = new ArrayBuffer(str.length * 2); // 2 bytes for each char
const uint16Array = new Uint16Array(buffer);
@@ -633,15 +645,28 @@
uint16Array[i] = str.charCodeAt(i);
}
return uint16Array;
- }
+ }
- var stringDefaultConstructor = ModAPI.hooks._classMap["java.lang.String"].constructors.filter(x => {return x.length === 0})[0];
+ var stringDefaultConstructor = ModAPI.hooks._classMap["java.lang.String"].constructors.filter(x => { return x.length === 0 })[0];
ModAPI.util.string = ModAPI.util.str = function (string) {
var jclString = stringDefaultConstructor();
jclString.$characters.data = ModAPI.util.stringToUint16Array(string);
return jclString;
}
+ ModAPI.util.setStringContent = function (jclString) {
+ jclString.$characters.data = ModAPI.util.stringToUint16Array(string);
+ }
+
+ ModAPI.util.jclStrToJsStr = function (jclString) {
+ var uint16Array = jclString.$characters.data;
+ let str = '';
+ for (let i = 0; i < uint16Array.length; i++) {
+ str += String.fromCharCode(uint16Array[i]);
+ }
+ return str;
+ }
+
ModAPI.displayToChat = function (param) {
var v = typeof param === "object" ? param.msg : (param + "");
v ||= "";
@@ -668,12 +693,27 @@
var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "loadIntegratedServerSourceInline");
//Integrated server setup has a randomised suffix on the end
- integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => {return key.startsWith(integratedServerStartup); })[0];
+ integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => { return key.startsWith(integratedServerStartup); })[0];
const integratedServerStartupMethod = ModAPI.hooks.methods[integratedServerStartup];
ModAPI.hooks.methods[integratedServerStartup] = function (worker, bootstrap) {
var x = integratedServerStartupMethod.apply(this, [worker, bootstrap + ";" + globalThis.modapi_postinit + ";" + ModAPI.dedicatedServer._data.join(";")]);
return x;
};
+
+ ModAPI.events.newEvent("sendchatmessage");
+ const sendChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "sendChatMessage");
+ const sendChatMessage = ModAPI.hooks.methods[sendChatMessageMethodName];
+ ModAPI.hooks.methods[sendChatMessageMethodName] = function ($this, $message) {
+ var data = {
+ preventDefault: false,
+ message: ModAPI.util.jclStrToJsStr($message)
+ }
+ ModAPI.events.callEvent("sendchatmessage", data);
+ if (data.preventDefault) {
+ return;
+ }
+ return sendChatMessage.apply(this, [$this, ModAPI.util.str(data.message) || $message]);
+ }
})();`;
diff --git a/postinit.js b/postinit.js
index e8fd3b7..d24241d 100644
--- a/postinit.js
+++ b/postinit.js
@@ -39,68 +39,71 @@
ModAPI.version = "v2.0";
ModAPI.flavour = "injector";
ModAPI.credits = ["ZXMushroom63", "radmanplays", "OtterCodes101", "TheIdiotPlays"];
- ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
- ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
- ModAPI.hooks._rippedData.forEach(block => {
- block.forEach(item => {
- if (typeof item === "function") {
- if (!item.$meta || typeof item.$meta.name !== "string") {
- return;
- }
+ ModAPI.hooks.regenerateClassMap = function () {
+ ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
+ ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
+ ModAPI.hooks._rippedData.forEach(block => {
+ block.forEach(item => {
+ if (typeof item === "function") {
+ if (!item.$meta || typeof item.$meta.name !== "string") {
+ return;
+ }
+
+ var classId = item.$meta.name;
+ var compiledName = ModAPI.util.getCompiledNameFromPackage(classId);
- var classId = item.$meta.name;
- var compiledName = ModAPI.util.getCompiledNameFromPackage(classId);
-
- if (!ModAPI.hooks._classMap[classId]) {
- ModAPI.hooks._classMap[classId] = {
- "name": classId.split(".")[classId.split(".").length - 1],
- "id": classId,
- "binaryName": item.$meta.binaryName,
- "constructors": [],
- "methods": {},
- "staticMethods": {},
- "staticVariables": {},
- "staticVariableNames": [],
- "class": item,
- "compiledName": compiledName
+ if (!ModAPI.hooks._classMap[classId]) {
+ ModAPI.hooks._classMap[classId] = {
+ "name": classId.split(".")[classId.split(".").length - 1],
+ "id": classId,
+ "binaryName": item.$meta.binaryName,
+ "constructors": [],
+ "methods": {},
+ "staticMethods": {},
+ "staticVariables": {},
+ "staticVariableNames": [],
+ "class": item,
+ "compiledName": compiledName
+ }
}
- }
- if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) {
- ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name;
- }
- ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName];
- ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName];
- if (item["$$constructor$$"]) {
- //Class does not have any hand written constructors
- //Eg: class MyClass {}
- ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]);
- } else {
- //Class has hand written constructors, we need to search in the stash
- ModAPI.hooks._rippedConstructorKeys.forEach(constructor => {
- if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) {
- ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]);
+ if (typeof item.$meta.superclass === "function" && item.$meta.superclass.$meta) {
+ ModAPI.hooks._classMap[classId].superclass = item.$meta.superclass.$meta.name;
+ }
+ ModAPI.hooks._classMap[classId].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName];
+ ModAPI.hooks._classMap[classId].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName];
+ if (item["$$constructor$$"]) {
+ //Class does not have any hand written constructors
+ //Eg: class MyClass {}
+ ModAPI.hooks._classMap[classId].constructors.push(item["$$constructor$$"]);
+ } else {
+ //Class has hand written constructors, we need to search in the stash
+ ModAPI.hooks._rippedConstructorKeys.forEach(constructor => {
+ if (constructor.startsWith(compiledName + "__init_") && !constructor.includes("$lambda$")) {
+ ModAPI.hooks._classMap[classId].constructors.push(ModAPI.hooks._rippedConstructors[constructor]);
+ }
+ });
+ }
+ ModAPI.hooks._rippedMethodKeys.forEach((method) => {
+ if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) {
+ var targetMethodMap = ModAPI.hooks._classMap[classId].methods;
+ if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") {
+ targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods;
+ }
+ targetMethodMap[method.replace(compiledName + "_", "")] = {
+ method: ModAPI.hooks.methods[method],
+ proxiedMethod: function (...args) {
+ return ModAPI.hooks.methods[method].apply(this, args);
+ },
+ methodName: method
+ };
}
});
}
- ModAPI.hooks._rippedMethodKeys.forEach((method) => {
- if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) {
- var targetMethodMap = ModAPI.hooks._classMap[classId].methods;
- if (ModAPI.hooks._rippedMethodTypeMap[method] === "static") {
- targetMethodMap = ModAPI.hooks._classMap[classId].staticMethods;
- }
- targetMethodMap[method] = {
- method: ModAPI.hooks.methods[method],
- proxiedMethod: function (...args) {
- return ModAPI.hooks.methods[method].apply(this, args);
- },
- methodName: method
- };
- }
- });
- }
+ });
});
- });
+ }
+ ModAPI.hooks.regenerateClassMap();
var reloadDeprecationWarnings = 0;
const TeaVM_to_BaseData_ProxyConf = {
get(target, prop, receiver) {
@@ -140,7 +143,7 @@
return outputValue;
},
set(object, prop, value) {
- object[prop]=value;
+ object[prop] = value;
return true;
}
}
@@ -253,6 +256,7 @@
});
};
ModAPI.events.newEvent("update");
+
ModAPI.require = function (module) {
ModAPI.required.add(module);
};
@@ -269,7 +273,7 @@
console.error(error);
}
}
-
+
ModAPI.util.stringToUint16Array = function stringToUint16Array(str) {
const buffer = new ArrayBuffer(str.length * 2); // 2 bytes for each char
const uint16Array = new Uint16Array(buffer);
@@ -277,15 +281,28 @@
uint16Array[i] = str.charCodeAt(i);
}
return uint16Array;
- }
+ }
- var stringDefaultConstructor = ModAPI.hooks._classMap["java.lang.String"].constructors.filter(x => {return x.length === 0})[0];
+ var stringDefaultConstructor = ModAPI.hooks._classMap["java.lang.String"].constructors.filter(x => { return x.length === 0 })[0];
ModAPI.util.string = ModAPI.util.str = function (string) {
var jclString = stringDefaultConstructor();
jclString.$characters.data = ModAPI.util.stringToUint16Array(string);
return jclString;
}
+ ModAPI.util.setStringContent = function (jclString) {
+ jclString.$characters.data = ModAPI.util.stringToUint16Array(string);
+ }
+
+ ModAPI.util.jclStrToJsStr = function (jclString) {
+ var uint16Array = jclString.$characters.data;
+ let str = '';
+ for (let i = 0; i < uint16Array.length; i++) {
+ str += String.fromCharCode(uint16Array[i]);
+ }
+ return str;
+ }
+
ModAPI.displayToChat = function (param) {
var v = typeof param === "object" ? param.msg : (param + "");
v ||= "";
@@ -312,10 +329,25 @@
var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "loadIntegratedServerSourceInline");
//Integrated server setup has a randomised suffix on the end
- integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => {return key.startsWith(integratedServerStartup); })[0];
+ integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => { return key.startsWith(integratedServerStartup); })[0];
const integratedServerStartupMethod = ModAPI.hooks.methods[integratedServerStartup];
ModAPI.hooks.methods[integratedServerStartup] = function (worker, bootstrap) {
var x = integratedServerStartupMethod.apply(this, [worker, bootstrap + ";" + globalThis.modapi_postinit + ";" + ModAPI.dedicatedServer._data.join(";")]);
return x;
};
+
+ ModAPI.events.newEvent("sendchatmessage");
+ const sendChatMessageMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.client.entity.EntityPlayerSP", "sendChatMessage");
+ const sendChatMessage = ModAPI.hooks.methods[sendChatMessageMethodName];
+ ModAPI.hooks.methods[sendChatMessageMethodName] = function ($this, $message) {
+ var data = {
+ preventDefault: false,
+ message: ModAPI.util.jclStrToJsStr($message)
+ }
+ ModAPI.events.callEvent("sendchatmessage", data);
+ if (data.preventDefault) {
+ return;
+ }
+ return sendChatMessage.apply(this, [$this, ModAPI.util.str(data.message) || $message]);
+ }
})();
\ No newline at end of file