From f793d2e301db4e466e47c090183829e893fca08a Mon Sep 17 00:00:00 2001 From: libraryaddict Date: Wed, 13 Dec 2023 22:55:36 +1300 Subject: [PATCH] Add support for 1.20.4 --- nms/pom.xml | 1 + nms/v1_20_R3/pom.xml | 116 ++++ .../v1_20_R3/ReflectionManager.java | 588 ++++++++++++++++++ plugin/pom.xml | 8 + .../libraryaddict/disguise/LibsDisguises.java | 57 +- .../disguise/disguisetypes/DisguiseType.java | 4 + .../disguise/disguisetypes/MetaIndex.java | 4 + .../disguisetypes/watchers/BreezeWatcher.java | 9 + .../disguisetypes/watchers/TNTWatcher.java | 14 + .../disguise/utilities/DisguiseUtilities.java | 36 +- .../utilities/reflection/NmsVersion.java | 3 +- .../reflection/ReflectionManager.java | 2 + .../utilities/sounds/DisguiseSoundEnums.java | 5 + pom.xml | 2 +- 14 files changed, 802 insertions(+), 47 deletions(-) create mode 100644 nms/v1_20_R3/pom.xml create mode 100644 nms/v1_20_R3/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20_R3/ReflectionManager.java create mode 100644 plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/BreezeWatcher.java diff --git a/nms/pom.xml b/nms/pom.xml index 34a22449..cca0f5a2 100644 --- a/nms/pom.xml +++ b/nms/pom.xml @@ -21,6 +21,7 @@ v1_19_R3 v1_20_R1 v1_20_R2 + v1_20_R3 diff --git a/nms/v1_20_R3/pom.xml b/nms/v1_20_R3/pom.xml new file mode 100644 index 00000000..98b73f7b --- /dev/null +++ b/nms/v1_20_R3/pom.xml @@ -0,0 +1,116 @@ + + + + nms + LibsDisguises + 1.0-SNAPSHOT + ../pom.xml + + + 4.0.0 + v1_20_R3 + 1.0-SNAPSHOT + + + 1.8 + 1.8 + UTF-8 + + 1.20.3-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 + + + + it.unimi.dsi + fastutil + 8.5.8 + provided + + + + com.mojang + authlib + 5.0.47 + 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_R3/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20_R3/ReflectionManager.java b/nms/v1_20_R3/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20_R3/ReflectionManager.java new file mode 100644 index 00000000..13540326 --- /dev/null +++ b/nms/v1_20_R3/src/main/java/me/libraryaddict/disguise/utilities/reflection/v1_20_R3/ReflectionManager.java @@ -0,0 +1,588 @@ +package me.libraryaddict.disguise.utilities.reflection.v1_20_R3; + +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.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.ClientInformation; +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.HumanoidArm; +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.entity.player.ChatVisiblity; +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_R3.CraftArt; +import org.bukkit.craftbukkit.v1_20_R3.CraftServer; +import org.bukkit.craftbukkit.v1_20_R3.CraftSound; +import org.bukkit.craftbukkit.v1_20_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_20_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftEntity; +import org.bukkit.craftbukkit.v1_20_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_20_R3.inventory.CraftItemStack; +import org.bukkit.craftbukkit.v1_20_R3.util.CraftMagicNumbers; +import org.bukkit.craftbukkit.v1_20_R3.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()) { + return null; + } + + 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"); + ClientInformation information = new ClientInformation("english", 10, ChatVisiblity.FULL, true, 0, HumanoidArm.RIGHT, true, true); + entity = new ServerPlayer(getMinecraftServer(), world, (GameProfile) gameProfile.getHandle(), information); + } 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; + } + + public MobEffect getMobEffectList(int id) { + return BuiltInRegistries.MOB_EFFECT.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 CraftSound.bukkitToMinecraftHolder(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.bukkitToMinecraft(art)).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 modifier = packet.getModifier(); + EnumSet enumSet = + EnumSet.copyOf(Arrays.stream(actions).map(action -> ClientboundPlayerInfoUpdatePacket.Action.valueOf(action.name())).collect(Collectors.toList())); + + modifier.write(0, enumSet); + modifier.write(1, Collections.singletonList(entry)); + + return packet; + } + + public Object getNmsEntity(Entity entity) { + return ((CraftEntity) entity).getHandle(); + } + + public double getPing(Player player) { + return player.getPing(); + } + + public float[] getSize(Entity entity) { + net.minecraft.world.entity.Entity nmsEntity = ((CraftEntity) entity).getHandle(); + EntityDimensions dimensions = nmsEntity.getDimensions(net.minecraft.world.entity.Pose.STANDING); + return new float[]{dimensions.width, nmsEntity.getEyeHeight()}; + } + + public WrappedGameProfile getSkullBlob(WrappedGameProfile gameProfile) { + DedicatedServer minecraftServer = getMinecraftServer(); + MinecraftSessionService sessionService = minecraftServer.getSessionService(); + return WrappedGameProfile.fromHandle(sessionService.fetchProfile(gameProfile.getUUID(), true).profile()); + } + + public Float getSoundModifier(Object entity) { + // Default is 1.0F on EntityLiving + if (!(entity instanceof net.minecraft.world.entity.LivingEntity)) { + return 0.0f; + } else { + try { + Method method = net.minecraft.world.entity.LivingEntity.class.getDeclaredMethod("eW"); + method.setAccessible(true); + + return (Float) method.invoke(entity); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + return 0f; + } + + public void injectCallback(String playername, ProfileLookupCallback callback) { + getMinecraftServer().getProfileRepository().findProfilesByNames(new String[]{playername}, callback); + } + + public void setBoundingBox(Entity entity, double x, double y, double z) { + Location loc = entity.getLocation(); + ((CraftEntity) entity).getHandle() + .setBoundingBox(new AABB(loc.getX() - x / 2, loc.getY() - y / 2, loc.getZ() - z / 2, loc.getX() + x / 2, loc.getY() + y / 2, loc.getZ() + z / 2)); + } + + public Enum getSoundCategory(String category) { + return Arrays.stream(SoundSource.values()).filter(soundSource -> category.equalsIgnoreCase(soundSource.getName())).findAny().get(); + } + + /** + * Creates the NMS object EnumItemSlot from an EquipmentSlot. + * + * @param slot + * @return null if the equipment slot is null + */ + public Enum createEnumItemSlot(EquipmentSlot slot) { + switch (slot) { + case HAND: + return net.minecraft.world.entity.EquipmentSlot.MAINHAND; + case OFF_HAND: + return net.minecraft.world.entity.EquipmentSlot.OFFHAND; + case FEET: + return net.minecraft.world.entity.EquipmentSlot.FEET; + case LEGS: + return net.minecraft.world.entity.EquipmentSlot.LEGS; + case CHEST: + return net.minecraft.world.entity.EquipmentSlot.CHEST; + case HEAD: + return net.minecraft.world.entity.EquipmentSlot.HEAD; + default: + return null; + } + } + + public Object getSoundString(Sound sound) { + return CraftSound.bukkitToMinecraft(sound).getLocation().toString(); + } + + public Optional convertOptional(Object val) { + if (val instanceof BlockPosition) { + BlockPosition pos = (BlockPosition) val; + return Optional.of(getBlockPosition(pos.getX(), pos.getY(), pos.getZ())); + } else if (val instanceof WrappedBlockData) { + Object obj = ((WrappedBlockData) val).getHandle(); + return Optional.of(obj); + } else if (val instanceof ItemStack) { + Object obj = getNmsItem((ItemStack) val); + return Optional.of(obj); + } else if (val instanceof WrappedChatComponent) { + Object obj = ((WrappedChatComponent) val).getHandle(); + return Optional.of(obj); + } + + return Optional.of(val); + } + + public Vector3f convertVec3(Object object) { + if (object instanceof Vector3F) { + Vector3F vector3F = (Vector3F) object; + return new Vector3f(vector3F.getX(), vector3F.getY(), vector3F.getZ()); + } else if (object instanceof EulerAngle) { + EulerAngle eulerAngle = (EulerAngle) object; + return new Vector3f((float) eulerAngle.getX(), (float) eulerAngle.getY(), (float) eulerAngle.getZ()); + } + + return null; + } + + public net.minecraft.core.Direction convertDirection(Direction direction) { + return net.minecraft.core.Direction.from3DDataValue(direction.ordinal()); + } + + public Material getMaterial(String name) { + return CraftMagicNumbers.INSTANCE.getMaterial(name, CraftMagicNumbers.INSTANCE.getDataVersion()); + } + + public String getItemName(Material material) { + return BuiltInRegistries.ITEM.getKey(CraftMagicNumbers.getItem(material)).getPath(); + } + + public net.minecraft.world.item.ItemStack getNmsItem(ItemStack itemStack) { + return CraftItemStack.asNMSCopy(itemStack); + } + + public VillagerData getNmsVillagerData(Villager.Type villagerType, Villager.Profession villagerProfession, int level) { + VillagerType nmsVillagerType = BuiltInRegistries.VILLAGER_TYPE.get(CraftNamespacedKey.toMinecraft(villagerType.getKey())); + VillagerProfession nmsVillagerProfession = BuiltInRegistries.VILLAGER_PROFESSION.get(CraftNamespacedKey.toMinecraft(villagerProfession.getKey())); + + return new net.minecraft.world.entity.npc.VillagerData(nmsVillagerType, nmsVillagerProfession, level); + } + + public VillagerType getVillagerType(Villager.Type type) { + return BuiltInRegistries.VILLAGER_TYPE.get(CraftNamespacedKey.toMinecraft(type.getKey())); + } + + public VillagerProfession getVillagerProfession(Villager.Profession profession) { + return BuiltInRegistries.VILLAGER_PROFESSION.get(CraftNamespacedKey.toMinecraft(profession.getKey())); + } + + public SynchedEntityData.DataItem createDataWatcherItem(WrappedDataWatcher.WrappedDataWatcherObject wrappedDataWatcherObject, T metaItem) { + return new SynchedEntityData.DataItem<>((EntityDataAccessor) wrappedDataWatcherObject.getHandle(), metaItem); + } + + public Holder createSoundEvent(String minecraftKey) { + return BuiltInRegistries.SOUND_EVENT.wrapAsHolder(SoundEvent.createVariableRangeEvent(createMinecraftKey(minecraftKey))); + } + + @Override + public ResourceLocation createMinecraftKey(String name) { + return new ResourceLocation(name); + } + + public Vec3 getVec3D(Vector vector) { + return new Vec3(vector.getX(), vector.getY(), vector.getZ()); + } + + public net.minecraft.world.entity.EntityType getEntityType(EntityType entityType) { + return net.minecraft.world.entity.EntityType.byString( + entityType.getName() == null ? entityType.name().toLowerCase(Locale.ENGLISH) : entityType.getName()).orElse(null); + } + + public Object registerEntityType(NamespacedKey key) { + net.minecraft.world.entity.EntityType newEntity = + new net.minecraft.world.entity.EntityType<>(null, null, false, false, false, false, null, null, 0, 0, FeatureFlagSet.of()); + Registry.register(BuiltInRegistries.ENTITY_TYPE, CraftNamespacedKey.toMinecraft(key), newEntity); + newEntity.getDescriptionId(); + return newEntity; // TODO ??? Some reflection in legacy that I'm unsure about + } + + public int getEntityTypeId(Object entityTypes) { + net.minecraft.world.entity.EntityType entityType = (net.minecraft.world.entity.EntityType) entityTypes; + + return BuiltInRegistries.ENTITY_TYPE.getId(entityType); + } + + public int getEntityTypeId(EntityType entityType) { + return getEntityTypeId(getEntityType(entityType)); + } + + public Object getEntityType(NamespacedKey name) { + return BuiltInRegistries.ENTITY_TYPE.get(CraftNamespacedKey.toMinecraft(name)); + } + + public Object getNmsEntityPose(String enumPose) { + return net.minecraft.world.entity.Pose.valueOf(enumPose); + } + + public int getCombinedIdByBlockData(BlockData data) { + BlockState state = ((CraftBlockData) data).getState(); + return Block.getId(state); + } + + public int getCombinedIdByItemStack(ItemStack itemStack) { + Block block = CraftMagicNumbers.getBlock(itemStack.getType()); + return Block.getId(block.defaultBlockState()); + } + + public BlockData getBlockDataByCombinedId(int id) { + return CraftBlockData.fromData(Block.stateById(id)); + } + + public ItemStack getItemStackByCombinedId(int id) { + return new ItemStack(CraftMagicNumbers.getMaterial(Block.stateById(id).getBlock())); + } + + public ServerLevel getWorldServer(World w) { + return ((CraftWorld) w).getHandle(); + } + + public ItemMeta getDeserializedItemMeta(Map meta) { + try { + Class aClass = Class.forName("org.bukkit.craftbukkit.v1_20_R3.inventory.CraftMetaItem$SerializableMeta"); + Method deserialize = aClass.getDeclaredMethod("deserialize", Map.class); + Object itemMeta = deserialize.invoke(null, meta); + + return (ItemMeta) itemMeta; + } catch (Exception e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public Object convertInvalidMeta(Object value) { + if (value instanceof Frog.Variant) { + return getFrogVariant((Frog.Variant) value); + } + + if (value instanceof Cat.Type) { + return getCatVariant((Cat.Type) value); + } + + if (value instanceof Art) { + return getArtVariant((Art) value); + } + + if (value instanceof BlockData) { + return ((CraftBlockData) value).getState(); + } + + if (value instanceof Sniffer.State) { + return net.minecraft.world.entity.animal.sniffer.Sniffer.State.values()[((Sniffer.State) value).ordinal()]; + } + + return value; + } + + private FrogVariant getFrogVariant(Frog.Variant variant) { + switch (variant) { + case COLD: + return FrogVariant.COLD; + case WARM: + return FrogVariant.WARM; + case TEMPERATE: + return FrogVariant.TEMPERATE; + } + + return null; + } + + private CatVariant getCatVariant(Cat.Type type) { + return BuiltInRegistries.CAT_VARIANT.byId(type.ordinal()); + } + + private Holder.Reference getArtVariant(Art art) { + return BuiltInRegistries.PAINTING_VARIANT.getHolder(art.ordinal()).get(); + } + + @Override + public Class getNmsClass(Class cl) { + if (Sniffer.State.class.isAssignableFrom(cl)) { + return net.minecraft.world.entity.animal.sniffer.Sniffer.State.class; + } + + return cl; + } +} diff --git a/plugin/pom.xml b/plugin/pom.xml index e1bb97cc..415ad0d8 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -259,6 +259,14 @@ compile true + + LibsDisguises + v1_20_R3 + 1.0-SNAPSHOT + remapped-spigot + compile + true + it.unimi.dsi diff --git a/plugin/src/main/java/me/libraryaddict/disguise/LibsDisguises.java b/plugin/src/main/java/me/libraryaddict/disguise/LibsDisguises.java index 06b7df57..0c667e8c 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/LibsDisguises.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/LibsDisguises.java @@ -209,33 +209,7 @@ public class LibsDisguises extends JavaPlugin { String requiredProtocolLib = StringUtils.join(DisguiseUtilities.getProtocolLibRequiredVersion(), " or build #"); String version = Bukkit.getPluginManager().getPlugin("ProtocolLib").getDescription().getVersion(); - BukkitRunnable runnable = new BukkitRunnable() { - private int timesRun; - - @Override - public void run() { - getLogger().severe("!! May I have your attention please !!"); - - if (DisguiseUtilities.isProtocollibUpdateDownloaded()) { - getLogger().severe( - "An update for ProtocolLib has been downloaded and will be installed when the server restarts. When possible, please restart " + - "the server. Lib's Disguises may not work correctly until you do so."); - } else { - getLogger().severe( - "Update your ProtocolLib! You are running " + version + " but the minimum version you should be on is " + requiredProtocolLib + - "!"); - getLogger().severe("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/target" + "/ProtocolLib" + ".jar"); - getLogger().severe("Or! Use /ld protocollib - To update to the latest development build"); - } - - if (timesRun++ > 0) { - getLogger().severe("This message is on repeat due to the sheer number of people who don't see this."); - } - - getLogger().severe("!! May I have your attention please !!"); - } - }; - + BukkitRunnable runnable = createProtocolLibOutdatedRunnable(version, requiredProtocolLib); runnable.run(); runnable.runTaskTimer(this, 20, 10 * 60 * 20); } @@ -320,6 +294,35 @@ public class LibsDisguises extends JavaPlugin { } } + @NotNull + private BukkitRunnable createProtocolLibOutdatedRunnable(String version, String requiredProtocolLib) { + return new BukkitRunnable() { + private int timesRun; + + @Override + public void run() { + getLogger().severe("!! May I have your attention please !!"); + + if (DisguiseUtilities.isProtocollibUpdateDownloaded()) { + getLogger().severe( + "An update for ProtocolLib has been downloaded and will be installed when the server restarts. When possible, please restart " + + "the server. Lib's Disguises may not work correctly until you do so."); + } else { + getLogger().severe( + "Update your ProtocolLib! You are running " + version + " but the minimum version you should be on is " + requiredProtocolLib + "!"); + getLogger().severe("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/target" + "/ProtocolLib" + ".jar"); + getLogger().severe("Or! Use /ld protocollib - To update to the latest development build"); + } + + if (timesRun++ > 0) { + getLogger().severe("This message is on repeat due to the sheer number of people who don't see this."); + } + + getLogger().severe("!! May I have your attention please !!"); + } + }; + } + public void unregisterCommands(boolean force) { CommandMap map = ReflectionManager.getCommandMap(); Map commands = ReflectionManager.getCommands(map); diff --git a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/DisguiseType.java b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/DisguiseType.java index f6d06b26..265f4b19 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/DisguiseType.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/DisguiseType.java @@ -33,6 +33,8 @@ public enum DisguiseType { BOAT(1), + @NmsAddedIn(NmsVersion.UNSUPPORTED) BREEZE, + @NmsAddedIn(NmsVersion.v1_20_R1) CAMEL, @NmsAddedIn(NmsVersion.v1_14) CAT, @@ -249,6 +251,8 @@ public enum DisguiseType { @NmsAddedIn(NmsVersion.v1_19_R1) WARDEN, + @NmsAddedIn(NmsVersion.UNSUPPORTED) WIND_CHARGE, + WITCH, WITHER, diff --git a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/MetaIndex.java b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/MetaIndex.java index 56dd8a05..7d2421ab 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/MetaIndex.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/MetaIndex.java @@ -786,6 +786,10 @@ public class MetaIndex { public static MetaIndex TNT_FUSE_TICKS = new MetaIndex<>(TNTWatcher.class, 0, Integer.MAX_VALUE); + @NmsAddedIn(NmsVersion.v1_20_R3) + public static MetaIndex TNT_BLOCK_TYPE = + new MetaIndex<>(TNTWatcher.class, 1, NmsVersion.v1_20_R3.isSupported() ? Bukkit.createBlockData(Material.TNT) : null); + public static MetaIndex TRIDENT_ENCHANTS = new MetaIndex<>(TridentWatcher.class, 0, (byte) 0); @NmsAddedIn(NmsVersion.v1_15) diff --git a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/BreezeWatcher.java b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/BreezeWatcher.java new file mode 100644 index 00000000..0114f72d --- /dev/null +++ b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/BreezeWatcher.java @@ -0,0 +1,9 @@ +package me.libraryaddict.disguise.disguisetypes.watchers; + +import me.libraryaddict.disguise.disguisetypes.Disguise; + +public class BreezeWatcher extends InsentientWatcher { + public BreezeWatcher(Disguise disguise) { + super(disguise); + } +} diff --git a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/TNTWatcher.java b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/TNTWatcher.java index 252018fb..76a5809e 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/TNTWatcher.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/disguisetypes/watchers/TNTWatcher.java @@ -2,9 +2,23 @@ package me.libraryaddict.disguise.disguisetypes.watchers; import me.libraryaddict.disguise.disguisetypes.Disguise; import me.libraryaddict.disguise.disguisetypes.FlagWatcher; +import me.libraryaddict.disguise.disguisetypes.MetaIndex; +import me.libraryaddict.disguise.utilities.reflection.NmsVersion; +import me.libraryaddict.disguise.utilities.reflection.annotations.NmsAddedIn; +import org.bukkit.block.data.BlockData; public class TNTWatcher extends FlagWatcher { public TNTWatcher(Disguise disguise) { super(disguise); } + + public BlockData getBlock() { + return getData(MetaIndex.TNT_BLOCK_TYPE); + } + + @NmsAddedIn(NmsVersion.v1_20_R3) + public void setBlock(BlockData block) { + setData(MetaIndex.TNT_BLOCK_TYPE, block); + sendData(MetaIndex.TNT_BLOCK_TYPE); + } } diff --git a/plugin/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java b/plugin/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java index d68fcae8..cabf0c64 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/utilities/DisguiseUtilities.java @@ -609,6 +609,11 @@ public class DisguiseUtilities { requiredVersion = new String[]{"5.1.1", "669"}; } + // If you're on 1.20.4 + if (NmsVersion.v1_20_R3.isSupported()) { + requiredVersion = new String[]{"5.2.0", "676"}; + } + return requiredVersion; } @@ -632,20 +637,21 @@ public class DisguiseUtilities { // If this is also checking for a custom build, and PL has the custom build in.. // We run this check first as the 4.7.1 isn't out, and it'd always tell us to update otherwise. if (reqVersion.length > 1 && plVersion.contains("-SNAPSHOT")) { - if (!plVersion.contains("-SNAPSHOT-b")) { + Matcher matcher = Pattern.compile("-SNAPSHOT-b?(\\d+)").matcher(plVersion); + + // Just incase they're running a custom build? + if (!matcher.find()) { return false; } try { - String build = plVersion.substring(plVersion.lastIndexOf("b") + 1); + int buildNo = Integer.parseInt(matcher.group(1)); - // Just incase they're running a custom build? - if (build.length() < 3) { + // Must be a custom build + if (buildNo < 100) { return false; } - int buildNo = Integer.parseInt(build); - return buildNo < Integer.parseInt(reqVersion[1]); } catch (Throwable ignored) { } @@ -689,6 +695,12 @@ public class DisguiseUtilities { // We're connecting to jenkins's API for ProtocolLib URL url = new URL("https://ci.dmulloy2.net/job/ProtocolLib/lastSuccessfulBuild/artifact/build/libs/ProtocolLib.jar"); + + // Bad workaround for failing jenkins + if (ReflectionManager.getVersion() == NmsVersion.v1_20_R3) { + url = new URL("https://ci.dmulloy2.net/job/ProtocolLib//lastBuild/artifact/build/libs/ProtocolLib.jar"); + } + // Creating a connection HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setRequestProperty("User-Agent", "libraryaddict/LibsDisguises"); @@ -751,18 +763,6 @@ public class DisguiseUtilities { } } - public static boolean isGrabSkinCommandUsed() { - return grabSkinCommandUsed; - } - - public static boolean isCopyDisguiseCommandUsed() { - return copyDisguiseCommandUsed; - } - - public static boolean isSaveDisguiseCommandUsed() { - return saveDisguiseCommandUsed; - } - public static void setPluginsUsed() { if (libsDisguisesCalled > System.currentTimeMillis()) { return; diff --git a/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/NmsVersion.java b/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/NmsVersion.java index 2022347f..c6d44650 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/NmsVersion.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/NmsVersion.java @@ -16,10 +16,11 @@ public enum NmsVersion { v1_19_R3, // 1.19.4 v1_20_R1, // 1.20 & 1.20.1 v1_20_R2, // 1.20.2 + v1_20_R3, // 1.20.3 UNSUPPORTED; /** - * If this nms version isn't newer than the running version + * If this enum version is older, or the same version as the current running server */ public boolean isSupported() { return ReflectionManager.getVersion() != null && ReflectionManager.getVersion().ordinal() >= ordinal(); diff --git a/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java b/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java index 86b4c3f8..5fbc1e51 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/utilities/reflection/ReflectionManager.java @@ -2333,6 +2333,8 @@ public class ReflectionManager { case WARDEN: case CAMEL: case SNIFFER: + case BREEZE: + case WIND_CHARGE: nmsEntityName = disguiseType.toReadable().replace(" ", ""); break; case DONKEY: diff --git a/plugin/src/main/java/me/libraryaddict/disguise/utilities/sounds/DisguiseSoundEnums.java b/plugin/src/main/java/me/libraryaddict/disguise/utilities/sounds/DisguiseSoundEnums.java index a163d66e..637867a4 100644 --- a/plugin/src/main/java/me/libraryaddict/disguise/utilities/sounds/DisguiseSoundEnums.java +++ b/plugin/src/main/java/me/libraryaddict/disguise/utilities/sounds/DisguiseSoundEnums.java @@ -35,6 +35,9 @@ public enum DisguiseSoundEnums { BOAT(null, Sound.ENTITY_BOAT_PADDLE_WATER, null, null, Sound.ENTITY_BOAT_PADDLE_LAND), + BREEZE(Sound.ENTITY_BREEZE_HURT, null, Sound.ENTITY_BREEZE_DEATH, new Sound[]{Sound.ENTITY_BREEZE_IDLE_AIR, Sound.ENTITY_BREEZE_IDLE_GROUND}, + Sound.ENTITY_BREEZE_LAND, Sound.ENTITY_BREEZE_JUMP, Sound.ENTITY_BREEZE_INHALE, Sound.ENTITY_BREEZE_SHOOT, Sound.ENTITY_BREEZE_SLIDE), + CAMEL(Sound.ENTITY_CAMEL_HURT, new Sound[]{Sound.ENTITY_CAMEL_STEP, Sound.ENTITY_CAMEL_STEP_SAND}, Sound.ENTITY_CAMEL_DEATH, Sound.ENTITY_CAMEL_AMBIENT, Sound.ENTITY_CAMEL_DASH, Sound.ENTITY_CAMEL_DASH_READY, Sound.ENTITY_CAMEL_EAT, Sound.ENTITY_CAMEL_SADDLE, Sound.ENTITY_CAMEL_SIT, Sound.ENTITY_CAMEL_STAND), @@ -257,6 +260,8 @@ public enum DisguiseSoundEnums { Sound.ENTITY_WARDEN_NEARBY_CLOSER, Sound.ENTITY_WARDEN_NEARBY_CLOSEST, Sound.ENTITY_WARDEN_SONIC_BOOM, Sound.ENTITY_WARDEN_SONIC_CHARGE, Sound.ENTITY_WARDEN_ROAR, Sound.ENTITY_WARDEN_SNIFF), + WINDCHARGE(null, null, Sound.ENTITY_GENERIC_WIND_BURST, null), + WITCH(Sound.ENTITY_WITCH_HURT, null, Sound.ENTITY_WITCH_DEATH, Sound.ENTITY_WITCH_AMBIENT), WITHER(Sound.ENTITY_WITHER_HURT, null, Sound.ENTITY_WITHER_DEATH, Sound.ENTITY_WITHER_AMBIENT, Sound.ENTITY_PLAYER_SMALL_FALL, Sound.ENTITY_WITHER_SPAWN, diff --git a/pom.xml b/pom.xml index 24eed8d3..52f0ae87 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,7 @@ 1.18.26 5.0.0 - 1.20.2-R0.1-SNAPSHOT + 1.20.3-R0.1-SNAPSHOT 4.13.2 5.9.3 1.19.4-R0.1-SNAPSHOT