Update for 1.15
This commit is contained in:
		
							
								
								
									
										4
									
								
								pom.xml
									
									
									
									
									
								
							
							
						
						
									
										4
									
								
								pom.xml
									
									
									
									
									
								
							| @@ -53,12 +53,12 @@ | ||||
|         <dependency> | ||||
|             <groupId>org.spigotmc</groupId> | ||||
|             <artifactId>spigot-api</artifactId> | ||||
|             <version>1.14-R0.1-SNAPSHOT</version> | ||||
|             <version>1.15-R0.1-SNAPSHOT</version> | ||||
|         </dependency> | ||||
|         <dependency> | ||||
|             <groupId>org.spigotmc</groupId> | ||||
|             <artifactId>spigot</artifactId> | ||||
|             <version>1.14-R0.1-SNAPSHOT</version> | ||||
|             <version>1.15-R0.1-SNAPSHOT</version> | ||||
|         </dependency> | ||||
|         <!-- testing --> | ||||
|         <dependency> | ||||
|   | ||||
| @@ -60,7 +60,7 @@ public class LibsDisguises extends JavaPlugin { | ||||
|                     "Blocks, Admins)"); | ||||
|         } | ||||
|  | ||||
|         if (!ReflectionManager.getMinecraftVersion().startsWith("1.14.4")) { | ||||
|         if (!ReflectionManager.getMinecraftVersion().startsWith("1.15")) { | ||||
|             getLogger().severe("You're using the wrong version of Lib's Disguises for your server! This is " + | ||||
|                     "intended for 1.14.4!"); | ||||
|             getPluginLoader().disablePlugin(this); | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import me.libraryaddict.disguise.utilities.translations.TranslateType; | ||||
| import org.apache.commons.lang.StringUtils; | ||||
| import org.bukkit.entity.Entity; | ||||
| import org.bukkit.entity.EntityType; | ||||
| import org.omg.CORBA.UNKNOWN; | ||||
|  | ||||
| public enum DisguiseType { | ||||
|     AREA_EFFECT_CLOUD(3, 0), | ||||
| @@ -14,6 +15,8 @@ public enum DisguiseType { | ||||
|  | ||||
|     BAT, | ||||
|  | ||||
|     BEE, | ||||
|  | ||||
|     BLAZE, | ||||
|  | ||||
|     BOAT(1), | ||||
|   | ||||
| @@ -108,6 +108,10 @@ public class MetaIndex<Y> { | ||||
|      */ | ||||
|     public static MetaIndex<Byte> BAT_HANGING = new MetaIndex<>(BatWatcher.class, 0, (byte) 1); | ||||
|  | ||||
|     public static MetaIndex<Byte> BEE_META = new MetaIndex<>(BeeWatcher.class, 0, (byte) 0); | ||||
|  | ||||
|     public static MetaIndex<Integer> BEE_ANGER = new MetaIndex<>(BeeWatcher.class, 1, 0); | ||||
|  | ||||
|     /** | ||||
|      * If the blaze is ignited, false/true state | ||||
|      */ | ||||
| @@ -195,6 +199,8 @@ public class MetaIndex<Y> { | ||||
|      */ | ||||
|     public static MetaIndex<Boolean> ENDERMAN_AGRESSIVE = new MetaIndex<>(EndermanWatcher.class, 1, false); | ||||
|  | ||||
|     public static MetaIndex<Boolean> ENDERMAN_UNKNOWN = new MetaIndex<>(EndermanWatcher.class, 2, false); | ||||
|  | ||||
|     /** | ||||
|      * What block the enderman is holding | ||||
|      */ | ||||
| @@ -342,7 +348,12 @@ public class MetaIndex<Y> { | ||||
|      */ | ||||
|     public static MetaIndex<Integer> LIVING_POTIONS = new MetaIndex<>(LivingWatcher.class, 2, 0); | ||||
|  | ||||
|     public static MetaIndex<Optional<BlockPosition>> LIVING_BED_POSITION = new MetaIndex<>(LivingWatcher.class, 5, | ||||
|     /** | ||||
|      * How many bee stings does the entity have | ||||
|      */ | ||||
|     public static MetaIndex<Integer> LIVING_STINGS = new MetaIndex<>(LivingWatcher.class, 5, 0); | ||||
|  | ||||
|     public static MetaIndex<Optional<BlockPosition>> LIVING_BED_POSITION = new MetaIndex<>(LivingWatcher.class, 6, | ||||
|             Optional.empty()); | ||||
|  | ||||
|     /** | ||||
| @@ -477,6 +488,8 @@ public class MetaIndex<Y> { | ||||
|  | ||||
|     public static MetaIndex<Byte> TRIDENT_ENCHANTS = new MetaIndex<>(TridentWatcher.class, 0, (byte) 0); | ||||
|  | ||||
|     public static MetaIndex<Boolean> TRIDENT_ENCHANTED = new MetaIndex<>(TridentWatcher.class, 1, false); | ||||
|  | ||||
|     public static MetaIndex<Integer> TROPICAL_FISH_VARIANT = new MetaIndex<>(TropicalFishWatcher.class, 0, 0); | ||||
|  | ||||
|     public static MetaIndex<BlockPosition> TURTLE_HOME_POSITION = new MetaIndex<>(TurtleWatcher.class, 0, | ||||
| @@ -512,11 +525,9 @@ public class MetaIndex<Y> { | ||||
|  | ||||
|     public static MetaIndex<Boolean> WITHER_SKULL_BLUE = new MetaIndex<>(WitherSkullWatcher.class, 0, false); | ||||
|  | ||||
|     public static MetaIndex<Boolean> WOLF_BEGGING = new MetaIndex<>(WolfWatcher.class, 1, false); | ||||
|     public static MetaIndex<Boolean> WOLF_BEGGING = new MetaIndex<>(WolfWatcher.class, 0, false); | ||||
|  | ||||
|     public static MetaIndex<Integer> WOLF_COLLAR = new MetaIndex<>(WolfWatcher.class, 2, 14); | ||||
|  | ||||
|     public static MetaIndex<Float> WOLF_DAMAGE = new MetaIndex<>(WolfWatcher.class, 0, 1F); | ||||
|     public static MetaIndex<Integer> WOLF_COLLAR = new MetaIndex<>(WolfWatcher.class, 1, 14); | ||||
|  | ||||
|     public static MetaIndex<Boolean> ZOMBIE_BABY = new MetaIndex<>(ZombieWatcher.class, 0, false); | ||||
|  | ||||
|   | ||||
| @@ -0,0 +1,63 @@ | ||||
| package me.libraryaddict.disguise.disguisetypes.watchers; | ||||
|  | ||||
| import me.libraryaddict.disguise.disguisetypes.Disguise; | ||||
| import me.libraryaddict.disguise.disguisetypes.MetaIndex; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 14/12/2019. | ||||
|  */ | ||||
| public class BeeWatcher extends AgeableWatcher { | ||||
|     public BeeWatcher(Disguise disguise) { | ||||
|         super(disguise); | ||||
|     } | ||||
|  | ||||
|     public void setBeeAnger(int beeAnger) { | ||||
|         setData(MetaIndex.BEE_ANGER, beeAnger); | ||||
|         sendData(MetaIndex.BEE_ANGER); | ||||
|     } | ||||
|  | ||||
|     public int getBeeAnger() { | ||||
|         return getData(MetaIndex.BEE_ANGER); | ||||
|     } | ||||
|  | ||||
|     public void setHasNectar(boolean hasNectar) { | ||||
|         setBeeFlag(8, hasNectar); | ||||
|     } | ||||
|  | ||||
|     public boolean hasNectar() { | ||||
|         return getBeeFlag(8); | ||||
|     } | ||||
|  | ||||
|     public void setHasStung(boolean hasStung) { | ||||
|         setBeeFlag(4, hasStung); | ||||
|     } | ||||
|  | ||||
|     public boolean hasStung() { | ||||
|         return getBeeFlag(4); | ||||
|     } | ||||
|  | ||||
|     public void setFlipped(boolean isFlipped) { | ||||
|         setBeeFlag(2, isFlipped); | ||||
|     } | ||||
|  | ||||
|     public boolean isFlipped() { | ||||
|         return getBeeFlag(2); | ||||
|     } | ||||
|  | ||||
|     private boolean getBeeFlag(int value) { | ||||
|         return (getData(MetaIndex.PANDA_META) & value) != 0; | ||||
|     } | ||||
|  | ||||
|     private void setBeeFlag(int no, boolean flag) { | ||||
|         byte b1 = getData(MetaIndex.BEE_META); | ||||
|  | ||||
|         if (flag) { | ||||
|             b1 = (byte) (b1 | no); | ||||
|         } else { | ||||
|             b1 = (byte) (b1 & ~no); | ||||
|         } | ||||
|  | ||||
|         setData(MetaIndex.BEE_META, b1); | ||||
|         sendData(MetaIndex.BEE_META); | ||||
|     } | ||||
| } | ||||
| @@ -55,4 +55,9 @@ public class EndermanWatcher extends InsentientWatcher { | ||||
|         setData(MetaIndex.ENDERMAN_AGRESSIVE, isAggressive); | ||||
|         sendData(MetaIndex.ENDERMAN_AGRESSIVE); | ||||
|     } | ||||
|  | ||||
|     public void setUnknown(boolean bo) { | ||||
|         setData(MetaIndex.ENDERMAN_UNKNOWN, bo); | ||||
|         sendData(MetaIndex.ENDERMAN_UNKNOWN); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,6 @@ | ||||
| package me.libraryaddict.disguise.disguisetypes.watchers; | ||||
|  | ||||
| import me.libraryaddict.disguise.disguisetypes.Disguise; | ||||
| import net.minecraft.server.v1_14_R1.EntityRaider; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 9/06/2017. | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package me.libraryaddict.disguise.disguisetypes.watchers; | ||||
|  | ||||
| import me.libraryaddict.disguise.disguisetypes.Disguise; | ||||
| import me.libraryaddict.disguise.disguisetypes.MetaIndex; | ||||
|  | ||||
| /** | ||||
|  * Created by libraryaddict on 6/08/2018. | ||||
| @@ -9,4 +10,13 @@ public class TridentWatcher extends ArrowWatcher { | ||||
|     public TridentWatcher(Disguise disguise) { | ||||
|         super(disguise); | ||||
|     } | ||||
|  | ||||
|     public void setEnchanted(boolean enchanted) { | ||||
|         setData(MetaIndex.TRIDENT_ENCHANTED, enchanted); | ||||
|         sendData(MetaIndex.TRIDENT_ENCHANTED); | ||||
|     } | ||||
|  | ||||
|     public boolean isEnchanted() { | ||||
|         return getData(MetaIndex.TRIDENT_ENCHANTED); | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -15,25 +15,6 @@ public class WolfWatcher extends TameableWatcher { | ||||
|         return AnimalColor.getColorByWool(getData(MetaIndex.WOLF_COLLAR)); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Used for tail rotation. | ||||
|      * | ||||
|      * @return | ||||
|      */ | ||||
|     public float getDamageTaken() { | ||||
|         return getData(MetaIndex.WOLF_DAMAGE); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * Used for tail rotation. | ||||
|      * | ||||
|      * @param damage | ||||
|      */ | ||||
|     public void setDamageTaken(float damage) { | ||||
|         setData(MetaIndex.WOLF_DAMAGE, damage); | ||||
|         sendData(MetaIndex.WOLF_DAMAGE); | ||||
|     } | ||||
|  | ||||
|     public boolean isBegging() { | ||||
|         return getData(MetaIndex.WOLF_BEGGING); | ||||
|     } | ||||
|   | ||||
| @@ -19,6 +19,9 @@ public enum DisguiseSound { | ||||
|     BAT(Sound.ENTITY_BAT_HURT, null, Sound.ENTITY_BAT_DEATH, Sound.ENTITY_BAT_AMBIENT, Sound.ENTITY_PLAYER_SMALL_FALL, | ||||
|             Sound.ENTITY_BAT_LOOP, Sound.ENTITY_PLAYER_BIG_FALL, Sound.ENTITY_BAT_TAKEOFF), | ||||
|  | ||||
|     BEE(Sound.ENTITY_BEE_HURT, null, Sound.ENTITY_BEE_DEATH, null, Sound.ENTITY_BEE_LOOP, | ||||
|             Sound.ENTITY_BEE_LOOP_AGGRESSIVE, Sound.ENTITY_BEE_POLLINATE, Sound.ENTITY_BEE_STING), | ||||
|  | ||||
|     BLAZE(Sound.ENTITY_BLAZE_HURT, null, Sound.ENTITY_BLAZE_DEATH, Sound.ENTITY_BLAZE_AMBIENT, | ||||
|             Sound.ENTITY_PLAYER_SMALL_FALL, Sound.ENTITY_PLAYER_BIG_FALL, Sound.ENTITY_BLAZE_BURN, | ||||
|             Sound.ENTITY_BLAZE_SHOOT), | ||||
|   | ||||
| @@ -525,62 +525,6 @@ public class DisguiseUtilities { | ||||
|         return cord; | ||||
|     } | ||||
|  | ||||
|     public static PacketContainer[] getBedChunkPacket(Location newLoc, Location oldLoc) { | ||||
|         int i = 0; | ||||
|  | ||||
|         PacketContainer[] packets = new PacketContainer[(newLoc != null ? 1 : 0) + (oldLoc != null ? 1 : 0)]; | ||||
|  | ||||
|         if (oldLoc != null) { | ||||
|             PacketContainer despawn = new PacketContainer(Server.UNLOAD_CHUNK); | ||||
|  | ||||
|             StructureModifier<Object> modifier = despawn.getModifier(); | ||||
|  | ||||
|             modifier.write(0, getChunkCord(oldLoc.getBlockX())); | ||||
|             modifier.write(1, getChunkCord(oldLoc.getBlockZ())); | ||||
|  | ||||
|             packets[i++] = despawn; | ||||
|         } | ||||
|  | ||||
|         if (newLoc != null) { | ||||
|             PacketContainer spawn = spawnChunk.shallowClone(); | ||||
|  | ||||
|             StructureModifier<Object> modifier = spawn.getModifier(); | ||||
|  | ||||
|             modifier.write(0, getChunkCord(newLoc.getBlockX())); | ||||
|             modifier.write(1, getChunkCord(newLoc.getBlockZ())); | ||||
|  | ||||
|             packets[i++] = spawn; | ||||
|         } | ||||
|  | ||||
|         return packets; | ||||
|     } | ||||
|  | ||||
|     public static PacketContainer[] getBedPackets(Location sleepingLocation, Location playerLocation, | ||||
|             PlayerDisguise disguise) { | ||||
|         int entity = disguise.getEntity().getEntityId(); | ||||
|         PlayerWatcher watcher = disguise.getWatcher(); | ||||
|  | ||||
|         //PacketContainer setBed = new PacketContainer(Server.BED); | ||||
|  | ||||
|         int bX = (getChunkCord(playerLocation.getBlockX()) * 16) + 1 + watcher.getSleepingDirection().getModX(); | ||||
|         int bZ = (getChunkCord(playerLocation.getBlockZ()) * 16) + 1 + watcher.getSleepingDirection().getModZ(); | ||||
|  | ||||
|         // setBed.getIntegers().write(0, entity); | ||||
|         // setBed.getBlockPositionModifier().write(0, new BlockPosition(bX, 0, bZ)); | ||||
|  | ||||
|         PacketContainer teleport = new PacketContainer(Server.ENTITY_TELEPORT); | ||||
|  | ||||
|         StructureModifier<Double> doubles = teleport.getDoubles(); | ||||
|  | ||||
|         teleport.getIntegers().write(0, entity); | ||||
|  | ||||
|         doubles.write(0, sleepingLocation.getX()); | ||||
|         doubles.write(1, DisguiseUtilities.getYModifier(disguise.getEntity(), disguise) + sleepingLocation.getY()); | ||||
|         doubles.write(2, sleepingLocation.getZ()); | ||||
|  | ||||
|         return new PacketContainer[]{teleport}; | ||||
|     } | ||||
|  | ||||
|     public static Disguise getClonedDisguise(String key) { | ||||
|         if (clonedDisguises.containsKey(key)) { | ||||
|             return clonedDisguises.get(key).clone(); | ||||
| @@ -879,81 +823,6 @@ public class DisguiseUtilities { | ||||
|         gson = gsonBuilder.create(); | ||||
|  | ||||
|         try { | ||||
|             Object world = ReflectionManager.getWorldServer(Bukkit.getWorlds().get(0)); | ||||
|             Class chunkClass = ReflectionManager.getNmsClass("Chunk"); | ||||
|             Object bedChunk = null; | ||||
|             Object[] biomes = (Object[]) Array.newInstance(ReflectionManager.getNmsClass("BiomeBase"), 256); | ||||
|  | ||||
|             Class registry = ReflectionManager.getNmsClass("IRegistry"); | ||||
|             Field biomeRegistry = ReflectionManager.getNmsField(registry, "BIOME"); | ||||
|             Iterator itel = ((Iterator) registry.getMethod("iterator").invoke(biomeRegistry.get(null))); | ||||
|  | ||||
|             for (int i = 0; i < biomes.length && itel.hasNext(); i++) { | ||||
|                 while (itel.hasNext()) { | ||||
|                     biomes[i] = itel.next(); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             for (Constructor constructor : chunkClass.getConstructors()) { | ||||
|                 if (constructor.getParameterTypes().length != 9) | ||||
|                     continue; | ||||
|  | ||||
|                 Object cords = ReflectionManager.getNmsConstructor("ChunkCoordIntPair", int.class, int.class) | ||||
|                         .newInstance(0, 0); | ||||
|  | ||||
|                 bedChunk = constructor.newInstance(world, cords, biomes, null, null, null, 0L, null, null); | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             if (bedChunk == null) { | ||||
|                 throw new IllegalStateException("[LibsDisguises] Cannot find constructor to create world chunk"); | ||||
|             } | ||||
|  | ||||
|             Field cSection = chunkClass.getDeclaredField("sections"); | ||||
|             cSection.setAccessible(true); | ||||
|  | ||||
|             Object chunkSection = ReflectionManager.getNmsClass("ChunkSection").getConstructor(int.class) | ||||
|                     .newInstance(0); | ||||
|  | ||||
|             Class blockClass = ReflectionManager.getNmsClass("Block"); | ||||
|             Object REGISTRY = ReflectionManager.getNmsField("IRegistry", "BLOCK").get(null); | ||||
|             Object minecraftKey = ReflectionManager.createMinecraftKey("white_bed"); | ||||
|  | ||||
|             Object block = REGISTRY.getClass().getMethod("get", minecraftKey.getClass()).invoke(REGISTRY, minecraftKey); | ||||
|             Object blockData = ReflectionManager.getNmsMethod(blockClass, "getBlockData").invoke(block); | ||||
|             Method method = null; | ||||
|  | ||||
|             for (Method method1 : blockData.getClass().getMethods()) { | ||||
|                 if (!method1.getName().equals("set") || method1.getParameterTypes().length != 2) | ||||
|                     continue; | ||||
|  | ||||
|                 method = method1; | ||||
|                 break; | ||||
|             } | ||||
|  | ||||
|             Method setType = chunkSection.getClass() | ||||
|                     .getMethod("setType", int.class, int.class, int.class, ReflectionManager.getNmsClass("IBlockData")); | ||||
|  | ||||
|             for (BlockFace face : new BlockFace[]{BlockFace.EAST, BlockFace.WEST, BlockFace.NORTH, BlockFace.SOUTH}) { | ||||
|                 int x = 1 + face.getModX(); | ||||
|                 int z = 1 + face.getModZ(); | ||||
|  | ||||
|                 Object data = method.invoke(blockData, block.getClass().getField("FACING").get(null), | ||||
|                         ReflectionManager.getEnumDirection(face.ordinal())); | ||||
|  | ||||
|                 setType.invoke(chunkSection, x, 0, z, data); | ||||
|             } | ||||
|  | ||||
|             Object[] array = (Object[]) Array.newInstance(chunkSection.getClass(), 16); | ||||
|  | ||||
|             array[0] = chunkSection; | ||||
|  | ||||
|             cSection.set(bedChunk, array); | ||||
|  | ||||
|             spawnChunk = ProtocolLibrary.getProtocolManager() | ||||
|                     .createPacketConstructor(PacketType.Play.Server.MAP_CHUNK, bedChunk, 65535) | ||||
|                     .createPacket(bedChunk, 65535); | ||||
|  | ||||
|             Field threadField = ReflectionManager.getNmsField("MinecraftServer", "serverThread"); | ||||
|             threadField.setAccessible(true); | ||||
|  | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package me.libraryaddict.disguise.utilities.packets.packethandlers; | ||||
|  | ||||
| import com.comphenix.protocol.PacketType; | ||||
| import com.comphenix.protocol.ProtocolLib; | ||||
| import com.comphenix.protocol.ProtocolLibrary; | ||||
| import com.comphenix.protocol.events.PacketContainer; | ||||
| import com.comphenix.protocol.reflect.StructureModifier; | ||||
| @@ -209,14 +210,18 @@ public class PacketHandlerSpawn implements IPacketHandler { | ||||
|             bytes.write(0, yaw); | ||||
|             bytes.write(1, pitch); | ||||
|  | ||||
|             spawnPlayer.getDataWatcherModifier().write(0, newWatcher); | ||||
|  | ||||
|             // Make him invisible | ||||
|             newWatcher.setObject(new WrappedDataWatcher.WrappedDataWatcherObject(MetaIndex.ENTITY_META.getIndex(), | ||||
|                     WrappedDataWatcher.Registry.get(Byte.class)), (byte) 32); | ||||
|  | ||||
|             packets.addPacket(spawnPlayer); | ||||
|  | ||||
|             PacketContainer metaPacket = ProtocolLibrary.getProtocolManager() | ||||
|                     .createPacketConstructor(PacketType.Play.Server.ENTITY_METADATA, entityId, newWatcher, true) | ||||
|                     .createPacket(entityId, newWatcher, true); | ||||
|  | ||||
|             packets.addPacket(metaPacket); | ||||
|  | ||||
|             if (!selfDisguise) { | ||||
|                 // Teleport the player back to where he's supposed to be | ||||
|                 PacketContainer teleportPacket = new PacketContainer(PacketType.Play.Server.ENTITY_TELEPORT); | ||||
| @@ -235,7 +240,7 @@ public class PacketHandlerSpawn implements IPacketHandler { | ||||
|                 packets.addDelayedPacket(teleportPacket, 3); | ||||
|  | ||||
|                 // Send a metadata packet | ||||
|                 PacketContainer metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA); | ||||
|                 metaPacket = new PacketContainer(PacketType.Play.Server.ENTITY_METADATA); | ||||
|  | ||||
|                 newWatcher = DisguiseUtilities | ||||
|                         .createSanitizedDataWatcher(WrappedDataWatcher.getEntityWatcher(disguisedEntity), | ||||
| @@ -302,9 +307,15 @@ public class PacketHandlerSpawn implements IPacketHandler { | ||||
|             mods.write(10, pitch); | ||||
|             mods.write(11, yaw); | ||||
|  | ||||
|             spawnEntity.getDataWatcherModifier().write(0, DisguiseUtilities | ||||
|             WrappedDataWatcher newWatcher = DisguiseUtilities | ||||
|                     .createSanitizedDataWatcher(WrappedDataWatcher.getEntityWatcher(disguisedEntity), | ||||
|                             disguise.getWatcher())); | ||||
|                             disguise.getWatcher()); | ||||
|  | ||||
|             PacketContainer metaPacket = ProtocolLibrary.getProtocolManager() | ||||
|                     .createPacketConstructor(PacketType.Play.Server.ENTITY_METADATA, disguisedEntity.getEntityId(), | ||||
|                             newWatcher, true).createPacket(disguisedEntity.getEntityId(), newWatcher, true); | ||||
|  | ||||
|             packets.addPacket(metaPacket); | ||||
|         } else if (disguise.getType().isMisc()) { | ||||
|             int data = ((MiscDisguise) disguise).getData(); | ||||
|             double x = loc.getX(); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user