Skip to content

Commit

Permalink
Port to 24w20a
Browse files Browse the repository at this point in the history
  • Loading branch information
DrexHD authored and modmuss50 committed May 16, 2024
1 parent 5e47b9c commit 03bdf4e
Show file tree
Hide file tree
Showing 26 changed files with 89 additions and 200 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import net.minecraft.test.GameTestException;
import net.minecraft.test.TestContext;
import net.minecraft.util.Identifier;
import net.minecraft.world.TeleportTarget;
import net.minecraft.world.World;

import net.fabricmc.fabric.api.attachment.v1.AttachmentRegistry;
Expand Down Expand Up @@ -56,7 +57,7 @@ public void testCrossWorldTeleport(TestContext context) {
entity.setAttached(DUMMY, () -> 10);
entity.setAttached(COPY_ON_DEATH, () -> 10);

Entity moved = entity.moveToWorld(end);
Entity moved = entity.moveToWorld(() -> new TeleportTarget(end));
if (moved == null) throw new GameTestException("Cross-world teleportation failed");

IntSupplier attached1 = moved.getAttached(DUMMY);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.jetbrains.annotations.Nullable;

import net.minecraft.entity.Entity;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.TeleportTarget;

import net.fabricmc.fabric.impl.dimension.FabricDimensionInternals;
Expand All @@ -33,30 +32,27 @@ private FabricDimensions() {
throw new AssertionError();
}

// TODO 1.21 - This is just a Vanilla wrapper now
/**
* Teleports an entity to a different dimension, placing it at the specified destination.
*
* <p>Using this method will circumvent Vanilla's portal placement code.
*
* <p>When teleporting to another dimension, the entity may be replaced with a new entity in the target
* dimension. This is not the case for players, but needs to be accounted for by the caller.
*
* @param teleported the entity to teleport
* @param destination the dimension the entity will be teleported to
* @param target where the entity will be placed in the target world.
* As in Vanilla, the target's velocity is not applied to players.
* If target is null, the entity will not be teleported.
* @param <E> the type of the teleported entity
* @return Returns the teleported entity in the target dimension, which may be a new entity or <code>teleported</code>,
* depending on the entity type.
* @throws IllegalStateException if this method is called on a client entity
* @apiNote this method must be called from the main server thread
*/
@Nullable
public static <E extends Entity> E teleport(E teleported, ServerWorld destination, TeleportTarget target) {
public static <E extends Entity> E teleport(E teleported, TeleportTarget target) {
Preconditions.checkNotNull(target, "A target must be provided");
Preconditions.checkState(!teleported.getWorld().isClient, "Entities can only be teleported on the server side");

return FabricDimensionInternals.changeDimension(teleported, destination, target);
return FabricDimensionInternals.changeDimension(teleported, target);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,30 +29,24 @@ private FabricDimensionInternals() {
}

@SuppressWarnings("unchecked")
public static <E extends Entity> E changeDimension(E teleported, ServerWorld dimension, TeleportTarget target) {
public static <E extends Entity> E changeDimension(E teleported, TeleportTarget target) {
Preconditions.checkArgument(!teleported.getWorld().isClient, "Entities can only be teleported on the server side");
Preconditions.checkArgument(Thread.currentThread() == ((ServerWorld) teleported.getWorld()).getServer().getThread(), "Entities must be teleported from the main server thread");

try {
((Teleportable) teleported).fabric_setCustomTeleportTarget(target);

// Fast path for teleporting within the same dimension.
if (teleported.getWorld() == dimension) {
if (teleported instanceof ServerPlayerEntity serverPlayerEntity) {
serverPlayerEntity.networkHandler.requestTeleport(target.position.x, target.position.y, target.position.z, target.yaw, target.pitch);
} else {
teleported.refreshPositionAndAngles(target.position.x, target.position.y, target.position.z, target.yaw, target.pitch);
}

teleported.setVelocity(target.velocity);
teleported.setHeadYaw(target.yaw);

return teleported;
// Fast path for teleporting within the same dimension.
if (teleported.getWorld() == target.newDimension()) {
if (teleported instanceof ServerPlayerEntity serverPlayerEntity) {
serverPlayerEntity.networkHandler.requestTeleport(target.position().x, target.position().y, target.position().z, target.yaw(), target.pitch());
} else {
teleported.refreshPositionAndAngles(target.position().x, target.position().y, target.position().z, target.yaw(), target.pitch());
}

return (E) teleported.moveToWorld(dimension);
} finally {
((Teleportable) teleported).fabric_setCustomTeleportTarget(null);
teleported.setVelocity(target.velocity());
teleported.setHeadYaw(target.yaw());

return teleported;
}

return (E) teleported.moveToWorld(() -> target);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
"package": "net.fabricmc.fabric.mixin.dimension",
"compatibilityLevel": "JAVA_17",
"mixins": [
"EntityMixin",
"DimensionOptionsRegistryHolderMixin",
"Schema2832Mixin",
"TaggedChoiceMixin",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,15 +78,15 @@ public void onInitialize() {
if (entity == null) throw new AssertionError("Could not create entity!");
if (!entity.getWorld().getRegistryKey().equals(World.OVERWORLD)) throw new AssertionError("Entity starting world isn't the overworld");

TeleportTarget target = new TeleportTarget(Vec3d.ZERO, new Vec3d(1, 1, 1), 45f, 60f);
TeleportTarget target = new TeleportTarget(world, Vec3d.ZERO, new Vec3d(1, 1, 1), 45f, 60f);

Entity teleported = FabricDimensions.teleport(entity, world, target);
Entity teleported = FabricDimensions.teleport(entity, target);

if (teleported == null) throw new AssertionError("Entity didn't teleport");

if (!teleported.getWorld().getRegistryKey().equals(WORLD_KEY)) throw new AssertionError("Target world not reached.");

if (!teleported.getPos().equals(target.position)) throw new AssertionError("Target Position not reached.");
if (!teleported.getPos().equals(target.position())) throw new AssertionError("Target Position not reached.");
});

CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
Expand Down Expand Up @@ -124,8 +124,8 @@ private int swapTargeted(CommandContext<ServerCommandSource> context) throws Com
ServerWorld modWorld = getModWorld(context);

if (serverWorld != modWorld) {
TeleportTarget target = new TeleportTarget(new Vec3d(0.5, 101, 0.5), Vec3d.ZERO, 0, 0);
FabricDimensions.teleport(player, modWorld, target);
TeleportTarget target = new TeleportTarget(modWorld, new Vec3d(0.5, 101, 0.5), Vec3d.ZERO, 0, 0);
FabricDimensions.teleport(player, target);

if (player.getWorld() != modWorld) {
throw FAILED_EXCEPTION.create();
Expand All @@ -134,9 +134,9 @@ private int swapTargeted(CommandContext<ServerCommandSource> context) throws Com
modWorld.setBlockState(new BlockPos(0, 100, 0), Blocks.DIAMOND_BLOCK.getDefaultState());
modWorld.setBlockState(new BlockPos(0, 101, 0), Blocks.TORCH.getDefaultState());
} else {
TeleportTarget target = new TeleportTarget(new Vec3d(0, 100, 0), Vec3d.ZERO,
TeleportTarget target = new TeleportTarget(getWorld(context, World.OVERWORLD), new Vec3d(0, 100, 0), Vec3d.ZERO,
(float) Math.random() * 360 - 180, (float) Math.random() * 360 - 180);
FabricDimensions.teleport(player, getWorld(context, World.OVERWORLD), target);
FabricDimensions.teleport(player, target);
}

return 1;
Expand All @@ -150,8 +150,8 @@ private int testDesync(CommandContext<ServerCommandSource> context) {
return 1;
}

TeleportTarget target = new TeleportTarget(player.getPos().add(5, 0, 0), player.getVelocity(), player.getYaw(), player.getPitch());
FabricDimensions.teleport(player, (ServerWorld) player.getWorld(), target);
TeleportTarget target = new TeleportTarget((ServerWorld) player.getWorld(), player.getPos().add(5, 0, 0), player.getVelocity(), player.getYaw(), player.getPitch());
FabricDimensions.teleport(player, target);

return 1;
}
Expand All @@ -175,16 +175,16 @@ private int testEntityTeleport(CommandContext<ServerCommandSource> context) {
return 1;
}

TeleportTarget target = new TeleportTarget(player.getPos(), player.getVelocity(), player.getYaw(), player.getPitch());
FabricDimensions.teleport(entity, (ServerWorld) entity.getWorld(), target);
TeleportTarget target = new TeleportTarget((ServerWorld) entity.getWorld(), player.getPos(), player.getVelocity(), player.getYaw(), player.getPitch());
FabricDimensions.teleport(entity, target);

return 1;
}

private int testVanillaTeleport(CommandContext<ServerCommandSource> context, ServerWorld targetWorld) throws CommandSyntaxException {
Entity entity = context.getSource().getEntityOrThrow();
TeleportTarget target = new TeleportTarget(entity.getPos(), entity.getVelocity(), entity.getYaw(), entity.getPitch());
FabricDimensions.teleport(entity, targetWorld, target);
TeleportTarget target = new TeleportTarget(targetWorld, entity.getPos(), entity.getVelocity(), entity.getYaw(), entity.getPitch());
FabricDimensions.teleport(entity, target);

return 1;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ abstract class EntityMixin {
public World world;

@Inject(method = "moveToWorld", at = @At("RETURN"))
private void afterWorldChanged(ServerWorld destination, CallbackInfoReturnable<Entity> cir) {
private void afterWorldChanged(Entity.class_9776 arg, CallbackInfoReturnable<Entity> cir) {
// Ret will only have an entity if the teleport worked (entity not removed, teleportTarget was valid, entity was successfully created)
Entity ret = cir.getReturnValue();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;

import net.minecraft.entity.Entity;
import net.minecraft.server.PlayerManager;
import net.minecraft.server.network.ServerPlayerEntity;

Expand All @@ -29,7 +30,7 @@
@Mixin(PlayerManager.class)
abstract class PlayerManagerMixin {
@Inject(method = "respawnPlayer", at = @At("TAIL"))
private void afterRespawn(ServerPlayerEntity oldPlayer, boolean alive, CallbackInfoReturnable<ServerPlayerEntity> cir) {
private void afterRespawn(ServerPlayerEntity oldPlayer, boolean alive, Entity.RemovalReason removalReason, CallbackInfoReturnable<ServerPlayerEntity> cir) {
ServerPlayerEvents.AFTER_RESPAWN.invoker().afterRespawn(oldPlayer, cir.getReturnValue(), alive);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerInteractItemC2SPacket;
import net.minecraft.network.packet.c2s.play.PlayerMoveC2SPacket;
import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.TypedActionResult;
Expand Down Expand Up @@ -118,18 +117,16 @@ public void interactBlock(ClientPlayerEntity player, Hand hand, BlockHitResult b
}
}

@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V", ordinal = 0), method = "interactItem", cancellable = true)
@Inject(at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/ClientPlayerInteractionManager;syncSelectedSlot()V", ordinal = 0), method = "interactItem", cancellable = true)
public void interactItem(PlayerEntity player, Hand hand, CallbackInfoReturnable<ActionResult> info) {
// hook interactBlock between the spectator check and sending the first packet to invoke the use item event first
// this needs to be in interactBlock to avoid sending a packet in line with the event javadoc
TypedActionResult<ItemStack> result = UseItemCallback.EVENT.invoker().interact(player, player.getWorld(), hand);

if (result.getResult() != ActionResult.PASS) {
if (result.getResult() == ActionResult.SUCCESS) {
// send the move packet like vanilla to ensure the position+view vectors are accurate
networkHandler.sendPacket(new PlayerMoveC2SPacket.Full(player.getX(), player.getY(), player.getZ(), player.getYaw(), player.getPitch(), player.isOnGround()));
// send interaction packet to the server with a new sequentially assigned id
sendSequencedPacket((ClientWorld) player.getWorld(), id -> new PlayerInteractItemC2SPacket(hand, id));
sendSequencedPacket((ClientWorld) player.getWorld(), id -> new PlayerInteractItemC2SPacket(hand, id, player.getYaw(), player.getPitch()));
}

info.setReturnValue(result.getResult());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

package net.fabricmc.fabric.mixin.item;

import java.util.function.Consumer;

import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import com.llamalad7.mixinextras.sugar.Local;
Expand All @@ -36,24 +38,29 @@

@Mixin(ItemStack.class)
public abstract class ItemStackMixin implements FabricItemStack {
@Shadow public abstract Item getItem();
@Shadow
public abstract Item getItem();

@Shadow
public abstract void decrement(int amount);

@WrapOperation(method = "damage(ILnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/EquipmentSlot;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILnet/minecraft/server/world/ServerWorld;Lnet/minecraft/server/network/ServerPlayerEntity;Ljava/lang/Runnable;)V"))
private void hookDamage(ItemStack instance, int amount, ServerWorld serverWorld, ServerPlayerEntity serverPlayerEntity, Runnable runnable, Operation<Void> original, @Local(argsOnly = true) EquipmentSlot slot) {
@WrapOperation(method = "damage(ILnet/minecraft/entity/LivingEntity;Lnet/minecraft/entity/EquipmentSlot;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;damage(ILnet/minecraft/server/world/ServerWorld;Lnet/minecraft/server/network/ServerPlayerEntity;Ljava/util/function/Consumer;)V"))
private void hookDamage(ItemStack instance, int amount, ServerWorld serverWorld, ServerPlayerEntity serverPlayerEntity, Consumer<Item> consumer, Operation<Void> original, @Local(argsOnly = true) EquipmentSlot slot) {
CustomDamageHandler handler = ((ItemExtensions) getItem()).fabric_getCustomDamageHandler();

if (handler != null) {
// Track whether an item has been broken by custom handler
MutableBoolean mut = new MutableBoolean(false);
amount = handler.damage((ItemStack) (Object) this, amount, serverPlayerEntity, slot, () -> {
mut.setTrue();
runnable.run();
this.decrement(1);
consumer.accept(this.getItem());
});

// If item is broken, there's no reason to call the original.
if (mut.booleanValue()) return;
}

original.call(instance, amount, serverWorld, serverPlayerEntity, runnable);
original.call(instance, amount, serverWorld, serverPlayerEntity, consumer);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
@Mixin(LivingEntity.class)
abstract class LivingEntityMixin {
@Inject(method = "getPreferredEquipmentSlot", at = @At(value = "HEAD"), cancellable = true)
private static void onGetPreferredEquipmentSlot(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> info) {
private void onGetPreferredEquipmentSlot(ItemStack stack, CallbackInfoReturnable<EquipmentSlot> info) {
EquipmentSlotProvider equipmentSlotProvider = ((ItemExtensions) stack.getItem()).fabric_getEquipmentSlotProvider();

if (equipmentSlotProvider != null) {
Expand Down
Loading

0 comments on commit 03bdf4e

Please sign in to comment.