Skip to content

Commit

Permalink
Add display to chat, plus example mod
Browse files Browse the repository at this point in the history
  • Loading branch information
ZXMushroom63 committed Aug 25, 2024
1 parent db6e60a commit fa9f50c
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 128 deletions.
5 changes: 0 additions & 5 deletions examplemods/minecraft_on_2x_speed.js

This file was deleted.

9 changes: 9 additions & 0 deletions examplemods/minecraft_on_3x_speed.js
Original file line number Diff line number Diff line change
@@ -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;
};`);
})();
166 changes: 103 additions & 63 deletions injector.html
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ <h4>
var modapi_preinit = `globalThis.ModAPI ||= {};
ModAPI.hooks ||= {};
ModAPI.hooks._rippedData ||= [];
ModAPI.hooks._teavmMethods ||= {};
ModAPI.hooks._rippedConstructors ||= {};
ModAPI.hooks.methods ||= {};
ModAPI.hooks._rippedMethodTypeMap ||= {};
Expand Down Expand Up @@ -287,7 +288,7 @@ <h4>
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"
}\`;
Expand All @@ -298,8 +299,9 @@ <h4>
}
);
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)) {
Expand Down Expand Up @@ -344,6 +346,12 @@ <h4>
});`;
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();");
});
Expand Down Expand Up @@ -395,68 +403,71 @@ <h4>
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) {
Expand Down Expand Up @@ -496,7 +507,7 @@ <h4>
return outputValue;
},
set(object, prop, value) {
object[prop]=value;
object[prop] = value;
return true;
}
}
Expand Down Expand Up @@ -609,6 +620,7 @@ <h4>
});
};
ModAPI.events.newEvent("update");
ModAPI.require = function (module) {
ModAPI.required.add(module);
};
Expand All @@ -625,23 +637,36 @@ <h4>
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);
for (let i = 0; i < str.length; i++) {
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 ||= "";
Expand All @@ -668,12 +693,27 @@ <h4>
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]);
}
})();`;
</script>

Expand Down
Loading

0 comments on commit fa9f50c

Please sign in to comment.