diff --git a/gradle.properties b/gradle.properties index 721cc2c6..d26f965f 100644 --- a/gradle.properties +++ b/gradle.properties @@ -4,16 +4,16 @@ org.gradle.jvmargs=-Xmx4G # Fabric Properties # check these on https://fabricmc.net/use -minecraft_version=1.21.2-pre4 -yarn_mappings=1.21.2-pre4+build.2 +minecraft_version=1.21.2-rc1 +yarn_mappings=1.21.2-rc1+build.1 loader_version=0.16.7 # Fabric API -fabric_version=0.105.4+1.21.2 +fabric_version=0.106.0+1.21.2 maven_group = eu.pb4 -mod_version = 0.10.0-alpha +mod_version = 0.10.0-rc.1 minecraft_version_supported = ">=1.21.2-" diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlock.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlock.java index ed0fcfd6..2641cf2b 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlock.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlock.java @@ -5,6 +5,10 @@ import net.minecraft.block.BlockState; import net.minecraft.item.ItemStack; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import xyz.nucleoid.packettweaker.PacketContext; @@ -58,4 +62,8 @@ default Block getPolymerReplacement(PacketContext context) { default boolean handleMiningOnServer(ItemStack tool, BlockState state, BlockPos pos, ServerPlayerEntity player) { return true; } + + default boolean isPolymerBlockInteraction(BlockState state, ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, BlockHitResult blockHitResult, ActionResult actionResult) { + return true; + } } diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlockUtils.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlockUtils.java index af1f564f..4bd71f0d 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlockUtils.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/block/PolymerBlockUtils.java @@ -26,6 +26,9 @@ import net.minecraft.registry.Registries; import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.ChunkSectionPos; import org.jetbrains.annotations.ApiStatus; @@ -45,6 +48,7 @@ public final class PolymerBlockUtils { */ public static final BooleanEvent SERVER_SIDE_MINING_CHECK = new BooleanEvent<>(); public static final SimpleEvent BREAKING_PROGRESS_UPDATE = new SimpleEvent<>(); + public static final BooleanEvent POLYMER_BLOCK_INTERACTION_CHECK = new BooleanEvent<>(); /** * This event allows you to force syncing of light updates between server and clinet */ @@ -146,7 +150,7 @@ public static BlockState getBlockBreakBlockStateSafely(PolymerBlock block, Block * * @param block PolymerBlock * @param blockState Server side BlockState - * @param player Possible target player + * @param context Possible target player * @return Client side BlockState */ public static BlockState getBlockStateSafely(PolymerBlock block, BlockState blockState, PacketContext context) { @@ -242,6 +246,17 @@ public static NbtCompound transformBlockEntityNbt(PacketContext context, BlockEn return override != null ? override : original; } + public static boolean isPolymerBlockInteraction(ServerPlayerEntity player, ItemStack stack, Hand hand, BlockHitResult blockHitResult, ServerWorld world, ActionResult actionResult) { + var blockState = world.getBlockState(blockHitResult.getBlockPos()); + if (blockState.getBlock() instanceof PolymerBlock polymerBlock && polymerBlock.isPolymerBlockInteraction(blockState, player, hand, stack, world, blockHitResult, actionResult)) { + return true; + } else if (stack.getItem() instanceof PolymerItem polymerItem && polymerItem.isPolymerBlockInteraction(blockState, player, hand, stack, world, blockHitResult, actionResult)) { + return true; + } + + return POLYMER_BLOCK_INTERACTION_CHECK.invoke(x -> x.isPolymerBlockInteraction(blockState, player, hand, stack, world, blockHitResult, actionResult)); + } + @FunctionalInterface public interface MineEventListener { boolean onBlockMine(BlockState state, BlockPos pos, ServerPlayerEntity player); @@ -251,4 +266,9 @@ public interface MineEventListener { public interface BreakingProgressListener { void onBreakingProgressUpdate(ServerPlayerEntity player, BlockPos pos, BlockState finalState, int i); } + + @FunctionalInterface + public interface PolymerBlockInteractionListener { + boolean isPolymerBlockInteraction(BlockState state, ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, BlockHitResult blockHitResult, ActionResult actionResult); + } } diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntity.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntity.java index 8b1a7eab..224d9207 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntity.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntity.java @@ -2,6 +2,7 @@ import com.mojang.datafixers.util.Pair; import eu.pb4.polymer.core.api.utils.PolymerObject; +import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.EquipmentSlot; import net.minecraft.entity.data.DataTracker; @@ -10,6 +11,11 @@ import net.minecraft.network.packet.s2c.play.EntityAttributesS2CPacket; import net.minecraft.server.network.PlayerAssociatedNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.Vec3d; import xyz.nucleoid.packettweaker.PacketContext; @@ -88,4 +94,8 @@ default boolean canSynchronizeToPolymerClient(ServerPlayerEntity player) { default boolean sendEmptyTrackerUpdates(ServerPlayerEntity player) { return true; } + + default boolean isPolymerEntityInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, ActionResult actionResult) { + return true; + } } diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntityUtils.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntityUtils.java index f3d23a5b..7e7996b1 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntityUtils.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/entity/PolymerEntityUtils.java @@ -1,26 +1,30 @@ package eu.pb4.polymer.core.api.entity; +import eu.pb4.polymer.common.api.events.BooleanEvent; import eu.pb4.polymer.common.impl.CommonImplUtils; import eu.pb4.polymer.common.impl.entity.InternalEntityHelpers; +import eu.pb4.polymer.core.api.item.PolymerItem; import eu.pb4.polymer.core.impl.interfaces.EntityAttachedPacket; import eu.pb4.polymer.core.impl.networking.PolymerServerProtocol; import eu.pb4.polymer.core.mixin.entity.EntityAccessor; import eu.pb4.polymer.core.mixin.entity.PlayerListS2CPacketAccessor; import eu.pb4.polymer.rsm.api.RegistrySyncUtils; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenCustomHashSet; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityType; import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.data.DataTracker; +import net.minecraft.item.ItemStack; import net.minecraft.network.packet.Packet; import net.minecraft.network.listener.ClientPlayPacketListener; import net.minecraft.network.packet.s2c.play.PlayerListS2CPacket; import net.minecraft.registry.Registries; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.server.network.ServerPlayerEntity; -import net.minecraft.util.Util; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.village.VillagerProfession; import org.jetbrains.annotations.Nullable; @@ -29,6 +33,7 @@ public final class PolymerEntityUtils { private PolymerEntityUtils() { } + public static final BooleanEvent POLYMER_ENTITY_INTERACTION_CHECK = new BooleanEvent<>(); private static final Set> ENTITY_TYPES = new ObjectOpenCustomHashSet<>(CommonImplUtils.IDENTITY_HASH); private static final Set ENTITY_ATTRIBUTES = new ObjectOpenCustomHashSet<>(CommonImplUtils.IDENTITY_HASH); @@ -159,5 +164,20 @@ public static Entity getEntityContext(Packet packet) { public static void sendEntityType(ServerPlayerEntity player, int entityId, EntityType entityType) { PolymerServerProtocol.sendEntityInfo(player.networkHandler, entityId, entityType); } + + public static boolean isPolymerEntityInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, Entity entity, ActionResult actionResult) { + if (entity instanceof PolymerEntity polymerEntity && polymerEntity.isPolymerEntityInteraction(player, hand, stack, world, actionResult)) { + return true; + } else if (stack.getItem() instanceof PolymerItem polymerItem && polymerItem.isPolymerEntityInteraction(player, hand, stack, world, entity, actionResult)) { + return true; + } + + return POLYMER_ENTITY_INTERACTION_CHECK.invoke(x -> x.isPolymerEntityInteraction(player, hand, stack, world, entity, actionResult)); + } + + @FunctionalInterface + public interface PolymerEntityInteractionListener { + boolean isPolymerEntityInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, Entity entity, ActionResult actionResult); + } } diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItem.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItem.java index 00a56d46..a1a98d25 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItem.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItem.java @@ -4,13 +4,19 @@ import eu.pb4.polymer.core.impl.PolymerImplUtils; import net.minecraft.block.BlockState; import net.minecraft.component.DataComponentTypes; +import net.minecraft.entity.Entity; import net.minecraft.item.tooltip.TooltipType; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.registry.RegistryWrapper; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Text; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; import net.minecraft.util.Identifier; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.hit.HitResult; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; import org.jetbrains.annotations.Nullable; @@ -69,4 +75,16 @@ default boolean handleMiningOnServer(ItemStack tool, BlockState targetBlock, Blo default boolean shouldStorePolymerItemStackCount() { return false; } + + default boolean isPolymerBlockInteraction(BlockState state, ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, BlockHitResult blockHitResult, ActionResult actionResult) { + return false; + } + + default boolean isPolymerEntityInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, Entity entity, ActionResult actionResult) { + return false; + } + + default boolean isPolymerItemInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, ActionResult actionResult) { + return true; + } } \ No newline at end of file diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItemUtils.java b/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItemUtils.java index e06756d1..6d3bbe45 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItemUtils.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/api/item/PolymerItemUtils.java @@ -30,11 +30,11 @@ import net.minecraft.registry.Registries; import net.minecraft.registry.RegistryOps; import net.minecraft.registry.RegistryWrapper; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; import net.minecraft.text.Style; import net.minecraft.text.Text; -import net.minecraft.util.Formatting; -import net.minecraft.util.Identifier; -import net.minecraft.util.Unit; +import net.minecraft.util.*; import org.jetbrains.annotations.Nullable; import xyz.nucleoid.packettweaker.PacketContext; @@ -74,6 +74,9 @@ public final class PolymerItemUtils { * You can also return new ItemStack, however please keep previous nbt so other modifications aren't removed if not needed! */ public static final FunctionEvent ITEM_MODIFICATION_EVENT = new FunctionEvent<>(); + + public static final BooleanEvent POLYMER_ITEM_INTERACTION_CHECK = new BooleanEvent<>(); + private static final ComponentType[] COMPONENTS_TO_COPY = {DataComponentTypes.CAN_BREAK, DataComponentTypes.CAN_PLACE_ON, DataComponentTypes.BLOCK_ENTITY_DATA, DataComponentTypes.TRIM, DataComponentTypes.TOOL, @@ -514,11 +517,23 @@ public static ItemStack getClientItemStack(ItemStack stack, PacketContext contex return out; } + public static boolean isPolymerItemInteraction(ServerPlayerEntity player, ItemStack stack, Hand hand, ServerWorld world, ActionResult actionResult) { + if (stack.getItem() instanceof PolymerItem polymerItem && polymerItem.isPolymerItemInteraction(player, hand, stack, world, actionResult)) { + return true; + } + return POLYMER_ITEM_INTERACTION_CHECK.invoke((x) -> x.isPolymerItemInteraction(player, hand, stack, world, actionResult)); + } + @FunctionalInterface public interface ItemModificationEventHandler { ItemStack modifyItem(ItemStack original, ItemStack client, PacketContext context); } + @FunctionalInterface + public interface PolymerItemInteractionListener { + boolean isPolymerItemInteraction(ServerPlayerEntity player, Hand hand, ItemStack stack, ServerWorld world, ActionResult actionResult); + } + public record ItemWithMetadata(Item item, Identifier itemModel) { } diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/impl/interfaces/LastActionResultStorer.java b/polymer-core/src/main/java/eu/pb4/polymer/core/impl/interfaces/LastActionResultStorer.java new file mode 100644 index 00000000..fdb05ad1 --- /dev/null +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/impl/interfaces/LastActionResultStorer.java @@ -0,0 +1,9 @@ +package eu.pb4.polymer.core.impl.interfaces; + +import eu.pb4.polymer.core.impl.other.ActionSource; +import net.minecraft.util.ActionResult; + +public interface LastActionResultStorer { + void polymer$setLastActionResult(ActionResult result); + void polymer$setLastActionSource(ActionSource source); +} diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/impl/other/ActionSource.java b/polymer-core/src/main/java/eu/pb4/polymer/core/impl/other/ActionSource.java new file mode 100644 index 00000000..f00dc321 --- /dev/null +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/impl/other/ActionSource.java @@ -0,0 +1,7 @@ +package eu.pb4.polymer.core.impl.other; + +public enum ActionSource { + BLOCK, + ITEM, + ENTITY +} diff --git a/polymer-core/src/main/java/eu/pb4/polymer/core/mixin/item/ServerPlayNetworkHandlerMixin.java b/polymer-core/src/main/java/eu/pb4/polymer/core/mixin/item/ServerPlayNetworkHandlerMixin.java index 50aa8df7..d181f08d 100644 --- a/polymer-core/src/main/java/eu/pb4/polymer/core/mixin/item/ServerPlayNetworkHandlerMixin.java +++ b/polymer-core/src/main/java/eu/pb4/polymer/core/mixin/item/ServerPlayNetworkHandlerMixin.java @@ -1,17 +1,25 @@ package eu.pb4.polymer.core.mixin.item; +import com.llamalad7.mixinextras.injector.ModifyExpressionValue; +import com.llamalad7.mixinextras.sugar.Local; import eu.pb4.polymer.common.impl.CommonImplUtils; +import eu.pb4.polymer.core.api.block.PolymerBlockUtils; +import eu.pb4.polymer.core.api.entity.PolymerEntityUtils; import eu.pb4.polymer.core.api.item.PolymerItem; import eu.pb4.polymer.core.api.item.PolymerItemUtils; import eu.pb4.polymer.core.impl.PolymerImpl; +import eu.pb4.polymer.core.impl.interfaces.LastActionResultStorer; import eu.pb4.polymer.core.impl.networking.PolymerServerProtocol; +import eu.pb4.polymer.core.impl.other.ActionSource; +import net.minecraft.entity.Entity; import net.minecraft.item.BlockItem; import net.minecraft.item.BucketItem; import net.minecraft.item.ItemStack; import net.minecraft.network.ClientConnection; import net.minecraft.network.packet.c2s.common.ClientOptionsC2SPacket; -import net.minecraft.network.packet.c2s.play.ClickSlotC2SPacket; +import net.minecraft.network.packet.c2s.play.ClientTickEndC2SPacket; 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.s2c.common.SynchronizeTagsS2CPacket; import net.minecraft.network.packet.s2c.play.*; @@ -21,8 +29,13 @@ import net.minecraft.server.network.ServerCommonNetworkHandler; import net.minecraft.server.network.ServerPlayNetworkHandler; import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.ActionResult; import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; import net.minecraft.util.math.Direction; +import org.jetbrains.annotations.Nullable; +import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -31,15 +44,24 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import xyz.nucleoid.packettweaker.PacketContext; -import java.util.ArrayList; -import java.util.List; - @Mixin(value = ServerPlayNetworkHandler.class, priority = 1200) -public abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler { +public abstract class ServerPlayNetworkHandlerMixin extends ServerCommonNetworkHandler implements LastActionResultStorer { @Shadow public ServerPlayerEntity player; + + @Shadow + public abstract void onPlayerInteractItem(PlayerInteractItemC2SPacket packet); + + @Shadow + private int sequence; @Unique private String polymerCore$language; + @Unique + @Nullable + private ActionResult lastActionResult = null; + @Unique + @Nullable + private ActionSource lastActionSource = null; public ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection connection, ConnectedClientData clientData) { super(server, connection, clientData); @@ -50,7 +72,6 @@ public ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection co this.polymerCore$language = clientData.syncedOptions().language(); } - @Inject(method = "onClientOptions", at = @At("TAIL")) private void polymerCore$resendLanguage(ClientOptionsC2SPacket packet, CallbackInfo ci) { if (CommonImplUtils.isMainPlayer(this.player)) { @@ -65,10 +86,16 @@ public ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection co } } - @Inject(method = "onPlayerInteractBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/server/world/ServerWorld;)V", shift = At.Shift.AFTER)) + @Inject(method = "onPlayerInteractBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/server/world/ServerWorld;)V", shift = At.Shift.AFTER), cancellable = true) private void polymer$resendHandOnPlace(PlayerInteractBlockC2SPacket packet, CallbackInfo ci) { ItemStack itemStack = this.player.getStackInHand(packet.getHand()); + if (this.lastActionResult != null && this.lastActionResult != ActionResult.PASS) { + ci.cancel(); + this.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(this.player.playerScreenHandler.syncId, this.player.playerScreenHandler.nextRevision(), packet.getHand() == Hand.MAIN_HAND ? 36 + this.player.getInventory().selectedSlot : 45, itemStack)); + return; + } + if (itemStack.getItem() instanceof PolymerItem polymerItem) { var data = PolymerItemUtils.getItemSafely(polymerItem, itemStack, PacketContext.create(this.player)); if (data.item() instanceof BlockItem || data.item() instanceof BucketItem) { @@ -77,6 +104,61 @@ public ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection co } } + + @ModifyExpressionValue(method = "onPlayerInteractBlock", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;interactBlock(Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;")) + private ActionResult captureBlockInteraction(ActionResult original, @Local ItemStack stack, @Local Hand hand, @Local BlockHitResult blockHitResult, @Local ServerWorld world) { + if (PolymerBlockUtils.isPolymerBlockInteraction(this.player, stack, hand, blockHitResult, world, original)) { + this.lastActionResult = original; + this.lastActionSource = ActionSource.BLOCK; + } + return original; + } + + @Inject(method = "onPlayerInteractItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/server/world/ServerWorld;)V", shift = At.Shift.AFTER), cancellable = true) + private void preventItemUse(PlayerInteractItemC2SPacket packet, CallbackInfo ci) { + if (this.lastActionResult != null && this.lastActionResult != ActionResult.PASS) { + this.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(this.player.playerScreenHandler.syncId, this.player.playerScreenHandler.nextRevision(), packet.getHand() == Hand.MAIN_HAND ? 36 + this.player.getInventory().selectedSlot : 45, this.player.getStackInHand(packet.getHand()))); + ci.cancel(); + } + } + + + @ModifyExpressionValue(method = "onPlayerInteractItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;interactItem(Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;")) + private ActionResult captureItemInteraction(ActionResult original, @Local ItemStack stack, @Local Hand hand, @Local ServerWorld world) { + if (PolymerItemUtils.isPolymerItemInteraction(this.player, stack, hand, world, original)) { + this.lastActionResult = original; + this.lastActionSource = ActionSource.ITEM; + } + return original; + } + + @Inject(method = "onPlayerInteractEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/NetworkThreadUtils;forceMainThread(Lnet/minecraft/network/packet/Packet;Lnet/minecraft/network/listener/PacketListener;Lnet/minecraft/server/world/ServerWorld;)V", shift = At.Shift.AFTER), cancellable = true) + private void preventEntityUse(PlayerInteractEntityC2SPacket packet, CallbackInfo ci) { + if (this.lastActionResult != null && this.lastActionResult != ActionResult.PASS) { + this.sendPacket(new ScreenHandlerSlotUpdateS2CPacket(this.player.playerScreenHandler.syncId, this.player.playerScreenHandler.nextRevision(), this.player.getInventory().selectedSlot, this.player.getStackInHand(Hand.MAIN_HAND))); + ci.cancel(); + } + } + + @Inject(method = "onClientTickEnd", at = @At("TAIL")) + private void onClientTickEndedPolymer(ClientTickEndC2SPacket packet, CallbackInfo ci) { + if (this.lastActionSource != ActionSource.ITEM && this.lastActionResult == ActionResult.PASS) { + try { + var seq = Math.max(this.sequence, 0); + for (var hand : Hand.values()) { + this.onPlayerInteractItem(new PlayerInteractItemC2SPacket(hand, seq, this.player.getYaw(), this.player.getPitch())); + } + } catch (Throwable e) { + //noinspection CallToPrintStackTrace + e.printStackTrace(); + } + } + + this.lastActionResult = null; + this.lastActionSource = null; + } + + @Inject(method = "onPlayerInteractBlock", at = @At("TAIL")) private void polymer$updateMoreBlocks(PlayerInteractBlockC2SPacket packet, CallbackInfo ci) { if (PolymerImpl.RESEND_BLOCKS_AROUND_CLICK) { @@ -94,14 +176,34 @@ public ServerPlayNetworkHandlerMixin(MinecraftServer server, ClientConnection co } } } + } - /*var stack = this.player.getStackInHand(packet.getHand()); + @Mixin(targets = "net/minecraft/server/network/ServerPlayNetworkHandler$1") + public static class EntityHandlerMixin { + @Shadow + @Final + ServerPlayNetworkHandler field_28963; + @Shadow + @Final + Entity field_28962; - if (stack.getItem() instanceof PolymerItem virtualItem) { - var data = PolymerItemUtils.getItemSafely(virtualItem, stack, this.player); - if (data.item() instanceof BlockItem || data.item() instanceof BucketItem) { - this.onPlayerInteractItem(new PlayerInteractItemC2SPacket(packet.getHand(), 0)); + @ModifyExpressionValue(method = "processInteract", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler$Interaction;run(Lnet/minecraft/server/network/ServerPlayerEntity;Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;")) + private ActionResult captureIEntityInteraction(ActionResult original, @Local(argsOnly = true) Hand hand) { + if (PolymerEntityUtils.isPolymerEntityInteraction(this.field_28963.player, hand, this.field_28963.player.getStackInHand(hand), (ServerWorld) this.field_28962.getWorld(), this.field_28962, original)) { + ((LastActionResultStorer) this.field_28963).polymer$setLastActionResult(original); + ((LastActionResultStorer) this.field_28963).polymer$setLastActionSource(ActionSource.ENTITY); } - }*/ + return original; + } + } + + + public void polymer$setLastActionResult(ActionResult lastActionResult) { + this.lastActionResult = lastActionResult; + } + + @Override + public void polymer$setLastActionSource(ActionSource source) { + this.lastActionSource = source; } } diff --git a/polymer-core/src/main/resources/polymer-core.mixins.json b/polymer-core/src/main/resources/polymer-core.mixins.json index baae545c..cc674f0e 100644 --- a/polymer-core/src/main/resources/polymer-core.mixins.json +++ b/polymer-core/src/main/resources/polymer-core.mixins.json @@ -59,6 +59,7 @@ "item.NbtHelperMixin", "item.PlayerManagerMixin", "item.ServerPlayNetworkHandlerMixin", + "item.ServerPlayNetworkHandlerMixin$EntityHandlerMixin", "item.component.ApplyEffectsConsumeEffectMixin", "item.component.AttributeModifiersComponentMixin", "item.component.ConsumableComponentMixin", @@ -66,7 +67,6 @@ "item.component.PotionContentsComponentMixin", "item.component.SuspiciousStewComponentMixin", "item.component.ench.AttributeEnchantmentEffectMixin", - "other.RegistryMixin", "item.packet.ItemStackPacketCodecMixin", "item.packet.RecipePropertySetMixin", "item.packet.SlotDisplayMixin", @@ -86,6 +86,7 @@ "other.PacketCodecsRegistryEntryMixin", "other.PacketCodecsRegistryMixin", "other.RegistryFixedCodecMixin", + "other.RegistryMixin", "other.ServerCommonNetworkHandlerMixin", "other.ServerConfigurationNetworkHandlerMixin", "other.ServerPlayerEntityMixin", diff --git a/polymer-core/src/testmod/java/eu/pb4/polymertest/TestBlock.java b/polymer-core/src/testmod/java/eu/pb4/polymertest/TestBlock.java index 4e21251c..cfe97cc8 100644 --- a/polymer-core/src/testmod/java/eu/pb4/polymertest/TestBlock.java +++ b/polymer-core/src/testmod/java/eu/pb4/polymertest/TestBlock.java @@ -52,7 +52,7 @@ protected void appendProperties(StateManager.Builder builder) @Override public BlockState getPolymerBlockState(BlockState state, PacketContext context) { - return Blocks.DISPENSER.getDefaultState().with(DispenserBlock.FACING, Direction.UP); + return state.get(TEST) % 2 == 0 ? Blocks.DISPENSER.getDefaultState().with(DispenserBlock.FACING, Direction.UP) : Blocks.NOTE_BLOCK.getDefaultState(); } @Override diff --git a/polymer-core/src/testmod/java/eu/pb4/polymertest/TestEntity3.java b/polymer-core/src/testmod/java/eu/pb4/polymertest/TestEntity3.java index 08698353..9df990b9 100644 --- a/polymer-core/src/testmod/java/eu/pb4/polymertest/TestEntity3.java +++ b/polymer-core/src/testmod/java/eu/pb4/polymertest/TestEntity3.java @@ -77,12 +77,10 @@ public Vec3d getPos() { this.rideAnchor.ignorePositionUpdates(); this.updateAnimation(); - VirtualEntityUtils.addVirtualPassenger(this, this.leftLeg.getEntityId(), this.rightLeg.getEntityId(), this.torso.getEntityId(), this.interaction.getEntityId()); - - this.holder.addElement(interaction); - this.holder.addElement(leftLeg); - this.holder.addElement(rightLeg); - this.holder.addElement(torso); + this.holder.addPassengerElement(interaction); + this.holder.addPassengerElement(leftLeg); + this.holder.addPassengerElement(rightLeg); + this.holder.addPassengerElement(torso); this.holder.addElement(rideAnchor); this.attachment = new EntityAttachment(this.holder, this, false); } @@ -152,21 +150,10 @@ public EntityType getPolymerEntityType(PacketContext context) { return EntityType.ARMOR_STAND; } - @Override - public void onEntityPacketSent(Consumer> consumer, Packet packet) { - if (packet instanceof EntityPassengersSetS2CPacket passengersSetS2CPacket) { - consumer.accept(VirtualEntityUtils.createRidePacket(this.rideAnchor.getEntityId(), IntList.of(passengersSetS2CPacket.getPassengerIds()))); - return; - } - - consumer.accept(packet); - } - @Override public void modifyRawTrackedData(List> data, ServerPlayerEntity player, boolean initial) { data.add(DataTracker.SerializedEntry.of(EntityTrackedData.FLAGS, (byte) (1 << EntityTrackedData.INVISIBLE_FLAG_INDEX))); data.add(new DataTracker.SerializedEntry(EntityAccessor.getNO_GRAVITY().id(), EntityAccessor.getNO_GRAVITY().dataType(), true)); data.add(DataTracker.SerializedEntry.of(ArmorStandEntity.ARMOR_STAND_FLAGS, (byte) (ArmorStandEntity.SMALL_FLAG | ArmorStandEntity.MARKER_FLAG))); } - } diff --git a/polymer-virtual-entity/src/main/java/eu/pb4/polymer/virtualentity/mixin/EntityTrackerEntryMixin.java b/polymer-virtual-entity/src/main/java/eu/pb4/polymer/virtualentity/mixin/EntityTrackerEntryMixin.java index 7cf0778b..b461f045 100644 --- a/polymer-virtual-entity/src/main/java/eu/pb4/polymer/virtualentity/mixin/EntityTrackerEntryMixin.java +++ b/polymer-virtual-entity/src/main/java/eu/pb4/polymer/virtualentity/mixin/EntityTrackerEntryMixin.java @@ -31,14 +31,16 @@ public class EntityTrackerEntryMixin { @Inject(method = "startTracking", at = @At("TAIL")) private void polymerVE$startTracking(ServerPlayerEntity player, CallbackInfo ci) { + boolean hasPassangers = false; var a = ((HolderAttachmentHolder) this.entity).polymerVE$getHolders(); if (!a.isEmpty()) { for (var x : a) { x.startWatching(player); + hasPassangers |= !x.holder().getAttachedPassengerEntityIds().isEmpty(); } } - if (!((EntityExt) this.entity).polymerVE$getVirtualRidden().isEmpty()) { + if (hasPassangers || !((EntityExt) this.entity).polymerVE$getVirtualRidden().isEmpty()) { player.networkHandler.sendPacket(new EntityPassengersSetS2CPacket(this.entity)); } }