IdUtil MaintainedSets rework, and proper sender tab completion.

This commit is contained in:
BuildTools 2015-07-02 17:51:32 +02:00 committed by Olof Larsson
parent a7216b0c20
commit eaa730ddfc
14 changed files with 511 additions and 160 deletions

View File

@ -141,17 +141,18 @@ public class MassiveCoreEngineMain extends EngineAbstract
Player watcher = event.getPlayer(); Player watcher = event.getPlayer();
if (MUtil.isntPlayer(watcher)) return; if (MUtil.isntPlayer(watcher)) return;
// Get the lowercased token // Get the lowercased token predicate
String tokenlc = event.getLastToken().toLowerCase(); Predictate<String> predictate = PredictateStartsWithIgnoreCase.get(event.getLastToken());
// Create a case insensitive set to check for already added stuff // Create a case insensitive set to check for already added stuff
Set<String> current = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER); Set<String> current = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
current.addAll(event.getTabCompletions()); current.addAll(event.getTabCompletions());
// Add names of all online senders that match and isn't added yet. // Add names of all online senders that match and isn't added yet.
for (String senderName : IdUtil.getOnlineNames()) // TODO: Should this only be players? Would a player actually want to tab-complete @console?
for (String senderName : IdUtil.getNames(SenderPresence.ONLINE, SenderType.ANY))
{ {
if (!senderName.toLowerCase().startsWith(tokenlc)) continue; if (!predictate.apply(senderName)) continue;
if (current.contains(senderName)) continue; if (current.contains(senderName)) continue;
if (!Mixin.canSee(watcher, senderName)) continue; if (!Mixin.canSee(watcher, senderName)) continue;

View File

@ -0,0 +1,29 @@
package com.massivecraft.massivecore;
public enum SenderPresence
{
// IMP NOTE: These must be sorted, with the most strict first
// and the most loose at the end.
LOCAL, // Online and logged in on this very server.
ONLINE, // Online somewhere on the cloud. May be this server may be another server.
OFFLINE, // The opposite of online.
ANY, // Any. Local, Online or Offline.
;
// -------------------------------------------- //
// GET FROM ONLINE VALUE
// -------------------------------------------- //
public static SenderPresence fromOnline(Boolean online)
{
if (online == null) return null;
return fromOnline(online.booleanValue());
}
public static SenderPresence fromOnline(boolean online)
{
return online ? ONLINE : OFFLINE;
}
}

View File

@ -0,0 +1,10 @@
package com.massivecraft.massivecore;
public enum SenderType
{
PLAYER, // A player. Such as Notch or Dinnerbone. @console is not a player.
NONPLAYER, // A sender which is not a player. Such as @console.
ANY, // Anyone. Both players, and nonplayers.
;
}

View File

@ -2,6 +2,8 @@ package com.massivecraft.massivecore.cmd.arg;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds; import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds;
import com.massivecraft.massivecore.util.IdUtil; import com.massivecraft.massivecore.util.IdUtil;
@ -15,7 +17,7 @@ public class ARPlayer extends ARSenderIdAbstract<Player>
public static ARPlayer get() { return i; } public static ARPlayer get() { return i; }
private ARPlayer() private ARPlayer()
{ {
super(SenderIdSourceMixinAllSenderIds.get(), true, true); super(SenderIdSourceMixinAllSenderIds.get(), SenderPresence.LOCAL, SenderType.PLAYER);
} }
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -2,6 +2,8 @@ package com.massivecraft.massivecore.cmd.arg;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds; import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds;
import com.massivecraft.massivecore.util.IdUtil; import com.massivecraft.massivecore.util.IdUtil;
@ -15,7 +17,7 @@ public class ARSender extends ARSenderIdAbstract<CommandSender>
public static ARSender get() { return i; } public static ARSender get() { return i; }
private ARSender() private ARSender()
{ {
super(SenderIdSourceMixinAllSenderIds.get(), true, false); super(SenderIdSourceMixinAllSenderIds.get(), SenderPresence.LOCAL, SenderType.ANY);
} }
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -3,6 +3,8 @@ package com.massivecraft.massivecore.cmd.arg;
import java.util.Collection; import java.util.Collection;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderColl; import com.massivecraft.massivecore.store.SenderColl;
import com.massivecraft.massivecore.store.SenderEntity; import com.massivecraft.massivecore.store.SenderEntity;
@ -18,15 +20,15 @@ public class ARSenderEntity<T extends SenderEntity<T>> extends ARSenderIdAbstrac
// CONSTRUCT // CONSTRUCT
// -------------------------------------------- // // -------------------------------------------- //
private ARSenderEntity(SenderColl<T> coll, boolean onlineOnly, boolean playerOnly) private ARSenderEntity(SenderColl<T> coll, SenderPresence presence, SenderType type)
{ {
super(coll, onlineOnly, playerOnly); super(coll, presence, type);
this.coll = coll; this.coll = coll;
} }
private ARSenderEntity(SenderColl<T> coll, boolean onlineOnly) private ARSenderEntity(SenderColl<T> coll, SenderPresence presence)
{ {
super(coll, onlineOnly); super(coll, presence);
this.coll = coll; this.coll = coll;
} }
@ -40,8 +42,8 @@ public class ARSenderEntity<T extends SenderEntity<T>> extends ARSenderIdAbstrac
// GET // GET
// -------------------------------------------- // // -------------------------------------------- //
public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll, boolean onlineOnly, boolean playerOnly) { return new ARSenderEntity<T>(coll, onlineOnly, playerOnly); } public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll, SenderPresence presence, SenderType type) { return new ARSenderEntity<T>(coll, presence, type); }
public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll, boolean onlineOnly) { return new ARSenderEntity<T>(coll, onlineOnly); } public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll, SenderPresence presence) { return new ARSenderEntity<T>(coll, presence); }
public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll) { return new ARSenderEntity<T>(coll); } public static <T extends SenderEntity<T>> ARSenderEntity<T> get(SenderColl<T> coll) { return new ARSenderEntity<T>(coll); }
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -1,5 +1,7 @@
package com.massivecraft.massivecore.cmd.arg; package com.massivecraft.massivecore.cmd.arg;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSource; import com.massivecraft.massivecore.store.SenderIdSource;
import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds; import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds;
@ -9,14 +11,14 @@ public class ARSenderId extends ARSenderIdAbstract<String>
// CONSTRUCT // CONSTRUCT
// -------------------------------------------- // // -------------------------------------------- //
private ARSenderId(SenderIdSource source, boolean onlineOnly, boolean playerOnly) private ARSenderId(SenderIdSource source, SenderPresence presence, SenderType type)
{ {
super(source, onlineOnly, playerOnly); super(source, presence, type);
} }
private ARSenderId(SenderIdSource source, boolean onlineOnly) private ARSenderId(SenderIdSource source, SenderPresence presence)
{ {
super(source, onlineOnly); super(source, presence);
} }
private ARSenderId(SenderIdSource source) private ARSenderId(SenderIdSource source)
@ -35,8 +37,8 @@ public class ARSenderId extends ARSenderIdAbstract<String>
// GET // GET
// -------------------------------------------- // // -------------------------------------------- //
public static ARSenderId get(SenderIdSource source, boolean onlineOnly, boolean playerOnly) { return new ARSenderId(source, onlineOnly, playerOnly); } public static ARSenderId get(SenderIdSource source, SenderPresence presence, SenderType type) { return new ARSenderId(source, presence, type); }
public static ARSenderId get(SenderIdSource source, boolean onlineOnly) { return new ARSenderId(source, onlineOnly); } public static ARSenderId get(SenderIdSource source, SenderPresence presence) { return new ARSenderId(source, presence); }
public static ARSenderId get(SenderIdSource source) { return new ARSenderId(source); } public static ARSenderId get(SenderIdSource source) { return new ARSenderId(source); }
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -1,14 +1,14 @@
package com.massivecraft.massivecore.cmd.arg; package com.massivecraft.massivecore.cmd.arg;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.Collections;
import java.util.Set; import java.util.Set;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import com.massivecraft.massivecore.MassiveException; import com.massivecraft.massivecore.MassiveException;
import com.massivecraft.massivecore.collections.MassiveList; import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.mixin.Mixin; import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSource; import com.massivecraft.massivecore.store.SenderIdSource;
import com.massivecraft.massivecore.util.IdUtil; import com.massivecraft.massivecore.util.IdUtil;
import com.massivecraft.massivecore.util.MUtil; import com.massivecraft.massivecore.util.MUtil;
@ -20,28 +20,32 @@ public abstract class ARSenderIdAbstract<T> extends ARAbstract<T>
// -------------------------------------------- // // -------------------------------------------- //
protected final SenderIdSource source; protected final SenderIdSource source;
protected final boolean onlineOnly; protected final SenderPresence presence;
protected final boolean playerOnly; protected final SenderType type;
// -------------------------------------------- // // -------------------------------------------- //
// CONSTRUCT // CONSTRUCT
// -------------------------------------------- // // -------------------------------------------- //
public ARSenderIdAbstract(SenderIdSource source, boolean onlineOnly, boolean playerOnly) public ARSenderIdAbstract(SenderIdSource source, SenderPresence presence, SenderType type)
{ {
if (source == null) throw new NullPointerException("source");
if (presence == null) throw new NullPointerException("presence");
if (type == null) throw new NullPointerException("type");
this.source = source; this.source = source;
this.onlineOnly = onlineOnly; this.presence = presence;
this.playerOnly = playerOnly; this.type = type;
} }
public ARSenderIdAbstract(SenderIdSource source, boolean online) public ARSenderIdAbstract(SenderIdSource source, SenderPresence presence)
{ {
this(source, online, false); this(source, presence, SenderType.ANY);
} }
public ARSenderIdAbstract(SenderIdSource source) public ARSenderIdAbstract(SenderIdSource source)
{ {
this(source, false); this(source, SenderPresence.ANY);
} }
// -------------------------------------------- // // -------------------------------------------- //
@ -57,8 +61,14 @@ public abstract class ARSenderIdAbstract<T> extends ARAbstract<T>
@Override @Override
public String getTypeName() public String getTypeName()
{ {
if (onlineOnly) return "online player"; switch (presence)
else return "player"; {
case LOCAL:
case ONLINE: return "online player";
case OFFLINE: return "offline player";
case ANY: return "player";
}
throw new UnsupportedOperationException("Unknown SenderPresence: " + presence);
} }
@Override @Override
@ -93,8 +103,7 @@ public abstract class ARSenderIdAbstract<T> extends ARAbstract<T>
if (MUtil.isUuid(arg)) return true; if (MUtil.isUuid(arg)) return true;
// Check data presence. This handles specials like "@console". // Check data presence. This handles specials like "@console".
if (IdUtil.getIdToData().containsKey(arg)) return true; if (IdUtil.getRegistryIdToSender().containsKey(arg)) return true;
if (IdUtil.getNameToData().containsKey(arg)) return true;
return false; return false;
} }
@ -102,25 +111,21 @@ public abstract class ARSenderIdAbstract<T> extends ARAbstract<T>
@Override @Override
public Collection<String> getTabList(CommandSender sender, String arg) public Collection<String> getTabList(CommandSender sender, String arg)
{ {
Set<String> names; // Step 1: Calculate presence.
if (onlineOnly) SenderPresence presence = this.presence;
{ if (presence == SenderPresence.ANY) presence = SenderPresence.ONLINE;
names = playerOnly ? IdUtil.getOnlinePlayerNames() : IdUtil.getOnlineNames();
List<String> ret = new MassiveList<String>(); // Special step: We don't tab complete offline players.
for (String name : names) if (presence == SenderPresence.OFFLINE) return Collections.emptySet();
{
if ( ! Mixin.canSee(sender, name)) continue;
ret.add(name);
}
return ret;
}
else
{
names = playerOnly ? IdUtil.getAllPlayerNames() : IdUtil.getAllNames();
return names; // Step 2: Calculate type.
} SenderType type = this.type;
// Step 3: Create the ret.
Set<String> ret = IdUtil.getNames(presence, type);
// Step 4: Return the ret.
return ret;
} }
// -------------------------------------------- // // -------------------------------------------- //
@ -135,14 +140,13 @@ public abstract class ARSenderIdAbstract<T> extends ARAbstract<T>
String senderId = arg.toLowerCase(); String senderId = arg.toLowerCase();
String betterId = IdUtil.getId(senderId); String betterId = IdUtil.getId(senderId);
if (betterId != null) senderId = betterId; if (betterId != null) senderId = betterId;
for (Collection<String> coll : this.source.getSenderIdCollections()) for (Collection<String> coll : this.source.getSenderIdCollections())
{ {
// If the senderId exists ... // If the senderId exists ...
if ( ! coll.contains(senderId)) continue; if ( ! coll.contains(senderId)) continue;
// ... and the online check passes ... // ... and the presence check passes ...
if (this.onlineOnly && !Mixin.isOnline(senderId)) continue; if (IdUtil.getMaintainedIds().contains(senderId, presence, type) || IdUtil.getMaintainedNames().contains(senderId, presence, type)) continue;
// ... and the result is non null ... // ... and the result is non null ...
T result = this.getResultForSenderId(senderId); T result = this.getResultForSenderId(senderId);

View File

@ -27,7 +27,7 @@ public class MessageMixinDefault extends MessageMixinAbstract
public boolean messageAll(Collection<String> messages) public boolean messageAll(Collection<String> messages)
{ {
if (messages == null) return false; if (messages == null) return false;
for (CommandSender sender : IdUtil.getOnlineSenders()) for (CommandSender sender : IdUtil.getLocalSenders())
{ {
this.messageOne(sender, messages); this.messageOne(sender, messages);
} }
@ -39,7 +39,7 @@ public class MessageMixinDefault extends MessageMixinAbstract
{ {
if (predictate == null) return false; if (predictate == null) return false;
if (messages == null) return false; if (messages == null) return false;
for (CommandSender sender : IdUtil.getOnlineSenders()) for (CommandSender sender : IdUtil.getLocalSenders())
{ {
if (!predictate.apply(sender)) continue; if (!predictate.apply(sender)) continue;
this.messageOne(sender, messages); this.messageOne(sender, messages);
@ -62,7 +62,7 @@ public class MessageMixinDefault extends MessageMixinAbstract
public boolean messageRawAll(Collection<Mson> msons) public boolean messageRawAll(Collection<Mson> msons)
{ {
if (msons == null) return false; if (msons == null) return false;
for (CommandSender sender : IdUtil.getOnlineSenders()) for (CommandSender sender : IdUtil.getLocalSenders())
{ {
this.messageRawOne(sender, msons); this.messageRawOne(sender, msons);
} }
@ -74,7 +74,7 @@ public class MessageMixinDefault extends MessageMixinAbstract
{ {
if (predictate == null) return false; if (predictate == null) return false;
if (msons == null) return false; if (msons == null) return false;
for (CommandSender sender : IdUtil.getOnlineSenders()) for (CommandSender sender : IdUtil.getLocalSenders())
{ {
if ( ! predictate.apply(sender)) continue; if ( ! predictate.apply(sender)) continue;
this.messageRawOne(sender, msons); this.messageRawOne(sender, msons);

View File

@ -9,6 +9,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.massivecraft.massivecore.Predictate; import com.massivecraft.massivecore.Predictate;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.cmd.arg.ARSenderEntity; import com.massivecraft.massivecore.cmd.arg.ARSenderEntity;
import com.massivecraft.massivecore.cmd.arg.ARSenderId; import com.massivecraft.massivecore.cmd.arg.ARSenderId;
import com.massivecraft.massivecore.util.IdUtil; import com.massivecraft.massivecore.util.IdUtil;
@ -114,7 +116,7 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
// You could say the corresponding entities latently exist in the collection because it's creative. // You could say the corresponding entities latently exist in the collection because it's creative.
if (this.isCreative()) if (this.isCreative())
{ {
ret.add(IdUtil.getAllIds()); ret.add(IdUtil.getIds(SenderPresence.ANY, SenderType.ANY));
} }
return ret; return ret;
@ -129,9 +131,9 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
return ARSenderEntity.get(this); return ARSenderEntity.get(this);
} }
public ARSenderEntity<E> getAREntity(boolean online) public ARSenderEntity<E> getAREntity(SenderPresence presence)
{ {
return ARSenderEntity.get(this, online); return ARSenderEntity.get(this, presence);
} }
public ARSenderId getARId() public ARSenderId getARId()
@ -139,9 +141,9 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
return ARSenderId.get(this); return ARSenderId.get(this);
} }
public ARSenderId getARId(boolean online) public ARSenderId getARId(SenderPresence presence)
{ {
return ARSenderId.get(this, online); return ARSenderId.get(this, presence);
} }
// -------------------------------------------- // // -------------------------------------------- //

View File

@ -4,6 +4,8 @@ import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.util.IdUtil; import com.massivecraft.massivecore.util.IdUtil;
public class SenderIdSourceMixinAllSenderIds implements SenderIdSource public class SenderIdSourceMixinAllSenderIds implements SenderIdSource
@ -23,7 +25,7 @@ public class SenderIdSourceMixinAllSenderIds implements SenderIdSource
public Collection<Collection<String>> getSenderIdCollections() public Collection<Collection<String>> getSenderIdCollections()
{ {
List<Collection<String>> ret = new ArrayList<Collection<String>>(); List<Collection<String>> ret = new ArrayList<Collection<String>>();
ret.add(IdUtil.getAllIds()); ret.add(IdUtil.getIds(SenderPresence.ANY, SenderType.ANY));
return ret; return ret;
} }

View File

@ -5,12 +5,12 @@ import java.lang.reflect.Type;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.GameMode; import org.bukkit.GameMode;
@ -24,6 +24,8 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerLoginEvent;
import com.massivecraft.massivecore.MassiveCore; import com.massivecraft.massivecore.MassiveCore;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave; import com.massivecraft.massivecore.event.EventMassiveCorePlayerLeave;
import com.massivecraft.massivecore.event.EventMassiveCoreSenderRegister; import com.massivecraft.massivecore.event.EventMassiveCoreSenderRegister;
import com.massivecraft.massivecore.event.EventMassiveCoreSenderUnregister; import com.massivecraft.massivecore.event.EventMassiveCoreSenderUnregister;
@ -106,24 +108,19 @@ public class IdUtil implements Listener, Runnable
// -------------------------------------------- // // -------------------------------------------- //
// Used for chat tab completion, argument readers, etc. // Used for chat tab completion, argument readers, etc.
private static Set<String> onlineIds = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER); private static SenderMap maintainedIds = new SenderMap();
public static Set<String> getOnlineIds() { return Collections.unmodifiableSet(onlineIds); } public static SenderMap getMaintainedIds() { return maintainedIds; }
public static Set<String> getIds(SenderPresence presence, SenderType type)
{
return maintainedIds.getValues(presence, type);
}
private static Set<String> onlineNames = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER); private static SenderMap maintainedNames = new SenderMap();
public static Set<String> getOnlineNames() { return Collections.unmodifiableSet(onlineNames); } public static SenderMap getMaintainedNames() { return maintainedNames; }
public static Set<String> getNames(SenderPresence presence, SenderType type)
private static Set<String> onlinePlayerNames = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER); {
public static Set<String> getOnlinePlayerNames() { return Collections.unmodifiableSet(onlinePlayerNames); } return maintainedNames.getValues(presence, type);
}
private static Set<String> allIds = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
public static Set<String> getAllIds() { return Collections.unmodifiableSet(allIds); }
private static Set<String> allNames = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
public static Set<String> getAllNames() { return Collections.unmodifiableSet(allNames); }
private static Set<String> allPlayerNames = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
public static Set<String> getAllPlayerNames() { return Collections.unmodifiableSet(allPlayerNames); }
// -------------------------------------------- // // -------------------------------------------- //
// REGISTRY // REGISTRY
@ -132,7 +129,10 @@ public class IdUtil implements Listener, Runnable
// It's assumed that the getName() returns the name which is also the id. // It's assumed that the getName() returns the name which is also the id.
private static Map<String, CommandSender> registryIdToSender = new ConcurrentHashMap<String, CommandSender>(); private static Map<String, CommandSender> registryIdToSender = new ConcurrentHashMap<String, CommandSender>();
public static Map<String, CommandSender> getRegistryIdToSender() { return Collections.unmodifiableMap(registryIdToSender); }
private static Map<CommandSender, String> registrySenderToId = new ConcurrentHashMap<CommandSender, String>(); private static Map<CommandSender, String> registrySenderToId = new ConcurrentHashMap<CommandSender, String>();
public static Map<CommandSender, String> getRegistrySenderToId() { return Collections.unmodifiableMap(registrySenderToId); }
public static void register(CommandSender sender) public static void register(CommandSender sender)
{ {
@ -145,7 +145,7 @@ public class IdUtil implements Listener, Runnable
registrySenderToId.put(sender, id); registrySenderToId.put(sender, id);
// Update data before the event is ran so that data is available. // Update data before the event is ran so that data is available.
update(id, name, true); update(id, name, SenderPresence.LOCAL);
EventMassiveCoreSenderRegister event = new EventMassiveCoreSenderRegister(sender, data); EventMassiveCoreSenderRegister event = new EventMassiveCoreSenderRegister(sender, data);
event.run(); event.run();
@ -163,7 +163,7 @@ public class IdUtil implements Listener, Runnable
if (removed == null) return; if (removed == null) return;
// Update data before the event is ran so that data is available. // Update data before the event is ran so that data is available.
update(id, name, false); update(id, name, SenderPresence.OFFLINE);
EventMassiveCoreSenderUnregister event = new EventMassiveCoreSenderUnregister(sender, data); EventMassiveCoreSenderUnregister event = new EventMassiveCoreSenderUnregister(sender, data);
event.run(); event.run();
@ -174,7 +174,7 @@ public class IdUtil implements Listener, Runnable
// -------------------------------------------- // // -------------------------------------------- //
// Used for retrieving the full set of senders currently present on this server. // Used for retrieving the full set of senders currently present on this server.
public static Set<CommandSender> getOnlineSenders() public static Set<CommandSender> getLocalSenders()
{ {
Set<CommandSender> ret = new LinkedHashSet<CommandSender>(); Set<CommandSender> ret = new LinkedHashSet<CommandSender>();
@ -199,8 +199,7 @@ public class IdUtil implements Listener, Runnable
{ {
if (id == null) throw new NullPointerException("id"); if (id == null) throw new NullPointerException("id");
onlineIds.remove(id); maintainedIds.removeValueCompletely(id);
allIds.remove(id);
IdData data = idToData.remove(id); IdData data = idToData.remove(id);
if (data == null) return null; if (data == null) return null;
@ -213,10 +212,7 @@ public class IdUtil implements Listener, Runnable
{ {
if (name == null) throw new NullPointerException("name"); if (name == null) throw new NullPointerException("name");
onlineNames.remove(name); maintainedNames.removeValueCompletely(name);
onlinePlayerNames.remove(name);
allNames.remove(name);
allPlayerNames.remove(name);
IdData data = nameToData.remove(name); IdData data = nameToData.remove(name);
if (data == null) return null; if (data == null) return null;
@ -224,9 +220,11 @@ public class IdUtil implements Listener, Runnable
return data.getId(); return data.getId();
} }
private static void addData(IdData data, boolean online) private static void addData(IdData data, SenderPresence presence)
{ {
if (data == null) throw new NullPointerException("data"); if (data == null) throw new NullPointerException("data");
if (presence == null) throw new NullPointerException("presence");
String id = data.getId(); String id = data.getId();
String name = data.getName(); String name = data.getName();
@ -244,15 +242,9 @@ public class IdUtil implements Listener, Runnable
if (id != null && name != null) if (id != null && name != null)
{ {
boolean player = MUtil.isValidPlayerName(name); List<SenderPresence> presences = SenderMap.getPresences(presence);
maintainedIds.addValue(id, presences);
if (online) onlineIds.add(id); maintainedNames.addValue(name, presences);
allIds.add(id);
if (online && player) onlinePlayerNames.add(name);
if (online) onlineNames.add(name);
if (player) allPlayerNames.add(name);
allNames.add(name);
} }
} }
@ -266,12 +258,12 @@ public class IdUtil implements Listener, Runnable
update(id, name, millis, null); update(id, name, millis, null);
} }
public static void update(final String id, final String name, Boolean online) public static void update(final String id, final String name, SenderPresence presence)
{ {
update(id, name, System.currentTimeMillis(), online); update(id, name, System.currentTimeMillis(), presence);
} }
public static void update(final String id, final String name, final long millis, Boolean online) public static void update(final String id, final String name, final long millis, SenderPresence presence)
{ {
// First Null Check // First Null Check
if (id == null && name == null) throw new NullPointerException("Either id or name must be set. They can't both be null."); if (id == null && name == null) throw new NullPointerException("Either id or name must be set. They can't both be null.");
@ -292,33 +284,45 @@ public class IdUtil implements Listener, Runnable
// The previousMillis is now null or the lowest of the two. // The previousMillis is now null or the lowest of the two.
if (previousMillis != null && previousMillis > millis) return; if (previousMillis != null && previousMillis > millis) return;
// Online Fix // Presence Fix
if (online == null) if (presence == null)
{ {
if (id != null) if (id != null)
{ {
online = onlineIds.contains(id); presence = maintainedIds.getPresence(id);
} }
else if (name != null) else if (name != null)
{ {
online = onlineNames.contains(name); presence = maintainedNames.getPresence(name);
} }
} }
// Removal of previous data // Removal of previous data
// TODO: This is not optimal but will do for now. It only "uproots" one step. removeIdAndNameRecurse(id, name);
String otherId = null;
String otherName = null;
if (id != null) otherName = removeId(id);
if (name != null) otherId = removeName(name);
if (otherId != null && !otherId.equals(id)) removeId(otherId);
if (otherName != null && !otherName.equals(name)) removeName(otherName);
// Adding new data // Adding new data
IdData data = new IdData(id, name, millis); IdData data = new IdData(id, name, millis);
addData(data, online); addData(data, presence);
}
private static void removeIdAndNameRecurse(String id, String name)
{
String otherId = null;
String otherName = null;
// Remove first
if (id != null) otherName = removeId(id);
if (name != null) otherId = removeName(name);
// If equal, then null. We shouldn't perform the same operation twice.
if (otherId != null && otherId.equals(id)) otherId = null;
if (otherName != null && otherName.equals(name)) otherName = null;
// If any isn't null. Repeat
if (otherId != null || otherName != null)
{
removeIdAndNameRecurse(otherId, otherName);
}
} }
// -------------------------------------------- // // -------------------------------------------- //
@ -339,13 +343,9 @@ public class IdUtil implements Listener, Runnable
idToData.clear(); idToData.clear();
nameToData.clear(); nameToData.clear();
onlineIds.clear(); maintainedIds.clear();
onlineNames.clear(); maintainedNames.clear();
onlinePlayerNames.clear();
allIds.clear();
allNames.clear();
allPlayerNames.clear();
// Load Datas // Load Datas
loadDatas(); loadDatas();
@ -394,9 +394,11 @@ public class IdUtil implements Listener, Runnable
String name = player.getName(); String name = player.getName();
// Declaring Existence? Sure, whatever you were before! // Declaring Existence? Sure, whatever you were before!
// It can definitely not be local at this point.
// But online or offline is fine.
boolean online = Mixin.isOnline(player); boolean online = Mixin.isOnline(player);
update(id, name, online); update(id, name, SenderPresence.fromOnline(online));
} }
// Can't be cancelled // Can't be cancelled
@ -410,10 +412,8 @@ public class IdUtil implements Listener, Runnable
String id = uuid.toString(); String id = uuid.toString();
String name = player.getName(); String name = player.getName();
// Joining? Sure, the player is online! // Joining? The player must be local at this point.
boolean online = true; update(id, name, SenderPresence.LOCAL);
update(id, name, online);
} }
// Can't be cancelled // Can't be cancelled
@ -428,9 +428,21 @@ public class IdUtil implements Listener, Runnable
String name = player.getName(); String name = player.getName();
// Leaving? Is it an actuall leave? // Leaving? Is it an actuall leave?
boolean online = !Mixin.isActualLeave(event); SenderPresence presence;
if (Mixin.isActualLeave(event))
{
// They actually left.
// They are offline.
presence = SenderPresence.OFFLINE;
}
else
{
// They didn't actually leave.
// They are online, but not local.
presence = SenderPresence.ONLINE;
}
update(id, name, online); update(id, name, presence);
} }
// -------------------------------------------- // // -------------------------------------------- //
@ -462,10 +474,16 @@ public class IdUtil implements Listener, Runnable
// Player // Player
// CommandSender // CommandSender
// UUID if (senderObject instanceof CommandSender)
if (senderObject instanceof CommandSender || senderObject instanceof UUID)
{ {
String id = getId(senderObject); String id = getIdFromSender((CommandSender) senderObject);
return getIdToData().get(id);
}
// UUID
if (senderObject instanceof UUID)
{
String id = getIdFromUuid((UUID) senderObject);
return getIdToData().get(id); return getIdToData().get(id);
} }
@ -620,8 +638,8 @@ public class IdUtil implements Listener, Runnable
// Already Done // Already Done
if (senderObject instanceof String && MUtil.isUuid((String)senderObject)) return (String)senderObject; if (senderObject instanceof String && MUtil.isUuid((String)senderObject)) return (String)senderObject;
// Console Type // Console
if (senderObject instanceof ConsoleCommandSender) return CONSOLE_ID; // Handled at "Command Sender"
// Console Id/Name // Console Id/Name
if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID; if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID;
@ -634,13 +652,13 @@ public class IdUtil implements Listener, Runnable
} }
// Player // Player
if (senderObject instanceof Player) return ((Player)senderObject).getUniqueId().toString(); // Handled at "Command Sender"
// CommandSender // Command Sender
if (senderObject instanceof CommandSender) return ((CommandSender)senderObject).getName().toLowerCase(); if (senderObject instanceof CommandSender) return getIdFromSender((CommandSender) senderObject);
// UUID // UUID
if (senderObject instanceof UUID) return ((UUID)senderObject).toString(); if (senderObject instanceof UUID) return getIdFromUuid((UUID) senderObject);
// String // String
// Handled at "Data" // Handled at "Data"
@ -656,6 +674,18 @@ public class IdUtil implements Listener, Runnable
return null; return null;
} }
public static String getIdFromSender(CommandSender sender)
{
if (sender instanceof Player) return ((Player) sender).getUniqueId().toString();
if (sender instanceof ConsoleCommandSender) return CONSOLE_ID;
return sender.getName().toLowerCase();
}
public static String getIdFromUuid(UUID uuid)
{
return uuid.toString();
}
public static String getName(Object senderObject) public static String getName(Object senderObject)
{ {
// Null Return // Null Return
@ -664,8 +694,8 @@ public class IdUtil implements Listener, Runnable
// Already Done // Already Done
// Handled at "Data" (not applicable - names can look differently) // Handled at "Data" (not applicable - names can look differently)
// Console Type // Console
if (senderObject instanceof ConsoleCommandSender) return CONSOLE_ID; // Handled at "Command Sender"
// Console Id/Name // Console Id/Name
if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID; if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID;
@ -678,10 +708,10 @@ public class IdUtil implements Listener, Runnable
} }
// Player // Player
// Handled at "CommandSender" // Handled at "Command Sender"
// CommandSender // CommandSender
if (senderObject instanceof CommandSender) return ((CommandSender)senderObject).getName(); if (senderObject instanceof CommandSender) return getNameFromSender((CommandSender)senderObject);
// UUID // UUID
// Handled at "Data". // Handled at "Data".
@ -705,10 +735,15 @@ public class IdUtil implements Listener, Runnable
return null; return null;
} }
public static String getNameFromSender(CommandSender sender)
{
if (sender instanceof ConsoleCommandSender) return CONSOLE_ID;
return sender.getName();
}
public static boolean isOnline(Object senderObject) public static boolean isOnline(Object senderObject)
{ {
// Fix the id ... // Fix the id ...
if (senderObject == null) return false;
String id = getId(senderObject); String id = getId(senderObject);
if (id == null) return false; if (id == null) return false;
@ -717,7 +752,7 @@ public class IdUtil implements Listener, Runnable
if (CONSOLE_ID.equals(id)) return true; if (CONSOLE_ID.equals(id)) return true;
// ... return by (case insensitive) set contains. // ... return by (case insensitive) set contains.
return getOnlineIds().contains(id); return IdUtil.getIds(SenderPresence.ONLINE, SenderType.ANY).contains(id);
} }
public static Long getMillis(Object senderObject) public static Long getMillis(Object senderObject)
@ -733,7 +768,7 @@ public class IdUtil implements Listener, Runnable
public static boolean isPlayerId(String string) public static boolean isPlayerId(String string)
{ {
// NOTE: Assuming all custom ids look like "@shite". // NOTE: Assuming all custom ids isn't a valid player name or id.
return MUtil.isValidPlayerName(string) || MUtil.isUuid(string); return MUtil.isValidPlayerName(string) || MUtil.isUuid(string);
} }
@ -805,20 +840,20 @@ public class IdUtil implements Listener, Runnable
MassiveCore.get().log(Txt.parse("<i>Loading Cachefile datas...")); MassiveCore.get().log(Txt.parse("<i>Loading Cachefile datas..."));
for (IdData data : getCachefileDatas()) for (IdData data : getCachefileDatas())
{ {
update(data.getId(), data.getName(), data.getMillis(), false); update(data.getId(), data.getName(), data.getMillis(), SenderPresence.OFFLINE);
} }
MassiveCore.get().log(Txt.parse("<i>Loading Onlineplayer datas...")); MassiveCore.get().log(Txt.parse("<i>Loading Onlineplayer datas..."));
for (IdData data : getOnlineplayerDatas()) for (IdData data : getLocalPlayerDatas())
{ {
update(data.getId(), data.getName(), data.getMillis(), true); update(data.getId(), data.getName(), data.getMillis(), SenderPresence.LOCAL);
} }
MassiveCore.get().log(Txt.parse("<i>Loading Registry datas...")); MassiveCore.get().log(Txt.parse("<i>Loading Registry datas..."));
for (String id : registryIdToSender.keySet()) for (String id : registryIdToSender.keySet())
{ {
String name = id; String name = id;
update(id, name, true); update(id, name, SenderPresence.LOCAL);
} }
MassiveCore.get().log(Txt.parse("<i>Saving Cachefile...")); MassiveCore.get().log(Txt.parse("<i>Saving Cachefile..."));
@ -867,7 +902,7 @@ public class IdUtil implements Listener, Runnable
// -------------------------------------------- // // -------------------------------------------- //
// This data source is simply based on the players currently online // This data source is simply based on the players currently online
public static Set<IdData> getOnlineplayerDatas() public static Set<IdData> getLocalPlayerDatas()
{ {
Set<IdData> ret = new LinkedHashSet<IdData>(); Set<IdData> ret = new LinkedHashSet<IdData>();

View File

@ -0,0 +1,206 @@
package com.massivecraft.massivecore.util;
import java.util.Collections;
import java.util.EnumMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentSkipListSet;
import com.google.common.collect.ImmutableList;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
public final class SenderMap
{
// -------------------------------------------- //
// FIELDS
// -------------------------------------------- //
private final Map<SenderPresence, Map<SenderType, Set<String>>> innerMap;
public Map<SenderPresence, Map<SenderType, Set<String>>> getInnerMap()
{
return innerMap;
}
// -------------------------------------------- //
// CONSTRUCT
// -------------------------------------------- //
public SenderMap()
{
innerMap = new EnumMap<SenderPresence, Map<SenderType, Set<String>>>(SenderPresence.class);
for (SenderPresence presence : SenderPresence.values())
{
Map<SenderType, Set<String>> map = new EnumMap<SenderType, Set<String>>(SenderType.class);
for (SenderType type : SenderType.values())
{
Set<String> set = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
map.put(type, set);
}
innerMap.put(presence, map);
}
}
// -------------------------------------------- //
// GET
// -------------------------------------------- //
public Set<String> getValues(SenderPresence presence, SenderType type)
{
if (presence == null) throw new NullPointerException("presence");
if (type == null) throw new NullPointerException("type");
return Collections.unmodifiableSet(getRawValues(presence, type));
}
private Set<String> getRawValues(SenderPresence presence, SenderType type)
{
return innerMap.get(presence).get(type);
}
public SenderPresence getPresence(String value)
{
if (value == null) throw new NullPointerException("value");
return getPresence(value, SenderType.ANY);
}
public SenderPresence getPresence(String value, SenderType type)
{
if (value == null) throw new NullPointerException("value");
if (type == null) throw new NullPointerException("type");
for (SenderPresence presence : SenderPresence.values())
{
if (contains(value, presence, type)) return presence;
}
return null;
}
// -------------------------------------------- //
// CONTAINS
// -------------------------------------------- //
public boolean contains(String value, SenderPresence presence, SenderType type)
{
if (value == null) throw new NullPointerException("value");
if (presence == null) throw new NullPointerException("presence");
if (type == null) throw new NullPointerException("type");
return getRawValues(presence, type).contains(value);
}
// -------------------------------------------- //
// CLEAR
// -------------------------------------------- //
public void clear()
{
for (Map<SenderType, Set<String>> map : innerMap.values())
{
for (Set<String> set : map.values())
{
set.clear();
}
}
}
// -------------------------------------------- //
// ADD
// -------------------------------------------- //
public void addValue(String value, SenderPresence presence)
{
if (value == null) throw new NullPointerException("value");
if (presence == null) throw new NullPointerException("presence");
addValue(value, getPresences(presence));
}
public void addValue(String value, List<SenderPresence> presences)
{
if (value == null) throw new NullPointerException("value");
if (presences == null) throw new NullPointerException("presences");
addValue(value, presences, getSenderTypes(value));
}
public void addValue(String value, List<SenderPresence> presences, List<SenderType> types)
{
if (value == null) throw new NullPointerException("value");
if (presences == null) throw new NullPointerException("presences");
if (types == null) throw new NullPointerException("types");
for (SenderPresence presence : presences)
{
Map<SenderType, Set<String>> map = innerMap.get(presence);
for (SenderType type : types)
{
Set<String> set = map.get(type);
set.add(value);
}
}
}
// -------------------------------------------- //
// REMOVE
// -------------------------------------------- //
public boolean removeValueCompletely(String value)
{
if (value == null) throw new NullPointerException("value");
boolean ret = false;
for (Map<SenderType, Set<String>> map : innerMap.values())
{
for (Set<String> set : map.values())
{
ret |= set.remove(value);
}
}
return ret;
}
// -------------------------------------------- //
// UTIL
// -------------------------------------------- //
public static final List<SenderPresence> LOCAL_PRESENCES = ImmutableList.of(SenderPresence.LOCAL, SenderPresence.ONLINE, SenderPresence.ANY);
public static final List<SenderPresence> ONLINE_PRESENCES = ImmutableList.of(SenderPresence.ONLINE, SenderPresence.ANY);
public static final List<SenderPresence> OFFLINE_PRESENCES = ImmutableList.of(SenderPresence.OFFLINE, SenderPresence.ANY);
// This accepts the most strict presence,
// and returns all other which also match.
public static List<SenderPresence> getPresences(SenderPresence presence)
{
if (presence == null) throw new NullPointerException("presence");
switch (presence)
{
case LOCAL : return LOCAL_PRESENCES;
case ONLINE : return ONLINE_PRESENCES;
case OFFLINE : return OFFLINE_PRESENCES;
case ANY : throw new UnsupportedOperationException("SenderPresence.ANY is not supported. You must know wether it is online or offline.");
}
throw new UnsupportedOperationException("Unknown SenderPresence: " + null);
}
public static final List<SenderType> PLAYER_TYPES = ImmutableList.of(SenderType.PLAYER, SenderType.ANY);
public static final List<SenderType> NONPLAYER_TYPES = ImmutableList.of(SenderType.NONPLAYER, SenderType.ANY);
public static List<SenderType> getSenderTypes(String value)
{
if (value == null) throw new NullPointerException("value");
if (isPlayerValue(value)) return PLAYER_TYPES;
else return NONPLAYER_TYPES;
}
public static boolean isPlayerValue(String value)
{
return IdUtil.isPlayerId(value);
//return MUtil.isValidPlayerName(value) || MUtil.isUuid(value);
}
}

View File

@ -0,0 +1,54 @@
package com.massivecraft.massivecore.util;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
class SenderMapTest
{
static SenderMap map = new SenderMap();
public static void main(String[] args)
{
map.addValue("Madus", SenderPresence.LOCAL); // Satisfying
//printMap();
map.removeValueCompletely("Madus"); // Satisfying
//printMap();
map.addValue("Madus", SenderPresence.LOCAL); // Satisfying
map.addValue("Cayorion", SenderPresence.ONLINE); // Satisfying
//printMap();
map.removeValueCompletely("madus"); // Satisfying (case insensitive)
//printMap();
map.addValue("@console", SenderPresence.OFFLINE); // Satisfying
//printMap();
System.out.println(map.getPresence("@console")); // Satisfying (OFFLINE)
System.out.println(map.getPresence("caYorioN")); // Satisfying (ONLINE)
System.out.println(map.getPresence("MaDus")); // Satisfying (null)
}
public static void printMap()
{
printMap(map);
}
public static void printMap(SenderMap map)
{
for (Entry<SenderPresence, Map<SenderType, Set<String>>> entry1 : map.getInnerMap().entrySet())
{
System.out.println(entry1.getKey());
for (Entry<SenderType, Set<String>> entry2 : entry1.getValue().entrySet())
{
System.out.println(" " + entry2.getKey() + ": " + entry2.getValue());
}
}
}
}