Perform disguise validation before doing any of the disguise work
If a disguise is invalid, we won't notify redis or prevent players from joining
This commit is contained in:
parent
ac2df004f0
commit
8b39fa4e24
@ -37,11 +37,9 @@ public class DisguiseCommand extends CommandBase<PlayerDisguiseManager> implemen
|
||||
return;
|
||||
}
|
||||
|
||||
Plugin.runAsync(() ->
|
||||
{
|
||||
new PlayerDisguiseNotification(realName, currentUUID, args[0], args.length > 1 ? args[1] : args[0]).publish();
|
||||
});
|
||||
|
||||
Plugin.disguise(caller, args[0], args.length > 1 ? args[1] : args[0]);
|
||||
String skin = args.length > 1 ? args[1] : args[0];
|
||||
Plugin.tryDisguise(caller, args[0], skin, () -> // onComplete
|
||||
Plugin.runAsync(() -> // task
|
||||
new PlayerDisguiseNotification(realName, currentUUID, args[0], skin).publish()));
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,96 @@
|
||||
package mineplex.core.disguise.playerdisguise;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.cache.Cache;
|
||||
import com.google.common.cache.CacheBuilder;
|
||||
|
||||
/**
|
||||
* Set with contents that expire after X amount of time units. Essentially HashSet reimplemented with a Cache instead of HashMap.
|
||||
* @author Dan
|
||||
*/
|
||||
public class ExpiringSet<E> extends AbstractSet<E> implements Set<E>
|
||||
{
|
||||
private transient Cache<E, Object> cache;
|
||||
|
||||
private static final Object DUMMY = new Object();
|
||||
|
||||
public ExpiringSet(long duration, TimeUnit unit)
|
||||
{
|
||||
this.cache = CacheBuilder.newBuilder().expireAfterWrite(duration, unit).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<E> iterator()
|
||||
{
|
||||
return cache.asMap().keySet().iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void forEach(Consumer<? super E> action)
|
||||
{
|
||||
cache.asMap().keySet().forEach(action);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeIf(Predicate<? super E> filter)
|
||||
{
|
||||
return cache.asMap().keySet().removeIf(filter);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Spliterator<E> spliterator()
|
||||
{
|
||||
return cache.asMap().keySet().spliterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<E> stream()
|
||||
{
|
||||
return cache.asMap().keySet().stream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<E> parallelStream()
|
||||
{
|
||||
return cache.asMap().keySet().parallelStream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size()
|
||||
{
|
||||
return (int) cache.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean contains(Object o)
|
||||
{
|
||||
return cache.getIfPresent(o) != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean add(E e)
|
||||
{
|
||||
boolean contained = contains(e);
|
||||
cache.put(e, DUMMY);
|
||||
return contained;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean remove(Object o)
|
||||
{
|
||||
boolean contained = contains(o);
|
||||
cache.invalidate(o);
|
||||
return contained;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear()
|
||||
{
|
||||
cache.invalidateAll();
|
||||
}
|
||||
}
|
@ -1,14 +1,8 @@
|
||||
package mineplex.core.disguise.playerdisguise;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import net.minecraft.server.v1_8_R3.MinecraftServer;
|
||||
@ -86,7 +80,7 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
|
||||
ILLEGAL_USERNAMES = ImmutableSet.copyOf(Arrays.asList("hypixel", "chiss", "dctr", "blondebug", "dooskee",
|
||||
"tomcallister", "jessiemarcia", "spu_", "sp614x", "deadmau5", "gwen", "mineplex", "samczsun", "sethbling",
|
||||
"xisuma", "cubehamster", "natet_bird", "qwertyuiopthepie"
|
||||
"xisuma", "cubehamster", "natet_bird", "qwertyuiopthepie", "hitler", "adolfhitler"
|
||||
));
|
||||
|
||||
VERY_SPECIAL_PEOPLE = ImmutableSet.copyOf(Arrays.asList(
|
||||
@ -121,14 +115,15 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
private CoreClientManager _clients = require(CoreClientManager.class);
|
||||
private DisguiseManager _disguise = require(DisguiseManager.class);
|
||||
private Punish _punish = require(Punish.class);
|
||||
private CosmeticManager _cosmetics = require(CosmeticManager.class);
|
||||
// private CosmeticManager _cosmetics = require(CosmeticManager.class);
|
||||
private PreferencesManager _prefs = require(PreferencesManager.class);
|
||||
|
||||
private RedisDataRepository<DisguisePlayerBean> _redis;
|
||||
|
||||
// The list of usernames which cannot join because someone else is joining
|
||||
private Set<String> _cannotJoin = Collections.synchronizedSet(new HashSet<>());
|
||||
private Set<String> _loggingIn = Collections.synchronizedSet(new HashSet<>());
|
||||
// Values expire in 30 seconds if they haven't been properly cleaned up
|
||||
private Set<String> _cannotJoin = Collections.synchronizedSet(new ExpiringSet<>(1, TimeUnit.MINUTES));
|
||||
private Set<String> _loggingIn = Collections.synchronizedSet(new ExpiringSet<>(1, TimeUnit.MINUTES));
|
||||
|
||||
private Set<UUID> _pendingDisguise1 = new HashSet<>();
|
||||
|
||||
@ -164,7 +159,7 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
if (disguisePlayer.getProfile().getName().equalsIgnoreCase(event.getPlayer().getName()))
|
||||
{
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
|
||||
event.setKickMessage("Failed to login: The authentication servers are currently down for maintainence");
|
||||
event.setKickMessage("Failed to login: The authentication servers are currently down for maintenance");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -172,7 +167,7 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
if (_cannotJoin.contains(event.getPlayer().getName().toLowerCase()))
|
||||
{
|
||||
event.setResult(PlayerLoginEvent.Result.KICK_OTHER);
|
||||
event.setKickMessage("Failed to login: The authentication servers are currently down for maintainence");
|
||||
event.setKickMessage("Failed to login: The authentication servers are currently down for maintenance");
|
||||
return;
|
||||
}
|
||||
|
||||
@ -231,7 +226,7 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
runSyncLater(() ->
|
||||
{
|
||||
UtilPlayer.message(event.getPlayer(), F.main(getName(), "Attempting to disguise you as " + bean.getGameProfile().getName()));
|
||||
disguise(event.getPlayer(), bean.getGameProfile());
|
||||
tryDisguise(event.getPlayer(), bean.getGameProfile(), () -> { });
|
||||
}, 1);
|
||||
}
|
||||
}
|
||||
@ -480,15 +475,15 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
}
|
||||
}
|
||||
|
||||
public void disguise(Player caller, GameProfile requestedProfile)
|
||||
public void tryDisguise(Player caller, GameProfile requestedProfile, Runnable onComplete)
|
||||
{
|
||||
if (getDisguiseManager().isDisguised(caller))
|
||||
{
|
||||
if (isDisguised(caller))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "You are already disguised. Please undisguise by using /disguise"));
|
||||
}
|
||||
else
|
||||
UtilPlayer.message(caller,
|
||||
F.main("Disguise", "You are already disguised. Please undisguise by using /disguise"));
|
||||
} else
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "You are already disguised. Perhaps you are morphed?"));
|
||||
}
|
||||
@ -497,134 +492,75 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
|
||||
if (isDisguised(caller))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "You are already disguised. Please undisguise by using /disguise"));
|
||||
return;
|
||||
}
|
||||
|
||||
String requestedUsername = requestedProfile.getName();
|
||||
|
||||
if (!requestedUsername.equalsIgnoreCase(caller.getName()))
|
||||
{
|
||||
_cannotJoin.add(requestedUsername.toLowerCase());
|
||||
for (Player other : UtilServer.getPlayersCollection())
|
||||
{
|
||||
if (other.getName().equalsIgnoreCase(requestedUsername))
|
||||
{
|
||||
UtilPlayer.message(caller, C.cRed + F.main("Disguise", "This name is already in use!"));
|
||||
_cannotJoin.remove(requestedUsername.toLowerCase());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!_pendingDisguise.add(requestedUsername.toLowerCase()))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "Someone is already disguising as that user"));
|
||||
return;
|
||||
}
|
||||
|
||||
PlayerPreDisguiseEvent playerPreDisguiseEvent = new PlayerPreDisguiseEvent(caller, requestedUsername);
|
||||
UtilServer.CallEvent(playerPreDisguiseEvent);
|
||||
if (playerPreDisguiseEvent.isCancelled())
|
||||
{
|
||||
UtilPlayer.message(caller, F.main(getName(), "Your disguise was cancelled by something"));
|
||||
_pendingDisguise.remove(requestedUsername.toLowerCase());
|
||||
UtilPlayer.message(caller,
|
||||
F.main("Disguise", "You are already disguised. Please undisguise by using /disguise"));
|
||||
return;
|
||||
}
|
||||
|
||||
CoreClient callerClient = getClientManager().Get(caller);
|
||||
|
||||
if (!requestedUsername.equalsIgnoreCase(caller.getName()))
|
||||
String requestedUsername = requestedProfile.getName();
|
||||
if (requestedUsername.equalsIgnoreCase(caller.getName()))
|
||||
{
|
||||
getClientManager().getOrLoadClient(requestedUsername, other ->
|
||||
if (doDisguise(caller, requestedProfile, callerClient, callerClient))
|
||||
{
|
||||
Rank otherRank = other != null ? other.GetRank() : Rank.ALL;
|
||||
onComplete.run();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
for (Player other : UtilServer.getPlayersCollection())
|
||||
{
|
||||
if (other.getName().equalsIgnoreCase(requestedUsername))
|
||||
{
|
||||
UtilPlayer.message(caller, C.cRed + F.main("Disguise", "This name is already in use!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (_pendingDisguise.contains(requestedUsername.toLowerCase()))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "Someone is already disguising as that user"));
|
||||
return;
|
||||
}
|
||||
|
||||
getClientManager().getOrLoadClient(requestedUsername, other ->
|
||||
{
|
||||
if (other != null)
|
||||
{
|
||||
Rank otherRank = other.GetRank();
|
||||
if (otherRank.has(Rank.TWITCH))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "You can't disguise as staff, YouTubers or Twitchers!"));
|
||||
UtilPlayer.message(caller,
|
||||
F.main("Disguise", "You can't disguise as staff, YouTubers or Twitchers!"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (other != null)
|
||||
PunishClient pclient = getPunishManager().GetClient(requestedUsername);
|
||||
if (pclient != null && (pclient.IsBanned() || pclient.IsMuted()))
|
||||
{
|
||||
PunishClient pclient = getPunishManager().GetClient(requestedUsername);
|
||||
if (pclient != null && (pclient.IsBanned() || pclient.IsMuted()))
|
||||
{
|
||||
UtilPlayer.message(caller, F.main("Disguise", "You can't disguise as players who are banned/muted!"));
|
||||
return;
|
||||
}
|
||||
UtilPlayer.message(caller,
|
||||
F.main("Disguise", "You can't disguise as players who are banned/muted!"));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
callerClient.disguise(requestedUsername, requestedProfile.getId(), otherRank);
|
||||
if (doDisguise(caller, requestedProfile, callerClient, other))
|
||||
{
|
||||
onComplete.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
_mapping.put(callerClient.getDisguisedAs().toLowerCase(), callerClient.getName());
|
||||
public boolean doDisguise(Player caller, GameProfile requestedProfile, CoreClient callerClient, CoreClient otherClient)
|
||||
{
|
||||
String requestedUsername = requestedProfile.getName();
|
||||
_pendingDisguise.add(requestedUsername.toLowerCase());
|
||||
|
||||
System.out.println("=================");
|
||||
System.out.println("Disguising " + caller.getName() + " as:");
|
||||
System.out.println(requestedProfile.getName() + " id " + requestedProfile.getId());
|
||||
System.out.println("Properties:");
|
||||
for (Map.Entry<String, Property> p : requestedProfile.getProperties().entries())
|
||||
{
|
||||
System.out.println("\t" + p.getKey() + " " + p.getValue().getName());
|
||||
System.out.println("\t" + p.getValue().getValue());
|
||||
System.out.println("\t" + p.getValue().getSignature());
|
||||
}
|
||||
System.out.println("=================");
|
||||
|
||||
DisguisePlayer disguisePlayer = new DisguisePlayer(caller, requestedProfile);
|
||||
disguisePlayer.showInTabList(true, 0);
|
||||
allow(caller);
|
||||
getDisguiseManager().disguise(disguisePlayer, () ->
|
||||
{
|
||||
GameProfile callerProfile = ((CraftPlayer) caller).getProfile();
|
||||
|
||||
require(ScoreboardManager.class).handlePlayerQuit(disguisePlayer.getOriginalProfile().getName());
|
||||
|
||||
try
|
||||
{
|
||||
UtilGameProfile.changeName(callerProfile, disguisePlayer.getProfile().getName());
|
||||
UtilGameProfile.changeId(callerProfile, disguisePlayer.getProfile().getId());
|
||||
|
||||
Field playersByName = PlayerList.class.getDeclaredField("playersByName");
|
||||
playersByName.setAccessible(true);
|
||||
Map map = (Map) playersByName.get(MinecraftServer.getServer().getPlayerList());
|
||||
map.remove(disguisePlayer.getOriginalProfile().getName());
|
||||
map.put(disguisePlayer.getProfile().getName(), disguisePlayer.getEntity());
|
||||
}
|
||||
catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
require(ScoreboardManager.class).handlePlayerJoin(disguisePlayer.getName());
|
||||
|
||||
callerProfile.getProperties().clear();
|
||||
callerProfile.getProperties().putAll(disguisePlayer.getProfile().getProperties());
|
||||
|
||||
callerProfile.getProperties().removeAll(ORIGINAL_UUID_KEY);
|
||||
callerProfile.getProperties().put(ORIGINAL_UUID_KEY, new Property(ORIGINAL_UUID_KEY, caller.getUniqueId().toString()));
|
||||
|
||||
require(FriendManager.class).updatePlayerStatus(disguisePlayer.getOriginalProfile().getId(), null);
|
||||
require(FriendManager.class).updatePlayerStatus(disguisePlayer.getProfile().getId(), new PlayerStatus(disguisePlayer.getProfile().getId(), requestedUsername, _serverName));
|
||||
|
||||
getPreferencesManager().handlePlayerJoin(caller, true);
|
||||
|
||||
_disguises.put(caller.getUniqueId(), disguisePlayer);
|
||||
|
||||
UtilPlayer.message(caller, F.main("Disguise", "Disguise Active: " + ChatColor.RESET + requestedUsername));
|
||||
|
||||
UtilServer.CallEvent(new PlayerDisguisedEvent(caller));
|
||||
|
||||
storeDisguiseData(caller, requestedUsername, requestedProfile);
|
||||
|
||||
_pendingDisguise.remove(requestedUsername.toLowerCase());
|
||||
|
||||
_cannotJoin.remove(requestedUsername.toLowerCase());
|
||||
});
|
||||
});
|
||||
}
|
||||
else
|
||||
if (!requestedUsername.equalsIgnoreCase(caller.getName()))
|
||||
{
|
||||
_cannotJoin.add(requestedUsername.toLowerCase());
|
||||
} else
|
||||
{
|
||||
DisguisePlayer disguisePlayer = new DisguisePlayer(caller, requestedProfile);
|
||||
disguisePlayer.showInTabList(true, 0);
|
||||
@ -641,10 +577,93 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
|
||||
_pendingDisguise.remove(requestedUsername.toLowerCase());
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
PlayerPreDisguiseEvent playerPreDisguiseEvent = new PlayerPreDisguiseEvent(caller, requestedUsername);
|
||||
UtilServer.CallEvent(playerPreDisguiseEvent);
|
||||
if (playerPreDisguiseEvent.isCancelled())
|
||||
{
|
||||
UtilPlayer.message(caller, F.main(getName(), "Your disguise was cancelled by something"));
|
||||
_pendingDisguise.remove(requestedUsername.toLowerCase());
|
||||
_cannotJoin.remove(requestedUsername.toLowerCase());
|
||||
return false;
|
||||
}
|
||||
|
||||
Rank otherRank = otherClient != null ? otherClient.GetRank() : Rank.ALL;
|
||||
callerClient.disguise(requestedUsername, requestedProfile.getId(), otherRank);
|
||||
|
||||
_mapping.put(callerClient.getDisguisedAs().toLowerCase(), callerClient.getName());
|
||||
|
||||
System.out.println("=================");
|
||||
System.out.println("Disguising " + caller.getName() + " as:");
|
||||
System.out.println(requestedProfile.getName() + " id " + requestedProfile.getId());
|
||||
System.out.println("Properties:");
|
||||
for (Map.Entry<String, Property> p : requestedProfile.getProperties().entries())
|
||||
{
|
||||
System.out.println("\t" + p.getKey() + " " + p.getValue().getName());
|
||||
System.out.println("\t" + p.getValue().getValue());
|
||||
System.out.println("\t" + p.getValue().getSignature());
|
||||
}
|
||||
System.out.println("=================");
|
||||
|
||||
DisguisePlayer disguisePlayer = new DisguisePlayer(caller, requestedProfile);
|
||||
disguisePlayer.showInTabList(true, 0);
|
||||
allow(caller);
|
||||
getDisguiseManager().disguise(disguisePlayer, () ->
|
||||
{
|
||||
GameProfile callerProfile = ((CraftPlayer) caller).getProfile();
|
||||
|
||||
require(ScoreboardManager.class).handlePlayerQuit(disguisePlayer.getOriginalProfile().getName());
|
||||
|
||||
try
|
||||
{
|
||||
UtilGameProfile.changeName(callerProfile, disguisePlayer.getProfile().getName());
|
||||
UtilGameProfile.changeId(callerProfile, disguisePlayer.getProfile().getId());
|
||||
|
||||
Field playersByName = PlayerList.class.getDeclaredField("playersByName");
|
||||
playersByName.setAccessible(true);
|
||||
Map map = (Map) playersByName.get(MinecraftServer.getServer().getPlayerList());
|
||||
map.remove(disguisePlayer.getOriginalProfile().getName());
|
||||
map.put(disguisePlayer.getProfile().getName(), disguisePlayer.getEntity());
|
||||
} catch (Throwable t)
|
||||
{
|
||||
t.printStackTrace();
|
||||
}
|
||||
|
||||
require(ScoreboardManager.class).handlePlayerJoin(disguisePlayer.getName());
|
||||
|
||||
callerProfile.getProperties().clear();
|
||||
callerProfile.getProperties().putAll(disguisePlayer.getProfile().getProperties());
|
||||
|
||||
callerProfile.getProperties().removeAll(ORIGINAL_UUID_KEY);
|
||||
callerProfile.getProperties()
|
||||
.put(ORIGINAL_UUID_KEY, new Property(ORIGINAL_UUID_KEY, caller.getUniqueId().toString()));
|
||||
|
||||
require(FriendManager.class).updatePlayerStatus(disguisePlayer.getOriginalProfile().getId(), null);
|
||||
require(FriendManager.class).updatePlayerStatus(disguisePlayer.getProfile().getId(),
|
||||
new PlayerStatus(disguisePlayer.getProfile().getId(), requestedUsername, _serverName));
|
||||
|
||||
getPreferencesManager().handlePlayerJoin(caller, true);
|
||||
|
||||
_disguises.put(caller.getUniqueId(), disguisePlayer);
|
||||
|
||||
UtilPlayer.message(caller, F.main("Disguise", "Disguise Active: " + ChatColor.RESET + requestedUsername));
|
||||
|
||||
UtilServer.CallEvent(new PlayerDisguisedEvent(caller));
|
||||
|
||||
storeDisguiseData(caller, requestedUsername, requestedProfile);
|
||||
|
||||
_pendingDisguise.remove(requestedUsername.toLowerCase());
|
||||
|
||||
_cannotJoin.remove(requestedUsername.toLowerCase());
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void disguise(Player caller, String requestedUsername, String requestedSkin)
|
||||
public void tryDisguise(Player caller, String requestedUsername, String requestedSkin, Runnable onComplete)
|
||||
{
|
||||
if (!validateUsername(caller, requestedUsername, true)) return;
|
||||
if (!validateUsername(caller, requestedSkin, false)) return;
|
||||
@ -667,7 +686,7 @@ public class PlayerDisguiseManager extends MiniPlugin implements IPacketHandler
|
||||
requestedProfile.getProperties().clear();
|
||||
requestedProfile.getProperties().put("textures", skinData.getProperty());
|
||||
|
||||
disguise(caller, requestedProfile);
|
||||
tryDisguise(caller, requestedProfile, onComplete);
|
||||
};
|
||||
|
||||
if (!requestedUsername.equalsIgnoreCase(requestedSkin))
|
||||
|
Loading…
Reference in New Issue
Block a user