diff --git a/src/com/massivecraft/mcore/MCore.java b/src/com/massivecraft/mcore/MCore.java index 5a79c8ec..abb7ad4d 100644 --- a/src/com/massivecraft/mcore/MCore.java +++ b/src/com/massivecraft/mcore/MCore.java @@ -2,6 +2,8 @@ package com.massivecraft.mcore; import java.lang.reflect.Modifier; import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import java.util.Random; import java.util.UUID; @@ -29,7 +31,9 @@ import com.massivecraft.mcore.ps.PSAdapter; import com.massivecraft.mcore.store.Coll; import com.massivecraft.mcore.store.ExamineThread; import com.massivecraft.mcore.teleport.EngineScheduledTeleport; +import com.massivecraft.mcore.util.MUtil; import com.massivecraft.mcore.util.PlayerUtil; +import com.massivecraft.mcore.util.Txt; import com.massivecraft.mcore.xlib.bson.types.ObjectId; import com.massivecraft.mcore.xlib.gson.Gson; import com.massivecraft.mcore.xlib.gson.GsonBuilder; @@ -155,6 +159,7 @@ public class MCore extends MPlugin MultiverseColl.get().init(); AspectColl.get().init(); MCoreConfColl.get().init(); + MCoreMPlayerColl.get().init(); // Register commands this.outerCmdMCore = new CmdMCore() { public List getAliases() { return MCoreConf.get().aliasesOuterMCore; } }; @@ -172,7 +177,7 @@ public class MCore extends MPlugin VaultFeatures.get() ); - // test(); + //test(); // Delete Files (at once and additionally after all plugins loaded) TaskDeleteFiles.get().run(); @@ -189,7 +194,18 @@ public class MCore extends MPlugin try { - // whatever you fee like + // whatever you feel like + for (int i = 0; i <= 1; i++) + { + Map map = PlayerUtil.getPlayerIds(MUtil.list("Cayorion", "MonMarty", "Thortuna", "yendor46", "Gethelp", "Th3_Drunk_Monk", "Ryciera", "Jamescl", "spectec", "Tom1804", "imboring56", "BigBellyBuddah", "MrHappyTinkles", "BabaManga", "_Omnomivore_", "Cielian", "BboyMVB", "MrWackeo", "Kellock93", "Feykronos", "Unluvable", "DanyWood", "jadex224", "MinecraftSpartan", "ravenwolfthorn", "ELtongo", "Azas", "TazeHD", "BillyA835", "duhsigil", "Sahrotaar", "Alj23")); + for (Entry entry : map.entrySet()) + { + String playerName = entry.getKey(); + UUID playerId = entry.getValue(); + log(Txt.parse("%s %s", playerName, playerId.toString())); + } + log("==========================="); + } } catch (Exception e) { diff --git a/src/com/massivecraft/mcore/MCoreMPlayer.java b/src/com/massivecraft/mcore/MCoreMPlayer.java new file mode 100644 index 00000000..eb4d875c --- /dev/null +++ b/src/com/massivecraft/mcore/MCoreMPlayer.java @@ -0,0 +1,49 @@ +package com.massivecraft.mcore; + +import com.massivecraft.mcore.store.Entity; + +public class MCoreMPlayer extends Entity +{ + // -------------------------------------------- // + // META + // -------------------------------------------- // + + public static MCoreMPlayer get(Object oid) + { + return MCoreMPlayerColl.get().get(oid); + } + + public static MCoreMPlayer get(Object oid, boolean creative) + { + return MCoreMPlayerColl.get().get(oid, creative); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public MCoreMPlayer load(MCoreMPlayer that) + { + this.name = that.name; + + return this; + } + + @Override + public boolean isDefault() + { + if (this.name != null) return false; + + return true; + } + + // -------------------------------------------- // + // FIELDS + // -------------------------------------------- // + + private String name = null; + public String getName() { return this.name; } + public void setName(String name) { this.name = name; this.changed(); } + +} diff --git a/src/com/massivecraft/mcore/MCoreMPlayerColl.java b/src/com/massivecraft/mcore/MCoreMPlayerColl.java new file mode 100644 index 00000000..4a18fed8 --- /dev/null +++ b/src/com/massivecraft/mcore/MCoreMPlayerColl.java @@ -0,0 +1,74 @@ +package com.massivecraft.mcore; + +import java.util.UUID; + +import org.bukkit.entity.Player; + +import com.massivecraft.mcore.store.Coll; +import com.massivecraft.mcore.store.MStore; +import com.massivecraft.mcore.util.MUtil; + +public class MCoreMPlayerColl extends Coll +{ + // -------------------------------------------- // + // INSTANCE & CONSTRUCT + // -------------------------------------------- // + + private static MCoreMPlayerColl i = new MCoreMPlayerColl(); + public static MCoreMPlayerColl get() { return i; } + public MCoreMPlayerColl() + { + super("mcore_mplayer", MCoreMPlayer.class, MStore.getDb(), MCore.get(), false, false, true); + } + + // -------------------------------------------- // + // OVERRIDE + // -------------------------------------------- // + + @Override + public String fixId(Object oid) + { + if (oid == null) return null; + + if (oid instanceof MCoreMPlayer) + { + return this.entity2id.get(oid); + } + + if (oid instanceof String) + { + String string = (String)oid; + string = string.toLowerCase(); + + // Handle Player Name + if (MUtil.isValidPlayerName(string)) + { + // TODO: Improve the speed of this using an index! + for (MCoreMPlayer mplayer : this.getAll()) + { + String name = mplayer.getName(); + if (name == null) continue; + if (!string.equals(name.toLowerCase())) continue; + return mplayer.getId(); + } + } + + return string; + } + + if (oid instanceof UUID) + { + UUID uuid = (UUID)oid; + return uuid.toString(); + } + + if (oid instanceof Player) + { + Player player = (Player)oid; + return player.getUniqueId().toString(); + } + + return null; + } + +} diff --git a/src/com/massivecraft/mcore/util/PlayerUtil.java b/src/com/massivecraft/mcore/util/PlayerUtil.java index 8bacbc6d..8c40de45 100644 --- a/src/com/massivecraft/mcore/util/PlayerUtil.java +++ b/src/com/massivecraft/mcore/util/PlayerUtil.java @@ -1,8 +1,16 @@ package com.massivecraft.mcore.util; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; +import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; import java.util.concurrent.ConcurrentSkipListSet; import net.minecraft.server.v1_7_R2.EntityPlayer; @@ -19,6 +27,7 @@ import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerQuitEvent; import com.massivecraft.mcore.MCore; +import com.massivecraft.mcore.MCoreMPlayer; public class PlayerUtil implements Listener { @@ -138,4 +147,223 @@ public class PlayerUtil implements Listener eplayer.playerConnection.sendPacket(new PacketPlayOutUpdateHealth(cplayer.getScaledHealth(), eplayer.getFoodData().a(), eplayer.getFoodData().e())); } + // -------------------------------------------- // + // PLAYER ID <---> PLAYER NAME + // -------------------------------------------- // + + public static String getPlayerName(final UUID playerId, final boolean usingCache, final boolean usingMojangApi) + { + List playerIds = Collections.singletonList(playerId); + Map map = getPlayerNames(playerIds, usingCache, usingMojangApi); + return map.get(playerId); + } + public static String getPlayerName(final UUID playerId, final boolean usingCache) + { + return getPlayerName(playerId, usingCache, true); + } + public static String getPlayerName(final UUID playerId) + { + return getPlayerName(playerId, true); + } + + public static UUID getPlayerId(final String playerName, final boolean usingCache, final boolean usingMojangApi) + { + List playerNames = Collections.singletonList(playerName); + Map map = getPlayerIds(playerNames, usingCache, usingMojangApi); + return map.get(playerName); + } + public static UUID getPlayerId(final String playerName, final boolean usingCache) + { + return getPlayerId(playerName, usingCache, true); + } + public static UUID getPlayerId(final String playerName) + { + return getPlayerId(playerName, true); + } + + // I suggest using ... + // final Map ret = new TreeMap(String.CASE_INSENSITIVE_ORDER); + // ... since you achieve case insensitivity that way. + public static Map getPlayerIds(Collection playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete, Map ret) + { + // Finalize Args + // To run the Async task we need final versions of all arguments. + // We shallow copy the array for the sake of concurrency and that we will want to remove those we could handle from cache in order to avoid contacting the mojang api in vain. + // We need a return value map. Create one if null. Here we do however not shallow copy. We aim to edit the supplied map instance so that it can be used inside the onComplete Runnable. + final List playerNamesFinal = new ArrayList(playerNames); + final Map retFinal = (ret != null ? ret : new TreeMap(String.CASE_INSENSITIVE_ORDER)); + + // Handle Async + // Just run sync from another thread. + if (!synchronous) + { + Bukkit.getScheduler().runTaskAsynchronously(MCore.get(), new Runnable() + { + @Override + public void run() + { + PlayerUtil.getPlayerIds(playerNamesFinal, usingCache, usingMojangApi, true, onComplete, retFinal); + } + }); + return retFinal; + } + + // Handle Cache + if (usingCache) + { + Iterator iter = playerNamesFinal.iterator(); + while (iter.hasNext()) + { + String playerName = iter.next(); + MCoreMPlayer mplayer = MCoreMPlayer.get(playerName); + if (mplayer == null) continue; + retFinal.put(mplayer.getName(), UUID.fromString(mplayer.getId())); + iter.remove(); + } + } + + // Handle Mojang Api + if (usingMojangApi && playerNamesFinal.size() > 0) + { + try + { + Map mojangApiResult = MojangApiUtil.getPlayerIds(playerNamesFinal); + // Add to the cache + for (Entry entry : mojangApiResult.entrySet()) + { + String name = entry.getKey(); + UUID id = entry.getValue(); + MCoreMPlayer mplayer = MCoreMPlayer.get(id, true); + mplayer.setName(name); + } + // Add to the return value + retFinal.putAll(mojangApiResult); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + // Run the onComplete task. + if (onComplete != null) + { + onComplete.run(); + } + + // Return + return retFinal; + } + public static Map getPlayerIds(Collection playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete) + { + return getPlayerIds(playerNames, usingCache, usingMojangApi, synchronous, onComplete, null); + } + public static Map getPlayerIds(Collection playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous) + { + return getPlayerIds(playerNames, usingCache, usingMojangApi, synchronous, null); + } + public static Map getPlayerIds(Collection playerNames, final boolean usingCache, final boolean usingMojangApi) + { + return getPlayerIds(playerNames, usingCache, usingMojangApi, true); + } + public static Map getPlayerIds(Collection playerNames, final boolean usingCache) + { + return getPlayerIds(playerNames, usingCache, true); + } + public static Map getPlayerIds(Collection playerNames) + { + return getPlayerIds(playerNames, true); + } + + public static Map getPlayerNames(Collection playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete, Map ret) + { + // Finalize Args + // To run the Async task we need final versions of all arguments. + // We shallow copy the array for the sake of concurrency and that we will want to remove those we could handle from cache in order to avoid contacting the mojang api in vain. + // We need a return value map. Create one if null. Here we do however not shallow copy. We aim to edit the supplied map instance so that it can be used inside the onComplete Runnable. + final List playerIdsFinal = new ArrayList(playerIds); + final Map retFinal = (ret != null ? ret : new HashMap()); + + // Handle Async + // Just run sync from another thread. + if (!synchronous) + { + Bukkit.getScheduler().runTaskAsynchronously(MCore.get(), new Runnable() + { + @Override + public void run() + { + PlayerUtil.getPlayerNames(playerIdsFinal, usingCache, usingMojangApi, true, onComplete, retFinal); + } + }); + return retFinal; + } + + // Handle Cache + if (usingCache) + { + Iterator iter = playerIdsFinal.iterator(); + while (iter.hasNext()) + { + UUID playerId = iter.next(); + MCoreMPlayer mplayer = MCoreMPlayer.get(playerId); + if (mplayer == null) continue; + retFinal.put(playerId, mplayer.getName()); + iter.remove(); + } + } + + // Handle Mojang Api + if (usingMojangApi && playerIdsFinal.size() > 0) + { + try + { + Map mojangApiResult = MojangApiUtil.getPlayerNames(playerIdsFinal); + // Add to the cache + for (Entry entry : mojangApiResult.entrySet()) + { + UUID id = entry.getKey(); + String name = entry.getValue(); + MCoreMPlayer mplayer = MCoreMPlayer.get(id, true); + mplayer.setName(name); + } + // Add to the return value + retFinal.putAll(mojangApiResult); + } + catch (Exception e) + { + e.printStackTrace(); + } + } + + // Run the onComplete task. + if (onComplete != null) + { + onComplete.run(); + } + + // Return + return retFinal; + } + public static Map getPlayerNames(Collection playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete) + { + return getPlayerNames(playerIds, usingCache, usingMojangApi, synchronous, onComplete, null); + } + public static Map getPlayerNames(Collection playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous) + { + return getPlayerNames(playerIds, usingCache, usingMojangApi, synchronous, null); + } + public static Map getPlayerNames(Collection playerIds, final boolean usingCache, final boolean usingMojangApi) + { + return getPlayerNames(playerIds, usingCache, usingMojangApi, true); + } + public static Map getPlayerNames(Collection playerIds, final boolean usingCache) + { + return getPlayerNames(playerIds, usingCache, true); + } + public static Map getPlayerNames(Collection playerIds) + { + return getPlayerNames(playerIds, true); + } + }