Added UUID support.

Rewrote and retested parts of the plugin to use UUIDs instead of player
names to uniquely identify players.  Added data migration code to
convert old data to the new (UUID) format.
This commit is contained in:
ryanhamshire 2014-09-22 13:46:13 -07:00
parent e855f10a75
commit 6da42a9077
17 changed files with 877 additions and 259 deletions

View File

@ -109,7 +109,7 @@ public class BlockEventHandler implements Listener
if(claim == null || claim.allowContainers(player) == null) return;
//if the player is under siege, he can't give away items
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
if(playerData.siegeData != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoDrop);
@ -177,7 +177,7 @@ public class BlockEventHandler implements Listener
return;
}
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(block.getLocation(), true, playerData.lastClaim);
//if there's a claim here
@ -218,7 +218,7 @@ public class BlockEventHandler implements Listener
String signMessage = lines.toString();
//if not empty and wasn't the same as the last sign, log it and remember it for later
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
if(notEmpty && playerData.lastMessage != null && !playerData.lastMessage.equals(signMessage))
{
GriefPrevention.AddLogEntry("[Sign Placement] <" + player.getName() + "> " + lines.toString() + " @ " + GriefPrevention.getfriendlyLocationString(event.getBlock().getLocation()));
@ -275,7 +275,7 @@ public class BlockEventHandler implements Listener
}
//if the block is being placed within or under an existing claim
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(block.getLocation(), true, playerData.lastClaim);
if(claim != null)
{
@ -350,7 +350,7 @@ public class BlockEventHandler implements Listener
//radius == 0 means protect ONLY the chest
if(GriefPrevention.instance.config_claims_automaticClaimsForNewPlayersRadius == 0)
{
this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getName(), null, null);
this.dataStore.createClaim(block.getWorld(), block.getX(), block.getX(), block.getY(), block.getY(), block.getZ(), block.getZ(), player.getUniqueId(), null, null);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.ChestClaimConfirmation);
}
@ -363,7 +363,7 @@ public class BlockEventHandler implements Listener
block.getX() - radius, block.getX() + radius,
block.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, block.getY(),
block.getZ() - radius, block.getZ() + radius,
player.getName(),
player.getUniqueId(),
null, null).succeeded)
{
radius--;
@ -687,7 +687,7 @@ public class BlockEventHandler implements Listener
OfflinePlayer fromOwner = null;
if(fromClaim != null)
{
fromOwner = GriefPrevention.instance.getServer().getOfflinePlayer(fromClaim.ownerName);
fromOwner = GriefPrevention.instance.getServer().getOfflinePlayer(fromClaim.ownerID);
}
//cancel unless the owner of the spreading block is allowed to build in the receiving claim

View File

@ -25,6 +25,7 @@ import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.*;
import org.bukkit.*;
import org.bukkit.World.Environment;
@ -48,15 +49,15 @@ public class Claim
//id number. unique to this claim, never changes.
Long id = null;
//ownername. for admin claims, this is the empty string
//ownerID. for admin claims, this is NULL
//use getOwnerName() to get a friendly name (will be "an administrator" for admin claims)
public String ownerName;
public UUID ownerID;
//list of players who (beyond the claim owner) have permission to grant permissions in this claim
public ArrayList<String> managers = new ArrayList<String>();
//permissions for this claim, see ClaimPermission class
private HashMap<String, ClaimPermission> playerNameToClaimPermissionMap = new HashMap<String, ClaimPermission>();
private HashMap<String, ClaimPermission> playerIDToClaimPermissionMap = new HashMap<String, ClaimPermission>();
//whether or not this claim is in the data store
//if a claim instance isn't in the data store, it isn't "active" - players can't interract with it
@ -84,7 +85,7 @@ public class Claim
//administrative claims are created and maintained by players with the griefprevention.adminclaims permission.
public boolean isAdminClaim()
{
return (this.ownerName == null || this.ownerName.isEmpty());
return (this.ownerID == null);
}
//accessor for ID
@ -197,7 +198,7 @@ public class Claim
}
//main constructor. note that only creating a claim instance does nothing - a claim must be added to the data store to be effective
Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, String ownerName, String [] builderNames, String [] containerNames, String [] accessorNames, String [] managerNames, Long id)
Claim(Location lesserBoundaryCorner, Location greaterBoundaryCorner, UUID ownerID, String [] builderIDs, String [] containerIds, String [] accessorIDs, String [] managerIDs, Long id)
{
//modification date
this.modifiedDate = Calendar.getInstance().getTime();
@ -210,42 +211,42 @@ public class Claim
this.greaterBoundaryCorner = greaterBoundaryCorner;
//owner
this.ownerName = ownerName;
this.ownerID = ownerID;
//other permissions
for(int i = 0; i < builderNames.length; i++)
for(int i = 0; i < builderIDs.length; i++)
{
String name = builderNames[i];
if(name != null && !name.isEmpty())
String builderID = builderIDs[i];
if(builderID != null)
{
this.playerNameToClaimPermissionMap.put(name, ClaimPermission.Build);
this.playerIDToClaimPermissionMap.put(builderID, ClaimPermission.Build);
}
}
for(int i = 0; i < containerNames.length; i++)
for(int i = 0; i < containerIds.length; i++)
{
String name = containerNames[i];
if(name != null && !name.isEmpty())
String containerID = containerIds[i];
if(containerID != null)
{
this.playerNameToClaimPermissionMap.put(name, ClaimPermission.Inventory);
this.playerIDToClaimPermissionMap.put(containerID, ClaimPermission.Inventory);
}
}
for(int i = 0; i < accessorNames.length; i++)
for(int i = 0; i < accessorIDs.length; i++)
{
String name = accessorNames[i];
if(name != null && !name.isEmpty())
String accessorID = accessorIDs[i];
if(accessorID != null)
{
this.playerNameToClaimPermissionMap.put(name, ClaimPermission.Access);
this.playerIDToClaimPermissionMap.put(accessorID, ClaimPermission.Access);
}
}
for(int i = 0; i < managerNames.length; i++)
for(int i = 0; i < managerIDs.length; i++)
{
String name = managerNames[i];
if(name != null && !name.isEmpty())
String managerID = managerIDs[i];
if(managerID != null)
{
this.managers.add(name);
this.managers.add(managerID);
}
}
}
@ -275,7 +276,7 @@ public class Claim
Claim claim = new Claim
(new Location(this.lesserBoundaryCorner.getWorld(), this.lesserBoundaryCorner.getBlockX() - howNear, this.lesserBoundaryCorner.getBlockY(), this.lesserBoundaryCorner.getBlockZ() - howNear),
new Location(this.greaterBoundaryCorner.getWorld(), this.greaterBoundaryCorner.getBlockX() + howNear, this.greaterBoundaryCorner.getBlockY(), this.greaterBoundaryCorner.getBlockZ() + howNear),
"", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
null, new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
return claim.contains(location, false, true);
}
@ -302,7 +303,7 @@ public class Claim
}
//no resizing, deleting, and so forth while under siege
if(this.ownerName.equals(player.getName()))
if(player.getUniqueId().equals(this.ownerID))
{
if(this.siegeData != null)
{
@ -343,20 +344,20 @@ public class Claim
}
//no building while in pvp combat
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
if(playerData.inPvpCombat())
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoBuildPvP);
}
//owners can make changes, or admins with ignore claims mode enabled
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
if(player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims) return null;
//anyone with explicit build permission can make changes
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//also everyone is a member of the "public", so check for public permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
//also everyone is a member of the "public", so check for public permission, indicated by a null key
ClaimPermission permissionLevel = this.playerIDToClaimPermissionMap.get(null);
if(ClaimPermission.Build == permissionLevel) return null;
//subdivision permission inheritance
@ -372,13 +373,13 @@ public class Claim
private boolean hasExplicitPermission(Player player, ClaimPermission level)
{
String playerName = player.getName();
Set<String> keys = this.playerNameToClaimPermissionMap.keySet();
String playerID = player.getUniqueId().toString();
Set<String> keys = this.playerIDToClaimPermissionMap.keySet();
Iterator<String> iterator = keys.iterator();
while(iterator.hasNext())
{
String identifier = iterator.next();
if(playerName.equalsIgnoreCase(identifier) && this.playerNameToClaimPermissionMap.get(identifier) == level) return true;
if(playerID.equalsIgnoreCase(identifier) && this.playerIDToClaimPermissionMap.get(identifier) == level) return true;
else if(identifier.startsWith("[") && identifier.endsWith("]"))
{
@ -389,7 +390,7 @@ public class Claim
if(permissionIdentifier == null || permissionIdentifier.isEmpty()) continue;
//check permission
if(player.hasPermission(permissionIdentifier) && this.playerNameToClaimPermissionMap.get(identifier) == level) return true;
if(player.hasPermission(permissionIdentifier) && this.playerIDToClaimPermissionMap.get(identifier) == level) return true;
}
}
@ -408,7 +409,7 @@ public class Claim
for(int i = 0; i < GriefPrevention.instance.config_siege_blocks.size(); i++)
{
Material breakableMaterial = GriefPrevention.instance.config_siege_blocks.get(i);
if(breakableMaterial.getId() == material.getId())
if(breakableMaterial == material)
{
breakable = true;
break;
@ -420,7 +421,7 @@ public class Claim
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NonSiegeMaterial);
}
else if(this.ownerName.equals(player.getName()))
else if(player.getUniqueId().equals(this.ownerID))
{
return GriefPrevention.instance.dataStore.getMessage(Messages.NoOwnerBuildUnderSiege);
}
@ -447,7 +448,7 @@ public class Claim
}
//claim owner and admins in ignoreclaims mode have access
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
if(player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims) return null;
//look for explicit individual access, inventory, or build permission
if(this.hasExplicitPermission(player, ClaimPermission.Access)) return null;
@ -455,7 +456,7 @@ public class Claim
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//also check for public permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
ClaimPermission permissionLevel = this.playerIDToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel || ClaimPermission.Access == permissionLevel) return null;
//permission inheritance for subdivisions
@ -485,7 +486,7 @@ public class Claim
}
//owner and administrators in ignoreclaims mode have access
if(this.ownerName.equals(player.getName()) || GriefPrevention.instance.dataStore.getPlayerData(player.getName()).ignoreClaims) return null;
if(player.getUniqueId().equals(this.ownerID) || GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId()).ignoreClaims) return null;
//admin claims need adminclaims permission only.
if(this.isAdminClaim())
@ -498,7 +499,7 @@ public class Claim
if(this.hasExplicitPermission(player, ClaimPermission.Build)) return null;
//check for public container or build permission
ClaimPermission permissionLevel = this.playerNameToClaimPermissionMap.get("public");
ClaimPermission permissionLevel = this.playerIDToClaimPermissionMap.get("public");
if(ClaimPermission.Build == permissionLevel || ClaimPermission.Inventory == permissionLevel) return null;
//permission inheritance for subdivisions
@ -525,7 +526,7 @@ public class Claim
for(int i = 0; i < this.managers.size(); i++)
{
String managerID = this.managers.get(i);
if(player.getName().equalsIgnoreCase(managerID)) return null;
if(player.getUniqueId().toString().equals(managerID)) return null;
else if(managerID.startsWith("[") && managerID.endsWith("]"))
{
@ -547,21 +548,21 @@ public class Claim
}
//grants a permission for a player or the public
public void setPermission(String playerName, ClaimPermission permissionLevel)
public void setPermission(String playerID, ClaimPermission permissionLevel)
{
this.playerNameToClaimPermissionMap.put(playerName.toLowerCase(), permissionLevel);
this.playerIDToClaimPermissionMap.put(playerID.toLowerCase(), permissionLevel);
}
//revokes a permission for a player or the public
public void dropPermission(String playerName)
public void dropPermission(String playerID)
{
this.playerNameToClaimPermissionMap.remove(playerName.toLowerCase());
this.playerIDToClaimPermissionMap.remove(playerID.toLowerCase());
}
//clears all permissions (except owner of course)
public void clearPermissions()
{
this.playerNameToClaimPermissionMap.clear();
this.playerIDToClaimPermissionMap.clear();
}
//gets ALL permissions
@ -569,7 +570,7 @@ public class Claim
public void getPermissions(ArrayList<String> builders, ArrayList<String> containers, ArrayList<String> accessors, ArrayList<String> managers)
{
//loop through all the entries in the hash map
Iterator<Map.Entry<String, ClaimPermission>> mappingsIterator = this.playerNameToClaimPermissionMap.entrySet().iterator();
Iterator<Map.Entry<String, ClaimPermission>> mappingsIterator = this.playerIDToClaimPermissionMap.entrySet().iterator();
while(mappingsIterator.hasNext())
{
Map.Entry<String, ClaimPermission> entry = mappingsIterator.next();
@ -615,10 +616,10 @@ public class Claim
if(this.parent != null)
return this.parent.getOwnerName();
if(this.ownerName.length() == 0)
if(this.ownerID == null)
return GriefPrevention.instance.dataStore.getMessage(Messages.OwnerNameForAdminClaims);
return this.ownerName;
return GriefPrevention.lookupPlayerName(this.ownerID);
}
//whether or not a location is in a claim

View File

@ -68,7 +68,7 @@ class CleanupUnusedClaimsTask implements Runnable
boolean cleanupChunks = false;
//get data for the player, especially last login timestamp
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerName);
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(claim.ownerID);
//determine area of the default chest claim
int areaOfDefaultClaim = 0;
@ -118,7 +118,7 @@ class CleanupUnusedClaimsTask implements Runnable
}
//delete them
GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.getOwnerName(), true);
GriefPrevention.instance.dataStore.deleteClaimsForPlayer(claim.ownerID, true);
GriefPrevention.AddLogEntry(" All of " + claim.getOwnerName() + "'s claims have expired.");
for(int i = 0; i < claims.size(); i++)
@ -189,9 +189,9 @@ class CleanupUnusedClaimsTask implements Runnable
}
//toss that player data out of the cache, it's probably not needed in memory right now
if(!GriefPrevention.instance.getServer().getOfflinePlayer(claim.ownerName).isOnline())
if(!GriefPrevention.instance.getServer().getOfflinePlayer(claim.ownerID).isOnline())
{
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerName);
GriefPrevention.instance.dataStore.clearCachedPlayerData(claim.ownerID);
}
//since we're potentially loading a lot of chunks to scan parts of the world where there are no players currently playing, be mindful of memory usage

View File

@ -21,6 +21,7 @@ package me.ryanhamshire.GriefPrevention;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.bukkit.*;
import org.bukkit.configuration.file.FileConfiguration;
@ -32,7 +33,7 @@ import org.bukkit.inventory.ItemStack;
public abstract class DataStore
{
//in-memory cache for player data
protected ConcurrentHashMap<String, PlayerData> playerNameToPlayerDataMap = new ConcurrentHashMap<String, PlayerData>();
protected ConcurrentHashMap<UUID, PlayerData> playerNameToPlayerDataMap = new ConcurrentHashMap<UUID, PlayerData>();
//in-memory cache for group (permission-based) data
protected ConcurrentHashMap<String, Integer> permissionToBonusBlocksMap = new ConcurrentHashMap<String, Integer>();
@ -43,6 +44,9 @@ public abstract class DataStore
//in-memory cache for messages
private String [] messages;
//pattern for unique user identifiers (UUIDs)
protected final static Pattern uuidpattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
//next claim ID
Long nextClaimID = (long)0;
@ -50,6 +54,35 @@ public abstract class DataStore
protected final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
//the latest version of the data schema implemented here
protected static final int latestSchemaVersion = 1;
//reading and writing the schema version to the data store
abstract int getSchemaVersionFromStorage();
abstract void updateSchemaVersionInStorage(int versionToSet);
//current version of the schema of data in secondary storage
private int currentSchemaVersion = -1; //-1 means not determined yet
protected int getSchemaVersion()
{
if(this.currentSchemaVersion >= 0)
{
return this.currentSchemaVersion;
}
else
{
this.currentSchemaVersion = this.getSchemaVersionFromStorage();
return this.currentSchemaVersion;
}
}
protected void setSchemaVersion(int versionToSet)
{
this.currentSchemaVersion = versionToSet;
this.updateSchemaVersionInStorage(versionToSet);
}
//initialization!
void initialize() throws Exception
@ -57,7 +90,7 @@ public abstract class DataStore
GriefPrevention.AddLogEntry(this.claims.size() + " total claims loaded.");
//make a list of players who own claims
Vector<String> playerNames = new Vector<String>();
Vector<UUID> playerNames = new Vector<UUID>();
for(int i = 0; i < this.claims.size(); i++)
{
Claim claim = this.claims.get(i);
@ -65,8 +98,8 @@ public abstract class DataStore
//ignore admin claims
if(claim.isAdminClaim()) continue;
if(!playerNames.contains(claim.ownerName))
playerNames.add(claim.ownerName);
if(!playerNames.contains(claim.ownerID))
playerNames.add(claim.ownerID);
}
GriefPrevention.AddLogEntry(playerNames.size() + " players have staked claims.");
@ -74,18 +107,34 @@ public abstract class DataStore
//load up all the messages from messages.yml
this.loadMessages();
//if converting up from an earlier schema version, write all claims back to storage using the latest format
if(this.getSchemaVersion() < this.latestSchemaVersion)
{
GriefPrevention.AddLogEntry("Please wait. Updating data format.");
for(Claim claim : this.claims)
{
this.saveClaim(claim);
}
}
//collect garbage, since lots of stuff was loaded into memory and then tossed out
System.gc();
//make a note of the data store schema version
this.setSchemaVersion(this.latestSchemaVersion);
}
//removes cached player data from memory
synchronized void clearCachedPlayerData(String playerName)
synchronized void clearCachedPlayerData(UUID playerID)
{
this.playerNameToPlayerDataMap.remove(playerName);
this.playerNameToPlayerDataMap.remove(playerID);
}
//gets the number of bonus blocks a player has from his permissions
synchronized int getGroupBonusBlocks(String playerName)
//Bukkit doesn't allow for checking permissions of an offline player.
//this will return 0 when he's offline, and the correct number when online.
synchronized int getGroupBonusBlocks(UUID playerID)
{
int bonusBlocks = 0;
Set<String> keys = permissionToBonusBlocksMap.keySet();
@ -93,7 +142,7 @@ public abstract class DataStore
while(iterator.hasNext())
{
String groupName = iterator.next();
Player player = GriefPrevention.instance.getServer().getPlayer(playerName);
Player player = GriefPrevention.instance.getServer().getPlayer(playerID);
if(player != null && player.hasPermission(groupName))
{
bonusBlocks += this.permissionToBonusBlocksMap.get(groupName);
@ -120,7 +169,7 @@ public abstract class DataStore
abstract void saveGroupBonusBlocks(String groupName, int amount);
synchronized public void changeClaimOwner(Claim claim, String newOwnerName) throws Exception
synchronized public void changeClaimOwner(Claim claim, UUID newOwnerID) throws Exception
{
//if it's a subdivision, throw an exception
if(claim.parent != null)
@ -134,14 +183,14 @@ public abstract class DataStore
PlayerData ownerData = null;
if(!claim.isAdminClaim())
{
ownerData = this.getPlayerData(claim.ownerName);
ownerData = this.getPlayerData(claim.ownerID);
}
//determine new owner
PlayerData newOwnerData = this.getPlayerData(newOwnerName);
PlayerData newOwnerData = this.getPlayerData(newOwnerID);
//transfer
claim.ownerName = newOwnerName;
claim.ownerID = newOwnerID;
this.saveClaim(claim);
//adjust blocks and other records
@ -149,12 +198,12 @@ public abstract class DataStore
{
ownerData.claims.remove(claim);
ownerData.bonusClaimBlocks -= claim.getArea();
this.savePlayerData(claim.ownerName, ownerData);
this.savePlayerData(claim.ownerID, ownerData);
}
newOwnerData.claims.add(claim);
newOwnerData.bonusClaimBlocks += claim.getArea();
this.savePlayerData(newOwnerName, newOwnerData);
this.savePlayerData(newOwnerID, newOwnerData);
}
//adds a claim to the datastore, making it an effective claim
@ -181,9 +230,9 @@ public abstract class DataStore
//except for administrative claims (which have no owner), update the owner's playerData with the new claim
if(!newClaim.isAdminClaim())
{
PlayerData ownerData = this.getPlayerData(newClaim.getOwnerName());
PlayerData ownerData = this.getPlayerData(newClaim.ownerID);
ownerData.claims.add(newClaim);
this.savePlayerData(newClaim.getOwnerName(), ownerData);
this.savePlayerData(newClaim.ownerID, ownerData);
}
//make sure the claim is saved to disk
@ -265,36 +314,36 @@ public abstract class DataStore
//retrieves player data from memory or secondary storage, as necessary
//if the player has never been on the server before, this will return a fresh player data with default values
synchronized public PlayerData getPlayerData(String playerName)
synchronized public PlayerData getPlayerData(UUID playerID)
{
//first, look in memory
PlayerData playerData = this.playerNameToPlayerDataMap.get(playerName);
PlayerData playerData = this.playerNameToPlayerDataMap.get(playerID);
//if not there, look in secondary storage
if(playerData == null)
{
playerData = this.getPlayerDataFromStorage(playerName);
playerData.playerName = playerName;
playerData = this.getPlayerDataFromStorage(playerID);
playerData.playerID = playerID;
//find all the claims belonging to this player and note them for future reference
for(int i = 0; i < this.claims.size(); i++)
{
Claim claim = this.claims.get(i);
if(claim.ownerName.equals(playerName))
if(playerID.equals(claim.ownerID))
{
playerData.claims.add(claim);
}
}
//shove that new player data into the hash map cache
this.playerNameToPlayerDataMap.put(playerName, playerData);
this.playerNameToPlayerDataMap.put(playerID, playerData);
}
//try the hash map again. if it's STILL not there, we have a bug to fix
return this.playerNameToPlayerDataMap.get(playerName);
return this.playerNameToPlayerDataMap.get(playerID);
}
abstract PlayerData getPlayerDataFromStorage(String playerName);
abstract PlayerData getPlayerDataFromStorage(UUID playerID);
//deletes a claim or subdivision
synchronized public void deleteClaim(Claim claim)
@ -329,7 +378,7 @@ public abstract class DataStore
//update player data, except for administrative claims, which have no owner
if(!claim.isAdminClaim())
{
PlayerData ownerData = this.getPlayerData(claim.getOwnerName());
PlayerData ownerData = this.getPlayerData(claim.ownerID);
for(int i = 0; i < ownerData.claims.size(); i++)
{
if(ownerData.claims.get(i).id.equals(claim.id))
@ -338,7 +387,7 @@ public abstract class DataStore
break;
}
}
this.savePlayerData(claim.getOwnerName(), ownerData);
this.savePlayerData(claim.ownerID, ownerData);
}
}
@ -394,7 +443,7 @@ public abstract class DataStore
//does NOT check a player has permission to create a claim, or enough claim blocks.
//does NOT check minimum claim size constraints
//does NOT visualize the new claim for any players
synchronized public CreateClaimResult createClaim(World world, int x1, int x2, int y1, int y2, int z1, int z2, String ownerName, Claim parent, Long id)
synchronized public CreateClaimResult createClaim(World world, int x1, int x2, int y1, int y2, int z1, int z2, UUID ownerID, Claim parent, Long id)
{
CreateClaimResult result = new CreateClaimResult();
@ -444,7 +493,7 @@ public abstract class DataStore
Claim newClaim = new Claim(
new Location(world, smallx, smally, smallz),
new Location(world, bigx, bigy, bigz),
ownerName,
ownerID,
new String [] {},
new String [] {},
new String [] {},
@ -488,7 +537,7 @@ public abstract class DataStore
}
//saves changes to player data to secondary storage. MUST be called after you're done making changes, otherwise a reload will lose them
public abstract void savePlayerData(String playerName, PlayerData playerData);
public abstract void savePlayerData(UUID playerID, PlayerData playerData);
//extends a claim to a new depth
//respects the max depth config variable
@ -522,8 +571,8 @@ public abstract class DataStore
{
//fill-in the necessary SiegeData instance
SiegeData siegeData = new SiegeData(attacker, defender, defenderClaim);
PlayerData attackerData = this.getPlayerData(attacker.getName());
PlayerData defenderData = this.getPlayerData(defender.getName());
PlayerData attackerData = this.getPlayerData(attacker.getUniqueId());
PlayerData defenderData = this.getPlayerData(defender.getUniqueId());
attackerData.siegeData = siegeData;
defenderData.siegeData = siegeData;
defenderClaim.siegeData = siegeData;
@ -571,10 +620,10 @@ public abstract class DataStore
grantAccess = true;
}
PlayerData attackerData = this.getPlayerData(siegeData.attacker.getName());
PlayerData attackerData = this.getPlayerData(siegeData.attacker.getUniqueId());
attackerData.siegeData = null;
PlayerData defenderData = this.getPlayerData(siegeData.defender.getName());
PlayerData defenderData = this.getPlayerData(siegeData.defender.getUniqueId());
defenderData.siegeData = null;
//start a cooldown for this attacker/defender pair
@ -587,7 +636,7 @@ public abstract class DataStore
{
Claim claim = siegeData.claims.get(i);
claim.siegeData = null;
this.siegeCooldownRemaining.put(siegeData.attacker.getName() + "_" + claim.ownerName, cooldownEnd);
this.siegeCooldownRemaining.put(siegeData.attacker.getName() + "_" + claim.getOwnerName(), cooldownEnd);
//if doors should be opened for looting, do that now
if(grantAccess)
@ -674,9 +723,9 @@ public abstract class DataStore
}
//look for an attacker/claim cooldown
if(cooldownEnd == null && this.siegeCooldownRemaining.get(attacker.getName() + "_" + defenderClaim.ownerName) != null)
if(cooldownEnd == null && this.siegeCooldownRemaining.get(attacker.getName() + "_" + defenderClaim.getOwnerName()) != null)
{
cooldownEnd = this.siegeCooldownRemaining.get(attacker.getName() + "_" + defenderClaim.ownerName);
cooldownEnd = this.siegeCooldownRemaining.get(attacker.getName() + "_" + defenderClaim.getOwnerName());
if(Calendar.getInstance().getTimeInMillis() < cooldownEnd)
{
@ -684,7 +733,7 @@ public abstract class DataStore
}
//if found but expired, remove it
this.siegeCooldownRemaining.remove(attacker.getName() + "_" + defenderClaim.ownerName);
this.siegeCooldownRemaining.remove(attacker.getName() + "_" + defenderClaim.getOwnerName());
}
return false;
@ -693,7 +742,7 @@ public abstract class DataStore
//extend a siege, if it's possible to do so
synchronized void tryExtendSiege(Player player, Claim claim)
{
PlayerData playerData = this.getPlayerData(player.getName());
PlayerData playerData = this.getPlayerData(player.getUniqueId());
//player must be sieged
if(playerData.siegeData == null) return;
@ -713,14 +762,14 @@ public abstract class DataStore
}
//deletes all claims owned by a player
synchronized public void deleteClaimsForPlayer(String playerName, boolean deleteCreativeClaims)
synchronized public void deleteClaimsForPlayer(UUID playerID, boolean deleteCreativeClaims)
{
//make a list of the player's claims
ArrayList<Claim> claimsToDelete = new ArrayList<Claim>();
for(int i = 0; i < this.claims.size(); i++)
{
Claim claim = this.claims.get(i);
if(claim.ownerName.equals(playerName) && (deleteCreativeClaims || !GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())))
if(playerID.equals(claim.ownerID) && (deleteCreativeClaims || !GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())))
claimsToDelete.add(claim);
}
@ -748,7 +797,7 @@ public abstract class DataStore
this.deleteClaim(claim);
//try to create this new claim, ignoring the original when checking for overlap
CreateClaimResult result = this.createClaim(claim.getLesserBoundaryCorner().getWorld(), newx1, newx2, newy1, newy2, newz1, newz2, claim.ownerName, claim.parent, claim.id);
CreateClaimResult result = this.createClaim(claim.getLesserBoundaryCorner().getWorld(), newx1, newx2, newy1, newy2, newz1, newz2, claim.ownerID, claim.parent, claim.id);
//if succeeded
if(result.succeeded)
@ -1031,5 +1080,49 @@ public abstract class DataStore
return message;
}
abstract void close();
//used in updating the data schema from 0 to 1.
//converts player names in a list to uuids
protected String[] convertNameListToUUIDList(String[] names)
{
//doesn't apply after schema has been updated to version 1
if(this.getSchemaVersion() >= 1) return names;
//list to build results
List<String> resultNames = new ArrayList<String>();
for(String name : names)
{
//skip non-player-names (groups and "public"), leave them as-is
if(name.startsWith("[") || name.equals("public"))
{
resultNames.add(name);
continue;
}
//otherwise try to convert to a UUID
UUID playerID = null;
try
{
playerID = UUIDFetcher.getUUIDOf(name);
}
catch(Exception ex){ }
//if successful, replace player name with corresponding UUID
if(playerID != null)
{
resultNames.add(playerID.toString());
}
}
//return final result of conversion
String [] resultArray = new String [resultNames.size()];
for(int i = 0; i < resultNames.size(); i++)
{
resultArray[i] = resultNames.get(i);
}
return resultArray;
}
abstract void close();
}

View File

@ -80,6 +80,16 @@ public class DatabaseDataStore extends DataStore
statement.execute("CREATE TABLE IF NOT EXISTS griefprevention_claimdata (id INT(15), owner VARCHAR(50), lessercorner VARCHAR(100), greatercorner VARCHAR(100), builders VARCHAR(1000), containers VARCHAR(1000), accessors VARCHAR(1000), managers VARCHAR(1000), parentid INT(15));");
statement.execute("CREATE TABLE IF NOT EXISTS griefprevention_playerdata (name VARCHAR(50), lastlogin DATETIME, accruedblocks INT(15), bonusblocks INT(15));");
statement.execute("CREATE TABLE IF NOT EXISTS griefprevention_schemaversion (version INT(15));");
//if the next claim id table is empty, this is a brand new database which will write using the latest schema
//otherwise, schema version is determined by schemaversion table (or =0 if table is empty, see getSchemaVersion())
ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_nextclaimid;");
if(!results.next())
{
this.setSchemaVersion(latestSchemaVersion);
}
}
catch(Exception e3)
{
@ -145,20 +155,49 @@ public class DatabaseDataStore extends DataStore
Location greaterBoundaryCorner = this.locationFromString(greaterCornerString);
String ownerName = results.getString("owner");
UUID ownerID = null;
if(ownerName.isEmpty())
{
ownerID = null; //administrative land claim
}
else if(this.getSchemaVersion() < 0)
{
try
{
ownerID = UUIDFetcher.getUUIDOf(ownerName);
}
catch(Exception ex){ } //if UUID not found, use NULL
}
else
{
try
{
ownerID = UUID.fromString(ownerName);
}
catch(Exception ex)
{
GriefPrevention.AddLogEntry("Failed to look up UUID for player " + ownerName + ".");
GriefPrevention.AddLogEntry(" Converted land claim to administrative @ " + lesserBoundaryCorner.toString());
}
}
String buildersString = results.getString("builders");
String [] builderNames = buildersString.split(";");
builderNames = this.convertNameListToUUIDList(builderNames);
String containersString = results.getString("containers");
String [] containerNames = containersString.split(";");
containerNames = this.convertNameListToUUIDList(containerNames);
String accessorsString = results.getString("accessors");
String [] accessorNames = accessorsString.split(";");
accessorNames = this.convertNameListToUUIDList(accessorNames);
String managersString = results.getString("managers");
String [] managerNames = managersString.split(";");
managerNames = this.convertNameListToUUIDList(managerNames);
Claim topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, claimID);
Claim topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerID, builderNames, containerNames, accessorNames, managerNames, claimID);
//search for another claim overlapping this one
Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true, null);
@ -196,17 +235,21 @@ public class DatabaseDataStore extends DataStore
buildersString = childResults.getString("builders");
builderNames = buildersString.split(";");
builderNames = this.convertNameListToUUIDList(builderNames);
containersString = childResults.getString("containers");
containerNames = containersString.split(";");
containerNames = this.convertNameListToUUIDList(containerNames);
accessorsString = childResults.getString("accessors");
accessorNames = accessorsString.split(";");
accessorNames = this.convertNameListToUUIDList(accessorNames);
managersString = childResults.getString("managers");
managerNames = managersString.split(";");
managerNames = this.convertNameListToUUIDList(managerNames);
Claim childClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, null);
Claim childClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, null, builderNames, containerNames, accessorNames, managerNames, null);
//add this claim to the list of children of the current top level claim
childClaim.parent = topLevelClaim;
@ -226,6 +269,57 @@ 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();
}
@ -261,7 +355,8 @@ public class DatabaseDataStore extends DataStore
{
String lesserCornerString = this.locationToString(claim.getLesserBoundaryCorner());
String greaterCornerString = this.locationToString(claim.getGreaterBoundaryCorner());
String owner = claim.ownerName;
String owner = "";
if(claim.ownerID != null) owner = claim.ownerID.toString();
ArrayList<String> builders = new ArrayList<String>();
ArrayList<String> containers = new ArrayList<String>();
@ -358,22 +453,22 @@ public class DatabaseDataStore extends DataStore
}
@Override
synchronized PlayerData getPlayerDataFromStorage(String playerName)
synchronized PlayerData getPlayerDataFromStorage(UUID playerID)
{
PlayerData playerData = new PlayerData();
playerData.playerName = playerName;
playerData.playerID = playerID;
try
{
this.refreshDataConnection();
Statement statement = this.databaseConnection.createStatement();
ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_playerdata WHERE name='" + playerName + "';");
ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_playerdata WHERE name='" + playerID.toString() + "';");
//if there's no data for this player, create it with defaults
if(!results.next())
{
this.savePlayerData(playerName, playerData);
this.savePlayerData(playerID, playerData);
}
//otherwise, just read from the database
@ -386,7 +481,7 @@ public class DatabaseDataStore extends DataStore
}
catch(SQLException e)
{
GriefPrevention.AddLogEntry("Unable to retrieve data for player " + playerName + ". Details:");
GriefPrevention.AddLogEntry("Unable to retrieve data for player " + playerID.toString() + ". Details:");
GriefPrevention.AddLogEntry(e.getMessage());
}
@ -395,11 +490,16 @@ public class DatabaseDataStore extends DataStore
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
@Override
synchronized public void savePlayerData(String playerName, PlayerData playerData)
synchronized public void savePlayerData(UUID playerID, PlayerData playerData)
{
//never save data for the "administrative" account. an empty string for player name indicates administrative account
if(playerName.length() == 0) return;
if(playerID == null) return;
this.savePlayerData(playerID.toString(), playerData);
}
private void savePlayerData(String playerID, PlayerData playerData)
{
try
{
this.refreshDataConnection();
@ -408,12 +508,12 @@ public class DatabaseDataStore extends DataStore
String dateString = sqlFormat.format(playerData.lastLogin);
Statement statement = databaseConnection.createStatement();
statement.execute("DELETE FROM griefprevention_playerdata WHERE name='" + playerName + "';");
statement.execute("INSERT INTO griefprevention_playerdata VALUES ('" + playerName + "', '" + dateString + "', " + playerData.accruedClaimBlocks + ", " + playerData.bonusClaimBlocks + ");");
statement.execute("DELETE FROM griefprevention_playerdata WHERE name='" + playerID.toString() + "';");
statement.execute("INSERT INTO griefprevention_playerdata VALUES ('" + playerID.toString() + "', '" + dateString + "', " + playerData.accruedClaimBlocks + ", " + playerData.bonusClaimBlocks + ");");
}
catch(SQLException e)
{
GriefPrevention.AddLogEntry("Unable to save data for player " + playerName + ". Details:");
GriefPrevention.AddLogEntry("Unable to save data for player " + playerID.toString() + ". Details:");
GriefPrevention.AddLogEntry(e.getMessage());
}
}
@ -487,4 +587,54 @@ public class DatabaseDataStore extends DataStore
this.databaseConnection = DriverManager.getConnection(this.databaseUrl, connectionProps);
}
}
@Override
protected int getSchemaVersionFromStorage()
{
try
{
this.refreshDataConnection();
Statement statement = this.databaseConnection.createStatement();
ResultSet results = statement.executeQuery("SELECT * FROM griefprevention_schemaversion;");
//if there's nothing yet, assume 0 and add it
if(!results.next())
{
this.setSchemaVersion(0);
return 0;
}
//otherwise return the value that's in the table
else
{
return results.getInt(0);
}
}
catch(SQLException e)
{
GriefPrevention.AddLogEntry("Unable to retrieve schema version from database. Details:");
GriefPrevention.AddLogEntry(e.getMessage());
return 0;
}
}
@Override
protected void updateSchemaVersionInStorage(int versionToSet)
{
try
{
this.refreshDataConnection();
Statement statement = databaseConnection.createStatement();
statement.execute("DELETE FROM griefprevention_schemaversion;");
statement.execute("INSERT INTO griefprevention_schemaversion VALUES (" + versionToSet + ");");
}
catch(SQLException e)
{
GriefPrevention.AddLogEntry("Unable to set next schema version to " + versionToSet + ". Details:");
GriefPrevention.AddLogEntry(e.getMessage());
}
}
}

View File

@ -40,7 +40,7 @@ class DeliverClaimBlocksTask implements Runnable
{
Player player = players[i];
DataStore dataStore = GriefPrevention.instance.dataStore;
PlayerData playerData = dataStore.getPlayerData(player.getName());
PlayerData playerData = dataStore.getPlayerData(player.getUniqueId());
Location lastLocation = playerData.lastAfkCheckLocation;
try //distance squared will throw an exception if the player has changed worlds

View File

@ -236,7 +236,7 @@ class EntityEventHandler implements Listener
if(!(entity instanceof Player)) return; //only tracking players
Player player = (Player)entity;
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//if involved in a siege
if(playerData.siegeData != null)
@ -327,7 +327,7 @@ class EntityEventHandler implements Listener
//otherwise, apply entity-count limitations for creative worlds
else if(GriefPrevention.instance.creativeRulesApply(event.getEntity().getLocation()))
{
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
Claim claim = this.dataStore.getClaimAt(event.getBlock().getLocation(), false, playerData.lastClaim);
if(claim == null) return;
@ -389,8 +389,8 @@ class EntityEventHandler implements Listener
Player defender = (Player)(event.getEntity());
PlayerData defenderData = this.dataStore.getPlayerData(((Player)event.getEntity()).getName());
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName());
PlayerData defenderData = this.dataStore.getPlayerData(((Player)event.getEntity()).getUniqueId());
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getUniqueId());
//otherwise if protecting spawning players
if(GriefPrevention.instance.config_pvp_protectFreshSpawns)
@ -461,7 +461,7 @@ class EntityEventHandler implements Listener
PlayerData playerData = null;
if(attacker != null)
{
playerData = this.dataStore.getPlayerData(attacker.getName());
playerData = this.dataStore.getPlayerData(attacker.getUniqueId());
cachedClaim = playerData.lastClaim;
}
@ -495,7 +495,7 @@ class EntityEventHandler implements Listener
PlayerData playerData = null;
if(attacker != null)
{
playerData = this.dataStore.getPlayerData(attacker.getName());
playerData = this.dataStore.getPlayerData(attacker.getUniqueId());
cachedClaim = playerData.lastClaim;
}
@ -583,7 +583,7 @@ class EntityEventHandler implements Listener
PlayerData playerData = null;
if(attacker != null)
{
playerData = this.dataStore.getPlayerData(attacker.getName());
playerData = this.dataStore.getPlayerData(attacker.getUniqueId());
cachedClaim = playerData.lastClaim;
}

View File

@ -42,7 +42,7 @@ class EquipShovelProcessingTask implements Runnable
//if he's not holding the golden shovel anymore, do nothing
if(player.getItemInHand().getType() != GriefPrevention.instance.config_claims_modificationTool) return;
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
int remainingBlocks = playerData.getRemainingClaimBlocks();

View File

@ -24,8 +24,6 @@ import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.bukkit.*;
//manages data stored in the file system
@ -34,9 +32,8 @@ public class FlatFileDataStore extends DataStore
private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData";
private final static String nextClaimIdFilePath = claimDataFolderPath + File.separator + "_nextClaimID";
private final static String schemaVersionFilePath = dataLayerFolderPath + File.separator + "_schemaVersion";
private final static Pattern uuidpattern = Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}");
static boolean hasData()
{
File playerDataFolder = new File(playerDataFolderPath);
@ -55,11 +52,23 @@ public class FlatFileDataStore extends DataStore
void initialize() throws Exception
{
//ensure data folders exist
new File(playerDataFolderPath).mkdirs();
new File(claimDataFolderPath).mkdirs();
boolean newDataStore = false;
File playerDataFolder = new File(playerDataFolderPath);
File claimDataFolder = new File(claimDataFolderPath);
if(!playerDataFolder.exists() || !claimDataFolder.exists())
{
newDataStore = true;
playerDataFolder.mkdirs();
claimDataFolder.mkdirs();
}
//if there's no data yet, then anything written will use the schema implemented by this code
if(newDataStore)
{
this.setSchemaVersion(DataStore.latestSchemaVersion);
}
//load group data into memory
File playerDataFolder = new File(playerDataFolderPath);
File [] files = playerDataFolder.listFiles();
for(int i = 0; i < files.length; i++)
{
@ -120,14 +129,13 @@ public class FlatFileDataStore extends DataStore
//load claims data into memory
//get a list of all the files in the claims data folder
File claimDataFolder = new File(claimDataFolderPath);
files = claimDataFolder.listFiles();
for(int i = 0; i < files.length; i++)
{
if(files[i].isFile()) //avoids folders
{
//skip any file starting with an underscore, to avoid the _nextClaimID file.
//skip any file starting with an underscore, to avoid special files not representing land claims
if(files[i].getName().startsWith("_")) continue;
//the filename is the claim ID. try to parse it
@ -182,23 +190,52 @@ public class FlatFileDataStore extends DataStore
//third line is owner name
line = inStream.readLine();
String ownerName = line;
UUID ownerID = null;
if(ownerName.isEmpty() || ownerName.startsWith("--"))
{
ownerID = null; //administrative land claim or subdivision
}
else if(this.getSchemaVersion() == 0)
{
try
{
ownerID = UUIDFetcher.getUUIDOf(ownerName);
}
catch(Exception ex){ } //if UUID not found, use NULL
}
else
{
try
{
ownerID = UUID.fromString(ownerName);
}
catch(Exception ex)
{
GriefPrevention.AddLogEntry("Failed to look up UUID for player " + ownerName + ".");
GriefPrevention.AddLogEntry(" Converted land claim to administrative @ " + lesserBoundaryCorner.toString());
}
}
//fourth line is list of builders
line = inStream.readLine();
String [] builderNames = line.split(";");
builderNames = this.convertNameListToUUIDList(builderNames);
//fifth line is list of players who can access containers
line = inStream.readLine();
String [] containerNames = line.split(";");
containerNames = this.convertNameListToUUIDList(containerNames);
//sixth line is list of players who can use buttons and switches
line = inStream.readLine();
String [] accessorNames = line.split(";");
accessorNames = this.convertNameListToUUIDList(accessorNames);
//seventh line is list of players who can grant permissions
line = inStream.readLine();
if(line == null) line = "";
String [] managerNames = line.split(";");
managerNames = this.convertNameListToUUIDList(managerNames);
//skip any remaining extra lines, until the "===" string, indicating the end of this claim or subdivision
line = inStream.readLine();
@ -210,7 +247,7 @@ public class FlatFileDataStore extends DataStore
if(topLevelClaim == null)
{
//instantiate
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, claimID);
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerID, builderNames, containerNames, accessorNames, managerNames, claimID);
//search for another claim overlapping this one
Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true, null);
@ -241,7 +278,7 @@ public class FlatFileDataStore extends DataStore
//otherwise there's already a top level claim, so this must be a subdivision of that top level claim
else
{
Claim subdivision = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, "--subdivision--", builderNames, containerNames, accessorNames, managerNames, null);
Claim subdivision = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, null, builderNames, containerNames, accessorNames, managerNames, null);
subdivision.modifiedDate = new Date(files[i].lastModified());
subdivision.parent = topLevelClaim;
@ -259,7 +296,7 @@ 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.getMessage());
GriefPrevention.AddLogEntry("Unable to load data for claim \"" + files[i].getName() + "\": " + e.toString());
}
try
@ -270,6 +307,42 @@ 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();
}
@ -301,7 +374,8 @@ public class FlatFileDataStore extends DataStore
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unexpected exception saving data for claim \"" + claimID + "\": " + e.getMessage());
GriefPrevention.AddLogEntry("Unexpected exception saving data for claim \"" + claimID + "\": " + e.toString());
e.printStackTrace();
}
//close the file
@ -324,7 +398,9 @@ public class FlatFileDataStore extends DataStore
outStream.newLine();
//third line is owner name
outStream.write(claim.ownerName);
String lineToWrite = "";
if(claim.ownerID != null) lineToWrite = claim.ownerID.toString();
outStream.write(lineToWrite);
outStream.newLine();
ArrayList<String> builders = new ArrayList<String>();
@ -382,18 +458,18 @@ public class FlatFileDataStore extends DataStore
}
@Override
synchronized PlayerData getPlayerDataFromStorage(String playerName)
synchronized PlayerData getPlayerDataFromStorage(UUID playerID)
{
File playerFile = new File(playerDataFolderPath + File.separator + playerName);
File playerFile = new File(playerDataFolderPath + File.separator + playerID.toString());
PlayerData playerData = new PlayerData();
playerData.playerName = playerName;
playerData.playerID = playerID;
//if it doesn't exist as a file
if(!playerFile.exists())
{
//create a file with defaults
this.savePlayerData(playerName, playerData);
this.savePlayerData(playerID, playerData);
}
//otherwise, read the file
@ -441,7 +517,7 @@ public class FlatFileDataStore extends DataStore
//if there's any problem with the file's content, log an error message
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unable to load data for player \"" + playerName + "\": " + e.getMessage());
GriefPrevention.AddLogEntry("Unable to load data for player \"" + playerID.toString() + "\": " + e.getMessage());
}
try
@ -456,16 +532,16 @@ public class FlatFileDataStore extends DataStore
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
@Override
synchronized public void savePlayerData(String playerName, PlayerData playerData)
synchronized public void savePlayerData(UUID playerID, PlayerData playerData)
{
//never save data for the "administrative" account. an empty string for claim owner indicates administrative account
if(playerName.length() == 0) return;
//never save data for the "administrative" account. null for claim owner ID indicates administrative account
if(playerID == null) return;
BufferedWriter outStream = null;
try
{
//open the player's file
File playerDataFile = new File(playerDataFolderPath + File.separator + playerName);
File playerDataFile = new File(playerDataFolderPath + File.separator + playerID.toString());
playerDataFile.createNewFile();
outStream = new BufferedWriter(new FileWriter(playerDataFile));
@ -498,7 +574,7 @@ public class FlatFileDataStore extends DataStore
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("GriefPrevention: Unexpected exception saving data for player \"" + playerName + "\": " + e.getMessage());
GriefPrevention.AddLogEntry("GriefPrevention: Unexpected exception saving data for player \"" + playerID.toString() + "\": " + e.getMessage());
}
try
@ -607,9 +683,12 @@ public class FlatFileDataStore extends DataStore
//all group data files start with a dollar sign. ignoring those, already handled above
if(file.getName().startsWith("$")) continue;
String playerName = file.getName();
databaseStore.savePlayerData(playerName, this.getPlayerData(playerName));
this.clearCachedPlayerData(playerName);
//ignore special files (claimID)
if(file.getName().startsWith("_")) continue;
UUID playerID = UUID.fromString(file.getName());
databaseStore.savePlayerData(playerID, this.getPlayerData(playerID));
this.clearCachedPlayerData(playerID);
}
//migrate next claim ID
@ -647,4 +726,69 @@ public class FlatFileDataStore extends DataStore
@Override
synchronized void close() { }
@Override
int getSchemaVersionFromStorage()
{
File schemaVersionFile = new File(schemaVersionFilePath);
if(schemaVersionFile.exists())
{
BufferedReader inStream = null;
int schemaVersion = 0;
try
{
inStream = new BufferedReader(new FileReader(schemaVersionFile.getAbsolutePath()));
//read the version number
String line = inStream.readLine();
//try to parse into an int value
schemaVersion = Integer.parseInt(line);
}
catch(Exception e){ }
try
{
if(inStream != null) inStream.close();
}
catch(IOException exception) {}
return schemaVersion;
}
else
{
this.updateSchemaVersionInStorage(0);
return 0;
}
}
@Override
void updateSchemaVersionInStorage(int versionToSet)
{
BufferedWriter outStream = null;
try
{
//open the file and write the new value
File schemaVersionFile = new File(schemaVersionFilePath);
schemaVersionFile.createNewFile();
outStream = new BufferedWriter(new FileWriter(schemaVersionFile));
outStream.write(String.valueOf(versionToSet));
}
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("Unexpected exception saving schema version: " + e.getMessage());
}
//close the file
try
{
if(outStream != null) outStream.close();
}
catch(IOException exception) {}
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger;
@ -802,7 +803,7 @@ public class GriefPrevention extends JavaPlugin
//ignoreclaims
if(cmd.getName().equalsIgnoreCase("ignoreclaims") && player != null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.ignoreClaims = !playerData.ignoreClaims;
@ -831,7 +832,7 @@ public class GriefPrevention extends JavaPlugin
}
//count claims
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
int originalClaimCount = playerData.claims.size();
//check count
@ -842,7 +843,7 @@ public class GriefPrevention extends JavaPlugin
}
//delete them
this.dataStore.deleteClaimsForPlayer(player.getName(), false);
this.dataStore.deleteClaimsForPlayer(player.getUniqueId(), false);
//inform the player
int remainingBlocks = playerData.getRemainingClaimBlocks();
@ -858,7 +859,7 @@ public class GriefPrevention extends JavaPlugin
else if(cmd.getName().equalsIgnoreCase("restorenature") && player != null)
{
//change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.RestoreNature;
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RestoreNatureActivate);
return true;
@ -868,7 +869,7 @@ public class GriefPrevention extends JavaPlugin
else if(cmd.getName().equalsIgnoreCase("restorenatureaggressive") && player != null)
{
//change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.RestoreNatureAggressive;
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.RestoreNatureAggressiveActivate);
return true;
@ -878,7 +879,7 @@ public class GriefPrevention extends JavaPlugin
else if(cmd.getName().equalsIgnoreCase("restorenaturefill") && player != null)
{
//change shovel mode
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.RestoreNatureFill;
//set radius based on arguments
@ -931,7 +932,7 @@ public class GriefPrevention extends JavaPlugin
return true;
}
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -941,7 +942,7 @@ public class GriefPrevention extends JavaPlugin
//change ownerhsip
try
{
this.dataStore.changeClaimOwner(claim, targetPlayer.getName());
this.dataStore.changeClaimOwner(claim, targetPlayer.getUniqueId());
}
catch(Exception e)
{
@ -992,7 +993,7 @@ public class GriefPrevention extends JavaPlugin
if(managers.size() > 0)
{
for(int i = 0; i < managers.size(); i++)
permissions.append(managers.get(i) + " ");
permissions.append(this.trustEntryToPlayerName(managers.get(i)) + " ");
}
player.sendMessage(permissions.toString());
@ -1002,7 +1003,7 @@ public class GriefPrevention extends JavaPlugin
if(builders.size() > 0)
{
for(int i = 0; i < builders.size(); i++)
permissions.append(builders.get(i) + " ");
permissions.append(this.trustEntryToPlayerName(builders.get(i)) + " ");
}
player.sendMessage(permissions.toString());
@ -1012,7 +1013,7 @@ public class GriefPrevention extends JavaPlugin
if(containers.size() > 0)
{
for(int i = 0; i < containers.size(); i++)
permissions.append(containers.get(i) + " ");
permissions.append(this.trustEntryToPlayerName(containers.get(i)) + " ");
}
player.sendMessage(permissions.toString());
@ -1022,7 +1023,7 @@ public class GriefPrevention extends JavaPlugin
if(accessors.size() > 0)
{
for(int i = 0; i < accessors.size(); i++)
permissions.append(accessors.get(i) + " ");
permissions.append(this.trustEntryToPlayerName(accessors.get(i)) + " ");
}
player.sendMessage(permissions.toString());
@ -1042,7 +1043,7 @@ public class GriefPrevention extends JavaPlugin
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
//bracket any permissions
if(args[0].contains("."))
if(args[0].contains(".") && !args[0].startsWith("[") && !args[0].endsWith("]"))
{
args[0] = "[" + args[0] + "]";
}
@ -1068,7 +1069,7 @@ public class GriefPrevention extends JavaPlugin
//validate player argument or group argument
if(!args[0].startsWith("[") || !args[0].endsWith("]"))
{
otherPlayer = this.resolvePlayer(args[0]);
otherPlayer = this.resolvePlayerByName(args[0]);
if(!clearPermissions && otherPlayer == null && !args[0].equals("public"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -1084,7 +1085,7 @@ public class GriefPrevention extends JavaPlugin
//if no claim here, apply changes to all his claims
if(claim == null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
for(int i = 0; i < playerData.claims.size(); i++)
{
claim = playerData.claims.get(i);
@ -1098,8 +1099,13 @@ public class GriefPrevention extends JavaPlugin
//otherwise drop individual permissions
else
{
claim.dropPermission(args[0]);
claim.managers.remove(args[0]);
String idToDrop = args[0];
if(otherPlayer != null)
{
idToDrop = otherPlayer.getUniqueId().toString();
}
claim.dropPermission(idToDrop);
claim.managers.remove(idToDrop);
}
//save changes
@ -1140,10 +1146,15 @@ public class GriefPrevention extends JavaPlugin
//otherwise individual permission drop
else
{
claim.dropPermission(args[0]);
String idToDrop = args[0];
if(otherPlayer != null)
{
idToDrop = otherPlayer.getUniqueId().toString();
}
claim.dropPermission(idToDrop);
if(claim.allowEdit(player) == null)
{
claim.managers.remove(args[0]);
claim.managers.remove(idToDrop);
//beautify for output
if(args[0].equals("public"))
@ -1225,14 +1236,14 @@ public class GriefPrevention extends JavaPlugin
//if no parameter, just tell player cost per block and balance
if(args.length != 1)
{
GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockPurchaseCost, String.valueOf(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost), String.valueOf(GriefPrevention.economy.getBalance(player.getName())));
GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockPurchaseCost, String.valueOf(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost), String.valueOf(GriefPrevention.economy.getBalance(player)));
return false;
}
else
{
//determine max purchasable blocks
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
int maxPurchasable = GriefPrevention.instance.config_claims_maxAccruedBlocks - playerData.accruedClaimBlocks;
//if the player is at his max, tell him so
@ -1265,7 +1276,7 @@ public class GriefPrevention extends JavaPlugin
}
//if the player can't afford his purchase, send error message
double balance = economy.getBalance(player.getName());
double balance = economy.getBalance(player);
double totalCost = blockCount * GriefPrevention.instance.config_economy_claimBlocksPurchaseCost;
if(totalCost > balance)
{
@ -1276,11 +1287,11 @@ public class GriefPrevention extends JavaPlugin
else
{
//withdraw cost
economy.withdrawPlayer(player.getName(), totalCost);
economy.withdrawPlayer(player, totalCost);
//add blocks
playerData.accruedClaimBlocks += blockCount;
this.dataStore.savePlayerData(player.getName(), playerData);
this.dataStore.savePlayerData(player.getUniqueId(), playerData);
//inform player
GriefPrevention.sendMessage(player, TextMode.Success, Messages.PurchaseConfirmation, String.valueOf(totalCost), String.valueOf(playerData.getRemainingClaimBlocks()));
@ -1314,7 +1325,7 @@ public class GriefPrevention extends JavaPlugin
}
//load player data
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
int availableBlocks = playerData.getRemainingClaimBlocks();
//if no amount provided, just tell player value per block sold, and how many he can sell
@ -1351,11 +1362,11 @@ public class GriefPrevention extends JavaPlugin
{
//compute value and deposit it
double totalValue = blockCount * GriefPrevention.instance.config_economy_claimBlocksSellValue;
economy.depositPlayer(player.getName(), totalValue);
economy.depositPlayer(player, totalValue);
//subtract blocks
playerData.accruedClaimBlocks -= blockCount;
this.dataStore.savePlayerData(player.getName(), playerData);
this.dataStore.savePlayerData(player.getUniqueId(), playerData);
//inform player
GriefPrevention.sendMessage(player, TextMode.Success, Messages.BlockSaleConfirmation, String.valueOf(totalValue), String.valueOf(playerData.getRemainingClaimBlocks()));
@ -1367,7 +1378,7 @@ public class GriefPrevention extends JavaPlugin
//adminclaims
else if(cmd.getName().equalsIgnoreCase("adminclaims") && player != null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.Admin;
GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdminClaimsMode);
@ -1377,7 +1388,7 @@ public class GriefPrevention extends JavaPlugin
//basicclaims
else if(cmd.getName().equalsIgnoreCase("basicclaims") && player != null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.Basic;
playerData.claimSubdividing = null;
GriefPrevention.sendMessage(player, TextMode.Success, Messages.BasicClaimsMode);
@ -1388,7 +1399,7 @@ public class GriefPrevention extends JavaPlugin
//subdivideclaims
else if(cmd.getName().equalsIgnoreCase("subdivideclaims") && player != null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.shovelMode = ShovelMode.Subdivide;
playerData.claimSubdividing = null;
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SubdivisionMode);
@ -1413,7 +1424,7 @@ public class GriefPrevention extends JavaPlugin
//deleting an admin claim additionally requires the adminclaims permission
if(!claim.isAdminClaim() || player.hasPermission("griefprevention.adminclaims"))
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
if(claim.children.size() > 0 && !playerData.warnedAboutMajorDeletion)
{
GriefPrevention.sendMessage(player, TextMode.Warn, Messages.DeletionSubdivisionWarning);
@ -1489,7 +1500,7 @@ public class GriefPrevention extends JavaPlugin
if(args.length != 1) return false;
//try to find that player
OfflinePlayer otherPlayer = this.resolvePlayer(args[0]);
OfflinePlayer otherPlayer = this.resolvePlayerByName(args[0]);
if(otherPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -1497,7 +1508,7 @@ public class GriefPrevention extends JavaPlugin
}
//delete all that player's claims
this.dataStore.deleteClaimsForPlayer(otherPlayer.getName(), true);
this.dataStore.deleteClaimsForPlayer(otherPlayer.getUniqueId(), true);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.DeleteAllSuccess, otherPlayer.getName());
if(player != null)
@ -1539,7 +1550,7 @@ public class GriefPrevention extends JavaPlugin
//otherwise try to find the specified player
else
{
otherPlayer = this.resolvePlayer(args[0]);
otherPlayer = this.resolvePlayerByName(args[0]);
if(otherPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -1548,8 +1559,8 @@ public class GriefPrevention extends JavaPlugin
}
//load the target player's data
PlayerData playerData = this.dataStore.getPlayerData(otherPlayer.getName());
GriefPrevention.sendMessage(player, TextMode.Instr, " " + playerData.accruedClaimBlocks + "(+" + (playerData.bonusClaimBlocks + this.dataStore.getGroupBonusBlocks(otherPlayer.getName())) + ")=" + (playerData.accruedClaimBlocks + playerData.bonusClaimBlocks + this.dataStore.getGroupBonusBlocks(otherPlayer.getName())));
PlayerData playerData = this.dataStore.getPlayerData(otherPlayer.getUniqueId());
GriefPrevention.sendMessage(player, TextMode.Instr, " " + playerData.accruedClaimBlocks + "(+" + (playerData.bonusClaimBlocks + this.dataStore.getGroupBonusBlocks(otherPlayer.getUniqueId())) + ")=" + (playerData.accruedClaimBlocks + playerData.bonusClaimBlocks + this.dataStore.getGroupBonusBlocks(otherPlayer.getUniqueId())));
for(int i = 0; i < playerData.claims.size(); i++)
{
Claim claim = playerData.claims.get(i);
@ -1561,7 +1572,7 @@ public class GriefPrevention extends JavaPlugin
//drop the data we just loaded, if the player isn't online
if(!otherPlayer.isOnline())
this.dataStore.clearCachedPlayerData(otherPlayer.getName());
this.dataStore.clearCachedPlayerData(otherPlayer.getUniqueId());
return true;
}
@ -1636,7 +1647,7 @@ public class GriefPrevention extends JavaPlugin
}
//delete all admin claims
this.dataStore.deleteClaimsForPlayer("", true); //empty string for owner name indicates an administrative claim
this.dataStore.deleteClaimsForPlayer(null, true); //null for owner id indicates an administrative claim
GriefPrevention.sendMessage(player, TextMode.Success, Messages.AllAdminDeleted);
if(player != null)
@ -1680,7 +1691,7 @@ public class GriefPrevention extends JavaPlugin
}
//otherwise, find the specified player
OfflinePlayer targetPlayer = this.resolvePlayer(args[0]);
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -1688,9 +1699,9 @@ public class GriefPrevention extends JavaPlugin
}
//give blocks to player
PlayerData playerData = this.dataStore.getPlayerData(targetPlayer.getName());
PlayerData playerData = this.dataStore.getPlayerData(targetPlayer.getUniqueId());
playerData.bonusClaimBlocks += adjustment;
this.dataStore.savePlayerData(targetPlayer.getName(), playerData);
this.dataStore.savePlayerData(targetPlayer.getUniqueId(), playerData);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.AdjustBlocksSuccess, targetPlayer.getName(), String.valueOf(adjustment), String.valueOf(playerData.bonusClaimBlocks));
if(player != null) GriefPrevention.AddLogEntry(player.getName() + " adjusted " + targetPlayer.getName() + "'s bonus claim blocks by " + adjustment + ".");
@ -1703,7 +1714,7 @@ public class GriefPrevention extends JavaPlugin
{
//FEATURE: empower players who get "stuck" in an area where they don't have permission to build to save themselves
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(player.getLocation(), false, playerData.lastClaim);
//if another /trapped is pending, ignore this slash command
@ -1771,7 +1782,7 @@ public class GriefPrevention extends JavaPlugin
//can't start a siege when you're already involved in one
Player attacker = player;
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getName());
PlayerData attackerData = this.dataStore.getPlayerData(attacker.getUniqueId());
if(attackerData.siegeData != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.AlreadySieging);
@ -1813,7 +1824,7 @@ public class GriefPrevention extends JavaPlugin
}
//victim must not be under siege already
PlayerData defenderData = this.dataStore.getPlayerData(defender.getName());
PlayerData defenderData = this.dataStore.getPlayerData(defender.getUniqueId());
if(defenderData.siegeData != null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.AlreadyUnderSiegePlayer);
@ -1875,14 +1886,26 @@ public class GriefPrevention extends JavaPlugin
return false;
}
public static String getfriendlyLocationString(Location location)
private String trustEntryToPlayerName(String entry)
{
if(entry.startsWith("[") || entry.equals("public"))
{
return entry;
}
else
{
return GriefPrevention.lookupPlayerName(entry);
}
}
public static String getfriendlyLocationString(Location location)
{
return location.getWorld().getName() + "(" + location.getBlockX() + "," + location.getBlockY() + "," + location.getBlockZ() + ")";
}
private boolean abandonClaimHandler(Player player, boolean deleteTopLevelClaim)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//which claim is being abandoned?
Claim claim = this.dataStore.getClaimAt(player.getLocation(), true /*ignore height*/, null);
@ -1954,6 +1977,7 @@ public class GriefPrevention extends JavaPlugin
//validate player or group argument
String permission = null;
OfflinePlayer otherPlayer = null;
UUID recipientID = null;
if(recipientName.startsWith("[") && recipientName.endsWith("]"))
{
permission = recipientName.substring(1, recipientName.length() - 1);
@ -1971,7 +1995,7 @@ public class GriefPrevention extends JavaPlugin
else
{
otherPlayer = this.resolvePlayer(recipientName);
otherPlayer = this.resolvePlayerByName(recipientName);
if(otherPlayer == null && !recipientName.equals("public") && !recipientName.equals("all"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
@ -1981,6 +2005,7 @@ public class GriefPrevention extends JavaPlugin
if(otherPlayer != null)
{
recipientName = otherPlayer.getName();
recipientID = otherPlayer.getUniqueId();
}
else
{
@ -1992,7 +2017,7 @@ public class GriefPrevention extends JavaPlugin
ArrayList<Claim> targetClaims = new ArrayList<Claim>();
if(claim == null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
for(int i = 0; i < playerData.claims.size(); i++)
{
targetClaims.add(playerData.claims.get(i));
@ -2057,16 +2082,26 @@ public class GriefPrevention extends JavaPlugin
for(int i = 0; i < targetClaims.size(); i++)
{
Claim currentClaim = targetClaims.get(i);
String identifierToAdd = recipientName;
if(permission != null)
{
identifierToAdd = "[" + permission + "]";
}
else if(recipientID != null)
{
identifierToAdd = recipientID.toString();
}
if(permissionLevel == null)
{
if(!currentClaim.managers.contains(recipientName))
if(!currentClaim.managers.contains(identifierToAdd))
{
currentClaim.managers.add(recipientName);
currentClaim.managers.add(identifierToAdd);
}
}
else
{
currentClaim.setPermission(recipientName, permissionLevel);
currentClaim.setPermission(identifierToAdd, permissionLevel);
}
this.dataStore.saveClaim(currentClaim);
}
@ -2105,26 +2140,75 @@ public class GriefPrevention extends JavaPlugin
}
//helper method to resolve a player by name
private OfflinePlayer resolvePlayer(String name)
private OfflinePlayer resolvePlayerByName(String name)
{
//try online players first
Player player = this.getServer().getPlayer(name);
if(player != null) return player;
OfflinePlayer [] players = this.getServer().getOnlinePlayers();
for(int i = 0; i < players.length; i++)
{
if(players[i].getName().equalsIgnoreCase(name))
{
return players[i];
}
}
//then search offline players
OfflinePlayer [] offlinePlayers = this.getServer().getOfflinePlayers();
for(int i = 0; i < offlinePlayers.length; i++)
{
if(offlinePlayers[i].getName().equalsIgnoreCase(name))
{
return offlinePlayers[i];
}
}
players = this.getServer().getOfflinePlayers();
for(int i = 0; i < players.length; i++)
{
if(players[i].getName().equalsIgnoreCase(name))
{
return players[i];
}
}
//if none found, return null
return null;
}
//helper method to resolve a player name from the player's UUID
static String lookupPlayerName(UUID playerID)
{
//parameter validation
if(playerID == null) return "someone";
//try online players first
Player player = GriefPrevention.instance.getServer().getPlayer(playerID);
if(player != null) return player.getName();
//then search offline players
OfflinePlayer [] players = GriefPrevention.instance.getServer().getOfflinePlayers();
for(int i = 0; i < players.length; i++)
{
if(players[i].getUniqueId().equals(playerID))
{
return players[i].getName();
}
}
//if none found
GriefPrevention.AddLogEntry("Error: Failed to find a local player with UUID: " + playerID.toString());
new Exception().printStackTrace();
return "someone";
}
//string overload for above helper
static String lookupPlayerName(String playerID)
{
UUID id;
try
{
id = UUID.fromString(playerID);
}
catch(IllegalArgumentException ex)
{
GriefPrevention.AddLogEntry("Error: Tried to look up a local player name for invalid UUID: " + playerID);
return "someone";
}
return lookupPlayerName(id);
}
public void onDisable()
{
//save data for any online players
@ -2132,9 +2216,9 @@ public class GriefPrevention extends JavaPlugin
for(int i = 0; i < players.length; i++)
{
Player player = players[i];
String playerName = player.getName();
PlayerData playerData = this.dataStore.getPlayerData(playerName);
this.dataStore.savePlayerData(playerName, playerData);
UUID playerID = player.getUniqueId();
PlayerData playerData = this.dataStore.getPlayerData(playerID);
this.dataStore.savePlayerData(playerID, playerData);
}
this.dataStore.close();
@ -2175,7 +2259,7 @@ public class GriefPrevention extends JavaPlugin
}
//otherwise, apply immunity
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.pvpImmune = true;
//inform the player
@ -2471,7 +2555,7 @@ public class GriefPrevention extends JavaPlugin
public String allowBuild(Player player, Location location)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
//exception: administrators in ignore claims mode and special player accounts created by server mods
@ -2513,7 +2597,7 @@ public class GriefPrevention extends JavaPlugin
public String allowBreak(Player player, Location location)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
//exception: administrators in ignore claims mode, and special player accounts created by server mods

View File

@ -20,6 +20,7 @@ package me.ryanhamshire.GriefPrevention;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.Date;
import java.util.UUID;
import java.util.Vector;
import me.ryanhamshire.GriefPrevention.Claim;
@ -33,8 +34,8 @@ import org.bukkit.Location;
//holds all of GriefPrevention's player-tied data
public class PlayerData
{
//the player's name
public String playerName;
//the player's ID
public UUID playerID;
//the player's claims
public Vector<Claim> claims = new Vector<Claim>();
@ -151,7 +152,7 @@ public class PlayerData
}
//add any blocks this player might have based on group membership (permissions)
remainingBlocks += GriefPrevention.instance.dataStore.getGroupBonusBlocks(this.playerName);
remainingBlocks += GriefPrevention.instance.dataStore.getGroupBonusBlocks(this.playerID);
return remainingBlocks;
}

View File

@ -22,6 +22,7 @@ import java.util.Calendar;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@ -40,7 +41,6 @@ import org.bukkit.entity.Entity;
import org.bukkit.entity.Hanging;
import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle;
import org.bukkit.entity.minecart.HopperMinecart;
import org.bukkit.entity.minecart.PoweredMinecart;
import org.bukkit.entity.minecart.StorageMinecart;
import org.bukkit.event.EventHandler;
@ -131,7 +131,7 @@ class PlayerEventHandler implements Listener
boolean spam = false;
boolean muted = false;
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//remedy any CAPS SPAM, exception for very short messages which could be emoticons like =D or XD
if(message.length() > 4 && this.stringsAreSimilar(message.toUpperCase(), message))
@ -367,7 +367,7 @@ class PlayerEventHandler implements Listener
}
//if in pvp, block any pvp-banned slash commands
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
if((playerData.inPvpCombat() || playerData.siegeData != null) && GriefPrevention.instance.config_pvp_blockedCommands.contains(command))
{
event.setCancelled(true);
@ -410,7 +410,7 @@ class PlayerEventHandler implements Listener
if(GriefPrevention.instance.config_spam_loginCooldownMinutes > 0 && event.getResult() == Result.ALLOWED)
{
//determine how long since last login and cooldown remaining
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
long millisecondsSinceLastLogin = (new Date()).getTime() - playerData.lastLogin.getTime();
long minutesSinceLastLogin = millisecondsSinceLastLogin / 1000 / 60;
long cooldownRemaining = GriefPrevention.instance.config_spam_loginCooldownMinutes - minutesSinceLastLogin;
@ -435,7 +435,7 @@ class PlayerEventHandler implements Listener
}
//remember the player's ip address
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
playerData.ipAddress = event.getAddress();
}
@ -443,7 +443,7 @@ class PlayerEventHandler implements Listener
@EventHandler(ignoreCancelled = true)
void onPlayerRespawn (PlayerRespawnEvent event)
{
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(event.getPlayer().getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(event.getPlayer().getUniqueId());
playerData.lastSpawn = Calendar.getInstance().getTimeInMillis();
GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer());
}
@ -453,14 +453,14 @@ class PlayerEventHandler implements Listener
void onPlayerJoin(PlayerJoinEvent event)
{
Player player = event.getPlayer();
String playerName = player.getName();
UUID playerID = player.getUniqueId();
//note login time
long now = Calendar.getInstance().getTimeInMillis();
PlayerData playerData = this.dataStore.getPlayerData(playerName);
PlayerData playerData = this.dataStore.getPlayerData(playerID);
playerData.lastSpawn = now;
playerData.lastLogin = new Date();
this.dataStore.savePlayerData(playerName, playerData);
this.dataStore.savePlayerData(playerID, playerData);
//if player has never played on the server before, may need pvp protection
if(!player.hasPlayedBefore())
@ -544,7 +544,7 @@ class PlayerEventHandler implements Listener
void onPlayerDeath(PlayerDeathEvent event)
{
//FEATURE: prevent death message spam by implementing a "cooldown period" for death messages
PlayerData playerData = this.dataStore.getPlayerData(event.getEntity().getName());
PlayerData playerData = this.dataStore.getPlayerData(event.getEntity().getUniqueId());
long now = Calendar.getInstance().getTimeInMillis();
if(now - playerData.lastDeathTimeStamp < GriefPrevention.instance.config_spam_deathMessageCooldownSeconds * 1000)
{
@ -559,7 +559,7 @@ class PlayerEventHandler implements Listener
void onPlayerQuit(PlayerQuitEvent event)
{
Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//if banned, add IP to the temporary IP ban list
if(player.isBanned() && playerData.ipAddress != null)
@ -575,7 +575,7 @@ class PlayerEventHandler implements Listener
}
//make sure his data is all saved - he might have accrued some claim blocks while playing that were not saved immediately
this.dataStore.savePlayerData(player.getName(), playerData);
this.dataStore.savePlayerData(player.getUniqueId(), playerData);
this.onPlayerDisconnect(event.getPlayer(), event.getQuitMessage());
}
@ -583,8 +583,8 @@ class PlayerEventHandler implements Listener
//helper for above
private void onPlayerDisconnect(Player player, String notificationMessage)
{
String playerName = player.getName();
PlayerData playerData = this.dataStore.getPlayerData(playerName);
UUID playerID = player.getUniqueId();
PlayerData playerData = this.dataStore.getPlayerData(playerID);
//FEATURE: claims where players have allowed explosions will revert back to not allowing them when the owner logs out
for(Claim claim : playerData.claims)
@ -607,7 +607,7 @@ class PlayerEventHandler implements Listener
}
//drop data about this player
this.dataStore.clearCachedPlayerData(player.getName());
this.dataStore.clearCachedPlayerData(playerID);
}
//determines whether or not a login or logout notification should be silenced, depending on how many there have been in the last minute
@ -650,7 +650,7 @@ class PlayerEventHandler implements Listener
return;
}
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//FEATURE: players under siege or in PvP combat, can't throw items on the ground to hide
//them or give them away to other players before they are defeated
@ -675,7 +675,7 @@ class PlayerEventHandler implements Listener
public void onPlayerTeleport(PlayerTeleportEvent event)
{
Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//FEATURE: prevent players from using ender pearls to gain access to secured claims
if(event.getCause() == TeleportCause.ENDER_PEARL && GriefPrevention.instance.config_claims_enderPearlsRequireAccessTrust)
@ -723,7 +723,7 @@ class PlayerEventHandler implements Listener
{
Player player = event.getPlayer();
Entity entity = event.getRightClicked();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
//don't allow interaction with item frames in claimed areas without build permission
if(entity instanceof Hanging)
@ -825,7 +825,7 @@ class PlayerEventHandler implements Listener
if(GriefPrevention.instance.config_pvp_protectFreshSpawns && (player.getItemInHand().getType() == Material.AIR))
{
//if that player is currently immune to pvp
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
if(playerData.pvpImmune)
{
//if it's been less than 10 seconds since the last time he spawned, don't pick up the item
@ -854,7 +854,7 @@ class PlayerEventHandler implements Listener
ItemStack newItemStack = player.getInventory().getItem(event.getNewSlot());
if(newItemStack != null && newItemStack.getType() == GriefPrevention.instance.config_claims_modificationTool)
{
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
//always reset to basic claims mode
if(playerData.shovelMode != ShovelMode.Basic)
@ -916,7 +916,7 @@ class PlayerEventHandler implements Listener
}
//if the bucket is being used in a claim, allow for dumping lava closer to other players
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Claim claim = this.dataStore.getClaimAt(block.getLocation(), false, playerData.lastClaim);
if(claim != null)
{
@ -1011,7 +1011,7 @@ class PlayerEventHandler implements Listener
Material clickedBlockType = clickedBlock.getType();
//apply rules for putting out fires (requires build permission)
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
if(event.getClickedBlock() != null && event.getClickedBlock().getRelative(event.getBlockFace()).getType() == Material.FIRE)
{
Claim claim = this.dataStore.getClaimAt(clickedBlock.getLocation(), false, playerData.lastClaim);
@ -1248,7 +1248,7 @@ class PlayerEventHandler implements Listener
//if deleteclaims permission, tell about the player's offline time
if(!claim.isAdminClaim() && player.hasPermission("griefprevention.deleteclaims"))
{
PlayerData otherPlayerData = this.dataStore.getPlayerData(claim.getOwnerName());
PlayerData otherPlayerData = this.dataStore.getPlayerData(claim.ownerID);
Date lastLogin = otherPlayerData.lastLogin;
Date now = new Date();
long daysElapsed = (now.getTime() - lastLogin.getTime()) / (1000 * 60 * 60 * 24);
@ -1256,8 +1256,8 @@ class PlayerEventHandler implements Listener
GriefPrevention.sendMessage(player, TextMode.Info, Messages.PlayerOfflineTime, String.valueOf(daysElapsed));
//drop the data we just loaded, if the player isn't online
if(GriefPrevention.instance.getServer().getPlayerExact(claim.getOwnerName()) == null)
this.dataStore.clearCachedPlayerData(claim.getOwnerName());
if(GriefPrevention.instance.getServer().getPlayer(claim.ownerID) == null)
this.dataStore.clearCachedPlayerData(claim.ownerID);
}
}
@ -1283,8 +1283,8 @@ class PlayerEventHandler implements Listener
}
//if the player is in restore nature mode, do only that
String playerName = player.getName();
playerData = this.dataStore.getPlayerData(player.getName());
UUID playerID = player.getUniqueId();
playerData = this.dataStore.getPlayerData(player.getUniqueId());
if(playerData.shovelMode == ShovelMode.RestoreNature || playerData.shovelMode == ShovelMode.RestoreNatureAggressive)
{
//if the clicked block is in a claim, visualize that claim and deliver an error message
@ -1538,7 +1538,7 @@ class PlayerEventHandler implements Listener
Claim newClaim = new Claim(
new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx1, newy1, newz1),
new Location(oldClaim.getLesserBoundaryCorner().getWorld(), newx2, newy2, newz2),
"", new String[]{}, new String[]{}, new String[]{}, new String[]{}, null);
null, new String[]{}, new String[]{}, new String[]{}, new String[]{}, null);
//if the new claim is smaller
if(!newClaim.contains(oldClaim.getLesserBoundaryCorner(), true, false) || !newClaim.contains(oldClaim.getGreaterBoundaryCorner(), true, false))
@ -1568,9 +1568,9 @@ class PlayerEventHandler implements Listener
Visualization.Apply(player, visualization);
//if resizing someone else's claim, make a log entry
if(!playerData.claimResizing.ownerName.equals(playerName))
if(!playerID.equals(playerData.claimResizing.ownerID))
{
GriefPrevention.AddLogEntry(playerName + " resized " + playerData.claimResizing.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(playerData.claimResizing.lesserBoundaryCorner) + ".");
GriefPrevention.AddLogEntry(player.getName() + " resized " + playerData.claimResizing.getOwnerName() + "'s claim at " + GriefPrevention.getfriendlyLocationString(playerData.claimResizing.lesserBoundaryCorner) + ".");
}
//if in a creative mode world and shrinking an existing claim, restore any unclaimed area
@ -1654,7 +1654,7 @@ class PlayerEventHandler implements Listener
playerData.lastShovelLocation.getBlockX(), clickedBlock.getX(),
playerData.lastShovelLocation.getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, clickedBlock.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance,
playerData.lastShovelLocation.getBlockZ(), clickedBlock.getZ(),
"--subdivision--", //owner name is not used for subdivisions
null, //owner is not used for subdivisions
playerData.claimSubdividing,
null);
@ -1720,7 +1720,7 @@ class PlayerEventHandler implements Listener
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.ClaimStart);
//show him where he's working
Visualization visualization = Visualization.FromClaim(new Claim(clickedBlock.getLocation(), clickedBlock.getLocation(), "", new String[]{}, new String[]{}, new String[]{}, new String[]{}, null), clickedBlock.getY(), VisualizationType.RestoreNature, player.getLocation());
Visualization visualization = Visualization.FromClaim(new Claim(clickedBlock.getLocation(), clickedBlock.getLocation(), null, new String[]{}, new String[]{}, new String[]{}, new String[]{}, null), clickedBlock.getY(), VisualizationType.RestoreNature, player.getLocation());
Visualization.Apply(player, visualization);
}
@ -1759,7 +1759,7 @@ class PlayerEventHandler implements Listener
}
else
{
playerName = "";
playerID = null;
}
//try to create a new claim (will return null if this claim overlaps another)
@ -1768,7 +1768,7 @@ class PlayerEventHandler implements Listener
lastShovelLocation.getBlockX(), clickedBlock.getX(),
lastShovelLocation.getBlockY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance, clickedBlock.getY() - GriefPrevention.instance.config_claims_claimsExtendIntoGroundDistance,
lastShovelLocation.getBlockZ(), clickedBlock.getZ(),
playerName,
playerID,
null, null);
//if it didn't succeed, tell the player why

View File

@ -43,7 +43,7 @@ class PlayerKickBanTask implements Runnable
if(this.banReason != null)
{
//ban
GriefPrevention.instance.getServer().getOfflinePlayer(this.player.getName()).setBanned(true);
GriefPrevention.instance.getServer().getOfflinePlayer(this.player.getUniqueId()).setBanned(true);
//kick
if(this.player.isOnline())

View File

@ -47,7 +47,7 @@ class PlayerRescueTask implements Runnable
if(!player.isOnline()) return;
//he no longer has a pending /trapped slash command, so he can try to use it again now
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
playerData.pendingTrapped = false;
//if the player moved three or more blocks from where he used /trapped, admonish him and don't save him

View File

@ -112,7 +112,7 @@ class RestoreNatureExecutionTask implements Runnable
//show visualization to player who started the restoration
if(player != null)
{
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
Claim claim = new Claim(lesserCorner, greaterCorner, null, new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature, player.getLocation());
Visualization.Apply(player, visualization);
}

View File

@ -0,0 +1,145 @@
//BIG THANKS to EvilMidget38 for providing this handy UUID lookup tool to the Bukkit community! :)
package me.ryanhamshire.GriefPrevention;
import com.google.common.collect.ImmutableList;
import org.bukkit.OfflinePlayer;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.Callable;
class UUIDFetcher implements Callable<Map<String, UUID>> {
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();
private final List<String> names;
private final boolean rateLimiting;
//cache for username -> uuid lookups
private static HashMap<String, UUID> lookupCache;
public UUIDFetcher(List<String> names, boolean rateLimiting) {
this.names = ImmutableList.copyOf(names);
this.rateLimiting = rateLimiting;
}
public UUIDFetcher(List<String> names) {
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);
}
}
return uuidMap;
}
private static void writeBody(HttpURLConnection connection, String body) throws Exception {
OutputStream stream = connection.getOutputStream();
stream.write(body.getBytes());
stream.flush();
stream.close();
}
private static HttpURLConnection createConnection() throws Exception {
URL url = new URL(PROFILE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.setUseCaches(false);
connection.setDoInput(true);
connection.setDoOutput(true);
return connection;
}
private static UUID getUUID(String id) {
return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" +id.substring(20, 32));
}
public static byte[] toBytes(UUID uuid) {
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]);
byteBuffer.putLong(uuid.getMostSignificantBits());
byteBuffer.putLong(uuid.getLeastSignificantBits());
return byteBuffer.array();
}
public static UUID fromBytes(byte[] array) {
if (array.length != 16) {
throw new IllegalArgumentException("Illegal byte array length: " + array.length);
}
ByteBuffer byteBuffer = ByteBuffer.wrap(array);
long mostSignificant = byteBuffer.getLong();
long leastSignificant = byteBuffer.getLong();
return new UUID(mostSignificant, leastSignificant);
}
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;
String correctCasingName = getNameWithCasing(name);
result = new UUIDFetcher(Arrays.asList(name)).call().get(correctCasingName);
if(result == null)
{
GriefPrevention.AddLogEntry(correctCasingName + " --> ???");
lookupCache.put(name, null);
throw new IllegalArgumentException(name);
}
GriefPrevention.AddLogEntry(correctCasingName + " --> " + result.toString());
lookupCache.put(name, result);
}
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;
}
}

View File

@ -37,7 +37,7 @@ public class Visualization
//sends a visualization to a player
public static void Apply(Player player, Visualization visualization)
{
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
//if he has any current visualization, clear it first
if(playerData.currentVisualization != null)
@ -55,7 +55,7 @@ public class Visualization
//reverts a visualization by sending another block change list, this time with the real world block values
public static void Revert(Player player)
{
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getUniqueId());
Visualization visualization = playerData.currentVisualization;