UUID Migration Rework, Bug Fixes
Using multi-faceted strategy to better resolve UUIDs, and do it faster. Fixed dispensers putting fluids in a neighboring claim. Automatically deleting claims for worlds which no longer exist. Streamlined visualization code, hopefully will reduce or eliminate weird visualizations for VERY big land claims. Removed option to disallow un-claiming land in creative mode. Better default for last login date for new players or players who've had their data deleted or lost.
This commit is contained in:
parent
bf4d5ee633
commit
29a2b8e17b
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String, UUID> changes = new HashMap<String, UUID>();
|
||||
|
||||
ArrayList<String> namesToConvert = new ArrayList<String>();
|
||||
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<String, UUID> changes = new HashMap<String, UUID>();
|
||||
|
||||
//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();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<String> namesToConvert = new ArrayList<String>();
|
||||
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();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import java.nio.ByteBuffer;
|
|||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
class UUIDFetcher implements Callable<Map<String, UUID>> {
|
||||
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<Map<String, UUID>> {
|
|||
private static HashMap<String, UUID> lookupCache;
|
||||
|
||||
public UUIDFetcher(List<String> names, boolean rateLimiting) {
|
||||
this.names = ImmutableList.copyOf(names);
|
||||
this.names = names;
|
||||
this.rateLimiting = rateLimiting;
|
||||
}
|
||||
|
||||
|
|
@ -37,26 +37,98 @@ class UUIDFetcher implements Callable<Map<String, UUID>> {
|
|||
this(names, true);
|
||||
}
|
||||
|
||||
public Map<String, UUID> call() throws Exception {
|
||||
Map<String, UUID> uuidMap = new HashMap<String, UUID>();
|
||||
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<String, UUID>();
|
||||
}
|
||||
|
||||
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<Map<String, UUID>> {
|
|||
|
||||
public static UUID getUUIDOf(String name) throws Exception
|
||||
{
|
||||
if(lookupCache == null)
|
||||
{
|
||||
lookupCache = new HashMap<String, UUID>();
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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 &&
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user