From 2bb2231d45625c86b13cc0d8d3c15040ede14bc2 Mon Sep 17 00:00:00 2001 From: radmanplays <95340057+radmanplays@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:26:11 +0330 Subject: [PATCH 01/20] Update mobnpcspawner.js --- examplemods/mobnpcspawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examplemods/mobnpcspawner.js b/examplemods/mobnpcspawner.js index 7b274e8..30c6a55 100644 --- a/examplemods/mobnpcspawner.js +++ b/examplemods/mobnpcspawner.js @@ -17,7 +17,7 @@ sheep.$setLocationAndAngles(senderPos.getX(), senderPos.getY(), senderPos.getZ(), senderPos.rotationYaw, senderPos.rotationPitch); // Disable AI (no AI behavior) - sheep.$getDataWatcher().$updateObject(15, 1); // AI flag, 15 is the byte for AI, 1 means no AI + sheep.$setNoAI(1) // Disable gravity sheep.$noGravity = 1; From c8127ad99d3875e4341f71c850adb7bcd85d4650 Mon Sep 17 00:00:00 2001 From: radmanplays <95340057+radmanplays@users.noreply.github.com> Date: Tue, 1 Oct 2024 17:34:28 +0330 Subject: [PATCH 02/20] Update mobnpcspawner.js --- examplemods/mobnpcspawner.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examplemods/mobnpcspawner.js b/examplemods/mobnpcspawner.js index 30c6a55..4d681dd 100644 --- a/examplemods/mobnpcspawner.js +++ b/examplemods/mobnpcspawner.js @@ -23,7 +23,7 @@ sheep.$noGravity = 1; // Make sheep invincible - sheep.$setEntityInvulnerable(1); + sheep.$invulnerable = 1 // Add the sheep to the world world.spawnEntityInWorld(sheep); From e6d0aae86e3a96b6fe2690a45d0ff2e5abcc0a1a Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Wed, 2 Oct 2024 14:39:56 +0800 Subject: [PATCH 03/20] patches beginnings, corrective basedatas --- examplemods/grapplehook.js | 81 ++++++++++++++++++----------------- patches.js | 13 ++++++ postinit.js | 86 ++++++++++++++++---------------------- 3 files changed, 92 insertions(+), 88 deletions(-) create mode 100644 patches.js diff --git a/examplemods/grapplehook.js b/examplemods/grapplehook.js index 2595f04..fa842e4 100644 --- a/examplemods/grapplehook.js +++ b/examplemods/grapplehook.js @@ -1,41 +1,44 @@ -PluginAPI.require("player"); //Require the player -var GrappleHookPlugin = { - oldXYZ: [0, 0, 0], //The previous hook position. - prev: "NONE", //The previous state - scaleH: 0.25, //Used for X and Z velocity - scaleV: 0.15, //((Grapple Y) minus (Player Y)) times scaleV - lift: 0.4, //Base vertical motion - crouchToCancel: true //Whether or not crouching should disable the grappling hook. -}; -PluginAPI.addEventListener("update", () => { //Every client tick - if (!PluginAPI.player.fishEntity) { //If the fish hook does not exist. - if (GrappleHookPlugin.prev === "GROUND" && (!GrappleHookPlugin.crouchToCancel || !PluginAPI.player.isSneaking())) { //If the old state was ground - GrappleHookPlugin.prev = "NONE"; //Update the state - var mx = GrappleHookPlugin.oldXYZ[0] - PluginAPI.player.posX; //Get delta X - var my = GrappleHookPlugin.oldXYZ[1] - PluginAPI.player.posY; //Get delta Y - var mz = GrappleHookPlugin.oldXYZ[2] - PluginAPI.player.posZ; //Get delta Z - mx *= GrappleHookPlugin.scaleH; //Multiply by horizontal scale - my *= GrappleHookPlugin.scaleV; //Multiply by vertical scale - mz *= GrappleHookPlugin.scaleH; //Multiply by horizontal scale - PluginAPI.player.motionX += mx; //Add x motion - PluginAPI.player.motionY += my + GrappleHookPlugin.lift; //Add y motion, plus base lift. - PluginAPI.player.motionZ += mz; //Add z motion - } else { - GrappleHookPlugin.prev = "NONE"; +(function grapplehook() { + PluginAPI.require("player"); //Require the player + var GrappleHookPlugin = { + oldXYZ: [0, 0, 0], //The previous hook position. + prev: "NONE", //The previous state + scaleH: 0.25, //Used for X and Z velocity + scaleV: 0.15, //((Grapple Y) minus (Player Y)) times scaleV + lift: 0.4, //Base vertical motion + crouchToCancel: true //Whether or not crouching should disable the grappling hook. + }; + var player = ModAPI.player.getCorrective(); //Gets the corrective version of the player object. This removes broken proerty suffixes. You usually don't need this, but in my case, I do. + PluginAPI.addEventListener("update", () => { //Every client tick + if (!player.fishEntity) { //If the fish hook does not exist. + if (GrappleHookPlugin.prev === "GROUND" && (!GrappleHookPlugin.crouchToCancel || !player.isSneaking())) { //If the old state was ground + GrappleHookPlugin.prev = "NONE"; //Update the state + var mx = GrappleHookPlugin.oldXYZ[0] - player.posX; //Get delta X + var my = GrappleHookPlugin.oldXYZ[1] - player.posY; //Get delta Y + var mz = GrappleHookPlugin.oldXYZ[2] - player.posZ; //Get delta Z + mx *= GrappleHookPlugin.scaleH; //Multiply by horizontal scale + my *= GrappleHookPlugin.scaleV; //Multiply by vertical scale + mz *= GrappleHookPlugin.scaleH; //Multiply by horizontal scale + player.motionX += mx; //Add x motion + player.motionY += my + GrappleHookPlugin.lift; //Add y motion, plus base lift. + player.motionZ += mz; //Add z motion + } else { + GrappleHookPlugin.prev = "NONE"; + } + } else if (GrappleHookPlugin.prev === "NONE") { //If the hook exists, but the previous state was NONE, update the state. + GrappleHookPlugin.prev = "AIR"; } - } else if (GrappleHookPlugin.prev === "NONE") { //If the hook exists, but the previous state was NONE, update the state. - GrappleHookPlugin.prev = "AIR"; - } - if ( - PluginAPI.player.fishEntity !== undefined && //If the fish hook exists - GrappleHookPlugin.prev === "AIR" && //And the hook was previously in the air - PluginAPI.player.fishEntity[PluginAPI.util.getNearestProperty(ModAPI.player.fishEntity, "inGround")] //And the hook is in the ground (the inGround property is botched with random suffixes sometimes) - ) { - GrappleHookPlugin.oldXYZ = [ //Set old grapple hook position - PluginAPI.player.fishEntity.posX, - PluginAPI.player.fishEntity.posY, - PluginAPI.player.fishEntity.posZ, - ]; - GrappleHookPlugin.prev = "GROUND";//Update state - } + if ( + player.fishEntity !== undefined && //If the fish hook exists + GrappleHookPlugin.prev === "AIR" && //And the hook was previously in the air + player.fishEntity.inGround //And the hook is in the ground + ) { + GrappleHookPlugin.oldXYZ = [ //Set old grapple hook position + player.fishEntity.posX, + player.fishEntity.posY, + player.fishEntity.posZ, + ]; + GrappleHookPlugin.prev = "GROUND";//Update state + } + }); }); \ No newline at end of file diff --git a/patches.js b/patches.js new file mode 100644 index 0000000..46e23c2 --- /dev/null +++ b/patches.js @@ -0,0 +1,13 @@ +class PatchesRegistry { + static patchedEventNames = [] + static patchedEventNames = [] + static getEventInjectorCode() { + return globalThis.modapi_specialevents = "[" + PatchesRegistry.patchedEventNames.flatMap(x=>`\`${x}\``).join(",") + "]" + } +} +function addPatch(params) { + +} +function addSpecialEvent(eventName) { + +} \ No newline at end of file diff --git a/postinit.js b/postinit.js index f83d8e6..eb4f35e 100644 --- a/postinit.js +++ b/postinit.js @@ -114,26 +114,40 @@ globalThis.modapi_postinit = "(" + (() => { }); return name; } - ModAPI.util.wrap = function (outputValue, target) { + ModAPI.util.wrap = function (outputValue, target, corrective) { + const CorrectiveArray = patchProxyConfToCorrective(ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf); + const CorrectiveRecursive = patchProxyConfToCorrective(ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf); if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { + if (corrective) { + return new Proxy(outputValue.data, CorrectiveArray); + } return new Proxy(outputValue.data, ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf); } if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { + if (corrective) { + return new Proxy(outputValue.data, CorrectiveRecursive); + } return new Proxy(outputValue, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf); } if (outputValue && typeof outputValue === "function" && target) { return function (...args) { var xOut = outputValue.apply(target, args); if (xOut && typeof xOut === "object" && Array.isArray(xOut.data) && typeof outputValue.type === "function") { + if (corrective) { + return new Proxy(outputValue.data, CorrectiveArray); + } return new Proxy(xOut.data, ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf); } if (xOut && typeof xOut === "object" && !Array.isArray(xOut)) { + if (corrective) { + return new Proxy(outputValue.data, CorrectiveRecursive); + } return new Proxy(xOut, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf); } return xOut; } } - return null; + return outputValue; } ModAPI.array.object = function (jclass, size) { if (Array.isArray(size)) { @@ -295,61 +309,18 @@ globalThis.modapi_postinit = "(" + (() => { return key ? ModAPI.hooks._classMap[key] : null; } var reloadDeprecationWarnings = 0; - const TeaVM_to_BaseData_ProxyConf = { - ownKeys(target) { - return Reflect.ownKeys(target).flatMap(x => x.substring(1)); - }, - getOwnPropertyDescriptor(target, prop) { - return Object.getOwnPropertyDescriptor(target, "$" + prop); - }, - has(target, prop) { - return ("$" + prop) in target; - }, - get(target, prop, receiver) { - if (prop === "getRef") { - return function () { - return target; - } - } - if (prop === "reload") { - return function () { - if (reloadDeprecationWarnings < 10) { - console.warn("ModAPI/PluginAPI reload() is obsolete, please stop using it in code.") - reloadDeprecationWarnings++; - } - } - } - - var outProp = "$" + prop; - var outputValue = Reflect.get(target, outProp, receiver); - if (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") { - return outputValue.data; - } - if (outputValue && typeof outputValue === "function") { - return function (...args) { - return outputValue.apply(target, args); - } - } - return outputValue; - }, - set(object, prop, value) { - var outProp = "$" + prop; - object[outProp] = value; - return true; - }, - }; const TeaVMArray_To_Recursive_BaseData_ProxyConf = { get(target, prop, receiver) { var outputValue = Reflect.get(target, prop, receiver); if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { - return new Proxy(outputValue, TeaVM_to_Recursive_BaseData_ProxyConf); + return ModAPI.util.wrap(outputValue, target, this._corrective); } if (prop === "getRef") { return function () { return target; } } - return outputValue; + return ModAPI.util.wrap(outputValue, target, this._corrective); }, set(object, prop, value) { object[prop] = value; @@ -367,6 +338,16 @@ globalThis.modapi_postinit = "(" + (() => { return ("$" + prop) in target; }, get(target, prop, receiver) { + if (prop === "getCorrective") { + return function () { + return new Proxy(target, patchProxyConfToCorrective(TeaVM_to_Recursive_BaseData_ProxyConf)); + } + } + if (prop === "isCorrective") { + return function () { + return !!this._corrective; + } + } if (prop === "getRef") { return function () { return target; @@ -382,8 +363,11 @@ globalThis.modapi_postinit = "(" + (() => { } var outProp = "$" + prop; + if (this._corrective) { + outProp = ModAPI.util.getNearestProperty(target, outProp); + } var outputValue = Reflect.get(target, outProp, receiver); - var wrapped = ModAPI.util.wrap(outputValue, target); + var wrapped = ModAPI.util.wrap(outputValue, target, this._corrective); if (wrapped) { return wrapped; } @@ -395,6 +379,11 @@ globalThis.modapi_postinit = "(" + (() => { return true; }, }; + function patchProxyConfToCorrective(conf) { + var pconf = Object.assign({}, conf); + pconf._corrective = true; + return pconf; + } const StaticProps_ProxyConf = { get(target, prop, receiver) { var outProp = prop; @@ -413,7 +402,6 @@ globalThis.modapi_postinit = "(" + (() => { return true; }, }; - ModAPI.util.TeaVM_to_BaseData_ProxyConf = TeaVM_to_BaseData_ProxyConf; ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf = TeaVMArray_To_Recursive_BaseData_ProxyConf; ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf = TeaVM_to_Recursive_BaseData_ProxyConf; ModAPI.util.StaticProps_ProxyConf = StaticProps_ProxyConf; From 9fcac52d2866bc5218923db05f813b5296a7bfb0 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Wed, 2 Oct 2024 14:49:17 +0800 Subject: [PATCH 04/20] Docs for corrective, and patches stuff --- docs/apidoc/index.md | 24 +++++++++++++++++++++++- docs/quirks.md | 2 +- patches.js | 12 +++++++++--- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/docs/apidoc/index.md b/docs/apidoc/index.md index 5336311..77d5e78 100644 --- a/docs/apidoc/index.md +++ b/docs/apidoc/index.md @@ -141,4 +141,26 @@ For example, take the method `setRenderViewEntity()` on `ModAPI.mcinstance`. Ins ```javascript var entityIndex = 1; //Index of the entity to look for. 0 means first, which is usually the player, so 1 is usually a natural entity. ModAPI.mc.setRenderViewEntity(ModAPI.world.loadedEntityList.get(entityIndex).getRef()); -``` \ No newline at end of file +``` + +## Corrective Proxies +By default, accessing a global like `ModAPI.player` will return a proxy to the original player that removes $ prefixes, as well as making instance methods callable. TeaVM has a quirk where it adds numerical suffixes to some properties. For example `ModAPI.player.inGround0` instead of `ModAPI.player.inGround`. As this is a large issue due to these suffixes changing for every eaglercraft update, you can now bypass this by obtaining a corrective version of `ModAPI.player`, using `ModAPI.player.getCorrective()`. + +For example: +```javascript +ModAPI.player.inGround //returns undefined +ModAPI.player.inGround0 //returns 1 or 0, the correct value + +ModAPI.player.isCorrective() //returns false + +var correctedPlayer = ModAPI.player.getCorrective(); + +correctedPlayer.inGround //returns 1 or 0, the correct value +correctedPlayer.inGround0 //returns 1 or 0, the correct value + +correctedPlayer.isCorrective() //returns true +``` + +You can check if an object is corrective using `.isCorrective()`; + +Accessing children of a corrective object will also make them corrective. `correctedPlayer.fishEntity.isCorrective(); //true` \ No newline at end of file diff --git a/docs/quirks.md b/docs/quirks.md index 92e3643..c719645 100644 --- a/docs/quirks.md +++ b/docs/quirks.md @@ -2,7 +2,7 @@ When TeaVM compiles code, it sometimes does strange things. #### Property Suffixes -TeaVM will add suffixes to some variables, seemingly randomly. An example is the property `inGround` of any entity. When accessing this on the `ModAPI.player.fishEntity` object, TeaVM has renamed it to `inGround2`. Can be mitigated with `ModAPI.util.getNearestProperty`. +TeaVM will add suffixes to some variables, seemingly randomly. An example is the property `inGround` of any entity. When accessing this on the `ModAPI.player.fishEntity` object, TeaVM has renamed it to `inGround2`. Can be mitigated with `ModAPI.util.getNearestProperty`, or, even better, using a corrective version of ModAPI.player. #### Collapsing Methods When I was trying to hook into the server-side processing of chat messages, I found that chat packets were handled by the method `processChatMessage` in `NetHandlerPlayServer`. However, in the compiled JavaScript, this method no longer exists. This is because it is only used once, in the `processPacket` method of `C01PacketChatMessage`. TeaVM automatically saw this, and collapsed one method into the other. diff --git a/patches.js b/patches.js index 46e23c2..7d59a59 100644 --- a/patches.js +++ b/patches.js @@ -1,11 +1,17 @@ class PatchesRegistry { - static patchedEventNames = [] + static patchFns = [] static patchedEventNames = [] static getEventInjectorCode() { - return globalThis.modapi_specialevents = "[" + PatchesRegistry.patchedEventNames.flatMap(x=>`\`${x}\``).join(",") + "]" + return "globalThis.modapi_specialevents = [" + PatchesRegistry.patchedEventNames.flatMap(x=>`\`${x}\``).join(",") + "]" + } + static addPatch(fn) { + patchFns.push(fn); + } + static addSpecialEvent(x) { + PatchesRegistry.patchedEventNames.push(x); } } -function addPatch(params) { +function addPatch() { } function addSpecialEvent(eventName) { From 0321c07978ca0eb2a2dcdfd8c10fbf19e8bbd1c1 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Wed, 2 Oct 2024 14:51:44 +0800 Subject: [PATCH 05/20] push --- patches.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/patches.js b/patches.js index 7d59a59..bff6ed7 100644 --- a/patches.js +++ b/patches.js @@ -5,15 +5,14 @@ class PatchesRegistry { return "globalThis.modapi_specialevents = [" + PatchesRegistry.patchedEventNames.flatMap(x=>`\`${x}\``).join(",") + "]" } static addPatch(fn) { - patchFns.push(fn); + PatchesRegistry.patchFns.push(fn); } - static addSpecialEvent(x) { + static regSpecialEvent(x) { PatchesRegistry.patchedEventNames.push(x); } } -function addPatch() { - -} -function addSpecialEvent(eventName) { - -} \ No newline at end of file +// PatchesRegistry.regSpecialEvent("test"); +// PatchesRegistry.addPatch(function (input) { +// var output = input; +// return output; +// }) \ No newline at end of file From 134967456cb671852c1a1eae482ed4e47ae10163 Mon Sep 17 00:00:00 2001 From: ZXMushroom63 Date: Wed, 2 Oct 2024 14:58:37 +0800 Subject: [PATCH 06/20] Finish patches registry --- index.html | 1 + injector.js | 6 ++++++ patches.js | 7 +++++++ postinit.js | 6 ++++++ 4 files changed, 20 insertions(+) diff --git a/index.html b/index.html index 5411a26..27d2158 100644 --- a/index.html +++ b/index.html @@ -175,6 +175,7 @@
`; var freezeCallstack = `if(ModAPI.hooks.freezeCallstack){return false};`; + diff --git a/injector.js b/injector.js index 3059bb3..2928342 100644 --- a/injector.js +++ b/injector.js @@ -276,6 +276,7 @@ var main;(function(){` patchedFile = patchedFile.replace( ` id="game_frame">`, ` id="game_frame"> + \