Skip to content

Commit

Permalink
player eat
Browse files Browse the repository at this point in the history
  • Loading branch information
valoeghese committed Aug 22, 2020
1 parent 5a40bc3 commit 57afbe0
Show file tree
Hide file tree
Showing 9 changed files with 153 additions and 9 deletions.
Empty file added logs/latest.log
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package io.github.fabriccommunity.events.impl;

import java.util.concurrent.atomic.AtomicReference;

import io.github.fabriccommunity.events.play.ItemEvents;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;

/**
* Some longer mixin implementations are done in classes such as this one in order to make debugging easier.
*/
public final class InteractionsImpl {
private InteractionsImpl() {
}

public static ItemStack eatFood(LivingEntity self, World world, ItemStack original) {
AtomicReference<ItemStack> eaten = new AtomicReference<>(original);
AtomicReference<ItemStack> moddedResultReference = new AtomicReference<>();
ActionResult eventResult = ItemEvents.EAT_FOOD.invoker().onPlayerEat(self, world, original, eaten, moddedResultReference);

ItemStack defaultResult = eventResult == ActionResult.FAIL ? original : self.eatFood(world, eaten.get());
ItemStack moddedResult = moddedResultReference.get();
return moddedResult == null ? defaultResult : moddedResult;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package io.github.fabriccommunity.events.mixin.item;

import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;

import io.github.fabriccommunity.events.impl.InteractionsImpl;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.world.World;

@Mixin(Item.class)
public class MixinItem {
@Redirect(
at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/LivingEntity;eatFood(Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;)Lnet/minecraft/item/ItemStack;"),
method = "finishUsing"
)
private ItemStack onEatFood(LivingEntity self, World world, ItemStack original) {
return InteractionsImpl.eatFood(self, world, original);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ public interface AttackKeyPress {
* @param hitResult the result of the hit (miss/block/entity), might be null.
*
* @return
* {@code SUCCESS} or {@code CONSUME} cancels further event processing and swings the player's arms.
* {@code PASS} pass event handling on to further processing. If all listeners pass, vanilla behavior is executed instead.
* {@code FAIL} cancels further event processing without swinging the player's arms.
* <ul>
* <li>{@code SUCCESS} or {@code CONSUME} cancels further event processing and swings the player's arms.
* <li>{@code PASS} pass event handling on to further processing. If all listeners pass, vanilla behavior is executed instead.
* <li>{@code FAIL} cancels further event processing without swinging the player's arms.
* </ul>
*/
ActionResult onAttackKeyPress(ClientPlayerEntity player, /* @Nullable */ HitResult hitResult);
}
Expand All @@ -70,9 +72,11 @@ public interface AttackKeyHold {
* @param hitResult the result of the hit (miss/block/entity), might be null.
*
* @return
* {@code SUCCESS} or {@code CONSUME} cancels further event processing and swings the player's arms.
* {@code PASS} pass event handling on to further processing. If all listeners pass, vanilla behavior is executed instead.
* {@code FAIL} cancels further event processing without swinging the player's arms.
* <ul>
* <li>{@code SUCCESS} or {@code CONSUME} cancels further event processing and swings the player's arms.
* <li>{@code PASS} pass event handling on to further processing. If all listeners pass, vanilla behavior is executed instead.
* <li>{@code FAIL} cancels further event processing without swinging the player's arms.
* </ul>
*/
ActionResult onAttackKeyHold(ClientPlayerEntity player, /* @Nullable */ HitResult hitResult);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package io.github.fabriccommunity.events.play;

import java.util.concurrent.atomic.AtomicReference;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.ActionResult;
import net.minecraft.world.World;

/**
* Collection of events pertaining to items and item stacks in gameplay.
*/
public final class ItemEvents {
/**
* An event which runs when an entity tries to eat food.
*/
public static final Event<EatFood> EAT_FOOD = EventFactory.createArrayBacked(EatFood.class, listeners -> (entity, world, original, eaten, result) -> {
for (EatFood listener : listeners) {
ActionResult eventResult = listener.onPlayerEat(entity, world, original, eaten, result);

if (eventResult != ActionResult.PASS) {
return eventResult;
}
}

return ActionResult.PASS;
});

/**
* Called when an entity tries to eat an item.
* @author Valoeghese
*/
@FunctionalInterface
public interface EatFood {
/**
* @param entity the entity eating the food.
* @param world the world the entity is eating the food in.
* @param original the original stack of food to be eaten.
* @param eaten the stack of food which is to be eaten. If the value stored herein differs from {@code original}, the value has been modded.<br/>
* @param result {@code null} by default. if {@code null}, the stack returned from eating will be the result of the eat method.
* If this is altered the resulting stack will be the item stored in here, regardless of whether the event fails.<br/>
* @return
* <ul>
* <li>{@code SUCCESS} or {@code CONSUME} to cancel further event processing and eat the food in {@code stack}<br/>
* <li>{@code PASS} pass event handling on to further processing. If all listeners pass, it is treated as a {@code SUCCESS}.
* <li>{@code FAIL} to cancel further event processing and do not eat the food.
* </ul>
*/
ActionResult onPlayerEat(LivingEntity entity, World world, final ItemStack original, AtomicReference<ItemStack> eaten, AtomicReference<ItemStack> result);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
* A collection of events for player interaction.
*/
public final class PlayerInteractionEvents {
/**
* An event which runs when the player picks up experience.
*/
public static final Event<XPGain> XP_GAIN = EventFactory.createArrayBacked(XPGain.class, listeners -> (player, original, experience) -> {
for (XPGain listener : listeners) {
ActionResult result = listener.onXPGained(player, original, experience);
Expand All @@ -34,9 +37,11 @@ public interface XPGain {
* @param original the original experience to be gained.
* @param experience the experience which will be gained. If the value stored in this is different to {@code original}, a mod has modified the experience gained.
* @return
* {@code SUCCESS} or {@code CONSUME} to cancel further event processing and add the experience in {@code experience}.
* {@code PASS} pass event handling on to further processing. If all listeners pass, it is treated as a {@code SUCCESS}.
* {@code FAIL} to cancel further event processing and add the original experience.
* <ul>
* <li>{@code SUCCESS} or {@code CONSUME} to cancel further event processing and add the experience in {@code experience}.<br/>
* <li>{@code PASS} pass event handling on to further processing. If all listeners pass, it is treated as a {@code SUCCESS}.
* <li>{@code FAIL} to cancel further event processing and add the original experience.
* </ul>
*/
ActionResult onXPGained(PlayerEntity player, final int original, AtomicInteger experience);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/resources/toomanyevents.mixins.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
"biomegen.MixinMultiNoiseBiomeSource",
"biomegen.MixinTheEndBiomeSource",
"biomegen.MixinVanillaLayeredBiomeSource",
"item.MixinItem",
"player.MixinPlayerEntity",
"player.MixinPlayerManager",
"spawn.MixinEntityType",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.github.fabriccommunity.events.test;

import io.github.fabriccommunity.events.play.ItemEvents;
import net.fabricmc.api.ModInitializer;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.util.ActionResult;

public class EatFoodTest implements ModInitializer {
public static final boolean ENABLED = true;

@Override
public void onInitialize() {
if (ENABLED) {
// This code makes potatoes behave as if they were golden apples.
ItemEvents.EAT_FOOD.register((entity, world, original, eaten, result) -> {
if (original.getItem() == Items.POTATO) {
eaten.set(new ItemStack(Items.GOLDEN_APPLE)); // use golden apple eat effects
// Make it return what it would be if the original had been eaten.
// Otherwise it will return nothing due to eating a stack of 1 golden apples giving back 0 golden apples, which is nothing.
ItemStack resultstk = original.copy();
resultstk.decrement(1);
result.set(resultstk); //
return ActionResult.SUCCESS;
}

return ActionResult.PASS;
});
}
}
}
1 change: 1 addition & 0 deletions src/test/resources/fabric.mod.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
"entrypoints": {
"main": [
"io.github.fabriccommunity.events.test.BiomePlacementTest",
"io.github.fabriccommunity.events.test.EatFoodTest",
"io.github.fabriccommunity.events.test.EntitySpawnTest",
"io.github.fabriccommunity.events.test.PlayerInteractionTest"
],
Expand Down

0 comments on commit 57afbe0

Please sign in to comment.