Skip to content

Commit

Permalink
Port fabric-entity-events-v1
Browse files Browse the repository at this point in the history
  • Loading branch information
Su5eD committed Jun 24, 2024
1 parent 843fd18 commit fa383e8
Show file tree
Hide file tree
Showing 15 changed files with 127 additions and 319 deletions.
2 changes: 1 addition & 1 deletion fabric-entity-events-v1/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ moduleDependencies(project, ['fabric-api-base'])

testDependencies(project, [
':fabric-command-api-v2',
':fabric-networking-api-v1',
// ':fabric-networking-api-v1',
':fabric-registry-sync-v0',
':fabric-rendering-v1'
])

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* 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.impl.entity.event;

import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents;
import net.fabricmc.fabric.api.entity.event.v1.ServerLivingEntityEvents;
import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.player.Player;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.event.entity.living.LivingAttackEvent;
import net.neoforged.neoforge.event.entity.living.LivingConversionEvent;
import net.neoforged.neoforge.event.entity.player.CanContinueSleepingEvent;
import net.neoforged.neoforge.event.entity.player.CanPlayerSleepEvent;
import net.neoforged.neoforge.event.entity.player.PlayerEvent;

@EventBusSubscriber
public final class EntityEventHooks {

@SubscribeEvent
public static void onLivingAttack(LivingAttackEvent event) {
LivingEntity entity = event.getEntity();
if (!entity.level().isClientSide() && !ServerLivingEntityEvents.ALLOW_DAMAGE.invoker().allowDamage(entity, event.getSource(), event.getAmount())) {
event.setCanceled(true);
}
}

@SubscribeEvent
public static void onPlayerSleepInBed(CanPlayerSleepEvent event) {
Player.BedSleepingProblem failureReason = EntitySleepEvents.ALLOW_SLEEPING.invoker().allowSleep(event.getEntity(), event.getPos());

if (failureReason != null) {
event.setProblem(failureReason);
}
}

@SubscribeEvent
public static void onPlayerSleepingTimeCheck(CanContinueSleepingEvent event) {
event.getEntity().getSleepingPos().ifPresent(sleepingPos -> {
if (event.getEntity() instanceof Player player) {
InteractionResult result = EntitySleepEvents.ALLOW_SLEEP_TIME.invoker().allowSleepTime(player, sleepingPos, !player.level().isDay());
if (result != InteractionResult.PASS) {
event.setContinueSleeping(result.consumesAction());
}
}
});
}

@SubscribeEvent
public static void onPlayerClone(PlayerEvent.Clone event) {
ServerPlayerEvents.COPY_FROM.invoker().copyFromPlayer((ServerPlayer) event.getOriginal(), (ServerPlayer) event.getEntity(), !event.isWasDeath());
}

@SubscribeEvent
public static void onLivingConversion(LivingConversionEvent.Post event) {
if (event.getEntity() instanceof Mob mobEntity && event.getOutcome() instanceof Mob converted) {
ServerLivingEntityEvents.MOB_CONVERSION.invoker().onConversion(mobEntity, converted, false);
}
}

private EntityEventHooks() {}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package net.fabricmc.fabric.mixin.entity.event;

import net.fabricmc.fabric.api.entity.event.v1.FabricElytraItem;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import net.neoforged.neoforge.common.extensions.IItemExtension;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

@Mixin(IItemExtension.class)
public interface IItemExtensionMixin {

@Inject(method = "canElytraFly", at = @At("HEAD"), cancellable = true)
default void canElytraFly(ItemStack stack, LivingEntity entity, CallbackInfoReturnable<Boolean> cir) {
cir.setReturnValue(this instanceof FabricElytraItem);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,18 @@

import java.util.Optional;

import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import com.llamalad7.mixinextras.injector.ModifyReturnValue;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Dynamic;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.ModifyArg;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
Expand All @@ -41,11 +44,8 @@
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.CollisionGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.BedBlock;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.Vec3;

Expand All @@ -64,7 +64,7 @@ private boolean onEntityKilledOther(Entity entity, ServerLevel serverWorld, @Nul
return result;
}

@Inject(method = "die", at = @At(value = "INVOKE", target = "net/minecraft/world/World.sendEntityStatus(Lnet/minecraft/entity/Entity;B)V"))
@Inject(method = "die", at = @At(value = "INVOKE", target = "net/minecraft/world/level/Level.broadcastEntityEvent(Lnet/minecraft/world/entity/Entity;B)V"))
private void notifyDeath(DamageSource source, CallbackInfo ci) {
ServerLivingEntityEvents.AFTER_DEATH.invoker().afterDeath((LivingEntity) (Object) this, source);
}
Expand Down Expand Up @@ -97,7 +97,7 @@ private void onWakeUp(CallbackInfo info) {
}

@Dynamic("method_18405: Synthetic lambda body for Optional.map in isSleepingInBed")
@Inject(method = "lambda$checkBedExists$7", at = @At("RETURN"), cancellable = true)
@Inject(method = "lambda$checkBedExists$10", 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());
Expand All @@ -107,46 +107,31 @@ private void onIsSleepingInBed(BlockPos sleepingPos, CallbackInfoReturnable<Bool
}
}

@WrapOperation(method = "getBedOrientation", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/BedBlock;getBedOrientation(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;)Lnet/minecraft/core/Direction;"))
private Direction onGetSleepingDirection(BlockGetter world, BlockPos sleepingPos, Operation<Direction> operation) {
final Direction sleepingDirection = operation.call(world, sleepingPos);
@ModifyReturnValue(method = "getBedOrientation", at = @At("TAIL"))
private Direction onGetSleepingDirection(Direction sleepingDirection, @Local BlockPos sleepingPos) {
return EntitySleepEvents.MODIFY_SLEEPING_DIRECTION.invoker().modifySleepDirection((LivingEntity) (Object) this, sleepingPos, sleepingDirection);
}

// This is needed 1) so that the vanilla logic in wakeUp runs for modded beds and 2) for the injector below.
// The injector is shared because method_18404 and sleep share much of the structure here.
@Dynamic("method_18404: Synthetic lambda body for Optional.ifPresent in wakeUp")
@ModifyVariable(method = {"lambda$stopSleeping$9", "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);
@ModifyExpressionValue(method = {"lambda$stopSleeping$9", "startSleeping"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;isBed(Lnet/minecraft/world/level/BlockGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/LivingEntity;)Z"))
private boolean modifyBedForOccupiedState(boolean vanillaResult, @Local(argsOnly = true) BlockPos sleepingPos, @Local BlockState state) {
InteractionResult result = EntitySleepEvents.ALLOW_BED.invoker().allowBed((LivingEntity) (Object) this, sleepingPos, state, vanillaResult);

// 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.consumesAction() || vanillaResult;
}

// The injector is shared because method_18404 and sleep share much of the structure here.
@Dynamic("method_18404: Synthetic lambda body for Optional.ifPresent in wakeUp")
@Redirect(method = {"lambda$stopSleeping$9", "startSleeping"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/Level;setBlockState(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/block/state/BlockState;I)Z"))
private boolean setOccupiedState(Level world, BlockPos pos, BlockState state, int flags) {
// This might have been replaced by a red bed above, so we get it again.
// Note that we *need* to replace it so the state.with(OCCUPIED, ...) call doesn't crash
// when the bed doesn't have the property.
BlockState originalState = world.getBlockState(pos);
boolean occupied = state.getValue(BedBlock.OCCUPIED);

if (EntitySleepEvents.SET_BED_OCCUPATION_STATE.invoker().setBedOccupationState((LivingEntity) (Object) this, pos, originalState, occupied)) {
return true;
} else if (originalState.hasProperty(BedBlock.OCCUPIED)) {
// This check is widened from (instanceof BedBlock) to a property check to allow modded blocks
// that don't use the event.
return world.setBlock(pos, originalState.setValue(BedBlock.OCCUPIED, occupied), flags);
} else {
return false;
}
@ModifyArg(method = {"lambda$stopSleeping$9", "startSleeping"}, at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/state/BlockState;setBedOccupied(Lnet/minecraft/world/level/Level;Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/entity/LivingEntity;Z)V"), index = 3)
private boolean setOccupiedState(boolean occupied, @Local BlockPos pos, @Local BlockState originalState) {
return occupied || EntitySleepEvents.SET_BED_OCCUPATION_STATE.invoker().setBedOccupationState((LivingEntity) (Object) this, pos, originalState, occupied);
}

@Dynamic("method_18404: Synthetic lambda body for Optional.ifPresent in wakeUp")
@Redirect(method = "lambda$stopSleeping$9", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/BedBlock;findStandUpPosition(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/level/CollisionGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/Direction;F)Ljava/util/Optional;"))
@Redirect(method = "lambda$stopSleeping$12", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/level/block/BedBlock;findStandUpPosition(Lnet/minecraft/world/entity/EntityType;Lnet/minecraft/world/level/CollisionGetter;Lnet/minecraft/core/BlockPos;Lnet/minecraft/core/Direction;F)Ljava/util/Optional;"))
private Optional<Vec3> modifyWakeUpPosition(EntityType<?> type, CollisionGetter world, BlockPos pos, Direction direction, float yaw) {
Optional<Vec3> original = Optional.empty();
BlockState bedState = world.getBlockState(pos);
Expand Down

This file was deleted.

This file was deleted.

Loading

0 comments on commit fa383e8

Please sign in to comment.