Skip to content

Commit

Permalink
lib events, custom events, custom items demp code
Browse files Browse the repository at this point in the history
  • Loading branch information
ZXMushroom63 committed Sep 8, 2024
1 parent 33d1a71 commit b3752f2
Show file tree
Hide file tree
Showing 5 changed files with 193 additions and 21 deletions.
15 changes: 14 additions & 1 deletion docs/apidoc/events.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Can only be used in the context of the dedicated server. More: [DedicatedServerD
The events global, `ModAPI.events`, allows you to register new event types and call them.

#### ModAPI.events.newEvent(eventName: String)
You can register new events using ModAPI, as long as the event name starts with `custom:`. For example, if I want to add a new event that can be used by other mods, I can use `ModAPI.events.newEvent("custom:myevent")`.
You can register new events using ModAPI, as long as the event name starts with `custom:` (`lib:` is only useful for library loading). For example, if I want to add a new event that can be used by other mods, I can use `ModAPI.events.newEvent("custom:myevent")`.


#### ModAPI.events.callEvent(eventName: String, data: Object)
Expand All @@ -91,4 +91,17 @@ ModAPI.events.newEvent("custom:myevent");
ModAPI.events.callEvent("custom:myevent", {
secretCode: "1234"
});
```

#### Using library load events
```javascript
// Mod #2, registers and calls lib event
ModAPI.events.newEvent("lib:mylibrary:loaded");
ModAPI.events.callEvent("lib:mylibrary:loaded", {});
```
```javascript
// Mod #1, registers event handler for lib event
ModAPI.addEventListener("lib:mylibrary:loaded", (e)=>{
//Lib events function differently to normal events, as when they are called once, any new event listener with automatically fire upon being registered.
});
```
28 changes: 28 additions & 0 deletions examplemods/CustomItemsDemo.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//This mod also requires lib.customitems.js
ModAPI.addEventListener("lib:libcustomitems:loaded", () => {
console.log("Registered my cool custom item.");
LibCustomItems.registerItem({
tag: "mymod:test_item_1",
base: "magma_cream",
name: "Custom Item",
qty: 32,
recipe: [
"###",
"# #",
"###"
],
recipeLegend: {
"#": {
"type": "block",
"id": "dirt"
}
},
onRightClickGround: `/*/user, world, itemstack, blockpos/*/
itemstack.stackSize -= 1;
if (itemstack.stackSize < 1) {
user.inventory.mainInventory[user.inventory.currentItem] = null;
}
user.setHealth(2);
`
});
});
83 changes: 82 additions & 1 deletion examplemods/lib.customitems.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,85 @@
// Library to make adding custom items with EaglerForgeInjector much easier.
(function LibItems() {
ModAPI.events.newEvent()
ModAPI.events.newEvent("lib:libcustomitems:loaded");
function libServerside() {
globalThis.LCI_REGISTRY ||= [];
globalThis.LCI_ACTIONREGISTRY ||= {};
var useName = ModAPI.util.getMethodFromPackage("net.minecraft.network.NetHandlerPlayServer", "processPlayerBlockPlacement");
var oldUse = ModAPI.hooks.methods[useName];
ModAPI.hooks.methods[useName] = function ($this, packet) {
if ($this?.$playerEntity?.$inventory && $this.$playerEntity.$inventory.$getCurrentItem()) {
var item = $this.$playerEntity.$inventory.$getCurrentItem();
if (item.$stackTagCompound && item.$stackTagCompound.$hasKey(ModAPI.util.str("display"), 10)) {
var displayTag = item.$stackTagCompound.$getCompoundTag(ModAPI.util.str("display"));
if (displayTag.$hasKey(ModAPI.util.str("Lore"), 9)) {
var loreTag = displayTag.$getTag(ModAPI.util.str("Lore"));
if (loreTag.$tagCount() > 0 && globalThis.LCI_REGISTRY.includes(ModAPI.util.ustr(loreTag.$getStringTagAt(0)))) {
var cid = loreTag.$getStringTagAt(0);
var positionTag = Object.keys(packet).filter(x => { return x.startsWith("$position") })[0];
if (packet[positionTag].$x === -1 && packet[positionTag].$y === -1 && packet[positionTag].$z === -1) {
return 0;
}
globalThis.LCI_ACTIONREGISTRY[cid].call(globalThis,
new Proxy($this.$playerEntity, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf),
new Proxy($this.$serverController.$worldServerForDimension($this.$playerEntity.$dimension), ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf),
new Proxy(item, ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf),
new Proxy(packet[positionTag], ModAPI.util.TeaVM_to_Recursive_BaseData_ProxyConf));
return 0;
}
}
}
}
return oldUse.apply(this, [$this, packet]);
}
}
function LCI_registerItem(data) {
globalThis.LCI_REGISTRY ||= [];
globalThis.LCI_ACTIONREGISTRY ||= {};
globalThis.LCI_REGISTRY.push(data.tag);
globalThis.LCI_ACTIONREGISTRY[data.tag] = new Function("user", "world", "itemstack", "blockpos", data.onRightClickGround);
var ObjectClass = ModAPI.reflect.getClassById("java.lang.Object").class;
function ToChar(char) {
return ModAPI.reflect.getClassById("java.lang.Character").staticMethods.valueOf.method(char[0].charCodeAt(0));
}
ModAPI.dedicatedServer.appendCode(`(function () {
function handler() {
LCI_registerItem(${JSON.stringify(data)});
ModAPI.removeEventListener("tick", handler);
}
ModAPI.addEventListener("tick", handler);
})()`);
var recipeInternal = [];
Object.keys(data.recipeLegend).forEach((key) => {
recipeInternal.push(ToChar(key));
var ingredient = null;
var schema = data.recipeLegend[key];
if (schema.type === "block") {
ingredient = ModAPI.blocks[schema.id].getRef();
} else {
ingredient = ModAPI.items[schema.id].getRef();
}
recipeInternal.push(ingredient);
});
var recipeContents = data.recipe.flatMap(x => { return ModAPI.util.str(x) });
var recipe = ModAPI.util.makeArray(ObjectClass, recipeContents.concat(recipeInternal));

var testItem = ModAPI.reflect.getClassById("net.minecraft.item.ItemStack").constructors[4](ModAPI.items[data.base].getRef(), data.qty);
testItem.$stackTagCompound = ModAPI.reflect.getClassById("net.minecraft.nbt.NBTTagCompound").constructors[0]();
testItem.$stackTagCompound.$setTag(ModAPI.util.str("display"), ModAPI.reflect.getClassById("net.minecraft.nbt.NBTTagCompound").constructors[0]());
var displayTag = testItem.$stackTagCompound.$getCompoundTag(ModAPI.util.str("display"));
displayTag.$setString(ModAPI.util.str("Name"), ModAPI.util.str(data.name));
var lore = ModAPI.reflect.getClassById("net.minecraft.nbt.NBTTagList").constructors[0]();
lore.$appendTag(ModAPI.reflect.getClassById("net.minecraft.nbt.NBTTagString").constructors.filter(x => { return x.length === 1 })[0](ModAPI.util.str(data.tag)));
displayTag.$setTag(ModAPI.util.str("Lore"), lore);

var craftingManager = ModAPI.reflect.getClassById("net.minecraft.item.crafting.CraftingManager").staticMethods.getInstance.method();
ModAPI.hooks.methods.nmic_CraftingManager_addRecipe(craftingManager, testItem, recipe);
}
ModAPI.dedicatedServer.appendCode(libServerside);
ModAPI.dedicatedServer.appendCode("globalThis.LCI_registerItem = " + LCI_registerItem.toString());
window.LibCustomItems = {};
LibCustomItems.registerItem = function register(data) {
LCI_registerItem(data);
}
ModAPI.events.callEvent("lib:libcustomitems:loaded", {});
})();
48 changes: 37 additions & 11 deletions postinit.injector.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,25 @@ globalThis.modapi_postinit = `(() => {
ModAPI.required = new Set();
ModAPI.events = {};
ModAPI.events.types = ["event"];
ModAPI.events.lib_map = {};
ModAPI.events.listeners = { "event": [] };
ModAPI.addEventListener = function addEventListener(name, callback) {
if (name.startsWith("lib:")) {
if (ModAPI.events.lib_map[name]) {
callback({});
} else {
if (!Array.isArray(ModAPI.events.listeners[name])) {
ModAPI.events.listeners[name] = [];
}
ModAPI.events.listeners[name].push(callback);
}
console.log("[ModAPI] Added new library listener.");
return;
}
if (!callback || typeof callback !== "function") {
throw new Error("[ModAPI] Invalid callback!");
}
if (ModAPI.events.types.includes(name) || name.startsWith("custom:")) {
if (ModAPI.events.types.includes(name) || name.startsWith("custom:") || name.startsWith("lib:")) {
if (!Array.isArray(ModAPI.events.listeners[name])) {
ModAPI.events.listeners[name] = [];
}
Expand Down Expand Up @@ -327,9 +340,11 @@ globalThis.modapi_postinit = `(() => {
});
}
};
ModAPI.events.newEvent = function newEvent(name, side) {
console.log("[ModAPI] Registered " + side + " event: " + name);
ModAPI.events.types.push(name);
ModAPI.events.newEvent = function newEvent(name, side = "unknown") {
if (!ModAPI.events.types.includes(name)) {
console.log("[ModAPI] Registered " + side + " event: " + name);
ModAPI.events.types.push(name);
}
};
ModAPI.events.callEvent = function callEvent(name, data) {
Expand All @@ -352,12 +367,19 @@ globalThis.modapi_postinit = `(() => {
console.error("Please report this bug to the repo.");
return;
}
ModAPI.events.listeners[name].forEach((func) => {
func(data);
});
ModAPI.events.listeners.event.forEach((func) => {
func({ event: name, data: data });
});
if (name.startsWith("lib:")) {
ModAPI.events.listeners[name].forEach((func) => {
func({});
});
ModAPI.events.lib_map[name] = true;
} else {
ModAPI.events.listeners[name].forEach((func) => {
func(data);
});
ModAPI.events.listeners.event.forEach((func) => {
func({ event: name, data: data });
});
}
};
ModAPI.events.newEvent("update", "client");
Expand Down Expand Up @@ -413,6 +435,10 @@ globalThis.modapi_postinit = `(() => {
ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.util.ChatComponentText")].constructors[0](jclString));
}
ModAPI.util.makeArray = function makeArray(arrayClass, arrayContents = []) {
return ModAPI.hooks._teavm.$rt_createArrayFromData(arrayClass, arrayContents);
}
ModAPI.clickMouse = function () {
ModAPI.hooks.methods["nmc_Minecraft_clickMouse"](ModAPI.javaClient);
}
Expand Down Expand Up @@ -442,7 +468,7 @@ globalThis.modapi_postinit = `(() => {
return x;
};
var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "createBlobObj");
var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "loadIntegratedServerSourceInline");
//Integrated server setup has a randomised suffix on the end
integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => { return key.startsWith(integratedServerStartup); })[0];
const integratedServerStartupMethod = ModAPI.hooks.methods[integratedServerStartup];
Expand Down
40 changes: 32 additions & 8 deletions postinit.js
Original file line number Diff line number Diff line change
Expand Up @@ -288,12 +288,25 @@
ModAPI.required = new Set();
ModAPI.events = {};
ModAPI.events.types = ["event"];
ModAPI.events.lib_map = {};
ModAPI.events.listeners = { "event": [] };
ModAPI.addEventListener = function addEventListener(name, callback) {
if (name.startsWith("lib:")) {
if (ModAPI.events.lib_map[name]) {
callback({});
} else {
if (!Array.isArray(ModAPI.events.listeners[name])) {
ModAPI.events.listeners[name] = [];
}
ModAPI.events.listeners[name].push(callback);
}
console.log("[ModAPI] Added new library listener.");
return;
}
if (!callback || typeof callback !== "function") {
throw new Error("[ModAPI] Invalid callback!");
}
if (ModAPI.events.types.includes(name) || name.startsWith("custom:")) {
if (ModAPI.events.types.includes(name) || name.startsWith("custom:") || name.startsWith("lib:")) {
if (!Array.isArray(ModAPI.events.listeners[name])) {
ModAPI.events.listeners[name] = [];
}
Expand Down Expand Up @@ -354,12 +367,19 @@
console.error("Please report this bug to the repo.");
return;
}
ModAPI.events.listeners[name].forEach((func) => {
func(data);
});
ModAPI.events.listeners.event.forEach((func) => {
func({ event: name, data: data });
});
if (name.startsWith("lib:")) {
ModAPI.events.listeners[name].forEach((func) => {
func({});
});
ModAPI.events.lib_map[name] = true;
} else {
ModAPI.events.listeners[name].forEach((func) => {
func(data);
});
ModAPI.events.listeners.event.forEach((func) => {
func({ event: name, data: data });
});
}
};
ModAPI.events.newEvent("update", "client");

Expand Down Expand Up @@ -415,6 +435,10 @@
ModAPI.hooks.methods["nmcg_GuiNewChat_printChatMessage"](ModAPI.javaClient.$ingameGUI.$persistantChatGUI, ModAPI.hooks._classMap[ModAPI.util.getCompiledName("net.minecraft.util.ChatComponentText")].constructors[0](jclString));
}

ModAPI.util.makeArray = function makeArray(arrayClass, arrayContents = []) {
return ModAPI.hooks._teavm.$rt_createArrayFromData(arrayClass, arrayContents);
}

ModAPI.clickMouse = function () {
ModAPI.hooks.methods["nmc_Minecraft_clickMouse"](ModAPI.javaClient);
}
Expand Down Expand Up @@ -444,7 +468,7 @@
return x;
};

var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "createBlobObj");
var integratedServerStartup = ModAPI.util.getMethodFromPackage("net.lax1dude.eaglercraft.v1_8.sp.internal.ClientPlatformSingleplayer", "loadIntegratedServerSourceInline");
//Integrated server setup has a randomised suffix on the end
integratedServerStartup = ModAPI.hooks._rippedMethodKeys.filter(key => { return key.startsWith(integratedServerStartup); })[0];
const integratedServerStartupMethod = ModAPI.hooks.methods[integratedServerStartup];
Expand Down

0 comments on commit b3752f2

Please sign in to comment.