diff --git a/NmsProvider - 1.21.R1/.classpath b/NmsProvider - 1.21.R1/.classpath new file mode 100644 index 00000000..fa968cc5 --- /dev/null +++ b/NmsProvider - 1.21.R1/.classpath @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NmsProvider - 1.21.R1/src/me/devtec/theapi/bukkit/nms/v1_21_R1.java b/NmsProvider - 1.21.R1/src/me/devtec/theapi/bukkit/nms/v1_21_R1.java new file mode 100644 index 00000000..1907ca5d --- /dev/null +++ b/NmsProvider - 1.21.R1/src/me/devtec/theapi/bukkit/nms/v1_21_R1.java @@ -0,0 +1,1759 @@ +package me.devtec.theapi.bukkit.nms; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import javax.imageio.ImageIO; + +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.v1_21_R1.CraftChunk; +import org.bukkit.craftbukkit.v1_21_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_21_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.v1_21_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftContainer; +import org.bukkit.craftbukkit.v1_21_R1.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_21_R1.util.CraftMagicNumbers; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +import com.google.common.base.Preconditions; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; + +import io.netty.channel.Channel; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import me.devtec.shared.Pair; +import me.devtec.shared.Ref; +import me.devtec.shared.components.ClickEvent; +import me.devtec.shared.components.Component; +import me.devtec.shared.components.ComponentAPI; +import me.devtec.shared.components.ComponentEntity; +import me.devtec.shared.components.ComponentItem; +import me.devtec.shared.components.HoverEvent; +import me.devtec.shared.events.EventManager; +import me.devtec.shared.json.Json; +import me.devtec.shared.utility.ParseUtils; +import me.devtec.theapi.bukkit.BukkitLoader; +import me.devtec.theapi.bukkit.events.ServerListPingEvent; +import me.devtec.theapi.bukkit.game.BlockDataStorage; +import me.devtec.theapi.bukkit.gui.AnvilGUI; +import me.devtec.theapi.bukkit.gui.GUI.ClickType; +import me.devtec.theapi.bukkit.gui.HolderGUI; +import me.devtec.theapi.bukkit.nms.GameProfileHandler.PropertyHandler; +import me.devtec.theapi.bukkit.nms.utils.InventoryUtils; +import me.devtec.theapi.bukkit.nms.utils.InventoryUtils.DestinationType; +import me.devtec.theapi.bukkit.packetlistener.PacketContainer; +import me.devtec.theapi.bukkit.xseries.XMaterial; +import net.minecraft.EnumChatFormat; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.CommandDispatcher; +import net.minecraft.core.BlockPosition; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.particles.Particle; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.registries.VanillaRegistries; +import net.minecraft.nbt.MojangsonParser; +import net.minecraft.nbt.NBTBase; +import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.NetworkManager; +import net.minecraft.network.chat.ChatClickable; +import net.minecraft.network.chat.ChatClickable.EnumClickAction; +import net.minecraft.network.chat.ChatHexColor; +import net.minecraft.network.chat.ChatHoverable; +import net.minecraft.network.chat.ChatHoverable.EnumHoverAction; +import net.minecraft.network.chat.ChatModifier; +import net.minecraft.network.chat.IChatBaseComponent; +import net.minecraft.network.chat.IChatMutableComponent; +import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket.a; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.PacketPlayInWindowClick; +import net.minecraft.network.protocol.game.PacketPlayOutBlockChange; +import net.minecraft.network.protocol.game.PacketPlayOutCloseWindow; +import net.minecraft.network.protocol.game.PacketPlayOutEntityDestroy; +import net.minecraft.network.protocol.game.PacketPlayOutEntityHeadRotation; +import net.minecraft.network.protocol.game.PacketPlayOutEntityMetadata; +import net.minecraft.network.protocol.game.PacketPlayOutExperience; +import net.minecraft.network.protocol.game.PacketPlayOutHeldItemSlot; +import net.minecraft.network.protocol.game.PacketPlayOutOpenWindow; +import net.minecraft.network.protocol.game.PacketPlayOutPlayerListHeaderFooter; +import net.minecraft.network.protocol.game.PacketPlayOutPosition; +import net.minecraft.network.protocol.game.PacketPlayOutRespawn; +import net.minecraft.network.protocol.game.PacketPlayOutScoreboardDisplayObjective; +import net.minecraft.network.protocol.game.PacketPlayOutScoreboardObjective; +import net.minecraft.network.protocol.game.PacketPlayOutScoreboardScore; +import net.minecraft.network.protocol.game.PacketPlayOutScoreboardTeam; +import net.minecraft.network.protocol.game.PacketPlayOutSetSlot; +import net.minecraft.network.protocol.game.PacketPlayOutSpawnEntity; +import net.minecraft.network.protocol.status.PacketStatusOutServerInfo; +import net.minecraft.network.protocol.status.ServerPing; +import net.minecraft.network.protocol.status.ServerPing.ServerData; +import net.minecraft.network.protocol.status.ServerPing.ServerPingPlayerSample; +import net.minecraft.resources.MinecraftKey; +import net.minecraft.resources.ResourceKey; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.ScoreboardServer; +import net.minecraft.server.level.EntityPlayer; +import net.minecraft.server.level.WorldServer; +import net.minecraft.server.network.PlayerConnection; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.world.entity.EntityLiving; +import net.minecraft.world.entity.EntityTypes; +import net.minecraft.world.entity.player.EntityHuman; +import net.minecraft.world.entity.player.PlayerInventory; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.inventory.Container; +import net.minecraft.world.inventory.ContainerAccess; +import net.minecraft.world.inventory.ContainerAnvil; +import net.minecraft.world.inventory.Containers; +import net.minecraft.world.inventory.InventoryClickType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.EnumGamemode; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BlockFalling; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.ITileEntity; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.state.BlockStateList; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.block.state.IBlockDataHolder; +import net.minecraft.world.level.block.state.properties.IBlockState; +import net.minecraft.world.level.chunk.Chunk.EnumTileEntityState; +import net.minecraft.world.level.chunk.ChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.ScoreboardObjective; +import net.minecraft.world.scores.criteria.IScoreboardCriteria.EnumScoreboardHealthDisplay; + +public class v1_21_R1 implements NmsProvider { + private static final MinecraftServer server = MinecraftServer.getServer(); + private static final IChatBaseComponent empty = IChatBaseComponent.b(""); + private static final CommandBuildContext dispatcher = CommandDispatcher.a(VanillaRegistries.a()); + + @Override + public Collection getOnlinePlayers() { + return Bukkit.getOnlinePlayers(); + } + + @Override + public Object getEntity(Entity entity) { + return ((CraftEntity) entity).getHandle(); + } + + @Override + public Object getEntityLiving(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle(); + } + + @Override + public Object getPlayer(Player player) { + return ((CraftPlayer) player).getHandle(); + } + + @Override + public Object getWorld(World world) { + return ((CraftWorld) world).getHandle(); + } + + @Override + public Object getChunk(Chunk chunk) { + return ((CraftChunk) chunk).getHandle(ChunkStatus.n); + } + + @Override + public int getEntityId(Object entity) { + return ((net.minecraft.world.entity.Entity) entity).an(); + } + + @Override + public Object getScoreboardAction(Action type) { + return type == Action.CHANGE ? ScoreboardServer.Action.a : ScoreboardServer.Action.b; + } + + @Override + public Object getEnumScoreboardHealthDisplay(DisplayType type) { + return type == DisplayType.INTEGER ? EnumScoreboardHealthDisplay.a : EnumScoreboardHealthDisplay.b; + } + + @Override + public Object getNBT(ItemStack itemStack) { + net.minecraft.world.item.ItemStack item = (net.minecraft.world.item.ItemStack) asNMSItem(itemStack); + if (item.e()) + return new NBTTagCompound(); + CustomData data = item.a(DataComponents.b); + if (data != null) + return data.c(); + return null; + } + + @Override + public Object parseNBT(String json) { + if (json == null) + return new NBTTagCompound(); + try { + return MojangsonParser.a(json); + } catch (Exception e) { + return new NBTTagCompound(); + } + } + + @Override + public ItemStack setNBT(ItemStack stack, Object nbt) { + if (nbt instanceof NBTEdit) + nbt = ((NBTEdit) nbt).getNBT(); + net.minecraft.world.item.ItemStack item = (net.minecraft.world.item.ItemStack) asNMSItem(stack); + item.b(DataComponents.b, CustomData.a((NBTTagCompound) nbt)); + return asBukkitItem(item); + } + + @Override + public Object asNMSItem(ItemStack stack) { + if (stack == null) + return net.minecraft.world.item.ItemStack.l; + return CraftItemStack.asNMSCopy(stack); + } + + @Override + public ItemStack asBukkitItem(Object stack) { + return CraftItemStack.asBukkitCopy(stack == null ? net.minecraft.world.item.ItemStack.l : (net.minecraft.world.item.ItemStack) stack); + } + + @Override + public int getContainerId(Object container) { + return ((Container) container).j; + } + + @Override + public Object packetResourcePackSend(String url, String hash, boolean requireRP, Component prompt) { + return new ClientboundResourcePackPushPacket(UUID.randomUUID(), url, hash, requireRP, + prompt == null ? null : prompt == null ? Optional.empty() : Optional.of((IChatBaseComponent) this.toIChatBaseComponent(prompt))); + } + + @Override + public Object packetSetSlot(int container, int slot, int changeId, Object itemStack) { + return new PacketPlayOutSetSlot(container, changeId, slot, (net.minecraft.world.item.ItemStack) (itemStack == null ? asNMSItem(null) : itemStack)); + } + + @Override + public Object packetEntityMetadata(int entityId, Object dataWatcher, boolean bal) { + return new PacketPlayOutEntityMetadata(entityId, ((net.minecraft.network.syncher.DataWatcher) dataWatcher).c()); + } + + @Override + public Object packetEntityDestroy(int... ids) { + return new PacketPlayOutEntityDestroy(ids); + } + + @Override + public Object packetSpawnEntity(Object entity, int id) { + BlockPosition pos = new BlockPosition(((net.minecraft.world.entity.Entity) entity).ds(), ((net.minecraft.world.entity.Entity) entity).dy(), ((net.minecraft.world.entity.Entity) entity).du()); + return new PacketPlayOutSpawnEntity((net.minecraft.world.entity.Entity) entity, id, pos); + } + + @Override + public Object packetNamedEntitySpawn(Object player) { + BlockPosition pos = new BlockPosition(((EntityHuman) player).ds(), ((EntityHuman) player).dy(), ((EntityHuman) player).du()); + return new PacketPlayOutSpawnEntity((EntityHuman) player, 0, pos); + } + + @Override + public Object packetSpawnEntityLiving(Object entityLiving) { + BlockPosition pos = new BlockPosition(((EntityLiving) entityLiving).ds(), ((EntityLiving) entityLiving).dy(), ((EntityLiving) entityLiving).du()); + return new PacketPlayOutSpawnEntity((EntityLiving) entityLiving, 0, pos); + } + + @Override + public Object packetPlayerListHeaderFooter(Component header, Component footer) { + return new PacketPlayOutPlayerListHeaderFooter((IChatBaseComponent) this.toIChatBaseComponent(header), (IChatBaseComponent) this.toIChatBaseComponent(footer)); + } + + @Override + public Object packetBlockChange(int x, int y, int z, Object iblockdata, int data) { + return new PacketPlayOutBlockChange(new BlockPosition(x, y, z), iblockdata == null ? Blocks.a.o() : (IBlockData) iblockdata); + } + + @Override + public Object packetScoreboardObjective() { + return Ref.newUnsafeInstance(PacketPlayOutScoreboardObjective.class); + } + + @Override + public Object packetScoreboardDisplayObjective(int id, Object scoreboardObjective) { + return new PacketPlayOutScoreboardDisplayObjective(DisplaySlot.values()[id], scoreboardObjective == null ? null : (ScoreboardObjective) scoreboardObjective); + } + + @Override + public Object packetScoreboardTeam() { + return Ref.newUnsafeInstance(PacketPlayOutScoreboardTeam.class); + } + + @Override + public Object packetScoreboardScore(Action action, String player, String line, int score) { + return new PacketPlayOutScoreboardScore(line, player, score, Optional.ofNullable(null), Optional.ofNullable(null)); + } + + @Override + public Object packetTitle(TitleAction action, Component text, int fadeIn, int stay, int fadeOut) { + switch (action) { + case ACTIONBAR: + return new ClientboundSetActionBarTextPacket((IChatBaseComponent) this.toIChatBaseComponent(text)); + case TITLE: + return new ClientboundSetTitleTextPacket((IChatBaseComponent) this.toIChatBaseComponent(text)); + case SUBTITLE: + return new ClientboundSetSubtitleTextPacket((IChatBaseComponent) this.toIChatBaseComponent(text)); + case TIMES: + return new ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + case CLEAR: + case RESET: + return new ClientboundClearTitlesPacket(true); + } + return null; + } + + @Override + public Object packetChat(ChatType type, Object chatBase, UUID uuid) { + return new ClientboundSystemChatPacket((IChatBaseComponent) chatBase, false); + } + + @Override + public Object packetChat(ChatType type, Component text, UUID uuid) { + return new ClientboundSystemChatPacket((IChatBaseComponent) this.toIChatBaseComponent(text), false); + } + + @Override + public void postToMainThread(Runnable runnable) { + v1_21_R1.server.execute(runnable); + } + + @Override + public Object getMinecraftServer() { + return v1_21_R1.server; + } + + @Override + public Thread getServerThread() { + return v1_21_R1.server.aj; + } + + @Override + public double[] getServerTPS() { + return v1_21_R1.server.recentTps; + } + + private IChatBaseComponent convert(Component c) { + if (c instanceof ComponentItem || c instanceof ComponentEntity) + return IChatBaseComponent.ChatSerializer.a(Json.writer().simpleWrite(c.toJsonMap()), dispatcher); + IChatMutableComponent current = IChatBaseComponent.b(c.getText()); + ChatModifier modif = current.a(); + if (c.getColor() != null && !c.getColor().isEmpty()) + if (c.getColor().startsWith("#")) + modif = modif.a(ChatHexColor.a(Integer.decode(c.getColor()))); + else + modif = modif.a(EnumChatFormat.a(c.colorToChar())); + if (c.getClickEvent() != null) + modif = modif.a(new ChatClickable(EnumClickAction.valueOf(c.getClickEvent().getAction().name()), c.getClickEvent().getValue())); + if (c.getHoverEvent() != null) + switch (c.getHoverEvent().getAction()) { + case SHOW_ENTITY: + try { + ComponentEntity compoundTag = (ComponentEntity) c.getHoverEvent().getValue(); + IChatBaseComponent component = compoundTag.getName() == null ? null : (IChatBaseComponent) toIChatBaseComponent(compoundTag.getName()); + EntityTypes entityType = BuiltInRegistries.f.a(MinecraftKey.a(compoundTag.getType())); + modif = modif.a(new ChatHoverable(EnumHoverAction.c, new ChatHoverable.b(entityType, compoundTag.getId(), component))); + } catch (Exception commandSyntaxException) { + } + break; + case SHOW_ITEM: + try { + + ComponentItem compoundTag = (ComponentItem) c.getHoverEvent().getValue(); + net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack( + CraftMagicNumbers.getItem(XMaterial.matchXMaterial(compoundTag.getId()).orElse(XMaterial.AIR).parseMaterial()), compoundTag.getCount()); + if (compoundTag.getNbt() != null) { + NBTTagCompound nbt = (NBTTagCompound) parseNBT(compoundTag.getNbt()); + if (!nbt.e().contains("id")) + nbt.a("id", BuiltInRegistries.g.b(CraftMagicNumbers.getItem(XMaterial.matchXMaterial(compoundTag.getId()).orElse(XMaterial.AIR).parseMaterial())).toString()); + if (!nbt.e().contains("count")) + nbt.a("count", compoundTag.getCount()); + stack = net.minecraft.world.item.ItemStack.a(CommandDispatcher.a(VanillaRegistries.a()), nbt); + } + modif = modif.a(new ChatHoverable(EnumHoverAction.b, new ChatHoverable.c(stack))); + } catch (Exception commandSyntaxException) { + } + break; + default: + modif = modif.a(new ChatHoverable(EnumHoverAction.a, (IChatBaseComponent) this.toIChatBaseComponent(c.getHoverEvent().getValue()))); + break; + } + modif = modif.a(c.isBold()); + modif = modif.b(c.isItalic()); + modif = modif.e(c.isObfuscated()); + modif = modif.c(c.isUnderlined()); + modif = modif.d(c.isStrikethrough()); + current.b(modif); + return current; + } + + @Override + public Object[] toIChatBaseComponents(List components) { + List chat = new ArrayList<>(); + chat.add(IChatBaseComponent.b("")); + for (Component c : components) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + return chat.toArray(new IChatBaseComponent[0]); + } + + private void addConverted(List chat, List extra) { + for (Component c : extra) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + } + + @Override + public Object[] toIChatBaseComponents(Component co) { + if (co == null) + return new IChatBaseComponent[] { empty }; + if (co instanceof ComponentItem || co instanceof ComponentEntity) + return new IChatBaseComponent[] { IChatBaseComponent.ChatSerializer.a(Json.writer().simpleWrite(co.toJsonMap()), dispatcher) }; + List chat = new ArrayList<>(); + chat.add(IChatBaseComponent.b("")); + if (co.getText() != null && !co.getText().isEmpty()) + chat.add(convert(co)); + if (co.getExtra() != null) + for (Component c : co.getExtra()) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + return chat.toArray(new IChatBaseComponent[0]); + } + + @Override + public Object toIChatBaseComponent(Component co) { + if (co == null) + return empty; + if (co instanceof ComponentItem || co instanceof ComponentEntity) + return IChatBaseComponent.ChatSerializer.a(Json.writer().simpleWrite(co.toJsonMap()), dispatcher); + IChatMutableComponent main = IChatBaseComponent.b(""); + List chat = new ArrayList<>(); + if (co.getText() != null && !co.getText().isEmpty()) + chat.add(convert(co)); + if (co.getExtra() != null) + for (Component c : co.getExtra()) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + main.c().addAll(chat); + return main.c().isEmpty() ? empty : main; + } + + @Override + public Object toIChatBaseComponent(List cc) { + IChatMutableComponent main = IChatBaseComponent.b(""); + for (Component c : cc) + main.c().add((IChatBaseComponent) this.toIChatBaseComponent(c)); + return main.c().isEmpty() ? empty : main; + } + + @Override + public Object chatBase(String json) { + return IChatBaseComponent.ChatSerializer.a(json, dispatcher); + } + + @Override + public Component fromIChatBaseComponent(Object componentObject) { + if (componentObject == null) + return Component.EMPTY_COMPONENT; + IChatBaseComponent component = (IChatBaseComponent) componentObject; + Object result = Ref.invoke(component.b(), "b"); + Component comp = new Component(result == null ? "" : (String) result); + ChatModifier modif = component.a(); + if (modif.a() != null) + comp.setColor(modif.a().b()); + + if (modif.h() != null) + comp.setClickEvent(new ClickEvent(ClickEvent.Action.valueOf(modif.h().a().name()), modif.h().b())); + + if (modif.i() != null) + switch (HoverEvent.Action.valueOf(modif.i().a().c().toUpperCase())) { + case SHOW_ENTITY: { + net.minecraft.network.chat.ChatHoverable.b hover = modif.i().a(EnumHoverAction.c); + ComponentEntity compEntity = new ComponentEntity(hover.b.toString(), hover.c); + if (hover.d.isPresent()) + compEntity.setName(fromIChatBaseComponent(hover.d.get())); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ENTITY, compEntity)); + break; + } + case SHOW_ITEM: { + net.minecraft.network.chat.ChatHoverable.c hover = modif.i().a(EnumHoverAction.b); + ComponentItem compEntity = new ComponentItem(CraftMagicNumbers.getMaterial(hover.a().g()).name(), hover.a().H()); + if (hover.a().a() != null) + compEntity.setNbt(hover.a().a(CommandDispatcher.a(VanillaRegistries.a())).toString()); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, compEntity)); + break; + } + default: + IChatBaseComponent hover = modif.i().a(EnumHoverAction.a); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, fromIChatBaseComponent(hover))); + break; + } + comp.setBold(modif.b()); + comp.setItalic(modif.c()); + comp.setObfuscated(modif.d()); + comp.setUnderlined(modif.e()); + comp.setStrikethrough(modif.f()); + + if (!component.c().isEmpty()) { + List extra = new ArrayList<>(); + for (IChatBaseComponent base : component.c()) + extra.add(fromIChatBaseComponent(base)); + comp.setExtra(extra); + } + return comp; + } + + @Override + public BlockDataStorage toMaterial(Object blockOrIBlockData) { + if (blockOrIBlockData instanceof Block) { + IBlockData data = ((Block) blockOrIBlockData).o(); + return new BlockDataStorage(CraftMagicNumbers.getMaterial(data.b()), (byte) 0, asString(data)); + } + if (blockOrIBlockData instanceof IBlockData) { + IBlockData data = (IBlockData) blockOrIBlockData; + return new BlockDataStorage(CraftMagicNumbers.getMaterial(data.b()), (byte) 0, asString(data)); + } + return new BlockDataStorage(Material.AIR); + } + + private String asString(IBlockData data) { + StringBuilder stateString = new StringBuilder(); + if (!data.C().isEmpty()) { + stateString.append('['); + stateString.append(data.C().entrySet().stream().map(IBlockDataHolder.a).collect(Collectors.joining(","))); + stateString.append(']'); + } + return stateString.toString(); + } + + @Override + public Object toIBlockData(BlockDataStorage material) { + if (material == null || material.getType() == null || material.getType() == Material.AIR) + return Blocks.a.o(); + Block block = CraftMagicNumbers.getBlock(material.getType()); + return readArgument(block, material); + } + + @Override + public Object toBlock(BlockDataStorage material) { + if (material == null || material.getType() == null || material.getType() == Material.AIR) + return Blocks.a; + Block block = CraftMagicNumbers.getBlock(material.getType()); + return readArgument(block, material).b(); + } + + private IBlockData readArgument(Block block, BlockDataStorage material) { + IBlockData ib = block.o(); + return writeData(ib, ib.b().l(), material.getData()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static IBlockData writeData(IBlockData ib, BlockStateList blockStateList, String string) { + if (string == null || string.trim().isEmpty()) + return ib; + + String key = ""; + String value = ""; + int set = 0; + + for (int i = 1; i < string.length() - 1; ++i) { + char c = string.charAt(i); + if (c == ',') { + IBlockState ibj = blockStateList.a(key); + if (ibj != null) { + Optional optional = ibj.b(value); + if (optional.isPresent()) + ib = ib.a(ibj, (Comparable) optional.get()); + } + key = ""; + value = ""; + set = 0; + continue; + } + if (c == '=') { + set = 1; + continue; + } + if (set == 0) + key += c; + else + value += c; + } + if (set == 1) { + IBlockState ibj = blockStateList.a(key); + if (ibj != null) { + Optional optional = ibj.b(value); + if (optional.isPresent()) + ib = ib.a(ibj, (Comparable) optional.get()); + } + } + return ib; + } + + @Override + public ItemStack toItemStack(BlockDataStorage material) { + Item item = CraftMagicNumbers.getItem(material.getType(), ParseUtils.getShort(material.getData())); + return CraftItemStack.asBukkitCopy(item.w()); + } + + @Override + public Object getChunk(World world, int x, int z) { + return ((CraftChunk) world.getChunkAt(x, z)).getHandle(ChunkStatus.n); + } + + @Override + public void setBlock(Object objChunk, int x, int y, int z, Object IblockData, int data) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + WorldServer world = chunk.r; + int highY = chunk.e(y); + if (highY < 0) + return; + ChunkSection sc = chunk.b(highY); + if (sc == null) + return; + BlockPosition pos = new BlockPosition(x, y, z); + + IBlockData iblock = IblockData == null ? Blocks.a.o() : (IBlockData) IblockData; + + boolean onlyModifyState = iblock.b() instanceof ITileEntity; + + // REMOVE TILE ENTITY IF NOT SAME TYPE + TileEntity ent = chunk.k.get(pos); + if (ent != null) { + boolean shouldSkip = true; + if (!onlyModifyState) + shouldSkip = false; + else if (onlyModifyState && !ent.r().a(iblock)) { + shouldSkip = false; + onlyModifyState = false; + } + if (!shouldSkip) + chunk.d(pos); + } + + IBlockData old = sc.a(x & 15, y & 15, z & 15, iblock, false); + + // ADD TILE ENTITY + if (iblock.b() instanceof ITileEntity && !onlyModifyState) { + ent = ((ITileEntity) iblock.b()).a(pos, iblock); + chunk.k.put(pos, ent); + ent.a(chunk.r); + Object packet = ent.az_(); + BukkitLoader.getPacketHandler().send(chunk.r.getWorld().getPlayers(), packet); + } + + // MARK CHUNK TO SAVE + chunk.a(true); + + // POI + if (!world.preventPoiUpdated) + world.a(pos, old, iblock); + } + + @Override + public void updatePhysics(Object objChunk, int x, int y, int z, Object iblockdata) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + + BlockPosition blockPos = new BlockPosition(x, y, z); + + doPhysicsAround(chunk.r, blockPos, ((IBlockData) iblockdata).b()); + } + + private void doPhysicsAround(WorldServer world, BlockPosition blockposition, Block block) { + doPhysics(world, blockposition.h(), block, blockposition); // west + doPhysics(world, blockposition.i(), block, blockposition); // east + doPhysics(world, blockposition.e(), block, blockposition); // down + doPhysics(world, blockposition.d(), block, blockposition); // up + doPhysics(world, blockposition.f(), block, blockposition); // north + doPhysics(world, blockposition.g(), block, blockposition); // south + } + + private static final Method callPhysics = Ref.method(BlockFalling.class, "b", IBlockData.class, net.minecraft.world.level.World.class, BlockPosition.class, IBlockData.class, boolean.class); + + private void doPhysics(WorldServer world, BlockPosition blockposition, Block block, BlockPosition blockposition1) { + IBlockData state = world.a_(blockposition); + state.a(world, blockposition, block, blockposition1, false); + if (state.b() instanceof BlockFalling) + Ref.invoke(state.b(), callPhysics, state, world, blockposition, block.o(), false); + } + + @Override + public void updateLightAt(Object objChunk, int x, int y, int z) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + chunk.r.l().a().a(new BlockPosition(x, y, z)); + } + + @Override + public Object getBlock(Object objChunk, int x, int y, int z) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + int highY = chunk.e(y); + if (highY < 0) + return Blocks.a.o(); + ChunkSection sc = chunk.b(highY); + if (sc == null) + return Blocks.a.o(); + return sc.h().a(x & 15, y & 15, z & 15); + } + + @Override + public byte getData(Object chunk, int x, int y, int z) { + return 0; + } + + @Override + public String getNBTOfTile(Object objChunk, int x, int y, int z) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + return chunk.a(new BlockPosition(x, y, z), EnumTileEntityState.a).a(dispatcher).toString(); + } + + @Override + public void setNBTToTile(Object objChunk, int x, int y, int z, String nbt) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + TileEntity ent = chunk.a(new BlockPosition(x, y, z), EnumTileEntityState.a); + NBTTagCompound parsedNbt = (NBTTagCompound) parseNBT(nbt); + parsedNbt.a("x", x); + parsedNbt.a("y", y); + parsedNbt.a("z", z); + ent.a(parsedNbt); + Object packet = ent.az_(); + BukkitLoader.getPacketHandler().send(chunk.r.getWorld().getPlayers(), packet); + } + + @Override + public boolean isTileEntity(Object objChunk, int x, int y, int z) { + net.minecraft.world.level.chunk.Chunk chunk = (net.minecraft.world.level.chunk.Chunk) objChunk; + return chunk.a(new BlockPosition(x, y, z), EnumTileEntityState.a) != null; + } + + @Override + public int getCombinedId(Object IblockDataOrBlock) { + return Block.i((IBlockData) IblockDataOrBlock); + } + + @Override + public Object blockPosition(int blockX, int blockY, int blockZ) { + return new BlockPosition(blockX, blockY, blockZ); + } + + @Override + public Object toIBlockData(Object data) { + return ((CraftBlockData) data).getState(); + } + + @Override + public Object toIBlockData(BlockState state) { + return CraftMagicNumbers.getBlock(state.getType(), state.getRawData()); + } + + @Override + public Chunk toBukkitChunk(Object nmsChunk) { + return new CraftChunk((net.minecraft.world.level.chunk.Chunk) nmsChunk); + } + + @Override + public int getPing(Player player) { + return ((PlayerConnection) getPlayerConnection(player)).k(); + } + + @Override + public Object getPlayerConnection(Player player) { + return ((EntityPlayer) getPlayer(player)).c; + } + + private static Field networkManagerField = Ref.field(ServerCommonPacketListenerImpl.class, NetworkManager.class); + + @Override + public Object getConnectionNetwork(Object playercon) { + return Ref.get(playercon, networkManagerField); + } + + @Override + public Object getNetworkChannel(Object network) { + return ((NetworkManager) network).n; + } + + @Override + public Object packetOpenWindow(int id, String legacy, int size, Component title) { + Containers windowType = Containers.a; + switch (size) { + case 0: { + windowType = Containers.i; + break; + } + case 18: { + windowType = Containers.b; + break; + } + case 27: { + windowType = Containers.c; + break; + } + case 36: { + windowType = Containers.d; + break; + } + case 45: { + windowType = Containers.e; + break; + } + case 54: { + windowType = Containers.f; + break; + } + } + return new PacketPlayOutOpenWindow(id, windowType, (IChatBaseComponent) this.toIChatBaseComponent(title)); + } + + @Override + public void closeGUI(Player player, Object container, boolean closePacket) { + if (closePacket) + BukkitLoader.getPacketHandler().send(player, new PacketPlayOutCloseWindow(BukkitLoader.getNmsProvider().getContainerId(container))); + EntityPlayer nmsPlayer = (EntityPlayer) getPlayer(player); + nmsPlayer.cd = nmsPlayer.cc; + ((Container) container).transferTo(nmsPlayer.cd, (CraftPlayer) player); + } + + @Override + public void setSlot(Object container, int slot, Object item) { + ((Container) container).b(slot, (net.minecraft.world.item.ItemStack) item); + } + + @Override + public void setGUITitle(Player player, Object container, String legacy, int size, Component title) { + int id = ((Container) container).j; + BukkitLoader.getPacketHandler().send(player, packetOpenWindow(id, legacy, size, title)); + net.minecraft.world.item.ItemStack carried = ((Container) container).g(); + if (!carried.e()) + BukkitLoader.getPacketHandler().send(player, new PacketPlayOutSetSlot(id, getContainerStateId(container), -1, carried)); + int slot = 0; + for (net.minecraft.world.item.ItemStack item : ((Container) container).c()) { + if (slot == size) + break; + if (!item.e()) + BukkitLoader.getPacketHandler().send(player, new PacketPlayOutSetSlot(id, getContainerStateId(container), slot, item)); + ++slot; + } + } + + @Override + public void openGUI(Player player, Object container, String legacy, int size, Component title) { + EntityPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + int id = ((Container) container).j; + BukkitLoader.getPacketHandler().send(player, packetOpenWindow(id, legacy, size, title)); + nmsPlayer.cd.transferTo((Container) container, (CraftPlayer) player); + nmsPlayer.cd = (Container) container; + postToMainThread(() -> nmsPlayer.a((Container) container)); + ((Container) container).checkReachable = false; + } + + @Override + public void openAnvilGUI(Player player, Object container, Component title) { + openGUI(player, container, "minecraft:anvil", 0, title); + } + + @Override + public Object createContainer(Inventory inv, Player player) { + if (inv.getType() == InventoryType.ANVIL) { + ContainerAnvil container = new ContainerAnvil(((CraftPlayer) player).getHandle().nextContainerCounter(), ((CraftPlayer) player).getHandle().fY(), new ContainerAccess() { + + @Override + public Optional a(BiFunction getter) { + return Optional.empty(); + } + + @Override + public Location getLocation() { + return null; + } + }); + postToMainThread(() -> { + int slot = 0; + for (ItemStack stack : inv.getContents()) + container.b(slot++).d((net.minecraft.world.item.ItemStack) asNMSItem(stack)); + }); + container.checkReachable = false; + return container; + } + return new CraftContainer(inv, ((CraftPlayer) player).getHandle(), ((CraftPlayer) player).getHandle().nextContainerCounter()); + } + + @Override + public Object getSlotItem(Object container, int slot) { + return slot < 0 ? null : ((Container) container).b(slot).g(); + } + + @Override + public String getAnvilRenameText(Object anvil) { + return ((ContainerAnvil) anvil).v; + } + + public static int c(final int quickCraftData) { + return quickCraftData >> 2 & 0x3; + } + + public static int d(final int quickCraftData) { + return quickCraftData & 0x3; + } + + @Override + public boolean processInvClickPacket(Player player, HolderGUI gui, Object provPacket) { + PacketPlayInWindowClick packet = (PacketPlayInWindowClick) provPacket; + int slot = packet.e(); + + Object container = gui.getContainer(player); + if (container == null) + return false; + + int id = packet.b(); + int mouseClick = packet.f(); + InventoryClickType type = packet.i(); + Container c = (Container) container; + + if (slot < -1 && slot != -999) + return true; + + EntityHuman nPlayer = ((CraftPlayer) player).getHandle(); + + ItemStack newItem; + ItemStack oldItem; + switch (type) { + case a: // PICKUP + oldItem = asBukkitItem(getSlotItem(container, slot)); + newItem = asBukkitItem(c.g()); + if (slot > 0 && mouseClick != 0) { + if (c.g().e()) { // pickup half + newItem = oldItem.clone(); + if (oldItem.getAmount() == 1) + newItem = new ItemStack(Material.AIR); + else + newItem.setAmount(Math.max(1, oldItem.getAmount() / 2)); + } else + // drop + if (oldItem.isSimilar(newItem) || oldItem.getType() == Material.AIR) + newItem.setAmount(oldItem.getType() == Material.AIR ? 1 : oldItem.getAmount() + 1); + } else if (slot > 0 && mouseClick == 0) // drop + if (oldItem.isSimilar(newItem)) + newItem.setAmount(Math.min(newItem.getAmount() + oldItem.getAmount(), newItem.getMaxStackSize())); + break; + case b: // QUICK_MOVE + newItem = asBukkitItem(c.g()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case c:// SWAP + newItem = asBukkitItem(nPlayer.fY().a(mouseClick)); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case d:// CLONE + newItem = asBukkitItem(getSlotItem(container, slot)); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case e:// THROW + if (c.g().e() && slot >= 0) { + Slot slot3 = c.b(slot); + newItem = asBukkitItem(slot3.g()); + if (mouseClick != 0 || newItem.getAmount() - 1 <= 0) + newItem = new ItemStack(Material.AIR); + else + newItem.setAmount(newItem.getAmount() - 1); + } else + newItem = asBukkitItem(c.g()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case f:// QUICK_CRAFT + newItem = asBukkitItem(c.g()); + oldItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(getSlotItem(container, slot)); + break; + case g:// PICKUP_ALL + newItem = asBukkitItem(c.g()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + default: + newItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(packet.f()); + oldItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(packet.f()); + break; + } + + if (oldItem.getType() == Material.AIR && newItem.getType() == Material.AIR) + return true; + + boolean cancel = false; + int gameSlot = slot > gui.size() - 1 ? InventoryUtils.convertToPlayerInvSlot(slot - gui.size()) : slot; + + ClickType clickType = InventoryUtils.buildClick(type == InventoryClickType.f ? 1 : type == InventoryClickType.b ? 2 : 0, mouseClick); + if (slot > -1) { + if (!cancel) + cancel = InventoryUtils.useItem(player, gui, slot, clickType); + if (!gui.isInsertable()) + cancel = true; + + if (!cancel) + cancel = gui.onInteractItem(player, newItem, oldItem, clickType, gameSlot, slot < gui.size()); + else + gui.onInteractItem(player, newItem, oldItem, clickType, gameSlot, slot < gui.size()); + } + if (!cancel) { + if (gui instanceof AnvilGUI) { // Event + final ItemStack newItemFinal = newItem; + postToMainThread(() -> { + processEvent(c, type, gui, player, slot, gameSlot, newItemFinal, oldItem, packet, mouseClick, clickType, nPlayer); + }); + } else + processEvent(c, type, gui, player, slot, gameSlot, newItem, oldItem, packet, mouseClick, clickType, nPlayer); + return true; + } + // MOUSE + int statusId = c.j(); + BukkitLoader.getPacketHandler().send(player, packetSetSlot(-1, -1, statusId, c.g())); + switch (type) { + case d: + break; + case c: + case b: + case g: + c.b(); + break; + default: + BukkitLoader.getPacketHandler().send(player, packetSetSlot(id, slot, statusId, c.b(slot).g())); + break; + } + return true; + } + + private void processEvent(Container c, InventoryClickType type, HolderGUI gui, Player player, int slot, int gameSlot, ItemStack newItem, ItemStack oldItem, PacketPlayInWindowClick packet, + int mouseClick, ClickType clickType, EntityHuman nPlayer) { + c.h(); + switch (type) { + case b: { + ItemStack[] contents = slot < gui.size() ? player.getInventory().getStorageContents() : gui.getInventory().getStorageContents(); + boolean interactWithResultSlot = false; + if (gui instanceof AnvilGUI && slot < gui.size() && slot == 2) + if (c.b(2).a(nPlayer)) + interactWithResultSlot = true; + else + return; + Pair result = slot < gui.size() + ? InventoryUtils.shift(slot, player, gui, clickType, gui instanceof AnvilGUI && slot != 2 ? DestinationType.PLAYER_FROM_ANVIL : DestinationType.PLAYER, null, contents, oldItem) + : InventoryUtils.shift(slot, player, gui, clickType, DestinationType.GUI, gui.getNotInterableSlots(player), contents, oldItem); + @SuppressWarnings("unchecked") + Map modified = (Map) result.getValue(); + int remaining = (int) result.getKey(); + + if (!modified.isEmpty()) + if (slot < gui.size()) { + for (Entry modif : modified.entrySet()) + nPlayer.fY().a(modif.getKey(), (net.minecraft.world.item.ItemStack) asNMSItem(modif.getValue())); + if (remaining == 0) { + c.b(gameSlot).d((net.minecraft.world.item.ItemStack) asNMSItem(null)); + if (interactWithResultSlot) { + c.b(0).d((net.minecraft.world.item.ItemStack) asNMSItem(null)); + c.b(1).d((net.minecraft.world.item.ItemStack) asNMSItem(null)); + } + } else { + newItem.setAmount(remaining); + c.b(gameSlot).d((net.minecraft.world.item.ItemStack) asNMSItem(newItem)); + } + } else { + for (Entry modif : modified.entrySet()) + c.b(modif.getKey()).d((net.minecraft.world.item.ItemStack) asNMSItem(modif.getValue())); // Visual & Nms side + // Plugin & Bukkit side + gui.getInventory().setStorageContents(contents); + if (remaining == 0) + nPlayer.fY().a(gameSlot, (net.minecraft.world.item.ItemStack) asNMSItem(null)); + else { + newItem.setAmount(remaining); + nPlayer.fY().a(gameSlot, (net.minecraft.world.item.ItemStack) asNMSItem(newItem)); + } + } + c.i(); + return; + } + default: + processClick(gui, gui.getNotInterableSlots(player), c, slot, mouseClick, type, nPlayer); + break; + } + postToMainThread(() -> { + if (type != InventoryClickType.f && (c.a().equals(Containers.i) || c.a().equals(Containers.v))) + c.b(); + for (final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry entry : Int2ObjectMaps.fastIterable(packet.h())) + c.b(entry.getIntKey(), entry.getValue()); + c.a(packet.g()); + c.i(); + if (packet.j() != c.j()) + c.e(); + else + c.d(); + }); + } + + private Method addAmount = Ref.method(Slot.class, "b", int.class); + private Method checkItem = Ref.method(Container.class, "a", EntityHuman.class, ClickAction.class, Slot.class, net.minecraft.world.item.ItemStack.class, net.minecraft.world.item.ItemStack.class); + + @SuppressWarnings("unchecked") + private void processClick(HolderGUI gui, List ignoredSlots, Container container, int slotIndex, int button, InventoryClickType actionType, EntityHuman player) { + if (actionType == InventoryClickType.f) + processDragMove(gui, container, player, slotIndex, button); + else { + int u = (int) Ref.get(container, containerU); + int j = getContainerStateId(container); + Set mod = (Set) Ref.get(container, containerV); + if (u != 0) { + Ref.set(container, containerU, u = 0); + mod.clear(); + } else if (actionType == InventoryClickType.a && (button == 0 || button == 1)) { + ClickAction clickaction = button == 0 ? ClickAction.a : ClickAction.b; + if (slotIndex == -999) { + if (!container.g().e()) + if (clickaction == ClickAction.a) { + net.minecraft.world.item.ItemStack carried = container.g(); + container.b(net.minecraft.world.item.ItemStack.l); + postToMainThread(() -> player.a(carried, true)); + } else + postToMainThread(() -> player.a(container.g().a(1), true)); + } else { + if (slotIndex < 0) + return; + Slot slot = container.b(slotIndex); + net.minecraft.world.item.ItemStack itemstack = slot.g(); + net.minecraft.world.item.ItemStack itemstack4 = container.g(); + player.a(itemstack4, slot.g(), clickaction); + if (!(boolean) Ref.invoke(container, checkItem, player, clickaction, slot, itemstack, itemstack4)) + if (itemstack.e()) { + if (!itemstack4.e()) { + int i2 = clickaction == ClickAction.a ? itemstack4.H() : 1; + net.minecraft.world.item.ItemStack stack = slot.b(itemstack4, i2); + container.b(stack); + } + } else if (slot.a(player)) + if (itemstack4.e()) { + int i2 = clickaction == ClickAction.a ? itemstack.H() : (itemstack.H() + 1) / 2; + Optional optional = slot.a(i2, 2147483647, player); + optional.ifPresent(i -> { + container.b(i); + slot.a(player, i); + }); + } else if (slot.a(itemstack4)) { + if (net.minecraft.world.item.ItemStack.c(itemstack, itemstack4)) { + int i2 = clickaction == ClickAction.a ? itemstack4.H() : 1; + net.minecraft.world.item.ItemStack stack = slot.b(itemstack4, i2); + container.b(stack); + } else if (itemstack4.H() <= slot.a_(itemstack4)) { + container.b(itemstack); + slot.d(itemstack4); + } + } else if (net.minecraft.world.item.ItemStack.c(itemstack, itemstack4)) { + Optional optional2 = slot.a(itemstack.H(), itemstack4.j() - itemstack4.H(), player); + optional2.ifPresent(i -> { + itemstack.g(i.H()); + slot.a(player, i); + }); + } + slot.b(); + if (player instanceof EntityPlayer && slot.a() != 64) { + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), BukkitLoader.getNmsProvider().packetSetSlot(j, slot.d, container.k(), slot.g())); + if (container.getBukkitView().getType() == InventoryType.WORKBENCH || container.getBukkitView().getType() == InventoryType.CRAFTING) + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), BukkitLoader.getNmsProvider().packetSetSlot(j, 0, container.k(), container.b(0).g())); + } + } + } else if (actionType == InventoryClickType.c) { + if (slotIndex < 0) + return; + PlayerInventory playerinventory = player.fY(); + Slot slot3 = container.b(slotIndex); + net.minecraft.world.item.ItemStack itemstack2 = playerinventory.a(button); + net.minecraft.world.item.ItemStack itemstack = slot3.g(); + if (!itemstack2.e() || !itemstack.e()) + if (itemstack2.e()) { + if (slot3.a(player)) { + playerinventory.a(button, itemstack); + Ref.invoke(slot3, addAmount, itemstack.H()); + slot3.d(net.minecraft.world.item.ItemStack.l); + slot3.a(player, itemstack); + } + } else if (itemstack.e()) { + if (slot3.a(itemstack2)) { + int j2 = slot3.a_(itemstack2); + if (itemstack2.H() > j2) + slot3.d(itemstack2.a(j2)); + else { + playerinventory.a(button, net.minecraft.world.item.ItemStack.l); + slot3.d(itemstack2); + } + } + } else if (slot3.a(player) && slot3.a(itemstack2)) { + int j2 = slot3.a_(itemstack2); + if (itemstack2.H() > j2) { + slot3.d(itemstack2.a(j2)); + slot3.a(player, itemstack); + if (!playerinventory.f(itemstack)) + postToMainThread(() -> player.a(itemstack, true)); + } else { + playerinventory.a(button, itemstack); + slot3.d(itemstack2); + slot3.a(player, itemstack); + } + } + } else if (actionType == InventoryClickType.d && player.fZ().d && container.g().e() && slotIndex >= 0) { + Slot slot3 = container.b(slotIndex); + if (slot3.h()) { + net.minecraft.world.item.ItemStack itemstack2 = slot3.g(); + container.b(itemstack2.c(itemstack2.j())); + } + } else if (actionType == InventoryClickType.e && container.g().e() && slotIndex >= 0) { + Slot slot3 = container.b(slotIndex); + int m = button == 0 ? 1 : slot3.g().H(); + net.minecraft.world.item.ItemStack itemstack = slot3.b(m, 2147483647, player); + postToMainThread(() -> player.a(itemstack, true)); + } else if (actionType == InventoryClickType.g && slotIndex >= 0) { + final Slot slot3 = container.i.get(slotIndex); + final net.minecraft.world.item.ItemStack itemstack2 = container.g(); + if (!itemstack2.e() && (!slot3.h() || !slot3.a(player))) { + List ignoreSlots = ignoredSlots == null ? Collections.emptyList() : ignoredSlots; + List corruptedSlots = ignoredSlots == null ? Collections.emptyList() : new ArrayList<>(); + Map modifiedSlots = new HashMap<>(); + Map modifiedSlotsPlayerInv = new HashMap<>(); + final int l = button == 0 ? 0 : container.i.size() - 1; + final int j2 = button == 0 ? 1 : -1; + for (int i2 = 0; i2 < 2; ++i2) + for (int slot = l; slot >= 0 && slot < container.i.size() && itemstack2.H() < itemstack2.j(); slot += j2) { + final Slot slot4 = container.i.get(slot); + if (slot4.h() && Container.a(slot4, itemstack2, true) && slot4.a(player) && container.a(itemstack2, slot4)) { + final net.minecraft.world.item.ItemStack itemstack5 = slot4.g(); + if (i2 != 0 || itemstack5.H() != itemstack5.j()) { + if (slot < gui.size() && ignoreSlots.contains(slot)) { + corruptedSlots.add(slot); + continue; + } + final net.minecraft.world.item.ItemStack itemstack6 = slot4.b(itemstack5.H(), itemstack2.j() - itemstack2.H(), player); + itemstack2.g(itemstack6.H()); + int gameSlot = slot > gui.size() - 1 ? InventoryUtils.convertToPlayerInvSlot(slot - gui.size()) : slot; + if (slot < gui.size()) + modifiedSlots.put(gameSlot, asBukkitItem(slot4.g())); + else + modifiedSlotsPlayerInv.put(gameSlot, asBukkitItem(slot4.g())); + } + } + } + if (slotIndex < gui.size()) + modifiedSlots.put(slotIndex, new ItemStack(Material.AIR)); + else + modifiedSlotsPlayerInv.put(InventoryUtils.convertToPlayerInvSlot(slotIndex - gui.size()), new ItemStack(Material.AIR)); + if (!modifiedSlots.isEmpty() || !modifiedSlotsPlayerInv.isEmpty()) + gui.onMultipleIteract((Player) player.getBukkitEntity(), modifiedSlots, modifiedSlotsPlayerInv); + for (int s : corruptedSlots) + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), BukkitLoader.getNmsProvider().packetSetSlot(BukkitLoader.getNmsProvider().getContainerId(container), s, + getContainerStateId(container), BukkitLoader.getNmsProvider().getSlotItem(container, s))); + } + } + } + } + + private Field containerU = Ref.field(Container.class, "u"), containerV = Ref.field(Container.class, "v"), containerT = Ref.field(Container.class, "t"); + + @SuppressWarnings("unchecked") + private void processDragMove(HolderGUI gui, Container container, EntityHuman player, int slot, int mouseClick) { + int previous = (int) Ref.get(container, containerU); + int u = d(mouseClick); + Set mod = (Set) Ref.get(container, containerV); + if ((previous != 1 || u != 2) && previous != u || container.g().e()) { + mod.clear(); + u = 0; + } else + switch (u) { + case 0: { + int t = c(mouseClick); + Ref.set(container, containerT, t); + if (Container.a(t, player)) { + u = 1; + mod.clear(); + } else { + mod.clear(); + u = 0; + } + break; + } + case 1: { + if (slot < 0) { + Ref.set(container, containerU, u); + return; // nothing + } + int t = (int) Ref.get(container, containerT); + final Slot bslot = container.b(slot); + final net.minecraft.world.item.ItemStack itemstack = container.g(); + if (Container.a(bslot, itemstack, true) && bslot.a(itemstack) && (t == 2 || itemstack.H() > mod.size()) && container.b(bslot)) + mod.add(bslot); + break; + } + case 2: + if (!mod.isEmpty()) { + final net.minecraft.world.item.ItemStack itemstack2 = container.g().s(); + if (itemstack2.e()) { + mod.clear(); + Ref.set(container, containerU, 0); + return; + } + int t = (int) Ref.get(container, containerT); + int l = container.g().H(); + final Map draggedSlots = new HashMap<>(); + for (Slot slot2 : mod) { + final net.minecraft.world.item.ItemStack itemstack3 = container.g(); + if (slot2 != null && Container.a(slot2, itemstack3, true) && slot2.a(itemstack3) && (t == 2 || itemstack3.H() >= mod.size()) && container.b(slot2)) { + final int j1 = slot2.h() ? slot2.g().H() : 0; + final int k1 = Math.min(itemstack2.j(), slot2.a_(itemstack2)); + final int l2 = Math.min(Container.a(mod, t, itemstack2) + j1, k1); + l -= l2 - j1; + draggedSlots.put(slot2.d, itemstack2.c(l2)); + } + } + final InventoryView view = container.getBukkitView(); + final org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack2); + newcursor.setAmount(l); + final Map guiSlots = new HashMap<>(); + final Map playerSlots = new HashMap<>(); + for (final Entry ditem : draggedSlots.entrySet()) + if (ditem.getKey() < gui.size()) + guiSlots.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue())); + else { + int finalSlot = ditem.getKey() - gui.size(); + if (finalSlot >= 27) + finalSlot -= 27; + else + finalSlot += 9; + playerSlots.put(finalSlot, CraftItemStack.asBukkitCopy(ditem.getValue())); + } + container.b(CraftItemStack.asNMSCopy(newcursor)); + if (!guiSlots.isEmpty() || !playerSlots.isEmpty()) + gui.onMultipleIteract((Player) player.getBukkitEntity(), guiSlots, playerSlots); + for (final Entry dslot : draggedSlots.entrySet()) + view.setItem(dslot.getKey(), CraftItemStack.asBukkitCopy(dslot.getValue())); + if (container.g() != null) + container.b(); + } + mod.clear(); + u = 0; + default: + mod.clear(); + u = 0; + break; + } + Ref.set(container, containerU, u); + } + + @Override + public boolean processServerListPing(String player, Object channel, Object packet) { + if (packet instanceof PacketContainer) { + PacketContainer container = (PacketContainer) packet; + PacketStatusOutServerInfo status = (PacketStatusOutServerInfo) container.getPacket(); + ServerPing ping = status.b(); + + List gameProfiles = new ArrayList<>(); + for (GameProfile profile : ping.b().get().c()) + gameProfiles.add(fromGameProfile(profile)); + + IChatBaseComponent motd = IChatBaseComponent.a(""); + Optional players = Optional.empty(); + Optional onlineCount = Optional.empty(); + Optional serverIcon = Optional.empty(); + boolean enforceSecureProfile = ping.e(); + + String favicon = "server-icon.png"; + ServerListPingEvent event = new ServerListPingEvent(getOnlinePlayers().size(), Bukkit.getMaxPlayers(), gameProfiles, Bukkit.getMotd(), favicon, + ((InetSocketAddress) ((Channel) channel).remoteAddress()).getAddress(), ping.c().get().b(), ping.c().get().c()); + EventManager.call(event); + if (event.isCancelled()) { + container.setCancelled(true); + return true; + } + ServerPingPlayerSample playerSample = new ServerPingPlayerSample(event.getMaxPlayers(), event.getOnlinePlayers(), new ArrayList<>()); + if (event.getSlots() != null) + for (GameProfileHandler s : event.getSlots()) + playerSample.c().add(new GameProfile(s.getUUID(), s.getUsername())); + players = Optional.of(playerSample); + + if (event.getMotd() != null) + motd = (IChatBaseComponent) this.toIChatBaseComponent(ComponentAPI.fromString(event.getMotd())); + if (event.getVersion() != null) + onlineCount = Optional.of(new ServerData(event.getVersion(), event.getProtocol())); + if (event.getFavicon() != null) + if (!event.getFavicon().equals("server-icon.png") && new File(event.getFavicon()).exists()) { + BufferedImage var1; + try { + var1 = ImageIO.read(new File(event.getFavicon())); + Preconditions.checkState(var1.getWidth() == 64, "Must be 64 pixels wide"); + Preconditions.checkState(var1.getHeight() == 64, "Must be 64 pixels high"); + ByteArrayOutputStream var2 = new ByteArrayOutputStream(); + ImageIO.write(var1, "PNG", var2); + serverIcon = Optional.of(new ServerPing.a(var2.toByteArray())); + } catch (IOException e) { + e.printStackTrace(); + } + } else + serverIcon = ping.d(); + container.setPacket(new PacketStatusOutServerInfo(new ServerPing(motd, players, onlineCount, serverIcon, enforceSecureProfile))); + return false; + } + JavaPlugin.getPlugin(BukkitLoader.class).getLogger().warning("You are using outdated version of TheAPI, please update TheAPI to the latest version!"); + return false; + } + + @Override + public Object getNBT(Entity entity) { + return ((CraftEntity) entity).getHandle().f(new NBTTagCompound()); + } + + @Override + public Object setString(Object nbt, String path, String value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setInteger(Object nbt, String path, int value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setDouble(Object nbt, String path, double value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setLong(Object nbt, String path, long value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setShort(Object nbt, String path, short value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setFloat(Object nbt, String path, float value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setBoolean(Object nbt, String path, boolean value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setIntArray(Object nbt, String path, int[] value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setByteArray(Object nbt, String path, byte[] value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public Object setNBTBase(Object nbt, String path, Object value) { + ((NBTTagCompound) nbt).a(path, (NBTBase) value); + return nbt; + } + + @Override + public String getString(Object nbt, String path) { + return ((NBTTagCompound) nbt).l(path); + } + + @Override + public int getInteger(Object nbt, String path) { + return ((NBTTagCompound) nbt).h(path); + } + + @Override + public double getDouble(Object nbt, String path) { + return ((NBTTagCompound) nbt).i(path); + } + + @Override + public long getLong(Object nbt, String path) { + return ((NBTTagCompound) nbt).i(path); + } + + @Override + public short getShort(Object nbt, String path) { + return ((NBTTagCompound) nbt).g(path); + } + + @Override + public float getFloat(Object nbt, String path) { + return ((NBTTagCompound) nbt).j(path); + } + + @Override + public boolean getBoolean(Object nbt, String path) { + return ((NBTTagCompound) nbt).e(path); + } + + @Override + public int[] getIntArray(Object nbt, String path) { + return ((NBTTagCompound) nbt).n(path); + } + + @Override + public byte[] getByteArray(Object nbt, String path) { + return ((NBTTagCompound) nbt).m(path); + } + + @Override + public Object getNBTBase(Object nbt, String path) { + return ((NBTTagCompound) nbt).c(path); + } + + @Override + public Set getKeys(Object nbt) { + return ((NBTTagCompound) nbt).e(); + } + + @Override + public boolean hasKey(Object nbt, String path) { + return ((NBTTagCompound) nbt).e(path); + } + + @Override + public void removeKey(Object nbt, String path) { + ((NBTTagCompound) nbt).r(path); + } + + @Override + public Object setByte(Object nbt, String path, byte value) { + ((NBTTagCompound) nbt).a(path, value); + return nbt; + } + + @Override + public byte getByte(Object nbt, String path) { + return ((NBTTagCompound) nbt).f(path); + } + + @Override + public Object getDataWatcher(Entity entity) { + return ((CraftEntity) entity).getHandle().ar(); + } + + @Override + public Object getDataWatcher(Object entity) { + return ((net.minecraft.world.entity.Entity) entity).ar(); + } + + @Override + public int incrementStateId(Object container) { + return ((Container) container).k(); + } + + @Override + public Object packetEntityHeadRotation(Entity entity) { + return new PacketPlayOutEntityHeadRotation((net.minecraft.world.entity.Entity) getEntity(entity), (byte) (entity.getLocation().getYaw() * 256F / 360F)); + } + + @Override + public Object packetHeldItemSlot(int slot) { + return new PacketPlayOutHeldItemSlot(slot); + } + + @Override + public Object packetExp(float exp, int total, int toNextLevel) { + return new PacketPlayOutExperience(exp, total, toNextLevel); + } + + @Override + public Object packetPlayerInfo(PlayerInfoType type, Player player) { + a action = null; + switch (type) { + case ADD_PLAYER: + action = a.a; + break; + case REMOVE_PLAYER: + return new ClientboundPlayerInfoRemovePacket(Arrays.asList(player.getUniqueId())); + case UPDATE_DISPLAY_NAME: + action = a.f; + break; + case UPDATE_GAME_MODE: + action = a.c; + break; + case UPDATE_LATENCY: + action = a.e; + break; + } + return new ClientboundPlayerInfoUpdatePacket(action, (EntityPlayer) getPlayer(player)); + } + + static Field setField, listField; + static Constructor clientboundConstructor; + + static { + setField = Ref.field(ClientboundPlayerInfoUpdatePacket.class, "b"); + listField = Ref.field(ClientboundPlayerInfoUpdatePacket.class, "c"); + } + + @Override + public Object packetPlayerInfo(PlayerInfoType type, GameProfileHandler gameProfile, int latency, GameMode gameMode, Component playerName) { + a action = null; + switch (type) { + case ADD_PLAYER: + action = a.a; + break; + case REMOVE_PLAYER: + return new ClientboundPlayerInfoRemovePacket(Arrays.asList(gameProfile.getUUID())); + case UPDATE_DISPLAY_NAME: + action = a.f; + break; + case UPDATE_GAME_MODE: + action = a.c; + break; + case UPDATE_LATENCY: + action = a.e; + break; + } + EnumSet set = EnumSet.of(action); + List list = Arrays.asList(new ClientboundPlayerInfoUpdatePacket.b(gameProfile.getUUID(), (GameProfile) toGameProfile(gameProfile), true, latency, + gameMode == null ? EnumGamemode.a : EnumGamemode.a(gameMode.name().toLowerCase()), + (IChatBaseComponent) (playerName == null ? toIChatBaseComponent(new Component(gameProfile.getUsername())) : toIChatBaseComponent(playerName)), null)); + ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) Ref.newUnsafeInstance(ClientboundPlayerInfoUpdatePacket.class); + Ref.set(packet, setField, set); + Ref.set(packet, listField, list); + return packet; + } + + @Override + public Object packetPosition(double x, double y, double z, float yaw, float pitch) { + return new PacketPlayOutPosition(x, y, z, yaw, pitch, Collections.emptySet(), 0); + } + + @Override + public Object packetRespawn(Player player) { + EntityPlayer entityPlayer = (EntityPlayer) getPlayer(player); + + return new PacketPlayOutRespawn(entityPlayer.b(entityPlayer.A()), (byte) 1); + } + + @Override + public String getProviderName() { + return "1_21_R1 (1.21)"; + } + + @Override + public int getContainerStateId(Object container) { + return ((Container) container).j(); + } + + @Override + public void loadParticles() { + for (Entry>, Particle> s : BuiltInRegistries.i.h()) + me.devtec.theapi.bukkit.game.particles.Particle.identifier.put(s.getKey().a().a(), s.getValue()); + } + + @Override + public Object toGameProfile(GameProfileHandler gameProfileHandler) { + GameProfile profile = new GameProfile(gameProfileHandler.getUUID(), gameProfileHandler.getUsername()); + for (Entry entry : gameProfileHandler.getProperties().entrySet()) + profile.getProperties().put(entry.getKey(), new Property(entry.getValue().getName(), entry.getValue().getValues(), entry.getValue().getSignature())); + return profile; + } + + private Field name = Ref.field(Property.class, "name"), value = Ref.field(Property.class, "value"), signature = Ref.field(Property.class, "signature"); + + @Override + public GameProfileHandler fromGameProfile(Object gameProfile) { + GameProfile profile = (GameProfile) gameProfile; + GameProfileHandler handler = GameProfileHandler.of(profile.getName(), profile.getId()); + for (Entry entry : profile.getProperties().entries()) + handler.getProperties().put(entry.getKey(), + PropertyHandler.of((String) Ref.get(entry.getValue(), name), (String) Ref.get(entry.getValue(), value), (String) Ref.get(entry.getValue(), signature))); + return handler; + } + + @Override + public Object getGameProfile(Object nmsPlayer) { + return ((EntityPlayer) nmsPlayer).fX(); + } + +} diff --git a/NmsProvider - 1.21.R1/v1_21_R1.jar b/NmsProvider - 1.21.R1/v1_21_R1.jar new file mode 100644 index 00000000..d6160362 Binary files /dev/null and b/NmsProvider - 1.21.R1/v1_21_R1.jar differ diff --git a/NmsProvider - 1.21/.classpath b/NmsProvider - 1.21/.classpath new file mode 100644 index 00000000..6693843a --- /dev/null +++ b/NmsProvider - 1.21/.classpath @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/NmsProvider - 1.21/src/me/devtec/theapi/bukkit/nms/v1_21.java b/NmsProvider - 1.21/src/me/devtec/theapi/bukkit/nms/v1_21.java new file mode 100644 index 00000000..983dcf8b --- /dev/null +++ b/NmsProvider - 1.21/src/me/devtec/theapi/bukkit/nms/v1_21.java @@ -0,0 +1,1746 @@ +package me.devtec.theapi.bukkit.nms; + +import java.awt.image.BufferedImage; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.InetSocketAddress; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +import javax.imageio.ImageIO; + +import org.bukkit.Bukkit; +import org.bukkit.Chunk; +import org.bukkit.GameMode; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.BlockState; +import org.bukkit.craftbukkit.CraftChunk; +import org.bukkit.craftbukkit.CraftWorld; +import org.bukkit.craftbukkit.block.data.CraftBlockData; +import org.bukkit.craftbukkit.entity.CraftEntity; +import org.bukkit.craftbukkit.entity.CraftLivingEntity; +import org.bukkit.craftbukkit.entity.CraftPlayer; +import org.bukkit.craftbukkit.inventory.CraftContainer; +import org.bukkit.craftbukkit.inventory.CraftItemStack; +import org.bukkit.craftbukkit.util.CraftMagicNumbers; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.InventoryType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryView; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; + +import com.google.common.base.Preconditions; +import com.mojang.authlib.GameProfile; +import com.mojang.authlib.properties.Property; + +import io.netty.channel.Channel; +import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; +import me.devtec.shared.Pair; +import me.devtec.shared.Ref; +import me.devtec.shared.components.ClickEvent; +import me.devtec.shared.components.Component; +import me.devtec.shared.components.ComponentAPI; +import me.devtec.shared.components.ComponentEntity; +import me.devtec.shared.components.ComponentItem; +import me.devtec.shared.components.HoverEvent; +import me.devtec.shared.events.EventManager; +import me.devtec.shared.json.Json; +import me.devtec.shared.utility.ParseUtils; +import me.devtec.theapi.bukkit.BukkitLoader; +import me.devtec.theapi.bukkit.events.ServerListPingEvent; +import me.devtec.theapi.bukkit.game.BlockDataStorage; +import me.devtec.theapi.bukkit.gui.AnvilGUI; +import me.devtec.theapi.bukkit.gui.GUI.ClickType; +import me.devtec.theapi.bukkit.gui.HolderGUI; +import me.devtec.theapi.bukkit.nms.GameProfileHandler.PropertyHandler; +import me.devtec.theapi.bukkit.nms.utils.InventoryUtils; +import me.devtec.theapi.bukkit.nms.utils.InventoryUtils.DestinationType; +import me.devtec.theapi.bukkit.packetlistener.PacketContainer; +import me.devtec.theapi.bukkit.xseries.XMaterial; +import net.minecraft.ChatFormatting; +import net.minecraft.commands.CommandBuildContext; +import net.minecraft.commands.Commands; +import net.minecraft.core.BlockPos; +import net.minecraft.core.component.DataComponents; +import net.minecraft.core.particles.ParticleType; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.data.registries.VanillaRegistries; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.nbt.TagParser; +import net.minecraft.network.Connection; +import net.minecraft.network.chat.HoverEvent.EntityTooltipInfo; +import net.minecraft.network.chat.HoverEvent.ItemStackInfo; +import net.minecraft.network.chat.MutableComponent; +import net.minecraft.network.chat.Style; +import net.minecraft.network.chat.TextColor; +import net.minecraft.network.protocol.common.ClientboundResourcePackPushPacket; +import net.minecraft.network.protocol.game.ClientboundAddEntityPacket; +import net.minecraft.network.protocol.game.ClientboundBlockUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundClearTitlesPacket; +import net.minecraft.network.protocol.game.ClientboundContainerClosePacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoRemovePacket; +import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket; +import net.minecraft.network.protocol.game.ClientboundRemoveEntitiesPacket; +import net.minecraft.network.protocol.game.ClientboundRespawnPacket; +import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket; +import net.minecraft.network.protocol.game.ClientboundSetActionBarTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetCarriedItemPacket; +import net.minecraft.network.protocol.game.ClientboundSetDisplayObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetEntityDataPacket; +import net.minecraft.network.protocol.game.ClientboundSetExperiencePacket; +import net.minecraft.network.protocol.game.ClientboundSetObjectivePacket; +import net.minecraft.network.protocol.game.ClientboundSetPlayerTeamPacket; +import net.minecraft.network.protocol.game.ClientboundSetScorePacket; +import net.minecraft.network.protocol.game.ClientboundSetSubtitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitleTextPacket; +import net.minecraft.network.protocol.game.ClientboundSetTitlesAnimationPacket; +import net.minecraft.network.protocol.game.ClientboundSystemChatPacket; +import net.minecraft.network.protocol.game.ClientboundTabListPacket; +import net.minecraft.network.protocol.game.ServerboundContainerClickPacket; +import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket; +import net.minecraft.network.protocol.status.ClientboundStatusResponsePacket; +import net.minecraft.network.protocol.status.ServerStatus; +import net.minecraft.network.protocol.status.ServerStatus.Favicon; +import net.minecraft.network.protocol.status.ServerStatus.Players; +import net.minecraft.network.protocol.status.ServerStatus.Version; +import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.resources.ResourceKey; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerCommonPacketListenerImpl; +import net.minecraft.server.network.ServerGamePacketListenerImpl; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.AnvilMenu; +import net.minecraft.world.inventory.ClickAction; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.component.CustomData; +import net.minecraft.world.level.GameType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.EntityBlock; +import net.minecraft.world.level.block.FallingBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.StateHolder; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunk.EntityCreationType; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.level.chunk.status.ChunkStatus; +import net.minecraft.world.scores.DisplaySlot; +import net.minecraft.world.scores.Objective; +import net.minecraft.world.scores.criteria.ObjectiveCriteria; + +public class v1_21 implements NmsProvider { + private static final MinecraftServer server = MinecraftServer.getServer(); + private static final net.minecraft.network.chat.Component empty = net.minecraft.network.chat.Component.literal(""); + private static final CommandBuildContext dispatcher = Commands.createValidationContext(VanillaRegistries.createLookup()); + + @Override + public Collection getOnlinePlayers() { + return Bukkit.getOnlinePlayers(); + } + + @Override + public Object getEntity(Entity entity) { + return ((CraftEntity) entity).getHandle(); + } + + @Override + public Object getEntityLiving(LivingEntity entity) { + return ((CraftLivingEntity) entity).getHandle(); + } + + @Override + public Object getPlayer(Player player) { + return ((CraftPlayer) player).getHandle(); + } + + @Override + public Object getWorld(World world) { + return ((CraftWorld) world).getHandle(); + } + + @Override + public Object getChunk(Chunk chunk) { + return ((CraftChunk) chunk).getHandle(ChunkStatus.FULL); + } + + @Override + public int getEntityId(Object entity) { + return ((net.minecraft.world.entity.Entity) entity).getId(); + } + + @Override + public Object getScoreboardAction(Action type) { + return type == Action.CHANGE ? ClientboundSetPlayerTeamPacket.Action.ADD : ClientboundSetPlayerTeamPacket.Action.REMOVE; + } + + @Override + public Object getEnumScoreboardHealthDisplay(DisplayType type) { + return type == DisplayType.INTEGER ? ObjectiveCriteria.RenderType.INTEGER : ObjectiveCriteria.RenderType.HEARTS; + } + + @Override + public Object getNBT(ItemStack itemStack) { + net.minecraft.world.item.ItemStack item = (net.minecraft.world.item.ItemStack) asNMSItem(itemStack); + if (item.isEmpty()) + return new CompoundTag(); + CustomData data = item.get(DataComponents.CUSTOM_DATA); + if (data != null) + return data.copyTag(); + return null; + } + + @Override + public Object parseNBT(String json) { + if (json == null) + return new CompoundTag(); + try { + return TagParser.parseTag(json); + } catch (Exception e) { + return new CompoundTag(); + } + } + + @Override + public ItemStack setNBT(ItemStack stack, Object nbt) { + if (nbt instanceof NBTEdit) + nbt = ((NBTEdit) nbt).getNBT(); + net.minecraft.world.item.ItemStack item = (net.minecraft.world.item.ItemStack) asNMSItem(stack); + item.set(DataComponents.CUSTOM_DATA, CustomData.of((CompoundTag) nbt)); + return asBukkitItem(item); + } + + @Override + public Object asNMSItem(ItemStack stack) { + if (stack == null) + return net.minecraft.world.item.ItemStack.EMPTY; + return CraftItemStack.asNMSCopy(stack); + } + + @Override + public ItemStack asBukkitItem(Object stack) { + return CraftItemStack.asBukkitCopy(stack == null ? net.minecraft.world.item.ItemStack.EMPTY : (net.minecraft.world.item.ItemStack) stack); + } + + @Override + public int getContainerId(Object container) { + return ((AbstractContainerMenu) container).containerId; + } + + @Override + public Object packetResourcePackSend(String url, String hash, boolean requireRP, Component prompt) { + return new ClientboundResourcePackPushPacket(UUID.randomUUID(), url, hash, requireRP, + prompt == null ? null : prompt == null ? Optional.empty() : Optional.of((net.minecraft.network.chat.Component) this.toIChatBaseComponent(prompt))); + } + + @Override + public Object packetSetSlot(int container, int slot, int changeId, Object itemStack) { + return new ClientboundContainerSetSlotPacket(container, changeId, slot, (net.minecraft.world.item.ItemStack) (itemStack == null ? asNMSItem(null) : itemStack)); + } + + @Override + public Object packetEntityMetadata(int entityId, Object dataWatcher, boolean bal) { + return new ClientboundSetEntityDataPacket(entityId, ((SynchedEntityData) dataWatcher).packAll()); + } + + @Override + public Object packetEntityDestroy(int... ids) { + return new ClientboundRemoveEntitiesPacket(ids); + } + + @Override + public Object packetSpawnEntity(Object entity, int id) { + return new ClientboundAddEntityPacket((net.minecraft.world.entity.Entity) entity, id); + } + + @Override + public Object packetNamedEntitySpawn(Object player) { + return new ClientboundAddEntityPacket((net.minecraft.world.entity.player.Player) player); + } + + @Override + public Object packetSpawnEntityLiving(Object entityLiving) { + return new ClientboundAddEntityPacket((net.minecraft.world.entity.LivingEntity) entityLiving); + } + + @Override + public Object packetPlayerListHeaderFooter(Component header, Component footer) { + return new ClientboundTabListPacket((net.minecraft.network.chat.Component) toIChatBaseComponent(header), (net.minecraft.network.chat.Component) this.toIChatBaseComponent(footer)); + } + + @Override + public Object packetBlockChange(int x, int y, int z, Object iblockdata, int data) { + return new ClientboundBlockUpdatePacket(new BlockPos(x, y, z), iblockdata == null ? Blocks.AIR.defaultBlockState() : (net.minecraft.world.level.block.state.BlockState) iblockdata); + } + + @Override + public Object packetScoreboardObjective() { + return Ref.newUnsafeInstance(ClientboundSetObjectivePacket.class); + } + + @Override + public Object packetScoreboardDisplayObjective(int id, Object scoreboardObjective) { + return new ClientboundSetDisplayObjectivePacket(DisplaySlot.values()[id], scoreboardObjective == null ? null : (Objective) scoreboardObjective); + } + + @Override + public Object packetScoreboardTeam() { + return Ref.newUnsafeInstance(ClientboundSetPlayerTeamPacket.class); + } + + @Override + public Object packetScoreboardScore(Action action, String player, String line, int score) { + return new ClientboundSetScorePacket(line, player, score, Optional.ofNullable(null), Optional.ofNullable(null)); + } + + @Override + public Object packetTitle(TitleAction action, Component text, int fadeIn, int stay, int fadeOut) { + switch (action) { + case ACTIONBAR: + return new ClientboundSetActionBarTextPacket((net.minecraft.network.chat.Component) this.toIChatBaseComponent(text)); + case TITLE: + return new ClientboundSetTitleTextPacket((net.minecraft.network.chat.Component) this.toIChatBaseComponent(text)); + case SUBTITLE: + return new ClientboundSetSubtitleTextPacket((net.minecraft.network.chat.Component) this.toIChatBaseComponent(text)); + case TIMES: + return new ClientboundSetTitlesAnimationPacket(fadeIn, stay, fadeOut); + case CLEAR: + case RESET: + return new ClientboundClearTitlesPacket(true); + } + return null; + } + + @Override + public Object packetChat(ChatType type, Object chatBase, UUID uuid) { + return new ClientboundSystemChatPacket((net.minecraft.network.chat.Component) chatBase, false); + } + + @Override + public Object packetChat(ChatType type, Component text, UUID uuid) { + return new ClientboundSystemChatPacket((net.minecraft.network.chat.Component) this.toIChatBaseComponent(text), false); + } + + @Override + public void postToMainThread(Runnable runnable) { + v1_21.server.execute(runnable); + } + + @Override + public Object getMinecraftServer() { + return v1_21.server; + } + + @Override + public Thread getServerThread() { + return v1_21.server.serverThread; + } + + @SuppressWarnings("removal") + @Override + public double[] getServerTPS() { + return v1_21.server.recentTps; + } + + private net.minecraft.network.chat.Component convert(Component c) { + if (c instanceof ComponentItem || c instanceof ComponentEntity) + return net.minecraft.network.chat.Component.Serializer.fromJson(Json.writer().simpleWrite(c.toJsonMap()), dispatcher); + MutableComponent current = net.minecraft.network.chat.Component.literal(c.getText()); + Style modif = current.getStyle(); + if (c.getColor() != null && !c.getColor().isEmpty()) + if (c.getColor().startsWith("#")) + modif = modif.withColor(TextColor.fromRgb(Integer.decode(c.getColor()))); + else + modif = modif.withColor(ChatFormatting.getByCode(c.colorToChar())); + if (c.getClickEvent() != null) + modif = modif.withClickEvent( + new net.minecraft.network.chat.ClickEvent(net.minecraft.network.chat.ClickEvent.Action.valueOf(c.getClickEvent().getAction().name()), c.getClickEvent().getValue())); + if (c.getHoverEvent() != null) + switch (c.getHoverEvent().getAction()) { + case SHOW_ENTITY: + try { + ComponentEntity compoundTag = (ComponentEntity) c.getHoverEvent().getValue(); + net.minecraft.network.chat.Component component = compoundTag.getName() == null ? null : (net.minecraft.network.chat.Component) toIChatBaseComponent(compoundTag.getName()); + EntityType entityType = BuiltInRegistries.ENTITY_TYPE.get(new ResourceLocation(compoundTag.getType())); + modif = modif.withHoverEvent(new net.minecraft.network.chat.HoverEvent(net.minecraft.network.chat.HoverEvent.Action.SHOW_ENTITY, + new net.minecraft.network.chat.HoverEvent.EntityTooltipInfo(entityType, compoundTag.getId(), component))); + } catch (Exception commandSyntaxException) { + } + break; + case SHOW_ITEM: + try { + + ComponentItem compoundTag = (ComponentItem) c.getHoverEvent().getValue(); + net.minecraft.world.item.ItemStack stack = new net.minecraft.world.item.ItemStack( + CraftMagicNumbers.getItem(XMaterial.matchXMaterial(compoundTag.getId()).orElse(XMaterial.AIR).parseMaterial()), compoundTag.getCount()); + if (compoundTag.getNbt() != null) { + CompoundTag nbt = (CompoundTag) parseNBT(compoundTag.getNbt()); + if (!nbt.contains("id")) + nbt.putString("id", + BuiltInRegistries.ITEM.getKey(CraftMagicNumbers.getItem(XMaterial.matchXMaterial(compoundTag.getId()).orElse(XMaterial.AIR).parseMaterial())).toString()); + if (!nbt.contains("count")) + nbt.putInt("count", compoundTag.getCount()); + stack = net.minecraft.world.item.ItemStack.parseOptional(dispatcher, nbt); + } + modif = modif.withHoverEvent( + new net.minecraft.network.chat.HoverEvent(net.minecraft.network.chat.HoverEvent.Action.SHOW_ITEM, new net.minecraft.network.chat.HoverEvent.ItemStackInfo(stack))); + } catch (Exception commandSyntaxException) { + } + break; + default: + modif = modif.withHoverEvent(new net.minecraft.network.chat.HoverEvent(net.minecraft.network.chat.HoverEvent.Action.SHOW_TEXT, + (net.minecraft.network.chat.Component) this.toIChatBaseComponent(c.getHoverEvent().getValue()))); + break; + } + modif = modif.withBold(c.isBold()); + modif = modif.withItalic(c.isItalic()); + modif = modif.withObfuscated(c.isObfuscated()); + modif = modif.withUnderlined(c.isUnderlined()); + modif = modif.withStrikethrough(c.isStrikethrough()); + current.setStyle(modif); + return current; + } + + @Override + public Object[] toIChatBaseComponents(List components) { + List chat = new ArrayList<>(); + chat.add(net.minecraft.network.chat.Component.literal("")); + for (Component c : components) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + return chat.toArray(new net.minecraft.network.chat.Component[0]); + } + + private void addConverted(List chat, List extra) { + for (Component c : extra) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + } + + @Override + public Object[] toIChatBaseComponents(Component co) { + if (co == null) + return new net.minecraft.network.chat.Component[] { empty }; + if (co instanceof ComponentItem || co instanceof ComponentEntity) + return new net.minecraft.network.chat.Component[] { net.minecraft.network.chat.Component.Serializer.fromJson(Json.writer().simpleWrite(co.toJsonMap()), dispatcher) }; + List chat = new ArrayList<>(); + chat.add(net.minecraft.network.chat.Component.literal("")); + if (co.getText() != null && !co.getText().isEmpty()) + chat.add(convert(co)); + if (co.getExtra() != null) + for (Component c : co.getExtra()) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + return chat.toArray(new net.minecraft.network.chat.Component[0]); + } + + @Override + public Object toIChatBaseComponent(Component co) { + if (co == null) + return empty; + if (co instanceof ComponentItem || co instanceof ComponentEntity) + return net.minecraft.network.chat.Component.Serializer.fromJson(Json.writer().simpleWrite(co.toJsonMap()), dispatcher); + MutableComponent main = net.minecraft.network.chat.Component.literal(""); + List chat = new ArrayList<>(); + if (co.getText() != null && !co.getText().isEmpty()) + chat.add(convert(co)); + if (co.getExtra() != null) + for (Component c : co.getExtra()) { + if (c.getText() == null || c.getText().isEmpty()) { + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + continue; + } + chat.add(convert(c)); + if (c.getExtra() != null) + addConverted(chat, c.getExtra()); + } + main.getSiblings().addAll(chat); + return main.getSiblings().isEmpty() ? empty : main; + } + + @Override + public Object toIChatBaseComponent(List cc) { + MutableComponent main = net.minecraft.network.chat.Component.literal(""); + for (Component c : cc) + main.getSiblings().add((net.minecraft.network.chat.Component) this.toIChatBaseComponent(c)); + return main.getSiblings().isEmpty() ? empty : main; + } + + @Override + public Object chatBase(String json) { + return net.minecraft.network.chat.Component.Serializer.fromJson(json, dispatcher); + } + + @Override + public Component fromIChatBaseComponent(Object componentObject) { + if (componentObject == null) + return Component.EMPTY_COMPONENT; + net.minecraft.network.chat.Component component = (net.minecraft.network.chat.Component) componentObject; + Object result = Ref.invoke(component.getContents(), "text"); + Component comp = new Component(result == null ? "" : (String) result); + Style modif = component.getStyle(); + if (modif.getColor() != null) + comp.setColor(modif.getColor().serialize()); + + if (modif.getClickEvent() != null) + comp.setClickEvent(new ClickEvent(ClickEvent.Action.valueOf(modif.getClickEvent().getAction().name()), modif.getClickEvent().getValue())); + + if (modif.getHoverEvent() != null) + switch (HoverEvent.Action.valueOf(modif.getHoverEvent().getAction().getSerializedName().toUpperCase())) { + case SHOW_ENTITY: { + EntityTooltipInfo hover = modif.getHoverEvent().getValue(net.minecraft.network.chat.HoverEvent.Action.SHOW_ENTITY); + ComponentEntity compEntity = new ComponentEntity(hover.type.toString(), hover.id); + if (hover.name.isPresent()) + compEntity.setName(fromIChatBaseComponent(hover.name.get())); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ENTITY, compEntity)); + break; + } + case SHOW_ITEM: { + ItemStackInfo hover = modif.getHoverEvent().getValue(net.minecraft.network.chat.HoverEvent.Action.SHOW_ITEM); + ComponentItem compEntity = new ComponentItem(CraftMagicNumbers.getMaterial(hover.getItemStack().getItem()).name(), hover.getItemStack().getCount()); + if (hover.getItemStack().getTags() != null) + compEntity.setNbt(hover.getItemStack().save(dispatcher).toString()); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_ITEM, compEntity)); + break; + } + default: + net.minecraft.network.chat.Component hover = modif.getHoverEvent().getValue(net.minecraft.network.chat.HoverEvent.Action.SHOW_TEXT); + comp.setHoverEvent(new HoverEvent(HoverEvent.Action.SHOW_TEXT, fromIChatBaseComponent(hover))); + break; + } + comp.setBold(modif.isBold()); + comp.setItalic(modif.isItalic()); + comp.setObfuscated(modif.isObfuscated()); + comp.setUnderlined(modif.isUnderlined()); + comp.setStrikethrough(modif.isStrikethrough()); + + if (!component.getSiblings().isEmpty()) { + List extra = new ArrayList<>(); + for (net.minecraft.network.chat.Component base : component.getSiblings()) + extra.add(fromIChatBaseComponent(base)); + comp.setExtra(extra); + } + return comp; + } + + @Override + public BlockDataStorage toMaterial(Object blockOrIBlockData) { + if (blockOrIBlockData instanceof Block) { + net.minecraft.world.level.block.state.BlockState data = ((Block) blockOrIBlockData).defaultBlockState(); + return new BlockDataStorage(CraftMagicNumbers.getMaterial(data.getBlock()), (byte) 0, asString(data)); + } + if (blockOrIBlockData instanceof net.minecraft.world.level.block.state.BlockState) { + net.minecraft.world.level.block.state.BlockState data = (net.minecraft.world.level.block.state.BlockState) blockOrIBlockData; + return new BlockDataStorage(CraftMagicNumbers.getMaterial(data.getBlock()), (byte) 0, asString(data)); + } + return new BlockDataStorage(Material.AIR); + } + + private String asString(net.minecraft.world.level.block.state.BlockState data) { + StringBuilder stateString = new StringBuilder(); + if (!data.getProperties().isEmpty()) { + stateString.append('['); + stateString.append(data.getValues().entrySet().stream().map(StateHolder.PROPERTY_ENTRY_TO_STRING_FUNCTION).collect(Collectors.joining(","))); + stateString.append(']'); + } + return stateString.toString(); + } + + @Override + public Object toIBlockData(BlockDataStorage material) { + if (material == null || material.getType() == null || material.getType() == Material.AIR) + return Blocks.AIR.defaultBlockState(); + Block block = CraftMagicNumbers.getBlock(material.getType()); + return readArgument(block, material); + } + + @Override + public Object toBlock(BlockDataStorage material) { + if (material == null || material.getType() == null || material.getType() == Material.AIR) + return Blocks.AIR; + Block block = CraftMagicNumbers.getBlock(material.getType()); + return readArgument(block, material).getBlock(); + } + + private net.minecraft.world.level.block.state.BlockState readArgument(Block block, BlockDataStorage material) { + net.minecraft.world.level.block.state.BlockState ib = block.defaultBlockState(); + return writeData(ib, ib.getBlock().getStateDefinition(), material.getData()); + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static net.minecraft.world.level.block.state.BlockState writeData(net.minecraft.world.level.block.state.BlockState ib, StateDefinition blockStateList, String string) { + if (string == null || string.trim().isEmpty()) + return ib; + + String key = ""; + String value = ""; + int set = 0; + + for (int i = 1; i < string.length() - 1; ++i) { + char c = string.charAt(i); + if (c == ',') { + net.minecraft.world.level.block.state.properties.Property ibj = blockStateList.getProperty(key); + if (ibj != null) { + Optional optional = ibj.getValue(value); + if (optional.isPresent()) + ib = ib.setValue(ibj, (Comparable) optional.get()); + } + key = ""; + value = ""; + set = 0; + continue; + } + if (c == '=') { + set = 1; + continue; + } + if (set == 0) + key += c; + else + value += c; + } + if (set == 1) { + net.minecraft.world.level.block.state.properties.Property ibj = blockStateList.getProperty(key); + if (ibj != null) { + Optional optional = ibj.getValue(value); + if (optional.isPresent()) + ib = ib.setValue(ibj, (Comparable) optional.get()); + } + } + return ib; + } + + @Override + public ItemStack toItemStack(BlockDataStorage material) { + Item item = CraftMagicNumbers.getItem(material.getType(), ParseUtils.getShort(material.getData())); + return CraftItemStack.asBukkitCopy(item.getDefaultInstance()); + } + + @Override + public Object getChunk(World world, int x, int z) { + return ((CraftChunk) world.getChunkAt(x, z)).getHandle(ChunkStatus.FULL); + } + + @Override + public void setBlock(Object objChunk, int x, int y, int z, Object IblockData, int data) { + LevelChunk chunk = (LevelChunk) objChunk; + ServerLevel world = chunk.level; + int highY = chunk.getSectionIndex(y); + if (highY < 0) + return; + LevelChunkSection sc = chunk.getSection(highY); + if (sc == null) + return; + BlockPos pos = new BlockPos(x, y, z); + + net.minecraft.world.level.block.state.BlockState iblock = IblockData == null ? Blocks.AIR.defaultBlockState() : (net.minecraft.world.level.block.state.BlockState) IblockData; + + boolean onlyModifyState = iblock.getBlock() instanceof EntityBlock; + + // REMOVE TILE ENTITY IF NOT SAME TYPE + BlockEntity ent = chunk.blockEntities.get(pos); + if (ent != null) { + boolean shouldSkip = true; + if (!onlyModifyState) + shouldSkip = false; + else if (onlyModifyState && !ent.getType().isValid(iblock)) { + shouldSkip = false; + onlyModifyState = false; + } + if (!shouldSkip) + chunk.removeBlockEntity(pos); + } + + net.minecraft.world.level.block.state.BlockState old = sc.setBlockState(x & 15, y & 15, z & 15, iblock, false); + + // ADD TILE ENTITY + if (iblock.getBlock() instanceof EntityBlock && !onlyModifyState) { + ent = ((EntityBlock) iblock.getBlock()).newBlockEntity(pos, iblock); + chunk.blockEntities.put(pos, ent); + ent.setLevel(world); + Object packet = ent.getUpdatePacket(); + BukkitLoader.getPacketHandler().send(chunk.level.getWorld().getPlayers(), packet); + } + + // MARK CHUNK TO SAVE + chunk.setUnsaved(true); + + // POI + if (!world.preventPoiUpdated) + world.onBlockStateChange(pos, old, iblock); + } + + @Override + public void updatePhysics(Object objChunk, int x, int y, int z, Object iblockdata) { + LevelChunk chunk = (LevelChunk) objChunk; + BlockPos blockPos = new BlockPos(x, y, z); + doPhysicsAround(chunk.level, blockPos, ((net.minecraft.world.level.block.state.BlockState) iblockdata).getBlock()); + } + + private void doPhysicsAround(ServerLevel world, BlockPos BlockPos, Block block) { + doPhysics(world, BlockPos.west(), block, BlockPos); // west + doPhysics(world, BlockPos.east(), block, BlockPos); // east + doPhysics(world, BlockPos.below(), block, BlockPos); // down + doPhysics(world, BlockPos.above(), block, BlockPos); // up + doPhysics(world, BlockPos.north(), block, BlockPos); // north + doPhysics(world, BlockPos.south(), block, BlockPos); // south + } + + private static final Method callPhysics = Ref.method(FallingBlock.class, "onPlace", net.minecraft.world.level.block.state.BlockState.class, Level.class, BlockPos.class, + net.minecraft.world.level.block.state.BlockState.class, boolean.class); + + private void doPhysics(ServerLevel world, BlockPos BlockPos, Block block, BlockPos BlockPos1) { + + net.minecraft.world.level.block.state.BlockState state = world.getBlockState(BlockPos); + state.handleNeighborChanged(world, BlockPos, block, BlockPos1, false); + if (state.getBlock() instanceof FallingBlock) + Ref.invoke(state.getBlock(), callPhysics, state, world, BlockPos, block.defaultBlockState(), false); + } + + @Override + public void updateLightAt(Object objChunk, int x, int y, int z) { + LevelChunk chunk = (LevelChunk) objChunk; + chunk.level.getChunkSource().getLightEngine().checkBlock(new BlockPos(x, y, z)); + } + + @Override + public Object getBlock(Object objChunk, int x, int y, int z) { + LevelChunk chunk = (LevelChunk) objChunk; + return chunk.getBlockState(x, y, z); + } + + @Override + public byte getData(Object chunk, int x, int y, int z) { + return 0; + } + + @Override + public String getNBTOfTile(Object objChunk, int x, int y, int z) { + LevelChunk chunk = (LevelChunk) objChunk; + return chunk.getBlockEntity(new BlockPos(x, y, z), EntityCreationType.IMMEDIATE).saveWithFullMetadata(dispatcher).toString(); + } + + @Override + public void setNBTToTile(Object objChunk, int x, int y, int z, String nbt) { + LevelChunk chunk = (LevelChunk) objChunk; + BlockEntity ent = chunk.getBlockEntity(new BlockPos(x, y, z), EntityCreationType.IMMEDIATE); + CompoundTag parsedNbt = (CompoundTag) parseNBT(nbt); + parsedNbt.putInt("x", x); + parsedNbt.putInt("y", y); + parsedNbt.putInt("z", z); + ent.loadWithComponents(parsedNbt, dispatcher); + Object packet = ent.getUpdatePacket(); + BukkitLoader.getPacketHandler().send(chunk.level.getWorld().getPlayers(), packet); + } + + @Override + public boolean isTileEntity(Object objChunk, int x, int y, int z) { + LevelChunk chunk = (LevelChunk) objChunk; + return chunk.getBlockEntity(new BlockPos(x, y, z), EntityCreationType.IMMEDIATE) != null; + } + + @Override + public int getCombinedId(Object IblockDataOrBlock) { + return Block.getId((net.minecraft.world.level.block.state.BlockState) IblockDataOrBlock); + } + + @Override + public Object blockPosition(int blockX, int blockY, int blockZ) { + return new BlockPos(blockX, blockY, blockZ); + } + + @Override + public Object toIBlockData(Object data) { + return ((CraftBlockData) data).getState(); + } + + @Override + public Object toIBlockData(BlockState state) { + return CraftMagicNumbers.getBlock(state.getType(), state.getRawData()); + } + + @Override + public Chunk toBukkitChunk(Object nmsChunk) { + return new CraftChunk((LevelChunk) nmsChunk); + } + + @Override + public int getPing(Player player) { + return ((ServerGamePacketListenerImpl) getPlayerConnection(player)).latency(); + } + + @Override + public Object getPlayerConnection(Player player) { + return ((ServerPlayer) getPlayer(player)).connection; + } + + private static Field networkManagerField = Ref.field(ServerCommonPacketListenerImpl.class, Connection.class); + + @Override + public Object getConnectionNetwork(Object playercon) { + return Ref.get(playercon, networkManagerField); + } + + @Override + public Object getNetworkChannel(Object network) { + return ((Connection) network).channel; + } + + @Override + public Object packetOpenWindow(int id, String legacy, int size, Component title) { + + MenuType windowType = MenuType.GENERIC_9x1; + switch (size) { + case 0: { + windowType = MenuType.ANVIL; + break; + } + case 18: { + windowType = MenuType.GENERIC_9x2; + break; + } + case 27: { + windowType = MenuType.GENERIC_9x3; + break; + } + case 36: { + windowType = MenuType.GENERIC_9x4; + break; + } + case 45: { + windowType = MenuType.GENERIC_9x5; + break; + } + case 54: { + windowType = MenuType.GENERIC_9x6; + break; + } + } + return new ClientboundOpenScreenPacket(id, windowType, (net.minecraft.network.chat.Component) this.toIChatBaseComponent(title)); + } + + @Override + public void closeGUI(Player player, Object container, boolean closePacket) { + if (closePacket) + BukkitLoader.getPacketHandler().send(player, new ClientboundContainerClosePacket(((AbstractContainerMenu) container).containerId)); + net.minecraft.world.entity.player.Player nmsPlayer = (net.minecraft.world.entity.player.Player) getPlayer(player); + nmsPlayer.containerMenu = nmsPlayer.inventoryMenu; + ((AbstractContainerMenu) container).transferTo(nmsPlayer.containerMenu, (CraftPlayer) player); + } + + @Override + public void setSlot(Object container, int slot, Object item) { + ((AbstractContainerMenu) container).setItem(slot, ((AbstractContainerMenu) container).getStateId(), (net.minecraft.world.item.ItemStack) item); + } + + @Override + public void setGUITitle(Player player, Object container, String legacy, int size, Component title) { + int id = ((AbstractContainerMenu) container).containerId; + BukkitLoader.getPacketHandler().send(player, packetOpenWindow(id, legacy, size, title)); + net.minecraft.world.item.ItemStack carried = ((AbstractContainerMenu) container).getCarried(); + if (!carried.isEmpty()) + BukkitLoader.getPacketHandler().send(player, new ClientboundContainerSetSlotPacket(id, getContainerStateId(container), -1, carried)); + int slot = 0; + for (net.minecraft.world.item.ItemStack item : ((AbstractContainerMenu) container).getItems()) { + if (slot == size) + break; + if (!item.isEmpty()) + BukkitLoader.getPacketHandler().send(player, new ClientboundContainerSetSlotPacket(id, getContainerStateId(container), slot, item)); + ++slot; + } + } + + @Override + public void openGUI(Player player, Object container, String legacy, int size, Component title) { + ServerPlayer nmsPlayer = ((CraftPlayer) player).getHandle(); + int id = ((AbstractContainerMenu) container).containerId; + BukkitLoader.getPacketHandler().send(player, packetOpenWindow(id, legacy, size, title)); + nmsPlayer.containerMenu.transferTo((AbstractContainerMenu) container, (CraftPlayer) player); + nmsPlayer.containerMenu = (AbstractContainerMenu) container; + postToMainThread(() -> nmsPlayer.initMenu((AbstractContainerMenu) container)); + ((AbstractContainerMenu) container).checkReachable = false; + } + + @Override + public void openAnvilGUI(Player player, Object container, Component title) { + openGUI(player, container, "minecraft:anvil", 0, title); + } + + @Override + public Object createContainer(Inventory inv, Player player) { + if (inv.getType() == InventoryType.ANVIL) { + AnvilMenu container = new AnvilMenu(((CraftPlayer) player).getHandle().nextContainerCounter(), ((CraftPlayer) player).getHandle().getInventory(), new ContainerLevelAccess() { + + @Override + public Optional evaluate(BiFunction getter) { + return Optional.empty(); + } + + @Override + public Location getLocation() { + return null; + } + }); + postToMainThread(() -> { + int slot = 0; + for (ItemStack stack : inv.getContents()) + container.getSlot(slot++).set((net.minecraft.world.item.ItemStack) asNMSItem(stack)); + }); + container.checkReachable = false; + return container; + } + return new CraftContainer(inv, ((CraftPlayer) player).getHandle(), ((CraftPlayer) player).getHandle().nextContainerCounter()); + } + + @Override + public Object getSlotItem(Object container, int slot) { + return slot < 0 ? null : ((AbstractContainerMenu) container).getSlot(slot).getItem(); + } + + @Override + public String getAnvilRenameText(Object anvil) { + return ((AnvilMenu) anvil).itemName; + } + + public static int c(final int quickCraftData) { + return quickCraftData >> 2 & 0x3; + } + + public static int d(final int quickCraftData) { + return quickCraftData & 0x3; + } + + @Override + public boolean processInvClickPacket(Player player, HolderGUI gui, Object provPacket) { + ServerboundContainerClickPacket packet = (ServerboundContainerClickPacket) provPacket; + int slot = packet.getSlotNum(); + + Object container = gui.getContainer(player); + if (container == null) + return false; + + int id = packet.getContainerId(); + int mouseClick = packet.getButtonNum(); + net.minecraft.world.inventory.ClickType type = packet.getClickType(); + AbstractContainerMenu c = (AbstractContainerMenu) container; + + if (slot < -1 && slot != -999) + return true; + + net.minecraft.world.entity.player.Player nPlayer = ((CraftPlayer) player).getHandle(); + + ItemStack newItem; + ItemStack oldItem; + switch (type) { + case PICKUP: // PICKUP + oldItem = asBukkitItem(getSlotItem(container, slot)); + newItem = asBukkitItem(c.getCarried()); + if (slot > 0 && mouseClick != 0) { + if (c.getCarried().isEmpty()) { // pickup half + newItem = oldItem.clone(); + if (oldItem.getAmount() == 1) + newItem = new ItemStack(Material.AIR); + else + newItem.setAmount(Math.max(1, oldItem.getAmount() / 2)); + } else + // drop + if (oldItem.isSimilar(newItem) || oldItem.getType() == Material.AIR) + newItem.setAmount(oldItem.getType() == Material.AIR ? 1 : oldItem.getAmount() + 1); + } else if (slot > 0 && mouseClick == 0) // drop + if (oldItem.isSimilar(newItem)) + newItem.setAmount(Math.min(newItem.getAmount() + oldItem.getAmount(), newItem.getMaxStackSize())); + break; + case QUICK_MOVE: // QUICK_MOVE + newItem = asBukkitItem(c.getCarried()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case SWAP:// SWAP + newItem = asBukkitItem(nPlayer.getInventory().getItem(mouseClick)); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case CLONE:// CLONE + newItem = asBukkitItem(getSlotItem(container, slot)); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case THROW:// THROW + if (c.getCarried().isEmpty() && slot >= 0) { + Slot slot3 = c.getSlot(slot); + newItem = asBukkitItem(slot3.getItem()); + if (mouseClick != 0 || newItem.getAmount() - 1 <= 0) + newItem = new ItemStack(Material.AIR); + else + newItem.setAmount(newItem.getAmount() - 1); + } else + newItem = asBukkitItem(c.getCarried()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + case QUICK_CRAFT:// QUICK_CRAFT + newItem = asBukkitItem(c.getCarried()); + oldItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(getSlotItem(container, slot)); + break; + case PICKUP_ALL:// PICKUP_ALL + newItem = asBukkitItem(c.getCarried()); + oldItem = asBukkitItem(getSlotItem(container, slot)); + break; + default: + newItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(packet.getCarriedItem()); + oldItem = slot <= -1 ? new ItemStack(Material.AIR) : asBukkitItem(packet.getCarriedItem()); + break; + } + + if (oldItem.getType() == Material.AIR && newItem.getType() == Material.AIR) + return true; + + boolean cancel = false; + int gameSlot = slot > gui.size() - 1 ? InventoryUtils.convertToPlayerInvSlot(slot - gui.size()) : slot; + + ClickType clickType = InventoryUtils.buildClick(type == net.minecraft.world.inventory.ClickType.QUICK_CRAFT ? 1 : type == net.minecraft.world.inventory.ClickType.QUICK_MOVE ? 2 : 0, + mouseClick); + if (slot > -1) { + if (!cancel) + cancel = InventoryUtils.useItem(player, gui, slot, clickType); + if (!gui.isInsertable()) + cancel = true; + + if (!cancel) + cancel = gui.onInteractItem(player, newItem, oldItem, clickType, gameSlot, slot < gui.size()); + else + gui.onInteractItem(player, newItem, oldItem, clickType, gameSlot, slot < gui.size()); + } + if (!cancel) { + if (gui instanceof AnvilGUI) { // Event + final ItemStack newItemFinal = newItem; + postToMainThread(() -> { + processEvent(c, type, gui, player, slot, gameSlot, newItemFinal, oldItem, packet, mouseClick, clickType, nPlayer); + }); + } else + processEvent(c, type, gui, player, slot, gameSlot, newItem, oldItem, packet, mouseClick, clickType, nPlayer); + return true; + } + // MOUSE + int statusId = c.getStateId(); + BukkitLoader.getPacketHandler().send(player, packetSetSlot(-1, -1, statusId, c.getCarried())); + switch (type) { + case CLONE: + break; + case SWAP: + case QUICK_MOVE: + case PICKUP_ALL: + c.sendAllDataToRemote(); + break; + default: + BukkitLoader.getPacketHandler().send(player, packetSetSlot(id, slot, statusId, c.getSlot(slot).getItem())); + break; + } + return true; + } + + private void processEvent(AbstractContainerMenu c, net.minecraft.world.inventory.ClickType type, HolderGUI gui, Player player, int slot, int gameSlot, ItemStack newItem, ItemStack oldItem, + ServerboundContainerClickPacket packet, int mouseClick, ClickType clickType, net.minecraft.world.entity.player.Player nPlayer) { + c.suppressRemoteUpdates(); + switch (type) { + case QUICK_MOVE: { + ItemStack[] contents = slot < gui.size() ? player.getInventory().getStorageContents() : gui.getInventory().getStorageContents(); + boolean interactWithResultSlot = false; + if (gui instanceof AnvilGUI && slot < gui.size() && slot == 2) + if (c.getSlot(2).allowModification(nPlayer)) + interactWithResultSlot = true; + else + return; + Pair result = slot < gui.size() + ? InventoryUtils.shift(slot, player, gui, clickType, gui instanceof AnvilGUI && slot != 2 ? DestinationType.PLAYER_FROM_ANVIL : DestinationType.PLAYER, null, contents, oldItem) + : InventoryUtils.shift(slot, player, gui, clickType, DestinationType.GUI, gui.getNotInterableSlots(player), contents, oldItem); + @SuppressWarnings("unchecked") + Map modified = (Map) result.getValue(); + int remaining = (int) result.getKey(); + + if (!modified.isEmpty()) + if (slot < gui.size()) { + for (Entry modif : modified.entrySet()) + nPlayer.getInventory().setItem(modif.getKey(), (net.minecraft.world.item.ItemStack) asNMSItem(modif.getValue())); + if (remaining == 0) { + c.getSlot(gameSlot).set((net.minecraft.world.item.ItemStack) asNMSItem(null)); + if (interactWithResultSlot) { + c.getSlot(0).set((net.minecraft.world.item.ItemStack) asNMSItem(null)); + c.getSlot(1).set((net.minecraft.world.item.ItemStack) asNMSItem(null)); + } + } else { + newItem.setAmount(remaining); + c.getSlot(gameSlot).set((net.minecraft.world.item.ItemStack) asNMSItem(newItem)); + } + } else { + for (Entry modif : modified.entrySet()) + c.getSlot(modif.getKey()).set((net.minecraft.world.item.ItemStack) asNMSItem(modif.getValue())); // Visual & Nms side + // Plugin & Bukkit side + gui.getInventory().setStorageContents(contents); + if (remaining == 0) + nPlayer.getInventory().setItem(gameSlot, (net.minecraft.world.item.ItemStack) asNMSItem(null)); + else { + newItem.setAmount(remaining); + nPlayer.getInventory().setItem(gameSlot, (net.minecraft.world.item.ItemStack) asNMSItem(newItem)); + } + } + c.resumeRemoteUpdates(); + return; + } + default: + processClick(gui, gui.getNotInterableSlots(player), c, slot, mouseClick, type, nPlayer); + break; + } + postToMainThread(() -> { + if (type != net.minecraft.world.inventory.ClickType.QUICK_CRAFT && (c.getType().equals(MenuType.ANVIL) || c.getType().equals(MenuType.SMITHING))) + c.sendAllDataToRemote(); + for (final it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry entry : Int2ObjectMaps.fastIterable(packet.getChangedSlots())) + c.setItem(entry.getIntKey(), packet.getStateId(), entry.getValue()); + c.setCarried(packet.getCarriedItem()); + c.resumeRemoteUpdates(); + if (packet.getStateId() != c.getStateId()) + c.broadcastFullState(); + else + c.broadcastChanges(); + }); + } + + private Method addAmount = Ref.method(Slot.class, "onSwapCraft", int.class); + private Method checkItem = Ref.method(AbstractContainerMenu.class, "tryItemClickBehaviourOverride", net.minecraft.world.entity.player.Player.class, ClickAction.class, Slot.class, + net.minecraft.world.item.ItemStack.class, net.minecraft.world.item.ItemStack.class); + + @SuppressWarnings("unchecked") + private void processClick(HolderGUI gui, List ignoredSlots, AbstractContainerMenu container, int slotIndex, int button, net.minecraft.world.inventory.ClickType actionType, + net.minecraft.world.entity.player.Player player) { + if (actionType == net.minecraft.world.inventory.ClickType.QUICK_CRAFT) + processDragMove(gui, container, player, slotIndex, button); + else { + int u = (int) Ref.get(container, containerU); + int j = getContainerStateId(container); + Set mod = (Set) Ref.get(container, containerV); + if (u != 0) { + Ref.set(container, containerU, u = 0); + mod.clear(); + } else if (actionType == net.minecraft.world.inventory.ClickType.PICKUP && (button == 0 || button == 1)) { + ClickAction clickaction = button == 0 ? ClickAction.PRIMARY : ClickAction.SECONDARY; + if (slotIndex == -999) { + if (!container.getCarried().isEmpty()) + if (clickaction == ClickAction.PRIMARY) { + net.minecraft.world.item.ItemStack carried = container.getCarried(); + container.setCarried(net.minecraft.world.item.ItemStack.EMPTY); + postToMainThread(() -> player.drop(carried, true)); + } else + postToMainThread(() -> player.drop(container.getCarried().split(1), true)); + } else { + if (slotIndex < 0) + return; + Slot slot = container.getSlot(slotIndex); + net.minecraft.world.item.ItemStack itemstack = slot.getItem(); + net.minecraft.world.item.ItemStack itemstack4 = container.getCarried(); + player.updateTutorialInventoryAction(itemstack4, slot.getItem(), clickaction); + if (!(boolean) Ref.invoke(container, checkItem, player, clickaction, slot, itemstack, itemstack4)) + if (itemstack.isEmpty()) { + if (!itemstack4.isEmpty()) { + int i2 = clickaction == ClickAction.PRIMARY ? itemstack4.getCount() : 1; + net.minecraft.world.item.ItemStack stack = slot.safeInsert(itemstack4, i2); + container.setCarried(stack); + } + } else if (slot.allowModification(player)) + if (itemstack4.isEmpty()) { + int i2 = clickaction == ClickAction.PRIMARY ? itemstack.getCount() : (itemstack.getCount() + 1) / 2; + Optional optional = slot.tryRemove(i2, 2147483647, player); + optional.ifPresent(i -> { + container.setCarried(i); + slot.onTake(player, i); + }); + } else if (slot.mayPlace(itemstack4)) { + if (net.minecraft.world.item.ItemStack.isSameItemSameComponents(itemstack, itemstack4)) { + int i2 = clickaction == ClickAction.PRIMARY ? itemstack4.getCount() : 1; + net.minecraft.world.item.ItemStack stack = slot.safeInsert(itemstack4, i2); + container.setCarried(stack); + } else if (itemstack4.getCount() <= slot.getMaxStackSize(itemstack4)) { + container.setCarried(itemstack); + slot.safeInsert(itemstack4); + } + } else if (net.minecraft.world.item.ItemStack.isSameItemSameComponents(itemstack, itemstack4)) { + Optional optional2 = slot.tryRemove(itemstack.getCount(), itemstack4.getMaxStackSize() - itemstack4.getCount(), player); + optional2.ifPresent(i -> { + itemstack.grow(i.getCount()); + slot.onTake(player, i); + }); + } + slot.setChanged(); + if (player instanceof net.minecraft.world.entity.player.Player && slot.getMaxStackSize() != 64) { + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), + BukkitLoader.getNmsProvider().packetSetSlot(j, slot.index, container.incrementStateId(), slot.getItem())); + if (container.getBukkitView().getType() == InventoryType.WORKBENCH || container.getBukkitView().getType() == InventoryType.CRAFTING) + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), + BukkitLoader.getNmsProvider().packetSetSlot(j, 0, container.incrementStateId(), container.getSlot(0).getItem())); + } + } + } else if (actionType == net.minecraft.world.inventory.ClickType.SWAP) { + if (slotIndex < 0) + return; + net.minecraft.world.entity.player.Inventory playerinventory = player.getInventory(); + Slot slot3 = container.getSlot(slotIndex); + net.minecraft.world.item.ItemStack itemstack2 = playerinventory.getItem(button); + net.minecraft.world.item.ItemStack itemstack = slot3.getItem(); + if (!itemstack2.isEmpty() || !itemstack.isEmpty()) + if (itemstack2.isEmpty()) { + if (slot3.allowModification(player)) { + playerinventory.setItem(button, itemstack); + Ref.invoke(slot3, addAmount, itemstack.getCount()); + slot3.set(net.minecraft.world.item.ItemStack.EMPTY); + slot3.onTake(player, itemstack); + } + } else if (itemstack.isEmpty()) { + if (slot3.mayPlace(itemstack2)) { + int j2 = slot3.getMaxStackSize(itemstack2); + if (itemstack2.getCount() > j2) + slot3.set(itemstack2.split(j2)); + else { + playerinventory.setItem(button, net.minecraft.world.item.ItemStack.EMPTY); + slot3.set(itemstack2); + } + } + } else if (slot3.allowModification(player) && slot3.mayPlace(itemstack2)) { + int j2 = slot3.getMaxStackSize(itemstack2); + if (itemstack2.getCount() > j2) { + slot3.set(itemstack2.split(j2)); + slot3.onTake(player, itemstack); + if (!playerinventory.add(itemstack)) + postToMainThread(() -> player.drop(itemstack, true)); + } else { + playerinventory.setItem(button, itemstack); + slot3.set(itemstack2); + slot3.onTake(player, itemstack); + } + } + } else if (actionType == net.minecraft.world.inventory.ClickType.CLONE && player.getAbilities().instabuild && container.getCarried().isEmpty() && slotIndex >= 0) { + Slot slot3 = container.getSlot(slotIndex); + if (slot3.hasItem()) { + net.minecraft.world.item.ItemStack itemstack2 = slot3.getItem(); + container.setCarried(itemstack2.copyWithCount(itemstack2.getMaxStackSize())); + } + } else if (actionType == net.minecraft.world.inventory.ClickType.THROW && container.getCarried().isEmpty() && slotIndex >= 0) { + Slot slot3 = container.getSlot(slotIndex); + int m = button == 0 ? 1 : slot3.getItem().getCount(); + net.minecraft.world.item.ItemStack itemstack = slot3.safeTake(m, 2147483647, player); + postToMainThread(() -> player.drop(itemstack, true)); + } else if (actionType == net.minecraft.world.inventory.ClickType.PICKUP_ALL && slotIndex >= 0) { + final Slot slot3 = container.slots.get(slotIndex); + final net.minecraft.world.item.ItemStack itemstack2 = container.getCarried(); + if (!itemstack2.isEmpty() && (!slot3.hasItem() || !slot3.allowModification(player))) { + List ignoreSlots = ignoredSlots == null ? Collections.emptyList() : ignoredSlots; + List corruptedSlots = ignoredSlots == null ? Collections.emptyList() : new ArrayList<>(); + Map modifiedSlots = new HashMap<>(); + Map modifiedSlotsPlayerInv = new HashMap<>(); + final int l = button == 0 ? 0 : container.slots.size() - 1; + final int j2 = button == 0 ? 1 : -1; + for (int i2 = 0; i2 < 2; ++i2) + for (int slot = l; slot >= 0 && slot < container.slots.size() && itemstack2.getCount() < itemstack2.getMaxStackSize(); slot += j2) { + final Slot slot4 = container.slots.get(slot); + if (slot4.hasItem() && AbstractContainerMenu.canItemQuickReplace(slot4, itemstack2, true) && slot4.allowModification(player) + && container.canTakeItemForPickAll(itemstack2, slot4)) { + final net.minecraft.world.item.ItemStack itemstack5 = slot4.getItem(); + if (i2 != 0 || itemstack5.getCount() != itemstack5.getMaxStackSize()) { + if (slot < gui.size() && ignoreSlots.contains(slot)) { + corruptedSlots.add(slot); + continue; + } + final net.minecraft.world.item.ItemStack itemstack6 = slot4.safeTake(itemstack5.getCount(), itemstack2.getMaxStackSize() - itemstack2.getCount(), player); + itemstack2.grow(itemstack6.getCount()); + int gameSlot = slot > gui.size() - 1 ? InventoryUtils.convertToPlayerInvSlot(slot - gui.size()) : slot; + if (slot < gui.size()) + modifiedSlots.put(gameSlot, asBukkitItem(slot4.getItem())); + else + modifiedSlotsPlayerInv.put(gameSlot, asBukkitItem(slot4.getItem())); + } + } + } + if (slotIndex < gui.size()) + modifiedSlots.put(slotIndex, new ItemStack(Material.AIR)); + else + modifiedSlotsPlayerInv.put(InventoryUtils.convertToPlayerInvSlot(slotIndex - gui.size()), new ItemStack(Material.AIR)); + if (!modifiedSlots.isEmpty() || !modifiedSlotsPlayerInv.isEmpty()) + gui.onMultipleIteract((Player) player.getBukkitEntity(), modifiedSlots, modifiedSlotsPlayerInv); + for (int s : corruptedSlots) + BukkitLoader.getPacketHandler().send((Player) player.getBukkitEntity(), BukkitLoader.getNmsProvider().packetSetSlot(BukkitLoader.getNmsProvider().getContainerId(container), s, + getContainerStateId(container), BukkitLoader.getNmsProvider().getSlotItem(container, s))); + } + } + } + } + + private Field containerU = Ref.field(AbstractContainerMenu.class, "quickcraftStatus"), containerV = Ref.field(AbstractContainerMenu.class, "quickcraftSlots"), + containerT = Ref.field(AbstractContainerMenu.class, "quickcraftType"); + + @SuppressWarnings("unchecked") + private void processDragMove(HolderGUI gui, AbstractContainerMenu container, net.minecraft.world.entity.player.Player player, int slot, int mouseClick) { + int previous = (int) Ref.get(container, containerU); + int u = d(mouseClick); + Set mod = (Set) Ref.get(container, containerV); + if ((previous != 1 || u != 2) && previous != u || container.getCarried().isEmpty()) { + mod.clear(); + u = 0; + } else + switch (u) { + case 0: { + int t = c(mouseClick); + Ref.set(container, containerT, t); + if (AbstractContainerMenu.isValidQuickcraftType(t, player)) { + u = 1; + mod.clear(); + } else { + mod.clear(); + u = 0; + } + break; + } + case 1: { + if (slot < 0) { + Ref.set(container, containerU, u); + return; // nothing + } + int t = (int) Ref.get(container, containerT); + final Slot bslot = container.getSlot(slot); + final net.minecraft.world.item.ItemStack itemstack = container.getCarried(); + if (AbstractContainerMenu.canItemQuickReplace(bslot, itemstack, true) && bslot.mayPlace(itemstack) && (t == 2 || itemstack.getCount() > mod.size()) && container.canDragTo(bslot)) + mod.add(bslot); + break; + } + case 2: + if (!mod.isEmpty()) { + final net.minecraft.world.item.ItemStack itemstack2 = container.getCarried().copy(); + if (itemstack2.isEmpty()) { + mod.clear(); + Ref.set(container, containerU, 0); + return; + } + int t = (int) Ref.get(container, containerT); + int l = container.getCarried().getCount(); + final Map draggedSlots = new HashMap<>(); + for (Slot slot2 : mod) { + final net.minecraft.world.item.ItemStack itemstack3 = container.getCarried(); + if (slot2 != null && AbstractContainerMenu.canItemQuickReplace(slot2, itemstack3, true) && slot2.mayPlace(itemstack3) && (t == 2 || itemstack3.getCount() >= mod.size()) + && container.canDragTo(slot2)) { + final int j1 = slot2.hasItem() ? slot2.getItem().getCount() : 0; + final int k1 = Math.min(itemstack2.getMaxStackSize(), slot2.getMaxStackSize(itemstack2)); + final int l2 = Math.min(AbstractContainerMenu.getQuickCraftPlaceCount(mod, t, itemstack2) + j1, k1); + l -= l2 - j1; + draggedSlots.put(slot2.index, itemstack2.copyWithCount(l2)); + } + } + final InventoryView view = container.getBukkitView(); + final org.bukkit.inventory.ItemStack newcursor = CraftItemStack.asCraftMirror(itemstack2); + newcursor.setAmount(l); + final Map guiSlots = new HashMap<>(); + final Map playerSlots = new HashMap<>(); + for (final Entry ditem : draggedSlots.entrySet()) + if (ditem.getKey() < gui.size()) + guiSlots.put(ditem.getKey(), CraftItemStack.asBukkitCopy(ditem.getValue())); + else { + int finalSlot = ditem.getKey() - gui.size(); + if (finalSlot >= 27) + finalSlot -= 27; + else + finalSlot += 9; + playerSlots.put(finalSlot, CraftItemStack.asBukkitCopy(ditem.getValue())); + } + container.setCarried(CraftItemStack.asNMSCopy(newcursor)); + if (!guiSlots.isEmpty() || !playerSlots.isEmpty()) + gui.onMultipleIteract((Player) player.getBukkitEntity(), guiSlots, playerSlots); + for (final Entry dslot : draggedSlots.entrySet()) + view.setItem(dslot.getKey(), CraftItemStack.asBukkitCopy(dslot.getValue())); + if (container.getCarried() != null) + container.sendAllDataToRemote(); + } + mod.clear(); + u = 0; + default: + mod.clear(); + u = 0; + break; + } + Ref.set(container, containerU, u); + } + + @Override + public boolean processServerListPing(String player, Object channel, Object packet) { + if (packet instanceof PacketContainer) { + PacketContainer container = (PacketContainer) packet; + ClientboundStatusResponsePacket status = (ClientboundStatusResponsePacket) container.getPacket(); + ServerStatus ping = status.status(); + List gameProfiles = new ArrayList<>(); + if (ping.players().isPresent()) + for (GameProfile profile : ping.players().get().sample()) + gameProfiles.add(fromGameProfile(profile)); + + net.minecraft.network.chat.Component motd = net.minecraft.network.chat.Component.literal(""); + Optional players = Optional.empty(); + Optional serverIcon = Optional.empty(); + Optional version = ping.version(); + boolean enforceSecureProfile = ping.enforcesSecureChat(); + + String favicon = "server-icon.png"; + ServerListPingEvent event = new ServerListPingEvent(getOnlinePlayers().size(), Bukkit.getMaxPlayers(), gameProfiles, Bukkit.getMotd(), favicon, + ((InetSocketAddress) ((Channel) channel).remoteAddress()).getAddress(), ping.version().get().name(), ping.version().get().protocol()); + EventManager.call(event); + if (event.isCancelled()) { + container.setCancelled(true); + return true; + } + Players playerSample = new Players(event.getMaxPlayers(), event.getOnlinePlayers(), new ArrayList<>()); + if (event.getSlots() != null) + for (GameProfileHandler s : event.getSlots()) + playerSample.sample().add(new GameProfile(s.getUUID(), s.getUsername())); + players = Optional.of(playerSample); + + if (event.getMotd() != null) + motd = (net.minecraft.network.chat.Component) this.toIChatBaseComponent(ComponentAPI.fromString(event.getMotd())); + if (event.getVersion() != null) + version = Optional.of(new Version(event.getVersion(), event.getProtocol())); + if (event.getFavicon() != null) + if (!event.getFavicon().equals("server-icon.png") && new File(event.getFavicon()).exists()) { + BufferedImage var1; + try { + var1 = ImageIO.read(new File(event.getFavicon())); + Preconditions.checkState(var1.getWidth() == 64, "Must be 64 pixels wide"); + Preconditions.checkState(var1.getHeight() == 64, "Must be 64 pixels high"); + ByteArrayOutputStream var2 = new ByteArrayOutputStream(); + ImageIO.write(var1, "PNG", var2); + serverIcon = Optional.of(new Favicon(var2.toByteArray())); + } catch (IOException e) { + e.printStackTrace(); + } + } else + serverIcon = ping.favicon(); + container.setPacket(new ClientboundStatusResponsePacket(new ServerStatus(motd, players, version, serverIcon, enforceSecureProfile))); + return false; + } + JavaPlugin.getPlugin(BukkitLoader.class).getLogger().warning("You are using outdated version of TheAPI, please update TheAPI to the latest version!"); + return false; + } + + @Override + public Object getNBT(Entity entity) { + return ((CraftEntity) entity).getHandle().saveWithoutId(new CompoundTag()); + } + + @Override + public Object setString(Object nbt, String path, String value) { + ((CompoundTag) nbt).putString(path, value); + return nbt; + } + + @Override + public Object setInteger(Object nbt, String path, int value) { + ((CompoundTag) nbt).putInt(path, value); + return nbt; + } + + @Override + public Object setDouble(Object nbt, String path, double value) { + ((CompoundTag) nbt).putDouble(path, value); + return nbt; + } + + @Override + public Object setLong(Object nbt, String path, long value) { + ((CompoundTag) nbt).putLong(path, value); + return nbt; + } + + @Override + public Object setShort(Object nbt, String path, short value) { + ((CompoundTag) nbt).putShort(path, value); + return nbt; + } + + @Override + public Object setFloat(Object nbt, String path, float value) { + ((CompoundTag) nbt).putFloat(path, value); + return nbt; + } + + @Override + public Object setBoolean(Object nbt, String path, boolean value) { + ((CompoundTag) nbt).putBoolean(path, value); + return nbt; + } + + @Override + public Object setIntArray(Object nbt, String path, int[] value) { + ((CompoundTag) nbt).putIntArray(path, value); + return nbt; + } + + @Override + public Object setByteArray(Object nbt, String path, byte[] value) { + ((CompoundTag) nbt).putByteArray(path, value); + return nbt; + } + + @Override + public Object setNBTBase(Object nbt, String path, Object value) { + ((CompoundTag) nbt).put(path, (Tag) value); + return nbt; + } + + @Override + public String getString(Object nbt, String path) { + return ((CompoundTag) nbt).getString(path); + } + + @Override + public int getInteger(Object nbt, String path) { + return ((CompoundTag) nbt).getInt(path); + } + + @Override + public double getDouble(Object nbt, String path) { + return ((CompoundTag) nbt).getDouble(path); + } + + @Override + public long getLong(Object nbt, String path) { + return ((CompoundTag) nbt).getLong(path); + } + + @Override + public short getShort(Object nbt, String path) { + return ((CompoundTag) nbt).getShort(path); + } + + @Override + public float getFloat(Object nbt, String path) { + return ((CompoundTag) nbt).getFloat(path); + } + + @Override + public boolean getBoolean(Object nbt, String path) { + return ((CompoundTag) nbt).getBoolean(path); + } + + @Override + public int[] getIntArray(Object nbt, String path) { + return ((CompoundTag) nbt).getIntArray(path); + } + + @Override + public byte[] getByteArray(Object nbt, String path) { + return ((CompoundTag) nbt).getByteArray(path); + } + + @Override + public Object getNBTBase(Object nbt, String path) { + return ((CompoundTag) nbt).get(path); + } + + @Override + public Set getKeys(Object nbt) { + return ((CompoundTag) nbt).getAllKeys(); + } + + @Override + public boolean hasKey(Object nbt, String path) { + return ((CompoundTag) nbt).contains(path); + } + + @Override + public void removeKey(Object nbt, String path) { + ((CompoundTag) nbt).remove(path); + } + + @Override + public Object setByte(Object nbt, String path, byte value) { + ((CompoundTag) nbt).putByte(path, value); + return nbt; + } + + @Override + public byte getByte(Object nbt, String path) { + return ((CompoundTag) nbt).getByte(path); + } + + @Override + public Object getDataWatcher(Entity entity) { + return ((CraftEntity) entity).getHandle().getEntityData(); + } + + @Override + public Object getDataWatcher(Object entity) { + return ((net.minecraft.world.entity.Entity) entity).getEntityData(); + } + + @Override + public int incrementStateId(Object container) { + return ((AbstractContainerMenu) container).incrementStateId(); + } + + @Override + public Object packetEntityHeadRotation(Entity entity) { + return new ClientboundRotateHeadPacket((net.minecraft.world.entity.Entity) getEntity(entity), (byte) (entity.getLocation().getYaw() * 256F / 360F)); + } + + @Override + public Object packetHeldItemSlot(int slot) { + return new ClientboundSetCarriedItemPacket(slot); + } + + @Override + public Object packetExp(float exp, int total, int toNextLevel) { + return new ClientboundSetExperiencePacket(exp, total, toNextLevel); + } + + @Override + public Object packetPlayerInfo(PlayerInfoType type, Player player) { + ClientboundPlayerInfoUpdatePacket.Action action = null; + switch (type) { + case ADD_PLAYER: + action = ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER; + break; + case REMOVE_PLAYER: + return new ClientboundPlayerInfoRemovePacket(Arrays.asList(player.getUniqueId())); + case UPDATE_DISPLAY_NAME: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME; + break; + case UPDATE_GAME_MODE: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE; + break; + case UPDATE_LATENCY: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY; + break; + } + return new ClientboundPlayerInfoUpdatePacket(action, (ServerPlayer) getPlayer(player)); + } + + @Override + public Object packetPlayerInfo(PlayerInfoType type, GameProfileHandler gameProfile, int latency, GameMode gameMode, Component playerName) { + ClientboundPlayerInfoUpdatePacket.Action action = null; + switch (type) { + case ADD_PLAYER: + action = ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER; + break; + case REMOVE_PLAYER: + return new ClientboundPlayerInfoRemovePacket(Arrays.asList(gameProfile.getUUID())); + case UPDATE_DISPLAY_NAME: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME; + break; + case UPDATE_GAME_MODE: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_GAME_MODE; + break; + case UPDATE_LATENCY: + action = ClientboundPlayerInfoUpdatePacket.Action.UPDATE_LATENCY; + break; + } + + EnumSet set = EnumSet.of(action); + List list = Arrays.asList(new ClientboundPlayerInfoUpdatePacket.Entry(gameProfile.getUUID(), (GameProfile) toGameProfile(gameProfile), true, latency, + gameMode == null ? GameType.SURVIVAL : GameType.byName(gameMode.name().toLowerCase()), + (net.minecraft.network.chat.Component) (playerName == null ? toIChatBaseComponent(new Component(gameProfile.getUsername())) : toIChatBaseComponent(playerName)), null)); + return new ClientboundPlayerInfoUpdatePacket(set, list); + } + + @Override + public Object packetPosition(double x, double y, double z, float yaw, float pitch) { + return new ServerboundMovePlayerPacket.PosRot(x, y, z, yaw, pitch, true); + } + + @Override + public Object packetRespawn(Player player) { + ServerPlayer entityPlayer = (ServerPlayer) getPlayer(player); + return new ClientboundRespawnPacket(entityPlayer.createCommonSpawnInfo(entityPlayer.serverLevel()), (byte) 1); + } + + @Override + public String getProviderName() { + return "PaperMC 1.20.6"; + } + + @Override + public int getContainerStateId(Object container) { + return ((AbstractContainerMenu) container).getStateId(); + } + + @Override + public void loadParticles() { + for (Entry>, ParticleType> s : BuiltInRegistries.PARTICLE_TYPE.entrySet()) + me.devtec.theapi.bukkit.game.particles.Particle.identifier.put(s.getKey().location().getPath(), s.getValue()); + } + + @Override + public Object toGameProfile(GameProfileHandler gameProfileHandler) { + GameProfile profile = new GameProfile(gameProfileHandler.getUUID(), gameProfileHandler.getUsername()); + for (Entry entry : gameProfileHandler.getProperties().entrySet()) + profile.getProperties().put(entry.getKey(), new Property(entry.getValue().getName(), entry.getValue().getValues(), entry.getValue().getSignature())); + return profile; + } + + private Field name = Ref.field(Property.class, "name"), value = Ref.field(Property.class, "value"), signature = Ref.field(Property.class, "signature"); + + @Override + public GameProfileHandler fromGameProfile(Object gameProfile) { + GameProfile profile = (GameProfile) gameProfile; + GameProfileHandler handler = GameProfileHandler.of(profile.getName(), profile.getId()); + for (Entry entry : profile.getProperties().entries()) + handler.getProperties().put(entry.getKey(), + PropertyHandler.of((String) Ref.get(entry.getValue(), name), (String) Ref.get(entry.getValue(), value), (String) Ref.get(entry.getValue(), signature))); + return handler; + } + + @Override + public Object getGameProfile(Object nmsPlayer) { + return ((net.minecraft.world.entity.player.Player) nmsPlayer).getGameProfile(); + } + +} diff --git a/NmsProvider - 1.21/v1_21.jar b/NmsProvider - 1.21/v1_21.jar new file mode 100644 index 00000000..9fcefca5 Binary files /dev/null and b/NmsProvider - 1.21/v1_21.jar differ