Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add AllowWorldChange, AllowTeleport and AfterTeleport #4089

Closed
wants to merge 6 commits into from
Closed
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
Expand Up @@ -45,6 +45,19 @@ public final class ServerEntityWorldChangeEvents {
}
});

/**
* Called before a player is being moved to a different world.
*/
public static final Event<AllowPlayerChange> ALLOW_PLAYER_CHANGE_WORLD = EventFactory.createArrayBacked(AllowPlayerChange.class, callbacks -> (player, origin, destination) -> {
for (AllowPlayerChange callback : callbacks) {
if (!callback.allowChangeWorld(player, origin, destination)){
return false;
}
}

return true;
});

/**
* An event which is called after a player has been moved to a different world.
*
Expand Down Expand Up @@ -75,6 +88,19 @@ public interface AfterEntityChange {
void afterChangeWorld(Entity originalEntity, Entity newEntity, ServerWorld origin, ServerWorld destination);
}

@FunctionalInterface
public interface AllowPlayerChange {
/**
* Called before a player is being moved to a different world.
*
* @param player the player
* @param origin the original world the player is in
* @param destination the new world the player is moving to
* @return true if the player is allowed to change worlds, false otherwise
*/
boolean allowChangeWorld(ServerPlayerEntity player, ServerWorld origin, ServerWorld destination);
}

@FunctionalInterface
public interface AfterPlayerChange {
/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import net.minecraft.entity.damage.DamageSource;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.util.math.Vec3d;

import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
Expand Down Expand Up @@ -62,6 +64,28 @@ public final class ServerPlayerEvents {
return true;
});

/**
* Called when a player is about to be teleported.
*/
public static final Event<AllowTeleport> ALLOW_TELEPORT = EventFactory.createArrayBacked(AllowTeleport.class, callbacks -> (player, world, pos) -> {
for (AllowTeleport callback : callbacks) {
if (!callback.allowTeleport(player, world, pos)) {
return false;
}
}

return true;
});

/**
* Called when a player has been teleported.
*/
public static final Event<AfterTeleport> AFTER_TELEPORT = EventFactory.createArrayBacked(AfterTeleport.class, callbacks -> (player) -> {
for (AfterTeleport callback : callbacks) {
callback.afterTeleport(player);
}
});

@FunctionalInterface
public interface CopyFrom {
/**
Expand All @@ -86,6 +110,33 @@ public interface AfterRespawn {
void afterRespawn(ServerPlayerEntity oldPlayer, ServerPlayerEntity newPlayer, boolean alive);
}

@FunctionalInterface
public interface AllowTeleport {
/**
* Called when a player is about to be teleported.
*
* <p>this event will not call if the player is using a portal.
*
* @param player the teleporting player
* @param world the world to teleport to
* @param pos the new position to teleport to
* @return true if the teleport should go ahead, false otherwise.
*/
boolean allowTeleport(ServerPlayerEntity player, ServerWorld world, Vec3d pos);
}

@FunctionalInterface
public interface AfterTeleport {
/**
* Called when a player has been teleported.
*
* <p>this event will not call if the player used a portal.
*
* @param player the teleported player
*/
void afterTeleport(ServerPlayerEntity player);
}

/**
* @deprecated Use the more general {@link ServerLivingEntityEvents#ALLOW_DEATH} event instead and check for {@code instanceof ServerPlayerEntity}.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,13 @@
package net.fabricmc.fabric.mixin.entity.event;

import java.util.List;
import java.util.Set;

import com.mojang.brigadier.LiteralMessage;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import com.mojang.datafixers.util.Either;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
Expand All @@ -35,6 +39,7 @@
import net.minecraft.entity.damage.DamageSource;
import net.minecraft.entity.mob.HostileEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.network.packet.s2c.play.PositionFlag;
import net.minecraft.registry.RegistryKey;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.server.world.ServerWorld;
Expand All @@ -43,6 +48,8 @@
import net.minecraft.util.Unit;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.TeleportTarget;
import net.minecraft.world.World;

import net.fabricmc.fabric.api.entity.event.v1.EntitySleepEvents;
Expand Down Expand Up @@ -77,6 +84,16 @@ private void notifyDeath(DamageSource source, CallbackInfo ci) {
ServerLivingEntityEvents.AFTER_DEATH.invoker().afterDeath((ServerPlayerEntity) (Object) this, source);
}

@Inject(method = "teleportTo", at = @At(value = "FIELD", target = "Lnet/minecraft/server/network/ServerPlayerEntity;inTeleportationState:Z", opcode = Opcodes.PUTFIELD), cancellable = true)
private void beforeWorldChanged(TeleportTarget teleportTarget, CallbackInfoReturnable<Entity> cir) {
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
boolean allowed = ServerEntityWorldChangeEvents.ALLOW_PLAYER_CHANGE_WORLD.invoker().allowChangeWorld(player, player.getServerWorld(), teleportTarget.world());

if (!allowed) {
cir.setReturnValue(null);
}
}

/**
* This is called by {@code teleportTo}.
*/
Expand All @@ -90,6 +107,22 @@ private void onCopyFrom(ServerPlayerEntity oldPlayer, boolean alive, CallbackInf
ServerPlayerEvents.COPY_FROM.invoker().copyFromPlayer(oldPlayer, (ServerPlayerEntity) (Object) this, alive);
}

@Inject(method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDLjava/util/Set;FF)Z", at = @At("HEAD"))
private void beforeTeleport(ServerWorld world, double destX, double destY, double destZ, Set<PositionFlag> flags, float yaw, float pitch, CallbackInfoReturnable<Boolean> cir) throws CommandSyntaxException {
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
boolean allowed = ServerPlayerEvents.ALLOW_TELEPORT.invoker().allowTeleport(player, world, new Vec3d(destX, destY, destZ));

if (!allowed) {
throw new CommandSyntaxException(null, new LiteralMessage(""));
}
}

@Inject(method = "teleport(Lnet/minecraft/server/world/ServerWorld;DDDLjava/util/Set;FF)Z", at = @At("TAIL"))
private void afterTeleported(ServerWorld world, double destX, double destY, double destZ, Set<PositionFlag> flags, float yaw, float pitch, CallbackInfoReturnable<Boolean> cir) {
ServerPlayerEntity player = (ServerPlayerEntity) (Object) this;
ServerPlayerEvents.AFTER_TELEPORT.invoker().afterTeleport(player);
}

@Redirect(method = "trySleep", at = @At(value = "INVOKE", target = "Lnet/minecraft/block/BlockState;get(Lnet/minecraft/state/property/Property;)Ljava/lang/Comparable;"))
private Comparable<?> redirectSleepDirection(BlockState state, Property<?> property, BlockPos pos) {
Direction initial = state.contains(property) ? (Direction) state.get(property) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,15 @@ public void onInitialize() {
LOGGER.info("Entity {} Killed: {}", entity, killed);
});

ServerEntityWorldChangeEvents.ALLOW_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> {
if (player.getStackInHand(Hand.MAIN_HAND).getItem() == Items.END_ROD) {
LOGGER.info("Player {} failed to change world because of handing an end rod", player.getGameProfile().getName());
return false;
}
LOGGER.info("Allow Moving player {}: [{} -> {}]", player, origin.getRegistryKey().getValue(), destination.getRegistryKey().getValue());
return true;
});

ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> {
LOGGER.info("Moved player {}: [{} -> {}]", player, origin.getRegistryKey().getValue(), destination.getRegistryKey().getValue());
});
Expand All @@ -80,6 +89,20 @@ public void onInitialize() {
LOGGER.info("Respawned {}, [{}, {}]", oldPlayer.getGameProfile().getName(), oldPlayer.getWorld().getRegistryKey().getValue(), newPlayer.getWorld().getRegistryKey().getValue());
});

ServerPlayerEvents.ALLOW_TELEPORT.register((player, world, pos) -> {
if (pos.y < -256)
{
LOGGER.info("Player {} is trying to teleport below the world height", player.getGameProfile().getName());
return false;
}
LOGGER.info("Player {} is teleporting to {} {}", player.getGameProfile().getName(), world, pos);
return true;
});

ServerPlayerEvents.AFTER_TELEPORT.register((player) -> {
LOGGER.info("Player {} is teleported", player.getGameProfile().getName());
});

// No fall damage if holding a feather in the main hand
ServerLivingEntityEvents.ALLOW_DAMAGE.register((entity, source, amount) -> {
if (source.getTypeRegistryEntry().matchesKey(DamageTypes.FALL) && entity.getStackInHand(Hand.MAIN_HAND).isOf(Items.FEATHER)) {
Expand Down