Merge pull request #32 from eaglerforge/main

ModAPI v2.2
This commit is contained in:
ZXMushroom63 2024-11-05 18:16:12 +08:00 committed by GitHub
commit a07c3207cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
14 changed files with 587 additions and 33 deletions

View File

@ -49,6 +49,10 @@ Can only be used in the context of the dedicated server. More: [DedicatedServerD
- `serverstart`: - `serverstart`:
- Called when the dedicated server starts. - Called when the dedicated server starts.
- Event object is blank. - Event object is blank.
- `bootstrap`:
- Called when the dedicated server registers blocks, items, materials, enchantments, etc.
- This is when you should register cstom blocks and items.
- Event object is blank.
- `serverstop`: - `serverstop`:
- Called when the dedicated server stops. - Called when the dedicated server stops.
- Event object is blank. - Event object is blank.

View File

@ -16,7 +16,12 @@ 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`
- 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
- `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.
- [Example usage](https://github.com/eaglerforge/EaglerForgeInjector/blob/6e8598c180f96a65c0c101be72e6d0fa53195404/examplemods/unlucky_blocks.js#L37)
### ReflectClass Definition ### ReflectClass Definition
Each `ReflectClass` has the following properties: Each `ReflectClass` has the following properties:
@ -44,7 +49,9 @@ 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: String?` - `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` - The class id of the class's superclass. Eg: `net.minecraft.client.entity.AbstractClientPlayer`
- Will be `null` if `hasMeta` is equal to `false` - Will be `null` if `hasMeta` is equal to `false`

View File

@ -37,6 +37,8 @@ Methods:
- `ModAPI.util.isCritical() : boolean` - `ModAPI.util.isCritical() : boolean`
- Checks wether the thread is in a critical state. - Checks wether the thread is in a critical state.
- When patching methods, it is good practice to allow the method to resume as usual if this is `true`, to avoid stack implosions. (yes, those are real) - When patching methods, it is good practice to allow the method to resume as usual if this is `true`, to avoid stack implosions. (yes, those are real)
- `ModAPI.util.bootstrap() : void`
- Regenerate proxies for ModAPI.items, .blocks, .materials, .enchantments
- `ModAPI.util.createArray(class, jsArray) : Object[]` - `ModAPI.util.createArray(class, jsArray) : Object[]`
- Makes a java array from a class and a javascript array. - Makes a java array from a class and a javascript array.
- The class parameter can be retrieved via reflect: `ModAPI.reflect.getClassById("net.minecraft.util.BlockPos").class` - The class parameter can be retrieved via reflect: `ModAPI.reflect.getClassById("net.minecraft.util.BlockPos").class`

View File

@ -0,0 +1 @@
# Coming Soon

View File

@ -1,10 +1,11 @@
ModAPI.meta.title("AsyncSink"); ModAPI.meta.title("AsyncSink");
ModAPI.meta.description("Library for patching and hooking into asynchronous filesystem requests for EaglercraftX."); ModAPI.meta.description("Library for patching and hooking into asynchronous filesystem requests for EaglercraftX.");
ModAPI.meta.icon("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAL9JREFUOE9jZGBg+M9ABcAIMsgtPo3hzZ2zYONEVIxJZu9aOIsBbJCRtTHcEJAgLgBSh82ic0fPIgyCKQAJXrx4EcUsfX19sBiIRrYU5gu4Qchew2cQyHSQYehBgdNruFwEcybMZci+gIcRIa+hhxu6LzBiDZvX0A1BDyuivYbLIJK8pqevjze5GlsbMxAdayCT/PQwDRS2gaQror2m36KH4SqjZybwxEl0gsQWRkM01ogpVQh6jaJihBgXEFIDAAIQ9AFDJlrxAAAAAElFTkSuQmCC"); const asyncSinkIcon = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAL9JREFUOE9jZGBg+M9ABcAIMsgtPo3hzZ2zYONEVIxJZu9aOIsBbJCRtTHcEJAgLgBSh82ic0fPIgyCKQAJXrx4EcUsfX19sBiIRrYU5gu4Qchew2cQyHSQYehBgdNruFwEcybMZci+gIcRIa+hhxu6LzBiDZvX0A1BDyuivYbLIJK8pqevjze5GlsbMxAdayCT/PQwDRS2gaQror2m36KH4SqjZybwxEl0gsQWRkM01ogpVQh6jaJihBgXEFIDAAIQ9AFDJlrxAAAAAElFTkSuQmCC";
ModAPI.meta.icon(asyncSinkIcon);
ModAPI.meta.credits("By ZXMushroom63"); ModAPI.meta.credits("By ZXMushroom63");
(function AsyncSinkFn() { (function AsyncSinkFn() {
//AsyncSink is a plugin to debug and override asynchronous methods in EaglercraftX //AsyncSink is a plugin to debug and override asynchronous methods in EaglercraftX
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);
const wrap = ModAPI.hooks.methods.otji_JSWrapper_wrap; const wrap = ModAPI.hooks.methods.otji_JSWrapper_wrap;
const unwrap = ModAPI.hooks.methods.otji_JSWrapper_unwrap; const unwrap = ModAPI.hooks.methods.otji_JSWrapper_unwrap;
@ -39,6 +40,7 @@ ModAPI.meta.credits("By ZXMushroom63");
// @type Map<string, ArrayBuffer> // @type Map<string, ArrayBuffer>
AsyncSink.FS = new Map(); AsyncSink.FS = new Map();
AsyncSink.L10N = new Map();
AsyncSink.FSOverride = new Set(); AsyncSink.FSOverride = new Set();
AsyncSink.MIDDLEWARE = []; AsyncSink.MIDDLEWARE = [];
AsyncSink.setFile = function setFile(path, data) { AsyncSink.setFile = function setFile(path, data) {
@ -80,8 +82,8 @@ ModAPI.meta.credits("By ZXMushroom63");
} }
return wrap(AsyncSink.getFile(ModAPI.util.ustr(args[1]))); return wrap(AsyncSink.getFile(ModAPI.util.ustr(args[1])));
} }
var ev = {method: "read", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: new ArrayBuffer()}; var ev = { method: "read", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: new ArrayBuffer() };
AsyncSink.MIDDLEWARE.forEach((fn)=>{fn(ev)}); AsyncSink.MIDDLEWARE.forEach((fn) => { fn(ev) });
if (ev.shim) { if (ev.shim) {
return wrap(ev.shimOutput); return wrap(ev.shimOutput);
} }
@ -100,8 +102,8 @@ ModAPI.meta.credits("By ZXMushroom63");
AsyncSink.setFile(ModAPI.util.ustr(args[1]), args[2]); AsyncSink.setFile(ModAPI.util.ustr(args[1]), args[2]);
return booleanResult(true); return booleanResult(true);
} }
var ev = {method: "write", file: ModAPI.util.ustr(args[1]), data: args[2], shim: false, shimOutput: true}; var ev = { method: "write", file: ModAPI.util.ustr(args[1]), data: args[2], shim: false, shimOutput: true };
AsyncSink.MIDDLEWARE.forEach((fn)=>{fn(ev)}); AsyncSink.MIDDLEWARE.forEach((fn) => { fn(ev) });
if (ev.shim) { if (ev.shim) {
return booleanResult(ev.shimOutput); return booleanResult(ev.shimOutput);
} }
@ -120,8 +122,8 @@ ModAPI.meta.credits("By ZXMushroom63");
AsyncSink.deleteFile(ModAPI.util.ustr(args[1])); AsyncSink.deleteFile(ModAPI.util.ustr(args[1]));
return booleanResult(true); return booleanResult(true);
} }
var ev = {method: "delete", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: true}; var ev = { method: "delete", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: true };
AsyncSink.MIDDLEWARE.forEach((fn)=>{fn(ev)}); AsyncSink.MIDDLEWARE.forEach((fn) => { fn(ev) });
if (ev.shim) { if (ev.shim) {
return booleanResult(ev.shimOutput); return booleanResult(ev.shimOutput);
} }
@ -140,17 +142,114 @@ ModAPI.meta.credits("By ZXMushroom63");
var result = AsyncSink.fileExists(ModAPI.util.ustr(args[1])); var result = AsyncSink.fileExists(ModAPI.util.ustr(args[1]));
return booleanResult(result); return booleanResult(result);
} }
var ev = {method: "exists", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: true}; var ev = { method: "exists", file: ModAPI.util.ustr(args[1]), shim: false, shimOutput: true };
AsyncSink.MIDDLEWARE.forEach((fn)=>{fn(ev)}); AsyncSink.MIDDLEWARE.forEach((fn) => { fn(ev) });
if (ev.shim) { if (ev.shim) {
return booleanResult(ev.shimOutput); return booleanResult(ev.shimOutput);
} }
return originalFileExists.apply(this, args); return originalFileExists.apply(this, args);
}; };
const L10NRead = ModAPI.util.getMethodFromPackage("net.minecraft.util.StatCollector", "translateToLocal");
const originalL10NRead = ModAPI.hooks.methods[L10NRead];
ModAPI.hooks.methods[L10NRead] = function (...args) {
var key = ModAPI.util.ustr(args[0]);
if (AsyncSink.L10N.has(key)) {
return ModAPI.util.str(AsyncSink.L10N.get(key));
}
return originalL10NRead.apply(this, args);
};
const L10NCheck = ModAPI.util.getMethodFromPackage("net.minecraft.util.StatCollector", "canTranslate");
const originalL10NCheck = ModAPI.hooks.methods[L10NRead];
ModAPI.hooks.methods[L10NCheck] = function (...args) {
if (AsyncSink.L10N.has(ModAPI.util.ustr(args[0]))) {
return 1;
}
return originalL10NCheck.apply(this, args);
};
globalThis.AsyncSink = AsyncSink; globalThis.AsyncSink = AsyncSink;
ModAPI.events.newEvent("lib:asyncsink");
ModAPI.events.callEvent("lib:asyncsink", {}); ModAPI.events.callEvent("lib:asyncsink", {});
console.log("[AsyncSink] Loaded!"); console.log("[AsyncSink] Loaded!");
} }
runtimeComponent(); runtimeComponent();
ModAPI.dedicatedServer.appendCode(runtimeComponent); ModAPI.dedicatedServer.appendCode(runtimeComponent);
async function assureAsyncSinkResources() {
const dec = new TextDecoder("utf-8");
const enc = new TextEncoder("utf-8");
var resourcePackKey = (await indexedDB.databases()).find(x => x?.name?.endsWith("_resourcePacks")).name;
const dbRequest = indexedDB.open(resourcePackKey);
const db = await promisifyIDBRequest(dbRequest);
const transaction = db.transaction(["filesystem"], "readonly");
const objectStore = transaction.objectStore("filesystem");
var object = (await promisifyIDBRequest(objectStore.get(["resourcepacks/manifest.json"])))?.data;
var resourcePackList = object ? JSON.parse(dec.decode(object)) : { resourcePacks: [] };
if (!resourcePackList.resourcePacks.find(x => x.name === "AsyncSinkLib")) {
resourcePackList.resourcePacks.push({
domains: ["minecraft"],
folder: "AsyncSinkLib",
name: "AsyncSinkLib",
timestamp: Date.now()
});
const writeableTransaction = db.transaction(["filesystem"], "readwrite");
const writeableObjectStore = writeableTransaction.objectStore("filesystem");
await promisifyIDBRequest(writeableObjectStore.put({
path: "resourcepacks/manifest.json",
data: enc.encode(JSON.stringify(resourcePackList)).buffer
}));
await promisifyIDBRequest(writeableObjectStore.put({
path: "resourcepacks/AsyncSinkLib/pack.mcmeta",
data: enc.encode(JSON.stringify({
"pack": {
"pack_format": 1,
"description": "AsyncSink Library Resources"
}
})).buffer
}));
var icon = {
path: "resourcepacks/AsyncSinkLib/pack.png",
data: await (await fetch(asyncSinkIcon)).arrayBuffer()
};
const imageTransaction = db.transaction(["filesystem"], "readwrite");
const imageObjectStore = imageTransaction.objectStore("filesystem");
await promisifyIDBRequest(imageObjectStore.put(icon));
}
}
// Client side reminders to enable the AsyncSink Resource Pack
var asyncSinkInstallStatus = false;
var installMessage = document.createElement("span");
installMessage.innerText = "Please enable the AsyncSink resource pack\nIn game, use the .reload_tex command to load textures for modded blocks and items.";
installMessage.style = "background-color: rgba(0,0,0,0.7); color: red; position: fixed; top: 0; left: 0; font-family: sans-serif; pointer-events: none; user-select: none;";
document.body.appendChild(installMessage);
assureAsyncSinkResources();
setInterval(() => {
var resourcePackEntries = ModAPI.mc.mcResourcePackRepository.getRepositoryEntries().getCorrective();
var array = resourcePackEntries.array || [resourcePackEntries.element];
asyncSinkInstallStatus = array.find(x => ModAPI.util.ustr(x.reResourcePack.resourcePackFile.getRef()) === "AsyncSinkLib") ? true : false;
assureAsyncSinkResources();
if (asyncSinkInstallStatus) {
installMessage.style.display = "none";
} else {
installMessage.style.display = "initial";
}
}, 8000);
ModAPI.events.newEvent("custom:asyncsink_reloaded");
ModAPI.addEventListener("sendchatmessage", (e) => {
if (e.message.toLowerCase().startsWith(".reload_tex")) {
e.preventDefault = true;
ModAPI.mc.renderItem.itemModelMesher.simpleShapesCache.clear();
ModAPI.promisify(ModAPI.mc.refreshResources)().then(()=>{
ModAPI.events.callEvent("custom:asyncsink_reloaded", {});
});
}
});
})(); })();

View File

@ -0,0 +1,127 @@
//THIS IS A DEMO MOD
//nice little utility function to fix the block identity map
function fixupBlockIds() {
var blockRegistry = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry).getCorrective();
var BLOCK_STATE_IDS = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.BLOCK_STATE_IDS).getCorrective();
blockRegistry.registryObjects.hashTableKToV.forEach(entry => {
if (entry) {
var block = entry.value;
var validStates = block.getBlockState().getValidStates();
var stateArray = validStates.array || [validStates.element];
stateArray.forEach(iblockstate => {
var i = blockRegistry.getIDForObject(block.getRef()) << 4 | block.getMetaFromState(iblockstate.getRef());
BLOCK_STATE_IDS.put(iblockstate.getRef(), i);
});
}
});
}
function makeSteveBlock() {
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var iproperty = ModAPI.reflect.getClassById("net.minecraft.block.properties.IProperty").class;
var makeBlockState = ModAPI.reflect.getClassById("net.minecraft.block.state.BlockState").constructors.find(x => x.length === 2);
var blockSuper = ModAPI.reflect.getSuper(blockClass, (x) => x.length === 2);
var creativeBlockTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabBlock;
var nmb_BlockSteve = function nmb_BlockSteve() {
blockSuper(this, ModAPI.materials.rock.getRef());
this.$defaultBlockState = this.$blockState.$getBaseState();
this.$setCreativeTab(creativeBlockTab);
}
ModAPI.reflect.prototypeStack(blockClass, nmb_BlockSteve);
nmb_BlockSteve.prototype.$isOpaqueCube = function () {
return 1;
}
nmb_BlockSteve.prototype.$createBlockState = function (t) {
return makeBlockState(this, ModAPI.array.object(iproperty, 0));
}
globalThis.nmb_BlockSteve = nmb_BlockSteve;
}
function registerSteveClientSide() {
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var block_of_steve = (new nmb_BlockSteve()).$setHardness(-1.0).$setStepSound(blockClass.staticVariables.soundTypeGravel).$setUnlocalizedName(
ModAPI.util.str("steve")
);
blockClass.staticMethods.registerBlock0.method(
198, //use blockid 198
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"));
});
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
{
"parent": "block/cube_all",
"textures": {
"all": "blocks/steve"
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/item/steve.json", JSON.stringify(
{
"parent": "block/steve",
"display": {
"thirdperson": {
"rotation": [10, -45, 170],
"translation": [0, 1.5, -2.75],
"scale": [0.375, 0.375, 0.375]
}
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/blockstates/steve.json", JSON.stringify(
{
"variants": {
"normal": [
{ "model": "steve" },
]
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/blocks/steve.png", await (await fetch(
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE0SURBVDhPpdO9S8NAHMbxy3sVfJmMg6h7FRXXkkUUX0addSjo4OAfIDqLIoiLi3+BRRx0EIQOnV0EcVAIWkR0KIFgrcEktX6vcXD0nuE+5Afhnhw5bWy4qylaidOfVQhT0zFKYozjBHVdzi3TwCZvteaS/0fLD8oGf5OzTeyxNUyE3Ln2HmGctpuxKuS3wd76CgPHsrEj142NeojCkHsFry+4c3aJ6g1OtlZp0Ok4DD4i+Y2GIZ+DMMAhtw+fHu8xi3IDM9t5YfMQF71dLHo+ZjsfXbh4WtnH0vYaqp/BcXGGM3D7BxiYTi+el8uYZWm2gM/VB/Tfaqje4GB5iga2Jv+sUuUa5/ITmOXq7gbnC+MY1r9QvcHG9AgN0lRex1u/ilr7ehqWvBNZvMlRbESfqNhAiG/Pb1bHXpMbFgAAAABJRU5ErkJggg=="
)).arrayBuffer());
});
}
function registerSteveServerSide() {
function fixupBlockIds() {
var blockRegistry = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry).getCorrective();
var BLOCK_STATE_IDS = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.BLOCK_STATE_IDS).getCorrective();
blockRegistry.registryObjects.hashTableKToV.forEach(entry => {
if (entry) {
var block = entry.value;
var validStates = block.getBlockState().getValidStates();
var stateArray = validStates.array || [validStates.element];
stateArray.forEach(iblockstate => {
var i = blockRegistry.getIDForObject(block.getRef()) << 4 | block.getMetaFromState(iblockstate.getRef());
BLOCK_STATE_IDS.put(iblockstate.getRef(), i);
});
}
});
}
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
ModAPI.addEventListener("bootstrap", () => {
var block_of_steve = (new nmb_BlockSteve()).$setHardness(-1.0).$setStepSound(blockClass.staticVariables.soundTypeGravel).$setUnlocalizedName(
ModAPI.util.str("steve")
);
blockClass.staticMethods.registerBlock0.method(
198,
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
fixupBlockIds();
});
}
ModAPI.dedicatedServer.appendCode(makeSteveBlock);
makeSteveBlock();
registerSteveClientSide();
fixupBlockIds();
ModAPI.dedicatedServer.appendCode(registerSteveServerSide);

View File

@ -0,0 +1,111 @@
//THIS IS A DEMO MOD
//nice little utility function to fix the block identity map
function fixupBlockIds() {
var blockRegistry = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry).getCorrective();
var BLOCK_STATE_IDS = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.BLOCK_STATE_IDS).getCorrective();
blockRegistry.registryObjects.hashTableKToV.forEach(entry => {
if (entry) {
var block = entry.value;
var validStates = block.getBlockState().getValidStates();
var stateArray = validStates.array || [validStates.element];
stateArray.forEach(iblockstate => {
var i = blockRegistry.getIDForObject(block.getRef()) << 4 | block.getMetaFromState(iblockstate.getRef());
BLOCK_STATE_IDS.put(iblockstate.getRef(), i);
});
}
});
}
function registerSteveClientSide() {
var creativeBlockTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabBlock;
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var constructor = blockClass.constructors.find(x=>x.length === 1);
var block_of_steve = constructor(ModAPI.materials.rock.getRef()).$setHardness(-1.0).$setStepSound(blockClass.staticVariables.soundTypeGravel).$setUnlocalizedName(
ModAPI.util.str("steve")
).$setCreativeTab(creativeBlockTab);
blockClass.staticMethods.registerBlock0.method(
198, //use blockid 198
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"));
});
AsyncSink.L10N.set("tile.steve.name", "Block Of Steve");
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/block/steve.json", JSON.stringify(
{
"parent": "block/cube_all",
"textures": {
"all": "blocks/steve"
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/item/steve.json", JSON.stringify(
{
"parent": "block/steve",
"display": {
"thirdperson": {
"rotation": [10, -45, 170],
"translation": [0, 1.5, -2.75],
"scale": [0.375, 0.375, 0.375]
}
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/blockstates/steve.json", JSON.stringify(
{
"variants": {
"normal": [
{ "model": "steve" },
]
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/blocks/steve.png", await (await fetch(
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAE0SURBVDhPpdO9S8NAHMbxy3sVfJmMg6h7FRXXkkUUX0addSjo4OAfIDqLIoiLi3+BRRx0EIQOnV0EcVAIWkR0KIFgrcEktX6vcXD0nuE+5Afhnhw5bWy4qylaidOfVQhT0zFKYozjBHVdzi3TwCZvteaS/0fLD8oGf5OzTeyxNUyE3Ln2HmGctpuxKuS3wd76CgPHsrEj142NeojCkHsFry+4c3aJ6g1OtlZp0Ok4DD4i+Y2GIZ+DMMAhtw+fHu8xi3IDM9t5YfMQF71dLHo+ZjsfXbh4WtnH0vYaqp/BcXGGM3D7BxiYTi+el8uYZWm2gM/VB/Tfaqje4GB5iga2Jv+sUuUa5/ITmOXq7gbnC+MY1r9QvcHG9AgN0lRex1u/ilr7ehqWvBNZvMlRbESfqNhAiG/Pb1bHXpMbFgAAAABJRU5ErkJggg=="
)).arrayBuffer());
});
}
function registerSteveServerSide() {
function fixupBlockIds() {
var blockRegistry = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry).getCorrective();
var BLOCK_STATE_IDS = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.BLOCK_STATE_IDS).getCorrective();
blockRegistry.registryObjects.hashTableKToV.forEach(entry => {
if (entry) {
var block = entry.value;
var validStates = block.getBlockState().getValidStates();
var stateArray = validStates.array || [validStates.element];
stateArray.forEach(iblockstate => {
var i = blockRegistry.getIDForObject(block.getRef()) << 4 | block.getMetaFromState(iblockstate.getRef());
BLOCK_STATE_IDS.put(iblockstate.getRef(), i);
});
}
});
}
var creativeBlockTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabBlock;
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
var constructor = blockClass.constructors.find(x=>x.length === 1);
ModAPI.addEventListener("bootstrap", () => {
var block_of_steve = constructor(ModAPI.materials.rock.getRef()).$setHardness(-1.0).$setStepSound(blockClass.staticVariables.soundTypeGravel).$setUnlocalizedName(
ModAPI.util.str("steve")
).$setCreativeTab(creativeBlockTab);
blockClass.staticMethods.registerBlock0.method(
198,
ModAPI.util.str("steve"),
block_of_steve
);
itemClass.staticMethods.registerItemBlock0.method(block_of_steve);
fixupBlockIds();
});
}
registerSteveClientSide();
fixupBlockIds();
ModAPI.dedicatedServer.appendCode(registerSteveServerSide);

View File

@ -92,7 +92,7 @@ function button_utility_script(inputArr, bindingClass, actionBindMode) {
{ {
text: "Server Close", text: "Server Close",
click: () => { click: () => {
var CloseWindow = ModAPI.reflect.getClassByName("C0DPacketCloseWindow").constructors.find(x => x.length === 1); var CloseWindow = ModAPI.reflect.getClassByName("C0DPacketCloseWindow").constructors[0];
ModAPI.player.sendQueue.addToSendQueue(CloseWindow(ModAPI.player.openContainer.getCorrective().windowId)); ModAPI.player.sendQueue.addToSendQueue(CloseWindow(ModAPI.player.openContainer.getCorrective().windowId));
}, },
x: 0, x: 0,

View File

@ -0,0 +1,134 @@
(()=>{
const unluckyBlockTexture = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAAXNSR0IArs4c6QAAAOhJREFUOE9jnJn2/z8DGvj4koHh9UOIoKg8AwO/OLoKBJ8RZED6LEbcKvDIzEz7z8DY5f//f9lGTANCGTAcxrCaAVUd2IBSg///uy+gSqBr/sJwF+6O7QwqcHaXPxYXgDTDNCArtmXYBtZ4mMELbkCpwX8GjDDwZLjD8IXhFopCkA5s4mAXEBOIMC+BXIbsKnAYEDIAOTywBiI+A0DO5mFQBvsZXTNIjKALQAHHw6CG4mzkZIE3HYAUEjIAHIjY0gGxyRIcjfgMgIUBNv+DLAEbgCspgxTAYgCXAUSnA1xegscCPj8TytoAA5eEOx9BbCgAAAAASUVORK5CYII=";
ModAPI.meta.title("Unlucky Blocks");
ModAPI.meta.version("v1.0");
ModAPI.meta.description("These purple cubes ruined my life. Requires AsyncSink.");
ModAPI.meta.credits("By ZXMushroom63");
ModAPI.meta.icon(unluckyBlockTexture);
function UnluckyBlocks() {
function fixupBlockIds() {
var blockRegistry = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.blockRegistry).getCorrective();
var BLOCK_STATE_IDS = ModAPI.util.wrap(ModAPI.reflect.getClassById("net.minecraft.block.Block").staticVariables.BLOCK_STATE_IDS).getCorrective();
blockRegistry.registryObjects.hashTableKToV.forEach(entry => {
if (entry) {
var block = entry.value;
var validStates = block.getBlockState().getValidStates();
var stateArray = validStates.array || [validStates.element];
stateArray.forEach(iblockstate => {
var i = blockRegistry.getIDForObject(block.getRef()) << 4 | block.getMetaFromState(iblockstate.getRef());
BLOCK_STATE_IDS.put(iblockstate.getRef(), i);
});
}
});
}
var itemClass = ModAPI.reflect.getClassById("net.minecraft.item.Item");
var blockClass = ModAPI.reflect.getClassById("net.minecraft.block.Block");
var iproperty = ModAPI.reflect.getClassById("net.minecraft.block.properties.IProperty").class;
var makeBlockState = ModAPI.reflect.getClassById("net.minecraft.block.state.BlockState").constructors.find(x => x.length === 2);
var blockSuper = ModAPI.reflect.getSuper(blockClass, (x) => x.length === 2); //Get super function from the block class with a target length of two. ($this (mandatory), material (optional))
var creativeBlockTab = ModAPI.reflect.getClassById("net.minecraft.creativetab.CreativeTabs").staticVariables.tabBlock;
var breakBlockMethod = blockClass.methods.breakBlock.method;
var nmb_BlockUnlucky = function nmb_BlockUnlucky() {
blockSuper(this, ModAPI.materials.rock.getRef()); //Use super function to get block properties on this class.
this.$defaultBlockState = this.$blockState.$getBaseState();
this.$setCreativeTab(creativeBlockTab);
}
ModAPI.reflect.prototypeStack(blockClass, nmb_BlockUnlucky);
nmb_BlockUnlucky.prototype.$isOpaqueCube = function () {
return 1;
}
nmb_BlockUnlucky.prototype.$createBlockState = function () {
return makeBlockState(this, ModAPI.array.object(iproperty, 0));
}
nmb_BlockUnlucky.prototype.$breakBlock = function ($world, $blockpos, $blockstate) {
var world = ModAPI.util.wrap($world);
var blockpos = ModAPI.util.wrap($blockpos);
if (Math.random() < 1) { //was gonna add random events but couldn't be bothered. Enjoy exploding!
world.newExplosion(null, blockpos.getX() + 0.5, blockpos.getY() + 0.5,
blockpos.getZ() + 0.5, 9, 1, 1);
}
return breakBlockMethod(this, $world, $blockpos, $blockstate);
}
function internal_reg() {
var block_of_unluckiness = (new nmb_BlockUnlucky()).$setHardness(0.0).$setStepSound(blockClass.staticVariables.soundTypePiston).$setUnlocalizedName(
ModAPI.util.str("unluckiness")
);
blockClass.staticMethods.registerBlock0.method(
544,
ModAPI.util.str("unluckiness"),
block_of_unluckiness
);
itemClass.staticMethods.registerItemBlock0.method(block_of_unluckiness);
fixupBlockIds();
ModAPI.blocks["unluckiness"] = block_of_unluckiness;
return block_of_unluckiness;
}
const WorldGenMineable = ModAPI.reflect.getClassById("net.minecraft.world.gen.feature.WorldGenMinable").constructors.find(x=>x.length===2);
const BiomeDecorator_decorate = ModAPI.util.getMethodFromPackage("net.minecraft.world.biome.BiomeDecorator", "decorate");
const oldDecorate = ModAPI.hooks.methods[BiomeDecorator_decorate];
ModAPI.hooks.methods[BiomeDecorator_decorate] = function ($this, $world, $random, $biomeGenBase, $blockpos) {
if (!$this.$currentWorld) {
$this.$unluckyBlockGen = WorldGenMineable(ModAPI.blocks.unluckiness.getDefaultState().getRef(), 4);
}
return oldDecorate.apply(this, [$this, $world, $random, $biomeGenBase, $blockpos]);
}
const BiomeDecorator_generateOres = ModAPI.util.getMethodFromPackage("net.minecraft.world.biome.BiomeDecorator", "generateOres");
const oldGenerateOres = ModAPI.hooks.methods[BiomeDecorator_generateOres];
ModAPI.hooks.methods[BiomeDecorator_generateOres] = function ($this) {
$this.$genStandardOre1(105, $this.$unluckyBlockGen || null, 0, 256);
return oldGenerateOres.apply(this, [$this]);
}
if (ModAPI.materials) {
return internal_reg();
} else {
ModAPI.addEventListener("bootstrap", internal_reg);
}
}
ModAPI.dedicatedServer.appendCode(UnluckyBlocks);
var block_of_unluckiness = UnluckyBlocks();
ModAPI.addEventListener("lib:asyncsink", async () => {
ModAPI.addEventListener("custom:asyncsink_reloaded", ()=>{
ModAPI.mc.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(
{
"parent": "block/cube_all",
"textures": {
"all": "blocks/unluckiness"
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/models/item/unluckiness.json", JSON.stringify(
{
"parent": "block/unluckiness",
"display": {
"thirdperson": {
"rotation": [10, -45, 170],
"translation": [0, 1.5, -2.75],
"scale": [0.375, 0.375, 0.375]
}
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/blockstates/unluckiness.json", JSON.stringify(
{
"variants": {
"normal": [
{ "model": "unluckiness" },
]
}
}
));
AsyncSink.setFile("resourcepacks/AsyncSinkLib/assets/minecraft/textures/blocks/unluckiness.png", await (await fetch(
unluckyBlockTexture
)).arrayBuffer());
});
})();

View File

@ -167,6 +167,7 @@
ModAPI.hooks._rippedData ||= []; ModAPI.hooks._rippedData ||= [];
ModAPI.hooks._teavm ||= {}; ModAPI.hooks._teavm ||= {};
ModAPI.hooks._rippedConstructors ||= {}; ModAPI.hooks._rippedConstructors ||= {};
ModAPI.hooks._rippedInternalConstructors ||= {};
ModAPI.hooks.methods ||= {}; ModAPI.hooks.methods ||= {};
ModAPI.hooks._rippedMethodTypeMap ||= {}; ModAPI.hooks._rippedMethodTypeMap ||= {};
ModAPI.hooks._postInit ||= ()=>{}; ModAPI.hooks._postInit ||= ()=>{};

View File

@ -9,6 +9,12 @@ function _status(x) {
document.querySelector("#status").innerText = x; document.querySelector("#status").innerText = x;
} }
function entriesToStaticVariableProxy(entries, prefix) { function entriesToStaticVariableProxy(entries, prefix) {
if (entries.length === 0) {
return `ModAPI.hooks._rippedStaticProperties[\`${prefix.replace(
"var ",
""
)}\`]={};`;
}
var getComponents = ""; var getComponents = "";
entries.forEach((entry) => { entries.forEach((entry) => {
getComponents += ` getComponents += `
@ -16,6 +22,9 @@ function entriesToStaticVariableProxy(entries, prefix) {
return ${entry.variable}; return ${entry.variable};
break;`; break;`;
}); });
getComponents += `
default:
return Reflect.get(a,b,c);`
var setComponents = ""; var setComponents = "";
entries.forEach((entry) => { entries.forEach((entry) => {
@ -24,7 +33,11 @@ function entriesToStaticVariableProxy(entries, prefix) {
${entry.variable} = c; ${entry.variable} = c;
break;`; break;`;
}); });
var proxy = ` setComponents += `
default:
a[b]=c;`
/*/
ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace( ModAPI.hooks._rippedStaticIndexer[\`${prefix.replace(
"var ", "var ",
"" ""
@ -33,7 +46,8 @@ function entriesToStaticVariableProxy(entries, prefix) {
return '"' + x.name + '"'; return '"' + x.name + '"';
}) })
.join(",")}]; .join(",")}];
ModAPI.hooks._rippedStaticProperties[\`${prefix.replace( /*/
var proxy = `ModAPI.hooks._rippedStaticProperties[\`${prefix.replace(
"var ", "var ",
"" ""
)}\`] = new Proxy({${entries )}\`] = new Proxy({${entries
@ -51,6 +65,7 @@ function entriesToStaticVariableProxy(entries, prefix) {
switch (b) { switch (b) {
${setComponents} ${setComponents}
} }
return true;
} }
});`; });`;
return proxy; return proxy;
@ -137,6 +152,20 @@ var main;(function(){`
} }
); );
const extractInternalConstructorRegex =
/^\s*function (\S*?)__init_\d*?\(\$this/gm; //same as extract constructor regex, but only allow $this as first argument
patchedFile = patchedFile.replaceAll(
extractInternalConstructorRegex,
(match) => {
var fullName = match.match(extractConstructorFullNameRegex);
fullName = fullName[0].replace("function ", "");
return (
`ModAPI.hooks._rippedInternalConstructors[\`${fullName}\`] = ${fullName};
` + match
);
}
);
if(globalThis.optimizePi){ if(globalThis.optimizePi){
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
"3.1415927410125732 / 180.0", "3.1415927410125732 / 180.0",
@ -224,7 +253,7 @@ var main;(function(){`
patchedFile = patchedFile.replaceAll( patchedFile = patchedFile.replaceAll(
/function [a-z]+?_([a-zA-Z\$]+?)\(\) \{/gm, /function [a-z]+?_([a-zA-Z0-9\$]+?)\(\) \{/gm,
(match) => { (match) => {
var prefix = "var " + match.replace("function ", "").replace("() {", ""); var prefix = "var " + match.replace("function ", "").replace("() {", "");
var entries = []; var entries = [];

View File

@ -35,4 +35,4 @@ PatchesRegistry.addPatch(function (input) {
if (!$this.$renderHand)` if (!$this.$renderHand)`
); );
return output; return output;
}) });

View File

@ -22,7 +22,7 @@ globalThis.modapi_postinit = "(" + (() => {
ModAPI.meta._versionMap = {}; ModAPI.meta._versionMap = {};
ModAPI.array = {}; ModAPI.array = {};
ModAPI.version = "v2.1.2"; ModAPI.version = "v2.2";
ModAPI.flavour = "injector"; ModAPI.flavour = "injector";
ModAPI.GNU = "terry pratchett"; ModAPI.GNU = "terry pratchett";
ModAPI.credits = ["ZXMushroom63", "radmanplays", "Murturtle", "OtterCodes101", "TheIdiotPlays", "OeildeLynx31", "Stpv22"]; ModAPI.credits = ["ZXMushroom63", "radmanplays", "Murturtle", "OtterCodes101", "TheIdiotPlays", "OeildeLynx31", "Stpv22"];
@ -149,7 +149,7 @@ globalThis.modapi_postinit = "(" + (() => {
} }
if (xOut && typeof xOut === "object" && !Array.isArray(xOut)) { if (xOut && typeof xOut === "object" && !Array.isArray(xOut)) {
if (corrective) { if (corrective) {
return new Proxy(outputValue.data, CorrectiveRecursive); return new Proxy(xOut, CorrectiveRecursive);
} }
return new Proxy(xOut, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf); return new Proxy(xOut, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf);
} }
@ -209,6 +209,7 @@ globalThis.modapi_postinit = "(" + (() => {
ModAPI.hooks.regenerateClassMap = function () { ModAPI.hooks.regenerateClassMap = function () {
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._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap); ModAPI.hooks._rippedMethodKeys = Object.keys(ModAPI.hooks._rippedMethodTypeMap);
var compiledNames = new Set(); var compiledNames = new Set();
@ -255,6 +256,7 @@ globalThis.modapi_postinit = "(" + (() => {
"id": classId, "id": classId,
"binaryName": item?.$meta?.binaryName || null, "binaryName": item?.$meta?.binaryName || null,
"constructors": [], "constructors": [],
"internalConstructors": [],
"methods": {}, "methods": {},
"staticMethods": {}, "staticMethods": {},
"staticVariables": {}, "staticVariables": {},
@ -268,12 +270,16 @@ globalThis.modapi_postinit = "(" + (() => {
} }
} }
if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) { if (typeof item?.$meta?.superclass === "function" && item?.$meta?.superclass?.$meta) {
ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass.$meta.name; ModAPI.hooks._classMap[compiledName].superclassName = item.$meta.superclass.$meta.name;
ModAPI.hooks._classMap[compiledName].superclass = item.$meta.superclass;
} else { } else {
ModAPI.hooks._classMap[compiledName].superclass = null; ModAPI.hooks._classMap[compiledName].superclass = null;
ModAPI.hooks._classMap[compiledName].superclassName = null;
} }
ModAPI.hooks._classMap[compiledName].staticVariableNames = ModAPI.hooks._rippedStaticIndexer[compiledName];
ModAPI.hooks._classMap[compiledName].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName]; ModAPI.hooks._classMap[compiledName].staticVariables = ModAPI.hooks._rippedStaticProperties[compiledName];
ModAPI.hooks._classMap[compiledName].staticVariableNames = Object.keys(ModAPI.hooks._classMap[compiledName].staticVariables || {});
if (item?.["$$constructor$$"]) { if (item?.["$$constructor$$"]) {
//Class does not have any hand written constructors //Class does not have any hand written constructors
//Eg: class MyClass {} //Eg: class MyClass {}
@ -286,6 +292,13 @@ globalThis.modapi_postinit = "(" + (() => {
} }
}); });
} }
ModAPI.hooks._rippedInternalConstructorKeys.forEach(initialiser => { // Find internal constructors/initialisers. Used for calling super() on custom classes. (They are the different implementations of a classes constructor, that don't automatically create an object. Thus, it is identical to calling super)
if (initialiser.startsWith(compiledName + "__init_") && !initialiser.includes("$lambda$")) {
ModAPI.hooks._classMap[compiledName].internalConstructors.push(ModAPI.hooks._rippedInternalConstructors[initialiser]);
}
});
ModAPI.hooks._rippedMethodKeys.forEach((method) => { ModAPI.hooks._rippedMethodKeys.forEach((method) => {
if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) { if (method.startsWith(compiledName + "_") && !method.includes("$lambda$")) {
var targetMethodMap = ModAPI.hooks._classMap[compiledName].methods; var targetMethodMap = ModAPI.hooks._classMap[compiledName].methods;
@ -319,6 +332,31 @@ globalThis.modapi_postinit = "(" + (() => {
var key = classKeys.filter(k => { return ModAPI.hooks._classMap[k].name === className })[0]; var key = classKeys.filter(k => { return ModAPI.hooks._classMap[k].name === className })[0];
return key ? ModAPI.hooks._classMap[key] : null; return key ? ModAPI.hooks._classMap[key] : null;
} }
//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;
var initialiser = reflectClass.internalConstructors.find(filter);
return function superFunction(thisArg, ...extra_args) {
reflectClass.class.call(thisArg);
initialiser(thisArg, ...extra_args);
}
}
//Iteratively load the superclasses' prototype methods.
ModAPI.reflect.prototypeStack = function prototypeStack(reflectClass, classFn) {
var stack = [reflectClass.class.prototype];
var currentSuperclass = reflectClass.superclass;
while (currentSuperclass) {
stack.push(currentSuperclass.prototype);
currentSuperclass = currentSuperclass?.$meta?.superclass;
}
stack.reverse();
stack.forEach(proto => {
Object.assign(classFn.prototype, proto);
});
}
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) {
@ -556,7 +594,7 @@ globalThis.modapi_postinit = "(" + (() => {
//Function used for running @Async / @Async-dependent TeaVM methods. //Function used for running @Async / @Async-dependent TeaVM methods.
ModAPI.promisify = function promisify(fn) { ModAPI.promisify = function promisify(fn) {
return function promisifiedJavaMethpd(...inArguments) { return function promisifiedJavaMethod(...inArguments) {
return new Promise((res, rej) => { return new Promise((res, rej) => {
Promise.resolve().then( //queue microtask Promise.resolve().then( //queue microtask
() => { () => {
@ -843,13 +881,19 @@ globalThis.modapi_postinit = "(" + (() => {
return x; return x;
} }
const originalBootstrap = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")]; ModAPI.util.bootstrap = function () {
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")] = function (...args) {
var x = originalBootstrap.apply(this, args);
ModAPI.items = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Items")].staticVariables, StaticProps_ProxyConf); ModAPI.items = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Items")].staticVariables, StaticProps_ProxyConf);
ModAPI.blocks = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Blocks")].staticVariables, StaticProps_ProxyConf); ModAPI.blocks = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.init.Blocks")].staticVariables, StaticProps_ProxyConf);
ModAPI.materials = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.block.material.Material")].staticVariables, StaticProps_ProxyConf); ModAPI.materials = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.block.material.Material")].staticVariables, StaticProps_ProxyConf);
ModAPI.enchantments = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.enchantment.Enchantment")].staticVariables, StaticProps_ProxyConf); ModAPI.enchantments = new Proxy(ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.enchantment.Enchantment")].staticVariables, StaticProps_ProxyConf);
}
ModAPI.events.newEvent("bootstrap", "server");
const originalBootstrap = ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")];
ModAPI.hooks.methods[ModAPI.util.getMethodFromPackage("net.minecraft.init.Bootstrap", "register")] = function (...args) {
var x = originalBootstrap.apply(this, args);
ModAPI.util.bootstrap();
ModAPI.events.callEvent("bootstrap", {});
console.log("[ModAPI] Hooked into bootstrap. .blocks, .items, .materials and .enchantments are now accessible."); console.log("[ModAPI] Hooked into bootstrap. .blocks, .items, .materials and .enchantments are now accessible.");
return x; return x;
} }

View File

@ -1,5 +0,0 @@
*/*/ ZXMushroom63's rather large to do list */*/
Add makeItemStack to LCI [Todo]
Fix blocklook.js [In progress]
Fix setblocktest.js [In progress]