Merge pull request #25 from eaglerforge/main

v2.1
This commit is contained in:
ZXMushroom63 2024-10-18 22:00:00 +08:00 committed by GitHub
commit aa53a8bc3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
22 changed files with 296 additions and 873 deletions

View File

@ -23,4 +23,15 @@ ModAPI.addEventListener("sendchatmessage", function downloadSomething(e) {
}); });
``` ```
The way this promisify method works is by taking in a java method, and (effectively) converting it into a javascript async function.
For example, you can do:
```javascript
var asyncDownloadRemoteURI = ModAPI.promisify(ModAPI.hooks.methods.nlevi_PlatformRuntime_downloadRemoteURI);
console.log(typeof asyncDownloadRemoteURI); //Logs function
```
When it is called, like any other asyncronoush function, it returns a `Promise` object.
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

@ -1,174 +0,0 @@
(function AStarPathfinding() {
ModAPI.meta.title("A* Pathfinding Bot");
ModAPI.meta.description("Use #move <x> <y> <z> to instruct the bot to move somewhere. Use #stop to terminate the job.");
ModAPI.meta.credits("By ZXMushroom63");
ModAPI.require("player");
ModAPI.require("world");
var tessellator = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.renderer.Tessellator", "getInstance")]();
var worldRenderer = tessellator.$getWorldRenderer();
var glStateManagerSetColor = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "color")];
var glStateManagerEnableBlend = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "enableBlend")];
var glStateManagerDisableBlend = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "disableBlend")];
var glStateManagerdisableTex2d = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "disableTexture2D")];
var glStateManagerenableTex2d = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "enableTexture2D")];
var glStateManagerdisableDepth = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "disableDepth")];
var glStateManagerenableDepth = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "enableDepth")];
var glStateManagerSetBlend = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "blendFunc")];
var glStateManagerDepthMask = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.GlStateManager", "depthMask")];
var eaglercraftGPUSetLineWidth = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.opengl.EaglercraftGPU", "glLineWidth")];
var positionVertexFormat = ModAPI.reflect.getClassByName("DefaultVertexFormats").staticVariables.POSITION;
globalThis.drawLine = function drawLine(positions, color) {
glStateManagerSetBlend(770, 771);
glStateManagerEnableBlend();
eaglercraftGPUSetLineWidth(2);
glStateManagerdisableTex2d();
glStateManagerdisableDepth();
glStateManagerDepthMask(0);
var renderManager = ModAPI.mc.getRenderManager();
glStateManagerSetColor(color.r, color.b, color.g, color.a);
worldRenderer.$begin(3, positionVertexFormat);
positions.forEach(pos => {
worldRenderer.$pos(pos.x - renderManager.renderPosX, pos.y - renderManager.renderPosY, pos.z - renderManager.renderPosZ).$endVertex();
});
tessellator.$draw();
glStateManagerenableTex2d();
glStateManagerDepthMask(1);
glStateManagerenableDepth();
glStateManagerDisableBlend();
}
var blockBreakCostMultiplier = 2;
const costMap = Object.fromEntries(Object.keys(ModAPI.blocks).flatMap(x => {
ModAPI.blocks[x].readableId = x;
return [[x, (Math.floor(ModAPI.blocks[x].blockHardness * 10 * blockBreakCostMultiplier) + 1) || 99999]]; //Block hardness is in decimals, unbreakable blocks are negative one, and base movement cost is 1. -1 + 1 = 0, and 0 || 99999 is 99999
}));
var makeBlockPos = ModAPI.reflect.getClassById("net.minecraft.util.BlockPos").constructors.find(x => x.length === 3);
function shouldPause(x, y, z) {
return !ModAPI.world.isAreaLoaded0(makeBlockPos(x, y, z), 2);
}
globalThis.APNode = class APNode {
constructor(x, y, z, g, h, parent = null) {
this.x = x;
this.y = y;
this.z = z;
this.g = g;
this.h = h;
this.f = g + h;
this.parent = parent;
}
}
function heuristic(a, b) {
return Math.abs(a.x - b.x) + Math.abs(a.y - b.y) + Math.abs(a.z - b.z);
}
function getNeighbors(node) {
const neighbors = [];
const directions = [
[1, 0, 0], [-1, 0, 0],
[0, 1, 0], [0, -1, 0],
[0, 0, 1], [0, 0, -1]
];
for (const [dx, dy, dz] of directions) {
const x = node.x + dx;
const y = node.y + dy;
const z = node.z + dz;
if (ModAPI.world.isBlockLoaded(makeBlockPos(Math.round(x), Math.round(y), Math.round(z)))) {
neighbors.push(new APNode(x, y, z, 0, 0));
}
}
return neighbors;
}
function lookupCost(x, y, z) {
var block = ModAPI.world.getBlockState(makeBlockPos(Math.round(x), Math.round(y), Math.round(z))).block;
return costMap[block.readableId];
}
globalThis.aStar = function* aStar(start, goal) {
const openSet = [];
const closedSet = new Set();
openSet.push(start);
while (openSet.length > 0) {
let current = openSet.reduce((prev, curr) => (prev.f < curr.f ? prev : curr));
if (current.x === goal.x && current.y === goal.y && current.z === goal.z) {
const path = [];
while (current) {
path.push([current.x, current.y, current.z]);
current = current.parent;
}
yield* path.reverse();
return;
}
openSet.splice(openSet.indexOf(current), 1);
closedSet.add(`${current.x},${current.y},${current.z}`);
for (const neighbor of getNeighbors(current)) {
if (closedSet.has(`${neighbor.x},${neighbor.y},${neighbor.z}`)) {
continue;
}
const tentativeG = current.g + lookupCost(neighbor.x, neighbor.y, neighbor.z);
if (!openSet.some(node => node.x === neighbor.x && node.y === neighbor.y && node.z === neighbor.z)) {
neighbor.g = tentativeG;
neighbor.h = heuristic(neighbor, goal);
neighbor.f = neighbor.g + neighbor.h;
neighbor.parent = current;
openSet.push(neighbor);
} else {
const existingNode = openSet.find(node => node.x === neighbor.x && node.y === neighbor.y && node.z === neighbor.z);
if (tentativeG < existingNode.g) {
existingNode.g = tentativeG;
existingNode.f = existingNode.g + existingNode.h;
existingNode.parent = current;
}
}
}
yield [current.x, current.y, current.z];
}
return [];
}
})();
var start = new APNode(-24, 73, 1, 0, 0);
var goal = new APNode(-30, 73, 1, 0, 0);
var pathGenerator = aStar(start, goal);
var positions = [];
var rendererPositions = [];
var timer = 0;
ModAPI.addEventListener("update", ()=>{
timer++;
if (timer > 20) {
timer = 0;
} else {
return;
}
if (positions.length > 0 && shouldPause(...positions[positions.length - 1])) {
return;
}
var nextPos = pathGenerator.next();
if (nextPos.value && nextPos.value.length === 3) {
positions.push(nextPos.value);
rendererPositions.push({x: nextPos.value[0] + 0.5, y: nextPos.value[1] + 0.5, z: nextPos.value[2] + 0.5});
}
});
ModAPI.addEventListener("render", () => {
drawLine(rendererPositions, { r: 1, g: 0, b: 0, a: 0.5 })
});

View File

@ -1,80 +0,0 @@
//NOT FUNCTIONAL
ModAPI.meta.title("Advanced VClip Exploit");
ModAPI.meta.description("Use .vclip <offset> to vertically phase through blocks with custom packet handling.");
ModAPI.meta.credits("By radmanplays");
// Custom syntax error function
function syntaxError() {
ModAPI.displayToChat("[AdvancedVClip] Syntax error: Usage is .vclip <offset>");
}
ModAPI.require("player");
ModAPI.addEventListener("sendchatmessage", (ev) => {
var msg = ev.message.toLowerCase();
if (msg.startsWith(".vclip")) {
ev.preventDefault == true;
var args = msg.split(" ");
if (args.length != 2) {
syntaxError();
return;
}
var offset = parseFloat(args[1]);
if (isNaN(offset)) {
syntaxError();
return;
}
var packetsRequired = Math.ceil(Math.abs(offset / 10));
if (packetsRequired > 20) {
packetsRequired = 1; // Limit to avoid server kicking for too many packets
}
var player = ModAPI.player;
var ridingEntity = player.ridingEntity;
if (ridingEntity != null) {
// Player is riding an entity
for (var packetNumber = 0; packetNumber < (packetsRequired - 1); packetNumber++) {
// Simulate entity movement
ridingEntity.posY += offset / packetsRequired; // Move a fraction of the total offset
ModAPI.network.addToSendQueue({
"action": "RIDING_JUMP", // Simulate a riding jump action
"entityId": ridingEntity.getEntityId(),
});
}
// Final move
ridingEntity.posY += offset / packetsRequired;
ModAPI.network.addToSendQueue({
"action": "RIDING_JUMP",
"entityId": ridingEntity.getEntityId(),
});
} else {
// Player is not riding any entity
for (var packetNumber = 0; packetNumber < (packetsRequired - 1); packetNumber++) {
ModAPI.network.addToSendQueue({
"x": player.posX,
"y": player.posY,
"z": player.posZ,
"onGround": true
});
}
// Final move
ModAPI.network.addToSendQueue({
"x": player.posX,
"y": player.posY + offset,
"z": player.posZ,
"onGround": true
});
// Set the players final position
player.setPosition(player.posX, player.posY + offset, player.posZ);
}
ModAPI.displayToChat("[AdvancedVClip] VClipped " + offset + " blocks.");
}
});

View File

@ -1,98 +0,0 @@
//WIP Blocklook plugin
//Causes call stack implosions occasionally, not sure why.
//Use with caution
ModAPI.meta.title("BlockLook");
ModAPI.meta.credits("Made with ❤️ by ZXMushroom63");
ModAPI.meta.icon("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAPlJREFUOE+Fk7EVwjAMRM8TQJEmS0DBBtAwBEtQwBBkCBqGoIEhsgFNGrKDeOdEjuw4Rk1eLN33WbIdAEEmROJl51yuDFyVtFgrVVTKZwEqfAnQAjiPm+dcRQAVfkchnRCg33sCYn0ABLsd0NeTiACFfAC8DSQLoFS6AUDQFQCFDBX7GhHMAPIE3HFqNkGHOhZWAvSuAFC/jlvbkIv/q9AUADdz4Ad8g3xwHHvtBBPNwhEUMHYuAuwArJgoAU5mZm3iIAAAuO2CAwLM4GcOyKeLHIC5cBc2A2gGWA8reiOjMdqGLz2cv1c5GdzkKHmZWhccpEJr0xbn6n64M6oBwREDxAAAAABJRU5ErkJggg==");
ModAPI.meta.description("EaglerForge port of the bukkit BlockLook plugin by GeorgeNotFound. Use /blocklook in a single-player world to toggle the plugin.");
ModAPI.dedicatedServer.appendCode(function () {
var worldMethodMap = ModAPI.reflect.getClassById("net.minecraft.world.World").methods;
var rayTraceMethod = worldMethodMap[Object.keys(worldMethodMap).filter(key => {
return key.startsWith("rayTraceBlocks") && worldMethodMap[key].method.length === 4;
})].method;
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 => {
var list = x.playerEntities;
var size = list.size();
for (let i = 0; i < size; i++) {
const playerEntity = list.get(i);
if (playerEntity) {
out.push({
world: x,
player: playerEntity
});
}
}
});
return out;
};
var active = false;
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")
))
)
});
event.preventDefault = true;
}
});
var t = 0;
ModAPI.addEventListener("tick", () => {
t++;
if (t > 5) {
t = 0;
} else {
return;
}
if (!active) {
return;
}
if (blockTypesList.length < 1) {
return;
}
var playerEntities = getPlayerEntitiesAndTheirWorld();
playerEntities.forEach(pair => {
var start = pair.player.getPositionEyes(1).getRef();
var lookVector = pair.player.getLookVec();
lookVector.xCoord *= 50;
lookVector.yCoord *= 50;
lookVector.zCoord *= 50;
lookVector.addVector(start.$xCoord, start.$yCoord, start.$zCoord);
var hitResult = rayTraceMethod(pair.world.getRef(), start, lookVector.getRef(), 0);
if (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)) {
return console.log("[BlockLook] Block is not loaded!");
}
var blockType = blockTypesList[Math.floor(Math.random() * blockTypesList.length)];
blockType = ModAPI.blocks[blockType];
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);
}
});
})
});

View File

@ -41,4 +41,4 @@
GrappleHookPlugin.prev = "GROUND";//Update state GrappleHookPlugin.prev = "GROUND";//Update state
} }
}); });
}); })();

View File

@ -1,20 +1,42 @@
//Metadata for the mod
ModAPI.meta.title("SimpleHats"); ModAPI.meta.title("SimpleHats");
ModAPI.meta.credits("Made with ❤️ by ZXMushroom63"); ModAPI.meta.credits("Made with ❤️ by ZXMushroom63");
ModAPI.meta.description("Use /hat to wear whatever you are holding!"); ModAPI.meta.description("Use /hat to wear whatever you are holding!");
// Run the code on the server
ModAPI.dedicatedServer.appendCode(function () { ModAPI.dedicatedServer.appendCode(function () {
// Find the constructor for the held item change packet that has only one argument.
// This will be used to notify the client that their hotbar has been updated.
var makePacketItemChange = ModAPI.reflect.getClassByName("S09PacketHeldItemChange").constructors.find(x => x.length === 1); var makePacketItemChange = ModAPI.reflect.getClassByName("S09PacketHeldItemChange").constructors.find(x => x.length === 1);
// Find the method for sending packets.
var sendPacket = ModAPI.reflect.getClassByName("NetHandlerPlayServer").methods.sendPacket.method; var sendPacket = ModAPI.reflect.getClassByName("NetHandlerPlayServer").methods.sendPacket.method;
// When the server is processing a command
ModAPI.addEventListener("processcommand", (event) => { ModAPI.addEventListener("processcommand", (event) => {
// If the command starts with /hat
if (event.command.toLowerCase().startsWith("/hat")) { if (event.command.toLowerCase().startsWith("/hat")) {
// Cancel if the sender isn't a player
if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return }; if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return };
// Otherwise, get the current held item
var heldItem = event.sender.inventory.getCurrentItem(); var heldItem = event.sender.inventory.getCurrentItem();
// Get the contents of the helmet slot
var armorItem = event.sender.inventory.armorInventory[3]; var armorItem = event.sender.inventory.armorInventory[3];
// Get the inventory index of the current held item
var hotbarIdx = event.sender.inventory.currentItem; var hotbarIdx = event.sender.inventory.currentItem;
// Set the helmet slot to heldItem.getRef() (raw java object) if heldItem exists, otherwise set it to null
event.sender.inventory.armorInventory[3] = heldItem ? heldItem.getRef() : null; event.sender.inventory.armorInventory[3] = heldItem ? heldItem.getRef() : null;
// Set the hotbar slot to the previous value of the helmet slot
event.sender.inventory.mainInventory[hotbarIdx] = armorItem ? armorItem.getRef() : null; event.sender.inventory.mainInventory[hotbarIdx] = armorItem ? armorItem.getRef() : null;
// Use the sendPacket method to send a item change packet to the client.
sendPacket(event.sender.playerNetServerHandler.getRef(), makePacketItemChange(hotbarIdx)); sendPacket(event.sender.playerNetServerHandler.getRef(), makePacketItemChange(hotbarIdx));
event.preventDefault = true; event.preventDefault = true;
} }
}); });

View File

@ -1,188 +0,0 @@
ModAPI.meta.title("LibCustomRender");
ModAPI.meta.credits("By ZXMushroom63");
ModAPI.meta.icon("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAQdJREFUOE9jZGBg+M9AAWAEGbBl2QmyjPCJsmAgaABbdybc8F+l01EswmsATONXLi4GYSkpBgZ+foY1O3cyuHWuhhuC1QBkjf///QMrFtHWZmD4+BHDEBQDUGzU1ITb8ubqVZyGoBjwsCONQYqXl0FYU5MBpAlsKxRgM+STUwoDhgG66upgZ4IAuiEooRcXx/DpCRuqAU97shg0jYzgfsVpSFwcg5mZGcOedRewGDBhAgPDokUohsBthmoE8U+dOoXdBfHHjoElUQxB03i9oABspnTJNFQXgARB3oAbwsAAdirMRmSNMFdhTQcwQ/BpxGsAzCUwRSCn4gJE5QV8uQxuAFlZEaoJAKrYrAHl38o6AAAAAElFTkSuQmCC");
ModAPI.meta.description("Library to make retexturing LCI items easier. Requires AsyncSink.");
(async function LibRender() {
var BreakingFour = ModAPI.reflect.getClassByName("BreakingFour").constructors[0];
var BakedQuad = ModAPI.reflect.getClassByName("BakedQuad").constructors[0];
var EnumFacing = ModAPI.reflect.getClassByName("EnumFacing");
function createBreakingFour(sprite$) {
var sprite = ModAPI.util.wrap(sprite$);
var vertexData = ModAPI.array.int(28); // 7 integers per vertex, 4 vertices
var vertexDataInternal = vertexData.data;
var vertexDataWithNormals = ModAPI.array.int(32); // 8 integers per vertex, 4 vertices
var normalDataInternal = vertexDataWithNormals.data;
var vertices = [
[0, 0, 0], [1, 0, 0], [1, 1, 0], [0, 1, 0]
];
var uvs = [
[0, 0], [1, 0], [1, 1], [0, 1]
];
for (let i = 0; i < 4; i++) {
let j = i * 7;
vertexDataInternal[j] = ModAPI.hooks.methods.jl_Float_floatToIntBits(vertices[i][0]);
vertexDataInternal[j + 1] = ModAPI.hooks.methods.jl_Float_floatToIntBits(vertices[i][1]);
vertexDataInternal[j + 2] = ModAPI.hooks.methods.jl_Float_floatToIntBits(vertices[i][2]);
vertexDataInternal[j + 3] = rgbToInt(255, 0, 0); // Color (red)
vertexDataInternal[j + 4] = ModAPI.hooks.methods.jl_Float_floatToIntBits(sprite.getInterpolatedU(uvs[i][0] * 16));
vertexDataInternal[j + 5] = ModAPI.hooks.methods.jl_Float_floatToIntBits(sprite.getInterpolatedV(uvs[i][1] * 16));
vertexDataInternal[j + 6] = 0; // Normal
let k = i * 8;
normalDataInternal[k] = vertexDataInternal[j];
normalDataInternal[k + 1] = vertexDataInternal[j + 1];
normalDataInternal[k + 2] = vertexDataInternal[j + 2];
normalDataInternal[k + 3] = vertexDataInternal[j + 3];
normalDataInternal[k + 4] = vertexDataInternal[j + 4];
normalDataInternal[k + 5] = vertexDataInternal[j + 5];
normalDataInternal[k + 6] = vertexDataInternal[j + 6];
normalDataInternal[k + 7] = 0;
}
var baseQuad = BakedQuad(vertexData, vertexDataWithNormals, -1, EnumFacing.staticVariables.NORTH);
return BreakingFour(baseQuad, sprite$);
}
function waitUntilPropertyExists(obj, prop) {
return new Promise((res, rej) => {
var timer = setInterval(() => {
if (obj[prop]) {
clearInterval(timer);
res();
}
}, 50);
});
}
function rgbToInt(red, green, blue) {
return (red << 16) | (green << 8) | blue;
}
function rgbaToInt(red, green, blue, alpha) {
return (alpha << 24) | (red << 16) | (green << 8) | blue;
}
function getLore(item) {
if (item.$stackTagCompound && item.$stackTagCompound.$hasKey(ModAPI.util.str("display"), 10)) {
var displayTag = item.$stackTagCompound.$getCompoundTag(ModAPI.util.str("display"));
if (displayTag.$hasKey(ModAPI.util.str("Lore"), 9)) {
var loreTag = displayTag.$getTag(ModAPI.util.str("Lore"));
if (loreTag.$tagCount() > 0) {
return ModAPI.util.ustr(loreTag.$getStringTagAt(0));
}
}
}
}
function recursiveAssign(target, patch) {
var keys = Object.keys(patch);
keys.forEach(k => {
if (typeof patch[k] === "object" && patch[k]) {
recursiveAssign(target[k], patch[k]);
} else if (typeof patch[k] === "number") {
target[k] = patch[k];
}
});
}
function cloneBaseModel(baseModel, newTexture, texName) {
var sprite = eaglerTextureAtlasSprite(imageDataToLaxImgData(newTexture), ModAPI.util.str(texName));
var newBaseModelBuilder = ModAPI.reflect.getClassByName("SimpleBakedModel$Builder").constructors[0](0, 0, ModAPI.reflect.getClassByName("ItemCameraTransforms").constructors.find(x => x.length === 0)());
newBaseModelBuilder.$builderTexture = sprite;
ModAPI.hooks.methods.nmcrm_SimpleBakedModel$Builder_addGeneralQuad(newBaseModelBuilder, createBreakingFour(sprite));
var newBaseModel = ModAPI.hooks.methods.nmcrm_SimpleBakedModel$Builder_makeBakedModel(newBaseModelBuilder);
//newBaseModel.$generalQuads = baseModel.$generalQuads.$clone();
//newBaseModel.$faceQuads = baseModel.$faceQuads.$clone();
//var cameraTransformsId = ModAPI.util.getNearestProperty(newBaseModel, "$cameraTransforms");
//recursiveAssign(newBaseModel[cameraTransformsId], baseModel[cameraTransformsId]);
return newBaseModel;
}
ModAPI.events.newEvent("lib:libcustomrender:loaded");
await waitUntilPropertyExists(ModAPI.minecraft, "renderItem");
var ItemRenderer = ModAPI.minecraft.renderItem;
var ItemModelMesher = ItemRenderer.itemModelMesher;
var laxImgDataClass = ModAPI.reflect.getClassByName("ImageData").class;
var makeLax1dudeImageData = ModAPI.reflect.getClassByName("ImageData").constructors.find(x => x.length === 4);
var eaglerTextureAtlasSprite = (imageData, name) => {
var atlas = ModAPI.reflect.getClassByName("EaglerTextureAtlasSprite").constructors[0](ModAPI.util.str(name));
var alias = ModAPI.util.wrap(atlas);
alias.loadSprite(ModAPI.util.makeArray(laxImgDataClass, [imageData]), null);
alias.initSprite(1, 1, 0, 0, 0);
return atlas;
};
/**
* @type {ImageData}
*/
function imageDataToLaxImgData(imageData) {
const { data, width, height } = imageData;
const intArray = [];
for (let i = 0; i < data.length; i += 4) {
const red = data[i];
const green = data[i + 1];
const blue = data[i + 2];
const alpha = data[i + 3];
intArray.push(rgbaToInt(red, green, blue, alpha));
}
return makeLax1dudeImageData(width, height, ModAPI.array.int(intArray), 1);
}
const LibCustomRender = {};
LibCustomRender.map = {};
LibCustomRender.addRetextureRule = (loreString, textureBuffer, baseItem) => {
baseItem ||= "paper";
var actualLoreStr = loreString;
loreString = loreString.replaceAll(":", "_").toLowerCase().replace(/[^a-z_]/g, '');
if (!(textureBuffer instanceof ImageData)) {
return console.error("Texture for retexture rule is not an ImageData.");
}
if (!(typeof loreString === "string")) {
return console.error("loreString for retexture rule is not a string.");
}
var baseModel = ItemModelMesher.simpleShapesCache.get(ModAPI.hooks.methods.jl_Integer_valueOf(ItemModelMesher.getIndex(ModAPI.items[baseItem].getRef(), 0)));
LibCustomRender.map[loreString] = {
lore: actualLoreStr,
identifier: loreString,
model: cloneBaseModel(baseModel.getRef(), textureBuffer, loreString)
}
return LibCustomRender.map[loreString].model;
}
// override
// public IBakedModel getItemModel(ItemStack stack) {
// Item item = stack.getItem();
// In ItemModelMesher.java
var methods = Object.keys(ModAPI.hooks.methods);
var prefix = ModAPI.util.getMethodFromPackage("net.minecraft.client.renderer.ItemModelMesher", "getItemModel");
var methodName = methods.find(x => x.startsWith(prefix) && ModAPI.hooks.methods[x].length === 2);
var original = ModAPI.hooks.methods[methodName];
ModAPI.hooks.methods[methodName] = function (...args) {
var item = args[1];
var lore = item ? getLore(item) : "";
if (!item) {
return original.apply(this, args);
}
var overrides = Object.values(LibCustomRender.map);
for (let i = 0; i < overrides.length; i++) {
const override = overrides[i];
if (lore === override.lore) {
return override.model;
}
}
return original.apply(this, args);
}
ModAPI.events.callEvent("lib:libcustomrender:loaded", {});
globalThis.LibCustomRender = LibCustomRender;
})();
//LibCustomRender.addRetextureRule("mymod:test_item_1", new ImageData(1, 1));
// const imageData = new ImageData(16, 16);
// for (let i = 0; i < imageData.data.length; i += 4) {
// imageData.data[i] = Math.floor(Math.random() * 256);
// imageData.data[i + 1] = Math.floor(Math.random() * 256);
// imageData.data[i + 2] = Math.floor(Math.random() * 256);
// imageData.data[i + 3] = 255;
// }
// LibCustomRender.addRetextureRule("mymod:test_item_1", imageData);

View File

@ -1,48 +0,0 @@
(() => {
PluginAPI.dedicatedServer.appendCode(function () {
PluginAPI.addEventListener("processcommand", (event) => {
// Check if the sender is a player
if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return; }
// Check if the command is "/spawnsheep"
if (event.command.toLowerCase().startsWith("/spawnsheep")) {
const world = event.sender.getServerForPlayer();
const senderPos = event.sender.getPosition();
// Create a sheep entity
const EntitySheepClass = ModAPI.reflect.getClassById("net.minecraft.entity.passive.EntitySheep");
const sheep = EntitySheepClass.constructors[0](world.getRef());
// Set sheep's position to player's position
sheep.$setLocationAndAngles(senderPos.getX(), senderPos.getY(), senderPos.getZ(), senderPos.rotationYaw, senderPos.rotationPitch);
// Disable AI (no AI behavior)
//sheep.$setNoAI(1)
// Disable gravity
//sheep.$noGravity = 1;
// Make sheep invincible
//sheep.$invulnerable = 1
if (globalThis.AsyncSink) { //If we can, start the AsyncSink debugger to see filesystem requests
AsyncSink.startDebuggingFS();
}
// Add the sheep to the world
ModAPI.promisify(ModAPI.hooks.methods.nmw_World_spawnEntityInWorld)(world.getRef(), sheep).then(result => {
// Notify the player that the sheep has been spawned
const ChatComponentTextClass = ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText");
event.sender.addChatMessage(ChatComponentTextClass.constructors[0](ModAPI.util.str("A special sheep has been spawned!")));
if (globalThis.AsyncSink) { //Stop debugging when we are done, otherwise the console will get filled up.
AsyncSink.stopDebuggingFS();
}
});
// Prevent the command from executing further
event.preventDefault = true;
}
});
});
})();

View File

@ -1,3 +1,5 @@
// Use ModAPI.util.getMethodFromPackage to find the internal name of the block destroy effect method
// and we replace it with our own function, that does nothing.
ModAPI.hooks.methods[ ModAPI.hooks.methods[
ModAPI.util.getMethodFromPackage( ModAPI.util.getMethodFromPackage(
"net.minecraft.client.particles.EffectRenderer", "net.minecraft.client.particles.EffectRenderer",

View File

@ -1,47 +0,0 @@
(() => {
PluginAPI.dedicatedServer.appendCode(function () {
PluginAPI.addEventListener("processcommand", (event) => {
if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return; }
if (event.command.toLowerCase().startsWith("/spawnnpc2")) {
AsyncSink.startDebuggingFS();
const world = event.sender.getServerForPlayer();
const senderPos = event.sender.getPosition();
// Create a fake player GameProfile
const GameProfileClass = ModAPI.reflect.getClassById("net.lax1dude.eaglercraft.v1_8.mojang.authlib.GameProfile");
var UUID = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.EaglercraftUUID", "randomUUID")]();
//Not using UUID to make patching easier for now
const fakeProfile = GameProfileClass.constructors[1](null, ModAPI.util.str("Steve"));
// Get the PlayerInteractionManager class
const PlayerInteractionManagerClass = ModAPI.reflect.getClassById("net.minecraft.server.management.ItemInWorldManager");
const playerInteractionManager = PlayerInteractionManagerClass.constructors[0](world.getRef());
// Get the EntityPlayerMP class to spawn the fake player
const EntityPlayerMPClass = ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP");
ModAPI.promisify(EntityPlayerMPClass.constructors[0])(ModAPI.server.getRef(), world.getRef(), fakeProfile, playerInteractionManager).then(result => {
console.log(result);
var fakePlayer = ModAPI.util.wrap(result);
// Set the fake player position to be near the command sender
console.log(senderPos);
fakePlayer.setPosition(senderPos.getX(), senderPos.getY(), senderPos.getZ());
// Add the fake player to the world
world.spawnEntityInWorld(fakePlayer.getRef());
// Notify the player that the fake player has been spawned
const ChatComponentTextClass = ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText");
event.sender.addChatMessage(ChatComponentTextClass.constructors[0](ModAPI.util.str("Fake Steve has been spawned!")));
});
// Prevent the command from executing further
event.preventDefault = true;
}
});
});
})();

214
examplemods/servermod.js Normal file
View File

@ -0,0 +1,214 @@
(function servermod() {
ModAPI.meta.title("Server Manager");
ModAPI.meta.version("a0");
ModAPI.meta.description("_");
ModAPI.meta.credits("ZXMushroom63 & radmanplays");
const gui = document.createElement("div");
gui.style.background = "black";
gui.style.fontFamily = "sans-serif";
gui.style.zIndex = 254;
gui.style.position = "fixed";
gui.style.display = "none";
gui.style.color = "white";
gui.style.top = gui.style.left = gui.style.bottom = gui.style.right = 0;
document.documentElement.appendChild(gui);
var cmdbox = document.createElement("input");
cmdbox.style.position = "absolute";
cmdbox.style.left = "0";
cmdbox.style.bottom = "0";
cmdbox.style.right = "0";
cmdbox.style.position = "inline-block";
cmdbox.style.border = "0";
cmdbox.style.borderTop = "2px solid white";
cmdbox.style.background = "black";
cmdbox.style.zIndex = 255;
cmdbox.style.color = "white";
cmdbox.type = "text";
cmdbox.addEventListener("keydown", (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
}, true);
cmdbox.addEventListener("keyup", (e) => {
e.stopPropagation();
e.stopImmediatePropagation();
if (e.key === "Enter") {
e.preventDefault();
toServer("chat", cmdbox.value);
}
}, true);
document.documentElement.appendChild(cmdbox);
function worldUpdate() {
if (ModAPI.mc && ModAPI.mc.theWorld) {
showgui();
openSharedWorld()
} else {
hidegui();
}
}
setInterval(() => {
worldUpdate();
}, 100);
function showgui() {
gui.style.opacity = "1";
gui.style.display = "block";
cmdbox.style.opacity = "1";
cmdbox.style.display = "block";
}
function hidegui() {
gui.style.opacity = "0";
gui.style.display = "none";
cmdbox.style.opacity = "0";
cmdbox.style.display = "none";
}
function openSharedWorld(){
if(ModAPI.mc.theWorld && !ModAPI.hooks.methods.nlevsl_LANServerController_isLANOpen()){
ModAPI.hooks.methods.nlevi_PlatformWebRTC_startRTCLANServer();
var worldName = ModAPI.util.unstr(ModAPI.mc.thePlayer.getName()) + "'s World";
var ls = ModAPI.mc.loadingScreen;
var code = ModAPI.hooks.methods.nlevsl_LANServerController_shareToLAN(ls.resetProgressAndMessage, worldName, false)
if (code != null) {
ModAPI.hooks.methods.nlevs_SingleplayerServerController_configureLAN(ModAPI.mc.playerController.getCurrentGameType(), false);
alert("code: " + code +" relay: " + ModAPI.hooks.methods.nlevsl_LANServerController_getCurrentURI())
}
} else {
return;
}
}
/*
NETWORKING OPCODES
chat - bidirectional, send chat to server/client
*/
function toServer(opcode, data) {
client_comms_channel.postMessage({
opcode: opcode,
audience: "server",
data: data,
});
}
var token = crypto.randomUUID();
const clientMessageHandlers = {
chat: function (data) {
gui.innerText += data + "\n";
},
};
var client_comms_channel = new BroadcastChannel("efserv:" + token);
client_comms_channel.addEventListener("message", (ev)=>{
if (ev.data.audience !== "client") {
return;
}
if (clientMessageHandlers[ev.data.opcode]) {
clientMessageHandlers[ev.data.opcode](ev.data.data);
}
});
ModAPI.dedicatedServer.appendCode(
`globalThis.efhost_security_token = "${token}";`
);
ModAPI.dedicatedServer.appendCode(function () {
var comms = new BroadcastChannel(
"efserv:" + globalThis.efhost_security_token
);
function toClient(opcode, data) {
comms.postMessage({
opcode: opcode,
audience: "client",
data: data,
});
}
function getHostPlayer() {
var host = null;
ModAPI.server.getRef().$worldServers.data.forEach((world) => {
host ||= world.$playerEntities.$array1.data.find((player) => {
var nameKey = ModAPI.util.getNearestProperty(
player.$gameProfile,
"$name"
);
return ModAPI.util.ustr(player.$gameProfile[nameKey]) === "HOST";
});
});
return host;
}
const messageHandlers = {
chat: function (data) {
ModAPI.hooks.methods.nmc_CommandHandler_executeCommand(
ModAPI.server.commandManager.getRef(),
getHostPlayer(),
ModAPI.util.str(data)
); //host has to use /say
},
};
comms.addEventListener("message", (ev) => {
if (ev.data.audience !== "server") {
return;
}
if (messageHandlers[ev.data.opcode]) {
messageHandlers[ev.data.opcode](ev.data.data);
}
});
var oldLog = ModAPI.hooks.methods.nlevl_Logger_log;
ModAPI.hooks.methods.nlevl_Logger_log = function (...args) {
toClient("chat", ModAPI.util.ustr(args[2]));
return oldLog.apply(this, args);
};
});
function renameButton(array, originalName, newName) {
array.find(
(x) => ModAPI.util.ustr(x.displayString.getRef()) === originalName
).displayString = ModAPI.util.str(newName);
}
const mainmenuinit = ModAPI.hooks.methods.nmcg_GuiMainMenu_initGui;
ModAPI.hooks.methods.nmcg_GuiMainMenu_initGui = function (...args) {
var result = mainmenuinit.apply(this, args);
var wrappedGuiObject = ModAPI.util.wrap(args[0], args[0], false, false);
wrappedGuiObject.splashText = ModAPI.util.str("Server Hosting Mode");
var btnarray = wrappedGuiObject.buttonList.array1;
renameButton(btnarray, "Singleplayer", "Host Server");
return result;
};
const GuiSelectWorldinit = ModAPI.hooks.methods.nmcg_GuiSelectWorld_initGui;
ModAPI.hooks.methods.nmcg_GuiSelectWorld_initGui = function (...args) {
var result = GuiSelectWorldinit.apply(this, args);
var wrappedGuiObject = ModAPI.util.wrap(args[0], args[0], false, false);
var btnarray = wrappedGuiObject.buttonList.array1.data;
//renameButton(btnarray, "Create", "Create Server");
return result;
};
const mainmenuactions = ModAPI.hooks.methods.nmcg_GuiMainMenu_actionPerformed;
ModAPI.hooks.methods.nmcg_GuiMainMenu_actionPerformed = function (...args) {
ModAPI.hooks.methods.nlevp_EaglerProfile_setName(ModAPI.util.str("HOST"));
var idKey = ModAPI.util.getNearestProperty(args[1], "$id");
var guiButtonid = args[1][idKey];
var blockedIds = [2]; // put the blocked/disabled button ids in there
if (blockedIds.includes(guiButtonid)) {
return 0;
}
return mainmenuactions.apply(this, args);
};
// disable rendering
ModAPI.hooks.methods.nmcr_EntityRenderer_renderWorld = () => { };
})();

View File

@ -1,13 +0,0 @@
//Test to make sure I can set a block
ModAPI.dedicatedServer.appendCode(function () {
var blockPosConstructor = ModAPI.reflect.getClassById("net.minecraft.util.BlockPos").constructors.find((x) => { return x.length === 3 });
ModAPI.addEventListener("processcommand", (event) => {
if (event.command.toLowerCase().startsWith("/testcmd")) {
var blockPos = blockPosConstructor(0, 0, 0);
var blockType = ModAPI.blocks["dirt"]; //blockType
var block = blockType.getDefaultState().getRef();
event.sender.getServerForPlayer().setBlockState(blockPos, block, 3);
event.preventDefault = true;
}
});
});

File diff suppressed because one or more lines are too long

View File

@ -1,68 +0,0 @@
//SUCCESS - While there is no TeaVM thread actively running, I am able to run an asynchronous function, and get a result.
ModAPI.hooks._teavm.$rt_startThread(() => {
return ModAPI.hooks.methods.nlevi_PlatformRuntime_downloadRemoteURI(ModAPI.util.str("data:text/plain,hi"))
}, function (...args) { console.log(this, args) })
// SUCCESS - Runs anywhere, anytime. Might work with async/await, but for now stick to .then()
ModAPI.promisify(ModAPI.hooks.methods.nlevi_PlatformRuntime_downloadRemoteURI)(ModAPI.util.str("data:text/plain,hi")).then(result => {
console.log(result); //Log arraybuffer
});
//WIP - Pausing and resuming client thread
globalThis.suspendTest = function (...args) {
if (!ModAPI.util.isCritical()) {
var thread = ModAPI.hooks._teavm.$rt_nativeThread();
var javaThread = ModAPI.hooks._teavm.$rt_getThread();
globalThis.testThread = thread;
console.log("BeforeAnything: ", thread.stack);
thread.suspend(function () {
console.log("Pausing for 10 seconds.", thread.stack);
setTimeout(function () {
console.log("Resuming...", thread.stack);
ModAPI.hooks._teavm.$rt_setThread(javaThread);
thread.resume();
console.log("After resume: ", thread.stack);
}, 10000);
});
}
return suspendTest.apply(this, args);
}
function jl_Thread_sleep$_asyncCall_$(millis) {
var thread = $rt_nativeThread();
var javaThread = $rt_getThread();
var callback = function () { };
callback.$complete = function (val) {
thread.attribute = val;
$rt_setThread(javaThread);
thread.resume();
};
callback.$error = function (e) {
thread.attribute = $rt_exception(e);
$rt_setThread(javaThread);
thread.resume();
};
callback = otpp_AsyncCallbackWrapper_create(callback);
thread.suspend(function () {
try {
jl_Thread_sleep0(millis, callback);
} catch ($e) {
callback.$error($rt_exception($e));
}
});
return null;
}
function jl_Thread_sleep0($millis, $callback) {
var $current, $handler;
$current = jl_Thread_currentThread();
$handler = new jl_Thread$SleepHandler;
$handler.$thread = $current;
$handler.$callback = $callback;
$handler.$scheduleId = otp_Platform_schedule($handler, Long_ge($millis, Long_fromInt(2147483647)) ? 2147483647 : Long_lo($millis));
$current.$interruptHandler = $handler;
}

View File

@ -1,17 +1,22 @@
//Metadata about the vclip mod
ModAPI.meta.title("Simple VClip Exploit"); ModAPI.meta.title("Simple VClip Exploit");
ModAPI.meta.description("Use .vclip <offset> to vertically phase through blocks."); ModAPI.meta.description("Use .vclip <offset> to vertically phase through blocks.");
ModAPI.meta.credits("By ZXMushroom63"); ModAPI.meta.credits("By ZXMushroom63");
// Require the player entity
ModAPI.require("player"); ModAPI.require("player");
//When the player tries to send a chat message to the server
ModAPI.addEventListener("sendchatmessage", (ev) => { ModAPI.addEventListener("sendchatmessage", (ev) => {
var msg = ev.message.toLowerCase(); var msg = ev.message.toLowerCase(); //Get the lowercase version of the command
if (msg.startsWith(".vclip")) { if (msg.startsWith(".vclip")) { //If it starts with .vclip
ev.preventDefault = true; ev.preventDefault = true; //Don't send the chat message to the server
var yOffset = 1; var yOffset = 1; //Set the default Y offset to 1. This let's you use .vclip with no arguments to "unstuck" yourself;
if (msg.split(" ")[1]) { if (msg.split(" ")[1]) { //If there is a second part to the command
yOffset = parseFloat(msg.split(" ")[1]) || 0; yOffset = parseFloat(msg.split(" ")[1]) || 0; //Set the yOffset to that
} }
ModAPI.player.setPosition(ModAPI.player.posX, ModAPI.player.posY ModAPI.player.setPosition(ModAPI.player.posX, ModAPI.player.posY
+ yOffset, ModAPI.player.posZ); + yOffset, ModAPI.player.posZ); //Set the player's position to their current position plus the y offset.
ModAPI.displayToChat("[SimpleVClip] VClipped " + yOffset + " blocks."); ModAPI.displayToChat("[SimpleVClip] VClipped " + yOffset + " blocks."); //Display information to the client side chat.
} }
}); });

View File

@ -1,34 +1,29 @@
(() => { (() => {
PluginAPI.dedicatedServer.appendCode(function () { PluginAPI.dedicatedServer.appendCode(function () { //Run this code on the server
PluginAPI.addEventListener("processcommand", (event) => { PluginAPI.addEventListener("processcommand", (event) => { //Command processing event
// Check if the sender is a player // Check if the sender is a player
if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return; } if (!ModAPI.reflect.getClassById("net.minecraft.entity.player.EntityPlayerMP").instanceOf(event.sender.getRef())) { return; }
// Check if the command is "/spawnsheep" // Check if the command is "/spawnxp"
if (event.command.toLowerCase().startsWith("/spawnxp")) { if (event.command.toLowerCase().startsWith("/spawnxp")) {
const world = event.sender.getServerForPlayer(); const world = event.sender.getServerForPlayer();
const senderPos = event.sender.getPosition(); const senderPos = event.sender.getPosition();
// Create a sheep entity // Create an xp orb entity
const EntityXP = ModAPI.reflect.getClassByName("EntityXPOrb"); const EntityXP = ModAPI.reflect.getClassByName("EntityXPOrb");
const xporb = EntityXP.constructors[0](world.getRef(), senderPos.getX(), senderPos.getY(), senderPos.getZ(), 10); const xporb = EntityXP.constructors[0](world.getRef(), senderPos.getX(), senderPos.getY(), senderPos.getZ(), 10);
if (globalThis.AsyncSink) { //If we can, start the AsyncSink debugger to see filesystem requests // Add the xp orb to the world
AsyncSink.startDebuggingFS();
}
// Add the sheep to the world
ModAPI.promisify(ModAPI.hooks.methods.nmw_World_spawnEntityInWorld)(world.getRef(), xporb).then(result => { ModAPI.promisify(ModAPI.hooks.methods.nmw_World_spawnEntityInWorld)(world.getRef(), xporb).then(result => {
// Notify the player that the sheep has been spawned // Notify the player that the xp orb has been spawned
const ChatComponentTextClass = ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText");
event.sender.addChatMessage(ChatComponentTextClass.constructors[0](ModAPI.util.str("An xp orb has been spawned!")));
if (globalThis.AsyncSink) { //Stop debugging when we are done, otherwise the console will get filled up. // Get the chat component class
AsyncSink.stopDebuggingFS(); const ChatComponentTextClass = ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText");
} // Construct the chat component and send it to the client.
event.sender.addChatMessage(ChatComponentTextClass.constructors[0](ModAPI.util.str("An xp orb has been spawned!")));
}); });
// Prevent the command from executing further // Prevent the command from executing further (stops syntax errors / command does not exist errors)
event.preventDefault = true; event.preventDefault = true;
} }
}); });

View File

@ -56,6 +56,9 @@ globalThis.modapi_guikit = `// ModAPI GUI made by TheIdiotPlays
Modloader linker by Modloader linker by
<a href="https://github.com/ZXMushroom63">ZXMushroom63</a> <a href="https://github.com/ZXMushroom63">ZXMushroom63</a>
</p> </p>
<p>
API by <a href="https://github.com/ZXMushroom63">ZXMushroom63,</a> <a href="https://leah.chromebooks.lol">Leah Anderson,</a> and <a href="https://github.com/radmanplays">radmanplays</a>
</p>
</footer> </footer>
<style> <style>

View File

@ -56,6 +56,9 @@
Modloader linker by Modloader linker by
<a href="https://github.com/ZXMushroom63">ZXMushroom63</a> <a href="https://github.com/ZXMushroom63">ZXMushroom63</a>
</p> </p>
<p>
API by <a href="https://github.com/ZXMushroom63">ZXMushroom63,</a> <a href="https://leah.chromebooks.lol">Leah Anderson,</a> and <a href="https://github.com/radmanplays">radmanplays</a>
</p>
</footer> </footer>
<style> <style>

View File

@ -115,6 +115,9 @@ globalThis.modapi_postinit = "(" + (() => {
return name; return name;
} }
ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) { ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) {
target ||= {};
corrective ||= false;
disableFunctions ||= false;
const CorrectiveArray = patchProxyConfToCorrective(ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf); const CorrectiveArray = patchProxyConfToCorrective(ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf);
const CorrectiveRecursive = patchProxyConfToCorrective(ModAPI.util.TeaVM_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 (outputValue && typeof outputValue === "object" && Array.isArray(outputValue.data) && typeof outputValue.type === "function") {
@ -125,7 +128,7 @@ globalThis.modapi_postinit = "(" + (() => {
} }
if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) { if (outputValue && typeof outputValue === "object" && !Array.isArray(outputValue)) {
if (corrective) { if (corrective) {
return new Proxy(outputValue.data, CorrectiveRecursive); return new Proxy(outputValue, CorrectiveRecursive);
} }
return new Proxy(outputValue, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf); return new Proxy(outputValue, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf);
} }
@ -197,7 +200,7 @@ globalThis.modapi_postinit = "(" + (() => {
} }
return ModAPI.hooks._teavm.$rt_createDoubleArray(size); return ModAPI.hooks._teavm.$rt_createDoubleArray(size);
} }
ModAPI.version = "v2.0"; ModAPI.version = "v2.1";
ModAPI.flavour = "injector"; ModAPI.flavour = "injector";
ModAPI.GNU = "terry pratchett"; ModAPI.GNU = "terry pratchett";
ModAPI.credits = ["ZXMushroom63", "radmanplays", "Murturtle", "OtterCodes101", "TheIdiotPlays", "OeildeLynx31", "Stpv22"]; ModAPI.credits = ["ZXMushroom63", "radmanplays", "Murturtle", "OtterCodes101", "TheIdiotPlays", "OeildeLynx31", "Stpv22"];

View File

@ -1,23 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>EF Injector Roadmap</title>
<link rel="stylesheet" href="roadmap.css" />
</head>
<body>
<h1>EaglerForgeInjector Roadmap</h1>
<div id="todolist">
Add custom itemstack meta to LCI [done]
Fix blocklook.js [todo]
Fix setblocktest.js [done]
Async toolkit library [done]
Object.keys() and `in` operator on proxy objects [todo]
Add textures to LCI. [todo]
</div>
<script src="roadmap.js"></script>
</body>
</html>

View File

@ -1,66 +0,0 @@
html,
body {
background-color: black;
color: white;
font-family: sans-serif;
overflow-x: hidden;
}
html {
padding: 0;
margin: 0;
width: 100vw;
height: 100vh;
}
body {
padding: 0.2rem;
}
* {
margin: 0;
padding: 0;
}
span {
text-align: left;
padding: 6px;
border-radius: 1rem;
background-color: rgba(125, 125, 125, 0.2);
margin-top: 1rem;
display: block;
}
summary {
background-color: rgba(255, 255, 255, 0.1);
padding: 4px;
border-radius: 0.6rem;
cursor: pointer;
padding-left: 8px;
}
span summary span {
width: 13.5px;
height: 13.5px;
display: inline-block;
float: right;
position: relative;
top: -19.5px;
right: -4px;
background-color: red;
border-radius: 9px;
opacity: 0.6;
transition: opacity 0.2s;
}
span summary span:hover {
opacity: 1;
}
span.working summary span {
background-color: rgb(255, 102, 0);
}
span.done summary span {
background-color: lime;
}
#todolist {
width: calc(50vw - 0.6rem);
margin-right: 0.2rem;
}
@media only screen and (max-width: 600px) {
#todolist {
width: calc(100vw - 0.6rem);
}
}

View File

@ -1,31 +0,0 @@
var todolist = document.querySelector("#todolist");
function getValue(a) {
if (a.includes("wip")) {
return 1;
}
if (a.includes("done")) {
return 2;
}
return 0;
}
var map = {
wip: "working",
done: "done"
}
var list = todolist.innerText.split("]").filter(x => x.length !== 0);
list.sort((a, b) => {
return getValue(a) - getValue(b);
});
todolist.innerHTML = "";
list.forEach(a => {
var x = a.split("[");
var d = document.createElement("span");
var s = document.createElement("summary");
d.appendChild(s);
s.innerHTML = x[0].trim().replaceAll("`", "<code>").replaceAll('#', "</code>");
var z = document.createElement("span");
d.classList.add(map[x[1].toLowerCase().trim()] || "todo");
s.appendChild(z);
todolist.appendChild(d);
});