diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java index a63b539be..7dfe46fa0 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/block/BukkitBlockManager.java @@ -10,7 +10,7 @@ import it.unimi.dsi.fastutil.objects.ObjectArrayList; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.injector.BlockGenerator; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.plugin.reflection.bukkit.CraftBukkitReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBlocks; @@ -102,7 +102,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { } this.stateId2ImmutableBlockStates = new ImmutableBlockState[this.customBlockCount]; Arrays.fill(this.stateId2ImmutableBlockStates, EmptyBlock.INSTANCE.defaultState()); - this.resetPacketConsumers(); + this.resetPacketListeners(); } @Override @@ -149,7 +149,7 @@ public final class BukkitBlockManager extends AbstractBlockManager { @Override public void delayedLoad() { - this.resetPacketConsumers(); + this.resetPacketListeners(); super.delayedLoad(); } @@ -263,14 +263,14 @@ public final class BukkitBlockManager extends AbstractBlockManager { holder.bindValue(emptyBlock); } - private void resetPacketConsumers() { + private void resetPacketListeners() { Map finalMapping = new HashMap<>(this.blockAppearanceMapper); int stoneId = BlockStateUtils.blockStateToId(MBlocks.STONE$defaultState); for (int custom : this.internalId2StateId.values()) { finalMapping.put(custom, stoneId); } finalMapping.putAll(this.tempBlockAppearanceConvertor); - PacketConsumers.initBlocks(finalMapping, RegistryUtils.currentBlockRegistrySize()); + BukkitNetworkManager.instance().registerBlockStatePacketListeners(finalMapping, RegistryUtils.currentBlockRegistrySize()); } private void initVanillaRegistry() { diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java index 6633b1fa3..e00b9b64b 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/BukkitCraftEngine.java @@ -20,12 +20,10 @@ import net.momirealms.craftengine.bukkit.plugin.command.BukkitSenderFactory; import net.momirealms.craftengine.bukkit.plugin.gui.BukkitGuiManager; import net.momirealms.craftengine.bukkit.plugin.injector.*; import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; import net.momirealms.craftengine.bukkit.plugin.scheduler.BukkitSchedulerAdapter; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.sound.BukkitSoundManager; import net.momirealms.craftengine.bukkit.util.EventUtils; -import net.momirealms.craftengine.bukkit.util.RegistryUtils; import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; import net.momirealms.craftengine.core.item.ItemManager; import net.momirealms.craftengine.core.plugin.CraftEngine; @@ -146,8 +144,8 @@ public class BukkitCraftEngine extends CraftEngine { throw new InjectionException("Error initializing ProtectedFieldVisitor", e); } super.onPluginLoad(); - super.blockManager.init(); super.networkManager = new BukkitNetworkManager(this); + super.blockManager.init(); super.itemManager = new BukkitItemManager(this); this.successfullyLoaded = true; super.compatibilityManager().onLoad(); @@ -191,7 +189,6 @@ public class BukkitCraftEngine extends CraftEngine { BukkitItemBehaviors.init(); BukkitHitBoxTypes.init(); BukkitBlockEntityElementConfigs.init(); - PacketConsumers.initEntities(RegistryUtils.currentEntityTypeRegistrySize()); super.packManager = new BukkitPackManager(this); super.senderFactory = new BukkitSenderFactory(this); super.recipeManager = new BukkitRecipeManager(this); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java index f97d36b3e..370b57d79 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/BukkitNetworkManager.java @@ -1,30 +1,92 @@ package net.momirealms.craftengine.bukkit.plugin.network; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.mojang.authlib.GameProfile; +import com.mojang.datafixers.util.Either; import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; import io.netty.channel.*; import io.netty.handler.codec.MessageToMessageDecoder; import io.netty.handler.codec.MessageToMessageEncoder; import io.netty.util.internal.logging.InternalLogger; import io.netty.util.internal.logging.InternalLoggerFactory; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.ints.IntList; +import net.kyori.adventure.text.Component; +import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; +import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; +import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; +import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; +import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; +import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; +import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; +import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; +import net.momirealms.craftengine.bukkit.item.BukkitItemManager; +import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIdFinder; +import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; +import net.momirealms.craftengine.bukkit.plugin.network.handler.*; +import net.momirealms.craftengine.bukkit.plugin.network.id.PlayPacketIdHelper; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20; import net.momirealms.craftengine.bukkit.plugin.network.id.PacketIds1_20_5; +import net.momirealms.craftengine.bukkit.plugin.network.listener.ByteBufferPacketListener; +import net.momirealms.craftengine.bukkit.plugin.network.listener.NMSPacketListener; +import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; +import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; +import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; import net.momirealms.craftengine.bukkit.plugin.reflection.leaves.LeavesReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.LibraryReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.*; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; import net.momirealms.craftengine.bukkit.plugin.user.FakeBukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.KeyUtils; +import net.momirealms.craftengine.bukkit.util.*; +import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; +import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; +import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; +import net.momirealms.craftengine.core.block.ImmutableBlockState; +import net.momirealms.craftengine.core.entity.player.InteractionHand; +import net.momirealms.craftengine.core.font.FontManager; +import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; +import net.momirealms.craftengine.core.item.CustomItem; +import net.momirealms.craftengine.core.item.Item; +import net.momirealms.craftengine.core.item.behavior.ItemBehavior; +import net.momirealms.craftengine.core.item.context.UseOnContext; +import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipeHolder; +import net.momirealms.craftengine.core.item.recipe.network.modern.RecipeBookEntry; +import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; +import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; +import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; +import net.momirealms.craftengine.core.plugin.context.ContextHolder; import net.momirealms.craftengine.core.plugin.context.CooldownData; +import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; +import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; +import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; +import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; +import net.momirealms.craftengine.core.plugin.locale.TranslationManager; import net.momirealms.craftengine.core.plugin.logger.Debugger; import net.momirealms.craftengine.core.plugin.network.*; +import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; import net.momirealms.craftengine.core.util.*; -import org.bukkit.Bukkit; +import net.momirealms.craftengine.core.world.*; +import net.momirealms.craftengine.core.world.chunk.CEChunk; +import net.momirealms.craftengine.core.world.chunk.ChunkStatus; +import net.momirealms.craftengine.core.world.chunk.Palette; +import net.momirealms.craftengine.core.world.chunk.PalettedContainer; +import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; +import net.momirealms.craftengine.core.world.chunk.packet.MCSection; +import net.momirealms.craftengine.core.world.collision.AABB; +import net.momirealms.sparrow.nbt.Tag; +import org.bukkit.*; +import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -32,49 +94,33 @@ import org.bukkit.event.HandlerList; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.PlayerInventory; import org.bukkit.persistence.PersistentDataType; import org.bukkit.plugin.messaging.PluginMessageListener; +import org.bukkit.util.RayTraceResult; +import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.BiConsumer; public class BukkitNetworkManager implements NetworkManager, Listener, PluginMessageListener { private static BukkitNetworkManager instance; - private static final Map, TriConsumer> NMS_PACKET_HANDLERS = new HashMap<>(); - // only for game stage for the moment - private static BiConsumer[] S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS; - private static BiConsumer[] C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS; + private final BukkitCraftEngine plugin; + private final Map, NMSPacketListener> nmsPacketListeners = new IdentityHashMap<>(128); - private static void registerNMSPacketConsumer(final TriConsumer function, @Nullable Class packet) { - if (packet == null) return; - NMS_PACKET_HANDLERS.put(packet, function); - } - - private static void registerS2CByteBufPacketConsumer(final BiConsumer function, int id) { - if (id == -1) return; - if (id < 0 || id >= S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { - throw new IllegalArgumentException("Invalid packet id: " + id); - } - S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function; - } - - private static void registerC2SByteBufPacketConsumer(final BiConsumer function, int id) { - if (id == -1) return; - if (id < 0 || id >= C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS.length) { - throw new IllegalArgumentException("Invalid packet id: " + id); - } - C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[id] = function; - } + private final ByteBufferPacketListener[] s2cGamePacketListeners; + private final ByteBufferPacketListener[] c2sGamePacketListeners; private final TriConsumer packetConsumer; private final TriConsumer, Object> packetsConsumer; private final TriConsumer immediatePacketConsumer; private final TriConsumer, Runnable> immediatePacketsConsumer; - private final BukkitCraftEngine plugin; private final Map users = new ConcurrentHashMap<>(); private final Map onlineUsers = new ConcurrentHashMap<>(); @@ -89,23 +135,24 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private static final String PACKET_ENCODER = "craftengine_encoder"; private static final String PACKET_DECODER = "craftengine_decoder"; - private static boolean hasModelEngine; - private static boolean hasViaVersion; + private final boolean hasModelEngine; + private final boolean hasViaVersion; + + private int[] blockStateRemapper; + private int[] modBlockStateRemapper; @SuppressWarnings("unchecked") public BukkitNetworkManager(BukkitCraftEngine plugin) { instance = this; - S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.s2cGamePackets()]; - C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS = new BiConsumer[PacketIdFinder.c2sGamePackets()]; - Arrays.fill(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); - Arrays.fill(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS, Handlers.DO_NOTHING); - hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; - hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; + this.s2cGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.CLIENTBOUND)]; + this.c2sGamePacketListeners = new ByteBufferPacketListener[PlayPacketIdHelper.count(PacketFlow.SERVERBOUND)]; + this.hasModelEngine = Bukkit.getPluginManager().getPlugin("ModelEngine") != null; + this.hasViaVersion = Bukkit.getPluginManager().getPlugin("ViaVersion") != null; this.plugin = plugin; // set up packet id this.packetIds = VersionHelper.isOrAbove1_20_5() ? new PacketIds1_20_5() : new PacketIds1_20(); // register packet handlers - this.registerPacketHandlers(); + this.registerPacketListeners(); PayloadHelper.registerDataTypes(); // set up packet senders this.packetConsumer = FastNMS.INSTANCE::method$Connection$send; @@ -156,6 +203,32 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return instance; } + @Override + public int remapBlockState(int stateId, boolean enableMod) { + return enableMod ? this.modBlockStateRemapper[stateId] : this.blockStateRemapper[stateId]; + } + + private void registerNMSPacketConsumer(final NMSPacketListener listener, @Nullable Class packet) { + if (packet == null) return; + this.nmsPacketListeners.put(packet, listener); + } + + private void registerS2CGamePacketListener(final ByteBufferPacketListener function, int id) { + if (id == -1) return; + if (id < 0 || id >= this.s2cGamePacketListeners.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + this.s2cGamePacketListeners[id] = function; + } + + private void registerC2SGamePacketListener(final ByteBufferPacketListener function, int id) { + if (id == -1) return; + if (id < 0 || id >= this.c2sGamePacketListeners.length) { + throw new IllegalArgumentException("Invalid packet id: " + id); + } + this.c2sGamePacketListeners[id] = function; + } + public void addFakePlayer(Player player) { FakeBukkitServerPlayer fakePlayer = new FakeBukkitServerPlayer(this.plugin); fakePlayer.setPlayer(player); @@ -189,65 +262,138 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - private void registerPacketHandlers() { - registerNMSPacketConsumer(PacketConsumers.PLAYER_INFO_UPDATE, NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); - registerNMSPacketConsumer(PacketConsumers.PLAYER_ACTION, NetworkReflections.clazz$ServerboundPlayerActionPacket); - registerNMSPacketConsumer(PacketConsumers.SWING_HAND, NetworkReflections.clazz$ServerboundSwingPacket); - registerNMSPacketConsumer(PacketConsumers.HELLO_C2S, NetworkReflections.clazz$ServerboundHelloPacket); - registerNMSPacketConsumer(PacketConsumers.USE_ITEM_ON, NetworkReflections.clazz$ServerboundUseItemOnPacket); - registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_BLOCK, NetworkReflections.clazz$ServerboundPickItemFromBlockPacket); - registerNMSPacketConsumer(PacketConsumers.SET_CREATIVE_SLOT, NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); - registerNMSPacketConsumer(PacketConsumers.LOGIN, NetworkReflections.clazz$ClientboundLoginPacket); - registerNMSPacketConsumer(PacketConsumers.RESPAWN, NetworkReflections.clazz$ClientboundRespawnPacket); - registerNMSPacketConsumer(PacketConsumers.SYNC_ENTITY_POSITION, NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); - registerNMSPacketConsumer(PacketConsumers.PICK_ITEM_FROM_ENTITY, NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); - registerNMSPacketConsumer(PacketConsumers.RENAME_ITEM, NetworkReflections.clazz$ServerboundRenameItemPacket); - registerNMSPacketConsumer(PacketConsumers.SIGN_UPDATE, NetworkReflections.clazz$ServerboundSignUpdatePacket); - registerNMSPacketConsumer(PacketConsumers.EDIT_BOOK, NetworkReflections.clazz$ServerboundEditBookPacket); - registerNMSPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD_1_20_2, VersionHelper.isOrAbove1_20_2() ? NetworkReflections.clazz$ServerboundCustomPayloadPacket : null); - registerNMSPacketConsumer(PacketConsumers.RESOURCE_PACK_RESPONSE, NetworkReflections.clazz$ServerboundResourcePackPacket); - registerNMSPacketConsumer(PacketConsumers.ENTITY_EVENT, NetworkReflections.clazz$ClientboundEntityEventPacket); - registerNMSPacketConsumer(PacketConsumers.MOVE_POS_AND_ROTATE_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); - registerNMSPacketConsumer(PacketConsumers.MOVE_POS_ENTITY, NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); - registerNMSPacketConsumer(PacketConsumers.ROTATE_HEAD, NetworkReflections.clazz$ClientboundRotateHeadPacket); - registerNMSPacketConsumer(PacketConsumers.SET_ENTITY_MOTION, NetworkReflections.clazz$ClientboundSetEntityMotionPacket); - registerNMSPacketConsumer(PacketConsumers.FINISH_CONFIGURATION, NetworkReflections.clazz$ClientboundFinishConfigurationPacket); - registerNMSPacketConsumer(PacketConsumers.LOGIN_FINISHED, NetworkReflections.clazz$ClientboundLoginFinishedPacket); - registerNMSPacketConsumer(PacketConsumers.UPDATE_TAGS, NetworkReflections.clazz$ClientboundUpdateTagsPacket); - registerNMSPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_21_5, VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); - registerS2CByteBufPacketConsumer(PacketConsumers.FORGET_LEVEL_CHUNK, this.packetIds.clientboundForgetLevelChunkPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_CHUNK_WITH_LIGHT, this.packetIds.clientboundLevelChunkWithLightPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SECTION_BLOCK_UPDATE, this.packetIds.clientboundSectionBlocksUpdatePacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.BLOCK_UPDATE, this.packetIds.clientboundBlockUpdatePacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_21_4() ? PacketConsumers.LEVEL_PARTICLE_1_21_4 : (VersionHelper.isOrAbove1_20_5() ? PacketConsumers.LEVEL_PARTICLE_1_20_5 : PacketConsumers.LEVEL_PARTICLE_1_20), this.packetIds.clientboundLevelParticlesPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.LEVEL_EVENT, this.packetIds.clientboundLevelEventPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.OPEN_SCREEN_1_20_3 : PacketConsumers.OPEN_SCREEN_1_20, this.packetIds.clientboundOpenScreenPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_TITLE_TEXT_1_20_3 : PacketConsumers.SET_TITLE_TEXT_1_20, this.packetIds.clientboundSetTitleTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_SUBTITLE_TEXT_1_20_3 : PacketConsumers.SET_SUBTITLE_TEXT_1_20, this.packetIds.clientboundSetSubtitleTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_ACTIONBAR_TEXT_1_20_3 : PacketConsumers.SET_ACTIONBAR_TEXT_1_20, this.packetIds.clientboundSetActionBarTextPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.BOSS_EVENT_1_20_3 : PacketConsumers.BOSS_EVENT_1_20, this.packetIds.clientboundBossEventPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SYSTEM_CHAT_1_20_3 : PacketConsumers.SYSTEM_CHAT_1_20, this.packetIds.clientboundSystemChatPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TAB_LIST_1_20_3 : PacketConsumers.TAB_LIST_1_20, this.packetIds.clientboundTabListPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.TEAM_1_20_3 : PacketConsumers.TEAM_1_20, this.packetIds.clientboundSetPlayerTeamPacket()); - registerS2CByteBufPacketConsumer(VersionHelper.isOrAbove1_20_3() ? PacketConsumers.SET_OBJECTIVE_1_20_3 : PacketConsumers.SET_OBJECTIVE_1_20, this.packetIds.clientboundSetObjectivePacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_SCORE_1_20_3, VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); - registerS2CByteBufPacketConsumer(PacketConsumers.ADD_RECIPE_BOOK, this.packetIds.clientboundRecipeBookAddPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.PLACE_GHOST_RECIPE, this.packetIds.clientboundPlaceGhostRecipePacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_RECIPES, this.packetIds.clientboundUpdateRecipesPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.UPDATE_ADVANCEMENTS, this.packetIds.clientboundUpdateAdvancementsPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.REMOVE_ENTITY, this.packetIds.clientboundRemoveEntitiesPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.ADD_ENTITY, this.packetIds.clientboundAddEntityPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SOUND, this.packetIds.clientboundSoundPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_ENTITY_DATA, this.packetIds.clientboundSetEntityDataPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_CONTENT, this.packetIds.clientboundContainerSetContentPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.CONTAINER_SET_SLOT, this.packetIds.clientboundContainerSetSlotPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_CURSOR_ITEM, this.packetIds.clientboundSetCursorItemPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_EQUIPMENT, this.packetIds.clientboundSetEquipmentPacket()); - registerS2CByteBufPacketConsumer(PacketConsumers.SET_PLAYER_INVENTORY_1_21_2, this.packetIds.clientboundSetPlayerInventoryPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.SET_CREATIVE_MODE_SLOT, this.packetIds.serverboundSetCreativeModeSlotPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.CONTAINER_CLICK_1_20, VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.INTERACT_ENTITY, this.packetIds.serverboundInteractPacket()); - registerC2SByteBufPacketConsumer(PacketConsumers.CUSTOM_PAYLOAD_1_20, VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket()); + public void registerBlockStatePacketListeners(Map map, int registrySize) { + int[] newMappings = new int[registrySize]; + for (int i = 0; i < registrySize; i++) { + newMappings[i] = i; + } + int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); + for (Map.Entry entry : map.entrySet()) { + newMappings[entry.getKey()] = entry.getValue(); + if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { + newMappingsMOD[entry.getKey()] = entry.getValue(); + } + } + for (int i = 0; i < newMappingsMOD.length; i++) { + if (BlockStateUtils.isVanillaBlock(i)) { + newMappingsMOD[i] = newMappings[i]; + } + } + this.blockStateRemapper = newMappings; + this.modBlockStateRemapper = newMappingsMOD; + registerS2CGamePacketListener(new LevelChunkWithLightListener(newMappings, newMappingsMOD, registrySize, RegistryUtils.currentBiomeRegistrySize()), this.packetIds.clientboundLevelChunkWithLightPacket()); + registerS2CGamePacketListener(new SectionBlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundSectionBlocksUpdatePacket()); + registerS2CGamePacketListener(new BlockUpdateListener(newMappings, newMappingsMOD), this.packetIds.clientboundBlockUpdatePacket()); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_21_4() ? + new LevelParticleListener1_21_4(newMappings, newMappingsMOD) : + (VersionHelper.isOrAbove1_20_5() ? + new LevelParticleListener1_20_5(newMappings, newMappingsMOD) : + new LevelParticleListener1_20(newMappings, newMappingsMOD)), + this.packetIds.clientboundLevelParticlesPacket() + ); + registerS2CGamePacketListener(new LevelEventListener(newMappings, newMappingsMOD), this.packetIds.clientboundLevelEventPacket()); + } + + private void registerPacketListeners() { + registerNMSPacketConsumer(new PlayerInfoUpdateListener(), NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); + registerNMSPacketConsumer(new PlayerActionListener(), NetworkReflections.clazz$ServerboundPlayerActionPacket); + registerNMSPacketConsumer(new SwingListener(), NetworkReflections.clazz$ServerboundSwingPacket); + registerNMSPacketConsumer(new HelloListener(), NetworkReflections.clazz$ServerboundHelloPacket); + registerNMSPacketConsumer(new UseItemOnListener(), NetworkReflections.clazz$ServerboundUseItemOnPacket); + registerNMSPacketConsumer(new PickItemFromBlockListener(), NetworkReflections.clazz$ServerboundPickItemFromBlockPacket); + registerNMSPacketConsumer(new PickItemFromEntityListener(), NetworkReflections.clazz$ServerboundPickItemFromEntityPacket); + registerNMSPacketConsumer(new SetCreativeSlotListener(), NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); + registerNMSPacketConsumer(new LoginListener(), NetworkReflections.clazz$ClientboundLoginPacket); + registerNMSPacketConsumer(new RespawnListener(), NetworkReflections.clazz$ClientboundRespawnPacket); + registerNMSPacketConsumer(new SyncEntityPositionListener(), NetworkReflections.clazz$ClientboundEntityPositionSyncPacket); + registerNMSPacketConsumer(new RenameItemListener(), NetworkReflections.clazz$ServerboundRenameItemPacket); + registerNMSPacketConsumer(new SignUpdateListener(), NetworkReflections.clazz$ServerboundSignUpdatePacket); + registerNMSPacketConsumer(new EditBookListener(), NetworkReflections.clazz$ServerboundEditBookPacket); + registerNMSPacketConsumer(new CustomPayloadListener1_20_2(), VersionHelper.isOrAbove1_20_2() ? NetworkReflections.clazz$ServerboundCustomPayloadPacket : null); + registerNMSPacketConsumer(new ResourcePackResponseListener(), NetworkReflections.clazz$ServerboundResourcePackPacket); + registerNMSPacketConsumer(new EntityEventListener(), NetworkReflections.clazz$ClientboundEntityEventPacket); + registerNMSPacketConsumer(new MovePosAndRotateEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$PosRot); + registerNMSPacketConsumer(new MovePosEntityListener(), NetworkReflections.clazz$ClientboundMoveEntityPacket$Pos); + registerNMSPacketConsumer(new RotateHeadListener(), NetworkReflections.clazz$ClientboundRotateHeadPacket); + registerNMSPacketConsumer(new SetEntityMotionListener(), NetworkReflections.clazz$ClientboundSetEntityMotionPacket); + registerNMSPacketConsumer(new FinishConfigurationListener(), NetworkReflections.clazz$ClientboundFinishConfigurationPacket); + registerNMSPacketConsumer(new LoginFinishedListener(), NetworkReflections.clazz$ClientboundLoginFinishedPacket); + registerNMSPacketConsumer(new UpdateTagsListener(), NetworkReflections.clazz$ClientboundUpdateTagsPacket); + registerNMSPacketConsumer(new ContainerClickListener1_21_5(), VersionHelper.isOrAbove1_21_5() ? NetworkReflections.clazz$ServerboundContainerClickPacket : null); + registerS2CGamePacketListener(new ForgetLevelChunkListener(), this.packetIds.clientboundForgetLevelChunkPacket()); + registerS2CGamePacketListener(new SetScoreListener1_20_3(), VersionHelper.isOrAbove1_20_3() ? this.packetIds.clientboundSetScorePacket() : -1); + registerS2CGamePacketListener(new AddRecipeBookListener(), this.packetIds.clientboundRecipeBookAddPacket()); + registerS2CGamePacketListener(new PlaceGhostRecipeListener(), this.packetIds.clientboundPlaceGhostRecipePacket()); + registerS2CGamePacketListener(new UpdateRecipesListener(), this.packetIds.clientboundUpdateRecipesPacket()); + registerS2CGamePacketListener(new UpdateAdvancementsListener(), this.packetIds.clientboundUpdateAdvancementsPacket()); + registerS2CGamePacketListener(new RemoveEntityListener(), this.packetIds.clientboundRemoveEntitiesPacket()); + registerS2CGamePacketListener(new SoundListener(), this.packetIds.clientboundSoundPacket()); + registerS2CGamePacketListener(new ContainerSetContentListener(), this.packetIds.clientboundContainerSetContentPacket()); + registerS2CGamePacketListener(new ContainerSetSlotListener(), this.packetIds.clientboundContainerSetSlotPacket()); + registerS2CGamePacketListener(new SetCursorItemListener(), this.packetIds.clientboundSetCursorItemPacket()); + registerS2CGamePacketListener(new SetEquipmentListener(), this.packetIds.clientboundSetEquipmentPacket()); + registerS2CGamePacketListener(new SetPlayerInventoryListener1_21_2(), VersionHelper.isOrAbove1_21_2() ? this.packetIds.clientboundSetPlayerInventoryPacket() : -1); + registerS2CGamePacketListener(new SetEntityDataListener(), this.packetIds.clientboundSetEntityDataPacket()); + registerC2SGamePacketListener(new SetCreativeModeSlotListener(), this.packetIds.serverboundSetCreativeModeSlotPacket()); + registerC2SGamePacketListener(new ContainerClick1_20(), VersionHelper.isOrAbove1_21_5() ? -1 : this.packetIds.serverboundContainerClickPacket()); + registerC2SGamePacketListener(new InteractEntityListener(), this.packetIds.serverboundInteractPacket()); + registerC2SGamePacketListener(new CustomPayloadListener1_20(), VersionHelper.isOrAbove1_20_2() ? -1 : this.packetIds.serverboundCustomPayloadPacket()); + registerS2CGamePacketListener(new AddEntityListener(RegistryUtils.currentEntityTypeRegistrySize()), this.packetIds.clientboundAddEntityPacket()); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new OpenScreenListener1_20_3() : + new OpenScreenListener1_20(), + this.packetIds.clientboundOpenScreenPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SystemChatListener1_20_3() : + new SystemChatListener1_20(), + this.packetIds.clientboundSystemChatPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetActionBarListener1_20_3() : + new SetActionBarListener1_20(), + this.packetIds.clientboundSetActionBarTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new TabListListener1_20_3() : + new TabListListener1_20(), + this.packetIds.clientboundTabListPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetTitleListener1_20_3() : + new SetTitleListener1_20(), + this.packetIds.clientboundSetTitleTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetSubtitleListener1_20_3() : + new SetSubtitleListener1_20(), + this.packetIds.clientboundSetSubtitleTextPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new BossEventListener1_20_3() : + new BossEventListener1_20(), + this.packetIds.clientboundBossEventPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new TeamListener1_20_3() : + new TeamListener1_20(), + this.packetIds.clientboundSetPlayerTeamPacket() + ); + registerS2CGamePacketListener( + VersionHelper.isOrAbove1_20_3() ? + new SetObjectiveListener1_20_3() : + new SetObjectiveListener1_20(), + this.packetIds.clientboundSetObjectivePacket() + ); } @EventHandler(priority = EventPriority.LOWEST) @@ -383,11 +529,11 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } - public static boolean hasModelEngine() { + public boolean hasModelEngine() { return hasModelEngine; } - public static boolean hasViaVersion() { + public boolean hasViaVersion() { return hasViaVersion; } @@ -709,7 +855,7 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes private void onNMSPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { Debugger.PACKET.debug(() -> "[C->S]" + packet.getClass()); - handleNMSPacket(user, event, packet); + handleReceiveNMSPacket(user, event, packet); } private void onNMSPacketSend(NetWorkUser player, NMSPacketEvent event, Object packet) { @@ -720,25 +866,54 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes } } else { Debugger.PACKET.debug(() -> "[S->C]" + packet.getClass()); - handleNMSPacket(player, event, packet); + handleSendNMSPacket(player, event, packet); } } - protected void handleNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { - Optional.ofNullable(NMS_PACKET_HANDLERS.get(packet.getClass())) - .ifPresent(function -> function.accept(user, event, packet)); + protected void handleReceiveNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { + NMSPacketListener nmsPacketListener = this.nmsPacketListeners.get(packet.getClass()); + if (nmsPacketListener != null) { + try { + nmsPacketListener.onPacketReceive(user, event, packet); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling packet " + packet.getClass(), t); + } + } + } + + protected void handleSendNMSPacket(NetWorkUser user, NMSPacketEvent event, Object packet) { + NMSPacketListener nmsPacketListener = this.nmsPacketListeners.get(packet.getClass()); + if (nmsPacketListener != null) { + try { + nmsPacketListener.onPacketSend(user, event, packet); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling packet " + packet.getClass(), t); + } + } } protected void handleS2CByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(S2C_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) - .ifPresent(function -> function.accept(user, event)); + ByteBufferPacketListener s2cGamePacketListener = this.s2cGamePacketListeners[packetID]; + if (s2cGamePacketListener != null) { + try { + s2cGamePacketListener.onPacketSend(user, event); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling sent packet id: " + packetID, t); + } + } } protected void handleC2SByteBufPacket(NetWorkUser user, ByteBufPacketEvent event) { int packetID = event.packetID(); - Optional.ofNullable(C2S_GAME_BYTE_BUFFER_PACKET_HANDLERS[packetID]) - .ifPresent(function -> function.accept(user, event)); + ByteBufferPacketListener c2sGamePacketListener = this.c2sGamePacketListeners[packetID]; + if (c2sGamePacketListener != null) { + try { + c2sGamePacketListener.onPacketReceive(user, event); + } catch (Throwable t) { + this.plugin.logger().warn("An error occurred when handling received packet id: " + packetID, t); + } + } } private void compress(ChannelHandlerContext ctx, ByteBuf input) { @@ -784,13 +959,2741 @@ public class BukkitNetworkManager implements NetworkManager, Listener, PluginMes return output; } - @FunctionalInterface - public interface Handlers extends BiConsumer { - Handlers DO_NOTHING = doNothing(); + /* + * + * + * Packet Listener Implementations + * + * + */ + public static class HelloListener implements NMSPacketListener { - static Handlers doNothing() { - return (user, byteBufPacketEvent) -> { + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + String name; + try { + name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get name from ServerboundHelloPacket", t); + return; + } + player.setUnverifiedName(name); + if (VersionHelper.isOrAbove1_20_2()) { + UUID uuid; + try { + uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get uuid from ServerboundHelloPacket", t); + return; + } + player.setUnverifiedUUID(uuid); + } else { + Optional uuid; + try { + // noinspection unchecked + uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().severe("Failed to get uuid from ServerboundHelloPacket", t); + return; + } + if (uuid.isPresent()) { + player.setUnverifiedUUID(uuid.get()); + } else { + player.setUnverifiedUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); + } + } + } + } + + public static class PlayerActionListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + Player platformPlayer = player.platformPlayer(); + World world = platformPlayer.getWorld(); + Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); + BlockPos pos = LocationUtils.fromBlockPos(blockPos); + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handlePlayerActionPacketOnMainThread(player, world, pos, packet); + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); + } + }, () -> {}); + } else { + handlePlayerActionPacketOnMainThread(player, world, pos, packet); + } + } + + private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { + Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); + if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); + int stateId = BlockStateUtils.blockStateToId(blockState); + // not a custom block + if (BlockStateUtils.isVanillaBlock(stateId)) { + if (Config.enableSoundSystem()) { + Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { + player.startMiningBlock(pos, blockState, null); + return; + } + } + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } else { + player.setClientSideCanBreakBlock(true); + } + return; + } + if (player.isAdventureMode()) { + if (Config.simplifyAdventureBreakCheck()) { + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); + if (!player.canBreak(pos, state.vanillaBlockState().literalObject())) { + player.preventMiningBlock(); + return; + } + } else { + if (!player.canBreak(pos, null)) { + player.preventMiningBlock(); + return; + } + } + } + player.startMiningBlock(pos, blockState, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId)); + } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) { + if (player.isMiningBlock()) { + player.abortMiningBlock(); + } + } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$STOP_DESTROY_BLOCK) { + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } + } + } + } + + public static class SwingListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (!player.isMiningBlock()) return; + Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); + if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { + player.onSwingHand(); + } + } + } + + public static class UseItemOnListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (player.isMiningBlock()) { + player.stopMiningBlock(); + } + } + } + + public static class PlayerInfoUpdateListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.interceptPlayerInfo()) return; + List entries = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$entries(packet); + if (entries instanceof MarkedArrayList) { + return; + } + EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); + outer: { + for (Object entry : enums) { + if (entry == NetworkReflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { + break outer; + } + } + return; + } + boolean isChanged = false; + List newEntries = new MarkedArrayList<>(); + for (Object entry : entries) { + Object mcComponent = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$Entry$displayName(entry); + if (mcComponent == null) { + newEntries.add(entry); + } else { + String json = ComponentUtils.minecraftToJson(mcComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) { + newEntries.add(entry); + } else { + Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, + ComponentUtils.adventureToMinecraft(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + newEntries.add(newEntry); + isChanged = true; + } + } + } + if (isChanged) { + event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enums, newEntries)); + } + } + } + + public static class PickItemFromBlockListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + Player player = (Player) user.platformPlayer(); + if (player == null) return; + Object pos; + try { + pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get pos from ServerboundPickItemFromBlockPacket", e); + return; + } + if (VersionHelper.isFolia()) { + int x = FastNMS.INSTANCE.field$Vec3i$x(pos); + int z = FastNMS.INSTANCE.field$Vec3i$z(pos); + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromBlockPacketOnMainThread(player, pos); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket on region thread", e); + } + }, player.getWorld(), x >> 4, z >> 4); + } else { + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromBlockPacketOnMainThread(player, pos); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket on main thread", e); + } + }); + } + } + + private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable { + Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); + Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); + ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); + if (state == null) return; + Key itemId = state.settings().itemId(); + if (itemId == null) return; + pickItem(player, itemId, pos, null); + } + } + + public static class PickItemFromEntityListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get entityId from ServerboundPickItemFromEntityPacket", e); + return; + } + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + if (furniture == null) return; + Player player = (Player) user.platformPlayer(); + if (player == null) return; + if (VersionHelper.isFolia()) { + player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handlePickItemFromEntityOnMainThread(player, furniture); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket on region thread", e); + } + }, () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().sync().run(() -> { + try { + handlePickItemFromEntityOnMainThread(player, furniture); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket on main thread", e); + } + }); + } + } + + private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable { + Key itemId = furniture.config().settings().itemId(); + if (itemId == null) return; + pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); + } + } + + private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable { + ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); + if (itemStack == null) { + CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); + return; + } + assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; + if (VersionHelper.isOrAbove1_21_5()) { + CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), + FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); + } else { + CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( + CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); + } + } + + + public static class SetCreativeSlotListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (VersionHelper.isOrAbove1_21_4()) return; + if (!user.isOnline()) return; + BukkitServerPlayer player = (BukkitServerPlayer) user; + if (VersionHelper.isFolia()) { + player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { + try { + handleSetCreativeSlotPacketOnMainThread(player, packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket on region thread", e); + } + }, () -> {}); + } else { + try { + handleSetCreativeSlotPacketOnMainThread(player, packet); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket on main thread", e); + } + } + } + + private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable { + Player bukkitPlayer = player.platformPlayer(); + if (bukkitPlayer == null) return; + if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; + int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet); + if (slot < 36 || slot > 44) return; + ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); + if (ItemStackUtils.isEmpty(item)) return; + if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { + return; + } + double interactionRange = player.getCachedInteractionRange(); + // do ray trace to get current block + RayTraceResult result = bukkitPlayer.rayTraceBlocks(interactionRange, FluidCollisionMode.NEVER); + if (result == null) return; + Block hitBlock = result.getHitBlock(); + if (hitBlock == null) return; + ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(hitBlock); + // not a custom block + if (state == null || state.isEmpty()) return; + Key itemId = state.settings().itemId(); + // no item available + if (itemId == null) return; + Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().literalObject()); + Object vanillaBlockItem = FastNMS.INSTANCE.method$Block$asItem(vanillaBlock); + if (vanillaBlockItem == null) return; + Key addItemId = KeyUtils.namespacedKey2Key(item.getType().getKey()); + Key blockItemId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, vanillaBlockItem)); + if (!addItemId.equals(blockItemId)) return; + ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, player); + if (ItemStackUtils.isEmpty(itemStack)) { + CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); + return; + } + PlayerInventory inventory = bukkitPlayer.getInventory(); + int sameItemSlot = -1; + int emptySlot = -1; + for (int i = 0; i < 9 + 27; i++) { + ItemStack invItem = inventory.getItem(i); + if (ItemStackUtils.isEmpty(invItem)) { + if (emptySlot == -1 && i < 9) emptySlot = i; + continue; + } + if (invItem.getType().equals(itemStack.getType()) && invItem.getItemMeta().equals(itemStack.getItemMeta())) { + if (sameItemSlot == -1) sameItemSlot = i; + } + } + if (sameItemSlot != -1) { + if (sameItemSlot < 9) { + inventory.setHeldItemSlot(sameItemSlot); + ItemStack previousItem = inventory.getItem(slot - 36); + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, previousItem)); + } else { + ItemStack sameItem = inventory.getItem(sameItemSlot); + int finalSameItemSlot = sameItemSlot; + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> { + inventory.setItem(finalSameItemSlot, new ItemStack(Material.AIR)); + inventory.setItem(slot - 36, sameItem); + }); + } + } else { + if (item.getAmount() == 1) { + if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) { + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); + return; + } + if (emptySlot != -1) { + inventory.setHeldItemSlot(emptySlot); + inventory.setItem(emptySlot, itemStack); + } else { + BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); + } + } + } + } + } + + public static class LoginListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + player.setConnectionState(ConnectionState.PLAY); + Object dimensionKey; + try { + if (!VersionHelper.isOrAbove1_20_2()) { + dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); + } else { + Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + } + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get dimensionKey from ClientboundLoginPacket", t); + return; + } + Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); + World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); + if (world != null) { + int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; + player.setClientSideSectionCount(sectionCount); + player.setClientSideDimension(Key.of(location.toString())); + } else { + CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist"); + } + } + } + + public static class RespawnListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + player.clearView(); + Object dimensionKey; + try { + if (!VersionHelper.isOrAbove1_20_2()) { + dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); + } else { + Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); + dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); + } + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get dimensionKey from ClientboundRespawnPacket", t); + return; + } + Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); + World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); + if (world != null) { + int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; + player.setClientSideSectionCount(sectionCount); + player.setClientSideDimension(Key.of(location.toString())); + player.clearTrackedChunks(); + } else { + CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); + } + } + } + + // 1.21.2+ + public static class SyncEntityPositionListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleSyncEntityPosition(user, event, packet); + } + } + } + + public static class RenameItemListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterAnvil()) return; + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { + return; + } + String message; + try { + message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get message from ServerboundRenameItemPacket", t); + return; + } + if (message != null && !message.isEmpty()) { + // check bypass + FontManager manager = CraftEngine.instance().fontManager(); + IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); + if (result.has()) { + try { + NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to set field 'name' for ServerboundRenameItemPacket", e); + } + } + } + } + } + + public static class SignUpdateListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterSign()) return; + // check bypass + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { + return; + } + String[] lines; + try { + lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get lines from ServerboundSignUpdatePacket", t); + return; + } + FontManager manager = CraftEngine.instance().fontManager(); + if (!manager.isDefaultFontInUse()) return; + for (int i = 0; i < lines.length; i++) { + String line = lines[i]; + if (line != null && !line.isEmpty()) { + IllegalCharacterProcessResult result = manager.processIllegalCharacters(line); + if (result.has()) { + lines[i] = result.text(); + } + } + } + } + } + + public static class EditBookListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!Config.filterBook()) return; + FontManager manager = CraftEngine.instance().fontManager(); + if (!manager.isDefaultFontInUse()) return; + // check bypass + if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_BOOK)) { + return; + } + + boolean changed = false; + + List pages; + try { + // noinspection unchecked + pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get pages from ServerboundEditBookPacket", t); + return; + } + List newPages = new ArrayList<>(pages.size()); + Optional title; + try { + // noinspection unchecked + title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get title from ServerboundEditBookPacket", t); + return; + } + Optional newTitle; + + if (title.isPresent()) { + String titleStr = title.get(); + Pair result = processClientString(titleStr, manager); + newTitle = Optional.of(result.right()); + if (result.left()) { + changed = true; + } + } else { + newTitle = Optional.empty(); + } + + for (String page : pages) { + Pair result = processClientString(page, manager); + newPages.add(result.right()); + if (result.left()) { + changed = true; + } + } + + if (changed) { + try { + Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( + (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), + newPages, + newTitle + ); + event.replacePacket(newPacket); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to construct ServerboundEditBookPacket", t); + } + } + } + + private static Pair processClientString(String original, FontManager manager) { + if (original.isEmpty()) { + return Pair.of(false, original); + } + int[] codepoints = CharacterUtils.charsToCodePoints(original.toCharArray()); + int[] newCodepoints = new int[codepoints.length]; + boolean hasIllegal = false; + for (int i = 0; i < codepoints.length; i++) { + int codepoint = codepoints[i]; + if (manager.isIllegalCodepoint(codepoint)) { + newCodepoints[i] = '*'; + hasIllegal = true; + } else { + newCodepoints[i] = codepoint; + } + } + return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); + } + } + + public static class CustomPayloadListener1_20_2 implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!VersionHelper.isOrAbove1_20_2()) return; + Object payload; + try { + payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get payload from ServerboundCustomPayloadPacket", t); + return; + } + Payload clientPayload; + if (VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { + clientPayload = DiscardedPayload.from(payload); + } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$ServerboundCustomPayloadPacket$UnknownPayload.isInstance(payload)) { + clientPayload = UnknownPayload.from(payload); + } else { + return; + } + if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; + PayloadHelper.handleReceiver(clientPayload, user); + } + } + + public static class ResourcePackResponseListener implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object action = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$action(packet); + + if (VersionHelper.isOrAbove1_20_3()) { + UUID uuid = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$id(packet); + if (!user.isResourcePackLoading(uuid)) { + // 不是CraftEngine发送的资源包,不管 + return; + } + } + + if (action == null) { + user.kick(Component.text("Corrupted ResourcePackResponse Packet")); + return; + } + + // 检查是否是拒绝 + if (Config.kickOnDeclined()) { + if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DISCARDED) { + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + return; + } + } + + // 检查是否失败 + if (Config.kickOnFailedApply()) { + if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD + || (VersionHelper.isOrAbove1_20_3() && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$INVALID_URL)) { + user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); + return; + } + } + + boolean isTerminal = action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$ACCEPTED && action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$DOWNLOADED; + if (isTerminal && VersionHelper.isOrAbove1_20_2()) { + event.setCancelled(true); + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) return; + // 主线程上处理这个包 + CraftEngine.instance().scheduler().executeSync(() -> { + try { + // 当客户端发出多次成功包的时候,finish会报错,我们忽略他 + NetworkReflections.methodHandle$ServerCommonPacketListener$handleResourcePackResponse.invokeExact(packetListener, packet); + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$ServerResourcePackConfigurationTask$TYPE); + } catch (Throwable e) { + Debugger.RESOURCE_PACK.warn(() -> "Cannot finish current task", e); + } + }); + } + } + } + + public static class EntityEventListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object player = user.serverPlayer(); + if (player == null) return; + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundEntityEventPacket", t); + return; + } + if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; + byte eventId; + try { + eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get event id from ClientboundEntityEventPacket", t); + return; + } + if (eventId >= 24 && eventId <= 28) { + CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); + } + } + } + + public static class MovePosAndRotateEntityListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMoveAndRotate(user, event, packet); + } + } + } + + public static class MovePosEntityListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); + EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); + if (handler != null) { + handler.handleMove(user, event, packet); + } + } + } + + public static class RotateHeadListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundRotateHeadPacket$entityIdGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundRotateHeadPacket", t); + return; + } + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + } + } + + public static class SetEntityMotionListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!VersionHelper.isOrAbove1_21_6()) return; + int entityId; + try { + entityId = (int) NetworkReflections.methodHandle$ClientboundSetEntityMotionPacket$idGetter.invokeExact(packet); + } catch (Throwable t) { + CraftEngine.instance().logger().warn("Failed to get entity id from ClientboundSetEntityMotionPacket", t); + return; + } + if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { + event.setCancelled(true); + } + } + } + + public static class FinishConfigurationListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + if (!VersionHelper.isOrAbove1_20_2() || !Config.sendPackOnJoin()) { + // 防止后期调试进配置阶段造成问题 + user.setShouldProcessFinishConfiguration(false); + return; + } + + if (!user.shouldProcessFinishConfiguration()) return; + Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); + if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) { + return; + } + + // 防止后续加入的JoinWorldTask再次处理 + user.setShouldProcessFinishConfiguration(false); + + // 检查用户UUID是否已经校验 + if (!user.isUUIDVerified()) { + if (Config.strictPlayerUuidValidation()) { + TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); + user.kick(Component.translatable("disconnect.loginFailedInfo").arguments(Component.translatable("argument.uuid.invalid"))); + return; + } + if (Config.debugResourcePack()) { + TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); + } + } + + // 取消 ClientboundFinishConfigurationPacket,让客户端发呆,并结束掉当前的进入世界任务 + event.setCancelled(true); + try { + CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$JoinWorldTask$TYPE); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to finish current task for " + user.name(), e); + } + + if (VersionHelper.isOrAbove1_20_5()) { + // 1.20.5+开始会检查是否结束需要重新设置回去,不然不会发keepAlive包 + try { + CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to set the 'closed' field of ServerCommonPacketListenerImpl for" + user.name(), e); + } + } + + // 请求资源包 + ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); + host.requestResourcePackDownloadLink(user.uuid()).whenComplete((dataList, t) -> { + if (t != null) { + CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t); + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + if (dataList.isEmpty()) { + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + Queue configurationTasks; + try { + // noinspection unchecked + configurationTasks = (Queue) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener); + } catch (Throwable e) { + CraftEngine.instance().logger().warn("Failed to get configuration tasks for player " + user.name(), e); + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + return; + } + // 向配置阶段连接的任务重加入资源包的任务 + for (ResourcePackDownloadData data : dataList) { + configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask(ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1()))); + user.addResourcePackUUID(data.uuid()); + } + // 最后再加入一个 JoinWorldTask 并开始资源包任务 + FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); + }); + } + } + + public static class LoginFinishedListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet); + user.setVerifiedName(gameProfile.getName()); + user.setVerifiedUUID(gameProfile.getId()); + } + } + + public static class UpdateTagsListener implements NMSPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket(); + if (packet.equals(modifiedPacket) || modifiedPacket == null) return; + event.replacePacket(modifiedPacket); + } + } + + public static class ContainerClickListener1_21_5 implements NMSPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + int containerId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$containerId(packet); + int stateId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$stateId(packet); + short slotNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$slotNum(packet); + byte buttonNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$buttonNum(packet); + Object clickType = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$clickType(packet); + @SuppressWarnings("unchecked") + Int2ObjectMap changedSlots = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$changedSlots(packet); + Int2ObjectMap newChangedSlots = new Int2ObjectOpenHashMap<>(changedSlots.size()); + for (Int2ObjectMap.Entry entry : changedSlots.int2ObjectEntrySet()) { + newChangedSlots.put(entry.getIntKey(), FastNMS.INSTANCE.constructor$InjectedHashedStack(entry.getValue(), player)); + } + Object carriedItem = FastNMS.INSTANCE.constructor$InjectedHashedStack(FastNMS.INSTANCE.field$ServerboundContainerClickPacket$carriedItem(packet), player); + event.replacePacket(FastNMS.INSTANCE.constructor$ServerboundContainerClickPacket(containerId, stateId, slotNum, buttonNum, clickType, Int2ObjectMaps.unmodifiable(newChangedSlots), carriedItem)); + } + } + + public static class ForgetLevelChunkListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + FriendlyByteBuf buf = event.getBuffer(); + CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); + if (VersionHelper.isOrAbove1_20_2()) { + long chunkPos = buf.readLong(); + user.removeTrackedChunk(chunkPos); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos); + if (ceChunk != null) { + ceChunk.despawnBlockEntities(player); + } + } else { + int x = buf.readInt(); + int y = buf.readInt(); + user.removeTrackedChunk(ChunkPos.asLong(x, y)); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(x, y); + if (ceChunk != null) { + ceChunk.despawnBlockEntities(player); + } + } + } + } + + public static class LevelChunkWithLightListener implements ByteBufferPacketListener { + private static BiConsumer> biomeRemapper = null; + + public static void setBiomeRemapper(BiConsumer> remapper) { + biomeRemapper = remapper; + } + + public static void remapBiomes(NetWorkUser user, PalettedContainer biomes) { + if (biomeRemapper != null) { + biomeRemapper.accept(user, biomes); + } + } + + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + private final IntIdentityList biomeList; + private final IntIdentityList blockList; + + public LevelChunkWithLightListener(int[] blockStateMapper, int[] modBlockStateMapper, int blockRegistrySize, int biomeRegistrySize) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + this.biomeList = new IntIdentityList(biomeRegistrySize); + this.blockList = new IntIdentityList(blockRegistrySize); + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + BukkitServerPlayer player = (BukkitServerPlayer) user; + FriendlyByteBuf buf = event.getBuffer(); + int chunkX = buf.readInt(); + int chunkZ = buf.readInt(); + boolean named = !VersionHelper.isOrAbove1_20_2(); + // ClientboundLevelChunkPacketData + int heightmapsCount = 0; + Map heightmapsMap = null; + net.momirealms.sparrow.nbt.Tag heightmaps = null; + if (VersionHelper.isOrAbove1_21_5()) { + heightmapsMap = new HashMap<>(); + heightmapsCount = buf.readVarInt(); + for (int i = 0; i < heightmapsCount; i++) { + int key = buf.readVarInt(); + long[] value = buf.readLongArray(); + heightmapsMap.put(key, value); + } + } else { + heightmaps = buf.readNbt(named); + } + + int varInt = buf.readVarInt(); + byte[] buffer = new byte[varInt]; + buf.readBytes(buffer); + int blockEntitiesDataCount = buf.readVarInt(); + List blockEntitiesData = new ArrayList<>(); + for (int i = 0; i < blockEntitiesDataCount; i++) { + byte packedXZ = buf.readByte(); + short y = buf.readShort(); + int type = buf.readVarInt(); + Tag tag = buf.readNbt(named); + BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag); + blockEntitiesData.add(blockEntityData); + } + // ClientboundLightUpdatePacketData + BitSet skyYMask = buf.readBitSet(); + BitSet blockYMask = buf.readBitSet(); + BitSet emptySkyYMask = buf.readBitSet(); + BitSet emptyBlockYMask = buf.readBitSet(); + List skyUpdates = buf.readByteArrayList(2048); + List blockUpdates = buf.readByteArrayList(2048); + // 开始处理 + if (user.clientModEnabled()) { + ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); + FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { + MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(user, mcSection.biomeContainer()); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(s -> this.modBlockStateMapper[s]); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = this.modBlockStateMapper[state]; + if (newState != state) { + container.set(j, newState); + } + } + } + mcSection.writePacket(newBuf); + } + buffer = newBuf.array(); + } else { + ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); + FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); + FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); + for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { + MCSection mcSection = new MCSection(user.clientBlockList(), this.blockList, this.biomeList); + mcSection.readPacket(friendlyByteBuf); + PalettedContainer container = mcSection.blockStateContainer(); + remapBiomes(user, mcSection.biomeContainer()); + Palette palette = container.data().palette(); + if (palette.canRemap()) { + palette.remap(s -> this.blockStateMapper[s]); + } else { + for (int j = 0; j < 4096; j++) { + int state = container.get(j); + int newState = this.blockStateMapper[state]; + if (newState != state) { + container.set(j, newState); + } + } + } + mcSection.writePacket(newBuf); + } + buffer = newBuf.array(); + } + + // 开始修改 + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeInt(chunkX); + buf.writeInt(chunkZ); + if (VersionHelper.isOrAbove1_21_5()) { + buf.writeVarInt(heightmapsCount); + for (Map.Entry entry : heightmapsMap.entrySet()) { + buf.writeVarInt(entry.getKey()); + buf.writeLongArray(entry.getValue()); + } + } else { + buf.writeNbt(heightmaps, named); + } + buf.writeVarInt(buffer.length); + buf.writeBytes(buffer); + buf.writeVarInt(blockEntitiesDataCount); + for (BlockEntityData blockEntityData : blockEntitiesData) { + buf.writeByte(blockEntityData.packedXZ()); + buf.writeShort(blockEntityData.y()); + buf.writeVarInt(blockEntityData.type()); + buf.writeNbt(blockEntityData.tag(), named); + } + buf.writeBitSet(skyYMask); + buf.writeBitSet(blockYMask); + buf.writeBitSet(emptySkyYMask); + buf.writeBitSet(emptyBlockYMask); + buf.writeByteArrayList(skyUpdates); + buf.writeByteArrayList(blockUpdates); + + ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); + // 记录加载的区块 + player.addTrackedChunk(chunkPos.longKey, new ChunkStatus()); + + CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); + CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey); + if (ceChunk != null) { + ceChunk.spawnBlockEntities(player); + } + } + } + + public static class SectionBlockUpdateListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public SectionBlockUpdateListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (user.clientModEnabled()) { + FriendlyByteBuf buf = event.getBuffer(); + long pos = buf.readLong(); + int blocks = buf.readVarInt(); + short[] positions = new short[blocks]; + int[] states = new int[blocks]; + for (int i = 0; i < blocks; i++) { + long k = buf.readVarLong(); + positions[i] = (short) ((int) (k & 4095L)); + states[i] = modBlockStateMapper[((int) (k >>> 12))]; + } + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeLong(pos); + buf.writeVarInt(blocks); + for (int i = 0; i < blocks; i++) { + buf.writeVarLong((long) states[i] << 12 | positions[i]); + } + event.setChanged(true); + } else { + FriendlyByteBuf buf = event.getBuffer(); + long pos = buf.readLong(); + int blocks = buf.readVarInt(); + short[] positions = new short[blocks]; + int[] states = new int[blocks]; + for (int i = 0; i < blocks; i++) { + long k = buf.readVarLong(); + positions[i] = (short) ((int) (k & 4095L)); + states[i] = blockStateMapper[((int) (k >>> 12))]; + } + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeLong(pos); + buf.writeVarInt(blocks); + for (int i = 0; i < blocks; i++) { + buf.writeVarLong((long) states[i] << 12 | positions[i]); + } + event.setChanged(true); + } + } + } + + public static class BlockUpdateListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public BlockUpdateListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + BlockPos pos = buf.readBlockPos(); + int before = buf.readVarInt(); + if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { + return; + } + int state = user.clientModEnabled() ? modBlockStateMapper[before] : blockStateMapper[before]; + if (state == before) { + return; + } + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBlockPos(pos); + buf.writeVarInt(state); + } + } + + public static class LevelParticleListener1_21_4 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_21_4(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean overrideLimiter = buf.readBoolean(); + boolean alwaysShow = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBoolean(overrideLimiter); + buf.writeBoolean(alwaysShow); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + } + } + + public static class LevelParticleListener1_20_5 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_20_5(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean overrideLimiter = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeBoolean(overrideLimiter); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); + } + } + + public static class LevelParticleListener1_20 implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelParticleListener1_20(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + Object particleType = FastNMS.INSTANCE.method$FriendlyByteBuf$readById(buf, MBuiltInRegistries.PARTICLE_TYPE); + boolean overrideLimiter = buf.readBoolean(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + float xDist = buf.readFloat(); + float yDist = buf.readFloat(); + float zDist = buf.readFloat(); + float maxSpeed = buf.readFloat(); + int count = buf.readInt(); + Object option = FastNMS.INSTANCE.method$ClientboundLevelParticlesPacket$readParticle(buf, particleType); + if (option == null) return; + if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; + Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); + int id = BlockStateUtils.blockStateToId(blockState); + int remapped = user.clientModEnabled() ? modBlockStateMapper[id] : blockStateMapper[id]; + if (remapped == id) return; + Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); + Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeId(buf, remappedOption, MBuiltInRegistries.PARTICLE_TYPE); + buf.writeBoolean(overrideLimiter); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeFloat(xDist); + buf.writeFloat(yDist); + buf.writeFloat(zDist); + buf.writeFloat(maxSpeed); + buf.writeInt(count); + FastNMS.INSTANCE.method$ParticleOptions$writeToNetwork(remappedOption, buf); + } + } + + public static class LevelEventListener implements ByteBufferPacketListener { + private final int[] blockStateMapper; + private final int[] modBlockStateMapper; + + public LevelEventListener(int[] blockStateMapper, int[] modBlockStateMapper) { + this.blockStateMapper = blockStateMapper; + this.modBlockStateMapper = modBlockStateMapper; + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int eventId = buf.readInt(); + if (eventId != WorldEvents.BLOCK_BREAK_EFFECT) return; + BlockPos blockPos = buf.readBlockPos(); + int state = buf.readInt(); + boolean global = buf.readBoolean(); + int newState = user.clientModEnabled() ? modBlockStateMapper[state] : blockStateMapper[state]; + Object blockState = BlockStateUtils.idToBlockState(newState); + Object block = BlockStateUtils.getBlockOwner(blockState); + if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { + Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); + Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); + Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); + Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mappedSoundId != null) { + Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); + Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); + Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( + mappedBreakSoundHolder, + CoreReflections.instance$SoundSource$BLOCKS, + blockPos.x() + 0.5, + blockPos.y() + 0.5, + blockPos.z() + 0.5, + (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, + FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, + RandomUtils.generateRandomLong() + ); + user.sendPacket(packet, true); + } + } + if (newState == state) { + return; + } + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeInt(eventId); + buf.writeBlockPos(blockPos); + buf.writeInt(newState); + buf.writeBoolean(global); + } + } + + public static class OpenScreenListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptContainer()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readVarInt(); + int type = buf.readVarInt(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(containerId); + buf.writeVarInt(type); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class OpenScreenListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptContainer()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readVarInt(); + int type = buf.readVarInt(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(containerId); + buf.writeVarInt(type); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SystemChatListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSystemChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + String jsonOrPlainString = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); + if (tokens.isEmpty()) return; + boolean overlay = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeBoolean(overlay); + } + } + + public static class SystemChatListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSystemChat()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + boolean overlay = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeBoolean(overlay); + } + } + + public static class TabListListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTabList()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json1 = buf.readUtf(); + String json2 = buf.readUtf(); + Map tokens1 = CraftEngine.instance().fontManager().matchTags(json1); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(json2); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + buf.writeUtf(tokens1.isEmpty() ? json1 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json1), tokens1, context))); + buf.writeUtf(tokens2.isEmpty() ? json2 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json2), tokens2, context))); + } + } + + public static class TabListListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTabList()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt1 = buf.readNbt(false); + if (nbt1 == null) return; + Tag nbt2 = buf.readNbt(false); + if (nbt2 == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(nbt1.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(nbt2.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + buf.writeNbt(tokens1.isEmpty() ? nbt1 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt1), tokens1, context)), false); + buf.writeNbt(tokens2.isEmpty() ? nbt2 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt2), tokens2, context)), false); + } + } + + public static class SetActionBarListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptActionBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetActionBarListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptActionBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SetTitleListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetTitleListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class SetSubtitleListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + + public static class SetSubtitleListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTitle()) return; + FriendlyByteBuf buf = event.getBuffer(); + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + + public static class BossEventListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptBossBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + UUID uuid = buf.readUUID(); + int actionType = buf.readVarInt(); + if (actionType == 0) { + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + float health = buf.readFloat(); + int color = buf.readVarInt(); + int division = buf.readVarInt(); + byte flag = buf.readByte(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeFloat(health); + buf.writeVarInt(color); + buf.writeVarInt(division); + buf.writeByte(flag); + } else if (actionType == 3) { + String json = buf.readUtf(); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + } + } + } + + public static class BossEventListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptBossBar()) return; + FriendlyByteBuf buf = event.getBuffer(); + UUID uuid = buf.readUUID(); + int actionType = buf.readVarInt(); + if (actionType == 0) { + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + float health = buf.readFloat(); + int color = buf.readVarInt(); + int division = buf.readVarInt(); + byte flag = buf.readByte(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeFloat(health); + buf.writeVarInt(color); + buf.writeVarInt(division); + buf.writeByte(flag); + } else if (actionType == 3) { + Tag nbt = buf.readNbt(false); + if (nbt == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUUID(uuid); + buf.writeVarInt(actionType); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } + } + + public static class TeamListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTeam()) return; + FriendlyByteBuf buf = event.getBuffer(); + String name = buf.readUtf(); + byte method = buf.readByte(); + if (method != 2 && method != 0) + return; + String displayName = buf.readUtf(); + byte friendlyFlags = buf.readByte(); + String nameTagVisibility = buf.readUtf(40); + String collisionRule = buf.readUtf(40); + int color = buf.readVarInt(); + String prefix = buf.readUtf(); + String suffix = buf.readUtf(); + + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix); + Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix); + if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; + event.setChanged(true); + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + + List entities = method == 0 ? buf.readStringList() : null; + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(name); + buf.writeByte(method); + buf.writeUtf(tokens1.isEmpty() ? displayName : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens1, context))); + buf.writeByte(friendlyFlags); + buf.writeUtf(nameTagVisibility); + buf.writeUtf(collisionRule); + buf.writeVarInt(color); + buf.writeUtf(tokens2.isEmpty() ? prefix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(prefix), tokens2, context))); + buf.writeUtf(tokens3.isEmpty() ? suffix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(suffix), tokens3, context))); + if (entities != null) { + buf.writeStringList(entities); + } + } + } + + public static class TeamListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptTeam()) return; + FriendlyByteBuf buf = event.getBuffer(); + String name = buf.readUtf(); + byte method = buf.readByte(); + if (method != 2 && method != 0) return; + Tag displayName = buf.readNbt(false); + if (displayName == null) return; + byte friendlyFlags = buf.readByte(); + Either eitherVisibility = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); + Either eitherCollisionRule = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); + int color = buf.readVarInt(); + Tag prefix = buf.readNbt(false); + if (prefix == null) return; + Tag suffix = buf.readNbt(false); + if (suffix == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix.getAsString()); + Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; + NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); + List entities = method == 0 ? buf.readStringList() : null; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(name); + buf.writeByte(method); + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, context)), false); + buf.writeByte(friendlyFlags); + eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); + eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); + buf.writeVarInt(color); + buf.writeNbt(tokens2.isEmpty() ? prefix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(prefix), tokens2, context)), false); + buf.writeNbt(tokens3.isEmpty() ? suffix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(suffix), tokens3, context)), false); + if (entities != null) { + buf.writeStringList(entities); + } + } + } + + public static class SetObjectiveListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptScoreboard()) return; + FriendlyByteBuf buf = event.getBuffer(); + String objective = buf.readUtf(); + byte mode = buf.readByte(); + if (mode != 0 && mode != 2) return; + String displayName = buf.readUtf(); + int renderType = buf.readVarInt(); + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); + buf.writeVarInt(renderType); + } + } + + public static class SetObjectiveListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptScoreboard()) return; + FriendlyByteBuf buf = event.getBuffer(); + String objective = buf.readUtf(); + byte mode = buf.readByte(); + if (mode != 0 && mode != 2) return; + Tag displayName = buf.readNbt(false); + if (displayName == null) return; + int renderType = buf.readVarInt(); + boolean optionalNumberFormat = buf.readBoolean(); + if (optionalNumberFormat) { + int format = buf.readVarInt(); + if (format == 0) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(0); + } else if (format == 1) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + Tag style = buf.readNbt(false); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(1); + buf.writeNbt(style, false); + } else if (format == 2) { + Tag fixed = buf.readNbt(false); + if (fixed == null) return; + Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + Map tokens2 = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); + if (tokens1.isEmpty() && tokens2.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(true); + buf.writeVarInt(2); + buf.writeNbt(tokens2.isEmpty() ? fixed : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(fixed), tokens2, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + } + } else { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(objective); + buf.writeByte(mode); + buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); + buf.writeVarInt(renderType); + buf.writeBoolean(false); + } + } + } + + public static class SetScoreListener1_20_3 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!Config.interceptSetScore()) return; + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + boolean isChanged = false; + FriendlyByteBuf buf = event.getBuffer(); + String owner = buf.readUtf(); + String objectiveName = buf.readUtf(); + int score = buf.readVarInt(); + boolean hasDisplay = buf.readBoolean(); + Tag displayName = null; + if (hasDisplay) { + displayName = buf.readNbt(false); + } + outside: + if (displayName != null) { + Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); + if (tokens.isEmpty()) break outside; + Component component = AdventureHelper.tagToComponent(displayName); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + displayName = AdventureHelper.componentToTag(component); + isChanged = true; + } + boolean hasNumberFormat = buf.readBoolean(); + int format = -1; + Tag style = null; + Tag fixed = null; + if (hasNumberFormat) { + format = buf.readVarInt(); + if (format == 0) { + if (displayName == null) return; + } else if (format == 1) { + if (displayName == null) return; + style = buf.readNbt(false); + } else if (format == 2) { + fixed = buf.readNbt(false); + if (fixed == null) return; + Map tokens = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); + if (tokens.isEmpty() && !isChanged) return; + if (!tokens.isEmpty()) { + Component component = AdventureHelper.tagToComponent(fixed); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + fixed = AdventureHelper.componentToTag(component); + isChanged = true; + } + } + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeUtf(owner); + buf.writeUtf(objectiveName); + buf.writeVarInt(score); + if (hasDisplay) { + buf.writeBoolean(true); + buf.writeNbt(displayName, false); + } else { + buf.writeBoolean(false); + } + if (hasNumberFormat) { + buf.writeBoolean(true); + buf.writeVarInt(format); + if (format == 1) { + buf.writeNbt(style, false); + } else if (format == 2) { + buf.writeNbt(fixed, false); + } + } else { + buf.writeBoolean(false); + } + } + } + } + + public static class AddRecipeBookListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + List entries = buf.readCollection(ArrayList::new, byteBuf -> { + RecipeBookEntry entry = RecipeBookEntry.read(byteBuf); + entry.applyClientboundData((BukkitServerPlayer) user); + return entry; + }); + boolean replace = buf.readBoolean(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeCollection(entries, ((byteBuf, recipeBookEntry) -> recipeBookEntry.write(byteBuf))); + buf.writeBoolean(replace); + } + } + + public static class PlaceGhostRecipeListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!VersionHelper.isOrAbove1_21_2()) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + RecipeDisplay display = RecipeDisplay.read(buf); + display.applyClientboundData((BukkitServerPlayer) user); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + display.write(buf); + } + } + + public static class UpdateRecipesListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (VersionHelper.isOrAbove1_21_2()) return; + FriendlyByteBuf buf = event.getBuffer(); + List holders = buf.readCollection(ArrayList::new, byteBuf -> { + LegacyRecipeHolder holder = LegacyRecipeHolder.read(byteBuf); + holder.recipe().applyClientboundData((BukkitServerPlayer) user); + return holder; + }); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeCollection(holders, ((byteBuf, recipeHolder) -> recipeHolder.write(byteBuf))); + } + } + + public static class UpdateAdvancementsListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean reset = buf.readBoolean(); + List added = buf.readCollection(ArrayList::new, byteBuf -> { + AdvancementHolder holder = AdvancementHolder.read(byteBuf); + holder.applyClientboundData(serverPlayer); + return holder; + }); + Set removed = buf.readCollection(Sets::newLinkedHashSetWithExpectedSize, FriendlyByteBuf::readKey); + Map progress = buf.readMap(FriendlyByteBuf::readKey, AdvancementProgress::read); + + boolean showAdvancement = false; + if (VersionHelper.isOrAbove1_21_5()) { + showAdvancement = buf.readBoolean(); + } + + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + + buf.writeBoolean(reset); + buf.writeCollection(added, (byteBuf, advancementHolder) -> advancementHolder.write(byteBuf)); + buf.writeCollection(removed, FriendlyByteBuf::writeKey); + buf.writeMap(progress, FriendlyByteBuf::writeKey, (byteBuf, advancementProgress) -> advancementProgress.write(byteBuf)); + if (VersionHelper.isOrAbove1_21_5()) { + buf.writeBoolean(showAdvancement); + } + } + } + + public static class RemoveEntityListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean isChange = false; + IntList intList = buf.readIntIdList(); + for (int i = 0, size = intList.size(); i < size; i++) { + int entityId = intList.getInt(i); + EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); + if (handler != null && handler.handleEntitiesRemove(intList)) { + isChange = true; + } + } + if (isChange) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeIntIdList(intList); + } + } + } + + public static class SoundListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + if (id == 0) { + Key soundId = buf.readKey(); + Float range = null; + if (buf.readBoolean()) { + range = buf.readFloat(); + } + int source = buf.readVarInt(); + int x = buf.readInt(); + int y = buf.readInt(); + int z = buf.readInt(); + float volume = buf.readFloat(); + float pitch = buf.readFloat(); + long seed = buf.readLong(); + Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mapped != null) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(0); + buf.writeKey(mapped); + if (range != null) { + buf.writeBoolean(true); + buf.writeFloat(range); + } else { + buf.writeBoolean(false); + } + buf.writeVarInt(source); + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeFloat(volume); + buf.writeFloat(pitch); + buf.writeLong(seed); + } + } else { + Optional optionalSound = FastNMS.INSTANCE.method$IdMap$byId(MBuiltInRegistries.SOUND_EVENT, id - 1); + if (optionalSound.isEmpty()) return; + Object soundEvent = optionalSound.get(); + Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent)); + int source = buf.readVarInt(); + int x = buf.readInt(); + int y = buf.readInt(); + int z = buf.readInt(); + float volume = buf.readFloat(); + float pitch = buf.readFloat(); + long seed = buf.readLong(); + Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); + if (mapped != null) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(0); + Object newId = KeyUtils.toResourceLocation(mapped); + Object newSoundEvent = FastNMS.INSTANCE.constructor$SoundEvent(newId, FastNMS.INSTANCE.method$SoundEvent$fixedRange(soundEvent)); + FastNMS.INSTANCE.method$SoundEvent$directEncode(buf, newSoundEvent); + buf.writeVarInt(source); + buf.writeInt(x); + buf.writeInt(y); + buf.writeInt(z); + buf.writeFloat(volume); + buf.writeFloat(pitch); + buf.writeLong(seed); + } + } + } + } + + public static class ContainerSetContentListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int listSize = buf.readVarInt(); + List items = new ArrayList<>(listSize); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int i = 0; i < listSize; i++) { + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + items.add(optional.get()); + changed = true; + } else { + items.add(itemStack); + } + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + ItemStack newCarriedItem = carriedItem; + Optional optional = BukkitItemManager.instance().s2c(carriedItem, serverPlayer); + if (optional.isPresent()) { + changed = true; + newCarriedItem = optional.get(); + } + if (!changed) return; + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeVarInt(listSize); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (ItemStack itemStack : items) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); + } + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); + } + } + + public static class ContainerSetSlotListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + int slot = buf.readShort(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack; + try { + itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } catch (Exception e) { + // 其他插件干的,比如某ty*****er,不要赖到ce头上 + return; + } + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetCursorItemListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetEquipmentListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int entity = buf.readVarInt(); + List> slots = Lists.newArrayList(); + int slotMask; + do { + slotMask = buf.readByte(); + Object equipmentSlot = CoreReflections.instance$EquipmentSlot$values[slotMask & 127]; + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); + } while ((slotMask & -128) != 0); + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(entity); + int i = slots.size(); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + for (int j = 0; j < i; ++j) { + com.mojang.datafixers.util.Pair pair = slots.get(j); + Enum equipmentSlot = (Enum) pair.getFirst(); + boolean bl = j != i - 1; + int k = equipmentSlot.ordinal(); + buf.writeByte(bl ? k | -128 : k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); + } + } + } + } + + public static class SetPlayerInventoryListener1_21_2 implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int slot = buf.readVarInt(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(slot); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + }); + } + } + + public static class SetCreativeModeSlotListener implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + if (!serverPlayer.isCreativeMode()) return; + FriendlyByteBuf buf = event.getBuffer(); + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + short slotNum = buf.readShort(); + ItemStack itemStack; + try { + itemStack = VersionHelper.isOrAbove1_20_5() ? + FastNMS.INSTANCE.method$FriendlyByteBuf$readUntrustedItem(friendlyBuf) : FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + } catch (Exception e) { + return; + } + BukkitItemManager.instance().c2s(itemStack).ifPresent((newItemStack) -> { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeShort(slotNum); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + if (VersionHelper.isOrAbove1_20_5()) { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); + } else { + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); + } + }); + } + } + + public static class ContainerClick1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + boolean changed = false; + Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + int containerId = buf.readContainerId(); + int stateId = buf.readVarInt(); + short slotNum = buf.readShort(); + byte buttonNum = buf.readByte(); + int clickType = buf.readVarInt(); + int i = buf.readVarInt(); + Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); + for (int j = 0; j < i; ++j) { + int k = buf.readShort(); + ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(itemStack); + if (optional.isPresent()) { + changed = true; + itemStack = optional.get(); + } + changedSlots.put(k, itemStack); + } + ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); + Optional optional = BukkitItemManager.instance().c2s(carriedItem); + if (optional.isPresent()) { + changed = true; + carriedItem = optional.get(); + } + if (changed) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeContainerId(containerId); + buf.writeVarInt(stateId); + buf.writeShort(slotNum); + buf.writeByte(buttonNum); + buf.writeVarInt(clickType); + buf.writeVarInt(changedSlots.size()); + Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); + changedSlots.forEach((k, v) -> { + buf.writeShort(k); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); + }); + FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); + } + } + } + + public class InteractEntityListener implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + int entityId = hasModelEngine() ? plugin.compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : buf.readVarInt(); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); + if (furniture == null) return; + int actionType = buf.readVarInt(); + BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; + if (serverPlayer.isSpectatorMode()) return; + Player platformPlayer = serverPlayer.platformPlayer(); + Location location = furniture.baseEntity().getLocation(); + + Runnable mainThreadTask; + if (actionType == 1) { + // ATTACK + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { + // todo 冒险模式破坏工具白名单 + if (serverPlayer.isAdventureMode() || + !furniture.isValid()) return; + + // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 + if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { + return; + } + + FurnitureAttemptBreakEvent preBreakEvent = new FurnitureAttemptBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(preBreakEvent)) + return; + + if (!BukkitCraftEngine.instance().antiGriefProvider().canBreak(platformPlayer, location)) + return; + + FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); + if (EventUtils.fireAndCheckCancel(breakEvent)) + return; + + Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) + .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.LEFT_CLICK); + furniture.config().execute(context, EventTrigger.BREAK); + if (cancellable.isCancelled()) { + return; + } + + CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); + }; + } else if (actionType == 2) { + // INTERACT_AT + float x = buf.readFloat(); + float y = buf.readFloat(); + float z = buf.readFloat(); + // todo 这个是错误的,这是实体的相对位置而非绝对位置 + Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); + InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeFloat(x).writeFloat(y).writeFloat(z); + buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); + buf.writeBoolean(usingSecondaryAction); + } + + mainThreadTask = () -> { + if (!furniture.isValid()) { + return; + } + + // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 + if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { + return; + } + + FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); + if (EventUtils.fireAndCheckCancel(interactEvent)) { + return; + } + + Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); + Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); + // execute functions + PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() + .withParameter(DirectContextParameters.EVENT, cancellable) + .withParameter(DirectContextParameters.FURNITURE, furniture) + .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) + .withParameter(DirectContextParameters.HAND, hand) + .withParameter(DirectContextParameters.POSITION, furniture.position()) + ); + furniture.config().execute(context, EventTrigger.RIGHT_CLICK); + if (cancellable.isCancelled()) { + return; + } + + // 必须从网络包层面处理,否则无法获取交互的具体实体 + if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { + // try placing another furniture above it + AABB hitBox = furniture.aabbByEntityId(entityId); + if (hitBox == null) return; + Optional> optionalCustomItem = itemInHand.getCustomItem(); + Location eyeLocation = platformPlayer.getEyeLocation(); + Vector direction = eyeLocation.getDirection(); + Location endLocation = eyeLocation.clone(); + endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); + Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); + if (result.isEmpty()) { + return; + } + EntityHitResult hitResult = result.get(); + if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { + for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { + if (behavior instanceof FurnitureItemBehavior) { + behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); + return; + } + } + } + // now simulate vanilla item behavior + serverPlayer.setResendSound(); + FastNMS.INSTANCE.simulateInteraction( + serverPlayer.serverPlayer(), + DirectionUtils.toNMSDirection(hitResult.direction()), + hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, + LocationUtils.toBlockPos(hitResult.blockPos()) + ); + } else { + if (!serverPlayer.isSecondaryUseActive()) { + furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { + if (furniture.tryOccupySeat(seatPos)) { + furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); + } + }); + } + } + }; + } else if (actionType == 0) { + int hand = buf.readVarInt(); + boolean usingSecondaryAction = buf.readBoolean(); + if (entityId != furniture.baseEntityId()) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(furniture.baseEntityId()); + buf.writeVarInt(actionType); + buf.writeVarInt(hand); + buf.writeBoolean(usingSecondaryAction); + } + return; + } else { + return; + } + + if (VersionHelper.isFolia()) { + platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); + } else { + BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); + } + } + } + + public static class CustomPayloadListener1_20 implements ByteBufferPacketListener { + + @Override + public void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + if (VersionHelper.isOrAbove1_20_2()) return; + FriendlyByteBuf byteBuf = event.getBuffer(); + Key key = byteBuf.readKey(); + if (!key.equals(NetworkManager.MOD_CHANNEL_KEY)) return; + PayloadHelper.handleReceiver(new UnknownPayload(key, byteBuf.readBytes(byteBuf.readableBytes())), user); + } + } + + public class AddEntityListener implements ByteBufferPacketListener { + private final EntityTypeHandler[] handlers; + + public AddEntityListener(int entityTypes) { + this.handlers = new EntityTypeHandler[entityTypes]; + Arrays.fill(this.handlers, EntityTypeHandler.DoNothing.INSTANCE); + this.handlers[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); + this.handlers[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + this.handlers[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + this.handlers[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); + this.handlers[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); + this.handlers[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); + this.handlers[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(true); + this.handlers[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false); + this.handlers[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); + this.handlers[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); + if (VersionHelper.isOrAbove1_20_3()) { + this.handlers[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE); + } + if (VersionHelper.isOrAbove1_20_5()) { + this.handlers[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); + } + this.handlers[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + UUID uuid = buf.readUUID(); + int type = buf.readVarInt(); + double x = buf.readDouble(); + double y = buf.readDouble(); + double z = buf.readDouble(); + byte xRot = buf.readByte(); + byte yRot = buf.readByte(); + byte yHeadRot = buf.readByte(); + int data = buf.readVarInt(); + // Falling blocks + int remapped = remapBlockState(data, user.clientModEnabled()); + if (remapped != data) { + int xa = buf.readShort(); + int ya = buf.readShort(); + int za = buf.readShort(); + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + buf.writeUUID(uuid); + buf.writeVarInt(type); + buf.writeDouble(x); + buf.writeDouble(y); + buf.writeDouble(z); + buf.writeByte(xRot); + buf.writeByte(yRot); + buf.writeByte(yHeadRot); + buf.writeVarInt(remapped); + buf.writeShort(xa); + buf.writeShort(ya); + buf.writeShort(za); + } }; + this.handlers[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + user.entityPacketHandlers().put(id, new FurniturePacketHandler(furniture.fakeEntityIds())); + user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); + if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { + event.setCancelled(true); + } + } else { + user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); + } + }; + this.handlers[MEntityTypes.INTERACTION$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + // Cancel collider entity packet + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); + } + }; + this.handlers[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { + if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + // Cancel collider entity packet + BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); + if (furniture != null) { + event.setCancelled(true); + user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); + } + }; + } + + private static EntityTypeHandler simpleAddEntityHandler(EntityPacketHandler handler) { + return (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + user.entityPacketHandlers().put(buf.readVarInt(), handler); + }; + } + + private static EntityTypeHandler createOptionalCustomProjectileEntityHandler(boolean fallback) { + return (user, event) -> { + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + BukkitProjectileManager.instance().projectileByEntityId(id).ifPresentOrElse(customProjectile -> { + ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, id); + handler.convertAddCustomProjectilePacket(buf, event); + user.entityPacketHandlers().put(id, handler); + }, () -> { + if (fallback) { + user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE); + } + }); + }; + } + + public interface EntityTypeHandler { + + void handle(NetWorkUser user, ByteBufPacketEvent event); + + class DoNothing implements EntityTypeHandler { + public static final DoNothing INSTANCE = new DoNothing(); + + @Override + public void handle(NetWorkUser user, ByteBufPacketEvent event) { + } + } + } + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + FriendlyByteBuf buf = event.getBuffer(); + buf.readVarInt(); + buf.readUUID(); + int type = buf.readVarInt(); + this.handlers[type].handle(user, event); + } + } + + public static class SetEntityDataListener implements ByteBufferPacketListener { + + @Override + public void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + if (!(user instanceof BukkitServerPlayer serverPlayer)) return; + FriendlyByteBuf buf = event.getBuffer(); + int id = buf.readVarInt(); + EntityPacketHandler handler = user.entityPacketHandlers().get(id); + if (handler != null) { + handler.handleSetEntityData(serverPlayer, event); + return; + } + if (Config.interceptEntityName()) { + boolean isChanged = false; + List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); + for (int i = 0; i < packedItems.size(); i++) { + Object packedItem = packedItems.get(i); + int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); + if (entityDataId != BaseEntityData.CustomName.id()) continue; + // noinspection unchecked + Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); + if (optionalTextComponent.isEmpty()) continue; + Object textComponent = optionalTextComponent.get(); + String json = ComponentUtils.minecraftToJson(textComponent); + Map tokens = CraftEngine.instance().fontManager().matchTags(json); + if (tokens.isEmpty()) continue; + Component component = AdventureHelper.jsonToComponent(json); + component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); + Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); + packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); + isChanged = true; + break; + } + if (isChanged) { + event.setChanged(true); + buf.clear(); + buf.writeVarInt(event.packetID()); + buf.writeVarInt(id); + FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); + } + } } } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java deleted file mode 100644 index 9a1c5bafa..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/PacketConsumers.java +++ /dev/null @@ -1,2703 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; -import com.mojang.authlib.GameProfile; -import com.mojang.datafixers.util.Either; -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import it.unimi.dsi.fastutil.ints.IntList; -import net.kyori.adventure.text.Component; -import net.momirealms.craftengine.bukkit.api.CraftEngineBlocks; -import net.momirealms.craftengine.bukkit.api.CraftEngineFurniture; -import net.momirealms.craftengine.bukkit.api.event.FurnitureAttemptBreakEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureBreakEvent; -import net.momirealms.craftengine.bukkit.api.event.FurnitureInteractEvent; -import net.momirealms.craftengine.bukkit.block.BukkitBlockManager; -import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurniture; -import net.momirealms.craftengine.bukkit.entity.furniture.BukkitFurnitureManager; -import net.momirealms.craftengine.bukkit.entity.projectile.BukkitProjectileManager; -import net.momirealms.craftengine.bukkit.item.BukkitItemManager; -import net.momirealms.craftengine.bukkit.item.behavior.FurnitureItemBehavior; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; -import net.momirealms.craftengine.bukkit.plugin.injector.ProtectedFieldVisitor; -import net.momirealms.craftengine.bukkit.plugin.network.handler.*; -import net.momirealms.craftengine.bukkit.plugin.network.payload.DiscardedPayload; -import net.momirealms.craftengine.bukkit.plugin.network.payload.Payload; -import net.momirealms.craftengine.bukkit.plugin.network.payload.PayloadHelper; -import net.momirealms.craftengine.bukkit.plugin.network.payload.UnknownPayload; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MBuiltInRegistries; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.MEntityTypes; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; -import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; -import net.momirealms.craftengine.bukkit.util.*; -import net.momirealms.craftengine.bukkit.world.BukkitWorldManager; -import net.momirealms.craftengine.core.advancement.network.AdvancementHolder; -import net.momirealms.craftengine.core.advancement.network.AdvancementProgress; -import net.momirealms.craftengine.core.block.ImmutableBlockState; -import net.momirealms.craftengine.core.entity.player.InteractionHand; -import net.momirealms.craftengine.core.font.FontManager; -import net.momirealms.craftengine.core.font.IllegalCharacterProcessResult; -import net.momirealms.craftengine.core.item.CustomItem; -import net.momirealms.craftengine.core.item.Item; -import net.momirealms.craftengine.core.item.behavior.ItemBehavior; -import net.momirealms.craftengine.core.item.context.UseOnContext; -import net.momirealms.craftengine.core.item.recipe.network.legacy.LegacyRecipeHolder; -import net.momirealms.craftengine.core.item.recipe.network.modern.RecipeBookEntry; -import net.momirealms.craftengine.core.item.recipe.network.modern.display.RecipeDisplay; -import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.ResourcePackHost; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.plugin.config.Config; -import net.momirealms.craftengine.core.plugin.context.ContextHolder; -import net.momirealms.craftengine.core.plugin.context.NetworkTextReplaceContext; -import net.momirealms.craftengine.core.plugin.context.PlayerOptionalContext; -import net.momirealms.craftengine.core.plugin.context.event.EventTrigger; -import net.momirealms.craftengine.core.plugin.context.parameter.DirectContextParameters; -import net.momirealms.craftengine.core.plugin.locale.TranslationManager; -import net.momirealms.craftengine.core.plugin.logger.Debugger; -import net.momirealms.craftengine.core.plugin.network.*; -import net.momirealms.craftengine.core.plugin.text.component.ComponentProvider; -import net.momirealms.craftengine.core.util.*; -import net.momirealms.craftengine.core.world.*; -import net.momirealms.craftengine.core.world.chunk.CEChunk; -import net.momirealms.craftengine.core.world.chunk.ChunkStatus; -import net.momirealms.craftengine.core.world.chunk.Palette; -import net.momirealms.craftengine.core.world.chunk.PalettedContainer; -import net.momirealms.craftengine.core.world.chunk.packet.BlockEntityData; -import net.momirealms.craftengine.core.world.chunk.packet.MCSection; -import net.momirealms.craftengine.core.world.collision.AABB; -import net.momirealms.sparrow.nbt.Tag; -import org.bukkit.*; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.PlayerInventory; -import org.bukkit.util.RayTraceResult; -import org.bukkit.util.Vector; -import org.jetbrains.annotations.Nullable; - -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.function.BiConsumer; -import java.util.function.Consumer; - -public class PacketConsumers { - private static BukkitNetworkManager.Handlers[] ADD_ENTITY_HANDLERS; - private static int[] BLOCK_STATE_MAPPINGS; - private static int[] MOD_BLOCK_STATE_MAPPINGS; - private static IntIdentityList SERVER_BLOCK_LIST; - private static IntIdentityList BIOME_LIST; - private static Consumer> BIOME_MAPPER; - - public static void initEntities(int registrySize) { - ADD_ENTITY_HANDLERS = new BukkitNetworkManager.Handlers[registrySize]; - Arrays.fill(ADD_ENTITY_HANDLERS, BukkitNetworkManager.Handlers.DO_NOTHING); - ADD_ENTITY_HANDLERS[MEntityTypes.FALLING_BLOCK$registryId] = (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - UUID uuid = buf.readUUID(); - int type = buf.readVarInt(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - byte xRot = buf.readByte(); - byte yRot = buf.readByte(); - byte yHeadRot = buf.readByte(); - int data = buf.readVarInt(); - // Falling blocks - int remapped = user.clientModEnabled() ? remapMOD(data) : remap(data); - if (remapped != data) { - int xa = buf.readShort(); - int ya = buf.readShort(); - int za = buf.readShort(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - buf.writeUUID(uuid); - buf.writeVarInt(type); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeByte(xRot); - buf.writeByte(yRot); - buf.writeByte(yHeadRot); - buf.writeVarInt(remapped); - buf.writeShort(xa); - buf.writeShort(ya); - buf.writeShort(za); - } - }; - - ADD_ENTITY_HANDLERS[MEntityTypes.BLOCK_DISPLAY$registryId] = simpleAddEntityHandler(BlockDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.TEXT_DISPLAY$registryId] = simpleAddEntityHandler(TextDisplayPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ARMOR_STAND$registryId] = simpleAddEntityHandler(ArmorStandPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.GLOW_ITEM_FRAME$registryId] = simpleAddEntityHandler(ItemFramePacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.ENDERMAN$registryId] = simpleAddEntityHandler(EndermanPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.CHEST_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.COMMAND_BLOCK_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.FURNACE_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.HOPPER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.SPAWNER_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.TNT_MINECART$registryId] = simpleAddEntityHandler(MinecartPacketHandler.INSTANCE); - ADD_ENTITY_HANDLERS[MEntityTypes.FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.EYE_OF_ENDER$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.FIREWORK_ROCKET$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.SMALL_FIREBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.EGG$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.ENDER_PEARL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.EXPERIENCE_BOTTLE$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.SNOWBALL$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.POTION$registryId] = createOptionalCustomProjectileEntityHandler(true); - ADD_ENTITY_HANDLERS[MEntityTypes.TRIDENT$registryId] = createOptionalCustomProjectileEntityHandler(false); - ADD_ENTITY_HANDLERS[MEntityTypes.ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); - ADD_ENTITY_HANDLERS[MEntityTypes.SPECTRAL_ARROW$registryId] = createOptionalCustomProjectileEntityHandler(false); - if (VersionHelper.isOrAbove1_20_3()) { - ADD_ENTITY_HANDLERS[MEntityTypes.TNT$registryId] = simpleAddEntityHandler(PrimedTNTPacketHandler.INSTANCE); - } - if (VersionHelper.isOrAbove1_20_5()) { - ADD_ENTITY_HANDLERS[MEntityTypes.OMINOUS_ITEM_SPAWNER$registryId] = simpleAddEntityHandler(CommonItemPacketHandler.INSTANCE); - } - - ADD_ENTITY_HANDLERS[MEntityTypes.ITEM_DISPLAY$registryId] = (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - user.entityPacketHandlers().put(id, new FurniturePacketHandler(furniture.fakeEntityIds())); - user.sendPacket(furniture.spawnPacket((Player) user.platformPlayer()), false); - if (Config.hideBaseEntity() && !furniture.hasExternalModel()) { - event.setCancelled(true); - } - } else { - user.entityPacketHandlers().put(id, ItemDisplayPacketHandler.INSTANCE); - } - }; - ADD_ENTITY_HANDLERS[MEntityTypes.INTERACTION$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.INTERACTION) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - event.setCancelled(true); - user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); - } - }; - ADD_ENTITY_HANDLERS[MEntityTypes.OAK_BOAT$registryId] = (user, event) -> { - if (BukkitFurnitureManager.NMS_COLLISION_ENTITY_TYPE != MEntityTypes.OAK_BOAT) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - // Cancel collider entity packet - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByRealEntityId(id); - if (furniture != null) { - event.setCancelled(true); - user.entityPacketHandlers().put(id, FurnitureCollisionPacketHandler.INSTANCE); - } - }; - } - - private static BukkitNetworkManager.Handlers simpleAddEntityHandler(EntityPacketHandler handler) { - return (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - user.entityPacketHandlers().put(buf.readVarInt(), handler); - }; - } - - private static BukkitNetworkManager.Handlers createOptionalCustomProjectileEntityHandler(boolean fallback) { - return (user, event) -> { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - BukkitProjectileManager.instance().projectileByEntityId(id).ifPresentOrElse(customProjectile -> { - ProjectilePacketHandler handler = new ProjectilePacketHandler(customProjectile, id); - handler.convertAddCustomProjectilePacket(buf, event); - user.entityPacketHandlers().put(id, handler); - }, () -> { - if (fallback) { - user.entityPacketHandlers().put(id, CommonItemPacketHandler.INSTANCE); - } - }); - }; - } - - public static void setBiomeMapper(Consumer> mapper) { - BIOME_MAPPER = mapper; - } - - public static void remapBiomes(PalettedContainer biomes) { - if (BIOME_MAPPER != null) { - BIOME_MAPPER.accept(biomes); - } - } - - public static void initBlocks(Map map, int registrySize) { - int[] newMappings = new int[registrySize]; - for (int i = 0; i < registrySize; i++) { - newMappings[i] = i; - } - int[] newMappingsMOD = Arrays.copyOf(newMappings, registrySize); - for (Map.Entry entry : map.entrySet()) { - newMappings[entry.getKey()] = entry.getValue(); - if (BlockStateUtils.isVanillaBlock((int) entry.getKey())) { - newMappingsMOD[entry.getKey()] = entry.getValue(); - } - } - for (int i = 0; i < newMappingsMOD.length; i++) { - if (BlockStateUtils.isVanillaBlock(i)) { - newMappingsMOD[i] = newMappings[i]; - } - } - BLOCK_STATE_MAPPINGS = newMappings; - MOD_BLOCK_STATE_MAPPINGS = newMappingsMOD; - SERVER_BLOCK_LIST = new IntIdentityList(registrySize); - BIOME_LIST = new IntIdentityList(RegistryUtils.currentBiomeRegistrySize()); - } - - public static int remap(int stateId) { - return BLOCK_STATE_MAPPINGS[stateId]; - } - - public static int remapMOD(int stateId) { - return MOD_BLOCK_STATE_MAPPINGS[stateId]; - } - - public static final BiConsumer FORGET_LEVEL_CHUNK = (user, event) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - FriendlyByteBuf buf = event.getBuffer(); - CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); - if (VersionHelper.isOrAbove1_20_2()) { - long chunkPos = buf.readLong(); - user.removeTrackedChunk(chunkPos); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos); - if (ceChunk != null) { - ceChunk.despawnBlockEntities(player); - } - } else { - int x = buf.readInt(); - int y = buf.readInt(); - user.removeTrackedChunk(ChunkPos.asLong(x, y)); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(x, y); - if (ceChunk != null) { - ceChunk.despawnBlockEntities(player); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundForgetLevelChunkPacket", e); - } - }; - - public static final BiConsumer LEVEL_CHUNK_WITH_LIGHT = (user, event) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - FriendlyByteBuf buf = event.getBuffer(); - int chunkX = buf.readInt(); - int chunkZ = buf.readInt(); - boolean named = !VersionHelper.isOrAbove1_20_2(); - // ClientboundLevelChunkPacketData - int heightmapsCount = 0; - Map heightmapsMap = null; - Tag heightmaps = null; - if (VersionHelper.isOrAbove1_21_5()) { - heightmapsMap = new HashMap<>(); - heightmapsCount = buf.readVarInt(); - for (int i = 0; i < heightmapsCount; i++) { - int key = buf.readVarInt(); - long[] value = buf.readLongArray(); - heightmapsMap.put(key, value); - } - } else { - heightmaps = buf.readNbt(named); - } - - int varInt = buf.readVarInt(); - byte[] buffer = new byte[varInt]; - buf.readBytes(buffer); - int blockEntitiesDataCount = buf.readVarInt(); - List blockEntitiesData = new ArrayList<>(); - for (int i = 0; i < blockEntitiesDataCount; i++) { - byte packedXZ = buf.readByte(); - short y = buf.readShort(); - int type = buf.readVarInt(); - Tag tag = buf.readNbt(named); - BlockEntityData blockEntityData = new BlockEntityData(packedXZ, y, type, tag); - blockEntitiesData.add(blockEntityData); - } - // ClientboundLightUpdatePacketData - BitSet skyYMask = buf.readBitSet(); - BitSet blockYMask = buf.readBitSet(); - BitSet emptySkyYMask = buf.readBitSet(); - BitSet emptyBlockYMask = buf.readBitSet(); - List skyUpdates = buf.readByteArrayList(2048); - List blockUpdates = buf.readByteArrayList(2048); - // 开始处理 - if (user.clientModEnabled()) { - ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); - FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); - for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - remapBiomes(mcSection.biomeContainer()); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remapMOD); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remapMOD(state); - if (newState != state) { - container.set(j, newState); - } - } - } - mcSection.writePacket(newBuf); - } - buffer = newBuf.array(); - } else { - ByteBuf byteBuf = Unpooled.copiedBuffer(buffer); - FriendlyByteBuf friendlyByteBuf = new FriendlyByteBuf(byteBuf); - FriendlyByteBuf newBuf = new FriendlyByteBuf(Unpooled.buffer()); - for (int i = 0, count = player.clientSideSectionCount(); i < count; i++) { - MCSection mcSection = new MCSection(user.clientBlockList(), SERVER_BLOCK_LIST, BIOME_LIST); - mcSection.readPacket(friendlyByteBuf); - PalettedContainer container = mcSection.blockStateContainer(); - remapBiomes(mcSection.biomeContainer()); - Palette palette = container.data().palette(); - if (palette.canRemap()) { - palette.remap(PacketConsumers::remap); - } else { - for (int j = 0; j < 4096; j++) { - int state = container.get(j); - int newState = remap(state); - if (newState != state) { - container.set(j, newState); - } - } - } - mcSection.writePacket(newBuf); - } - buffer = newBuf.array(); - } - - // 开始修改 - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeInt(chunkX); - buf.writeInt(chunkZ); - if (VersionHelper.isOrAbove1_21_5()) { - buf.writeVarInt(heightmapsCount); - for (Map.Entry entry : heightmapsMap.entrySet()) { - buf.writeVarInt(entry.getKey()); - buf.writeLongArray(entry.getValue()); - } - } else { - buf.writeNbt(heightmaps, named); - } - buf.writeVarInt(buffer.length); - buf.writeBytes(buffer); - buf.writeVarInt(blockEntitiesDataCount); - for (BlockEntityData blockEntityData : blockEntitiesData) { - buf.writeByte(blockEntityData.packedXZ()); - buf.writeShort(blockEntityData.y()); - buf.writeVarInt(blockEntityData.type()); - buf.writeNbt(blockEntityData.tag(), named); - } - buf.writeBitSet(skyYMask); - buf.writeBitSet(blockYMask); - buf.writeBitSet(emptySkyYMask); - buf.writeBitSet(emptyBlockYMask); - buf.writeByteArrayList(skyUpdates); - buf.writeByteArrayList(blockUpdates); - - ChunkPos chunkPos = new ChunkPos(chunkX, chunkZ); - // 记录加载的区块 - player.addTrackedChunk(chunkPos.longKey, new ChunkStatus()); - - CEWorld ceWorld = BukkitWorldManager.instance().getWorld(player.world().uuid()); - CEChunk ceChunk = ceWorld.getChunkAtIfLoaded(chunkPos.longKey); - if (ceChunk != null) { - ceChunk.spawnBlockEntities(player); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelChunkWithLightPacket", e); - } - }; - - public static final BiConsumer SECTION_BLOCK_UPDATE = (user, event) -> { - try { - if (user.clientModEnabled()) { - FriendlyByteBuf buf = event.getBuffer(); - long pos = buf.readLong(); - int blocks = buf.readVarInt(); - short[] positions = new short[blocks]; - int[] states = new int[blocks]; - for (int i = 0; i < blocks; i++) { - long k = buf.readVarLong(); - positions[i] = (short) ((int) (k & 4095L)); - states[i] = remapMOD((int) (k >>> 12)); - } - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeLong(pos); - buf.writeVarInt(blocks); - for (int i = 0; i < blocks; i++) { - buf.writeVarLong((long) states[i] << 12 | positions[i]); - } - event.setChanged(true); - } else { - FriendlyByteBuf buf = event.getBuffer(); - long pos = buf.readLong(); - int blocks = buf.readVarInt(); - short[] positions = new short[blocks]; - int[] states = new int[blocks]; - for (int i = 0; i < blocks; i++) { - long k = buf.readVarLong(); - positions[i] = (short) ((int) (k & 4095L)); - states[i] = remap((int) (k >>> 12)); - } - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeLong(pos); - buf.writeVarInt(blocks); - for (int i = 0; i < blocks; i++) { - buf.writeVarLong((long) states[i] << 12 | positions[i]); - } - event.setChanged(true); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSectionBlocksUpdatePacket", e); - } - }; - - public static final BiConsumer BLOCK_UPDATE = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - BlockPos pos = buf.readBlockPos(); - int before = buf.readVarInt(); - if (user.clientModEnabled() && !BlockStateUtils.isVanillaBlock(before)) { - return; - } - int state = user.clientModEnabled() ? remapMOD(before) : remap(before); - if (state == before) { - return; - } - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBlockPos(pos); - buf.writeVarInt(state); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBlockUpdatePacket", e); - } - }; - - public static final BiConsumer LEVEL_EVENT = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int eventId = buf.readInt(); - if (eventId != WorldEvents.BLOCK_BREAK_EFFECT) return; - BlockPos blockPos = buf.readBlockPos(); - int state = buf.readInt(); - boolean global = buf.readBoolean(); - int newState = user.clientModEnabled() ? remapMOD(state) : remap(state); - Object blockState = BlockStateUtils.idToBlockState(newState); - Object block = BlockStateUtils.getBlockOwner(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(block) && !FastNMS.INSTANCE.method$BlockStateBase$isAir(blockState)) { - Object soundType = FastNMS.INSTANCE.method$BlockBehaviour$BlockStateBase$getSoundType(blockState); - Object breakSound = FastNMS.INSTANCE.field$SoundType$breakSound(soundType); - Key soundId = Key.of(FastNMS.INSTANCE.field$SoundEvent$location(breakSound).toString()); - Key mappedSoundId = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mappedSoundId != null) { - Object mappedBreakSound = FastNMS.INSTANCE.constructor$SoundEvent(KeyUtils.toResourceLocation(mappedSoundId), Optional.empty()); - Object mappedBreakSoundHolder = FastNMS.INSTANCE.method$Holder$direct(mappedBreakSound); - Object packet = FastNMS.INSTANCE.constructor$ClientboundSoundPacket( - mappedBreakSoundHolder, - CoreReflections.instance$SoundSource$BLOCKS, - blockPos.x() + 0.5, - blockPos.y() + 0.5, - blockPos.z() + 0.5, - (FastNMS.INSTANCE.field$SoundType$volume(soundType) + 1.0F) / 2.0F, - FastNMS.INSTANCE.field$SoundType$pitch(soundType) * 0.8F, - RandomUtils.generateRandomLong() - ); - user.sendPacket(packet, true); - } - } - if (newState == state) { - return; - } - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeInt(eventId); - buf.writeBlockPos(blockPos); - buf.writeInt(newState); - buf.writeBoolean(global); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelEventPacket", e); - } - }; - - public static final BiConsumer TEAM_1_20_3 = (user, event) -> { - if (!Config.interceptTeam()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String name = buf.readUtf(); - byte method = buf.readByte(); - if (method != 2 && method != 0) return; - Tag displayName = buf.readNbt(false); - if (displayName == null) return; - byte friendlyFlags = buf.readByte(); - Either eitherVisibility = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); - Either eitherCollisionRule = VersionHelper.isOrAbove1_21_5() ? Either.right(buf.readVarInt()) : Either.left(buf.readUtf(40)); - int color = buf.readVarInt(); - Tag prefix = buf.readNbt(false); - if (prefix == null) return; - Tag suffix = buf.readNbt(false); - if (suffix == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix.getAsString()); - Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - List entities = method == 0 ? buf.readStringList() : null; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(name); - buf.writeByte(method); - buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, context)), false); - buf.writeByte(friendlyFlags); - eitherVisibility.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); - eitherCollisionRule.ifLeft(buf::writeUtf).ifRight(buf::writeVarInt); - buf.writeVarInt(color); - buf.writeNbt(tokens2.isEmpty() ? prefix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(prefix), tokens2, context)), false); - buf.writeNbt(tokens3.isEmpty() ? suffix : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(suffix), tokens3, context)), false); - if (entities != null) { - buf.writeStringList(entities); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerTeamPacket", e); - } - }; - - public static final TriConsumer PLAYER_INFO_UPDATE = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - if (!Config.interceptPlayerInfo()) return; - List entries = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$entries(packet); - if (entries instanceof MarkedArrayList) { - return; - } - EnumSet> enums = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$actions(packet); - outer: { - for (Object entry : enums) { - if (entry == NetworkReflections.instance$ClientboundPlayerInfoUpdatePacket$Action$UPDATE_DISPLAY_NAME) { - break outer; - } - } - return; - } - boolean isChanged = false; - List newEntries = new MarkedArrayList<>(); - for (Object entry : entries) { - Object mcComponent = FastNMS.INSTANCE.field$ClientboundPlayerInfoUpdatePacket$Entry$displayName(entry); - if (mcComponent == null) { - newEntries.add(entry); - } else { - String json = ComponentUtils.minecraftToJson(mcComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) { - newEntries.add(entry); - } else { - Object newEntry = FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket$Entry(entry, - ComponentUtils.adventureToMinecraft(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - newEntries.add(newEntry); - isChanged = true; - } - } - } - if (isChanged) { - event.replacePacket(FastNMS.INSTANCE.constructor$ClientboundPlayerInfoUpdatePacket(enums, newEntries)); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundPlayerInfoUpdatePacket", e); - } - }; - - public static final BiConsumer TEAM_1_20 = (user, event) -> { - if (!Config.interceptTeam()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String name = buf.readUtf(); - byte method = buf.readByte(); - if (method != 2 && method != 0) - return; - String displayName = buf.readUtf(); - byte friendlyFlags = buf.readByte(); - String nameTagVisibility = buf.readUtf(40); - String collisionRule = buf.readUtf(40); - int color = buf.readVarInt(); - String prefix = buf.readUtf(); - String suffix = buf.readUtf(); - - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(prefix); - Map tokens3 = CraftEngine.instance().fontManager().matchTags(suffix); - if (tokens1.isEmpty() && tokens2.isEmpty() && tokens3.isEmpty()) return; - event.setChanged(true); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - - List entities = method == 0 ? buf.readStringList() : null; - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(name); - buf.writeByte(method); - buf.writeUtf(tokens1.isEmpty() ? displayName : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens1, context))); - buf.writeByte(friendlyFlags); - buf.writeUtf(nameTagVisibility); - buf.writeUtf(collisionRule); - buf.writeVarInt(color); - buf.writeUtf(tokens2.isEmpty() ? prefix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(prefix), tokens2, context))); - buf.writeUtf(tokens3.isEmpty() ? suffix : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(suffix), tokens3, context))); - if (entities != null) { - buf.writeStringList(entities); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerTeamPacket", e); - } - }; - - public static final BiConsumer BOSS_EVENT_1_20 = (user, event) -> { - if (!Config.interceptBossBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - UUID uuid = buf.readUUID(); - int actionType = buf.readVarInt(); - if (actionType == 0) { - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - float health = buf.readFloat(); - int color = buf.readVarInt(); - int division = buf.readVarInt(); - byte flag = buf.readByte(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeFloat(health); - buf.writeVarInt(color); - buf.writeVarInt(division); - buf.writeByte(flag); - } else if (actionType == 3) { - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); - } - }; - - public static final BiConsumer BOSS_EVENT_1_20_3 = (user, event) -> { - if (!Config.interceptBossBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - UUID uuid = buf.readUUID(); - int actionType = buf.readVarInt(); - if (actionType == 0) { - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - float health = buf.readFloat(); - int color = buf.readVarInt(); - int division = buf.readVarInt(); - byte flag = buf.readByte(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeFloat(health); - buf.writeVarInt(color); - buf.writeVarInt(division); - buf.writeByte(flag); - } else if (actionType == 3) { - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUUID(uuid); - buf.writeVarInt(actionType); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundBossEventPacket", e); - } - }; - - public static final BiConsumer SET_OBJECTIVE_1_20 = (user, event) -> { - if (!Config.interceptScoreboard()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String objective = buf.readUtf(); - byte mode = buf.readByte(); - if (mode != 0 && mode != 2) return; - String displayName = buf.readUtf(); - int renderType = buf.readVarInt(); - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeVarInt(renderType); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetObjectivePacket", e); - } - }; - - public static final BiConsumer SET_OBJECTIVE_1_20_3 = (user, event) -> { - if (!Config.interceptScoreboard()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String objective = buf.readUtf(); - byte mode = buf.readByte(); - if (mode != 0 && mode != 2) return; - Tag displayName = buf.readNbt(false); - if (displayName == null) return; - int renderType = buf.readVarInt(); - boolean optionalNumberFormat = buf.readBoolean(); - if (optionalNumberFormat) { - int format = buf.readVarInt(); - if (format == 0) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(0); - } else if (format == 1) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - Tag style = buf.readNbt(false); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(1); - buf.writeNbt(style, false); - } else if (format == 2) { - Tag fixed = buf.readNbt(false); - if (fixed == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(tokens1.isEmpty() ? displayName : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens1, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(true); - buf.writeVarInt(2); - buf.writeNbt(tokens2.isEmpty() ? fixed : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(fixed), tokens2, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } - } else { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(objective); - buf.writeByte(mode); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(displayName), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeVarInt(renderType); - buf.writeBoolean(false); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetObjectivePacket", e); - } - }; - - public static final BiConsumer SYSTEM_CHAT_1_20 = (user, event) -> { - if (!Config.interceptSystemChat()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String jsonOrPlainString = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(jsonOrPlainString); - if (tokens.isEmpty()) return; - boolean overlay = buf.readBoolean(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(jsonOrPlainString), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - buf.writeBoolean(overlay); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); - } - }; - - public static final BiConsumer SYSTEM_CHAT_1_20_3 = (user, event) -> { - if (!Config.interceptSystemChat()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - boolean overlay = buf.readBoolean(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - buf.writeBoolean(overlay); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSystemChatPacket", e); - } - }; - - public static final BiConsumer SET_SUBTITLE_TEXT_1_20 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); - } - }; - - public static final BiConsumer SET_SUBTITLE_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetSubtitleTextPacket", e); - } - }; - - public static final BiConsumer SET_TITLE_TEXT_1_20 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); - } - }; - - public static final BiConsumer SET_TITLE_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptTitle()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetTitleTextPacket", e); - } - }; - - public static final BiConsumer SET_ACTIONBAR_TEXT_1_20 = (user, event) -> { - if (!Config.interceptActionBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); - } - }; - - public static final BiConsumer SET_ACTIONBAR_TEXT_1_20_3 = (user, event) -> { - if (!Config.interceptActionBar()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetActionBarTextPacket", e); - } - }; - - public static final BiConsumer TAB_LIST_1_20 = (user, event) -> { - if (!Config.interceptTabList()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - String json1 = buf.readUtf(); - String json2 = buf.readUtf(); - Map tokens1 = CraftEngine.instance().fontManager().matchTags(json1); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(json2); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - buf.writeUtf(tokens1.isEmpty() ? json1 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json1), tokens1, context))); - buf.writeUtf(tokens2.isEmpty() ? json2 : AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json2), tokens2, context))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); - } - }; - - public static final BiConsumer TAB_LIST_1_20_3 = (user, event) -> { - if (!Config.interceptTabList()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - Tag nbt1 = buf.readNbt(false); - if (nbt1 == null) return; - Tag nbt2 = buf.readNbt(false); - if (nbt2 == null) return; - Map tokens1 = CraftEngine.instance().fontManager().matchTags(nbt1.getAsString()); - Map tokens2 = CraftEngine.instance().fontManager().matchTags(nbt2.getAsString()); - if (tokens1.isEmpty() && tokens2.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - NetworkTextReplaceContext context = NetworkTextReplaceContext.of((BukkitServerPlayer) user); - buf.writeNbt(tokens1.isEmpty() ? nbt1 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt1), tokens1, context)), false); - buf.writeNbt(tokens2.isEmpty() ? nbt2 : AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt2), tokens2, context)), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundTabListPacket", e); - } - }; - - public static final BiConsumer OPEN_SCREEN_1_20 = (user, event) -> { - if (!Config.interceptContainer()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readVarInt(); - int type = buf.readVarInt(); - String json = buf.readUtf(); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(containerId); - buf.writeVarInt(type); - buf.writeUtf(AdventureHelper.componentToJson(AdventureHelper.replaceText(AdventureHelper.jsonToComponent(json), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user)))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); - } - }; - - public static final BiConsumer OPEN_SCREEN_1_20_3 = (user, event) -> { - if (!Config.interceptContainer()) return; - try { - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readVarInt(); - int type = buf.readVarInt(); - Tag nbt = buf.readNbt(false); - if (nbt == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(nbt.getAsString()); - if (tokens.isEmpty()) return; - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(containerId); - buf.writeVarInt(type); - buf.writeNbt(AdventureHelper.componentToTag(AdventureHelper.replaceText(AdventureHelper.tagToComponent(nbt), tokens, NetworkTextReplaceContext.of((BukkitServerPlayer) user))), false); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundOpenScreenPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_21_4 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean overrideLimiter = buf.readBoolean(); - boolean alwaysShow = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBoolean(overrideLimiter); - buf.writeBoolean(alwaysShow); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_20_5 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean overrideLimiter = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$StreamCodec$decode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeBoolean(overrideLimiter); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$StreamCodec$encode(NetworkReflections.instance$ParticleTypes$STREAM_CODEC, buf, remappedOption); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final BiConsumer LEVEL_PARTICLE_1_20 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - Object particleType = FastNMS.INSTANCE.method$FriendlyByteBuf$readById(buf, MBuiltInRegistries.PARTICLE_TYPE); - boolean overrideLimiter = buf.readBoolean(); - double x = buf.readDouble(); - double y = buf.readDouble(); - double z = buf.readDouble(); - float xDist = buf.readFloat(); - float yDist = buf.readFloat(); - float zDist = buf.readFloat(); - float maxSpeed = buf.readFloat(); - int count = buf.readInt(); - Object option = FastNMS.INSTANCE.method$ClientboundLevelParticlesPacket$readParticle(buf, particleType); - if (option == null) return; - if (!CoreReflections.clazz$BlockParticleOption.isInstance(option)) return; - Object blockState = FastNMS.INSTANCE.field$BlockParticleOption$blockState(option); - int id = BlockStateUtils.blockStateToId(blockState); - int remapped = user.clientModEnabled() ? remapMOD(id) : remap(id); - if (remapped == id) return; - Object type = FastNMS.INSTANCE.method$BlockParticleOption$getType(option); - Object remappedOption = FastNMS.INSTANCE.constructor$BlockParticleOption(type, BlockStateUtils.idToBlockState(remapped)); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeId(buf, remappedOption, MBuiltInRegistries.PARTICLE_TYPE); - buf.writeBoolean(overrideLimiter); - buf.writeDouble(x); - buf.writeDouble(y); - buf.writeDouble(z); - buf.writeFloat(xDist); - buf.writeFloat(yDist); - buf.writeFloat(zDist); - buf.writeFloat(maxSpeed); - buf.writeInt(count); - FastNMS.INSTANCE.method$ParticleOptions$writeToNetwork(remappedOption, buf); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLevelParticlesPacket", e); - } - }; - - public static final TriConsumer PLAYER_ACTION = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - Player platformPlayer = player.platformPlayer(); - World world = platformPlayer.getWorld(); - Object blockPos = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$pos(packet); - BlockPos pos = LocationUtils.fromBlockPos(blockPos); - if (VersionHelper.isFolia()) { - platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handlePlayerActionPacketOnMainThread(player, world, pos, packet); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); - } - }, () -> {}); - } else { - handlePlayerActionPacketOnMainThread(player, world, pos, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPlayerActionPacket", e); - } - }; - - private static void handlePlayerActionPacketOnMainThread(BukkitServerPlayer player, World world, BlockPos pos, Object packet) { - Object action = FastNMS.INSTANCE.field$ServerboundPlayerActionPacket$action(packet); - if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$START_DESTROY_BLOCK) { - Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(world); - Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, LocationUtils.toBlockPos(pos)); - int stateId = BlockStateUtils.blockStateToId(blockState); - // not a custom block - if (BlockStateUtils.isVanillaBlock(stateId)) { - if (Config.enableSoundSystem()) { - Object blockOwner = FastNMS.INSTANCE.method$BlockState$getBlock(blockState); - if (BukkitBlockManager.instance().isBlockSoundRemoved(blockOwner)) { - player.startMiningBlock(pos, blockState, null); - return; - } - } - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } else { - player.setClientSideCanBreakBlock(true); - } - return; - } - if (player.isAdventureMode()) { - if (Config.simplifyAdventureBreakCheck()) { - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId); - if (!player.canBreak(pos, state.vanillaBlockState().literalObject())) { - player.preventMiningBlock(); - return; - } - } else { - if (!player.canBreak(pos, null)) { - player.preventMiningBlock(); - return; - } - } - } - player.startMiningBlock(pos, blockState, BukkitBlockManager.instance().getImmutableBlockStateUnsafe(stateId)); - } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$ABORT_DESTROY_BLOCK) { - if (player.isMiningBlock()) { - player.abortMiningBlock(); - } - } else if (action == NetworkReflections.instance$ServerboundPlayerActionPacket$Action$STOP_DESTROY_BLOCK) { - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } - } - } - - public static final TriConsumer HELLO_C2S = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - String name = (String) NetworkReflections.methodHandle$ServerboundHelloPacket$nameGetter.invokeExact(packet); - player.setUnverifiedName(name); - if (VersionHelper.isOrAbove1_20_2()) { - UUID uuid = (UUID) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); - player.setUnverifiedUUID(uuid); - } else { - @SuppressWarnings("unchecked") - Optional uuid = (Optional) NetworkReflections.methodHandle$ServerboundHelloPacket$uuidGetter.invokeExact(packet); - if (uuid.isPresent()) { - player.setUnverifiedUUID(uuid.get()); - } else { - player.setUnverifiedUUID(UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(StandardCharsets.UTF_8))); - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundHelloPacket", e); - } - }; - - public static final TriConsumer SWING_HAND = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (!player.isMiningBlock()) return; - Object hand = FastNMS.INSTANCE.field$ServerboundSwingPacket$hand(packet); - if (hand == CoreReflections.instance$InteractionHand$MAIN_HAND) { - player.onSwingHand(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSwingPacket", e); - } - }; - - public static final TriConsumer USE_ITEM_ON = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (player.isMiningBlock()) { - player.stopMiningBlock(); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundUseItemOnPacket", e); - } - }; - - public static final TriConsumer RESPAWN = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - player.clearView(); - Object dimensionKey; - if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.methodHandle$ClientboundRespawnPacket$dimensionGetter.invokeExact(packet); - } else { - Object commonInfo = NetworkReflections.methodHandle$ClientboundRespawnPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); - } - Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); - World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); - if (world != null) { - int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; - player.setClientSideSectionCount(sectionCount); - player.setClientSideDimension(Key.of(location.toString())); - player.clearTrackedChunks(); - } else { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket: World " + location + " does not exist"); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRespawnPacket", e); - } - }; - - public static final TriConsumer LOGIN = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - player.setConnectionState(ConnectionState.PLAY); - Object dimensionKey; - if (!VersionHelper.isOrAbove1_20_2()) { - dimensionKey = NetworkReflections.methodHandle$ClientboundLoginPacket$dimensionGetter.invokeExact(packet); - } else { - Object commonInfo = NetworkReflections.methodHandle$ClientboundLoginPacket$commonPlayerSpawnInfoGetter.invokeExact(packet); - dimensionKey = NetworkReflections.methodHandle$CommonPlayerSpawnInfo$dimensionGetter.invokeExact(commonInfo); - } - Object location = FastNMS.INSTANCE.field$ResourceKey$location(dimensionKey); - World world = Bukkit.getWorld(Objects.requireNonNull(NamespacedKey.fromString(location.toString()))); - if (world != null) { - int sectionCount = (world.getMaxHeight() - world.getMinHeight()) / 16; - player.setClientSideSectionCount(sectionCount); - player.setClientSideDimension(Key.of(location.toString())); - } else { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket: World " + location + " does not exist"); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginPacket", e); - } - }; - - // 1.21.4- - // We can't find the best solution, we can only keep the feel as good as possible - // When the hotbar is full, the latest creative mode inventory can only be accessed when the player opens the inventory screen. Currently, it is not worth further handling this issue. - public static final TriConsumer SET_CREATIVE_SLOT = (user, event, packet) -> { - try { - if (VersionHelper.isOrAbove1_21_4()) return; - if (!user.isOnline()) return; - BukkitServerPlayer player = (BukkitServerPlayer) user; - if (VersionHelper.isFolia()) { - player.platformPlayer().getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handleSetCreativeSlotPacketOnMainThread(player, packet); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }, () -> {}); - } else { - handleSetCreativeSlotPacketOnMainThread(player, packet); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }; - - private static void handleSetCreativeSlotPacketOnMainThread(BukkitServerPlayer player, Object packet) throws Throwable { - Player bukkitPlayer = player.platformPlayer(); - if (bukkitPlayer == null) return; - if (bukkitPlayer.getGameMode() != GameMode.CREATIVE) return; - int slot = VersionHelper.isOrAbove1_20_5() ? (short) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet) : (int) NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$slotNumGetter.invokeExact(packet); - if (slot < 36 || slot > 44) return; - ItemStack item = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(NetworkReflections.methodHandle$ServerboundSetCreativeModeSlotPacket$itemStackGetter.invokeExact(packet)); - if (ItemStackUtils.isEmpty(item)) return; - if (slot - 36 != bukkitPlayer.getInventory().getHeldItemSlot()) { - return; - } - double interactionRange = player.getCachedInteractionRange(); - // do ray trace to get current block - RayTraceResult result = bukkitPlayer.rayTraceBlocks(interactionRange, FluidCollisionMode.NEVER); - if (result == null) return; - Block hitBlock = result.getHitBlock(); - if (hitBlock == null) return; - ImmutableBlockState state = CraftEngineBlocks.getCustomBlockState(hitBlock); - // not a custom block - if (state == null || state.isEmpty()) return; - Key itemId = state.settings().itemId(); - // no item available - if (itemId == null) return; - Object vanillaBlock = FastNMS.INSTANCE.method$BlockState$getBlock(state.vanillaBlockState().literalObject()); - Object vanillaBlockItem = FastNMS.INSTANCE.method$Block$asItem(vanillaBlock); - if (vanillaBlockItem == null) return; - Key addItemId = KeyUtils.namespacedKey2Key(item.getType().getKey()); - Key blockItemId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$Registry$getKey(MBuiltInRegistries.ITEM, vanillaBlockItem)); - if (!addItemId.equals(blockItemId)) return; - ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, player); - if (ItemStackUtils.isEmpty(itemStack)) { - CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); - return; - } - PlayerInventory inventory = bukkitPlayer.getInventory(); - int sameItemSlot = -1; - int emptySlot = -1; - for (int i = 0; i < 9 + 27; i++) { - ItemStack invItem = inventory.getItem(i); - if (ItemStackUtils.isEmpty(invItem)) { - if (emptySlot == -1 && i < 9) emptySlot = i; - continue; - } - if (invItem.getType().equals(itemStack.getType()) && invItem.getItemMeta().equals(itemStack.getItemMeta())) { - if (sameItemSlot == -1) sameItemSlot = i; - } - } - if (sameItemSlot != -1) { - if (sameItemSlot < 9) { - inventory.setHeldItemSlot(sameItemSlot); - ItemStack previousItem = inventory.getItem(slot - 36); - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, previousItem)); - } else { - ItemStack sameItem = inventory.getItem(sameItemSlot); - int finalSameItemSlot = sameItemSlot; - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> { - inventory.setItem(finalSameItemSlot, new ItemStack(Material.AIR)); - inventory.setItem(slot - 36, sameItem); - }); - } - } else { - if (item.getAmount() == 1) { - if (ItemStackUtils.isEmpty(inventory.getItem(slot - 36))) { - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); - return; - } - if (emptySlot != -1) { - inventory.setHeldItemSlot(emptySlot); - inventory.setItem(emptySlot, itemStack); - } else { - BukkitCraftEngine.instance().scheduler().sync().runDelayed(() -> inventory.setItem(slot - 36, itemStack)); - } - } - } - } - - // 1.21.4+ - public static final TriConsumer PICK_ITEM_FROM_BLOCK = (user, event, packet) -> { - try { - if (!user.isOnline()) return; - Player player = (Player) user.platformPlayer(); - if (player == null) return; - Object pos = NetworkReflections.methodHandle$ServerboundPickItemFromBlockPacket$posGetter.invokeExact(packet); - if (VersionHelper.isFolia()) { - int x = FastNMS.INSTANCE.field$Vec3i$x(pos); - int z = FastNMS.INSTANCE.field$Vec3i$z(pos); - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }, player.getWorld(), x >> 4, z >> 4); - } else { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromBlockPacketOnMainThread(player, pos); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromBlockPacket", e); - } - }; - - private static void handlePickItemFromBlockPacketOnMainThread(Player player, Object pos) throws Throwable { - Object serverLevel = FastNMS.INSTANCE.field$CraftWorld$ServerLevel(player.getWorld()); - Object blockState = FastNMS.INSTANCE.method$BlockGetter$getBlockState(serverLevel, pos); - ImmutableBlockState state = BukkitBlockManager.instance().getImmutableBlockState(BlockStateUtils.blockStateToId(blockState)); - if (state == null) return; - Key itemId = state.settings().itemId(); - if (itemId == null) return; - pickItem(player, itemId, pos, null); - } - - // 1.21.4+ - public static final TriConsumer PICK_ITEM_FROM_ENTITY = (user, event, packet) -> { - try { - int entityId = (int) NetworkReflections.methodHandle$ServerboundPickItemFromEntityPacket$idGetter.invokeExact(packet); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); - if (furniture == null) return; - Player player = (Player) user.platformPlayer(); - if (player == null) return; - if (VersionHelper.isFolia()) { - player.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), (t) -> { - try { - handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }, () -> {}); - } else { - BukkitCraftEngine.instance().scheduler().sync().run(() -> { - try { - handlePickItemFromEntityOnMainThread(player, furniture); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundPickItemFromEntityPacket", e); - } - }; - - private static void handlePickItemFromEntityOnMainThread(Player player, BukkitFurniture furniture) throws Throwable { - Key itemId = furniture.config().settings().itemId(); - if (itemId == null) return; - pickItem(player, itemId, null, FastNMS.INSTANCE.method$CraftEntity$getHandle(furniture.baseEntity())); - } - - private static void pickItem(Player player, Key itemId, @Nullable Object blockPos, @Nullable Object entity) throws Throwable { - ItemStack itemStack = BukkitCraftEngine.instance().itemManager().buildCustomItemStack(itemId, BukkitCraftEngine.instance().adapt(player)); - if (itemStack == null) { - CraftEngine.instance().logger().warn("Item: " + itemId + " is not a valid item"); - return; - } - assert CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem != null; - if (VersionHelper.isOrAbove1_21_5()) { - CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), - FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack), blockPos, entity, true); - } else { - CoreReflections.method$ServerGamePacketListenerImpl$tryPickItem.invoke( - CoreReflections.methodHandle$ServerPlayer$connectionGetter.invokeExact(FastNMS.INSTANCE.method$CraftPlayer$getHandle(player)), FastNMS.INSTANCE.method$CraftItemStack$asNMSCopy(itemStack)); - } - } - - public static final BiConsumer ADD_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - buf.readVarInt(); - buf.readUUID(); - int type = buf.readVarInt(); - ADD_ENTITY_HANDLERS[type].accept(user, event); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundAddEntityPacket", e); - } - }; - - // 1.21.2+ - public static final TriConsumer SYNC_ENTITY_POSITION = (user, event, packet) -> { - try { - int entityId = FastNMS.INSTANCE.method$ClientboundEntityPositionSyncPacket$id(packet); - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleSyncEntityPosition(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityPositionSyncPacket", e); - } - }; - - public static final BiConsumer REMOVE_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean isChange = false; - IntList intList = buf.readIntIdList(); - for (int i = 0, size = intList.size(); i < size; i++) { - int entityId = intList.getInt(i); - EntityPacketHandler handler = user.entityPacketHandlers().remove(entityId); - if (handler != null && handler.handleEntitiesRemove(intList)) { - isChange = true; - } - } - if (isChange) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeIntIdList(intList); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRemoveEntitiesPacket", e); - } - }; - - public static final BiConsumer INTERACT_ENTITY = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int entityId = BukkitNetworkManager.hasModelEngine() ? - CraftEngine.instance().compatibilityManager().interactionToBaseEntity(buf.readVarInt()) : - buf.readVarInt(); - BukkitFurniture furniture = BukkitFurnitureManager.instance().loadedFurnitureByEntityId(entityId); - if (furniture == null) return; - int actionType = buf.readVarInt(); - BukkitServerPlayer serverPlayer = (BukkitServerPlayer) user; - if (serverPlayer.isSpectatorMode()) return; - Player platformPlayer = serverPlayer.platformPlayer(); - Location location = furniture.baseEntity().getLocation(); - - Runnable mainThreadTask; - if (actionType == 1) { - // ATTACK - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeBoolean(usingSecondaryAction); - } - - mainThreadTask = () -> { - // todo 冒险模式破坏工具白名单 - if (serverPlayer.isAdventureMode() || - !furniture.isValid()) return; - - // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 - if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { - return; - } - - FurnitureAttemptBreakEvent preBreakEvent = new FurnitureAttemptBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(preBreakEvent)) - return; - - if (!BukkitCraftEngine.instance().antiGriefProvider().canBreak(platformPlayer, location)) - return; - - FurnitureBreakEvent breakEvent = new FurnitureBreakEvent(serverPlayer.platformPlayer(), furniture); - if (EventUtils.fireAndCheckCancel(breakEvent)) - return; - - Cancellable cancellable = Cancellable.of(breakEvent::isCancelled, breakEvent::setCancelled); - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.HAND, InteractionHand.MAIN_HAND) - .withParameter(DirectContextParameters.ITEM_IN_HAND, serverPlayer.getItemInHand(InteractionHand.MAIN_HAND)) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.LEFT_CLICK); - furniture.config().execute(context, EventTrigger.BREAK); - if (cancellable.isCancelled()) { - return; - } - - CraftEngineFurniture.remove(furniture, serverPlayer, !serverPlayer.isCreativeMode(), true); - }; - } else if (actionType == 2) { - // INTERACT_AT - float x = buf.readFloat(); - float y = buf.readFloat(); - float z = buf.readFloat(); - // todo 这个是错误的,这是实体的相对位置而非绝对位置 - Location interactionPoint = new Location(platformPlayer.getWorld(), x, y, z); - InteractionHand hand = buf.readVarInt() == 0 ? InteractionHand.MAIN_HAND : InteractionHand.OFF_HAND; - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeFloat(x).writeFloat(y).writeFloat(z); - buf.writeVarInt(hand == InteractionHand.MAIN_HAND ? 0 : 1); - buf.writeBoolean(usingSecondaryAction); - } - - mainThreadTask = () -> { - if (!furniture.isValid()) { - return; - } - - // todo 重构家具时候注意,需要准备加载好的hitbox类,以获取hitbox坐标 - if (!serverPlayer.canInteractPoint(new Vec3d(location.getX(), location.getY(), location.getZ()), 16d)) { - return; - } - - FurnitureInteractEvent interactEvent = new FurnitureInteractEvent(serverPlayer.platformPlayer(), furniture, hand, interactionPoint); - if (EventUtils.fireAndCheckCancel(interactEvent)) { - return; - } - - Item itemInHand = serverPlayer.getItemInHand(InteractionHand.MAIN_HAND); - Cancellable cancellable = Cancellable.of(interactEvent::isCancelled, interactEvent::setCancelled); - // execute functions - PlayerOptionalContext context = PlayerOptionalContext.of(serverPlayer, ContextHolder.builder() - .withParameter(DirectContextParameters.EVENT, cancellable) - .withParameter(DirectContextParameters.FURNITURE, furniture) - .withParameter(DirectContextParameters.ITEM_IN_HAND, itemInHand) - .withParameter(DirectContextParameters.HAND, hand) - .withParameter(DirectContextParameters.POSITION, furniture.position()) - ); - furniture.config().execute(context, EventTrigger.RIGHT_CLICK); - if (cancellable.isCancelled()) { - return; - } - - // 必须从网络包层面处理,否则无法获取交互的具体实体 - if (serverPlayer.isSecondaryUseActive() && !itemInHand.isEmpty()) { - // try placing another furniture above it - AABB hitBox = furniture.aabbByEntityId(entityId); - if (hitBox == null) return; - Optional> optionalCustomItem = itemInHand.getCustomItem(); - Location eyeLocation = platformPlayer.getEyeLocation(); - Vector direction = eyeLocation.getDirection(); - Location endLocation = eyeLocation.clone(); - endLocation.add(direction.multiply(serverPlayer.getCachedInteractionRange())); - Optional result = hitBox.clip(LocationUtils.toVec3d(eyeLocation), LocationUtils.toVec3d(endLocation)); - if (result.isEmpty()) { - return; - } - EntityHitResult hitResult = result.get(); - if (optionalCustomItem.isPresent() && !optionalCustomItem.get().behaviors().isEmpty()) { - for (ItemBehavior behavior : optionalCustomItem.get().behaviors()) { - if (behavior instanceof FurnitureItemBehavior) { - behavior.useOnBlock(new UseOnContext(serverPlayer, InteractionHand.MAIN_HAND, new BlockHitResult(hitResult.hitLocation(), hitResult.direction(), BlockPos.fromVec3d(hitResult.hitLocation()), false))); - return; - } - } - } - // now simulate vanilla item behavior - serverPlayer.setResendSound(); - FastNMS.INSTANCE.simulateInteraction( - serverPlayer.serverPlayer(), - DirectionUtils.toNMSDirection(hitResult.direction()), - hitResult.hitLocation().x, hitResult.hitLocation().y, hitResult.hitLocation().z, - LocationUtils.toBlockPos(hitResult.blockPos()) - ); - } else { - if (!serverPlayer.isSecondaryUseActive()) { - furniture.findFirstAvailableSeat(entityId).ifPresent(seatPos -> { - if (furniture.tryOccupySeat(seatPos)) { - furniture.spawnSeatEntityForPlayer(serverPlayer, seatPos); - } - }); - } - } - }; - } else if (actionType == 0) { - int hand = buf.readVarInt(); - boolean usingSecondaryAction = buf.readBoolean(); - if (entityId != furniture.baseEntityId()) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(furniture.baseEntityId()); - buf.writeVarInt(actionType); - buf.writeVarInt(hand); - buf.writeBoolean(usingSecondaryAction); - } - return; - } else { - return; - } - - if (VersionHelper.isFolia()) { - platformPlayer.getScheduler().run(BukkitCraftEngine.instance().javaPlugin(), t -> mainThreadTask.run(), () -> {}); - } else { - BukkitCraftEngine.instance().scheduler().executeSync(mainThreadTask); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundInteractPacket", e); - } - }; - - public static final BiConsumer SOUND = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - if (id == 0) { - Key soundId = buf.readKey(); - Float range = null; - if (buf.readBoolean()) { - range = buf.readFloat(); - } - int source = buf.readVarInt(); - int x = buf.readInt(); - int y = buf.readInt(); - int z = buf.readInt(); - float volume = buf.readFloat(); - float pitch = buf.readFloat(); - long seed = buf.readLong(); - Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mapped != null) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(0); - buf.writeKey(mapped); - if (range != null) { - buf.writeBoolean(true); - buf.writeFloat(range); - } else { - buf.writeBoolean(false); - } - buf.writeVarInt(source); - buf.writeInt(x); - buf.writeInt(y); - buf.writeInt(z); - buf.writeFloat(volume); - buf.writeFloat(pitch); - buf.writeLong(seed); - } - } else { - Optional optionalSound = FastNMS.INSTANCE.method$IdMap$byId(MBuiltInRegistries.SOUND_EVENT, id - 1); - if (optionalSound.isEmpty()) return; - Object soundEvent = optionalSound.get(); - Key soundId = KeyUtils.resourceLocationToKey(FastNMS.INSTANCE.method$SoundEvent$location(soundEvent)); - int source = buf.readVarInt(); - int x = buf.readInt(); - int y = buf.readInt(); - int z = buf.readInt(); - float volume = buf.readFloat(); - float pitch = buf.readFloat(); - long seed = buf.readLong(); - Key mapped = BukkitBlockManager.instance().replaceSoundIfExist(soundId); - if (mapped != null) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(0); - Object newId = KeyUtils.toResourceLocation(mapped); - Object newSoundEvent = FastNMS.INSTANCE.constructor$SoundEvent(newId, FastNMS.INSTANCE.method$SoundEvent$fixedRange(soundEvent)); - FastNMS.INSTANCE.method$SoundEvent$directEncode(buf, newSoundEvent); - buf.writeVarInt(source); - buf.writeInt(x); - buf.writeInt(y); - buf.writeInt(z); - buf.writeFloat(volume); - buf.writeFloat(pitch); - buf.writeLong(seed); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSoundPacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - public static final TriConsumer RENAME_ITEM = (user, event, packet) -> { - try { - if (!Config.filterAnvil()) return; - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_ANVIL)) { - return; - } - String message = (String) NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameGetter.invokeExact(packet); - if (message != null && !message.isEmpty()) { - // check bypass - FontManager manager = CraftEngine.instance().fontManager(); - IllegalCharacterProcessResult result = manager.processIllegalCharacters(message); - if (result.has()) { - try { - NetworkReflections.methodHandle$ServerboundRenameItemPacket$nameSetter.invokeExact(packet, result.text()); - } catch (ReflectiveOperationException e) { - CraftEngine.instance().logger().warn("Failed to replace chat", e); - } - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundRenameItemPacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - public static final TriConsumer SIGN_UPDATE = (user, event, packet) -> { - try { - if (!Config.filterSign()) return; - // check bypass - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_SIGN)) { - return; - } - String[] lines = (String[]) NetworkReflections.methodHandle$ServerboundSignUpdatePacket$linesGetter.invokeExact(packet); - FontManager manager = CraftEngine.instance().fontManager(); - if (!manager.isDefaultFontInUse()) return; - for (int i = 0; i < lines.length; i++) { - String line = lines[i]; - if (line != null && !line.isEmpty()) { - IllegalCharacterProcessResult result = manager.processIllegalCharacters(line); - if (result.has()) { - lines[i] = result.text(); - } - } - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSignUpdatePacket", e); - } - }; - - // we handle it on packet level to prevent it from being captured by plugins - @SuppressWarnings("unchecked") - public static final TriConsumer EDIT_BOOK = (user, event, packet) -> { - try { - if (!Config.filterBook()) return; - FontManager manager = CraftEngine.instance().fontManager(); - if (!manager.isDefaultFontInUse()) return; - // check bypass - if (((BukkitServerPlayer) user).hasPermission(FontManager.BYPASS_BOOK)) { - return; - } - - boolean changed = false; - - List pages = (List) NetworkReflections.methodHandle$ServerboundEditBookPacket$pagesGetter.invokeExact(packet); - List newPages = new ArrayList<>(pages.size()); - Optional title = (Optional) NetworkReflections.methodHandle$ServerboundEditBookPacket$titleGetter.invokeExact(packet); - Optional newTitle; - - if (title.isPresent()) { - String titleStr = title.get(); - Pair result = processClientString(titleStr, manager); - newTitle = Optional.of(result.right()); - if (result.left()) { - changed = true; - } - } else { - newTitle = Optional.empty(); - } - - for (String page : pages) { - Pair result = processClientString(page, manager); - newPages.add(result.right()); - if (result.left()) { - changed = true; - } - } - - if (changed) { - Object newPacket = NetworkReflections.constructor$ServerboundEditBookPacket.newInstance( - (int) NetworkReflections.methodHandle$ServerboundEditBookPacket$slotGetter.invokeExact(packet), - newPages, - newTitle - ); - event.replacePacket(newPacket); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundEditBookPacket", e); - } - }; - - private static Pair processClientString(String original, FontManager manager) { - if (original.isEmpty()) { - return Pair.of(false, original); - } - int[] codepoints = CharacterUtils.charsToCodePoints(original.toCharArray()); - int[] newCodepoints = new int[codepoints.length]; - boolean hasIllegal = false; - for (int i = 0; i < codepoints.length; i++) { - int codepoint = codepoints[i]; - if (manager.isIllegalCodepoint(codepoint)) { - newCodepoints[i] = '*'; - hasIllegal = true; - } else { - newCodepoints[i] = codepoint; - } - } - return hasIllegal ? Pair.of(true, new String(newCodepoints, 0, newCodepoints.length)) : Pair.of(false, original); - } - - public static final TriConsumer CUSTOM_PAYLOAD_1_20_2 = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_20_2()) return; - Object payload = NetworkReflections.methodHandle$ServerboundCustomPayloadPacket$payloadGetter.invokeExact(packet); - Payload clientPayload; - if (VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$DiscardedPayload.isInstance(payload)) { - clientPayload = DiscardedPayload.from(payload); - } else if (!VersionHelper.isOrAbove1_20_5() && NetworkReflections.clazz$ServerboundCustomPayloadPacket$UnknownPayload.isInstance(payload)) { - clientPayload = UnknownPayload.from(payload); - } else { - return; - } - if (clientPayload == null || !clientPayload.channel().equals(NetworkManager.MOD_CHANNEL_KEY)) return; - PayloadHelper.handleReceiver(clientPayload, user); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); - } - }; - - public static final BiConsumer CUSTOM_PAYLOAD_1_20 = (user, event) -> { - try { - if (VersionHelper.isOrAbove1_20_2()) return; - FriendlyByteBuf byteBuf = event.getBuffer(); - Key key = byteBuf.readKey(); - if (!key.equals(NetworkManager.MOD_CHANNEL_KEY)) return; - PayloadHelper.handleReceiver(new UnknownPayload(key, byteBuf.readBytes(byteBuf.readableBytes())), user); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundCustomPayloadPacket", e); - } - }; - - @SuppressWarnings("unchecked") - public static final BiConsumer SET_ENTITY_DATA = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int id = buf.readVarInt(); - EntityPacketHandler handler = user.entityPacketHandlers().get(id); - if (handler != null) { - handler.handleSetEntityData(serverPlayer, event); - return; - } - if (Config.interceptEntityName()) { - boolean isChanged = false; - List packedItems = FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$unpack(buf); - for (int i = 0; i < packedItems.size(); i++) { - Object packedItem = packedItems.get(i); - int entityDataId = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$id(packedItem); - if (entityDataId != BaseEntityData.CustomName.id()) continue; - Optional optionalTextComponent = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - if (optionalTextComponent.isEmpty()) continue; - Object textComponent = optionalTextComponent.get(); - String json = ComponentUtils.minecraftToJson(textComponent); - Map tokens = CraftEngine.instance().fontManager().matchTags(json); - if (tokens.isEmpty()) continue; - Component component = AdventureHelper.jsonToComponent(json); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); - packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, Optional.of(ComponentUtils.adventureToMinecraft(component)))); - isChanged = true; - break; - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(id); - FastNMS.INSTANCE.method$ClientboundSetEntityDataPacket$pack(packedItems, buf); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityDataPacket", e); - } - }; - - public static final BiConsumer SET_SCORE_1_20_3 = (user, event) -> { - try { - if (!Config.interceptSetScore()) return; - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - boolean isChanged = false; - FriendlyByteBuf buf = event.getBuffer(); - String owner = buf.readUtf(); - String objectiveName = buf.readUtf(); - int score = buf.readVarInt(); - boolean hasDisplay = buf.readBoolean(); - Tag displayName = null; - if (hasDisplay) { - displayName = buf.readNbt(false); - } - outside: - if (displayName != null) { - Map tokens = CraftEngine.instance().fontManager().matchTags(displayName.getAsString()); - if (tokens.isEmpty()) break outside; - Component component = AdventureHelper.tagToComponent(displayName); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - displayName = AdventureHelper.componentToTag(component); - isChanged = true; - } - boolean hasNumberFormat = buf.readBoolean(); - int format = -1; - Tag style = null; - Tag fixed = null; - if (hasNumberFormat) { - format = buf.readVarInt(); - if (format == 0) { - if (displayName == null) return; - } else if (format == 1) { - if (displayName == null) return; - style = buf.readNbt(false); - } else if (format == 2) { - fixed = buf.readNbt(false); - if (fixed == null) return; - Map tokens = CraftEngine.instance().fontManager().matchTags(fixed.getAsString()); - if (tokens.isEmpty() && !isChanged) return; - if (!tokens.isEmpty()) { - Component component = AdventureHelper.tagToComponent(fixed); - component = AdventureHelper.replaceText(component, tokens, NetworkTextReplaceContext.of(serverPlayer)); - fixed = AdventureHelper.componentToTag(component); - isChanged = true; - } - } - } - if (isChanged) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeUtf(owner); - buf.writeUtf(objectiveName); - buf.writeVarInt(score); - if (hasDisplay) { - buf.writeBoolean(true); - buf.writeNbt(displayName, false); - } else { - buf.writeBoolean(false); - } - if (hasNumberFormat) { - buf.writeBoolean(true); - buf.writeVarInt(format); - if (format == 1) { - buf.writeNbt(style, false); - } else if (format == 2) { - buf.writeNbt(fixed, false); - } - } else { - buf.writeBoolean(false); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetScorePacket", e); - } - }; - - public static final BiConsumer CONTAINER_SET_CONTENT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - int listSize = buf.readVarInt(); - List items = new ArrayList<>(listSize); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (int i = 0; i < listSize; i++) { - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); - if (optional.isPresent()) { - items.add(optional.get()); - changed = true; - } else { - items.add(itemStack); - } - } - ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - ItemStack newCarriedItem = carriedItem; - Optional optional = BukkitItemManager.instance().s2c(carriedItem, serverPlayer); - if (optional.isPresent()) { - changed = true; - newCarriedItem = optional.get(); - } - if (!changed) return; - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeVarInt(listSize); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (ItemStack itemStack : items) { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, itemStack); - } - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newCarriedItem); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetContentPacket", e); - } - }; - - public static final BiConsumer CONTAINER_SET_SLOT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - int slot = buf.readShort(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack; - try { - itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - } catch (Exception e) { - // 其他插件干的,比如某ty*****er,不要赖到ce头上 - return; - } - BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundContainerSetSlotPacket", e); - } - }; - - public static final BiConsumer SET_CURSOR_ITEM = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetCursorItemPacket", e); - } - }; - - public static final BiConsumer SET_EQUIPMENT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - int entity = buf.readVarInt(); - List> slots = Lists.newArrayList(); - int slotMask; - do { - slotMask = buf.readByte(); - Object equipmentSlot = CoreReflections.instance$EquipmentSlot$values[slotMask & 127]; - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().s2c(itemStack, serverPlayer); - if (optional.isPresent()) { - changed = true; - itemStack = optional.get(); - } - slots.add(com.mojang.datafixers.util.Pair.of(equipmentSlot, itemStack)); - } while ((slotMask & -128) != 0); - if (changed) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(entity); - int i = slots.size(); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - for (int j = 0; j < i; ++j) { - com.mojang.datafixers.util.Pair pair = slots.get(j); - Enum equipmentSlot = (Enum) pair.getFirst(); - boolean bl = j != i - 1; - int k = equipmentSlot.ordinal(); - buf.writeByte(bl ? k | -128 : k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, pair.getSecond()); - } - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEquipmentPacket", e); - } - }; - - public static final BiConsumer SET_PLAYER_INVENTORY_1_21_2 = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - int slot = buf.readVarInt(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - BukkitItemManager.instance().s2c(itemStack, serverPlayer).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeVarInt(slot); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetPlayerInventoryPacket", e); - } - }; - - public static final BiConsumer SET_CREATIVE_MODE_SLOT = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - if (!serverPlayer.isCreativeMode()) return; - FriendlyByteBuf buf = event.getBuffer(); - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - short slotNum = buf.readShort(); - ItemStack itemStack; - try { - itemStack = VersionHelper.isOrAbove1_20_5() ? - FastNMS.INSTANCE.method$FriendlyByteBuf$readUntrustedItem(friendlyBuf) : FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - } catch (Exception e) { - return; - } - BukkitItemManager.instance().c2s(itemStack).ifPresent((newItemStack) -> { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeShort(slotNum); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - if (VersionHelper.isOrAbove1_20_5()) { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeUntrustedItem(newFriendlyBuf, newItemStack); - } else { - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, newItemStack); - } - }); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundSetCreativeModeSlotPacket", e); - } - }; - - // 因为不能走编码器只能替换对象 - public static final TriConsumer CONTAINER_CLICK_1_21_5 = (user, event, packet) -> { - try { - BukkitServerPlayer player = (BukkitServerPlayer) user; - int containerId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$containerId(packet); - int stateId = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$stateId(packet); - short slotNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$slotNum(packet); - byte buttonNum = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$buttonNum(packet); - Object clickType = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$clickType(packet); - @SuppressWarnings("unchecked") - Int2ObjectMap changedSlots = FastNMS.INSTANCE.field$ServerboundContainerClickPacket$changedSlots(packet); - Int2ObjectMap newChangedSlots = new Int2ObjectOpenHashMap<>(changedSlots.size()); - for (Int2ObjectMap.Entry entry : changedSlots.int2ObjectEntrySet()) { - newChangedSlots.put(entry.getIntKey(), FastNMS.INSTANCE.constructor$InjectedHashedStack(entry.getValue(), player)); - } - Object carriedItem = FastNMS.INSTANCE.constructor$InjectedHashedStack(FastNMS.INSTANCE.field$ServerboundContainerClickPacket$carriedItem(packet), player); - event.replacePacket(FastNMS.INSTANCE.constructor$ServerboundContainerClickPacket(containerId, stateId, slotNum, buttonNum, clickType, Int2ObjectMaps.unmodifiable(newChangedSlots), carriedItem)); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); - } - }; - - public static final BiConsumer CONTAINER_CLICK_1_20 = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - boolean changed = false; - Object friendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - int containerId = buf.readContainerId(); - int stateId = buf.readVarInt(); - short slotNum = buf.readShort(); - byte buttonNum = buf.readByte(); - int clickType = buf.readVarInt(); - int i = buf.readVarInt(); - Int2ObjectMap changedSlots = new Int2ObjectOpenHashMap<>(i); - for (int j = 0; j < i; ++j) { - int k = buf.readShort(); - ItemStack itemStack = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().c2s(itemStack); - if (optional.isPresent()) { - changed = true; - itemStack = optional.get(); - } - changedSlots.put(k, itemStack); - } - ItemStack carriedItem = FastNMS.INSTANCE.method$FriendlyByteBuf$readItem(friendlyBuf); - Optional optional = BukkitItemManager.instance().c2s(carriedItem); - if (optional.isPresent()) { - changed = true; - carriedItem = optional.get(); - } - if (changed) { - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - buf.writeVarInt(stateId); - buf.writeShort(slotNum); - buf.writeByte(buttonNum); - buf.writeVarInt(clickType); - buf.writeVarInt(changedSlots.size()); - Object newFriendlyBuf = FastNMS.INSTANCE.constructor$FriendlyByteBuf(buf); - changedSlots.forEach((k, v) -> { - buf.writeShort(k); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, v); - }); - FastNMS.INSTANCE.method$FriendlyByteBuf$writeItem(newFriendlyBuf, carriedItem); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundContainerClickPacket", e); - } - }; - - public static final TriConsumer RESOURCE_PACK_RESPONSE = (user, event, packet) -> { - try { - Object action = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$action(packet); - - if (VersionHelper.isOrAbove1_20_3()) { - UUID uuid = FastNMS.INSTANCE.field$ServerboundResourcePackPacket$id(packet); - if (!user.isResourcePackLoading(uuid)) { - // 不是CraftEngine发送的资源包,不管 - return; - } - } - - if (action == null) { - user.kick(Component.text("Corrupted ResourcePackResponse Packet")); - return; - } - - // 检查是否是拒绝 - if (Config.kickOnDeclined()) { - if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DECLINED || action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$DISCARDED) { - user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); - return; - } - } - - // 检查是否失败 - if (Config.kickOnFailedApply()) { - if (action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$FAILED_DOWNLOAD - || (VersionHelper.isOrAbove1_20_3() && action == NetworkReflections.instance$ServerboundResourcePackPacket$Action$INVALID_URL)) { - user.kick(Component.translatable("multiplayer.requiredTexturePrompt.disconnect")); - return; - } - } - - boolean isTerminal = action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$ACCEPTED && action != NetworkReflections.instance$ServerboundResourcePackPacket$Action$DOWNLOADED; - if (isTerminal && VersionHelper.isOrAbove1_20_2()) { - event.setCancelled(true); - Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); - if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) return; - // 主线程上处理这个包 - CraftEngine.instance().scheduler().executeSync(() -> { - try { - // 当客户端发出多次成功包的时候,finish会报错,我们忽略他 - NetworkReflections.methodHandle$ServerCommonPacketListener$handleResourcePackResponse.invokeExact(packetListener, packet); - CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$ServerResourcePackConfigurationTask$TYPE); - } catch (Throwable e) { - Debugger.RESOURCE_PACK.warn(() -> "Cannot finish current task", e); - } - }); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ServerboundResourcePackPacket", e); - } - }; - - public static final TriConsumer ENTITY_EVENT = (user, event, packet) -> { - try { - Object player = user.serverPlayer(); - if (player == null) return; - int entityId = (int) NetworkReflections.methodHandle$ClientboundEntityEventPacket$entityIdGetter.invokeExact(packet); - if (entityId != FastNMS.INSTANCE.method$Entity$getId(player)) return; - byte eventId = (byte) NetworkReflections.methodHandle$ClientboundEntityEventPacket$eventIdGetter.invokeExact(packet); - if (eventId >= 24 && eventId <= 28) { - CraftEngine.instance().fontManager().refreshEmojiSuggestions(user.uuid()); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundEntityEventPacket", e); - } - }; - - public static final TriConsumer MOVE_POS_AND_ROTATE_ENTITY = (user, event, packet) -> { - try { - int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleMoveAndRotate(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket$PosRot", e); - } - }; - - public static final TriConsumer MOVE_POS_ENTITY = (user, event, packet) -> { - try { - int entityId = ProtectedFieldVisitor.get().field$ClientboundMoveEntityPacket$entityId(packet); - EntityPacketHandler handler = user.entityPacketHandlers().get(entityId); - if (handler != null) { - handler.handleMove(user, event, packet); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundMoveEntityPacket", e); - } - }; - - public static final TriConsumer ROTATE_HEAD = (user, event, packet) -> { - try { - int entityId = (int) NetworkReflections.methodHandle$ClientboundRotateHeadPacket$entityIdGetter.invokeExact(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRotateHeadPacket", e); - } - }; - - public static final TriConsumer SET_ENTITY_MOTION = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_21_6()) return; - int entityId = (int) NetworkReflections.methodHandle$ClientboundSetEntityMotionPacket$idGetter.invokeExact(packet); - if (BukkitFurnitureManager.instance().isFurnitureRealEntity(entityId)) { - event.setCancelled(true); - } - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundSetEntityMotionPacket", e); - } - }; - - // 这个包是由 JoinWorldTask 发出的,客户端收到后会返回 ServerboundFinishConfigurationPacket - @SuppressWarnings("unchecked") - public static final TriConsumer FINISH_CONFIGURATION = (user, event, packet) -> { - try { - if (!VersionHelper.isOrAbove1_20_2() || !Config.sendPackOnJoin()) { - // 防止后期调试进配置阶段造成问题 - user.setShouldProcessFinishConfiguration(false); - return; - } - - if (!user.shouldProcessFinishConfiguration()) return; - Object packetListener = FastNMS.INSTANCE.method$Connection$getPacketListener(user.connection()); - if (!CoreReflections.clazz$ServerConfigurationPacketListenerImpl.isInstance(packetListener)) { - return; - } - - // 防止后续加入的JoinWorldTask再次处理 - user.setShouldProcessFinishConfiguration(false); - - // 检查用户UUID是否已经校验 - if (!user.isUUIDVerified()) { - if (Config.strictPlayerUuidValidation()) { - TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); - user.kick(Component.translatable("disconnect.loginFailedInfo").arguments(Component.translatable("argument.uuid.invalid"))); - return; - } - if (Config.debugResourcePack()) { - TranslationManager.instance().log("warning.network.resource_pack.unverified_uuid", user.name(), user.uuid().toString()); - } - } - - // 取消 ClientboundFinishConfigurationPacket,让客户端发呆,并结束掉当前的进入世界任务 - event.setCancelled(true); - try { - CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$finishCurrentTask.invokeExact(packetListener, CoreReflections.instance$JoinWorldTask$TYPE); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to finish current task for " + user.name(), e); - } - - if (VersionHelper.isOrAbove1_20_5()) { - // 1.20.5+开始会检查是否结束需要重新设置回去,不然不会发keepAlive包 - CoreReflections.methodHandle$ServerCommonPacketListenerImpl$closedSetter.invokeExact(packetListener, false); - } - - // 请求资源包 - ResourcePackHost host = CraftEngine.instance().packManager().resourcePackHost(); - host.requestResourcePackDownloadLink(user.uuid()).whenComplete((dataList, t) -> { - if (t != null) { - CraftEngine.instance().logger().warn("Failed to get pack data for player " + user.name(), t); - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - return; - } - if (dataList.isEmpty()) { - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - return; - } - Queue configurationTasks; - try { - configurationTasks = (Queue) CoreReflections.methodHandle$ServerConfigurationPacketListenerImpl$configurationTasksGetter.invokeExact(packetListener); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to get configuration tasks for player " + user.name(), e); - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - return; - } - // 向配置阶段连接的任务重加入资源包的任务 - for (ResourcePackDownloadData data : dataList) { - configurationTasks.add(FastNMS.INSTANCE.constructor$ServerResourcePackConfigurationTask(ResourcePackUtils.createServerResourcePackInfo(data.uuid(), data.url(), data.sha1()))); - user.addResourcePackUUID(data.uuid()); - } - // 最后再加入一个 JoinWorldTask 并开始资源包任务 - FastNMS.INSTANCE.method$ServerConfigurationPacketListenerImpl$returnToWorld(packetListener); - }); - } catch (Throwable e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundFinishConfigurationPacket", e); - } - }; - - public static final TriConsumer LOGIN_FINISHED = (user, event, packet) -> { - try { - GameProfile gameProfile = FastNMS.INSTANCE.field$ClientboundLoginFinishedPacket$gameProfile(packet); - user.setVerifiedName(gameProfile.getName()); - user.setVerifiedUUID(gameProfile.getId()); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundLoginFinishedPacket", e); - } - }; - - public static final BiConsumer ADD_RECIPE_BOOK = (user, event) -> { - try { - FriendlyByteBuf buf = event.getBuffer(); - List entries = buf.readCollection(ArrayList::new, byteBuf -> { - RecipeBookEntry entry = RecipeBookEntry.read(byteBuf); - entry.applyClientboundData((BukkitServerPlayer) user); - return entry; - }); - boolean replace = buf.readBoolean(); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeCollection(entries, ((byteBuf, recipeBookEntry) -> recipeBookEntry.write(byteBuf))); - buf.writeBoolean(replace); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundRecipeBookAddPacket", e); - } - }; - - public static final BiConsumer PLACE_GHOST_RECIPE = (user, event) -> { - try { - if (!VersionHelper.isOrAbove1_21_2()) return; - FriendlyByteBuf buf = event.getBuffer(); - int containerId = buf.readContainerId(); - RecipeDisplay display = RecipeDisplay.read(buf); - display.applyClientboundData((BukkitServerPlayer) user); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeContainerId(containerId); - display.write(buf); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundPlaceGhostRecipePacket", e); - } - }; - - public static final BiConsumer UPDATE_RECIPES = (user, event) -> { - try { - if (VersionHelper.isOrAbove1_21_2()) return; - FriendlyByteBuf buf = event.getBuffer(); - List holders = buf.readCollection(ArrayList::new, byteBuf -> { - LegacyRecipeHolder holder = LegacyRecipeHolder.read(byteBuf); - holder.recipe().applyClientboundData((BukkitServerPlayer) user); - return holder; - }); - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - buf.writeCollection(holders, ((byteBuf, recipeHolder) -> recipeHolder.write(byteBuf))); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateRecipesPacket", e); - } - }; - - public static final BiConsumer UPDATE_ADVANCEMENTS = (user, event) -> { - try { - if (!(user instanceof BukkitServerPlayer serverPlayer)) return; - FriendlyByteBuf buf = event.getBuffer(); - boolean reset = buf.readBoolean(); - List added = buf.readCollection(ArrayList::new, byteBuf -> { - AdvancementHolder holder = AdvancementHolder.read(byteBuf); - holder.applyClientboundData(serverPlayer); - return holder; - }); - Set removed = buf.readCollection(Sets::newLinkedHashSetWithExpectedSize, FriendlyByteBuf::readKey); - Map progress = buf.readMap(FriendlyByteBuf::readKey, AdvancementProgress::read); - - boolean showAdvancement = false; - if (VersionHelper.isOrAbove1_21_5()) { - showAdvancement = buf.readBoolean(); - } - - event.setChanged(true); - buf.clear(); - buf.writeVarInt(event.packetID()); - - buf.writeBoolean(reset); - buf.writeCollection(added, (byteBuf, advancementHolder) -> advancementHolder.write(byteBuf)); - buf.writeCollection(removed, FriendlyByteBuf::writeKey); - buf.writeMap(progress, FriendlyByteBuf::writeKey, (byteBuf, advancementProgress) -> advancementProgress.write(byteBuf)); - if (VersionHelper.isOrAbove1_21_5()) { - buf.writeBoolean(showAdvancement); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateAdvancementsPacket", e); - } - }; - - public static final TriConsumer UPDATE_TAGS = (user, event, packet) -> { - try { - Object modifiedPacket = BukkitBlockManager.instance().cachedUpdateTagsPacket(); - if (packet.equals(modifiedPacket) || modifiedPacket == null) return; - event.replacePacket(modifiedPacket); - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to handle ClientboundUpdateTagsPacket", e); - } - }; -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java index 953f45bf5..fa86d8d8f 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/BlockDisplayPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.BlockDisplayEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -36,12 +36,7 @@ public class BlockDisplayPacketHandler implements EntityPacketHandler { if (entityDataId == BlockDisplayEntityData.DisplayedBlock.id()) { Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId= BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java index 80a4c20cd..ecc0a03d5 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/CommonItemPacketHandler.java @@ -41,7 +41,7 @@ public class CommonItemPacketHandler implements EntityPacketHandler { continue; } ItemStack itemStack = FastNMS.INSTANCE.method$CraftItemStack$asCraftMirror(nmsItemStack); - Optional optional = BukkitItemManager.instance().s2c(itemStack, (BukkitServerPlayer) user); + Optional optional = BukkitItemManager.instance().s2c(itemStack, user); if (optional.isEmpty()) continue; isChanged = true; itemStack = optional.get(); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java index 3d5561c01..760820024 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/EndermanPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.EnderManData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -38,12 +38,7 @@ public class EndermanPacketHandler implements EntityPacketHandler { Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (blockState.isEmpty()) continue; int stateId = BlockStateUtils.blockStateToId(blockState.get()); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java index 653b1f18a..718946298 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/MinecartPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.AbstractMinecartData; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -79,12 +79,7 @@ public class MinecartPacketHandler implements EntityPacketHandler { Optional blockState = (Optional) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); if (blockState.isEmpty()) return null; int stateId = BlockStateUtils.blockStateToId(blockState.get()); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) return null; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( @@ -100,12 +95,7 @@ public class MinecartPacketHandler implements EntityPacketHandler { public Object handle(NetWorkUser user, Object packedItem, int entityDataId) { if (entityDataId != AbstractMinecartData.DisplayBlock.id()) return null; int stateId = (int) FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) return null; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); return FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue(entityDataId, serializer, newStateId); diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java index ef3178e21..6fab87f02 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/handler/PrimedTNTPacketHandler.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import net.momirealms.craftengine.bukkit.entity.data.BaseEntityData; import net.momirealms.craftengine.bukkit.entity.data.PrimedTntData; import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.network.PacketConsumers; +import net.momirealms.craftengine.bukkit.plugin.network.BukkitNetworkManager; import net.momirealms.craftengine.bukkit.util.BlockStateUtils; import net.momirealms.craftengine.bukkit.util.ComponentUtils; import net.momirealms.craftengine.core.entity.player.Player; @@ -36,12 +36,7 @@ public class PrimedTNTPacketHandler implements EntityPacketHandler { if (entityDataId == PrimedTntData.BlockState.id()) { Object blockState = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$value(packedItem); int stateId = BlockStateUtils.blockStateToId(blockState); - int newStateId; - if (!user.clientModEnabled()) { - newStateId = PacketConsumers.remap(stateId); - } else { - newStateId = PacketConsumers.remapMOD(stateId); - } + int newStateId = BukkitNetworkManager.instance().remapBlockState(stateId, user.clientModEnabled()); if (newStateId == stateId) continue; Object serializer = FastNMS.INSTANCE.field$SynchedEntityData$DataValue$serializer(packedItem); packedItems.set(i, FastNMS.INSTANCE.constructor$SynchedEntityData$DataValue( diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java deleted file mode 100644 index e8d383aec..000000000 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIdFinder.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.momirealms.craftengine.bukkit.plugin.network.id; - -import com.google.gson.JsonElement; -import net.momirealms.craftengine.bukkit.nms.FastNMS; -import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.VersionHelper; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class PacketIdFinder { - private static final Map> gamePacketIdsByName = new HashMap<>(); - private static final Map, Integer>> gamePacketIdsByClazz = new HashMap<>(); - private static final int maxC2SPacketId; - private static final int maxS2CPacketId; - - static { - try { - if (VersionHelper.isOrAbove1_21()) { - Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null); - JsonElement jsonElement = (JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport); - JsonElement play = jsonElement.getAsJsonObject().get("play"); - for (Map.Entry entry : play.getAsJsonObject().entrySet()) { - Map ids = new HashMap<>(); - gamePacketIdsByName.put(entry.getKey(), ids); - for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) { - ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt()); - } - } - } else if (VersionHelper.isOrAbove1_20_5()) { - gamePacketIdsByName.putAll(FastNMS.INSTANCE.gamePacketIdsByName()); - } else { - gamePacketIdsByClazz.putAll(FastNMS.INSTANCE.gamePacketIdsByClazz()); - } - } catch (Exception e) { - CraftEngine.instance().logger().warn("Failed to get packets", e); - } - maxS2CPacketId = calculateMaxId("clientbound"); - maxC2SPacketId = calculateMaxId("serverbound"); - } - - private static int calculateMaxId(String direction) { - if (VersionHelper.isOrAbove1_20_5()) { - return gamePacketIdsByName.getOrDefault(direction, Collections.emptyMap()).size(); - } else { - return gamePacketIdsByClazz.getOrDefault(direction, Collections.emptyMap()).size(); - } - } - - public static int c2sGamePackets() { - return maxC2SPacketId; - } - - public static int s2cGamePackets() { - return maxS2CPacketId; - } - - public static int clientboundByName(String packetName) { - return gamePacketIdsByName.get("clientbound").getOrDefault(packetName, -1); - } - - public static int clientboundByClazz(Class clazz) { - return gamePacketIdsByClazz.get("clientbound").getOrDefault(clazz, -1); - } - - public static int serverboundByName(String packetName) { - return gamePacketIdsByName.get("serverbound").getOrDefault(packetName, -1); - } - - public static int serverboundByClazz(Class clazz) { - return gamePacketIdsByClazz.get("serverbound").getOrDefault(clazz, -1); - } -} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java index 99eb1c449..8b33c8fef 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20.java @@ -2,181 +2,183 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.NetworkReflections; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; public class PacketIds1_20 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBlockUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSectionBlocksUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSectionBlocksUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSectionBlocksUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelParticlesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelParticlesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelParticlesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelEventPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelEventPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundAddEntityPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundAddEntityPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundAddEntityPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundOpenScreenPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundOpenScreenPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundOpenScreenPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSoundPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSoundPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSoundPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundRemoveEntitiesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRemoveEntitiesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundRemoveEntitiesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEntityDataPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetEntityDataPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetEntityDataPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetTitleTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetTitleTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetTitleTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetSubtitleTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetSubtitleTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetSubtitleTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetActionBarTextPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetActionBarTextPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetActionBarTextPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundBossEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBossEventPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBossEventPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSystemChatPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSystemChatPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSystemChatPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundTabListPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundTabListPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundTabListPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerTeamPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetPlayerTeamPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetPlayerTeamPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetObjectivePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetObjectivePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetObjectivePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelChunkWithLightPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundLevelChunkWithLightPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundLevelChunkWithLightPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundPlayerInfoUpdatePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlayerInfoUpdatePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetScorePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetScorePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetScorePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetContentPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundContainerSetContentPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundContainerSetContentPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetSlotPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundContainerSetSlotPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundContainerSetSlotPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetCursorItemPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetCursorItemPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetCursorItemPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEquipmentPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetEquipmentPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetEquipmentPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerInventoryPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundSetPlayerInventoryPacket); - } - - @Override - public int serverboundContainerClickPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundContainerClickPacket); - } - - @Override - public int serverboundSetCreativeModeSlotPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket); - } - - @Override - public int clientboundBlockEventPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundBlockEventPacket); - } - - @Override - public int serverboundInteractPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundInteractPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundSetPlayerInventoryPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundRecipeBookAddPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundRecipeBookAddPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundPlaceGhostRecipePacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundPlaceGhostRecipePacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateRecipesPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundUpdateRecipesPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateAdvancementsPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundUpdateAdvancementsPacket, PacketFlow.CLIENTBOUND); } @Override public int clientboundForgetLevelChunkPacket() { - return PacketIdFinder.clientboundByClazz(NetworkReflections.clazz$ClientboundForgetLevelChunkPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundForgetLevelChunkPacket, PacketFlow.CLIENTBOUND); + } + + @Override + public int clientboundBlockEventPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ClientboundBlockEventPacket, PacketFlow.CLIENTBOUND); + } + + @Override + public int serverboundContainerClickPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundContainerClickPacket, PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundSetCreativeModeSlotPacket, PacketFlow.SERVERBOUND); + } + + + @Override + public int serverboundInteractPacket() { + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundInteractPacket, PacketFlow.SERVERBOUND); } @Override public int serverboundCustomPayloadPacket() { - return PacketIdFinder.serverboundByClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket); + return PlayPacketIdHelper.byClazz(NetworkReflections.clazz$ServerboundCustomPayloadPacket, PacketFlow.SERVERBOUND); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java index 70596861c..9aea4a3df 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PacketIds1_20_5.java @@ -1,181 +1,182 @@ package net.momirealms.craftengine.bukkit.plugin.network.id; import net.momirealms.craftengine.bukkit.plugin.network.PacketIds; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; public class PacketIds1_20_5 implements PacketIds { @Override public int clientboundBlockUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:block_update"); + return PlayPacketIdHelper.byName("minecraft:block_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundSectionBlocksUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:section_blocks_update"); + return PlayPacketIdHelper.byName("minecraft:section_blocks_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelParticlesPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_particles"); + return PlayPacketIdHelper.byName("minecraft:level_particles", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_event"); + return PlayPacketIdHelper.byName("minecraft:level_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundAddEntityPacket() { - return PacketIdFinder.clientboundByName("minecraft:add_entity"); + return PlayPacketIdHelper.byName("minecraft:add_entity", PacketFlow.CLIENTBOUND); } @Override public int clientboundOpenScreenPacket() { - return PacketIdFinder.clientboundByName("minecraft:open_screen"); + return PlayPacketIdHelper.byName("minecraft:open_screen", PacketFlow.CLIENTBOUND); } @Override public int clientboundSoundPacket() { - return PacketIdFinder.clientboundByName("minecraft:sound"); + return PlayPacketIdHelper.byName("minecraft:sound", PacketFlow.CLIENTBOUND); } @Override public int clientboundRemoveEntitiesPacket() { - return PacketIdFinder.clientboundByName("minecraft:remove_entities"); + return PlayPacketIdHelper.byName("minecraft:remove_entities", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEntityDataPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_entity_data"); + return PlayPacketIdHelper.byName("minecraft:set_entity_data", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetTitleTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_title_text"); + return PlayPacketIdHelper.byName("minecraft:set_title_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetSubtitleTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_subtitle_text"); + return PlayPacketIdHelper.byName("minecraft:set_subtitle_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetActionBarTextPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_action_bar_text"); + return PlayPacketIdHelper.byName("minecraft:set_action_bar_text", PacketFlow.CLIENTBOUND); } @Override public int clientboundBossEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:boss_event"); + return PlayPacketIdHelper.byName("minecraft:boss_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundSystemChatPacket() { - return PacketIdFinder.clientboundByName("minecraft:system_chat"); + return PlayPacketIdHelper.byName("minecraft:system_chat", PacketFlow.CLIENTBOUND); } @Override public int clientboundTabListPacket() { - return PacketIdFinder.clientboundByName("minecraft:tab_list"); + return PlayPacketIdHelper.byName("minecraft:tab_list", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerTeamPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_player_team"); + return PlayPacketIdHelper.byName("minecraft:set_player_team", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetObjectivePacket() { - return PacketIdFinder.clientboundByName("minecraft:set_objective"); + return PlayPacketIdHelper.byName("minecraft:set_objective", PacketFlow.CLIENTBOUND); } @Override public int clientboundLevelChunkWithLightPacket() { - return PacketIdFinder.clientboundByName("minecraft:level_chunk_with_light"); + return PlayPacketIdHelper.byName("minecraft:level_chunk_with_light", PacketFlow.CLIENTBOUND); } @Override public int clientboundPlayerInfoUpdatePacket() { - return PacketIdFinder.clientboundByName("minecraft:player_info_update"); + return PlayPacketIdHelper.byName("minecraft:player_info_update", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetScorePacket() { - return PacketIdFinder.clientboundByName("minecraft:set_score"); + return PlayPacketIdHelper.byName("minecraft:set_score", PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetContentPacket() { - return PacketIdFinder.clientboundByName("minecraft:container_set_content"); + return PlayPacketIdHelper.byName("minecraft:container_set_content", PacketFlow.CLIENTBOUND); } @Override public int clientboundContainerSetSlotPacket() { - return PacketIdFinder.clientboundByName("minecraft:container_set_slot"); + return PlayPacketIdHelper.byName("minecraft:container_set_slot", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetCursorItemPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_cursor_item"); + return PlayPacketIdHelper.byName("minecraft:set_cursor_item", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetEquipmentPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_equipment"); + return PlayPacketIdHelper.byName("minecraft:set_equipment", PacketFlow.CLIENTBOUND); } @Override public int clientboundSetPlayerInventoryPacket() { - return PacketIdFinder.clientboundByName("minecraft:set_player_inventory"); + return PlayPacketIdHelper.byName("minecraft:set_player_inventory", PacketFlow.CLIENTBOUND); } @Override public int clientboundBlockEventPacket() { - return PacketIdFinder.clientboundByName("minecraft:block_event"); + return PlayPacketIdHelper.byName("minecraft:block_event", PacketFlow.CLIENTBOUND); } @Override public int clientboundRecipeBookAddPacket() { - return PacketIdFinder.clientboundByName("minecraft:recipe_book_add"); + return PlayPacketIdHelper.byName("minecraft:recipe_book_add", PacketFlow.CLIENTBOUND); } @Override public int clientboundPlaceGhostRecipePacket() { - return PacketIdFinder.clientboundByName("minecraft:place_ghost_recipe"); + return PlayPacketIdHelper.byName("minecraft:place_ghost_recipe", PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateRecipesPacket() { - return PacketIdFinder.clientboundByName("minecraft:update_recipes"); + return PlayPacketIdHelper.byName("minecraft:update_recipes", PacketFlow.CLIENTBOUND); } @Override public int clientboundUpdateAdvancementsPacket() { - return PacketIdFinder.clientboundByName("minecraft:update_advancements"); - } - - @Override - public int serverboundContainerClickPacket() { - return PacketIdFinder.serverboundByName("minecraft:container_click"); - } - - @Override - public int serverboundSetCreativeModeSlotPacket() { - return PacketIdFinder.serverboundByName("minecraft:set_creative_mode_slot"); - } - - @Override - public int serverboundInteractPacket() { - return PacketIdFinder.serverboundByName("minecraft:interact"); + return PlayPacketIdHelper.byName("minecraft:update_advancements", PacketFlow.CLIENTBOUND); } @Override public int clientboundForgetLevelChunkPacket() { - return PacketIdFinder.clientboundByName("minecraft:forget_level_chunk"); + return PlayPacketIdHelper.byName("minecraft:forget_level_chunk", PacketFlow.CLIENTBOUND); + } + + @Override + public int serverboundContainerClickPacket() { + return PlayPacketIdHelper.byName("minecraft:container_click", PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundSetCreativeModeSlotPacket() { + return PlayPacketIdHelper.byName("minecraft:set_creative_mode_slot", PacketFlow.SERVERBOUND); + } + + @Override + public int serverboundInteractPacket() { + return PlayPacketIdHelper.byName("minecraft:interact", PacketFlow.SERVERBOUND); } @Override public int serverboundCustomPayloadPacket() { - return PacketIdFinder.serverboundByName("custom_payload"); + return PlayPacketIdHelper.byName("custom_payload", PacketFlow.SERVERBOUND); } } diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java new file mode 100644 index 000000000..8d903bca8 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/id/PlayPacketIdHelper.java @@ -0,0 +1,61 @@ +package net.momirealms.craftengine.bukkit.plugin.network.id; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.momirealms.craftengine.bukkit.nms.FastNMS; +import net.momirealms.craftengine.bukkit.plugin.reflection.minecraft.CoreReflections; +import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.network.PacketFlow; +import net.momirealms.craftengine.core.util.VersionHelper; + +import java.util.*; + +public class PlayPacketIdHelper { + // 1.20.5-latest + private static final Map> byName = new EnumMap<>(PacketFlow.class); + // 1.20-1.20.4 + private static final Map, Integer>> byClazz = new EnumMap<>(PacketFlow.class); + + static { + try { + if (VersionHelper.isOrAbove1_21()) { + Object packetReport = CoreReflections.constructor$PacketReport.newInstance((Object) null); + JsonObject packetReportData = ((JsonElement) CoreReflections.method$PacketReport$serializePackets.invoke(packetReport)).getAsJsonObject(); + JsonObject playData = packetReportData.get("play").getAsJsonObject(); + for (Map.Entry entry : playData.entrySet()) { + Map ids = new HashMap<>(); + byName.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), ids); + for (var entry2 : entry.getValue().getAsJsonObject().entrySet()) { + ids.put(entry2.getKey(), entry2.getValue().getAsJsonObject().get("protocol_id").getAsInt()); + } + } + } else if (VersionHelper.isOrAbove1_20_5()) { + for (Map.Entry> entry : FastNMS.INSTANCE.gamePacketIdsByName().entrySet()) { + byName.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), entry.getValue()); + } + } else { + for (Map.Entry, Integer>> entry : FastNMS.INSTANCE.gamePacketIdsByClazz().entrySet()) { + byClazz.put(PacketFlow.valueOf(entry.getKey().toUpperCase(Locale.ROOT)), entry.getValue()); + } + } + } catch (Exception e) { + CraftEngine.instance().logger().warn("Failed to init packet registry", e); + } + } + + public static int count(PacketFlow direction) { + if (VersionHelper.isOrAbove1_20_5()) { + return byName.getOrDefault(direction, Collections.emptyMap()).size(); + } else { + return byClazz.getOrDefault(direction, Collections.emptyMap()).size(); + } + } + + public static int byName(String packetName, PacketFlow direction) { + return byName.get(direction).getOrDefault(packetName, -1); + } + + public static int byClazz(Class clazz, PacketFlow direction) { + return byClazz.get(direction).getOrDefault(clazz, -1); + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java new file mode 100644 index 000000000..ebc7dbe34 --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/ByteBufferPacketListener.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.plugin.network.listener; + +import net.momirealms.craftengine.core.plugin.network.ByteBufPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public interface ByteBufferPacketListener { + + default void onPacketReceive(NetWorkUser user, ByteBufPacketEvent event) { + } + + default void onPacketSend(NetWorkUser user, ByteBufPacketEvent event) { + } +} diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java new file mode 100644 index 000000000..b7471726b --- /dev/null +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/plugin/network/listener/NMSPacketListener.java @@ -0,0 +1,13 @@ +package net.momirealms.craftengine.bukkit.plugin.network.listener; + +import net.momirealms.craftengine.core.plugin.network.NMSPacketEvent; +import net.momirealms.craftengine.core.plugin.network.NetWorkUser; + +public interface NMSPacketListener { + + default void onPacketReceive(NetWorkUser user, NMSPacketEvent event, Object packet) { + } + + default void onPacketSend(NetWorkUser user, NMSPacketEvent event, Object packet) { + } +} diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java index 808dd56eb..2db50e789 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/NetworkManager.java @@ -22,6 +22,8 @@ public interface NetworkManager extends Manageable { Channel getChannel(Player player); + int remapBlockState(int stateId, boolean enableMod); + Player[] onlineUsers(); default void sendPacket(@NotNull NetWorkUser player, Object packet) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java new file mode 100644 index 000000000..2311d2fad --- /dev/null +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/network/PacketFlow.java @@ -0,0 +1,6 @@ +package net.momirealms.craftengine.core.plugin.network; + +public enum PacketFlow { + SERVERBOUND, + CLIENTBOUND; +} diff --git a/gradle.properties b/gradle.properties index 3dfd4ae54..20d23a1d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -60,9 +60,9 @@ authlib_version=6.0.58 concurrent_util_version=0.0.3 # Proxy settings -#systemProp.socks.proxyHost=127.0.0.1 -#systemProp.socks.proxyPort=7890 -#systemProp.http.proxyHost=127.0.0.1 -#systemProp.http.proxyPort=7890 -#systemProp.https.proxyHost=127.0.0.1 -#systemProp.https.proxyPort=7890 \ No newline at end of file +systemProp.socks.proxyHost=127.0.0.1 +systemProp.socks.proxyPort=7890 +systemProp.http.proxyHost=127.0.0.1 +systemProp.http.proxyPort=7890 +systemProp.https.proxyHost=127.0.0.1 +systemProp.https.proxyPort=7890 \ No newline at end of file