mirror of
https://github.com/eaglerforge/EaglerForgeInjector
synced 2025-07-26 15:29:26 -09:00
commit
2618cefdc4
@ -1,5 +1,5 @@
|
|||||||
# EaglerForgeInjector
|
# EaglerForgeInjector
|
||||||
An advanced modding API injector for vanilla eaglercraft builds.
|
An advanced modding API injector for unminified, unobfuscated, unsigned eaglercraft builds.
|
||||||
Current features:
|
Current features:
|
||||||
- Method hooking/monkey patching
|
- Method hooking/monkey patching
|
||||||
- Reflection
|
- Reflection
|
||||||
@ -13,5 +13,11 @@ Go to https://eaglerforge.github.io/EaglerForgeInjector/ and upload an unminifie
|
|||||||
#### Portable Offline
|
#### Portable Offline
|
||||||
Download this repository as a .zip, and extract it. Open index.html with your preferred browser (use `ctrl` + `O` on a new tab) and upload an unminified, unobfuscated, unsigned EaglercraftX offline download.
|
Download this repository as a .zip, and extract it. Open index.html with your preferred browser (use `ctrl` + `O` on a new tab) and upload an unminified, unobfuscated, unsigned EaglercraftX offline download.
|
||||||
|
|
||||||
|
#### How does it work?
|
||||||
|
This tool matches patterns in eaglercraft builds and adds patching code to let you modify how the code works at runtime. It then adds a [corelib](./postinit.js) that initialises the `ModAPI` object.
|
||||||
|
|
||||||
|
#### History
|
||||||
|
EaglerForgeInjector is a replacement for the `ModAPI` in the [old eaglerforge](https://github.com/EaglerForge/EaglerForge-old), which was maintained by @radmanplays. The legacy eaglerforge was a port of [OtterDev's EaglerReborn (dmca'd)](https://github.com/EaglerReborn/reborn)'s `PluginAPI` (created by me, @ZXMushroom63) to run on newer versions of Eaglercraft, with a few improvements and new features. Unlike EaglerForgeInjector, both legacy eaglerforge and eaglerreborn manually exposed properties and methods one by one.
|
||||||
|
|
||||||
## Discord server
|
## Discord server
|
||||||
[https://discord.gg/rbxN7kby5W](https://discord.gg/rbxN7kby5W)
|
[https://discord.gg/rbxN7kby5W](https://discord.gg/rbxN7kby5W)
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
## ModAPI.keygen
|
## ModAPI.keygen
|
||||||
ModAPI.keygen contains the API for getting item and block IDs from a string. It looks at the registries for items and blocks to derive the IDs, so IDs will not be automatically reserved until a block/item is actually registered. Ideally, you'd want to call a keygen method just before registering your block.
|
ModAPI.keygen contains the API for getting numerical item, block and entity IDs from a string. It looks at registries to derive the IDs, so IDs will not be automatically reserved until a block/item is actually registered into the game. Ideally, you'd want to call a keygen method just before registering your block.
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
- `ModAPI.keygen.item(itemId: String) : number`
|
- `ModAPI.keygen.item(itemId: String) : number`
|
||||||
- Example usage is: `var id = ModAPI.keygen.item("my_example_item");`
|
- Example usage is: `var id = ModAPI.keygen.item("my_example_item");`
|
||||||
- `ModAPI.keygen.block(blockId: String) : number`
|
- `ModAPI.keygen.block(blockId: String) : number`
|
||||||
- Example usage is: `var id = ModAPI.keygen.block("my_example_block");`
|
- Example usage is: `var id = ModAPI.keygen.block("my_example_block");`
|
||||||
|
- `ModAPI.keygen.entity(entityId: String) : number`
|
||||||
|
- Example usage is: `var id = ModAPI.keygen.entity("my_example_entity");`
|
@ -6,6 +6,7 @@ Properties:
|
|||||||
|
|
||||||
- `classes: ReflectClass[]`
|
- `classes: ReflectClass[]`
|
||||||
- `ModAPI.reflect.classes` is an array of ReflectClasses, representing (almost) every java class.
|
- `ModAPI.reflect.classes` is an array of ReflectClasses, representing (almost) every java class.
|
||||||
|
- `classMap: Map<String, ReflectClass>` is a map of every class.
|
||||||
|
|
||||||
Methods:
|
Methods:
|
||||||
|
|
||||||
@ -16,12 +17,17 @@ Methods:
|
|||||||
- This method is used to find a class by its id.
|
- This method is used to find a class by its id.
|
||||||
- For example, to get the `Minecraft` class, you can use `ModAPI.reflect.getClassById("Minecraft")`
|
- For example, to get the `Minecraft` class, you can use `ModAPI.reflect.getClassById("Minecraft")`
|
||||||
- This runs slower than `getClassById` because it has to filter through all classes. Make sure to cache the result rather than calling it over and over again.
|
- This runs slower than `getClassById` because it has to filter through all classes. Make sure to cache the result rather than calling it over and over again.
|
||||||
- `ModAPI.reflect.getSuper(rClass: ReflectClass, filter: Function) : Function`
|
- `ModAPI.reflect.getSuper(rClass: ReflectClass, filter: Function?) : Function`
|
||||||
- Gets a super function from a reflect class. This is used to extend built in classes, like `Block`.
|
- Gets a super function from a reflect class. This is used to extend built in classes, like `Block`.
|
||||||
- For an example, see lines [29](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L29) and [33](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L33) in unlucky_blocks.js
|
- For an example, see lines [29](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L29) and [33](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L33) in `unlucky_blocks.js`
|
||||||
|
- When called without a filter function, the filter defaults to `(fn)=>fn.length === 1`
|
||||||
- `ModAPI.reflect.prototypeStack(rClass: ReflectClass, target: Class/ConstructorFunction) : void`
|
- `ModAPI.reflect.prototypeStack(rClass: ReflectClass, target: Class/ConstructorFunction) : void`
|
||||||
- Copies methods from a reflect class and it's parents onto a target native JavaScript class. This allows TeaVM to use these objects normally, without you having to manually reimplement every method. In other words, this is the equivalent of extending a class.
|
- Copies methods from a reflect class and it's parents onto a target native JavaScript class. This allows TeaVM to use these objects normally, without you having to manually reimplement every method. In other words, this is the equivalent of extending a class.
|
||||||
|
- Also adds some metadata to make the class work with `ModAPI.util.asClass`
|
||||||
- [Example usage](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L37)
|
- [Example usage](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L37)
|
||||||
|
- `ModAPI.reflect.implements(target: Class/ConstructorFunction, interface: ReflectClass)`
|
||||||
|
- Marks the provided interface as a supertype of the target class.
|
||||||
|
- JavaScript equivalent of the `implements` keyword
|
||||||
### ReflectClass Definition
|
### ReflectClass Definition
|
||||||
|
|
||||||
Each `ReflectClass` has the following properties:
|
Each `ReflectClass` has the following properties:
|
||||||
@ -49,11 +55,8 @@ Each `ReflectClass` has the following properties:
|
|||||||
- List of all the static variable names for the class.
|
- List of all the static variable names for the class.
|
||||||
- `staticVariables: Map<String, *>`
|
- `staticVariables: Map<String, *>`
|
||||||
- key-value dictionary of all the static variables in a class.
|
- key-value dictionary of all the static variables in a class.
|
||||||
- `superclass: Class?`
|
- `superclass: ReflectClass?`
|
||||||
- The raw teavm class of the superclass.
|
- The superclass.
|
||||||
- `superclassName: String?`
|
|
||||||
- The class id of the class's superclass. Eg: `net.minecraft.client.entity.AbstractClientPlayer`
|
|
||||||
- Will be `null` if `hasMeta` is equal to `false`
|
|
||||||
|
|
||||||
Each `ReflectClass` has the following methods:
|
Each `ReflectClass` has the following methods:
|
||||||
|
|
||||||
|
@ -82,3 +82,6 @@ Methods:
|
|||||||
- Gets a block by it's ID
|
- Gets a block by it's ID
|
||||||
- `ModAPI.util.getBlockFromItem(item: Item) : Block`
|
- `ModAPI.util.getBlockFromItem(item: Item) : Block`
|
||||||
- Gets a block from an ItemBlock instance.
|
- Gets a block from an ItemBlock instance.
|
||||||
|
- `ModAPI.util.asClass(class: Class) : Class`
|
||||||
|
- Converts a javascript class to a java class.
|
||||||
|
- Equivalent of using `MyClass.class` in java.
|
@ -185,7 +185,7 @@ When it's loaded, we'll:
|
|||||||
ModAPI.addEventListener("lib:asyncsink", async () => { //Add an asyncronous listener to AsyncSink loading.
|
ModAPI.addEventListener("lib:asyncsink", async () => { //Add an asyncronous listener to AsyncSink loading.
|
||||||
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
||||||
//when asyncsink yells at us to register the custom block, register it
|
//when asyncsink yells at us to register the custom block, register it
|
||||||
renderItem.registerItem(custom_block, ModAPI.util.str("custom_block"));
|
renderItem.registerBlock(custom_block, ModAPI.util.str("custom_block"));
|
||||||
});
|
});
|
||||||
AsyncSink.L10N.set("tile.custom_block.name", "My Custom Block"); //Set the name of the block
|
AsyncSink.L10N.set("tile.custom_block.name", "My Custom Block"); //Set the name of the block
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ const asyncSinkIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAY
|
|||||||
ModAPI.meta.icon(asyncSinkIcon);
|
ModAPI.meta.icon(asyncSinkIcon);
|
||||||
ModAPI.meta.credits("By ZXMushroom63");
|
ModAPI.meta.credits("By ZXMushroom63");
|
||||||
(function AsyncSinkFn() {
|
(function AsyncSinkFn() {
|
||||||
|
const ResourceLocation = ModAPI.reflect.getClassByName("ResourceLocation").constructors.find(x => x.length === 1);
|
||||||
//AsyncSink is a plugin to debug and override asynchronous methods in EaglercraftX
|
//AsyncSink is a plugin to debug and override asynchronous methods in EaglercraftX
|
||||||
async function runtimeComponent() {
|
async function runtimeComponent() {
|
||||||
const booleanResult = (b) => ModAPI.hooks.methods.nlevit_BooleanResult__new(b * 1);
|
const booleanResult = (b) => ModAPI.hooks.methods.nlevit_BooleanResult__new(b * 1);
|
||||||
@ -43,6 +44,17 @@ ModAPI.meta.credits("By ZXMushroom63");
|
|||||||
AsyncSink.L10N = new Map();
|
AsyncSink.L10N = new Map();
|
||||||
AsyncSink.FSOverride = new Set();
|
AsyncSink.FSOverride = new Set();
|
||||||
AsyncSink.MIDDLEWARE = [];
|
AsyncSink.MIDDLEWARE = [];
|
||||||
|
|
||||||
|
//takes in a ResourceLocation and removes cached data. Use to only reload a specific texture if you know where it is stored.
|
||||||
|
AsyncSink.clearResourcePointer = function clearResourcePointer(resourceLocation) {
|
||||||
|
if (!resourceLocation) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var res = ModAPI.util.wrap((resourceLocation.isModProxy === true) ? resourceLocation.getRef() : resourceLocation);
|
||||||
|
res.cachedPointer = null;
|
||||||
|
res.cachedPointerType = 0;
|
||||||
|
ModAPI.mc.getTextureManager().mapTextureObjects.remove(res.getRef());
|
||||||
|
}
|
||||||
AsyncSink.setFile = function setFile(path, data) {
|
AsyncSink.setFile = function setFile(path, data) {
|
||||||
if (typeof data === "string") {
|
if (typeof data === "string") {
|
||||||
data = encoder.encode(data).buffer;
|
data = encoder.encode(data).buffer;
|
||||||
@ -58,6 +70,12 @@ ModAPI.meta.credits("By ZXMushroom63");
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsyncSink.hideFile = function hideFile(path) {
|
||||||
|
AsyncSink.FSOverride.add(path);
|
||||||
|
AsyncSink.FS.delete(path);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
AsyncSink.getFile = function getFile(path) {
|
AsyncSink.getFile = function getFile(path) {
|
||||||
return AsyncSink.FS.get(path) || new ArrayBuffer(0);
|
return AsyncSink.FS.get(path) || new ArrayBuffer(0);
|
||||||
}
|
}
|
||||||
@ -160,6 +178,16 @@ ModAPI.meta.credits("By ZXMushroom63");
|
|||||||
return originalL10NRead.apply(this, args);
|
return originalL10NRead.apply(this, args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const L18NFormat = ModAPI.util.getMethodFromPackage("net.minecraft.client.resources.I18n", "format");
|
||||||
|
const originalL18NFormat = ModAPI.hooks.methods[L18NFormat];
|
||||||
|
ModAPI.hooks.methods[L18NFormat] = function (...args) {
|
||||||
|
var key = ModAPI.util.ustr(args[0]);
|
||||||
|
if (AsyncSink.L10N.has(key)) {
|
||||||
|
args[0] = ModAPI.util.str(AsyncSink.L10N.get(key));
|
||||||
|
}
|
||||||
|
return originalL18NFormat.apply(this, args);
|
||||||
|
};
|
||||||
|
|
||||||
const L10NCheck = ModAPI.util.getMethodFromPackage("net.minecraft.util.StatCollector", "canTranslate");
|
const L10NCheck = ModAPI.util.getMethodFromPackage("net.minecraft.util.StatCollector", "canTranslate");
|
||||||
const originalL10NCheck = ModAPI.hooks.methods[L10NCheck];
|
const originalL10NCheck = ModAPI.hooks.methods[L10NCheck];
|
||||||
ModAPI.hooks.methods[L10NCheck] = function (...args) {
|
ModAPI.hooks.methods[L10NCheck] = function (...args) {
|
||||||
@ -257,6 +285,7 @@ ModAPI.meta.credits("By ZXMushroom63");
|
|||||||
ModAPI.mc.renderItem.itemModelMesher.simpleShapesCache.clear();
|
ModAPI.mc.renderItem.itemModelMesher.simpleShapesCache.clear();
|
||||||
ModAPI.promisify(ModAPI.mc.refreshResources)().then(() => {
|
ModAPI.promisify(ModAPI.mc.refreshResources)().then(() => {
|
||||||
ModAPI.events.callEvent("custom:asyncsink_reloaded", {});
|
ModAPI.events.callEvent("custom:asyncsink_reloaded", {});
|
||||||
|
ModAPI.events.callEvent("lib:asyncsink:registeritems", ModAPI.mc.renderItem);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -268,4 +297,69 @@ ModAPI.meta.credits("By ZXMushroom63");
|
|||||||
ModAPI.events.callEvent("lib:asyncsink:registeritems", ModAPI.util.wrap(args[0]));
|
ModAPI.events.callEvent("lib:asyncsink:registeritems", ModAPI.util.wrap(args[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AsyncSink.Audio = {};
|
||||||
|
AsyncSink.Audio.Category = ModAPI.reflect.getClassByName("SoundCategory").staticVariables;
|
||||||
|
AsyncSink.Audio.Objects = [];
|
||||||
|
const SoundHandler_onResourceManagerReload = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.audio.SoundHandler", "onResourceManagerReload")];
|
||||||
|
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.client.audio.SoundHandler", "onResourceManagerReload")] = function (...args) {
|
||||||
|
SoundHandler_onResourceManagerReload.apply(this, args);
|
||||||
|
if (ModAPI.util.isCritical()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var snd = ModAPI.mc.mcSoundHandler;
|
||||||
|
var registry = snd.sndRegistry.soundRegistry;
|
||||||
|
console.log("[AsyncSink] Populating sound registry hash map with " + AsyncSink.Audio.Objects.length + " sound effects.");
|
||||||
|
AsyncSink.Audio.Objects.forEach(pair => {
|
||||||
|
registry.put(pair[0], pair[1]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// key = "mob.entity.say"
|
||||||
|
// values = SoundEntry[]
|
||||||
|
// category: AsyncSink.Audio.Category.*
|
||||||
|
// SoundEntry = {path: String, pitch: 1, volume: 1, streaming: false}
|
||||||
|
const SoundPoolEntry = ModAPI.reflect.getClassByName("SoundPoolEntry").constructors.find(x => x.length === 4);
|
||||||
|
const EaglercraftRandom = ModAPI.reflect.getClassByName("EaglercraftRandom").constructors.find(x=>x.length===0);
|
||||||
|
const SoundEventAccessorClass = ModAPI.reflect.getClassByName("SoundEventAccessor").class;
|
||||||
|
function makeSoundEventAccessor(soundpoolentry, weight) {
|
||||||
|
var object = new SoundEventAccessorClass;
|
||||||
|
var wrapped = ModAPI.util.wrap(object).getCorrective();
|
||||||
|
wrapped.entry = soundpoolentry;
|
||||||
|
wrapped.weight = weight;
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
const SoundEventAccessorCompositeClass = ModAPI.reflect.getClassByName("SoundEventAccessorComposite").class;
|
||||||
|
function makeSoundEventAccessorComposite(rKey, pitch, volume, category) {
|
||||||
|
var object = new SoundEventAccessorCompositeClass;
|
||||||
|
var wrapped = ModAPI.util.wrap(object).getCorrective();
|
||||||
|
wrapped.soundLocation = rKey;
|
||||||
|
wrapped.eventPitch = pitch;
|
||||||
|
wrapped.eventVolume = volume;
|
||||||
|
wrapped.category = category;
|
||||||
|
wrapped.soundPool = ModAPI.hooks.methods.cgcc_Lists_newArrayList1();
|
||||||
|
wrapped.rnd = EaglercraftRandom();
|
||||||
|
return object;
|
||||||
|
}
|
||||||
|
AsyncSink.Audio.register = function addSfx(key, category, values) {
|
||||||
|
if (!category) {
|
||||||
|
throw new Error("[AsyncSink] Invalid audio category provided: "+category);
|
||||||
|
}
|
||||||
|
var snd = ModAPI.mc.mcSoundHandler;
|
||||||
|
var registry = snd.sndRegistry.soundRegistry;
|
||||||
|
var rKey = ResourceLocation(ModAPI.util.str(key));
|
||||||
|
var soundPool = values.map(se => {
|
||||||
|
var path = ResourceLocation(ModAPI.util.str(se.path));
|
||||||
|
return SoundPoolEntry(path, se.pitch, se.volume, 1 * se.streaming);
|
||||||
|
}).map(spe => {
|
||||||
|
return makeSoundEventAccessor(spe, 1); // 1 = weight
|
||||||
|
});
|
||||||
|
var compositeSound = makeSoundEventAccessorComposite(rKey, 1, 1, category);
|
||||||
|
var compositeSoundWrapped = ModAPI.util.wrap(compositeSound);
|
||||||
|
soundPool.forEach(sound => {
|
||||||
|
compositeSoundWrapped.soundPool.add(sound);
|
||||||
|
});
|
||||||
|
AsyncSink.Audio.Objects.push([rKey, compositeSound]);
|
||||||
|
registry.put(rKey, compositeSound);
|
||||||
|
values.map(x=>"resourcepacks/AsyncSinkLib/assets/minecraft/" + x.path + ".mcmeta").forEach(x=>AsyncSink.setFile(x, new ArrayBuffer(0)));
|
||||||
|
}
|
||||||
})();
|
})();
|
@ -1,4 +1,4 @@
|
|||||||
//This mod also requires lib.customitems.js
|
//Demo mod showing how to use lib.customitems.js
|
||||||
ModAPI.addEventListener("lib:libcustomitems:loaded", () => {
|
ModAPI.addEventListener("lib:libcustomitems:loaded", () => {
|
||||||
console.log("Registered my cool custom item.");
|
console.log("Registered my cool custom item.");
|
||||||
LibCustomItems.registerItem({
|
LibCustomItems.registerItem({
|
||||||
|
209
examplemods/DuckMod.js
Normal file
209
examplemods/DuckMod.js
Normal file
File diff suppressed because one or more lines are too long
@ -92,7 +92,7 @@
|
|||||||
|
|
||||||
ModAPI.addEventListener("lib:asyncsink", async () => { //Add an asyncronous listener to AsyncSink loading.
|
ModAPI.addEventListener("lib:asyncsink", async () => { //Add an asyncronous listener to AsyncSink loading.
|
||||||
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
||||||
renderItem.registerItem(custom_block, ModAPI.util.str("custom_block"));
|
renderItem.registerBlock(custom_block, ModAPI.util.str("custom_block"));
|
||||||
});
|
});
|
||||||
AsyncSink.L10N.set("tile.custom_block.name", "My Custom Block"); //Set the name of the block
|
AsyncSink.L10N.set("tile.custom_block.name", "My Custom Block"); //Set the name of the block
|
||||||
|
|
||||||
|
28
examplemods/afkmod.js
Normal file
28
examplemods/afkmod.js
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
(function AntiAFKMod() {
|
||||||
|
ModAPI.meta.title("Anti AFK Mod");
|
||||||
|
ModAPI.meta.credits("By ZXMushroom63");
|
||||||
|
ModAPI.meta.description("Type .afk in game chat to toggle the mod");
|
||||||
|
ModAPI.require("player");
|
||||||
|
var active = null;
|
||||||
|
function queueJump() {
|
||||||
|
try {
|
||||||
|
ModAPI.player.jump();
|
||||||
|
} catch (error) {
|
||||||
|
|
||||||
|
}
|
||||||
|
active = setTimeout(queueJump, 15000 + (10000 * Math.random()));
|
||||||
|
}
|
||||||
|
ModAPI.addEventListener("sendchatmessage", (e)=>{
|
||||||
|
if (e.message.toLowerCase() === ".afk") {
|
||||||
|
if (active === null) {
|
||||||
|
queueJump();
|
||||||
|
ModAPI.displayToChat("Activated anti-afk mod!\nI recommend using the sliders mod to decrease your max fps to save battery.");
|
||||||
|
} else {
|
||||||
|
clearTimeout(active);
|
||||||
|
active = null;
|
||||||
|
ModAPI.displayToChat("Deactivated anti-afk mod.");
|
||||||
|
}
|
||||||
|
e.preventDefault = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
@ -43,7 +43,7 @@ function registerSteveClientSide() {
|
|||||||
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
|
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
|
||||||
ModAPI.addEventListener("lib:asyncsink", async () => {
|
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||||
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
||||||
renderItem.registerItem(block_of_steve, ModAPI.util.str("steve"));
|
renderItem.registerBlock(block_of_steve, ModAPI.util.str("steve"));
|
||||||
});
|
});
|
||||||
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
|
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
|
||||||
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
|
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
|
||||||
|
@ -34,7 +34,7 @@ function registerSteveClientSide() {
|
|||||||
|
|
||||||
ModAPI.addEventListener("lib:asyncsink", async () => {
|
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||||
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
||||||
renderItem.registerItem(block_of_steve, ModAPI.util.str("steve"));
|
renderItem.registerBlock(block_of_steve, ModAPI.util.str("steve"));
|
||||||
});
|
});
|
||||||
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
|
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
|
||||||
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
|
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
|
||||||
|
135
examplemods/cubeentity.js
Normal file
135
examplemods/cubeentity.js
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
(function CubeEntity() {
|
||||||
|
ModAPI.meta.title("Cube Entity");
|
||||||
|
ModAPI.meta.version("v0");
|
||||||
|
ModAPI.meta.description("testing custom entities");
|
||||||
|
ModAPI.meta.credits("By ZXMushroom63");
|
||||||
|
|
||||||
|
function registerEntity() {
|
||||||
|
// Utils
|
||||||
|
const ResourceLocation = ModAPI.reflect.getClassByName("ResourceLocation").constructors.find(x => x.length === 1);
|
||||||
|
const GlStateManager = Object.fromEntries(Object.values(ModAPI.reflect.getClassByName("GlStateManager").staticMethods).map(x => [x.methodNameShort, x.method]));
|
||||||
|
const IAnimals = ModAPI.reflect.getClassById("net.minecraft.entity.passive.IAnimals");
|
||||||
|
|
||||||
|
// START CUSTOM ENTITY
|
||||||
|
var entityClass = ModAPI.reflect.getClassById("net.minecraft.entity.Entity");
|
||||||
|
var entitySuper = ModAPI.reflect.getSuper(entityClass, (x) => x.length === 2);
|
||||||
|
var nme_EntityCube = function nme_EntityCube($worldIn) {
|
||||||
|
entitySuper(this, $worldIn);
|
||||||
|
this.$preventEntitySpawning = 1;
|
||||||
|
this.$setSize(1, 1);
|
||||||
|
}
|
||||||
|
ModAPI.reflect.prototypeStack(entityClass, nme_EntityCube);
|
||||||
|
|
||||||
|
//Turns out that minecraft 1.8's networking code is really stupid. Notch hardcoded every entity except for ones that implement the IAnimals interface.
|
||||||
|
//I don't know why, and I don't really care either. As long as it works (been working on this for too long, losing sanity)
|
||||||
|
ModAPI.reflect.implements(nme_EntityCube, IAnimals);
|
||||||
|
|
||||||
|
nme_EntityCube.prototype.$canTriggerWalking = function () { return 0 };
|
||||||
|
nme_EntityCube.prototype.$canBePushed = function () { return 1 };
|
||||||
|
nme_EntityCube.prototype.$getCollisionBox = function () { return this.$getEntityBoundingBox() };
|
||||||
|
nme_EntityCube.prototype.$getCollisionBoundingBox = function () { return this.$getEntityBoundingBox() };
|
||||||
|
nme_EntityCube.prototype.$readEntityFromNBT = function (nbtTagCompount) { // Needed, is an abstract method in parent class
|
||||||
|
nbtTagCompount = ModAPI.util.wrap(nbtTagCompount);
|
||||||
|
};
|
||||||
|
nme_EntityCube.prototype.$writeEntityToNBT = function (nbtTagCompount) { // Needed, is an abstract method in parent class
|
||||||
|
nbtTagCompount = ModAPI.util.wrap(nbtTagCompount);
|
||||||
|
};
|
||||||
|
nme_EntityCube.prototype.$entityInit = function () {
|
||||||
|
console.log("Cube entity created!");
|
||||||
|
};
|
||||||
|
// END CUSTOM ENTITY
|
||||||
|
|
||||||
|
|
||||||
|
// START CUSTOM MODEL
|
||||||
|
var ModelRenderer = ModAPI.reflect.getClassById("net.minecraft.client.model.ModelRenderer").constructors.find(x => x.length === 1);
|
||||||
|
var modelBaseClass = ModAPI.reflect.getClassById("net.minecraft.client.model.ModelBase");
|
||||||
|
var modelBaseSuper = ModAPI.reflect.getSuper(modelBaseClass); //while super isn't used when extending this class, java implies the call.
|
||||||
|
var nmcm_ModelCube = function nmcm_ModelCube() {
|
||||||
|
modelBaseSuper(this);
|
||||||
|
this.$textureWidth = 64;
|
||||||
|
this.$textureHeight = 64;
|
||||||
|
this.$cubeRenderer = ModelRenderer(this).$setTextureOffset(0, 0);
|
||||||
|
this.$cubeRenderer.$addBox0(0, 0, 0, 64, 64, 64);
|
||||||
|
this.$cubeRenderer.$setRotationPoint(0, 0, 0);
|
||||||
|
}
|
||||||
|
ModAPI.reflect.prototypeStack(modelBaseClass, nmcm_ModelCube);
|
||||||
|
nmcm_ModelCube.prototype.$render = function ($entity, useless1, useless2, partialTicks, useless3, useless4, degToRad) {
|
||||||
|
this.$cubeRenderer.$render(degToRad);
|
||||||
|
}
|
||||||
|
// END CUSTOM MODEL
|
||||||
|
|
||||||
|
|
||||||
|
// START CUSTOM RENDERER
|
||||||
|
var renderClass = ModAPI.reflect.getClassById("net.minecraft.client.renderer.entity.Render");
|
||||||
|
var renderSuper = ModAPI.reflect.getSuper(renderClass, (x) => x.length === 2);
|
||||||
|
const cubeTextures = ResourceLocation(ModAPI.util.str("textures/entity/cube.png"));
|
||||||
|
var nmcre_RenderCube = function nmcre_RenderCube(renderManager) {
|
||||||
|
renderSuper(this, renderManager);
|
||||||
|
this.$modelCube = new nmcm_ModelCube();
|
||||||
|
this.$shadowSize = 0.5;
|
||||||
|
}
|
||||||
|
ModAPI.reflect.prototypeStack(renderClass, nmcre_RenderCube);
|
||||||
|
nmcre_RenderCube.prototype.$getEntityTexture = function (entity) {
|
||||||
|
return cubeTextures;
|
||||||
|
}
|
||||||
|
const parentDoRender = nmcre_RenderCube.prototype.$doRender;
|
||||||
|
nmcre_RenderCube.prototype.$doRender = function (entity, x, y, z, yaw, pitch) {
|
||||||
|
GlStateManager.pushMatrix();
|
||||||
|
GlStateManager.translate(x + 0.5, y, z + 0.5);
|
||||||
|
GlStateManager.rotate(180 - yaw, 0, 1, 0);
|
||||||
|
GlStateManager.scale(0.25, 0.25, 0.25);
|
||||||
|
this.$bindEntityTexture(entity);
|
||||||
|
this.$modelCube.$render(entity, 0, 0, -0.1, 0, 0, 0.0625);
|
||||||
|
GlStateManager.popMatrix();
|
||||||
|
parentDoRender.apply(this, [entity, x, y, z, yaw, pitch]);
|
||||||
|
}
|
||||||
|
const ID = ModAPI.keygen.entity("cube");
|
||||||
|
ModAPI.reflect.getClassById("net.minecraft.entity.EntityList").staticMethods.addMapping0.method(
|
||||||
|
ModAPI.util.asClass(nme_EntityCube),
|
||||||
|
{
|
||||||
|
$createEntity: function ($worldIn) {
|
||||||
|
return new nme_EntityCube($worldIn);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ModAPI.util.str("Cube"),
|
||||||
|
ID,
|
||||||
|
0x000000, //egg base
|
||||||
|
0x00FF00 //egg spots
|
||||||
|
);
|
||||||
|
// Note that the spawn egg for this will not work, as spawn eggs only spawn entities that are a subclass of EntityLivingBase
|
||||||
|
console.log(ID);
|
||||||
|
|
||||||
|
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||||
|
AsyncSink.L10N.set("entity.Cube.name", "Cube (TM)");
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
EntityCube: nme_EntityCube,
|
||||||
|
ModelCube: nmcm_ModelCube,
|
||||||
|
RenderCube: nmcre_RenderCube,
|
||||||
|
cubeTexture: cubeTextures
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModAPI.dedicatedServer.appendCode(registerEntity);
|
||||||
|
var data = registerEntity();
|
||||||
|
|
||||||
|
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||||
|
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/entity/cube.png", await (await fetch(
|
||||||
|
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAAXNSR0IArs4c6QAAAQBJREFUeF7l0BFzAmAAgOGvKxgMgiAYDIJgEARBEASDQTAIgiAYBEEQBN0NBkEQBEEQBIMgCAZBEAwGgyAIgiAIgiConxE88PJ790RCCNdYCOGeRe/4j4SYDvCgAzzqAHEdIKEDJHWAJx3gWQdI6QBpHeBFB8joAFkdIKcD5HWAgg5Q1AFedYA3HaCkA7zrAGUdoKIDVHWAmg7woQPUdYCGDtDUAVo6QFsH6OgAnzrAlw7Q1QF6OkBfBxjoAEMdYKQDjHWAiQ7wrQNMdYCZDjDXAX50gIUOsNQBVjrArw7wpwP86wBrHWCjA2x1gJ0OsNcBDjrAUQc46QBnHeBiA9wALSueIjTE4PwAAAAASUVORK5CYII="
|
||||||
|
)).arrayBuffer());
|
||||||
|
AsyncSink.hideFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/entity/cube.png.mcmeta");
|
||||||
|
ModAPI.mc.renderManager.entityRenderMap.put(ModAPI.util.asClass(data.EntityCube), new data.RenderCube(ModAPI.mc.renderManager.getRef()));
|
||||||
|
ModAPI.promisify(ModAPI.mc.renderEngine.bindTexture)(data.cubeTexture).then(() => {
|
||||||
|
console.log("Loaded cube texture into cache.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
console.log(data);
|
||||||
|
window.temp1 = data;
|
||||||
|
})();
|
||||||
|
//var cube_man = new temp1.EntityCube(ModAPI.mc.theWorld.getRef());
|
||||||
|
//cube_man.$setPosition(-191, 74, 26);
|
||||||
|
//AsyncSink.startDebugging();
|
||||||
|
//AsyncSink.startDebuggingFS();
|
||||||
|
//ModAPI.mc.theWorld.spawnEntityInWorld(cube_man);
|
@ -5,6 +5,8 @@
|
|||||||
ModAPI.meta.icon(itemTexture);
|
ModAPI.meta.icon(itemTexture);
|
||||||
ModAPI.meta.description("Requires AsyncSink.");
|
ModAPI.meta.description("Requires AsyncSink.");
|
||||||
|
|
||||||
|
ModAPI.require("player");
|
||||||
|
|
||||||
function PistolItem() {
|
function PistolItem() {
|
||||||
var recoilSpeed = 0; //recoil controller
|
var recoilSpeed = 0; //recoil controller
|
||||||
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
ModAPI.meta.icon(itemTexture);
|
ModAPI.meta.icon(itemTexture);
|
||||||
ModAPI.meta.description("Requires AsyncSink.");
|
ModAPI.meta.description("Requires AsyncSink.");
|
||||||
|
|
||||||
|
ModAPI.require("player");
|
||||||
|
|
||||||
function PistolItem() {
|
function PistolItem() {
|
||||||
var recoilSpeed = 0; //recoil controller
|
var recoilSpeed = 0; //recoil controller
|
||||||
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
||||||
|
@ -87,7 +87,7 @@
|
|||||||
var block_of_unluckiness = UnluckyBlocks();
|
var block_of_unluckiness = UnluckyBlocks();
|
||||||
ModAPI.addEventListener("lib:asyncsink", async () => {
|
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||||
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
ModAPI.addEventListener("lib:asyncsink:registeritems", (renderItem)=>{
|
||||||
renderItem.registerItem(block_of_unluckiness, ModAPI.util.str("unluckiness"));
|
renderItem.registerBlock(block_of_unluckiness, ModAPI.util.str("unluckiness"));
|
||||||
});
|
});
|
||||||
AsyncSink.L10N.set("tile.unluckiness.name", "Unlucky Block");
|
AsyncSink.L10N.set("tile.unluckiness.name", "Unlucky Block");
|
||||||
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/unluckiness.json", JSON.stringify(
|
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/unluckiness.json", JSON.stringify(
|
||||||
|
@ -151,6 +151,7 @@
|
|||||||
ModAPI.hooks ||= {};
|
ModAPI.hooks ||= {};
|
||||||
ModAPI.hooks.freezeCallstack = false;
|
ModAPI.hooks.freezeCallstack = false;
|
||||||
ModAPI.hooks._rippedData ||= [];
|
ModAPI.hooks._rippedData ||= [];
|
||||||
|
ModAPI.hooks._rippedInterfaceMap ||= {};
|
||||||
ModAPI.hooks._teavm ||= {};
|
ModAPI.hooks._teavm ||= {};
|
||||||
ModAPI.hooks._rippedConstructors ||= {};
|
ModAPI.hooks._rippedConstructors ||= {};
|
||||||
ModAPI.hooks._rippedInternalConstructors ||= {};
|
ModAPI.hooks._rippedInternalConstructors ||= {};
|
||||||
|
11
injector.js
11
injector.js
@ -1,4 +1,4 @@
|
|||||||
globalThis.ModAPIVersion = "v2.6";
|
globalThis.ModAPIVersion = "v2.7";
|
||||||
globalThis.doEaglerforge = true;
|
globalThis.doEaglerforge = true;
|
||||||
document.querySelector("title").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
document.querySelector("title").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
||||||
document.querySelector("h1").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
document.querySelector("h1").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
||||||
@ -205,6 +205,7 @@ var main;(function(){`
|
|||||||
}).filter(x => {
|
}).filter(x => {
|
||||||
return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$"))
|
return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$"))
|
||||||
});
|
});
|
||||||
|
//Also stores classes from $rt_classWithoutFields(0)
|
||||||
patchedFile = patchedFile.replaceAll(
|
patchedFile = patchedFile.replaceAll(
|
||||||
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
|
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||||
function (match) {
|
function (match) {
|
||||||
@ -213,6 +214,7 @@ var main;(function(){`
|
|||||||
""
|
""
|
||||||
);
|
);
|
||||||
var entries = [];
|
var entries = [];
|
||||||
|
|
||||||
staticVariables.forEach((entry) => {
|
staticVariables.forEach((entry) => {
|
||||||
if (entry.startsWith(prefix)) {
|
if (entry.startsWith(prefix)) {
|
||||||
var variableName = entry
|
var variableName = entry
|
||||||
@ -229,8 +231,11 @@ var main;(function(){`
|
|||||||
});
|
});
|
||||||
|
|
||||||
var proxy = entriesToStaticVariableProxy(entries, prefix, clinitList);
|
var proxy = entriesToStaticVariableProxy(entries, prefix, clinitList);
|
||||||
|
var shortPrefix = prefix.replace(
|
||||||
return match + proxy;
|
"var ",
|
||||||
|
""
|
||||||
|
);
|
||||||
|
return match + `ModAPI.hooks._rippedInterfaceMap[\`${shortPrefix}\`]=${shortPrefix};` + proxy;
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
//Edge cases. sigh
|
//Edge cases. sigh
|
||||||
|
95
postinit.js
95
postinit.js
@ -166,6 +166,8 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModAPI.util.asClass = ModAPI.hooks._teavm.$rt_cls;
|
||||||
|
|
||||||
ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) {
|
ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) {
|
||||||
target ||= {};
|
target ||= {};
|
||||||
corrective ||= false;
|
corrective ||= false;
|
||||||
@ -187,9 +189,9 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
if (!disableFunctions && outputValue && typeof outputValue === "function" && target) {
|
if (!disableFunctions && outputValue && typeof outputValue === "function" && target) {
|
||||||
return function (...args) {
|
return function (...args) {
|
||||||
var xOut = outputValue.apply(target, args);
|
var xOut = outputValue.apply(target, args);
|
||||||
if (xOut && typeof xOut === "object" && Array.isArray(xOut.data) && typeof outputValue.type === "function") {
|
if (xOut && typeof xOut === "object" && Array.isArray(xOut.data) && typeof xOut.type === "function") {
|
||||||
if (corrective) {
|
if (corrective) {
|
||||||
return new Proxy(outputValue.data, CorrectiveArray);
|
return new Proxy(xOut.data, CorrectiveArray);
|
||||||
}
|
}
|
||||||
return new Proxy(xOut.data, ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf);
|
return new Proxy(xOut.data, ModAPI.util.TeaVMArray_To_Recursive_BaseData_ProxyConf);
|
||||||
}
|
}
|
||||||
@ -267,6 +269,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
|
ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
|
||||||
ModAPI.hooks._rippedInternalConstructorKeys = Object.keys(ModAPI.hooks._rippedInternalConstructors);
|
ModAPI.hooks._rippedInternalConstructorKeys = Object.keys(ModAPI.hooks._rippedInternalConstructors);
|
||||||
ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
|
ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
|
||||||
|
ModAPI.hooks._rippedInterfaceKeys = Object.keys(ModAPI.hooks._rippedInterfaceMap);
|
||||||
|
|
||||||
var compiledNames = new Set();
|
var compiledNames = new Set();
|
||||||
var metaMap = {};
|
var metaMap = {};
|
||||||
@ -300,10 +303,19 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ModAPI.hooks._rippedInterfaceKeys.forEach(className => {
|
||||||
|
if (typeof className === "string" && className.length > 0) {
|
||||||
|
//Interfaces using $rt_classWithoutFields(0) and no constructors.
|
||||||
|
if (className && className.includes("_")) {
|
||||||
|
compiledNames.add(className);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
//Initialise all compiled names into the class map
|
//Initialise all compiled names into the class map
|
||||||
compiledNames.forEach(compiledName => {
|
compiledNames.forEach(compiledName => {
|
||||||
var item = metaMap[compiledName];
|
var item = metaMap[compiledName] || ModAPI.hooks._rippedInterfaceMap[compiledName];
|
||||||
var classId = item?.$meta?.name || null;
|
var classId = item?.$meta?.name || null;
|
||||||
|
|
||||||
if (!ModAPI.hooks._classMap[compiledName]) {
|
if (!ModAPI.hooks._classMap[compiledName]) {
|
||||||
@ -319,7 +331,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
"staticVariables": {},
|
"staticVariables": {},
|
||||||
"staticVariableNames": [],
|
"staticVariableNames": [],
|
||||||
"class": item || null,
|
"class": item || null,
|
||||||
"hasMeta": !!item,
|
"hasMeta": !!(item?.$meta),
|
||||||
"instanceOf": function (object) {
|
"instanceOf": function (object) {
|
||||||
try {
|
try {
|
||||||
return ModAPI.hooks._teavm.$rt_isInstance(object, item || null);
|
return ModAPI.hooks._teavm.$rt_isInstance(object, item || null);
|
||||||
@ -341,15 +353,14 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
return this.constructors[i];
|
return this.constructors[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) {
|
if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) {
|
||||||
ModAPI.hooks._classMap[compiledName].superclassName = item.$meta.superclass.$meta.name;
|
ModAPI.hooks._classMap[compiledName].superclassRaw = item.$meta.superclass;
|
||||||
ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass;
|
|
||||||
} else {
|
} else {
|
||||||
ModAPI.hooks._classMap[compiledName].superclass = null;
|
ModAPI.hooks._classMap[compiledName].superclassRaw = null;
|
||||||
ModAPI.hooks._classMap[compiledName].superclassName = null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item?.["$$constructor$$"]) {
|
if (item?.["$$constructor$$"]) {
|
||||||
@ -385,9 +396,14 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
|
|
||||||
//Prototype Injection, allows for far easier access to methods
|
//Prototype Injection, allows for far easier access to methods
|
||||||
if (typeof item === "function" && ModAPI.hooks._rippedMethodTypeMap[method] === "instance") {
|
if (typeof item === "function" && ModAPI.hooks._rippedMethodTypeMap[method] === "instance") {
|
||||||
item.prototype["$" + method.replace(compiledName + "_", "")] ||= function (...args) {
|
var prototypeInjectedMethod = function prototypeInjectedMethod(...args) {
|
||||||
return ModAPI.hooks.methods[method].apply(this, [this, ...args]);
|
return ModAPI.hooks.methods[method].apply(this, [this, ...args]);
|
||||||
}
|
}
|
||||||
|
if ((item.prototype["$" + method.replace(compiledName + "_", "")]?.name ?? "prototypeInjectedMethod") === "prototypeInjectedMethod") {
|
||||||
|
item.prototype["$" + method.replace(compiledName + "_", "")] = prototypeInjectedMethod;
|
||||||
|
} else {
|
||||||
|
item.prototype["$" + method.replace(compiledName + "_", "")] ||= prototypeInjectedMethod;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -396,7 +412,19 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
}));
|
}));
|
||||||
ModAPI.hooks._classMap[compiledName].staticVariableNames = Object.keys(ModAPI.hooks._classMap[compiledName].staticVariables);
|
ModAPI.hooks._classMap[compiledName].staticVariableNames = Object.keys(ModAPI.hooks._classMap[compiledName].staticVariables);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
//populate superclasses
|
||||||
|
compiledNames.forEach(compiledName => {
|
||||||
|
var item = ModAPI.hooks._classMap[compiledName];
|
||||||
|
if (item.superclassRaw) {
|
||||||
|
item.superclass = ModAPI.hooks._classMap[item.superclassRaw.name];
|
||||||
|
} else {
|
||||||
|
item.superclass = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
ModAPI.reflect.classes = Object.values(ModAPI.hooks._classMap);
|
ModAPI.reflect.classes = Object.values(ModAPI.hooks._classMap);
|
||||||
|
ModAPI.reflect.classMap = ModAPI.hooks._classMap;
|
||||||
console.log("[ModAPI] Regenerated hook classmap.");
|
console.log("[ModAPI] Regenerated hook classmap.");
|
||||||
}
|
}
|
||||||
ModAPI.hooks.regenerateClassMap();
|
ModAPI.hooks.regenerateClassMap();
|
||||||
@ -411,8 +439,14 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
|
|
||||||
//Magical function for making a subclass with a custom constructor that you can easily use super(...) on.
|
//Magical function for making a subclass with a custom constructor that you can easily use super(...) on.
|
||||||
ModAPI.reflect.getSuper = function getSuper(reflectClass, filter) {
|
ModAPI.reflect.getSuper = function getSuper(reflectClass, filter) {
|
||||||
filter ||= () => true;
|
filter ||= (x) => x.length === 1;
|
||||||
|
while (!reflectClass.internalConstructors.find(filter) && reflectClass.superclass) {
|
||||||
|
reflectClass = reflectClass.superclass;
|
||||||
|
}
|
||||||
var initialiser = reflectClass.internalConstructors.find(filter);
|
var initialiser = reflectClass.internalConstructors.find(filter);
|
||||||
|
if (!initialiser) {
|
||||||
|
throw new Error("[ModAPI] Failed to find matching superclass constructor in tree.");
|
||||||
|
}
|
||||||
return function superFunction(thisArg, ...extra_args) {
|
return function superFunction(thisArg, ...extra_args) {
|
||||||
reflectClass.class.call(thisArg);
|
reflectClass.class.call(thisArg);
|
||||||
initialiser(thisArg, ...extra_args);
|
initialiser(thisArg, ...extra_args);
|
||||||
@ -427,18 +461,27 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
item: null,
|
item: null,
|
||||||
supertypes: [reflectClass.class]
|
supertypes: [reflectClass.class]
|
||||||
};
|
};
|
||||||
|
classFn.classObject = null;
|
||||||
|
}
|
||||||
|
ModAPI.reflect.implements = function impl(classFn, reflectClass) {
|
||||||
|
classFn.$meta ||= {};
|
||||||
|
classFn.$meta.supertypes ||= [];
|
||||||
|
if (reflectClass && reflectClass.class) {
|
||||||
|
classFn.$meta.supertypes.push(reflectClass.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var reloadDeprecationWarnings = 0;
|
var reloadDeprecationWarnings = 0;
|
||||||
const TeaVMArray_To_Recursive_BaseData_ProxyConf = {
|
const TeaVMArray_To_Recursive_BaseData_ProxyConf = {
|
||||||
get(target, prop, receiver) {
|
get(target, prop, receiver) {
|
||||||
|
var corrective = !!this._corrective;
|
||||||
if (prop === "getRef") {
|
if (prop === "getRef") {
|
||||||
return function () {
|
return function () {
|
||||||
return target;
|
return target;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var outputValue = Reflect.get(target, prop, receiver);
|
var outputValue = Reflect.get(target, prop, receiver);
|
||||||
var wrapped = ModAPI.util.wrap(outputValue, target, this._corrective, true);
|
var wrapped = ModAPI.util.wrap(outputValue, target, corrective, true);
|
||||||
if (wrapped) {
|
if (wrapped) {
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
@ -460,6 +503,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
return ("$" + prop) in target;
|
return ("$" + prop) in target;
|
||||||
},
|
},
|
||||||
get(target, prop, receiver) {
|
get(target, prop, receiver) {
|
||||||
|
var corrective = !!this._corrective;
|
||||||
if (prop === "getCorrective") {
|
if (prop === "getCorrective") {
|
||||||
return function () {
|
return function () {
|
||||||
return new Proxy(target, patchProxyConfToCorrective(TeaVM_to_Recursive_BaseData_ProxyConf));
|
return new Proxy(target, patchProxyConfToCorrective(TeaVM_to_Recursive_BaseData_ProxyConf));
|
||||||
@ -467,7 +511,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
}
|
}
|
||||||
if (prop === "isCorrective") {
|
if (prop === "isCorrective") {
|
||||||
return function () {
|
return function () {
|
||||||
return !!this._corrective;
|
return corrective;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prop === "getRef") {
|
if (prop === "getRef") {
|
||||||
@ -484,22 +528,26 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (prop === "isModProxy") {
|
if (prop === "isModProxy") {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
var outProp = "$" + prop;
|
var outProp = "$" + prop;
|
||||||
if (this._corrective) {
|
if (corrective) {
|
||||||
outProp = ModAPI.util.getNearestProperty(target, outProp);
|
outProp = ModAPI.util.getNearestProperty(target, outProp);
|
||||||
}
|
}
|
||||||
var outputValue = Reflect.get(target, outProp, receiver);
|
var outputValue = Reflect.get(target, outProp, receiver);
|
||||||
var wrapped = ModAPI.util.wrap(outputValue, target, this._corrective, false);
|
var wrapped = ModAPI.util.wrap(outputValue, target, corrective, false);
|
||||||
if (wrapped) {
|
if (wrapped) {
|
||||||
return wrapped;
|
return wrapped;
|
||||||
}
|
}
|
||||||
return outputValue;
|
return outputValue;
|
||||||
},
|
},
|
||||||
set(object, prop, value) {
|
set(object, prop, value) {
|
||||||
|
var corrective = !!this._corrective;
|
||||||
var outProp = "$" + prop;
|
var outProp = "$" + prop;
|
||||||
|
if (corrective) {
|
||||||
|
outProp = ModAPI.util.getNearestProperty(object, outProp);
|
||||||
|
}
|
||||||
object[outProp] = value;
|
object[outProp] = value;
|
||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
@ -1019,9 +1067,9 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
ModAPI.util.getBlockFromItem = easyStaticMethod("net.minecraft.block.Block", "getBlockFromItem", true);
|
ModAPI.util.getBlockFromItem = easyStaticMethod("net.minecraft.block.Block", "getBlockFromItem", true);
|
||||||
ModAPI.util.getIdFromBlock = easyStaticMethod("net.minecraft.block.Block", "getIdFromBlock", true);
|
ModAPI.util.getIdFromBlock = easyStaticMethod("net.minecraft.block.Block", "getIdFromBlock", true);
|
||||||
|
|
||||||
function qhash(txt, arr) {
|
function qhash(txt, arr, interval) {
|
||||||
var interval = 4095; //used to be 4095 - arr.length, but that increases incompatibility based on load order and otehr circumstances
|
// var interval = 4095; //used to be 4095 - arr.length, but that increases incompatibility based on load order and other circumstances
|
||||||
if (arr.length >= 4095) {
|
if (arr.length >= interval) {
|
||||||
console.error("[ModAPI.keygen] Ran out of IDs while generating for " + txt);
|
console.error("[ModAPI.keygen] Ran out of IDs while generating for " + txt);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -1049,10 +1097,15 @@ globalThis.modapi_postinit = "(" + (() => {
|
|||||||
}
|
}
|
||||||
ModAPI.keygen.item = function (item) {
|
ModAPI.keygen.item = function (item) {
|
||||||
var values = [...ModAPI.reflect.getClassById("net.minecraft.item.Item").staticVariables.itemRegistry.$modapi_specmap.values()];
|
var values = [...ModAPI.reflect.getClassById("net.minecraft.item.Item").staticVariables.itemRegistry.$modapi_specmap.values()];
|
||||||
return qhash(item, values);
|
return qhash(item, values, 4095);
|
||||||
}
|
}
|
||||||
ModAPI.keygen.block = function (block) {
|
ModAPI.keygen.block = function (block) {
|
||||||
var values = [...ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry.$modapi_specmap.values()];
|
var values = [...ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry.$modapi_specmap.values()];
|
||||||
return qhash(block, values);
|
return qhash(block, values, 4095);
|
||||||
|
}
|
||||||
|
ModAPI.keygen.entity = function (entity) {
|
||||||
|
var hashMap = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.entity.EntityList").staticVariables.idToClassMapping).getCorrective();
|
||||||
|
var values = hashMap.keys.getRef().data.filter(x=>hashMap.get(x));
|
||||||
|
return qhash(entity, values, 127);
|
||||||
}
|
}
|
||||||
}).toString() + ")();";
|
}).toString() + ")();";
|
||||||
|
Loading…
x
Reference in New Issue
Block a user