diff --git a/fabric-api-base/src/main/java/net/fabricmc/fabric/api/util/EventResult.java b/fabric-api-base/src/main/java/net/fabricmc/fabric/api/util/EventResult.java new file mode 100644 index 00000000000..2c5d5364c58 --- /dev/null +++ b/fabric-api-base/src/main/java/net/fabricmc/fabric/api/util/EventResult.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2016, 2017, 2018, 2019 FabricMC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package net.fabricmc.fabric.api.util; + +import com.mojang.serialization.Codec; + +import net.minecraft.util.StringRepresentable; + +/** + * Represents a result of an event that controls execution of some action. + */ +public enum EventResult implements StringRepresentable { + /** + * Prevents further event handling, while allowing related action. + */ + ALLOW("allow"), + /** + * Continues execution of further events. + * In case of being returned by a final callback, it might either act the same as ALLOW + * or execute additional logic to determine the outcome. + */ + PASS("pass"), + /** + * Prevents further event handling, while also preventing related action. + */ + DENY("deny"); + + public static final Codec CODEC = StringRepresentable.fromEnum(EventResult::values); + + private final String name; + + /** + * Checks whatever action should be allowed. + * @return true if it's allowed, otherwise false. + */ + public boolean allowAction() { + return this != DENY; + } + + /** + * Checks whatever action should be allowed, with custom return value for {@link EventResult#PASS}. + * @return true if it's allowed, otherwise false. + */ + public boolean allowAction(boolean passResult) { + return switch (this) { + case PASS -> passResult; + case ALLOW -> true; + case DENY -> false; + }; + } + + /** + * Value of this enum as string. + * + * @return lowercase name of the value. + */ + @Override + public String getSerializedName() { + return this.name; + } + + EventResult(String name) { + this.name = name; + } +} diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/EntitySleepEvents.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/EntitySleepEvents.java index fc968c990f8..6d1b375bb55 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/EntitySleepEvents.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/api/entity/event/v1/EntitySleepEvents.java @@ -20,7 +20,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; -import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.state.BlockState; @@ -28,6 +27,7 @@ import net.fabricmc.fabric.api.event.Event; import net.fabricmc.fabric.api.event.EventFactory; +import net.fabricmc.fabric.api.util.EventResult; /** * Events about the sleep of {@linkplain LivingEntity living entities}. @@ -107,14 +107,14 @@ public final class EntitySleepEvents { */ public static final Event ALLOW_BED = EventFactory.createArrayBacked(AllowBed.class, callbacks -> (entity, sleepingPos, state, vanillaResult) -> { for (AllowBed callback : callbacks) { - InteractionResult result = callback.allowBed(entity, sleepingPos, state, vanillaResult); + EventResult result = callback.allowBed(entity, sleepingPos, state, vanillaResult); - if (result != InteractionResult.PASS) { + if (result != EventResult.PASS) { return result; } } - return InteractionResult.PASS; + return EventResult.PASS; }); /** @@ -124,14 +124,14 @@ public final class EntitySleepEvents { */ public static final Event ALLOW_NEARBY_MONSTERS = EventFactory.createArrayBacked(AllowNearbyMonsters.class, callbacks -> (player, sleepingPos, vanillaResult) -> { for (AllowNearbyMonsters callback : callbacks) { - InteractionResult result = callback.allowNearbyMonsters(player, sleepingPos, vanillaResult); + EventResult result = callback.allowNearbyMonsters(player, sleepingPos, vanillaResult); - if (result != InteractionResult.PASS) { + if (result != EventResult.PASS) { return result; } } - return InteractionResult.PASS; + return EventResult.PASS; }); /** @@ -251,16 +251,16 @@ public interface AllowBed { /** * Checks whether a block is a valid bed for the entity. * - *

Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks. + *

Non-{@linkplain EventResult#PASS passing} return values cancel further callbacks. * * @param entity the sleeping entity * @param sleepingPos the position of the block * @param state the block state to check * @param vanillaResult {@code true} if vanilla allows the block, {@code false} otherwise - * @return {@link InteractionResult#SUCCESS} if the bed is valid, {@link InteractionResult#FAIL} if it's not, - * {@link InteractionResult#PASS} to fall back to other callbacks + * @return {@link EventResult#ALLOW} if the bed is valid, {@link EventResult#DENY} if it's not, + * {@link EventResult#PASS} to fall back to other callbacks */ - InteractionResult allowBed(LivingEntity entity, BlockPos sleepingPos, BlockState state, boolean vanillaResult); + EventResult allowBed(LivingEntity entity, BlockPos sleepingPos, BlockState state, boolean vanillaResult); } @FunctionalInterface @@ -268,15 +268,15 @@ public interface AllowSleepTime { /** * Checks whether the current time of day is valid for sleeping. * - *

Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks. + *

Non-{@linkplain EventResult#PASS passing} return values cancel further callbacks. * * @param player the sleeping player * @param sleepingPos the (possibly still unset) {@linkplain LivingEntity#getSleepingPos() sleeping position} of the player * @param vanillaResult {@code true} if vanilla allows the time, {@code false} otherwise - * @return {@link InteractionResult#SUCCESS} if the time is valid, {@link InteractionResult#FAIL} if it's not, - * {@link InteractionResult#PASS} to fall back to other callbacks + * @return {@link EventResult#ALLOW} if the time is valid, {@link EventResult#DENY} if it's not, + * {@link EventResult#PASS} to fall back to other callbacks */ - InteractionResult allowSleepTime(Player player, BlockPos sleepingPos, boolean vanillaResult); + EventResult allowSleepTime(Player player, BlockPos sleepingPos, boolean vanillaResult); } @FunctionalInterface @@ -284,15 +284,15 @@ public interface AllowNearbyMonsters { /** * Checks whether a player can sleep when monsters are nearby. * - *

Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks. + *

Non-{@linkplain EventResult#PASS passing} return values cancel further callbacks. * * @param player the sleeping player * @param sleepingPos the (possibly still unset) {@linkplain LivingEntity#getSleepingPos() sleeping position} of the player * @param vanillaResult {@code true} if vanilla's monster check succeeded (there were no monsters), {@code false} otherwise - * @return {@link InteractionResult#SUCCESS} to allow sleeping, {@link InteractionResult#FAIL} to prevent sleeping, - * {@link InteractionResult#PASS} to fall back to other callbacks + * @return {@link EventResult#ALLOW} to allow sleeping, {@link EventResult#DENY} to prevent sleeping, + * {@link EventResult#PASS} to fall back to other callbacks */ - InteractionResult allowNearbyMonsters(Player player, BlockPos sleepingPos, boolean vanillaResult); + EventResult allowNearbyMonsters(Player player, BlockPos sleepingPos, boolean vanillaResult); } @FunctionalInterface diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java index 61f297b18b4..10e9acdddef 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/LivingEntityMixin.java @@ -35,7 +35,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.EntityType; @@ -51,6 +50,7 @@ import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerEntityCombatEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents; +import net.fabricmc.fabric.api.util.EventResult; @Mixin(LivingEntity.class) abstract class LivingEntityMixin { @@ -110,10 +110,10 @@ private void onWakeUp(CallbackInfo info) { @Inject(method = "lambda$checkBedExists$0", at = @At("RETURN"), cancellable = true) private void onIsSleepingInBed(BlockPos sleepingPos, CallbackInfoReturnable info) { BlockState bedState = ((LivingEntity) (Object) this).level().getBlockState(sleepingPos); - InteractionResult result = EntitySleepEvents.ALLOW_BED.invoker().allowBed((LivingEntity) (Object) this, sleepingPos, bedState, info.getReturnValueZ()); + EventResult result = EntitySleepEvents.ALLOW_BED.invoker().allowBed((LivingEntity) (Object) this, sleepingPos, bedState, info.getReturnValueZ()); - if (result != InteractionResult.PASS) { - info.setReturnValue(result.consumesAction()); + if (result != EventResult.PASS) { + info.setReturnValue(result.allowAction()); } } @@ -128,10 +128,10 @@ private Direction onGetSleepingDirection(BlockGetter level, BlockPos sleepingPos @Dynamic("lambda$stopSleeping$0: Synthetic lambda body for Optional.ifPresent in stopSleeping") @ModifyVariable(method = {"lambda$stopSleeping$0", "startSleeping"}, at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/level/Level;getBlockState(Lnet/minecraft/core/BlockPos;)Lnet/minecraft/world/level/block/state/BlockState;")) private BlockState modifyBedForOccupiedState(BlockState state, BlockPos sleepingPos) { - InteractionResult result = EntitySleepEvents.ALLOW_BED.invoker().allowBed((LivingEntity) (Object) this, sleepingPos, state, state.getBlock() instanceof BedBlock); + EventResult result = EntitySleepEvents.ALLOW_BED.invoker().allowBed((LivingEntity) (Object) this, sleepingPos, state, state.getBlock() instanceof BedBlock); // If a valid bed, replace with vanilla red bed so that the vanilla instanceof check succeeds. - return result.consumesAction() ? Blocks.RED_BED.defaultBlockState() : state; + return result.allowAction(false) ? Blocks.RED_BED.defaultBlockState() : state; } // The injector is shared because lambda$stopSleeping$23 and sleep share much of the structure here. diff --git a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/ServerPlayerMixin.java b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/ServerPlayerMixin.java index 8d82f829250..4eb056340b6 100644 --- a/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/ServerPlayerMixin.java +++ b/fabric-entity-events-v1/src/main/java/net/fabricmc/fabric/mixin/entity/event/ServerPlayerMixin.java @@ -35,7 +35,6 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.util.Unit; -import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; @@ -49,6 +48,7 @@ import net.fabricmc.fabric.api.entity.event.v1.ServerEntityLevelChangeEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import net.fabricmc.fabric.api.util.EventResult; @Mixin(ServerPlayer.class) abstract class ServerPlayerMixin extends LivingEntityMixin { @@ -111,7 +111,7 @@ private void onSetSpawnPoint(ServerPlayer player, ServerPlayer.RespawnConfig spa @Redirect(method = "startSleepInBed", at = @At(value = "INVOKE", target = "Ljava/util/List;isEmpty()Z")) private boolean hasNoMonstersNearby(List monsters, BlockPos pos) { boolean vanillaResult = monsters.isEmpty(); - InteractionResult result = EntitySleepEvents.ALLOW_NEARBY_MONSTERS.invoker().allowNearbyMonsters((Player) (Object) this, pos, vanillaResult); - return result != InteractionResult.PASS ? result.consumesAction() : vanillaResult; + EventResult result = EntitySleepEvents.ALLOW_NEARBY_MONSTERS.invoker().allowNearbyMonsters((Player) (Object) this, pos, vanillaResult); + return result.allowAction(vanillaResult); } } diff --git a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java index d0eca3adf7b..515403f5b70 100644 --- a/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java +++ b/fabric-entity-events-v1/src/testmod/java/net/fabricmc/fabric/test/entity/event/EntityEventTests.java @@ -32,7 +32,6 @@ import net.minecraft.sounds.SoundEvents; import net.minecraft.util.Unit; import net.minecraft.world.InteractionHand; -import net.minecraft.world.InteractionResult; import net.minecraft.world.damagesource.DamageTypes; import net.minecraft.world.entity.EquipmentSlot; import net.minecraft.world.entity.player.Inventory; @@ -56,6 +55,7 @@ import net.fabricmc.fabric.api.entity.event.v1.ServerEntityLevelChangeEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents; import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; +import net.fabricmc.fabric.api.util.EventResult; public final class EntityEventTests implements ModInitializer { private static final Logger LOGGER = LoggerFactory.getLogger(EntityEventTests.class); @@ -174,7 +174,7 @@ public void onInitialize() { }); EntitySleepEvents.ALLOW_BED.register((entity, sleepingPos, state, vanillaResult) -> { - return state.is(TEST_BED) ? InteractionResult.SUCCESS : InteractionResult.PASS; + return state.is(TEST_BED) ? EventResult.ALLOW : EventResult.PASS; }); EntitySleepEvents.MODIFY_SLEEPING_DIRECTION.register((entity, sleepingPos, sleepingDirection) -> { @@ -186,12 +186,12 @@ public void onInitialize() { ItemStack stack = player.getItemInHand(InteractionHand.MAIN_HAND); if (stack.is(Items.GREEN_WOOL)) { - return InteractionResult.SUCCESS; + return EventResult.ALLOW; } else if (stack.is(Items.RED_WOOL)) { - return InteractionResult.FAIL; + return EventResult.DENY; } - return InteractionResult.PASS; + return EventResult.PASS; }); EntitySleepEvents.ALLOW_SETTING_SPAWN.register((player, sleepingPos) -> {