Fix more stack implosion occurences

This commit is contained in:
ZXMushroom63 2024-09-13 18:50:13 +08:00
parent 03f62846cc
commit 195a50315c
6 changed files with 53 additions and 14 deletions

View File

@ -4,7 +4,7 @@ The EaglerForge ModAPI is housed in a global JavaScript object stored on `global
The global object has the following properties:
- `ModAPI.player: EntityPlayerSP`
- Only accessible after `ModAPI.require("player")` is called, this is the local player entity. It is regenerated every time the `update` event is called.
- `ModAPI.world: WorldClient`
- `ModAPI.world: WorldClient`
- Only accessible after `ModAPI.require("world")` is called, this is the client-side world. It is regenerated every time the `update` event is called.
- `ModAPI.network: NetHandlerPlayClient`
- Only accessible after `ModAPI.require("network")` is called, this is the client's networking handler. It is regenerated every time the `update` event is called.

View File

@ -24,11 +24,16 @@ Methods:
- Alias: `ModAPI.util.ustr()`
- Alias: `ModAPI.util.unstring()`
- Alias: `ModAPI.util.jclStrToJsStr()`
- `ModAPI.util.getMethodFromPackage(classId: String, methodName: String)`
- `ModAPI.util.getMethodFromPackage(classId: String, methodName: String) : String`
- Takes a class id (eg: `net.minecraft.client.Minecraft`) and a method name (eg: `middleClickMouse`) and returns its key in `ModAPI.hooks.methods`.
- `ModAPI.util.stringToUint16Array(string: String) : Uint16Array`
- Encodes a string into a uint16array.
- `ModAPI.util.setStringContent(jclString: java.lang.String, contents: String) : void`
- Writes a new javascript string into the contents of a java string.
- `ModAPI.util.getMethodFromPackage(classId: String, methodName: String)`
- `ModAPI.util.getMethodFromPackage(classId: String, methodName: String) : String`
- Takes a class id (eg: `net.minecraft.client.Minecraft`) and a method name (eg: `middleClickMouse`) and returns its key in `ModAPI.hooks.methods`.
- `ModAPI.util.hashCode(string: String) : String`
- Returns the hash of a string.
- `ModAPI.util.isCritical() : boolean`
- Checks wether the thread is in a critical state.
- When patching methods, it is good practice to allow the method to resume as usual if this is `true`, to avoid stack implosions. (yes, those are real)

View File

@ -12,3 +12,6 @@ Incorrectly patching methods with ModAPI.hooks (such as returning `false` instea
Update 13/09/2024:
Any form of incorrect data type, even passing the wrong values, can cause this sort of hang. I encountered this when trying to set a block in the world to any form of wood or leaf block, without adding iproperties to the tree type.
Update 13/09/2024:
Calling methods while the TeaVM thread is in a critical transition state (see `ModAPI.util.isCritical()`) will shift the call stack, cause methods to access the incorrect values at runtime, and also cause the stack to implode. Gotta love TeaVM.

View File

@ -8,8 +8,16 @@ ModAPI.dedicatedServer.appendCode(function () {
var rayTraceMethod = worldMethodMap[Object.keys(worldMethodMap).filter(key => {
return key.startsWith("rayTraceBlocks") && worldMethodMap[key].method.length === 4;
})].method;
var blockPosConstructor = ModAPI.reflect.getClassById("net.minecraft.util.BlockPos").constructors.find((x) => { return x.length === 3 });
var blockTypesList = Object.keys(ModAPI.blocks);
var blockTypesList = [];
ModAPI.addEventListener("serverstart", () => {
blockTypesList = Object.keys(ModAPI.blocks).filter(key => {
var blockType = ModAPI.blocks[key];
if (!blockType) {
return false;
}
return blockType.fullBlock && !blockType.needsRandomTick;
});
});
function getPlayerEntitiesAndTheirWorld() {
var out = [];
ModAPI.server.worldServers.forEach(x => {
@ -31,11 +39,12 @@ ModAPI.dedicatedServer.appendCode(function () {
ModAPI.addEventListener("processcommand", (event) => {
if (event.command.toLowerCase().startsWith("/blocklook")) {
active = !active;
console.log(blockTypesList);
var playerEntities = getPlayerEntitiesAndTheirWorld();
playerEntities.forEach(pair => {
pair.player.addChatMessage(
ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText").constructors[0](ModAPI.util.str(
"[BlockLook] Toggled to " + (active ? "on" : off)
"[BlockLook] Toggled to " + (active ? "on" : "off")
))
)
});
@ -45,7 +54,7 @@ ModAPI.dedicatedServer.appendCode(function () {
var t = 0;
ModAPI.addEventListener("tick", () => {
t++;
if (t > 20) {
if (t > 5) {
t = 0;
} else {
return;
@ -53,6 +62,9 @@ ModAPI.dedicatedServer.appendCode(function () {
if (!active) {
return;
}
if (blockTypesList.length < 1) {
return;
}
var playerEntities = getPlayerEntitiesAndTheirWorld();
playerEntities.forEach(pair => {
var start = pair.player.getPositionEyes(1).getRef();
@ -63,21 +75,22 @@ ModAPI.dedicatedServer.appendCode(function () {
lookVector.addVector(start.$xCoord, start.$yCoord, start.$zCoord);
var hitResult = rayTraceMethod(pair.world.getRef(), start, lookVector.getRef(), 0);
if (hitResult) {
console.log(hitResult);
if (ModAPI.util.unstr(hitResult.$typeOfHit.$name5) !== "BLOCK") {
return console.log("Non block collision detected.")
}
var blockPos = hitResult.$blockPos;
if (!pair.world.isBlockLoaded(blockPos)) {
console.log("[BlockLook] Block is not loaded!");
return console.log("[BlockLook] Block is not loaded!");
}
var blockType = blockTypesList[Math.floor(Math.random() * blockTypesList.length)];
blockType = ModAPI.blocks[blockType];
if (!blockType.fullBlock) {
if (!blockType.fullBlock || blockType.needsRandomTick) {
return;
}
console.log("[BlockLook] " + ModAPI.util.unstr(blockType.unlocalizedName.getRef()));
var block = blockType.getDefaultState();
pair.world.setBlockState(blockPos, block.getRef(), 2);
pair.world.notifyNeighborsRespectDebug(blockPos, block.getRef());
}
});
});
})
});

View File

@ -509,6 +509,12 @@ globalThis.modapi_postinit = `(() => {
return Math.floor(Math.abs(hash)) + "";
};
//Check whether the thread is in a critical transition state (resuming or suspending)
//Calling functions in a critical state will cause stack implosions.
ModAPI.util.isCritical = function isCritical() {
return ModAPI.hooks._teavm.$rt_suspending() || ModAPI.hooks._teavm.$rt_resuming();
}
ModAPI.clickMouse = function () {
ModAPI.hooks.methods["nmc_Minecraft_clickMouse"](ModAPI.javaClient);
}
@ -573,6 +579,9 @@ globalThis.modapi_postinit = `(() => {
const serverTickMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "tick");
const serverTickMethod = ModAPI.hooks.methods[serverTickMethodName];
ModAPI.hooks.methods[serverTickMethodName] = function ($this) {
if (ModAPI.util.isCritical()) {
return serverTickMethod.apply(this, [$this]);
}
var data = { preventDefault: false }
ModAPI.events.callEvent("tick", data);
if (data.preventDefault) {

View File

@ -509,6 +509,12 @@
return Math.floor(Math.abs(hash)) + "";
};
//Check whether the thread is in a critical transition state (resuming or suspending)
//Calling functions in a critical state will cause stack implosions.
ModAPI.util.isCritical = function isCritical() {
return ModAPI.hooks._teavm.$rt_suspending() || ModAPI.hooks._teavm.$rt_resuming();
}
ModAPI.clickMouse = function () {
ModAPI.hooks.methods["nmc_Minecraft_clickMouse"](ModAPI.javaClient);
}
@ -573,6 +579,9 @@
const serverTickMethodName = ModAPI.util.getMethodFromPackage("net.minecraft.server.MinecraftServer", "tick");
const serverTickMethod = ModAPI.hooks.methods[serverTickMethodName];
ModAPI.hooks.methods[serverTickMethodName] = function ($this) {
if (ModAPI.util.isCritical()) {
return serverTickMethod.apply(this, [$this]);
}
var data = { preventDefault: false }
ModAPI.events.callEvent("tick", data);
if (data.preventDefault) {