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();
if (MUtil.isntPlayer(watcher)) return;
// Get the lowercased token
String tokenlc = event.getLastToken().toLowerCase();
// Get the lowercased token predicate
Predictate<String> predictate = PredictateStartsWithIgnoreCase.get(event.getLastToken());
// Create a case insensitive set to check for already added stuff
Set<String> current = new TreeSet<String>(String.CASE_INSENSITIVE_ORDER);
current.addAll(event.getTabCompletions());
// 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 (!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 com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds;
import com.massivecraft.massivecore.util.IdUtil;
@ -15,7 +17,7 @@ public class ARPlayer extends ARSenderIdAbstract<Player>
public static ARPlayer get() { return i; }
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 com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.store.SenderIdSourceMixinAllSenderIds;
import com.massivecraft.massivecore.util.IdUtil;
@ -15,7 +17,7 @@ public class ARSender extends ARSenderIdAbstract<CommandSender>
public static ARSender get() { return i; }
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 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.SenderEntity;
@ -18,15 +20,15 @@ public class ARSenderEntity<T extends SenderEntity<T>> extends ARSenderIdAbstrac
// 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;
}
private ARSenderEntity(SenderColl<T> coll, boolean onlineOnly)
private ARSenderEntity(SenderColl<T> coll, SenderPresence presence)
{
super(coll, onlineOnly);
super(coll, presence);
this.coll = coll;
}
@ -40,8 +42,8 @@ public class ARSenderEntity<T extends SenderEntity<T>> extends ARSenderIdAbstrac
// 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, boolean onlineOnly) { return new ARSenderEntity<T>(coll, onlineOnly); }
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, 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); }
// -------------------------------------------- //

View File

@ -1,5 +1,7 @@
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.SenderIdSourceMixinAllSenderIds;
@ -9,14 +11,14 @@ public class ARSenderId extends ARSenderIdAbstract<String>
// 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)
@ -35,8 +37,8 @@ public class ARSenderId extends ARSenderIdAbstract<String>
// GET
// -------------------------------------------- //
public static ARSenderId get(SenderIdSource source, boolean onlineOnly, boolean playerOnly) { return new ARSenderId(source, onlineOnly, playerOnly); }
public static ARSenderId get(SenderIdSource source, boolean onlineOnly) { return new ARSenderId(source, onlineOnly); }
public static ARSenderId get(SenderIdSource source, SenderPresence presence, SenderType type) { return new ARSenderId(source, presence, type); }
public static ARSenderId get(SenderIdSource source, SenderPresence presence) { return new ARSenderId(source, presence); }
public static ARSenderId get(SenderIdSource source) { return new ARSenderId(source); }
// -------------------------------------------- //

View File

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

View File

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

View File

@ -9,6 +9,8 @@ import org.bukkit.command.CommandSender;
import org.bukkit.plugin.Plugin;
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.ARSenderId;
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.
if (this.isCreative())
{
ret.add(IdUtil.getAllIds());
ret.add(IdUtil.getIds(SenderPresence.ANY, SenderType.ANY));
}
return ret;
@ -129,9 +131,9 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
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()
@ -139,9 +141,9 @@ public class SenderColl<E extends SenderEntity<E>> extends Coll<E> implements Se
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.List;
import com.massivecraft.massivecore.SenderPresence;
import com.massivecraft.massivecore.SenderType;
import com.massivecraft.massivecore.util.IdUtil;
public class SenderIdSourceMixinAllSenderIds implements SenderIdSource
@ -23,7 +25,7 @@ public class SenderIdSourceMixinAllSenderIds implements SenderIdSource
public Collection<Collection<String>> getSenderIdCollections()
{
List<Collection<String>> ret = new ArrayList<Collection<String>>();
ret.add(IdUtil.getAllIds());
ret.add(IdUtil.getIds(SenderPresence.ANY, SenderType.ANY));
return ret;
}

View File

@ -5,12 +5,12 @@ import java.lang.reflect.Type;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.ConcurrentSkipListSet;
import org.bukkit.Bukkit;
import org.bukkit.GameMode;
@ -24,6 +24,8 @@ import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerLoginEvent;
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.EventMassiveCoreSenderRegister;
import com.massivecraft.massivecore.event.EventMassiveCoreSenderUnregister;
@ -106,24 +108,19 @@ public class IdUtil implements Listener, Runnable
// -------------------------------------------- //
// Used for chat tab completion, argument readers, etc.
private static Set<String> onlineIds = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
public static Set<String> getOnlineIds() { return Collections.unmodifiableSet(onlineIds); }
private static SenderMap maintainedIds = new SenderMap();
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);
public static Set<String> getOnlineNames() { return Collections.unmodifiableSet(onlineNames); }
private static Set<String> onlinePlayerNames = new ConcurrentSkipListSet<String>(String.CASE_INSENSITIVE_ORDER);
public static Set<String> getOnlinePlayerNames() { return Collections.unmodifiableSet(onlinePlayerNames); }
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); }
private static SenderMap maintainedNames = new SenderMap();
public static SenderMap getMaintainedNames() { return maintainedNames; }
public static Set<String> getNames(SenderPresence presence, SenderType type)
{
return maintainedNames.getValues(presence, type);
}
// -------------------------------------------- //
// 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.
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>();
public static Map<CommandSender, String> getRegistrySenderToId() { return Collections.unmodifiableMap(registrySenderToId); }
public static void register(CommandSender sender)
{
@ -145,7 +145,7 @@ public class IdUtil implements Listener, Runnable
registrySenderToId.put(sender, id);
// 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);
event.run();
@ -163,7 +163,7 @@ public class IdUtil implements Listener, Runnable
if (removed == null) return;
// 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);
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.
public static Set<CommandSender> getOnlineSenders()
public static Set<CommandSender> getLocalSenders()
{
Set<CommandSender> ret = new LinkedHashSet<CommandSender>();
@ -199,8 +199,7 @@ public class IdUtil implements Listener, Runnable
{
if (id == null) throw new NullPointerException("id");
onlineIds.remove(id);
allIds.remove(id);
maintainedIds.removeValueCompletely(id);
IdData data = idToData.remove(id);
if (data == null) return null;
@ -213,10 +212,7 @@ public class IdUtil implements Listener, Runnable
{
if (name == null) throw new NullPointerException("name");
onlineNames.remove(name);
onlinePlayerNames.remove(name);
allNames.remove(name);
allPlayerNames.remove(name);
maintainedNames.removeValueCompletely(name);
IdData data = nameToData.remove(name);
if (data == null) return null;
@ -224,9 +220,11 @@ public class IdUtil implements Listener, Runnable
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 (presence == null) throw new NullPointerException("presence");
String id = data.getId();
String name = data.getName();
@ -244,15 +242,9 @@ public class IdUtil implements Listener, Runnable
if (id != null && name != null)
{
boolean player = MUtil.isValidPlayerName(name);
if (online) onlineIds.add(id);
allIds.add(id);
if (online && player) onlinePlayerNames.add(name);
if (online) onlineNames.add(name);
if (player) allPlayerNames.add(name);
allNames.add(name);
List<SenderPresence> presences = SenderMap.getPresences(presence);
maintainedIds.addValue(id, presences);
maintainedNames.addValue(name, presences);
}
}
@ -266,12 +258,12 @@ public class IdUtil implements Listener, Runnable
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
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.
if (previousMillis != null && previousMillis > millis) return;
// Online Fix
if (online == null)
// Presence Fix
if (presence == null)
{
if (id != null)
{
online = onlineIds.contains(id);
presence = maintainedIds.getPresence(id);
}
else if (name != null)
{
online = onlineNames.contains(name);
presence = maintainedNames.getPresence(name);
}
}
// Removal of previous data
// TODO: This is not optimal but will do for now. It only "uproots" one step.
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);
removeIdAndNameRecurse(id, name);
// Adding new data
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();
nameToData.clear();
onlineIds.clear();
onlineNames.clear();
onlinePlayerNames.clear();
maintainedIds.clear();
maintainedNames.clear();
allIds.clear();
allNames.clear();
allPlayerNames.clear();
// Load Datas
loadDatas();
@ -394,9 +394,11 @@ public class IdUtil implements Listener, Runnable
String name = player.getName();
// 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);
update(id, name, online);
update(id, name, SenderPresence.fromOnline(online));
}
// Can't be cancelled
@ -410,10 +412,8 @@ public class IdUtil implements Listener, Runnable
String id = uuid.toString();
String name = player.getName();
// Joining? Sure, the player is online!
boolean online = true;
update(id, name, online);
// Joining? The player must be local at this point.
update(id, name, SenderPresence.LOCAL);
}
// Can't be cancelled
@ -428,9 +428,21 @@ public class IdUtil implements Listener, Runnable
String name = player.getName();
// 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
// CommandSender
// UUID
if (senderObject instanceof CommandSender || senderObject instanceof UUID)
if (senderObject instanceof CommandSender)
{
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);
}
@ -620,8 +638,8 @@ public class IdUtil implements Listener, Runnable
// Already Done
if (senderObject instanceof String && MUtil.isUuid((String)senderObject)) return (String)senderObject;
// Console Type
if (senderObject instanceof ConsoleCommandSender) return CONSOLE_ID;
// Console
// Handled at "Command Sender"
// Console Id/Name
if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID;
@ -634,13 +652,13 @@ public class IdUtil implements Listener, Runnable
}
// Player
if (senderObject instanceof Player) return ((Player)senderObject).getUniqueId().toString();
// Handled at "Command Sender"
// CommandSender
if (senderObject instanceof CommandSender) return ((CommandSender)senderObject).getName().toLowerCase();
// Command Sender
if (senderObject instanceof CommandSender) return getIdFromSender((CommandSender) senderObject);
// UUID
if (senderObject instanceof UUID) return ((UUID)senderObject).toString();
if (senderObject instanceof UUID) return getIdFromUuid((UUID) senderObject);
// String
// Handled at "Data"
@ -656,6 +674,18 @@ public class IdUtil implements Listener, Runnable
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)
{
// Null Return
@ -664,8 +694,8 @@ public class IdUtil implements Listener, Runnable
// Already Done
// Handled at "Data" (not applicable - names can look differently)
// Console Type
if (senderObject instanceof ConsoleCommandSender) return CONSOLE_ID;
// Console
// Handled at "Command Sender"
// Console Id/Name
if (CONSOLE_ID.equals(senderObject)) return CONSOLE_ID;
@ -678,10 +708,10 @@ public class IdUtil implements Listener, Runnable
}
// Player
// Handled at "CommandSender"
// Handled at "Command Sender"
// CommandSender
if (senderObject instanceof CommandSender) return ((CommandSender)senderObject).getName();
if (senderObject instanceof CommandSender) return getNameFromSender((CommandSender)senderObject);
// UUID
// Handled at "Data".
@ -705,10 +735,15 @@ public class IdUtil implements Listener, Runnable
return null;
}
public static String getNameFromSender(CommandSender sender)
{
if (sender instanceof ConsoleCommandSender) return CONSOLE_ID;
return sender.getName();
}
public static boolean isOnline(Object senderObject)
{
// Fix the id ...
if (senderObject == null) return false;
String id = getId(senderObject);
if (id == null) return false;
@ -717,7 +752,7 @@ public class IdUtil implements Listener, Runnable
if (CONSOLE_ID.equals(id)) return true;
// ... 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)
@ -733,7 +768,7 @@ public class IdUtil implements Listener, Runnable
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);
}
@ -805,20 +840,20 @@ public class IdUtil implements Listener, Runnable
MassiveCore.get().log(Txt.parse("<i>Loading Cachefile datas..."));
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..."));
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..."));
for (String id : registryIdToSender.keySet())
{
String name = id;
update(id, name, true);
update(id, name, SenderPresence.LOCAL);
}
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
public static Set<IdData> getOnlineplayerDatas()
public static Set<IdData> getLocalPlayerDatas()
{
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());
}
}
}
}