mirror of
https://github.com/libraryaddict/LibsDisguises.git
synced 2024-12-17 15:49:17 +01:00
More stuff including a small amount of cleanup
This commit is contained in:
parent
25a6e713af
commit
a969811c64
@ -11,6 +11,7 @@ import me.libraryaddict.disguise.utilities.ReflectionManager;
|
|||||||
|
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Entity;
|
import org.bukkit.entity.Entity;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class DisguiseAPI {
|
public class DisguiseAPI {
|
||||||
private static boolean hearSelfDisguise;
|
private static boolean hearSelfDisguise;
|
||||||
@ -47,6 +48,7 @@ public class DisguiseAPI {
|
|||||||
* Disguise this entity with this disguise
|
* Disguise this entity with this disguise
|
||||||
*/
|
*/
|
||||||
public static void disguiseToAll(Entity entity, Disguise disguise) {
|
public static void disguiseToAll(Entity entity, Disguise disguise) {
|
||||||
|
// TODO Make everyone see this disguise. Remove any old disguises.
|
||||||
// If they are trying to disguise a null entity or use a null disguise
|
// If they are trying to disguise a null entity or use a null disguise
|
||||||
// Just return.
|
// Just return.
|
||||||
if (entity == null || disguise == null)
|
if (entity == null || disguise == null)
|
||||||
@ -84,12 +86,22 @@ public class DisguiseAPI {
|
|||||||
/**
|
/**
|
||||||
* Get the disguise of a entity
|
* Get the disguise of a entity
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static Disguise getDisguise(Entity disguised) {
|
public static Disguise getDisguise(Entity disguised) {
|
||||||
if (disguised == null)
|
if (disguised == null)
|
||||||
return null;
|
return null;
|
||||||
return DisguiseUtilities.getDisguise(disguised.getEntityId());
|
return DisguiseUtilities.getDisguise(disguised.getEntityId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the disguise of a entity
|
||||||
|
*/
|
||||||
|
public static Disguise getDisguise(Player observer, Entity disguised) {
|
||||||
|
if (disguised == null)
|
||||||
|
return null;
|
||||||
|
return DisguiseUtilities.getDisguise(observer, disguised.getEntityId());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the ID of a fake disguise for a entityplayer
|
* Get the ID of a fake disguise for a entityplayer
|
||||||
*/
|
*/
|
||||||
@ -102,10 +114,22 @@ public class DisguiseAPI {
|
|||||||
/**
|
/**
|
||||||
* Is this entity disguised
|
* Is this entity disguised
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
public static boolean isDisguised(Entity disguised) {
|
public static boolean isDisguised(Entity disguised) {
|
||||||
return getDisguise(disguised) != null;
|
return getDisguise(disguised) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDisguiseInUse(Disguise disguise) {
|
||||||
|
return DisguiseUtilities.isDisguiseInUse(disguise);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is this entity disguised
|
||||||
|
*/
|
||||||
|
public static boolean isDisguised(Player observer, Entity disguised) {
|
||||||
|
return getDisguise(observer, disguised) != null;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isEntityAnimationsAdded() {
|
public static boolean isEntityAnimationsAdded() {
|
||||||
return isEntityAnimationsAdded;
|
return isEntityAnimationsAdded;
|
||||||
}
|
}
|
||||||
@ -213,6 +237,7 @@ public class DisguiseAPI {
|
|||||||
* the world.
|
* the world.
|
||||||
*/
|
*/
|
||||||
public static void undisguiseToAll(Entity entity) {
|
public static void undisguiseToAll(Entity entity) {
|
||||||
|
// TODO Make all of these disguises be removed
|
||||||
Disguise disguise = getDisguise(entity);
|
Disguise disguise = getDisguise(entity);
|
||||||
if (disguise == null)
|
if (disguise == null)
|
||||||
return;
|
return;
|
||||||
|
@ -92,8 +92,7 @@ public class DisguiseListener implements Listener {
|
|||||||
public void onVechileEnter(VehicleEnterEvent event) {
|
public void onVechileEnter(VehicleEnterEvent event) {
|
||||||
if (event.isCancelled())
|
if (event.isCancelled())
|
||||||
return;
|
return;
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(event.getEntered());
|
if (event.getEntered() instanceof Player && DisguiseAPI.isDisguised((Player) event.getEntered(), event.getEntered())) {
|
||||||
if (disguise != null && event.getEntered() instanceof Player) {
|
|
||||||
DisguiseUtilities.removeSelfDisguise((Player) event.getEntered());
|
DisguiseUtilities.removeSelfDisguise((Player) event.getEntered());
|
||||||
((Player) event.getEntered()).updateInventory();
|
((Player) event.getEntered()).updateInventory();
|
||||||
}
|
}
|
||||||
@ -103,8 +102,9 @@ public class DisguiseListener implements Listener {
|
|||||||
public void onVechileLeave(VehicleExitEvent event) {
|
public void onVechileLeave(VehicleExitEvent event) {
|
||||||
if (event.isCancelled())
|
if (event.isCancelled())
|
||||||
return;
|
return;
|
||||||
final Disguise disguise = DisguiseAPI.getDisguise(event.getExited());
|
if (event.getExited() instanceof Player) {
|
||||||
if (disguise != null && event.getExited() instanceof Player) {
|
final Disguise disguise = DisguiseAPI.getDisguise((Player) event.getExited(), event.getExited());
|
||||||
|
if (disguise != null) {
|
||||||
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
Bukkit.getScheduler().scheduleSyncDelayedTask(plugin, new Runnable() {
|
||||||
public void run() {
|
public void run() {
|
||||||
DisguiseUtilities.setupFakeDisguise(disguise);
|
DisguiseUtilities.setupFakeDisguise(disguise);
|
||||||
@ -113,6 +113,7 @@ public class DisguiseListener implements Listener {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void setSlap(final String player, Disguise disguise) {
|
public void setSlap(final String player, Disguise disguise) {
|
||||||
if (disguiseSlap.containsKey(player)) {
|
if (disguiseSlap.containsKey(player)) {
|
||||||
|
@ -332,15 +332,15 @@ public abstract class Disguise {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMiscDisguise() {
|
public boolean isMiscDisguise() {
|
||||||
return this instanceof MiscDisguise;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMobDisguise() {
|
public boolean isMobDisguise() {
|
||||||
return this instanceof MobDisguise;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isPlayerDisguise() {
|
public boolean isPlayerDisguise() {
|
||||||
return this instanceof PlayerDisguise;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSelfDisguiseSoundsReplaced() {
|
public boolean isSelfDisguiseSoundsReplaced() {
|
||||||
@ -550,7 +550,7 @@ public abstract class Disguise {
|
|||||||
if (this.viewSelfDisguise != viewSelfDisguise) {
|
if (this.viewSelfDisguise != viewSelfDisguise) {
|
||||||
this.viewSelfDisguise = viewSelfDisguise;
|
this.viewSelfDisguise = viewSelfDisguise;
|
||||||
if (getEntity() != null && getEntity() instanceof Player) {
|
if (getEntity() != null && getEntity() instanceof Player) {
|
||||||
if (DisguiseAPI.getDisguise(getEntity()) == this) {
|
if (DisguiseAPI.getDisguise((Player) getEntity(), getEntity()) == this) {
|
||||||
if (viewSelfDisguise) {
|
if (viewSelfDisguise) {
|
||||||
DisguiseUtilities.setupFakeDisguise(this);
|
DisguiseUtilities.setupFakeDisguise(this);
|
||||||
} else
|
} else
|
||||||
|
@ -29,6 +29,10 @@ public class MiscDisguise extends TargettedDisguise {
|
|||||||
|| disguiseType == DisguiseType.DROPPED_ITEM ? -1 : addictionalData));
|
|| disguiseType == DisguiseType.DROPPED_ITEM ? -1 : addictionalData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMiscDisguise() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public MiscDisguise(DisguiseType disguiseType, boolean replaceSounds, int id, int data) {
|
public MiscDisguise(DisguiseType disguiseType, boolean replaceSounds, int id, int data) {
|
||||||
createDisguise(disguiseType, replaceSounds);
|
createDisguise(disguiseType, replaceSounds);
|
||||||
switch (disguiseType) {
|
switch (disguiseType) {
|
||||||
|
@ -22,6 +22,12 @@ public class MobDisguise extends TargettedDisguise {
|
|||||||
createDisguise(disguiseType, replaceSounds);
|
createDisguise(disguiseType, replaceSounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public boolean isMobDisguise() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public MobDisguise(EntityType entityType) {
|
public MobDisguise(EntityType entityType) {
|
||||||
this(entityType, true);
|
this(entityType, true);
|
||||||
|
@ -14,6 +14,11 @@ public class PlayerDisguise extends TargettedDisguise {
|
|||||||
createDisguise(DisguiseType.PLAYER, replaceSounds);
|
createDisguise(DisguiseType.PLAYER, replaceSounds);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlayerDisguise() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PlayerDisguise clone() {
|
public PlayerDisguise clone() {
|
||||||
PlayerDisguise disguise = new PlayerDisguise(getName(), isSoundsReplaced());
|
PlayerDisguise disguise = new PlayerDisguise(getName(), isSoundsReplaced());
|
||||||
|
@ -2,6 +2,8 @@ package me.libraryaddict.disguise.disguisetypes;
|
|||||||
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
|
||||||
|
import me.libraryaddict.disguise.utilities.DisguiseUtilities;
|
||||||
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public abstract class TargettedDisguise extends Disguise {
|
public abstract class TargettedDisguise extends Disguise {
|
||||||
@ -9,6 +11,13 @@ public abstract class TargettedDisguise extends Disguise {
|
|||||||
SHOW_TO_THESE, HIDE_FROM_THESE;
|
SHOW_TO_THESE, HIDE_FROM_THESE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setTargetType(TargetType newTargetType) {
|
||||||
|
if (DisguiseUtilities.isDisguiseInUse(this)) {
|
||||||
|
throw new RuntimeException("Cannot set the disguise target after the entity has been disguised");
|
||||||
|
}
|
||||||
|
targetType = newTargetType;
|
||||||
|
}
|
||||||
|
|
||||||
private HashSet<String> disguiseViewers = new HashSet<String>();
|
private HashSet<String> disguiseViewers = new HashSet<String>();
|
||||||
private TargetType targetType = TargetType.HIDE_FROM_THESE;
|
private TargetType targetType = TargetType.HIDE_FROM_THESE;
|
||||||
|
|
||||||
@ -16,6 +25,10 @@ public abstract class TargettedDisguise extends Disguise {
|
|||||||
return canSee(player.getName());
|
return canSee(player.getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public HashSet<String> getObservers() {
|
||||||
|
return disguiseViewers;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean canSee(String playername) {
|
public boolean canSee(String playername) {
|
||||||
boolean contains = disguiseViewers.contains(playername);
|
boolean contains = disguiseViewers.contains(playername);
|
||||||
if (targetType == TargetType.HIDE_FROM_THESE) {
|
if (targetType == TargetType.HIDE_FROM_THESE) {
|
||||||
|
@ -46,6 +46,14 @@ public class DisguiseUtilities {
|
|||||||
libsDisguises = disguises;
|
libsDisguises = disguises;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean isDisguiseInUse(Disguise disguise) {
|
||||||
|
if (getDisguises().containsKey(disguise.getEntity().getEntityId())
|
||||||
|
&& getDisguises().get(disguise.getEntity().getEntityId()).contains(disguise)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Resends
|
* @param Resends
|
||||||
* the entity to all the watching players, which is where the magic begins
|
* the entity to all the watching players, which is where the magic begins
|
||||||
@ -242,11 +250,12 @@ public class DisguiseUtilities {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Deprecated
|
||||||
public static TargettedDisguise getDisguise(int entityId) {
|
public static TargettedDisguise getDisguise(int entityId) {
|
||||||
TargettedDisguise toReturn = null;
|
TargettedDisguise toReturn = null;
|
||||||
if (getDisguises().containsKey(entityId)) {
|
if (getDisguises().containsKey(entityId)) {
|
||||||
for (TargettedDisguise disguise : getDisguises().get(entityId)) {
|
for (TargettedDisguise disguise : getDisguises().get(entityId)) {
|
||||||
if (disguise.getTargetType() == TargetType.HIDE_FROM_THESE) {
|
if (disguise.getTargetType() == TargetType.HIDE_FROM_THESE && disguise.getObservers().isEmpty()) {
|
||||||
return disguise;
|
return disguise;
|
||||||
}
|
}
|
||||||
if (toReturn == null) {
|
if (toReturn == null) {
|
||||||
|
@ -467,8 +467,10 @@ public class PacketsManager {
|
|||||||
((Integer) mods.read(2)) / 8D, ((Integer) mods.read(3)) / 8D);
|
((Integer) mods.read(2)) / 8D, ((Integer) mods.read(3)) / 8D);
|
||||||
Entity disguisedEntity = null;
|
Entity disguisedEntity = null;
|
||||||
DisguiseSound entitySound = null;
|
DisguiseSound entitySound = null;
|
||||||
|
Disguise disguise = null;
|
||||||
for (Entity entity : soundLoc.getChunk().getEntities()) {
|
for (Entity entity : soundLoc.getChunk().getEntities()) {
|
||||||
if (DisguiseAPI.isDisguised(entity)) {
|
Disguise entityDisguise = DisguiseAPI.getDisguise(observer, entity);
|
||||||
|
if (entityDisguise != null) {
|
||||||
Location loc = entity.getLocation();
|
Location loc = entity.getLocation();
|
||||||
loc = new Location(observer.getWorld(), ((int) (loc.getX() * 8)) / 8D, ((int) (loc.getY() * 8)) / 8D,
|
loc = new Location(observer.getWorld(), ((int) (loc.getX() * 8)) / 8D, ((int) (loc.getY() * 8)) / 8D,
|
||||||
((int) (loc.getZ() * 8)) / 8D);
|
((int) (loc.getZ() * 8)) / 8D);
|
||||||
@ -506,6 +508,7 @@ public class PacketsManager {
|
|||||||
soundType = entitySound.getType(soundName, !hasInvun);
|
soundType = entitySound.getType(soundName, !hasInvun);
|
||||||
}
|
}
|
||||||
if (soundType != null) {
|
if (soundType != null) {
|
||||||
|
disguise = entityDisguise;
|
||||||
disguisedEntity = entity;
|
disguisedEntity = entity;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -513,7 +516,6 @@ public class PacketsManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(disguisedEntity);
|
|
||||||
if (disguise != null) {
|
if (disguise != null) {
|
||||||
if (disguise.isSelfDisguiseSoundsReplaced() || disguisedEntity != event.getPlayer()) {
|
if (disguise.isSelfDisguiseSoundsReplaced() || disguisedEntity != event.getPlayer()) {
|
||||||
if (disguise.isSoundsReplaced()) {
|
if (disguise.isSoundsReplaced()) {
|
||||||
@ -599,7 +601,7 @@ public class PacketsManager {
|
|||||||
if ((Byte) mods.read(1) == 1) {
|
if ((Byte) mods.read(1) == 1) {
|
||||||
// It made a damage animation
|
// It made a damage animation
|
||||||
Entity entity = event.getPacket().getEntityModifier(observer.getWorld()).read(0);
|
Entity entity = event.getPacket().getEntityModifier(observer.getWorld()).read(0);
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(entity);
|
Disguise disguise = DisguiseAPI.getDisguise(observer, entity);
|
||||||
if (disguise != null && (disguise.isSelfDisguiseSoundsReplaced() || entity != event.getPlayer())) {
|
if (disguise != null && (disguise.isSelfDisguiseSoundsReplaced() || entity != event.getPlayer())) {
|
||||||
DisguiseSound disSound = DisguiseSound.getType(entity.getType().name());
|
DisguiseSound disSound = DisguiseSound.getType(entity.getType().name());
|
||||||
if (disSound == null)
|
if (disSound == null)
|
||||||
@ -769,7 +771,7 @@ public class PacketsManager {
|
|||||||
public void onPacketSending(PacketEvent event) {
|
public void onPacketSending(PacketEvent event) {
|
||||||
// If the inventory is the players inventory
|
// If the inventory is the players inventory
|
||||||
if (event.getPlayer().getVehicle() == null && event.getPacket().getIntegers().read(0) == 0) {
|
if (event.getPlayer().getVehicle() == null && event.getPacket().getIntegers().read(0) == 0) {
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(event.getPlayer());
|
Disguise disguise = DisguiseAPI.getDisguise(event.getPlayer(), event.getPlayer());
|
||||||
// If the player is disguised, views self disguises and is hiding a item.
|
// If the player is disguised, views self disguises and is hiding a item.
|
||||||
if (disguise != null && disguise.isSelfDisguiseVisible()
|
if (disguise != null && disguise.isSelfDisguiseVisible()
|
||||||
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
||||||
@ -860,7 +862,7 @@ public class PacketsManager {
|
|||||||
@Override
|
@Override
|
||||||
public void onPacketReceiving(final PacketEvent event) {
|
public void onPacketReceiving(final PacketEvent event) {
|
||||||
if (event.getPlayer().getVehicle() == null) {
|
if (event.getPlayer().getVehicle() == null) {
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(event.getPlayer());
|
Disguise disguise = DisguiseAPI.getDisguise(event.getPlayer(), event.getPlayer());
|
||||||
// If player is disguised, views self disguises and has a inventory modifier
|
// If player is disguised, views self disguises and has a inventory modifier
|
||||||
if (disguise != null && disguise.isSelfDisguiseVisible()
|
if (disguise != null && disguise.isSelfDisguiseVisible()
|
||||||
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
||||||
@ -1056,7 +1058,7 @@ public class PacketsManager {
|
|||||||
ProtocolLibrary.getProtocolManager().removePacketListener(inventoryListenerServer);
|
ProtocolLibrary.getProtocolManager().removePacketListener(inventoryListenerServer);
|
||||||
}
|
}
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(player);
|
Disguise disguise = DisguiseAPI.getDisguise(player, player);
|
||||||
if (disguise != null) {
|
if (disguise != null) {
|
||||||
if (viewDisguisesListenerEnabled && disguise.isSelfDisguiseVisible()
|
if (viewDisguisesListenerEnabled && disguise.isSelfDisguiseVisible()
|
||||||
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
&& (disguise.isHidingArmorFromSelf() || disguise.isHidingHeldItemFromSelf())) {
|
||||||
@ -1076,7 +1078,7 @@ public class PacketsManager {
|
|||||||
ProtocolLibrary.getProtocolManager().removePacketListener(viewDisguisesListener);
|
ProtocolLibrary.getProtocolManager().removePacketListener(viewDisguisesListener);
|
||||||
}
|
}
|
||||||
for (Player player : Bukkit.getOnlinePlayers()) {
|
for (Player player : Bukkit.getOnlinePlayers()) {
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(player);
|
Disguise disguise = DisguiseAPI.getDisguise(player, player);
|
||||||
if (disguise != null) {
|
if (disguise != null) {
|
||||||
if (disguise.isSelfDisguiseVisible()) {
|
if (disguise.isSelfDisguiseVisible()) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
@ -1102,7 +1104,7 @@ public class PacketsManager {
|
|||||||
// First get the entity, the one sending this packet
|
// First get the entity, the one sending this packet
|
||||||
StructureModifier<Entity> entityModifer = sentPacket.getEntityModifier(observer.getWorld());
|
StructureModifier<Entity> entityModifer = sentPacket.getEntityModifier(observer.getWorld());
|
||||||
org.bukkit.entity.Entity entity = entityModifer.read((Packets.Server.COLLECT == sentPacket.getID() ? 1 : 0));
|
org.bukkit.entity.Entity entity = entityModifer.read((Packets.Server.COLLECT == sentPacket.getID() ? 1 : 0));
|
||||||
Disguise disguise = DisguiseAPI.getDisguise(entity);
|
Disguise disguise = DisguiseAPI.getDisguise(observer, entity);
|
||||||
// If disguised.
|
// If disguised.
|
||||||
if (disguise != null) {
|
if (disguise != null) {
|
||||||
// If packet is Packets.Server.UPDATE_ATTRIBUTES
|
// If packet is Packets.Server.UPDATE_ATTRIBUTES
|
||||||
@ -1157,8 +1159,9 @@ public class PacketsManager {
|
|||||||
case Packets.Server.COLLECT:
|
case Packets.Server.COLLECT:
|
||||||
|
|
||||||
{
|
{
|
||||||
if (disguise.getType().isMisc())
|
if (disguise.getType().isMisc()) {
|
||||||
packets = new PacketContainer[0];
|
packets = new PacketContainer[0];
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user