diff --git a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java index 5f23eee..8d6c1cb 100644 --- a/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/BlockEventHandler.java @@ -51,6 +51,7 @@ import org.bukkit.event.world.StructureGrowEvent; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.PlayerInventory; +import org.bukkit.material.Dispenser; import org.bukkit.util.Vector; //event handlers related to blocks @@ -763,24 +764,10 @@ public class BlockEventHandler implements Listener { //from where? Block fromBlock = dispenseEvent.getBlock(); + Dispenser dispenser = new Dispenser(fromBlock.getType(), fromBlock.getData()); //to where? - Vector velocity = dispenseEvent.getVelocity(); - int xChange = 0; - int zChange = 0; - if(Math.abs(velocity.getX()) > Math.abs(velocity.getZ())) - { - if(velocity.getX() > 0) xChange = 1; - else xChange = -1; - } - else - { - if(velocity.getZ() > 0) zChange = 1; - else zChange = -1; - } - - Block toBlock = fromBlock.getRelative(xChange, 0, zChange); - + Block toBlock = fromBlock.getRelative(dispenser.getFacing()); Claim fromClaim = this.dataStore.getClaimAt(fromBlock.getLocation(), false, null); Claim toClaim = this.dataStore.getClaimAt(toBlock.getLocation(), false, fromClaim); diff --git a/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java b/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java index 5779807..b303442 100644 --- a/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/DatabaseDataStore.java @@ -95,6 +95,7 @@ public class DatabaseDataStore extends DataStore { GriefPrevention.AddLogEntry("ERROR: Unable to create the necessary database table. Details:"); GriefPrevention.AddLogEntry(e3.getMessage()); + e3.printStackTrace(); throw e3; } @@ -133,6 +134,85 @@ public class DatabaseDataStore extends DataStore this.nextClaimID = results.getLong("nextid"); } + if(this.getSchemaVersion() == 0) + { + try + { + this.refreshDataConnection(); + + //pull ALL player data from the database + statement = this.databaseConnection.createStatement(); + results = statement.executeQuery("SELECT * FROM griefprevention_playerdata;"); + + //make a list of changes to be made + HashMap changes = new HashMap(); + + ArrayList namesToConvert = new ArrayList(); + while(results.next()) + { + //get the id + String playerName = results.getString("name"); + + //ignore groups + if(playerName.startsWith("$")) continue; + + //add to list of names to convert to UUID + namesToConvert.add(playerName); + } + + //resolve and cache as many as possible through various means + try + { + UUIDFetcher fetcher = new UUIDFetcher(namesToConvert); + fetcher.call(); + } + catch(Exception e) + { + GriefPrevention.AddLogEntry("Failed to resolve a batch of names to UUIDs. Details:" + e.getMessage()); + e.printStackTrace(); + } + + //reset results cursor + results.beforeFirst(); + + //for each result + while(results.next()) + { + //get the id + String playerName = results.getString("name"); + + //ignore groups + if(playerName.startsWith("$")) continue; + + //try to convert player name to UUID + try + { + UUID playerID = UUIDFetcher.getUUIDOf(playerName); + + //if successful, update the playerdata row by replacing the player's name with the player's UUID + if(playerID != null) + { + changes.put(playerName, playerID); + } + } + //otherwise leave it as-is. no harm done - it won't be requested by name, and this update only happens once. + catch(Exception ex){ } + } + + for(String name : changes.keySet()) + { + statement = this.databaseConnection.createStatement(); + statement.execute("UPDATE griefprevention_playerdata SET name = '" + changes.get(name).toString() + "' WHERE name = '" + name + "';"); + } + } + catch(SQLException e) + { + GriefPrevention.AddLogEntry("Unable to convert player data. Details:"); + GriefPrevention.AddLogEntry(e.getMessage()); + e.printStackTrace(); + } + } + //load claims data into memory results = statement.executeQuery("SELECT * FROM griefprevention_claimdata;"); @@ -148,11 +228,30 @@ public class DatabaseDataStore extends DataStore long claimID = results.getLong("id"); - String lesserCornerString = results.getString("lessercorner"); - Location lesserBoundaryCorner = this.locationFromString(lesserCornerString); - - String greaterCornerString = results.getString("greatercorner"); - Location greaterBoundaryCorner = this.locationFromString(greaterCornerString); + Location lesserBoundaryCorner = null; + Location greaterBoundaryCorner = null; + try + { + String lesserCornerString = results.getString("lessercorner"); + lesserBoundaryCorner = this.locationFromString(lesserCornerString); + + String greaterCornerString = results.getString("greatercorner"); + greaterBoundaryCorner = this.locationFromString(greaterCornerString); + } + catch(Exception e) + { + if(e.getMessage().contains("World not found")) + { + Claim claim = new Claim(); + claim.id = claimID; + claimsToRemove.add(claim); + continue; + } + else + { + throw e; + } + } String ownerName = results.getString("owner"); UUID ownerID = null; @@ -166,7 +265,11 @@ public class DatabaseDataStore extends DataStore { ownerID = UUIDFetcher.getUUIDOf(ownerName); } - catch(Exception ex){ } //if UUID not found, use NULL + catch(Exception ex) + { + GriefPrevention.AddLogEntry("This owner name did not convert to aUUID: " + ownerName + "."); + GriefPrevention.AddLogEntry(" Converted land claim to administrative @ " + lesserBoundaryCorner.toString()); + } } else { @@ -221,10 +324,10 @@ public class DatabaseDataStore extends DataStore while(childResults.next()) { - lesserCornerString = childResults.getString("lessercorner"); + String lesserCornerString = childResults.getString("lessercorner"); lesserBoundaryCorner = this.locationFromString(lesserCornerString); - greaterCornerString = childResults.getString("greatercorner"); + String greaterCornerString = childResults.getString("greatercorner"); greaterBoundaryCorner = this.locationFromString(greaterCornerString); buildersString = childResults.getString("builders"); @@ -248,7 +351,7 @@ public class DatabaseDataStore extends DataStore //add this claim to the list of children of the current top level claim childClaim.parent = topLevelClaim; topLevelClaim.children.add(childClaim); - childClaim.inDataStore = true; + childClaim.inDataStore = true; } } catch(SQLException e) @@ -263,57 +366,6 @@ public class DatabaseDataStore extends DataStore this.deleteClaimFromSecondaryStorage(claimsToRemove.get(i)); } - if(this.getSchemaVersion() == 0) - { - try - { - this.refreshDataConnection(); - - //pull ALL player data from the database - statement = this.databaseConnection.createStatement(); - results = statement.executeQuery("SELECT * FROM griefprevention_playerdata;"); - - //make a list of changes to be made - HashMap changes = new HashMap(); - - //for each result - while(results.next()) - { - //get the id - String playerName = results.getString("name"); - - //ignore groups - if(playerName.startsWith("$")) continue; - - //try to convert player name to UUID - try - { - UUID playerID = UUIDFetcher.getUUIDOf(playerName); - - //if successful, update the playerdata row by replacing the player's name with the player's UUID - if(playerID != null) - { - changes.put(playerName, playerID); - } - } - //otherwise leave it as-is. no harm done - it won't be requested by name, and this update only happens once. - catch(Exception ex){ } - } - - for(String name : changes.keySet()) - { - statement = this.databaseConnection.createStatement(); - statement.execute("UPDATE griefprevention_playerdata SET name = '" + changes.get(name).toString() + "' WHERE name = '" + name + "';"); - } - } - catch(SQLException e) - { - GriefPrevention.AddLogEntry("Unable to convert player data. Details:"); - GriefPrevention.AddLogEntry(e.getMessage()); - e.printStackTrace(); - } - } - super.initialize(); } @@ -441,8 +493,9 @@ public class DatabaseDataStore extends DataStore } catch(SQLException e) { - GriefPrevention.AddLogEntry("Unable to delete data for claim at " + this.locationToString(claim.lesserBoundaryCorner) + ". Details:"); + GriefPrevention.AddLogEntry("Unable to delete data for claim " + claim.id + ". Details:"); GriefPrevention.AddLogEntry(e.getMessage()); + e.printStackTrace(); } } diff --git a/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java b/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java index 3e8a0ef..34e2147 100644 --- a/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java +++ b/src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java @@ -127,6 +127,65 @@ public class FlatFileDataStore extends DataStore catch(IOException exception) {} } + //if converting up from schema version 0, rename player data files using UUIDs instead of player names + //get a list of all the files in the claims data folder + if(this.getSchemaVersion() == 0) + { + files = playerDataFolder.listFiles(); + ArrayList namesToConvert = new ArrayList(); + for(File playerFile : files) + { + //anything starting with an underscore or dollar sign isn't a player, ignore those + String currentFilename = playerFile.getName(); + if(currentFilename.startsWith("$") || currentFilename.startsWith("_")) continue; + + namesToConvert.add(currentFilename); + } + + //resolve and cache as many as possible through various means + try + { + UUIDFetcher fetcher = new UUIDFetcher(namesToConvert); + fetcher.call(); + } + catch(Exception e) + { + GriefPrevention.AddLogEntry("Failed to resolve a batch of names to UUIDs. Details:" + e.getMessage()); + e.printStackTrace(); + } + + //rename files + for(File playerFile : files) + { + //anything starting with an underscore or dollar sign isn't a player, ignore those + String currentFilename = playerFile.getName(); + if(currentFilename.startsWith("$") || currentFilename.startsWith("_")) continue; + + //try to convert player name to UUID + UUID playerID = null; + try + { + playerID = UUIDFetcher.getUUIDOf(currentFilename); + + //if successful, rename the file using the UUID + if(playerID != null) + { + playerFile.renameTo(new File(playerDataFolder, playerID.toString())); + } + + //otherwise hide it from the data store for the future + else + { + playerFile.renameTo(new File(playerDataFolder, "__" + currentFilename)); + } + } + catch(Exception ex) + { + playerFile.renameTo(new File(playerDataFolder, "__" + currentFilename)); + } + } + } + //load claims data into memory //get a list of all the files in the claims data folder files = claimDataFolder.listFiles(); @@ -201,7 +260,11 @@ public class FlatFileDataStore extends DataStore { ownerID = UUIDFetcher.getUUIDOf(ownerName); } - catch(Exception ex){ } //if UUID not found, use NULL + catch(Exception ex) + { + GriefPrevention.AddLogEntry("Couldn't resolve this name to a UUID: " + ownerName + "."); + GriefPrevention.AddLogEntry(" Converted land claim to administrative @ " + lesserBoundaryCorner.toString()); + } } else { @@ -290,7 +353,14 @@ public class FlatFileDataStore extends DataStore //if there's any problem with the file's content, log an error message and skip it catch(Exception e) { - GriefPrevention.AddLogEntry("Unable to load data for claim \"" + files[i].getName() + "\": " + e.toString()); + if(e.getMessage().contains("World not found")) + { + files[i].delete(); + } + else + { + GriefPrevention.AddLogEntry("Unable to load data for claim \"" + files[i].getName() + "\": " + e.toString()); + } } try @@ -301,42 +371,6 @@ public class FlatFileDataStore extends DataStore } } - //if converting up from schema version 0, rename files using UUIDs instead of player names - //get a list of all the files in the claims data folder - if(this.getSchemaVersion() == 0) - { - files = playerDataFolder.listFiles(); - for(File playerFile : files) - { - //anything starting with an underscore or dollar sign isn't a player, ignore those - String currentFilename = playerFile.getName(); - if(currentFilename.startsWith("$") || currentFilename.startsWith("_")) continue; - - //try to convert player name to UUID - UUID playerID = null; - try - { - playerID = UUIDFetcher.getUUIDOf(currentFilename); - - //if successful, rename the file using the UUID - if(playerID != null) - { - playerFile.renameTo(new File(playerDataFolder, playerID.toString())); - } - - //otherwise hide it from the data store for the future - else - { - playerFile.renameTo(new File(playerDataFolder, "__" + currentFilename)); - } - } - catch(Exception ex) - { - playerFile.renameTo(new File(playerDataFolder, "__" + currentFilename)); - } - } - } - super.initialize(); } diff --git a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java index 8c293e6..452e399 100644 --- a/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java +++ b/src/me/ryanhamshire/GriefPrevention/GriefPrevention.java @@ -83,7 +83,6 @@ public class GriefPrevention extends JavaPlugin public boolean config_claims_creationRequiresPermission; //whether creating claims with the shovel requires a permission public int config_claims_claimsExtendIntoGroundDistance; //how far below the shoveled block a new claim will reach public int config_claims_minSize; //minimum width and height for non-admin claims - public boolean config_claims_allowUnclaimInCreative; //whether players may unclaim land (resize or abandon) in creative mode public boolean config_claims_autoRestoreUnclaimedCreativeLand; //whether unclaimed land in creative worlds is automatically /restorenature-d public boolean config_claims_noBuildOutsideClaims; //whether players can build in survival worlds outside their claimed areas @@ -311,7 +310,6 @@ public class GriefPrevention extends JavaPlugin this.config_claims_trappedCooldownHours = config.getInt("GriefPrevention.Claims.TrappedCommandCooldownHours", 8); this.config_claims_noBuildOutsideClaims = config.getBoolean("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", false); this.config_claims_warnOnBuildOutside = config.getBoolean("GriefPrevention.Claims.WarnWhenBuildingOutsideClaims", true); - this.config_claims_allowUnclaimInCreative = config.getBoolean("GriefPrevention.Claims.AllowUnclaimingCreativeModeLand", true); this.config_claims_autoRestoreUnclaimedCreativeLand = config.getBoolean("GriefPrevention.Claims.AutoRestoreUnclaimedCreativeLand", true); this.config_claims_chestClaimExpirationDays = config.getInt("GriefPrevention.Claims.Expiration.ChestClaimDays", 7); @@ -571,7 +569,6 @@ public class GriefPrevention extends JavaPlugin outConfig.set("GriefPrevention.Claims.ModificationTool", this.config_claims_modificationTool.name()); outConfig.set("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", this.config_claims_noBuildOutsideClaims); outConfig.set("GriefPrevention.Claims.WarnWhenBuildingOutsideClaims", this.config_claims_warnOnBuildOutside); - outConfig.set("GriefPrevention.Claims.AllowUnclaimingCreativeModeLand", this.config_claims_allowUnclaimInCreative); outConfig.set("GriefPrevention.Claims.AutoRestoreUnclaimedCreativeLand", this.config_claims_autoRestoreUnclaimedCreativeLand); outConfig.set("GriefPrevention.Spam.Enabled", this.config_spam_enabled); @@ -841,12 +838,6 @@ public class GriefPrevention extends JavaPlugin { if(args.length != 0) return false; - if(!GriefPrevention.instance.config_claims_allowUnclaimInCreative && creativeRulesApply(player.getLocation())) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim); - return true; - } - //count claims PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId()); int originalClaimCount = playerData.claims.size(); @@ -1936,12 +1927,6 @@ public class GriefPrevention extends JavaPlugin GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotYourClaim); } - //don't allow abandon of creative mode claims - else if(!GriefPrevention.instance.config_claims_allowUnclaimInCreative && this.creativeRulesApply(player.getLocation())) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim); - } - //warn if has children and we're not explicitly deleting a top level claim else if(claim.children.size() > 0 && !deleteTopLevelClaim) { @@ -2200,8 +2185,6 @@ public class GriefPrevention extends JavaPlugin } //if none found - GriefPrevention.AddLogEntry("Error: Failed to find a local player with UUID: " + playerID.toString()); - new Exception().printStackTrace(); return "someone"; } @@ -2242,15 +2225,15 @@ public class GriefPrevention extends JavaPlugin //called when a player spawns, applies protection for that player if necessary public void checkPvpProtectionNeeded(Player player) { - //if pvp is disabled, do nothing + //if anti spawn camping feature is not enabled, do nothing + if(!this.config_pvp_protectFreshSpawns) return; + + //if pvp is disabled, do nothing if(!this.config_pvp_enabledWorlds.contains(player.getWorld())) return; //if player is in creative mode, do nothing if(player.getGameMode() == GameMode.CREATIVE) return; - //if anti spawn camping feature is not enabled, do nothing - if(!this.config_pvp_protectFreshSpawns) return; - //if the player has the damage any player permission enabled, do nothing if(player.hasPermission("griefprevention.nopvpimmunity")) return; diff --git a/src/me/ryanhamshire/GriefPrevention/PlayerData.java b/src/me/ryanhamshire/GriefPrevention/PlayerData.java index 4bf0b4e..e75204f 100644 --- a/src/me/ryanhamshire/GriefPrevention/PlayerData.java +++ b/src/me/ryanhamshire/GriefPrevention/PlayerData.java @@ -117,13 +117,16 @@ public class PlayerData PlayerData() { - //default last login date value to a year ago to ensure a brand new player can log in + //default last login date value to 5 minutes ago to ensure a brand new player can log in //see login cooldown feature, PlayerEventHandler.onPlayerLogin() //if the player successfully logs in, this value will be overwritten with the current date and time - Calendar lastYear = Calendar.getInstance(); - lastYear.add(Calendar.YEAR, -1); - this.lastLogin = lastYear.getTime(); - this.lastTrappedUsage = lastYear.getTime(); + Calendar fiveMinutesBack = Calendar.getInstance(); + fiveMinutesBack.add(Calendar.MINUTE, -5); + this.lastLogin = fiveMinutesBack.getTime(); + + //default last trapped usage to 5 hours ago, so the command is available right away + fiveMinutesBack.add(Calendar.HOUR, -5); + this.lastTrappedUsage = fiveMinutesBack.getTime(); } //whether or not this player is "in" pvp combat diff --git a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java index d3e45a4..9c10595 100644 --- a/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java +++ b/src/me/ryanhamshire/GriefPrevention/PlayerEventHandler.java @@ -481,7 +481,6 @@ class PlayerEventHandler implements Listener PlayerData playerData = this.dataStore.getPlayerData(playerID); playerData.lastSpawn = now; playerData.lastLogin = new Date(); - this.dataStore.savePlayerData(playerID, playerData); //if player has never played on the server before, may need pvp protection if(!player.hasPlayedBefore()) @@ -1558,9 +1557,8 @@ class PlayerEventHandler implements Listener } } - //special rules for making a top-level claim smaller. to check this, verifying the old claim's corners are inside the new claim's boundaries. - //rule1: in creative mode, top-level claims can't be moved or resized smaller. - //rule2: in any mode, shrinking a claim removes any surface fluids + //special rule for making a top-level claim smaller. to check this, verifying the old claim's corners are inside the new claim's boundaries. + //rule: in any mode, shrinking a claim removes any surface fluids Claim oldClaim = playerData.claimResizing; boolean smaller = false; if(oldClaim.parent == null) @@ -1576,13 +1574,6 @@ class PlayerEventHandler implements Listener { smaller = true; - //enforce creative mode rule - if(!GriefPrevention.instance.config_claims_allowUnclaimInCreative && !player.hasPermission("griefprevention.deleteclaims") && GriefPrevention.instance.creativeRulesApply(player.getLocation())) - { - GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoCreativeUnClaim); - return; - } - //remove surface fluids about to be unclaimed oldClaim.removeSurfaceFluids(newClaim); } diff --git a/src/me/ryanhamshire/GriefPrevention/UUIDFetcher.java b/src/me/ryanhamshire/GriefPrevention/UUIDFetcher.java index 996252a..f027fb5 100644 --- a/src/me/ryanhamshire/GriefPrevention/UUIDFetcher.java +++ b/src/me/ryanhamshire/GriefPrevention/UUIDFetcher.java @@ -18,7 +18,7 @@ import java.nio.ByteBuffer; import java.util.*; import java.util.concurrent.Callable; -class UUIDFetcher implements Callable> { +class UUIDFetcher { private static final double PROFILES_PER_REQUEST = 100; private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; private final JSONParser jsonParser = new JSONParser(); @@ -29,7 +29,7 @@ class UUIDFetcher implements Callable> { private static HashMap lookupCache; public UUIDFetcher(List names, boolean rateLimiting) { - this.names = ImmutableList.copyOf(names); + this.names = names; this.rateLimiting = rateLimiting; } @@ -37,26 +37,98 @@ class UUIDFetcher implements Callable> { this(names, true); } - public Map call() throws Exception { - Map uuidMap = new HashMap(); - int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); - for (int i = 0; i < requests; i++) { - HttpURLConnection connection = createConnection(); - String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size()))); - writeBody(connection, body); - JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); - for (Object profile : array) { - JSONObject jsonProfile = (JSONObject) profile; - String id = (String) jsonProfile.get("id"); - String name = (String) jsonProfile.get("name"); - UUID uuid = UUIDFetcher.getUUID(id); - uuidMap.put(name, uuid); - } - if (rateLimiting && i != requests - 1) { - Thread.sleep(100L); + public void call() throws Exception + { + if(lookupCache == null) + { + lookupCache = new HashMap(); + } + + GriefPrevention.AddLogEntry("UUID conversion process started. Please be patient - this may take a while."); + + //try to get correct casing from local data + OfflinePlayer [] players = GriefPrevention.instance.getServer().getOfflinePlayers(); + GriefPrevention.AddLogEntry("Checking local server data to get correct casing for player names..."); + for(int i = 0; i < names.size(); i++) + { + String name = names.get(i); + for(OfflinePlayer player : players) + { + if(player.getName().equalsIgnoreCase(name)) + { + if(!player.getName().equals(name)) + { + GriefPrevention.AddLogEntry(name + " --> " + player.getName()); + names.set(i, player.getName()); + continue; + } + } + } + } + + //look for local data first + GriefPrevention.AddLogEntry("Checking local server data for UUIDs already seen..."); + for(int i = 0; i < names.size(); i++) + { + String name = names.get(i); + for(OfflinePlayer player : players) + { + if(player.getName().equalsIgnoreCase(name)) + { + UUID uuid = player.getUniqueId(); + if(uuid != null) + { + GriefPrevention.AddLogEntry(name + " --> " + uuid.toString()); + lookupCache.put(name, uuid); + lookupCache.put(name.toLowerCase(), uuid); + names.remove(i--); + continue; + } + } + } + } + + //for online mode, call Mojang to resolve the rest + if(GriefPrevention.instance.getServer().getOnlineMode()) + { + GriefPrevention.AddLogEntry("Calling Mojang to get UUIDs for remaining unresolved players (this is the slowest step)..."); + + int requests = (int) Math.ceil(names.size() / PROFILES_PER_REQUEST); + for (int i = 0; i < requests; i++) + { + HttpURLConnection connection = createConnection(); + String body = JSONArray.toJSONString(names.subList(i * 100, Math.min((i + 1) * 100, names.size()))); + writeBody(connection, body); + JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); + for (Object profile : array) { + JSONObject jsonProfile = (JSONObject) profile; + String id = (String) jsonProfile.get("id"); + String name = (String) jsonProfile.get("name"); + UUID uuid = UUIDFetcher.getUUID(id); + GriefPrevention.AddLogEntry(name + " --> " + uuid.toString()); + lookupCache.put(name, uuid); + lookupCache.put(name.toLowerCase(), uuid); + } + if (rateLimiting && i != requests - 1) { + Thread.sleep(200L); + } + } + } + + //for offline mode, generate UUIDs for the rest + else + { + GriefPrevention.AddLogEntry("Generating offline mode UUIDs for remaining unresolved players..."); + + for(int i = 0; i < names.size(); i++) + { + String name = names.get(i); + UUID uuid = java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + name).getBytes(Charsets.UTF_8)); + GriefPrevention.AddLogEntry(name + " --> " + uuid.toString()); + lookupCache.put(name, uuid); + lookupCache.put(name.toLowerCase(), uuid); } } - return uuidMap; } private static void writeBody(HttpURLConnection connection, String body) throws Exception { @@ -100,76 +172,14 @@ class UUIDFetcher implements Callable> { public static UUID getUUIDOf(String name) throws Exception { - if(lookupCache == null) - { - lookupCache = new HashMap(); - } - UUID result = lookupCache.get(name); if(result == null) { - if(lookupCache.containsKey(name)) return null; - - //use local minecraft player data to try correcting a name to the correct casing - String correctCasingName = getNameWithCasing(name); - - //online mode: look it up by calling Mojang's web service - if(GriefPrevention.instance.getServer().getOnlineMode() == true) - { - result = new UUIDFetcher(Arrays.asList(name)).call().get(correctCasingName); - } - - //offline mode best guess - else - { - //search server's minecraft player data to find a UUID - OfflinePlayer [] players = GriefPrevention.instance.getServer().getOfflinePlayers(); - for(OfflinePlayer player : players) - { - if(player.getName().equals(correctCasingName)) - { - result = player.getUniqueId(); - break; - } - } - - //if that doesn't work, make a wild guess by imitating what Mojang reportedly does - if(result == null) - { - result = java.util.UUID.nameUUIDFromBytes(("OfflinePlayer:" + correctCasingName).getBytes(Charsets.UTF_8)); - } - } - - //if none of the above worked, throw up our hands and report the problem in the logs + //throw up our hands and report the problem in the logs //this player will lose his land claim blocks, but claims will stay in place as admin claims - if(result == null) - { - GriefPrevention.AddLogEntry(correctCasingName + " --> ???"); - lookupCache.put(name, null); - throw new IllegalArgumentException(name); - } - GriefPrevention.AddLogEntry(correctCasingName + " --> " + result.toString()); - lookupCache.put(name, result); + throw new IllegalArgumentException(name); } - return result; - } - - private static String getNameWithCasing(String name) - { - OfflinePlayer [] players = GriefPrevention.instance.getServer().getOfflinePlayers(); - for(OfflinePlayer player : players) - { - if(player.getName().equalsIgnoreCase(name)) - { - if(!player.getName().equals(name)) - { - GriefPrevention.AddLogEntry(name + " --> " + player.getName()); - } - return player.getName(); - } - } - - return name; + return result; } } \ No newline at end of file diff --git a/src/me/ryanhamshire/GriefPrevention/Visualization.java b/src/me/ryanhamshire/GriefPrevention/Visualization.java index 28c70ce..d7ed81d 100644 --- a/src/me/ryanhamshire/GriefPrevention/Visualization.java +++ b/src/me/ryanhamshire/GriefPrevention/Visualization.java @@ -66,6 +66,8 @@ public class Visualization for(int i = 0; i < visualization.elements.size(); i++) { VisualizationElement element = visualization.elements.get(i); + if(!element.location.getChunk().isLoaded()) continue; + if(element.location.distanceSquared(player.getLocation()) > 10000) continue; Block block = element.location.getBlock(); player.sendBlockChange(element.location, block.getType(), block.getData()); } @@ -198,7 +200,14 @@ public class Visualization //finds a block the player can probably see. this is how visualizations "cling" to the ground or ceiling private static Location getVisibleLocation(World world, int x, int y, int z) { - Block block = world.getBlockAt(x, y, z); + //cheap distance check - also avoids loading chunks just for a big visualization + Location location = new Location(world, x, y, z); + if(!location.getChunk().isLoaded()) + { + return location; + } + + Block block = world.getBlockAt(x, y, z); BlockFace direction = (isTransparent(block)) ? BlockFace.DOWN : BlockFace.UP; while( block.getY() >= 1 && diff --git a/src/me/ryanhamshire/GriefPrevention/VisualizationApplicationTask.java b/src/me/ryanhamshire/GriefPrevention/VisualizationApplicationTask.java index 774093e..0380d9b 100644 --- a/src/me/ryanhamshire/GriefPrevention/VisualizationApplicationTask.java +++ b/src/me/ryanhamshire/GriefPrevention/VisualizationApplicationTask.java @@ -43,6 +43,7 @@ class VisualizationApplicationTask implements Runnable VisualizationElement element = visualization.elements.get(i); //send the player a fake block change event + if(!element.location.getChunk().isLoaded()) continue; //cheap distance check player.sendBlockChange(element.location, element.visualizedMaterial, element.visualizedData); }