Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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<EventResult> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,14 @@

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;
import net.minecraft.world.phys.Vec3;

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}.
Expand Down Expand Up @@ -107,14 +107,14 @@ public final class EntitySleepEvents {
*/
public static final Event<AllowBed> 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;
});

/**
Expand All @@ -124,14 +124,14 @@ public final class EntitySleepEvents {
*/
public static final Event<AllowNearbyMonsters> 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;
});

/**
Expand Down Expand Up @@ -251,48 +251,48 @@ public interface AllowBed {
/**
* Checks whether a block is a valid bed for the entity.
*
* <p>Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks.
* <p>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
public interface AllowSleepTime {
/**
* Checks whether the current time of day is valid for sleeping.
*
* <p>Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks.
* <p>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
public interface AllowNearbyMonsters {
/**
* Checks whether a player can sleep when monsters are nearby.
*
* <p>Non-{@linkplain InteractionResult#PASS passing} return values cancel further callbacks.
* <p>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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Boolean> 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());
}
}

Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand Down Expand Up @@ -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<Monster> 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
Expand Down Expand Up @@ -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) -> {
Expand All @@ -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) -> {
Expand Down
Loading