Starting development on a Player name and id framework with bult in caching. Still missing index for reverse lookup speed improvement. Still missing information updates on player join.

This commit is contained in:
Olof Larsson 2014-04-09 14:11:22 +02:00
parent ebb5cbe74a
commit d73d453994
4 changed files with 369 additions and 2 deletions

View File

@ -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<String> getAliases() { return MCoreConf.get().aliasesOuterMCore; } };
@ -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<String, UUID> 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<String, UUID> entry : map.entrySet())
{
String playerName = entry.getKey();
UUID playerId = entry.getValue();
log(Txt.parse("<k>%s <v>%s", playerName, playerId.toString()));
}
log("===========================");
}
}
catch (Exception e)
{

View File

@ -0,0 +1,49 @@
package com.massivecraft.mcore;
import com.massivecraft.mcore.store.Entity;
public class MCoreMPlayer extends Entity<MCoreMPlayer>
{
// -------------------------------------------- //
// 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(); }
}

View File

@ -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<MCoreMPlayer>
{
// -------------------------------------------- //
// 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;
}
}

View File

@ -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<UUID> playerIds = Collections.singletonList(playerId);
Map<UUID, String> 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<String> playerNames = Collections.singletonList(playerName);
Map<String, UUID> 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<String, UUID> ret = new TreeMap<String, UUID>(String.CASE_INSENSITIVE_ORDER);
// ... since you achieve case insensitivity that way.
public static Map<String, UUID> getPlayerIds(Collection<String> playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete, Map<String, UUID> 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<String> playerNamesFinal = new ArrayList<String>(playerNames);
final Map<String, UUID> retFinal = (ret != null ? ret : new TreeMap<String, UUID>(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<String> 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<String, UUID> mojangApiResult = MojangApiUtil.getPlayerIds(playerNamesFinal);
// Add to the cache
for (Entry<String, UUID> 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<String, UUID> getPlayerIds(Collection<String> playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete)
{
return getPlayerIds(playerNames, usingCache, usingMojangApi, synchronous, onComplete, null);
}
public static Map<String, UUID> getPlayerIds(Collection<String> playerNames, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous)
{
return getPlayerIds(playerNames, usingCache, usingMojangApi, synchronous, null);
}
public static Map<String, UUID> getPlayerIds(Collection<String> playerNames, final boolean usingCache, final boolean usingMojangApi)
{
return getPlayerIds(playerNames, usingCache, usingMojangApi, true);
}
public static Map<String, UUID> getPlayerIds(Collection<String> playerNames, final boolean usingCache)
{
return getPlayerIds(playerNames, usingCache, true);
}
public static Map<String, UUID> getPlayerIds(Collection<String> playerNames)
{
return getPlayerIds(playerNames, true);
}
public static Map<UUID, String> getPlayerNames(Collection<UUID> playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete, Map<UUID, String> 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<UUID> playerIdsFinal = new ArrayList<UUID>(playerIds);
final Map<UUID, String> retFinal = (ret != null ? ret : new HashMap<UUID, String>());
// 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<UUID> 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<UUID, String> mojangApiResult = MojangApiUtil.getPlayerNames(playerIdsFinal);
// Add to the cache
for (Entry<UUID, String> 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<UUID, String> getPlayerNames(Collection<UUID> playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous, final Runnable onComplete)
{
return getPlayerNames(playerIds, usingCache, usingMojangApi, synchronous, onComplete, null);
}
public static Map<UUID, String> getPlayerNames(Collection<UUID> playerIds, final boolean usingCache, final boolean usingMojangApi, final boolean synchronous)
{
return getPlayerNames(playerIds, usingCache, usingMojangApi, synchronous, null);
}
public static Map<UUID, String> getPlayerNames(Collection<UUID> playerIds, final boolean usingCache, final boolean usingMojangApi)
{
return getPlayerNames(playerIds, usingCache, usingMojangApi, true);
}
public static Map<UUID, String> getPlayerNames(Collection<UUID> playerIds, final boolean usingCache)
{
return getPlayerNames(playerIds, usingCache, true);
}
public static Map<UUID, String> getPlayerNames(Collection<UUID> playerIds)
{
return getPlayerNames(playerIds, true);
}
}