Merge pull request #33 from eaglerforge/main

add self-compile instructions to documentation
This commit is contained in:
ZXMushroom63 2024-11-17 10:46:23 +08:00 committed by GitHub
commit acc4df76ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 246 additions and 25 deletions

53
docs/compiling_client.md Normal file
View File

@ -0,0 +1,53 @@
# Compiling Eaglercraft with support for EFI
In recent updates of eaglercraft, compiling for EaglerForgeInjector has become a great deal more complicated. To enable reflection and disable obfuscation, follow these steps once you have an EaglercraftX workspace set up:
1. In any files named `build.gradle`, set the `obfuscate` property to `false`.
2. In any files named `build.gradle`, find any code that looks like this:
```javascript
tasks.named("generateJavaScript") {
doLast {
// NOTE: This step may break at any time, and is not required for 99% of browsers
def phile = file(folder + "/" + name)
def dest = phile.getText("UTF-8")
def i = dest.substring(0, dest.indexOf("=\$rt_globals.Symbol('jsoClass');")).lastIndexOf("let ")
dest = dest.substring(0, i) + "var" + dest.substring(i + 3)
def j = dest.indexOf("function(\$rt_globals,\$rt_exports){")
dest = dest.substring(0, j + 34) + "\n" + file(folder + "/ES6ShimScript.txt").getText("UTF-8") + "\n" + dest.substring(j + 34)
phile.write(dest, "UTF-8")
}
}
```
and delete it.
3. Inside of the `src/teavm/java/net/lax1dude/eaglercraft/v1_8/internal/teavm/` folder, create a new file called `ForceReflection.java`, with these contents:
```java
package net.lax1dude.eaglercraft.v1_8.internal.teavm;
public class ForceReflection {
public static Object myObject;
public static Object forceInit(Class iClass) {
myObject = new ReflectiveClass();
try {
myObject = iClass.newInstance();
} catch (Exception e) {
// TODO: handle exception
}
return myObject;
}
public static class ReflectiveClass {
}
}
```
4. In the same folder, edit `MainClass.java` edit the start of the `main(String[] args)` method to look like this:
```java
public static void main(String[] args) {
ForceReflection.forceInit(ForceReflection.class);
if(args.length == 1) {
//... rest of method
```
5. Finally, build an offline download by using `CompileJS.bat`/`CompileJS.sh` and then `MakeOfflineDownload.bat`/`MakeOfflineDownload.sh`.
6. You can then upload the `EaglercraftX_1.8_Offline_en_US.html` into EaglerForgeInjector.

View File

@ -180,6 +180,58 @@ ModAPI.addEventListener("lib:libcustomitems:loaded", () => {
}
event.preventDefault = true;
}
// "this command was made by EymenWSMC. comments included" - radmanplays
if (event.command.toLowerCase().startsWith("//replacenear")) {
const args = event.command.split(" ").slice(1);
if (args.length < 3) {
event.sender.addChatMessage(ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText").constructors[0](ModAPI.util.str(prefix + "Usage: //replacenear <radius> <targetBlock> <replacementBlock>")));
event.preventDefault = true;
return;
}
const radius = parseInt(args[0]);
const targetBlockName = args[1];
const replacementBlockName = args[2];
const targetBlock = ModAPI.blocks[targetBlockName];
const replacementBlock = ModAPI.blocks[replacementBlockName];
if (!targetBlock || !replacementBlock) {
event.sender.addChatMessage(ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText").constructors[0](ModAPI.util.str(prefix + "Invalid block names!")));
event.preventDefault = true;
return;
}
//Replacing logic
const targetBlockState = targetBlock.getDefaultState().getRef();
const replacementBlockState = replacementBlock.getDefaultState().getRef();
const playerPos = event.sender.getPosition();
const xStart = Math.floor(playerPos.x - radius);
const xEnd = Math.floor(playerPos.x + radius);
const yStart = Math.floor(playerPos.y - radius);
const yEnd = Math.floor(playerPos.y + radius);
const zStart = Math.floor(playerPos.z - radius);
const zEnd = Math.floor(playerPos.z + radius);
//Replace ity with radoius
for (let x = xStart; x <= xEnd; x++) {
for (let y = yStart; y <= yEnd; y++) {
for (let z = zStart; z <= zEnd; z++) {
const blockPos = blockPosConstructor(x, y, z);
const currentBlock = event.sender.getServerForPlayer().getBlockState(blockPos);
if (currentBlock.equals(targetBlockState)) {
event.sender.getServerForPlayer().setBlockState(blockPos, replacementBlockState, 3);
}
}
}
}
//Send messages shit
event.sender.addChatMessage(ModAPI.reflect.getClassById("net.minecraft.util.ChatComponentText").constructors[0](ModAPI.util.str(prefix + `Replaced ${targetBlockName} with ${replacementBlockName} within radius ${radius}`)));
event.preventDefault = true;
}
});
});
})();

View File

@ -44,12 +44,11 @@ function registerSteveClientSide() {
ModAPI.util.str("steve")
);
blockClass.staticMethods.registerBlock0.method(
198, //use blockid 198
198, //use blockid 198. MAKE SURE TO CHANGE IF YOU ARE MAKING A MOD USING THIS, MAXIMUM BLOCK ID IS 4095.
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
ModAPI.mc.renderItem.registerBlock(block_of_steve, ModAPI.util.str("steve"));
ModAPI.addEventListener("lib:asyncsink", async () => {
ModAPI.addEventListener("custom:asyncsink_reloaded", ()=>{
ModAPI.mc.renderItem.registerBlock(block_of_steve, ModAPI.util.str("steve"));
@ -88,6 +87,7 @@ function registerSteveClientSide() {
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE0SURBVDhPpdO9S8NAHMbxy3sVfJmMg6h7FRXXkkUUX0addSjo4OAfIDqLIoiLi3+BRRx0EIQOnV0EcVAIWkR0KIFgrcEktX6vcXD0nuE+5Afhnhw5bWy4qylaidOfVQhT0zFKYozjBHVdzi3TwCZvteaS/0fLD8oGf5OzTeyxNUyE3Ln2HmGctpuxKuS3wd76CgPHsrEj142NeojCkHsFry+4c3aJ6g1OtlZp0Ok4DD4i+Y2GIZ+DMMAhtw+fHu8xi3IDM9t5YfMQF71dLHo+ZjsfXbh4WtnH0vYaqp/BcXGGM3D7BxiYTi+el8uYZWm2gM/VB/Tfaqje4GB5iga2Jv+sUuUa5/ITmOXq7gbnC+MY1r9QvcHG9AgN0lRex1u/ilr7ehqWvBNZvMlRbESfqNhAiG/Pb1bHXpMbFgAAAABJRU5ErkJggg=="
)).arrayBuffer());
});
ModAPI.blocks["steve"] = block_of_steve;
}
function registerSteveServerSide() {
function fixupBlockIds() {
@ -112,16 +112,18 @@ function registerSteveServerSide() {
ModAPI.util.str("steve")
);
blockClass.staticMethods.registerBlock0.method(
198,
198, //use blockid 198. MAKE SURE TO CHANGE IF YOU ARE MAKING A MOD USING THIS, MAXIMUM BLOCK ID IS 4095.
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
fixupBlockIds();
ModAPI.blocks["steve"] = block_of_steve;
});
}
ModAPI.dedicatedServer.appendCode(makeSteveBlock);
makeSteveBlock();
registerSteveClientSide();
fixupBlockIds();
ModAPI.dedicatedServer.appendCode(registerSteveServerSide);

View File

@ -26,13 +26,11 @@ function registerSteveClientSide() {
ModAPI.util.str("steve")
).$setCreativeTab(creativeBlockTab);
blockClass.staticMethods.registerBlock0.method(
198, //use blockid 198
198, //use blockid 198. MAKE SURE TO CHANGE IF YOU ARE MAKING A MOD USING THIS, MAXIMUM BLOCK ID IS 4095.
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
ModAPI.mc.renderItem.registerBlock(block_of_steve, ModAPI.util.str("steve"));
ModAPI.addEventListener("lib:asyncsink", async () => {
ModAPI.addEventListener("custom:asyncsink_reloaded", ()=>{
@ -72,6 +70,7 @@ function registerSteveClientSide() {
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE0SURBVDhPpdO9S8NAHMbxy3sVfJmMg6h7FRXXkkUUX0addSjo4OAfIDqLIoiLi3+BRRx0EIQOnV0EcVAIWkR0KIFgrcEktX6vcXD0nuE+5Afhnhw5bWy4qylaidOfVQhT0zFKYozjBHVdzi3TwCZvteaS/0fLD8oGf5OzTeyxNUyE3Ln2HmGctpuxKuS3wd76CgPHsrEj142NeojCkHsFry+4c3aJ6g1OtlZp0Ok4DD4i+Y2GIZ+DMMAhtw+fHu8xi3IDM9t5YfMQF71dLHo+ZjsfXbh4WtnH0vYaqp/BcXGGM3D7BxiYTi+el8uYZWm2gM/VB/Tfaqje4GB5iga2Jv+sUuUa5/ITmOXq7gbnC+MY1r9QvcHG9AgN0lRex1u/ilr7ehqWvBNZvMlRbESfqNhAiG/Pb1bHXpMbFgAAAABJRU5ErkJggg=="
)).arrayBuffer());
});
ModAPI.blocks["steve"] = block_of_steve;
}
function registerSteveServerSide() {
function fixupBlockIds() {
@ -98,12 +97,13 @@ function registerSteveServerSide() {
ModAPI.util.str("steve")
).$setCreativeTab(creativeBlockTab);
blockClass.staticMethods.registerBlock0.method(
198,
198, //use blockid 198. MAKE SURE TO CHANGE IF YOU ARE MAKING A MOD USING THIS, MAXIMUM BLOCK ID IS 4095.
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
fixupBlockIds();
ModAPI.blocks["steve"] = block_of_steve;
});
}
registerSteveClientSide();

View File

@ -0,0 +1,51 @@
(function AddDiamondRecipe() {
ModAPI.meta.title("DiamondCraftingRecipeMod");
ModAPI.meta.description("Adds a crafting recipe to create diamond blocks from dirt.");
async function addDiamondRecipe() {
await new Promise((res,rej)=>{var x = setInterval(()=>{if(ModAPI.blocks){clearInterval(x);res();}}, 100);})
var ObjectClass = ModAPI.reflect.getClassById("java.lang.Object").class;
function ToChar(char) {
return ModAPI.reflect.getClassById("java.lang.Character").staticMethods.valueOf.method(char[0].charCodeAt(0));
}
// Define the recipe legend to map characters to items
var recipeLegend = {
"D": {
type: "block",
id: "dirt" // Using dirt blocks
}
};
// Define the crafting grid pattern for the recipe
var recipePattern = [
"DDD",
"DDD",
"DDD"
];
// Convert the recipe pattern and legend into the required format
var recipeInternal = [];
Object.keys(recipeLegend).forEach((key) => {
recipeInternal.push(ToChar(key));
var ingredient = ModAPI.blocks[recipeLegend[key].id].getRef();
recipeInternal.push(ingredient);
});
var recipeContents = recipePattern.flatMap(row => ModAPI.util.str(row));
var recipe = ModAPI.util.makeArray(ObjectClass, recipeContents.concat(recipeInternal));
// Define the output item as diamond_block
var resultItem = ModAPI.reflect.getClassById("net.minecraft.item.ItemStack").constructors[1](ModAPI.blocks["diamond_block"].getRef(), 1);
// Register the recipe with CraftingManager
var craftingManager = ModAPI.reflect.getClassById("net.minecraft.item.crafting.CraftingManager").staticMethods.getInstance.method();
ModAPI.hooks.methods.nmic_CraftingManager_addRecipe(craftingManager, resultItem, recipe);
}
ModAPI.dedicatedServer.appendCode(addDiamondRecipe);
addDiamondRecipe();
})();

View File

@ -15,7 +15,7 @@
globalThis.LCI_ITEMDB ||= {};
globalThis.LibCustomItems = {
makeItemStack: function makeItemStack(tag) {
return globalThis.LCI_ITEMBD[tag] || null;
return globalThis.LCI_ITEMDB[tag] || null;
}
};
var useName = ModAPI.util.getMethodFromPackage("net.minecraft.network.NetHandlerPlayServer", "processPlayerBlockPlacement");
@ -148,7 +148,7 @@
if (globalThis.LCI_RECIPEEVENTS[data.tag]) {
globalThis.LCI_RECIPEEVENTS[data.tag](new Proxy(testItem, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf));
}
globalThis.LCI_ITEMBD[data.tag] = new Proxy(testItem, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf);
globalThis.LCI_ITEMDB[data.tag] = new Proxy(testItem, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf);
var craftingManager = ModAPI.reflect.getClassById("net.minecraft.item.crafting.CraftingManager").staticMethods.getInstance.method();
if((data.useRecipe !== false) || (data.useRecipe !== "false")) {
@ -162,7 +162,7 @@
LCI_registerItem(data);
}
LibCustomItems.makeItemStack = function makeItemStack(tag) {
return globalThis.LCI_ITEMBD[tag] || null;
return globalThis.LCI_ITEMDB[tag] || null;
}
ModAPI.events.callEvent("lib:libcustomitems:loaded", {});
})();

View File

@ -0,0 +1,4 @@
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.particle.EffectRenderer", "renderParticles")] = ()=>{};
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.particle.EffectRenderer", "hasParticlesInAlphaLayer")] = ()=>{return 0};
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.particle.EffectRenderer", "addEffect")] = ()=>{};
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.particle.EffectRenderer", "addBlockDestroyEffects")] = ()=>{};

View File

@ -56,7 +56,7 @@
ModAPI.util.str("unluckiness")
);
blockClass.staticMethods.registerBlock0.method(
544,
544, //use blockid 544. MAKE SURE TO CHANGE IF YOU ARE MAKING A MOD USING THIS, MAXIMUM BLOCK ID IS 4095.
ModAPI.util.str("unluckiness"),
block_of_unluckiness
);

View File

@ -0,0 +1,72 @@
// This is an example mod on how to register an item.
(()=>{
const itemTexture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAKZJREFUOE9j/P//PxMDBIBoEP6HREOl4PLIciA2AyPIgMcM//7KgvWSDJjBBpx9/+YvJzc3Sbq12DhB6sEGsJ19/+YnmQawYhigzc7FcPXnN4KugbqAHWQAy9n3b34T4wJkw6EGYLqAoNVQBWS5ANlwZBfAvUCs/0EGkW0AzBKqGoCSDgh5A80F2KMRpAgfAKUT6kcjsfEPUycmKMQgy8AETkgUZWcAS3CPIf4oSPsAAAAASUVORK5CYII=";
//this texture is really baad, so the item appears 2d in game.
ModAPI.meta.title("Adding items demo.");
ModAPI.meta.version("v1.0");
ModAPI.meta.icon(itemTexture);
ModAPI.meta.description("Requires AsyncSink.");
function ExampleItem() {
var creativeMiscTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabMisc;
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
var itemSuper = ModAPI.reflect.getSuper(itemClass, (x) => x.length === 1);
var nmi_ItemExample = function nmi_ItemExample() {
itemSuper(this); //Use super function to get block properties on this class.
this.$setCreativeTab(creativeMiscTab);
}
ModAPI.reflect.prototypeStack(itemClass, nmi_ItemExample);
nmi_ItemExample.prototype.$onItemRightClick = function ($itemstack, $world, $player) { //example of how to override a method
return $itemstack;
}
function internal_reg() {
var example_item = (new nmi_ItemExample()).$setUnlocalizedName(
ModAPI.util.str("exampleitem")
);
itemClass.staticMethods.registerItem0.method(432, ModAPI.util.str("exampleitem"), example_item);
ModAPI.items["exampleitem"] = example_item;
return example_item;
}
if (ModAPI.items) {
return internal_reg();
} else {
ModAPI.addEventListener("bootstrap", internal_reg);
}
}
ModAPI.dedicatedServer.appendCode(ExampleItem);
var example_item = ExampleItem();
ModAPI.addEventListener("lib:asyncsink", async () => {
ModAPI.addEventListener("custom:asyncsink_reloaded", ()=>{
ModAPI.mc.renderItem.registerItem(example_item, ModAPI.util.str("exampleitem"));
});
AsyncSink.L10N.set("item.exampleitem.name", "Example Item");
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/item/exampleitem.json", JSON.stringify(
{
"parent": "builtin/generated",
"textures": {
"layer0": "items/exampleitem"
},
"display": {
"thirdperson": {
"rotation": [ -90, 0, 0 ],
"translation": [ 0, 1, -3 ],
"scale": [ 0.55, 0.55, 0.55 ]
},
"firstperson": {
"rotation": [ 0, -135, 25 ],
"translation": [ 0, 4, 2 ],
"scale": [ 1.7, 1.7, 1.7 ]
}
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/items/exampleitem.png", await (await fetch(
itemTexture
)).arrayBuffer());
});
})();

View File

@ -117,20 +117,7 @@
<summary>
How do I compile my own unobfuscated unsigned Eaglercraft build?
</summary>
Once you have a local EaglercraftX workspace setup, in
<code>build.gradle</code>, set the <code>obfuscate</code> property to
<code>false</code>. Then, run <code>CompileJS.bat</code> (or .sh if on
a unix-based os), and then run <code>MakeOfflineDownload.bat</code>.
The outputted offline download will have a much larger file size than
other offline builds. This is the file you should select. (it should
have a naming convention similar to
<code>EaglercraftX_1.8_Offline_en_US.html</code>)
</details>
<details>
<summary>Roadmap?</summary>
<a href="https://eaglerforge.github.io/EaglerForgeInjector/roadmap/"
>roadmap.</a
>
<a href="docs/compiling_client.md">tutorial here</a>
</details>
<details>
<summary>How does this tool work?</summary>