diff --git a/nms/pom.xml b/nms/pom.xml
index 4da2f5b7..6657a715 100644
--- a/nms/pom.xml
+++ b/nms/pom.xml
@@ -19,6 +19,7 @@
v1_19_R1
v1_19_R2
v1_19_R3
+ v1_20_R1
diff --git a/nms/v1_20_R1/pom.xml b/nms/v1_20_R1/pom.xml
new file mode 100644
index 00000000..343b03b5
--- /dev/null
+++ b/nms/v1_20_R1/pom.xml
@@ -0,0 +1,123 @@
+
+
+
+ nms
+ LibsDisguises
+ 1.0-SNAPSHOT
+ ../pom.xml
+
+
+ 4.0.0
+ v1_20_R1
+ 1.0-SNAPSHOT
+
+
+ 1.8
+ 1.8
+ UTF-8
+
+ 1.20-R0.1-SNAPSHOT
+
+
+
+
+ org.spigotmc
+ spigot
+ ${spigot.version}
+ remapped-mojang
+ provided
+
+
+ org.spigotmc
+ spigot-api
+ ${spigot.version}
+ provided
+
+
+ LibsDisguises
+ shared
+ 1.0-SNAPSHOT
+
+
+ com.comphenix.protocol
+ ProtocolLib
+
+
+
+ com.mojang
+ authlib
+ 3.3.39
+ provided
+
+
+
+ it.unimi.dsi
+ fastutil
+ 8.5.8
+ provided
+
+
+
+ com.mojang
+ authlib
+ 3.5.41
+ provided
+
+
+
+ com.mojang
+ datafixerupper
+ 5.0.28
+ provided
+
+
+
+ com.mojang
+ brigadier
+ 1.0.18
+ compile
+
+
+
+
+
+
+ net.md-5
+ specialsource-maven-plugin
+ 1.2.4
+
+
+ package
+
+ remap
+
+ remap-obf
+
+ org.spigotmc:minecraft-server:${spigot.version}:txt:maps-mojang
+ true
+ org.spigotmc:spigot:${spigot.version}:jar:remapped-mojang
+ remapped-mojang
+ true
+
+
+
+ package
+
+ remap
+
+ remap-spigot
+
+ target/${project.build.finalName}-remapped-mojang.jar
+ org.spigotmc:minecraft-server:${spigot.version}:csrg:maps-spigot
+ org.spigotmc:spigot:${spigot.version}:jar:remapped-obf
+ remapped-spigot
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/nms/v1_20_R1/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20/ReflectionManager.java b/nms/v1_20_R1/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20/ReflectionManager.java
new file mode 100644
index 00000000..7404263a
--- /dev/null
+++ b/nms/v1_20_R1/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20/ReflectionManager.java
@@ -0,0 +1,585 @@
+package me.libraryaddict.disguise.utilities.reflection.v1_20;
+
+import com.comphenix.protocol.PacketType;
+import com.comphenix.protocol.events.PacketContainer;
+import com.comphenix.protocol.events.PacketEvent;
+import com.comphenix.protocol.reflect.StructureModifier;
+import com.comphenix.protocol.wrappers.BlockPosition;
+import com.comphenix.protocol.wrappers.EnumWrappers;
+import com.comphenix.protocol.wrappers.EnumWrappers.Direction;
+import com.comphenix.protocol.wrappers.Vector3F;
+import com.comphenix.protocol.wrappers.WrappedBlockData;
+import com.comphenix.protocol.wrappers.WrappedChatComponent;
+import com.comphenix.protocol.wrappers.WrappedDataWatcher;
+import com.comphenix.protocol.wrappers.WrappedGameProfile;
+import com.mojang.authlib.Agent;
+import com.mojang.authlib.GameProfile;
+import com.mojang.authlib.ProfileLookupCallback;
+import com.mojang.authlib.minecraft.MinecraftSessionService;
+import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
+import me.libraryaddict.disguise.utilities.reflection.ReflectionManagerAbstract;
+import net.minecraft.core.BlockPos;
+import net.minecraft.core.Holder;
+import net.minecraft.core.Registry;
+import net.minecraft.core.Vector3f;
+import net.minecraft.core.registries.BuiltInRegistries;
+import net.minecraft.network.chat.Component;
+import net.minecraft.network.protocol.game.ClientboundPlayerInfoUpdatePacket;
+import net.minecraft.network.syncher.EntityDataAccessor;
+import net.minecraft.network.syncher.SynchedEntityData;
+import net.minecraft.resources.ResourceLocation;
+import net.minecraft.server.dedicated.DedicatedServer;
+import net.minecraft.server.level.ChunkMap;
+import net.minecraft.server.level.ServerChunkCache;
+import net.minecraft.server.level.ServerEntity;
+import net.minecraft.server.level.ServerLevel;
+import net.minecraft.server.level.ServerPlayer;
+import net.minecraft.server.network.ServerGamePacketListenerImpl;
+import net.minecraft.server.network.ServerPlayerConnection;
+import net.minecraft.sounds.SoundEvent;
+import net.minecraft.sounds.SoundSource;
+import net.minecraft.world.effect.MobEffect;
+import net.minecraft.world.effect.MobEffectInstance;
+import net.minecraft.world.entity.EntityDimensions;
+import net.minecraft.world.entity.animal.CatVariant;
+import net.minecraft.world.entity.animal.FrogVariant;
+import net.minecraft.world.entity.decoration.PaintingVariant;
+import net.minecraft.world.entity.npc.VillagerData;
+import net.minecraft.world.entity.npc.VillagerProfession;
+import net.minecraft.world.entity.npc.VillagerType;
+import net.minecraft.world.flag.FeatureFlagSet;
+import net.minecraft.world.level.GameType;
+import net.minecraft.world.level.block.Block;
+import net.minecraft.world.level.block.state.BlockState;
+import net.minecraft.world.phys.AABB;
+import net.minecraft.world.phys.Vec3;
+import org.bukkit.Art;
+import org.bukkit.Bukkit;
+import org.bukkit.Location;
+import org.bukkit.Material;
+import org.bukkit.NamespacedKey;
+import org.bukkit.Sound;
+import org.bukkit.World;
+import org.bukkit.block.data.BlockData;
+import org.bukkit.craftbukkit.v1_20_R1.CraftArt;
+import org.bukkit.craftbukkit.v1_20_R1.CraftServer;
+import org.bukkit.craftbukkit.v1_20_R1.CraftSound;
+import org.bukkit.craftbukkit.v1_20_R1.CraftWorld;
+import org.bukkit.craftbukkit.v1_20_R1.block.data.CraftBlockData;
+import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer;
+import org.bukkit.craftbukkit.v1_20_R1.inventory.CraftItemStack;
+import org.bukkit.craftbukkit.v1_20_R1.util.CraftMagicNumbers;
+import org.bukkit.craftbukkit.v1_20_R1.util.CraftNamespacedKey;
+import org.bukkit.entity.Cat;
+import org.bukkit.entity.Entity;
+import org.bukkit.entity.EntityType;
+import org.bukkit.entity.Frog;
+import org.bukkit.entity.Player;
+import org.bukkit.entity.Sniffer;
+import org.bukkit.entity.Villager;
+import org.bukkit.inventory.EquipmentSlot;
+import org.bukkit.inventory.ItemStack;
+import org.bukkit.inventory.meta.ItemMeta;
+import org.bukkit.potion.PotionEffect;
+import org.bukkit.util.EulerAngle;
+import org.bukkit.util.Vector;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Optional;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+public class ReflectionManager implements ReflectionManagerAbstract {
+ public boolean hasInvul(Entity entity) {
+ net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle();
+
+ if (nmsEntity instanceof net.minecraft.world.entity.LivingEntity) {
+ return nmsEntity.invulnerableTime > 0;
+ } else {
+ return nmsEntity.isInvulnerableTo(nmsEntity.damageSources().generic());
+ }
+ }
+
+ public int getIncrementedStateId(Player player) {
+ ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
+ return serverPlayer.containerMenu.incrementStateId(); // TODO Check correct container
+ }
+
+ public int getNewEntityId() {
+ return getNewEntityId(true);
+ }
+
+ public int getNewEntityId(boolean increment) {
+ try {
+ Field entityCounter = net.minecraft.world.entity.Entity.class.getDeclaredField("d");
+ entityCounter.setAccessible(true);
+ AtomicInteger atomicInteger = (AtomicInteger) entityCounter.get(null);
+ if (increment) {
+ return atomicInteger.incrementAndGet();
+ } else {
+ return atomicInteger.get();
+ }
+ } catch (ReflectiveOperationException e) {
+ e.printStackTrace();
+ }
+
+ return -1;
+ }
+
+ public ServerGamePacketListenerImpl getPlayerConnectionOrPlayer(Player player) {
+ return ((CraftPlayer) player).getHandle().connection;
+ }
+
+ public net.minecraft.world.entity.Entity createEntityInstance(String entityName) {
+ Optional> optional = net.minecraft.world.entity.EntityType.byString(entityName.toLowerCase(Locale.ROOT));
+ if (optional.isPresent()) {
+ net.minecraft.world.entity.EntityType> entityType = optional.get();
+ ServerLevel world = getWorldServer(Bukkit.getWorlds().get(0));
+ net.minecraft.world.entity.Entity entity;
+ if (entityType == net.minecraft.world.entity.EntityType.PLAYER) {
+ WrappedGameProfile gameProfile = ReflectionManagerAbstract.getGameProfile(new UUID(0, 0), "Steve");
+ entity = new ServerPlayer(getMinecraftServer(), world, (GameProfile) gameProfile.getHandle());
+ } else {
+ entity = entityType.create(world);
+ }
+
+ if (entity == null) {
+ return null;
+ }
+
+ // Workaround for paper being 2 smart 4 me
+ entity.setPos(1.0, 1.0, 1.0);
+ entity.setPos(0.0, 0.0, 0.0);
+ return entity;
+ }
+
+ return null;
+ }
+
+ public MobEffect getMobEffectList(int id) {
+ return MobEffect.byId(id);
+ }
+
+ public MobEffectInstance createMobEffect(PotionEffect effect) {
+ return createMobEffect(effect.getType().getId(), effect.getDuration(), effect.getAmplifier(), effect.isAmbient(), effect.hasParticles());
+ }
+
+ public MobEffectInstance createMobEffect(int id, int duration, int amplification, boolean ambient, boolean particles) {
+ return new MobEffectInstance(getMobEffectList(id), duration, amplification, ambient, particles);
+ }
+
+ public AABB getBoundingBox(Entity entity) {
+ return ((CraftEntity) entity).getHandle().getBoundingBox();
+ }
+
+ public double getXBoundingBox(Entity entity) {
+ return getBoundingBox(entity).maxX - getBoundingBox(entity).minX;
+ }
+
+ public double getYBoundingBox(Entity entity) {
+ return getBoundingBox(entity).maxY - getBoundingBox(entity).minY;
+ }
+
+ public double getZBoundingBox(Entity entity) {
+ return getBoundingBox(entity).maxZ - getBoundingBox(entity).minZ;
+ }
+
+ public ServerPlayer getPlayerFromPlayerConnection(Object nmsEntity) {
+ return ((ServerPlayerConnection) nmsEntity).getPlayer();
+ }
+
+ public Entity getBukkitEntity(Object nmsEntity) {
+ return ((net.minecraft.world.entity.Entity) nmsEntity).getBukkitEntity();
+ }
+
+ public ItemStack getBukkitItem(Object nmsItem) {
+ return CraftItemStack.asBukkitCopy((net.minecraft.world.item.ItemStack) nmsItem);
+ }
+
+ public ItemStack getCraftItem(ItemStack bukkitItem) {
+ return CraftItemStack.asCraftCopy(bukkitItem);
+ }
+
+ public Holder getCraftSound(Sound sound) {
+ return BuiltInRegistries.SOUND_EVENT.wrapAsHolder(CraftSound.getSoundEffect(sound));
+ }
+
+ public ServerEntity getEntityTrackerEntry(Entity target) throws Exception {
+ ServerLevel world = ((CraftWorld) target.getWorld()).getHandle();
+ ServerChunkCache chunkSource = world.getChunkSource();
+ ChunkMap chunkMap = chunkSource.chunkMap;
+ Int2ObjectMap entityMap = chunkMap.entityMap;
+ ChunkMap.TrackedEntity trackedEntity = entityMap.get(target.getEntityId());
+ if (trackedEntity == null) {
+ return null;
+ }
+
+ Field field = ChunkMap.TrackedEntity.class.getDeclaredField("b");
+ field.setAccessible(true);
+
+ return (ServerEntity) field.get(trackedEntity);
+ }
+
+ public DedicatedServer getMinecraftServer() {
+ return ((CraftServer) Bukkit.getServer()).getServer();
+ }
+
+ public String getEnumArt(Art art) {
+ return BuiltInRegistries.PAINTING_VARIANT.getKey(CraftArt.BukkitToNotch(art).value()).getPath();
+ }
+
+ public BlockPos getBlockPosition(int x, int y, int z) {
+ return new BlockPos(x, y, z);
+ }
+
+ public net.minecraft.core.Direction getEnumDirection(int direction) {
+ return net.minecraft.core.Direction.from2DDataValue(direction);
+ }
+
+ @Override
+ public void handleTablistPacket(PacketEvent event, Function shouldRemove) {
+ ClientboundPlayerInfoUpdatePacket packet = (ClientboundPlayerInfoUpdatePacket) event.getPacket().getHandle();
+
+ if (!packet.actions().contains(ClientboundPlayerInfoUpdatePacket.Action.ADD_PLAYER)) {
+ return;
+ }
+
+ List canKeep = new ArrayList<>();
+
+ for (ClientboundPlayerInfoUpdatePacket.Entry entry : packet.entries()) {
+ if (shouldRemove.apply(entry.profileId())) {
+ continue;
+ }
+
+ canKeep.add(entry);
+ }
+
+ if (canKeep.size() == packet.entries().size()) {
+ return;
+ }
+
+ if (canKeep.isEmpty()) {
+ event.setCancelled(true);
+ return;
+ }
+
+ event.getPacket().getModifier().write(1, canKeep);
+ }
+
+ public PacketContainer getTabListPacket(String displayName, WrappedGameProfile gameProfile, boolean nameVisible, EnumWrappers.PlayerInfoAction... actions) {
+ if (actions[0] == EnumWrappers.PlayerInfoAction.REMOVE_PLAYER) {
+ PacketContainer packet = new PacketContainer(PacketType.Play.Server.PLAYER_INFO_REMOVE);
+ packet.getModifier().write(0, Collections.singletonList(gameProfile.getUUID()));
+
+ return packet;
+ }
+
+ ClientboundPlayerInfoUpdatePacket.Entry entry =
+ new ClientboundPlayerInfoUpdatePacket.Entry(gameProfile.getUUID(), (GameProfile) gameProfile.getHandle(), nameVisible, 0, GameType.SURVIVAL,
+ Component.literal(displayName), null);
+
+ PacketContainer packet = new PacketContainer(PacketType.Play.Server.PLAYER_INFO);
+ StructureModifier