diff --git a/pom.xml b/pom.xml index cec0553af..e649e58e1 100755 --- a/pom.xml +++ b/pom.xml @@ -78,6 +78,7 @@ com.turt2live.metrics:MetricsExtension commons-logging:commons-logging net.snaq:dbpool + com.turt2live:UUID-Library @@ -93,6 +94,10 @@ net.snaq com.gmail.nossr50.dbpool + + com.turt2live.uuid + com.gmail.nossr50.uuid + @@ -123,7 +128,7 @@ http://repo.md-5.net/content/repositories/releases/ - Plugin MetricsExtension + turt2live-repo http://repo.turt2live.com @@ -151,6 +156,11 @@ dbpool 5.1 + + com.turt2live + UUID-Library + 0.0.1-SNAPSHOT + diff --git a/src/main/java/com/gmail/nossr50/config/Config.java b/src/main/java/com/gmail/nossr50/config/Config.java index 3aa8d1706..d09cac8ba 100644 --- a/src/main/java/com/gmail/nossr50/config/Config.java +++ b/src/main/java/com/gmail/nossr50/config/Config.java @@ -250,6 +250,7 @@ public class Config extends AutoUpdateConfigLoader { public boolean getUpdateCheckEnabled() { return config.getBoolean("General.Update_Check", true); } public boolean getPreferBeta() { return config.getBoolean("General.Prefer_Beta", false); } public boolean getVerboseLoggingEnabled() { return config.getBoolean("General.Verbose_Logging", false); } + public boolean getUseUUIDWebCache(){ return config.getBoolean("General.Use_UUID_Web_Cache", false); } public String getPartyChatPrefix() { return config.getString("Commands.partychat.Chat_Prefix_Format", "[[GREEN]]([[WHITE]]{0}[[GREEN]])"); } public boolean getPartyChatColorLeaderName() { return config.getBoolean("Commands.partychat.Gold_Leader_Name", true); } diff --git a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java index 54504e8c6..a14e44fa8 100644 --- a/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java +++ b/src/main/java/com/gmail/nossr50/runnables/database/UUIDUpdateAsyncTask.java @@ -13,9 +13,10 @@ import com.gmail.nossr50.config.HiddenConfig; import com.gmail.nossr50.database.DatabaseManager; import com.gmail.nossr50.datatypes.database.UpgradeType; import com.gmail.nossr50.util.Misc; -import com.gmail.nossr50.util.uuid.UUIDFetcher; +import com.gmail.nossr50.util.uuid.UUIDService; public class UUIDUpdateAsyncTask extends BukkitRunnable { + private mcMMO plugin; private static final int MAX_LOOKUP = Math.max(HiddenConfig.getInstance().getUUIDConvertAmount(), 100); private static final int RATE_LIMIT = HiddenConfig.getInstance().getMojangRateLimit(); @@ -25,6 +26,7 @@ public class UUIDUpdateAsyncTask extends BukkitRunnable { private List userNames; private int size; private int checkedUsers; + private int fetchedUsers; private long startMillis; public UUIDUpdateAsyncTask(mcMMO plugin, List userNames) { @@ -32,12 +34,14 @@ public class UUIDUpdateAsyncTask extends BukkitRunnable { this.userNames = userNames; this.checkedUsers = 0; + this.fetchedUsers = 0; this.startMillis = System.currentTimeMillis(); } @Override public void run() { size = userNames.size(); + UUIDService uuidService = null; plugin.getLogger().info("Starting to check and update UUIDs, total amount of users: " + size); @@ -45,7 +49,7 @@ public class UUIDUpdateAsyncTask extends BukkitRunnable { Map fetchedUUIDs = new HashMap(); while (size != 0) { - if (checkedUsers + 100 > RATE_LIMIT) { + if (fetchedUsers + 100 > RATE_LIMIT) { try { Thread.sleep(LIMIT_PERIOD); } catch (InterruptedException e) { @@ -53,25 +57,27 @@ public class UUIDUpdateAsyncTask extends BukkitRunnable { return; } startMillis = System.currentTimeMillis(); - checkedUsers = 0; + fetchedUsers = 0; } if (size > MAX_LOOKUP) { userNamesSection = userNames.subList(size - MAX_LOOKUP, size); size -= MAX_LOOKUP; - } - else { + } else { userNamesSection = userNames.subList(0, size); size = 0; } try { - fetchedUUIDs.putAll(new UUIDFetcher(userNamesSection).call()); - } - catch (Exception e) { + if (uuidService == null) uuidService = new UUIDService(userNamesSection); + else uuidService.setList(userNamesSection); + + fetchedUUIDs.putAll(uuidService.call()); + } catch (Exception e) { plugin.getLogger().log(Level.SEVERE, "Unable to fetch UUIDs!", e); return; } + fetchedUsers += uuidService.getNumberFetched(); checkedUsers += userNamesSection.size(); userNamesSection.clear(); size = userNames.size(); diff --git a/src/main/java/com/gmail/nossr50/util/uuid/UUIDService.java b/src/main/java/com/gmail/nossr50/util/uuid/UUIDService.java new file mode 100644 index 000000000..065ec952d --- /dev/null +++ b/src/main/java/com/gmail/nossr50/util/uuid/UUIDService.java @@ -0,0 +1,111 @@ +package com.gmail.nossr50.util.uuid; + +import com.gmail.nossr50.config.Config; +import com.google.common.collect.ImmutableList; +import com.turt2live.uuid.CachingServiceProvider; +import com.turt2live.uuid.PlayerRecord; +import com.turt2live.uuid.ServiceProvider; +import com.turt2live.uuid.turt2live.v2.ApiV2Service; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +/** + * Service layer for UUIDs + * + * @author turt2live + */ +public class UUIDService { + + private static final int SERVICE_LIMIT_PER_REQUEST = 100; + + private static ServiceProvider UUID_PROVIDER; + + private List names; + private int numFetched = 0; // From last request + + /** + * Creates a new UUID service that takes a list of usernames + * to lookup via {@link #call()} + * + * @param names the names to lookup + */ + public UUIDService(List names) { + this.names = ImmutableList.copyOf(names); + } + + /** + * Sets a new list of names to parse + * + * @param names the names to lookup + */ + public void setList(List names) { + this.names = ImmutableList.copyOf(names); + } + + /** + * Parses the predefined list of names to a UUID map + * + * @return the generated map + */ + public Map call() throws Exception { + int fetched = 0; + Map map = new HashMap(); + + if (Config.getInstance().getUseUUIDWebCache()) { + int requests = (int) Math.ceil(names.size() / SERVICE_LIMIT_PER_REQUEST); + for (int i = 0; i < requests; i++) { + List subNames = names.subList(i * SERVICE_LIMIT_PER_REQUEST, Math.min((i + 1) * SERVICE_LIMIT_PER_REQUEST, names.size())); + List records = UUID_PROVIDER.doBulkLookup(subNames.toArray(new String[subNames.size()])); + + // List only includes successful lookups + for (PlayerRecord record : records) { + map.put(record.getName(), record.getUuid()); + if (!record.isCached()) fetched++; + } + } + } else { + map = new UUIDFetcher(names).call(); + fetched = map.size(); + } + + numFetched = fetched; + return map; + } + + /** + * Gets the number of profiles that were actually fetched from the last + * call to {@link #call()}. + * + * @return the number of profiles actually fetched + */ + public int getNumberFetched() { + return numFetched; + } + + /** + * Gets the UUID for the supplied username + * + * @param name the username to lookup, cannot be null + * + * @return the UUID, if found. + * + * @throws Exception thrown if something goes wrong + */ + public static UUID getUUIDOf(String name) throws Exception { + if (name == null) throw new IllegalArgumentException(); + + if (Config.getInstance().getUseUUIDWebCache()) { + if (UUID_PROVIDER == null) initProvider(); + PlayerRecord record = UUID_PROVIDER.doLookup(name); + return record == null ? null : record.getUuid(); + } else return UUIDFetcher.getUUIDOf(name); + } + + private static void initProvider() { + UUID_PROVIDER = new CachingServiceProvider(new ApiV2Service()); + } + +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index a0ace507a..2a3b9d592 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -26,6 +26,10 @@ General: Config_Update_Overwrite: true # Play level-up sounds LevelUp_Sounds: true + # Instead of asking Mojang for UUIDs, should mcMMO access a web caching service + # for player UUIDs? If enabled, mcMMO will use the web service. If disabled, mcMMO + # will use Mojang. + Use_UUID_Web_Cache: false # This should fix blocks being broken client side, but not server-side. # Enable to refresh the chunks around a player at the end of Super Breaker,