Skip to content

Commit

Permalink
feat(coremod): LivingFoodEffectEvent
Browse files Browse the repository at this point in the history
Co-authored-by: lainio24 <lainio24@outlook.com>
  • Loading branch information
WakelessSloth56 and lainio24 committed Feb 14, 2024
1 parent 2443650 commit 9f89e84
Show file tree
Hide file tree
Showing 4 changed files with 355 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.RandomSource;
import net.minecraft.world.effect.MobEffectInstance;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.projectile.Projectile;
Expand All @@ -31,6 +32,7 @@
import org.auioc.mcmod.arnicalib.mod.server.event.AHServerEventFactory;

import javax.annotation.Nullable;
import java.util.List;

public class AHCoreModHandler {

Expand Down Expand Up @@ -62,4 +64,14 @@ public static int onItemHurt(ItemStack itemStack, int damage, RandomSource rando
return AHServerEventFactory.onItemHurt(itemStack, damage, random, player).getDamage();
}

/**
* @see <code>coremod: arnicalib.living_entity.add_eat_effect<code/>
*/
public static void onLivingEatAddEffect(LivingEntity living, ItemStack food, List<MobEffectInstance> effects) {
var newEffects = AHServerEventFactory.onLivingEatAddEffect(living, food, effects);
for (var effect : newEffects) {
living.addEffect(effect);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ public static ItemHurtEvent onItemHurt(ItemStack itemStack, int damage, RandomSo
return BUS.post(event);
}

/**
* @see AHCoreModHandler#onLivingEatAddEffect
*/
public static List<MobEffectInstance> onLivingEatAddEffect(LivingEntity living, ItemStack food, List<MobEffectInstance> effects) {
var event = new LivingFoodEffectEvent(living, food, effects);
BUS.post(event);
Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/META-INF/coremods.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
"arnicalib.cross_bow_item.shoot_projectile": "coremods/cross_bow_item.shoot_projectile.js",
"arnicalib.fishing_rod_item.use": "coremods/fishing_rod_item.use.js",
"arnicalib.piston_base_block.is_pushable": "coremods/piston_base_block.is_pushable.js",
"arnicalib.item_stack.hurt": "coremods/item_stack.hurt.js"
"arnicalib.item_stack.hurt": "coremods/item_stack.hurt.js",
"arnicalib.living_entity.add_eat_effect": "coremods/living_entity.add_eat_effect.js"
}
338 changes: 338 additions & 0 deletions src/main/resources/coremods/living_entity.add_eat_effect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,338 @@
function initializeCoreMod() {
var ASMAPI = Java.type('net.neoforged.coremod.api.ASMAPI');
var Opcodes = Java.type('org.objectweb.asm.Opcodes');
var InsnList = Java.type('org.objectweb.asm.tree.InsnList');
var InsnNode = Java.type('org.objectweb.asm.tree.InsnNode');
var LabelNode = Java.type('org.objectweb.asm.tree.LabelNode');
var FrameNode = Java.type('org.objectweb.asm.tree.FrameNode');
var VarInsnNode = Java.type('org.objectweb.asm.tree.VarInsnNode');
var JumpInsnNode = Java.type('org.objectweb.asm.tree.JumpInsnNode');
var TypeInsnNode = Java.type('org.objectweb.asm.tree.TypeInsnNode');
var FieldInsnNode = Java.type('org.objectweb.asm.tree.FieldInsnNode');
var MethodInsnNode = Java.type('org.objectweb.asm.tree.MethodInsnNode');
var LocalVariableNode = Java.type('org.objectweb.asm.tree.LocalVariableNode');

function findEndLabelNode(instructions) {
for (var i = instructions.size() - 1; i > -1; i--) {
var node = instructions.get(i);
if (
node instanceof InsnNode
&& node.getOpcode() === Opcodes.RETURN
) {
return instructions.get(i - 3);
}
}
}

function findInsertAfterNode(instructions) {
for (var i = 0; i < instructions.size(); i++) {
var node = instructions.get(i);
if (
node instanceof MethodInsnNode
&& node.owner === 'net/minecraft/world/item/Item'
&& node.name === 'isEdible'
) {
return instructions.get(i + 1);
}
}
}

function findInsertisClient(instructions) {
for (var i = instructions.size() - 1; i > -1; i--) {
var node = instructions.get(i);
if (
node instanceof FieldInsnNode
&& node.getOpcode() === Opcodes.GETFIELD
&& node.owner === 'net/minecraft/world/level/Level'
&& node.name === 'isClientSide'
) {
return [instructions.get(i - 1), node, instructions.get(i + 1)];
}
}
}

function findVarAload3(instructions) {
for (var i = instructions.size() - 1; i > -1; i--) {
var node = instructions.get(i);
if (
node instanceof VarInsnNode
&& node.getOpcode() === Opcodes.ALOAD
&& node.var === 3
) {
return node;
}
}
}

function findLoopEndJump(instructions) {
for (var i = 0; i < instructions.size(); i++) {
var node = instructions.get(i);
if (
node instanceof MethodInsnNode
&& node.owner === 'java/util/Iterator'
&& node.name === 'hasNext'
) {
return instructions.get(i + 1);
}
}
}

function findInvokeAddEffect(instructions) {
for (var i = instructions.size() - 1; i > -1; i--) {
var node = instructions.get(i);
if (
node instanceof MethodInsnNode
&& node.owner === 'net/minecraft/world/entity/LivingEntity'
&& node.name === 'addEffect'
) {
return node;
}
}
}

return {
'LivingEntity#addEatEffect': {
target: {
type: 'METHOD',
class: 'net.minecraft.world.entity.LivingEntity',
methodName: 'addEatEffect',
methodDesc: '(Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/level/Level;Lnet/minecraft/world/entity/LivingEntity;)V'
},
transformer: function (methodNode) {
var instructions = methodNode.instructions;


var toRemove = findInsertisClient(instructions);
toRemove.forEach(function (node) {
instructions.remove(node);
});

var startLabel = new LabelNode();
var endLabel = findEndLabelNode(instructions);

methodNode.localVariables.add(
new LocalVariableNode(
'effects',
'Ljava/util/ArrayList;',
'Ljava/util/ArrayList<Lnet/minecraft/world/effect/MobEffectInstance;>;',
startLabel,
endLabel,
7
)
);

var insnList1 = new InsnList();
{
insnList1.add(new VarInsnNode(Opcodes.ALOAD, 2));
insnList1.add(
new FieldInsnNode(
Opcodes.GETFIELD,
'net/minecraft/world/level/Level',
'isClientSide',
'Z'
)
);
insnList1.add(new JumpInsnNode(Opcodes.IFNE, endLabel));
insnList1.add(startLabel);
insnList1.add(
new TypeInsnNode(
Opcodes.NEW,
'java/util/ArrayList'
)
);
insnList1.add(new InsnNode(Opcodes.DUP));
insnList1.add(new MethodInsnNode(
Opcodes.INVOKESPECIAL,
'java/util/ArrayList',
'<init>',
'()V',
false
)
);
insnList1.add(new VarInsnNode(Opcodes.ASTORE, 7));
}
var insertAfter = findInsertAfterNode(instructions);
methodNode.instructions.insert(insertAfter, insnList1);

var aload3 = findVarAload3(instructions);
instructions.set(
aload3,
new VarInsnNode(Opcodes.ALOAD, 7)
);

var invokeAddEffect = findInvokeAddEffect(instructions);
instructions.set(
invokeAddEffect,
new MethodInsnNode(
Opcodes.INVOKEVIRTUAL,
'java/util/ArrayList',
'add',
'(Ljava/lang/Object;)Z',
false
)
);

var loopEndLabel = new LabelNode();

var loopEndJump = findLoopEndJump(instructions);
instructions.set(
loopEndJump,
new JumpInsnNode(Opcodes.IFEQ, loopEndLabel)
);

var insnList2 = new InsnList();
{
insnList2.add(loopEndLabel);
insnList2.add(new FrameNode(Opcodes.F_CHOP, 1, null, 0, null));
insnList2.add(new VarInsnNode(Opcodes.ALOAD, 3));
insnList2.add(new VarInsnNode(Opcodes.ALOAD, 1));
insnList2.add(new VarInsnNode(Opcodes.ALOAD, 7));
insnList2.add(new MethodInsnNode(
Opcodes.INVOKESTATIC,
'org/auioc/mcmod/arnicalib/mod/coremod/AHCoreModHandler',
'onLivingEatAddEffect',
'(Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Ljava/util/List;)V',
false
)
);
}
methodNode.instructions.insertBefore(endLabel, insnList2);

methodNode.visitMaxs(4, 8);

print(ASMAPI.methodNodeToString(methodNode));
return methodNode;
}
}
};
}


//! LocalVariableTable
/*
Slot Name Signature
1 pFood Lnet/minecraft/world/item/ItemStack;
2 pLevel Lnet/minecraft/world/level/Level;
3 pLivingEntity Lnet/minecraft/world/entity/LivingEntity;
+ 7 effects Ljava/util/ArrayList<Lnet/minecraft/world/effect/MobEffectInstance;>;
*/

//! Code
/*
private void addEatEffect(ItemStack pFood, Level pLevel, LivingEntity pLivingEntity) {
Item item = pFood.getItem();
- if (item.isEdible()) {
+ if (item.isEdible() && !pLevel.isClientSide) {
+ ArrayList effects = new ArrayList();
for(Pair<MobEffectInstance, Float> pair : pFood.getFoodProperties(this).getEffects()) {
- if (!pLevel.isClientSide && pair.getFirst() != null && pLevel.random.nextFloat() < pair.getSecond()) {
+ if (pair.getFirst() != null && pLevel.random.nextFloat() < (Float)pair.getSecond()) {
- pLivingEntity.addEffect(new MobEffectInstance(pair.getFirst()));
+ effects.add(new MobEffectInstance(pair.getFirst()));
}
}
+ AHCoreModHandler.onLivingEatAddEffect(pLivingEntity, pFood, effects);
}
}
* ========== ByteCode ========== *
L0
LINENUMBER 3608 L0
ALOAD 1
INVOKEVIRTUAL net/minecraft/world/item/ItemStack.getItem ()Lnet/minecraft/world/item/Item;
ASTORE 4
L1
LINENUMBER 3609 L1
ALOAD 4
INVOKEVIRTUAL net/minecraft/world/item/Item.isEdible ()Z
IFEQ L2
+ ALOAD 2
+ GETFIELD net/minecraft/world/level/Level.isClientSide : Z
+ IFNE L2
L3
- LINENUMBER 3610 L3
+ NEW java/util/ArrayList
+ DUP
+ INVOKESPECIAL java/util/ArrayList.<init> ()V
+ ASTORE 7
+ L4
+ LINENUMBER 3610 L4
ALOAD 1
ALOAD 0
INVOKEVIRTUAL net/minecraft/world/item/ItemStack.getFoodProperties (Lnet/minecraft/world/entity/LivingEntity;)Lnet/minecraft/world/food/FoodProperties;
INVOKEVIRTUAL net/minecraft/world/food/FoodProperties.getEffects ()Ljava/util/List;
INVOKEINTERFACE java/util/List.iterator ()Ljava/util/Iterator; (itf)
ASTORE 5
- L4
+ L5
FRAME APPEND [net/minecraft/world/item/Item java/util/Iterator]
ALOAD 5
INVOKEINTERFACE java/util/Iterator.hasNext ()Z (itf)
- IFEQ L2
+ IFEQ L6
ALOAD 5
INVOKEINTERFACE java/util/Iterator.next ()Ljava/lang/Object; (itf)
CHECKCAST com/mojang/datafixers/util/Pair
ASTORE 6
- L5
- LINENUMBER 3611 L5
- ALOAD 2
- GETFIELD net/minecraft/world/level/Level.isClientSide : Z
- IFNE L6
+ L7
+ LINENUMBER 3611 L7
ALOAD 6
INVOKEVIRTUAL com/mojang/datafixers/util/Pair.getFirst ()Ljava/lang/Object;
- IFNULL L6
+ IFNULL L8
ALOAD 2
GETFIELD net/minecraft/world/level/Level.random : Lnet/minecraft/util/RandomSource;
INVOKEINTERFACE net/minecraft/util/RandomSource.nextFloat ()F (itf)
ALOAD 6
INVOKEVIRTUAL com/mojang/datafixers/util/Pair.getSecond ()Ljava/lang/Object;
CHECKCAST java/lang/Float
INVOKEVIRTUAL java/lang/Float.floatValue ()F
FCMPG
- IFGE L6
- L7
- LINENUMBER 3612 L7
- ALOAD 3
+ IFGE L8
+ L9
+ LINENUMBER 3612 L9
+ ALOAD 7
NEW net/minecraft/world/effect/MobEffectInstance
DUP
ALOAD 6
INVOKEVIRTUAL com/mojang/datafixers/util/Pair.getFirst ()Ljava/lang/Object;
CHECKCAST net/minecraft/world/effect/MobEffectInstance
INVOKESPECIAL net/minecraft/world/effect/MobEffectInstance.<init> (Lnet/minecraft/world/effect/MobEffectInstance;)V
- INVOKEVIRTUAL net/minecraft/world/entity/LivingEntity.addEffect (Lnet/minecraft/world/effect/MobEffectInstance;)Z
+ INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
POP
- L6
- LINENUMBER 3614 L6
+ L8
+ LINENUMBER 3614 L8
FRAME SAME
- GOTO L4
+ GOTO L5
+ L6
+ FRAME CHOP 1
+ ALOAD 3
+ ALOAD 1
+ ALOAD 7
+ INVOKESTATIC org/auioc/mcmod/arnicalib/mod/coremod/AHCoreModHandler.onLivingEatAddEffect (Lnet/minecraft/world/entity/LivingEntity;Lnet/minecraft/world/item/ItemStack;Ljava/util/List;)V
L2
LINENUMBER 3616 L2
FRAME CHOP 1
RETURN
- L8
+ L10
//_ ...
+ LOCALVARIABLE effects Ljava/util/ArrayList; L3 L2 7
+ // signature Ljava/util/ArrayList<Lnet/minecraft/world/effect/MobEffectInstance;>;
+ // declaration: effects extends java.util.ArrayList<net.minecraft.world.effect.MobEffectInstance>
MAXSTACK = 4
- MAXLOCALS = 7
+ MAXLOCALS = 8
*/

0 comments on commit 9f89e84

Please sign in to comment.