Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * To change this license header, choose License Headers in Project Properties.
- * To change this template file, choose Tools | Templates
- * and open the template in the editor.
- */
- package sander;
- import java.io.IOException;
- import java.net.URL;
- import java.net.URLConnection;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Scanner;
- import java.util.UUID;
- import java.util.concurrent.Callable;
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.Future;
- import java.util.concurrent.FutureTask;
- import org.bukkit.Bukkit;
- import org.bukkit.plugin.Plugin;
- import org.bukkit.scheduler.BukkitRunnable;
- import org.json.simple.JSONObject;
- import org.json.simple.parser.JSONParser;
- import org.json.simple.parser.ParseException;
- /**
- *
- * @author Fernando
- */
- public class UUIDResolver {
- private static final String USERNAME_DATA = "https://api.mojang.com/users/profiles/minecraft/%USERNAME%";
- private static final String USERNAME_DATA_TIME = "https://api.mojang.com/users/profiles/minecraft/%USERNAME%?at=%TIMESTAMP%";
- private static final String UUID_PREVIOUS_NAMES = "https://api.mojang.com/user/profiles/%UUID%/names";
- private static final String UUID_SKIN_INFO = "https://sessionserver.mojang.com/session/minecraft/profile/%UUID%?unsigned=false";
- private final Plugin plugin;
- public UUIDResolver(Plugin plugin) {
- this.plugin = plugin;
- }
- /**
- * The cache used to store player names to uuid's
- */
- private final Map<String, Pair<FutureTask<UUID>, List<Callback<UUID>>>> playerNameCache = new HashMap<>();
- public UUID getUUIDAsync(String username) throws InterruptedException, ExecutionException
- {
- return Bukkit.getScheduler().<Future<UUID>>callSyncMethod(plugin, new Callable<Future<UUID>>() {
- @Override
- public Future<UUID> call() throws Exception {
- return getUUID(username);
- }
- }).get().get();
- }
- /**
- * Gets the UUID from a username, This method needs to be called from the
- * main thread
- *
- * @param userName Thge username to lookup
- * @return Returns a Future object, do not call get() on it from the main
- * bukkit thread
- */
- public Future<UUID> getUUID(String userName) {
- return this.getUUID(userName, null);
- }
- /**
- * Gets the UUID from a username, This method needs to be called from the
- * main thread
- *
- * @param userName Thge username to lookup
- * @param callBack This will be called when the lookup is done
- * @return Returns a Future object, do not call get() on it from the main
- * bukkit thread
- */
- public Future<UUID> getUUID(String userName, Callback<UUID> callBack) {
- return this.<UUID, String>resolve(userName, playerNameCache, callBack,
- uuidConverter,
- "https://api.mojang.com/users/profiles/minecraft/%s", userName);
- }
- /**
- * The cache used to store player names and times to uuid's
- */
- private final Map<Pair<String, Long>, Pair<FutureTask<UUID>, List<Callback<UUID>>>> playerNameTimeCache = new HashMap<>();
- /**
- * Gets the UUID from a username, This method needs to be called from the
- * main thread
- *
- * @param userName Thge username to lookup
- * @param unixTime Time to lookup
- * @return Returns a Future object, do not call get() on it from the main
- * bukkit thread
- */
- public Future<UUID> getUUID(String userName, long unixTime) {
- return this.getUUID(userName, unixTime, null);
- }
- /**
- * Gets the UUID from a username, This method needs to be called from the
- * main thread
- *
- * @param userName Thge username to lookup
- * @param unixTime Time to lookup
- * @param callBack This will be called when the lookup is done
- * @return Returns a Future object, do not call get() on it from the main
- * bukkit thread
- */
- public Future<UUID> getUUID(String userName, long unixTime, Callback<UUID> callBack) {
- return this.<UUID, Pair<String, Long>>resolve(new Pair<>(userName, unixTime), playerNameTimeCache, callBack,
- uuidConverter,
- "https://api.mojang.com/users/profiles/minecraft/%s?at=%d",
- userName, unixTime);
- }
- /**
- * The cache used to store player names to uuid's
- */
- private final Map<UUID, Pair<FutureTask<JSONObject>, List<Callback<JSONObject>>>> playerDataCache = new HashMap<>();
- public JSONObject getInternalDataAsync(UUID uuid) throws InterruptedException, ExecutionException
- {
- return Bukkit.getScheduler().<Future<JSONObject>>callSyncMethod(plugin, new Callable<Future<JSONObject>>() {
- @Override
- public Future<JSONObject> call() throws Exception {
- return getInternalData(uuid);
- }
- }).get().get();
- }
- public Future<JSONObject> getInternalData(UUID userName)
- {
- return this.getInternalData(userName,null);
- }
- /**
- * This method needs to be called from the
- * main thread
- *
- * @param userName The UUID to lookup
- * @param callBack This will be called when the lookup is done
- * @return Returns a Future object, do not call get() on it from the main
- * bukkit thread
- */
- public Future<JSONObject> getInternalData(UUID userName, Callback<JSONObject> callBack) {
- return this.<JSONObject, UUID>resolve(userName, playerDataCache, callBack,
- new ResponseResolver<JSONObject>() {
- @Override
- public JSONObject resolveResult(JSONObject obj) {
- return obj;
- }
- },
- "https://api.mojang.com/users/profiles/minecraft/%s", userName.toString().replaceAll("-", ""));
- }
- /**
- * Read a json object from a url
- *
- * @param url
- * @return
- * @throws ParseException
- * @throws IOException
- */
- private JSONObject readJSONFromURL(URL url)
- throws ParseException, IOException {
- URLConnection uc = url.openConnection();
- uc.setUseCaches(true);
- uc.setDefaultUseCaches(true);
- uc.addRequestProperty("User-Agent", "Java Bigteddy98 UUID Library");
- try (Scanner scanner = new Scanner(uc.getInputStream())) {
- scanner.useDelimiter("\\A");
- return (JSONObject) new JSONParser().parse(scanner.next());
- }
- }
- /**
- * Private class used to convert the json response to the correct object
- */
- private interface ResponseResolver<R> {
- public R resolveResult(JSONObject obj);
- }
- /**
- * Private class used to convert the json response to a uuid
- */
- private static final ResponseResolver<UUID> uuidConverter
- = new ResponseResolver<UUID>() {
- @Override
- public UUID resolveResult(JSONObject obj) {
- return UUID.fromString(obj.get("id").toString().replaceAll(
- "(\\w{8})(\\w{4})(\\w{4})(\\w{4})(\\w{12})",
- "$1-$2-$3-$4-$5"));
- }
- };
- /**
- * Private method used to resolve the queries
- *
- * @param <R> The result of the operation
- * @param <I> The unique input of the operation, this will be used to lookup
- * the cache result
- * @param cacheIndex This is the unique value of the result in the cache
- * @param cache The Map<...> object used to hold the cached values
- * @param callback This object will be called when the request is done
- * @param request Its the job of the <code>RequestResolver</code> to convert
- * the <code>JSONObject</code> back to the object the code needs
- * @param baseUrl The main url used for this operation, this will be passed
- * to <code>String.format</code>
- * @param formats The arguments for <code>String.format</code>
- * @return This method returns a Future<R> to see what the result of the
- * request is
- */
- private <R, I> Future<R> resolve(
- I cacheIndex, Map<I, Pair<FutureTask<R>, List<Callback<R>>>> cache,
- Callback<R> callback, ResponseResolver<R> request,
- String baseUrl, Object... formats) {
- if (!Bukkit.isPrimaryThread()) {
- throw new IllegalStateException(
- "You need to call this method from the main thread "
- + "because of the request limits Mojang has configured");
- }
- if (!cache.containsKey(cacheIndex)) {
- final List<Callback<R>> callBackList = new LinkedList<>();
- FutureTask<R> task = new FutureTask<R>(new Callable<R>() {
- @Override
- public R call() throws Exception {
- assert !Bukkit.isPrimaryThread();
- return request.resolveResult(UUIDResolver.this.readJSONFromURL(
- new URL(String.format(baseUrl, (Object[]) formats))
- ));
- }
- }) {
- @Override
- protected void done() {
- FutureTask<R> th = this;
- new BukkitRunnable() {
- @Override
- public void run() {
- assert Bukkit.isPrimaryThread();
- for (Callback<R> id : callBackList) {
- id.onCallBack(th);
- }
- callBackList.clear();
- }
- }.runTask(plugin);
- }
- };
- cache.put(cacheIndex, new Pair<>(task, callBackList));
- Bukkit.getScheduler().runTaskAsynchronously(plugin, task);
- }
- assert cache.containsKey(cacheIndex);
- Pair<FutureTask<R>, List<Callback<R>>> result
- = cache.get(cacheIndex);
- if (result.first.isDone()) {
- if (!result.second.isEmpty()) {
- for (Callback<R> c : result.second) {
- c.onCallBack(result.first);
- }
- result.second = Collections.emptyList();
- }
- if (callback != null) {
- callback.onCallBack(result.first);
- }
- } else {
- if (callback != null) {
- result.second.add(callback);
- }
- }
- return result.first;
- }
- /**
- * This class contains a pair of other objects
- * <p>
- * Taken from: <br/>
- * <a href="http://stackoverflow.com/a/677248/1542723">StackOverflow</a>
- *
- * @param <A> first type
- * @param <B> second type
- */
- private static class Pair<A, B> {
- private A first;
- private B second;
- public Pair(A first, B second) {
- super();
- this.first = first;
- this.second = second;
- }
- @Override
- public int hashCode() {
- int hashFirst = first != null ? first.hashCode() : 0;
- int hashSecond = second != null ? second.hashCode() : 0;
- return (hashFirst + hashSecond) * hashSecond + hashFirst;
- }
- @Override
- public boolean equals(Object other) {
- if (other instanceof Pair) {
- Pair otherPair = (Pair) other;
- return ((this.first == otherPair.first
- || (this.first != null && otherPair.first != null
- && this.first.equals(otherPair.first)))
- && (this.second == otherPair.second
- || (this.second != null && otherPair.second != null
- && this.second.equals(otherPair.second))));
- }
- return false;
- }
- @Override
- public String toString() {
- return "(" + first + ", " + second + ")";
- }
- public A getFirst() {
- return first;
- }
- public void setFirst(A first) {
- this.first = first;
- }
- public B getSecond() {
- return second;
- }
- public void setSecond(B second) {
- this.second = second;
- }
- }
- /**
- * Class used to pass the results back to the parent stack
- *
- * @param <E>
- */
- public interface Callback<E> {
- /**
- * This method is called when the lookup is done
- *
- * @param result The result of the operation
- */
- public void onCallBack(FutureTask<E> result);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment