mirror of
https://github.com/eaglerforge/EaglerForgeInjector
synced 2025-07-25 07:01:20 -09:00
commit
2618cefdc4
@ -1,5 +1,5 @@
|
||||
# EaglerForgeInjector
|
||||
An advanced modding API injector for vanilla eaglercraft builds.
|
||||
An advanced modding API injector for unminified, unobfuscated, unsigned eaglercraft builds.
|
||||
Current features:
|
||||
- Method hooking/monkey patching
|
||||
- Reflection
|
||||
@ -13,5 +13,11 @@ Go to https://eaglerforge.github.io/EaglerForgeInjector/ and upload an unminifie
|
||||
#### 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.
|
||||
|
||||
#### 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
|
||||
[https://discord.gg/rbxN7kby5W](https://discord.gg/rbxN7kby5W)
|
||||
|
@ -1,8 +1,10 @@
|
||||
## 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:
|
||||
- `ModAPI.keygen.item(itemId: String) : number`
|
||||
- Example usage is: `var id = ModAPI.keygen.item("my_example_item");`
|
||||
- `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[]`
|
||||
- `ModAPI.reflect.classes` is an array of ReflectClasses, representing (almost) every java class.
|
||||
- `classMap: Map<String, ReflectClass>` is a map of every class.
|
||||
|
||||
Methods:
|
||||
|
||||
@ -16,12 +17,17 @@ Methods:
|
||||
- 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")`
|
||||
- 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`.
|
||||
- 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`
|
||||
- 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)
|
||||
- `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
|
||||
|
||||
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.
|
||||
- `staticVariables: Map<String, *>`
|
||||
- key-value dictionary of all the static variables in a class.
|
||||
- `superclass: Class?`
|
||||
- The raw teavm class of 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`
|
||||
- `superclass: ReflectClass?`
|
||||
- The superclass.
|
||||
|
||||
Each `ReflectClass` has the following methods:
|
||||
|
||||
|
@ -81,4 +81,7 @@ Methods:
|
||||
- `ModAPI.util.getBlockById(id: number) : Block`
|
||||
- Gets a block by it's ID
|
||||
- `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:registeritems", (renderItem)=>{
|
||||
//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
|
||||
|
||||
|
@ -4,6 +4,7 @@ const asyncSinkIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAY
|
||||
ModAPI.meta.icon(asyncSinkIcon);
|
||||
ModAPI.meta.credits("By ZXMushroom63");
|
||||
(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
|
||||
async function runtimeComponent() {
|
||||
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.FSOverride = new Set();
|
||||
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) {
|
||||
if (typeof data === "string") {
|
||||
data = encoder.encode(data).buffer;
|
||||
@ -58,6 +70,12 @@ ModAPI.meta.credits("By ZXMushroom63");
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncSink.hideFile = function hideFile(path) {
|
||||
AsyncSink.FSOverride.add(path);
|
||||
AsyncSink.FS.delete(path);
|
||||
return true;
|
||||
}
|
||||
|
||||
AsyncSink.getFile = function getFile(path) {
|
||||
return AsyncSink.FS.get(path) || new ArrayBuffer(0);
|
||||
}
|
||||
@ -160,6 +178,16 @@ ModAPI.meta.credits("By ZXMushroom63");
|
||||
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 originalL10NCheck = ModAPI.hooks.methods[L10NCheck];
|
||||
ModAPI.hooks.methods[L10NCheck] = function (...args) {
|
||||
@ -203,7 +231,7 @@ ModAPI.meta.credits("By ZXMushroom63");
|
||||
} else {
|
||||
resourcePackList.resourcePacks.push(pack);
|
||||
}
|
||||
|
||||
|
||||
const writeableTransaction = db.transaction(["filesystem"], "readwrite");
|
||||
const writeableObjectStore = writeableTransaction.objectStore("filesystem");
|
||||
await promisifyIDBRequest(writeableObjectStore.put({
|
||||
@ -255,8 +283,9 @@ ModAPI.meta.credits("By ZXMushroom63");
|
||||
if (e.message.toLowerCase().startsWith(".reload_tex")) {
|
||||
e.preventDefault = true;
|
||||
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("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]));
|
||||
}
|
||||
|
||||
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", () => {
|
||||
console.log("Registered my cool custom item.");
|
||||
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: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
|
||||
|
||||
|
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);
|
||||
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||
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.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: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.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.description("Requires AsyncSink.");
|
||||
|
||||
ModAPI.require("player");
|
||||
|
||||
function PistolItem() {
|
||||
var recoilSpeed = 0; //recoil controller
|
||||
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
||||
|
@ -5,6 +5,8 @@
|
||||
ModAPI.meta.icon(itemTexture);
|
||||
ModAPI.meta.description("Requires AsyncSink.");
|
||||
|
||||
ModAPI.require("player");
|
||||
|
||||
function PistolItem() {
|
||||
var recoilSpeed = 0; //recoil controller
|
||||
var DamageSourceClass = ModAPI.reflect.getClassByName("DamageSource");
|
||||
|
@ -87,7 +87,7 @@
|
||||
var block_of_unluckiness = UnluckyBlocks();
|
||||
ModAPI.addEventListener("lib:asyncsink", async () => {
|
||||
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.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/unluckiness.json", JSON.stringify(
|
||||
|
@ -151,6 +151,7 @@
|
||||
ModAPI.hooks ||= {};
|
||||
ModAPI.hooks.freezeCallstack = false;
|
||||
ModAPI.hooks._rippedData ||= [];
|
||||
ModAPI.hooks._rippedInterfaceMap ||= {};
|
||||
ModAPI.hooks._teavm ||= {};
|
||||
ModAPI.hooks._rippedConstructors ||= {};
|
||||
ModAPI.hooks._rippedInternalConstructors ||= {};
|
||||
|
37
injector.js
37
injector.js
@ -1,4 +1,4 @@
|
||||
globalThis.ModAPIVersion = "v2.6";
|
||||
globalThis.ModAPIVersion = "v2.7";
|
||||
globalThis.doEaglerforge = true;
|
||||
document.querySelector("title").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
||||
document.querySelector("h1").innerText = `EaglerForge Injector ${ModAPIVersion}`;
|
||||
@ -50,13 +50,13 @@ function entriesToStaticVariableProxy(entries, prefix, clinitList) {
|
||||
.join(",")}];
|
||||
/*/
|
||||
var proxy = `ModAPI.hooks._rippedStaticProperties[\`${prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
)}\`] = new Proxy({${entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(":null,") + (entries.length > 0 ? ":null" : "")
|
||||
"var ",
|
||||
""
|
||||
)}\`] = new Proxy({${entries
|
||||
.flatMap((x) => {
|
||||
return '"' + x.name + '"';
|
||||
})
|
||||
.join(":null,") + (entries.length > 0 ? ":null" : "")
|
||||
}}, {
|
||||
get: function (a,b,c) {
|
||||
switch (b) {
|
||||
@ -136,7 +136,7 @@ var main;(function(){`
|
||||
patchedFile = patchedFile.replaceAll("function TeaVMThread(", "globalThis.ModAPI.hooks.TeaVMThread = TeaVMThread;\nfunction TeaVMThread(");
|
||||
|
||||
_status("Getting clinit list...");
|
||||
var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x=>x[0].replaceAll("function ", "").replaceAll("(", "").trim());
|
||||
var clinitList = [...patchedFile.matchAll(/^[\t ]*function \S+?_\S+?_\$callClinit\(/gm)].map(x => x[0].replaceAll("function ", "").replaceAll("(", "").trim());
|
||||
console.log(clinitList);
|
||||
|
||||
_status("Extracting constructors and methods...");
|
||||
@ -171,7 +171,7 @@ var main;(function(){`
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
const extractInstanceMethodRegex =
|
||||
/^[\t ]*function \S+?_\S+?_\S+?\((\$this)?/gm; // /^[\t ]*function \S+?_\S+?_\S+?\(\$this/gm
|
||||
const extractInstanceMethodFullNameRegex = /function (\S*?)\(/gm; // /function (\S*?)\(\$this/gm
|
||||
@ -205,6 +205,7 @@ var main;(function(){`
|
||||
}).filter(x => {
|
||||
return (!x.includes("$_clinit_$")) && (!x.includes("$lambda$"))
|
||||
});
|
||||
//Also stores classes from $rt_classWithoutFields(0)
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/var \S+?_\S+? = \$rt_classWithoutFields\(\S*?\);/gm,
|
||||
function (match) {
|
||||
@ -213,6 +214,7 @@ var main;(function(){`
|
||||
""
|
||||
);
|
||||
var entries = [];
|
||||
|
||||
staticVariables.forEach((entry) => {
|
||||
if (entry.startsWith(prefix)) {
|
||||
var variableName = entry
|
||||
@ -229,14 +231,17 @@ var main;(function(){`
|
||||
});
|
||||
|
||||
var proxy = entriesToStaticVariableProxy(entries, prefix, clinitList);
|
||||
|
||||
return match + proxy;
|
||||
var shortPrefix = prefix.replace(
|
||||
"var ",
|
||||
""
|
||||
);
|
||||
return match + `ModAPI.hooks._rippedInterfaceMap[\`${shortPrefix}\`]=${shortPrefix};` + proxy;
|
||||
}
|
||||
);
|
||||
//Edge cases. sigh
|
||||
//Done: add support for static properties on classes with constructors like this: function nmcg_GuiMainMenu() {
|
||||
|
||||
|
||||
|
||||
patchedFile = patchedFile.replaceAll(
|
||||
/function [a-z]+?_([a-zA-Z0-9\$]+?)\(\) \{/gm,
|
||||
(match) => {
|
||||
@ -335,7 +340,7 @@ document.querySelector("#giveme").addEventListener("click", () => {
|
||||
} else if (globalThis.doShronk) {
|
||||
patchedFile = await shronk(patchedFile);
|
||||
}
|
||||
|
||||
|
||||
patchedFile.replace(`{"._|_libserverside_|_."}`, "");
|
||||
var blob = new Blob([patchedFile], { type: file.type });
|
||||
saveAs(blob, "processed." + fileType);
|
||||
@ -356,13 +361,13 @@ document.querySelector("#givemeserver").addEventListener("click", () => {
|
||||
|
||||
file.text().then(async (string) => {
|
||||
var patchedFile = string;
|
||||
|
||||
|
||||
if (globalThis.doEaglerforge) {
|
||||
patchedFile = await processClasses(patchedFile);
|
||||
} else if (globalThis.doShronk) {
|
||||
patchedFile = await shronk(patchedFile);
|
||||
}
|
||||
|
||||
|
||||
patchedFile.replace(`{"._|_libserverside_|_."}`, `(${EFServer.toString()})()`);
|
||||
var blob = new Blob([patchedFile], { type: file.type });
|
||||
saveAs(blob, "efserver." + fileType);
|
||||
|
95
postinit.js
95
postinit.js
@ -166,6 +166,8 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
return name;
|
||||
}
|
||||
|
||||
ModAPI.util.asClass = ModAPI.hooks._teavm.$rt_cls;
|
||||
|
||||
ModAPI.util.wrap = function (outputValue, target, corrective, disableFunctions) {
|
||||
target ||= {};
|
||||
corrective ||= false;
|
||||
@ -187,9 +189,9 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
if (!disableFunctions && outputValue && typeof outputValue === "function" && target) {
|
||||
return function (...args) {
|
||||
var xOut = outputValue.apply(target, args);
|
||||
if (xOut && typeof xOut === "object" && Array.isArray(xOut.data) && typeof outputValue.type === "function") {
|
||||
if (xOut && typeof xOut === "object" && Array.isArray(xOut.data) && typeof xOut.type === "function") {
|
||||
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);
|
||||
}
|
||||
@ -267,6 +269,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
ModAPI.hooks._rippedConstructorKeys = Object.keys(ModAPI.hooks._rippedConstructors);
|
||||
ModAPI.hooks._rippedInternalConstructorKeys = Object.keys(ModAPI.hooks._rippedInternalConstructors);
|
||||
ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
|
||||
ModAPI.hooks._rippedInterfaceKeys = Object.keys(ModAPI.hooks._rippedInterfaceMap);
|
||||
|
||||
var compiledNames = new Set();
|
||||
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
|
||||
compiledNames.forEach(compiledName => {
|
||||
var item = metaMap[compiledName];
|
||||
var item = metaMap[compiledName] || ModAPI.hooks._rippedInterfaceMap[compiledName];
|
||||
var classId = item?.$meta?.name || null;
|
||||
|
||||
if (!ModAPI.hooks._classMap[compiledName]) {
|
||||
@ -319,7 +331,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
"staticVariables": {},
|
||||
"staticVariableNames": [],
|
||||
"class": item || null,
|
||||
"hasMeta": !!item,
|
||||
"hasMeta": !!(item?.$meta),
|
||||
"instanceOf": function (object) {
|
||||
try {
|
||||
return ModAPI.hooks._teavm.$rt_isInstance(object, item || null);
|
||||
@ -341,15 +353,14 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
return this.constructors[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) {
|
||||
ModAPI.hooks._classMap[compiledName].superclassName = item.$meta.superclass.$meta.name;
|
||||
ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass;
|
||||
ModAPI.hooks._classMap[compiledName].superclassRaw = item.$meta.superclass;
|
||||
} else {
|
||||
ModAPI.hooks._classMap[compiledName].superclass = null;
|
||||
ModAPI.hooks._classMap[compiledName].superclassName = null;
|
||||
ModAPI.hooks._classMap[compiledName].superclassRaw = null;
|
||||
}
|
||||
|
||||
if (item?.["$$constructor$$"]) {
|
||||
@ -385,9 +396,14 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
|
||||
//Prototype Injection, allows for far easier access to methods
|
||||
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]);
|
||||
}
|
||||
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);
|
||||
});
|
||||
|
||||
//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.classMap = ModAPI.hooks._classMap;
|
||||
console.log("[ModAPI] Regenerated hook classmap.");
|
||||
}
|
||||
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.
|
||||
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);
|
||||
if (!initialiser) {
|
||||
throw new Error("[ModAPI] Failed to find matching superclass constructor in tree.");
|
||||
}
|
||||
return function superFunction(thisArg, ...extra_args) {
|
||||
reflectClass.class.call(thisArg);
|
||||
initialiser(thisArg, ...extra_args);
|
||||
@ -427,18 +461,27 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
item: null,
|
||||
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;
|
||||
const TeaVMArray_To_Recursive_BaseData_ProxyConf = {
|
||||
get(target, prop, receiver) {
|
||||
var corrective = !!this._corrective;
|
||||
if (prop === "getRef") {
|
||||
return function () {
|
||||
return target;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
return wrapped;
|
||||
}
|
||||
@ -460,6 +503,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
return ("$" + prop) in target;
|
||||
},
|
||||
get(target, prop, receiver) {
|
||||
var corrective = !!this._corrective;
|
||||
if (prop === "getCorrective") {
|
||||
return function () {
|
||||
return new Proxy(target, patchProxyConfToCorrective(TeaVM_to_Recursive_BaseData_ProxyConf));
|
||||
@ -467,7 +511,7 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
}
|
||||
if (prop === "isCorrective") {
|
||||
return function () {
|
||||
return !!this._corrective;
|
||||
return corrective;
|
||||
}
|
||||
}
|
||||
if (prop === "getRef") {
|
||||
@ -484,22 +528,26 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
}
|
||||
}
|
||||
if (prop === "isModProxy") {
|
||||
return true
|
||||
return true;
|
||||
}
|
||||
|
||||
var outProp = "$" + prop;
|
||||
if (this._corrective) {
|
||||
if (corrective) {
|
||||
outProp = ModAPI.util.getNearestProperty(target, outProp);
|
||||
}
|
||||
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) {
|
||||
return wrapped;
|
||||
}
|
||||
return outputValue;
|
||||
},
|
||||
set(object, prop, value) {
|
||||
var corrective = !!this._corrective;
|
||||
var outProp = "$" + prop;
|
||||
if (corrective) {
|
||||
outProp = ModAPI.util.getNearestProperty(object, outProp);
|
||||
}
|
||||
object[outProp] = value;
|
||||
return true;
|
||||
},
|
||||
@ -1019,9 +1067,9 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
ModAPI.util.getBlockFromItem = easyStaticMethod("net.minecraft.block.Block", "getBlockFromItem", true);
|
||||
ModAPI.util.getIdFromBlock = easyStaticMethod("net.minecraft.block.Block", "getIdFromBlock", true);
|
||||
|
||||
function qhash(txt, arr) {
|
||||
var interval = 4095; //used to be 4095 - arr.length, but that increases incompatibility based on load order and otehr circumstances
|
||||
if (arr.length >= 4095) {
|
||||
function qhash(txt, arr, interval) {
|
||||
// var interval = 4095; //used to be 4095 - arr.length, but that increases incompatibility based on load order and other circumstances
|
||||
if (arr.length >= interval) {
|
||||
console.error("[ModAPI.keygen] Ran out of IDs while generating for " + txt);
|
||||
return -1;
|
||||
}
|
||||
@ -1049,10 +1097,15 @@ globalThis.modapi_postinit = "(" + (() => {
|
||||
}
|
||||
ModAPI.keygen.item = function (item) {
|
||||
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) {
|
||||
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() + ")();";
|
||||
|
Loading…
x
Reference in New Issue
Block a user