5.1
This commit is contained in:
parent
6cb8df52c7
commit
311db20522
|
|
@ -1,7 +1,7 @@
|
||||||
name: GriefPrevention
|
name: GriefPrevention
|
||||||
main: me.ryanhamshire.GriefPrevention.GriefPrevention
|
main: me.ryanhamshire.GriefPrevention.GriefPrevention
|
||||||
softdepend: [Vault, Multiverse-Core]
|
softdepend: [Vault, Multiverse-Core]
|
||||||
version: 5.0
|
version: 5.1
|
||||||
commands:
|
commands:
|
||||||
abandonclaim:
|
abandonclaim:
|
||||||
description: Deletes a claim.
|
description: Deletes a claim.
|
||||||
|
|
|
||||||
|
|
@ -297,7 +297,7 @@ public class BlockEventHandler implements Listener
|
||||||
|
|
||||||
//show the player the protected area
|
//show the player the protected area
|
||||||
Claim newClaim = this.dataStore.getClaimAt(block.getLocation(), false, null);
|
Claim newClaim = this.dataStore.getClaimAt(block.getLocation(), false, null);
|
||||||
Visualization visualization = Visualization.FromClaim(newClaim, block.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(newClaim, block.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,9 @@ public class Claim
|
||||||
//don't do this for administrative claims
|
//don't do this for administrative claims
|
||||||
if(this.isAdminClaim()) return;
|
if(this.isAdminClaim()) return;
|
||||||
|
|
||||||
|
//don't do it for very large claims
|
||||||
|
if(this.getArea() > 10000) return;
|
||||||
|
|
||||||
Location lesser = this.getLesserBoundaryCorner();
|
Location lesser = this.getLesserBoundaryCorner();
|
||||||
Location greater = this.getGreaterBoundaryCorner();
|
Location greater = this.getGreaterBoundaryCorner();
|
||||||
|
|
||||||
|
|
@ -154,6 +157,9 @@ public class Claim
|
||||||
Location lesser = this.getLesserBoundaryCorner();
|
Location lesser = this.getLesserBoundaryCorner();
|
||||||
Location greater = this.getGreaterBoundaryCorner();
|
Location greater = this.getGreaterBoundaryCorner();
|
||||||
|
|
||||||
|
//don't bother for very large claims, too expensive
|
||||||
|
if(this.getArea() > 10000) return false;
|
||||||
|
|
||||||
int seaLevel = 0; //clean up all fluids in the end
|
int seaLevel = 0; //clean up all fluids in the end
|
||||||
|
|
||||||
//respect sea level in normal worlds
|
//respect sea level in normal worlds
|
||||||
|
|
@ -695,6 +701,9 @@ public class Claim
|
||||||
//this rule only applies to creative mode worlds
|
//this rule only applies to creative mode worlds
|
||||||
if(!GriefPrevention.instance.creativeRulesApply(this.getLesserBoundaryCorner())) return null;
|
if(!GriefPrevention.instance.creativeRulesApply(this.getLesserBoundaryCorner())) return null;
|
||||||
|
|
||||||
|
//admin claims aren't restricted
|
||||||
|
if(this.isAdminClaim()) return null;
|
||||||
|
|
||||||
//determine maximum allowable entity count, based on claim size
|
//determine maximum allowable entity count, based on claim size
|
||||||
int maxEntities = this.getArea() / 50;
|
int maxEntities = this.getArea() / 50;
|
||||||
if(maxEntities == 0) return GriefPrevention.instance.dataStore.getMessage(Messages.ClaimTooSmallForEntities);
|
if(maxEntities == 0) return GriefPrevention.instance.dataStore.getMessage(Messages.ClaimTooSmallForEntities);
|
||||||
|
|
|
||||||
|
|
@ -19,9 +19,6 @@
|
||||||
package me.ryanhamshire.GriefPrevention;
|
package me.ryanhamshire.GriefPrevention;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.text.DateFormat;
|
|
||||||
import java.text.ParseException;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import org.bukkit.*;
|
import org.bukkit.*;
|
||||||
|
|
@ -31,13 +28,13 @@ import org.bukkit.entity.Player;
|
||||||
import org.bukkit.inventory.ItemStack;
|
import org.bukkit.inventory.ItemStack;
|
||||||
|
|
||||||
//singleton class which manages all GriefPrevention data (except for config options)
|
//singleton class which manages all GriefPrevention data (except for config options)
|
||||||
public class DataStore
|
public abstract class DataStore
|
||||||
{
|
{
|
||||||
//in-memory cache for player data
|
//in-memory cache for player data
|
||||||
private HashMap<String, PlayerData> playerNameToPlayerDataMap = new HashMap<String, PlayerData>();
|
protected HashMap<String, PlayerData> playerNameToPlayerDataMap = new HashMap<String, PlayerData>();
|
||||||
|
|
||||||
//in-memory cache for group (permission-based) data
|
//in-memory cache for group (permission-based) data
|
||||||
private HashMap<String, Integer> permissionToBonusBlocksMap = new HashMap<String, Integer>();
|
protected HashMap<String, Integer> permissionToBonusBlocksMap = new HashMap<String, Integer>();
|
||||||
|
|
||||||
//in-memory cache for claim data
|
//in-memory cache for claim data
|
||||||
ArrayList<Claim> claims = new ArrayList<Claim>();
|
ArrayList<Claim> claims = new ArrayList<Claim>();
|
||||||
|
|
@ -49,227 +46,18 @@ public class DataStore
|
||||||
Long nextClaimID = (long)0;
|
Long nextClaimID = (long)0;
|
||||||
|
|
||||||
//path information, for where stuff stored on disk is well... stored
|
//path information, for where stuff stored on disk is well... stored
|
||||||
private final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
|
protected final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
|
||||||
private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
|
|
||||||
private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData";
|
|
||||||
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
|
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
|
||||||
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
|
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
|
||||||
final static String nextClaimIdFilePath = claimDataFolderPath + File.separator + "_nextClaimID";
|
|
||||||
|
|
||||||
//initialization!
|
//initialization!
|
||||||
|
abstract void initialize();
|
||||||
|
|
||||||
DataStore()
|
DataStore()
|
||||||
{
|
{
|
||||||
//ensure data folders exist
|
this.initialize();
|
||||||
new File(playerDataFolderPath).mkdirs();
|
|
||||||
new File(claimDataFolderPath).mkdirs();
|
|
||||||
|
|
||||||
//load group data into memory
|
GriefPrevention.AddLogEntry(this.claims.size() + " total claims loaded.");
|
||||||
File playerDataFolder = new File(playerDataFolderPath);
|
|
||||||
File [] files = playerDataFolder.listFiles();
|
|
||||||
for(int i = 0; i < files.length; i++)
|
|
||||||
{
|
|
||||||
File file = files[i];
|
|
||||||
if(!file.isFile()) continue; //avoids folders
|
|
||||||
|
|
||||||
//all group data files start with an underscore. ignoring the rest, which are player data files.
|
|
||||||
if(!file.getName().startsWith("$")) continue;
|
|
||||||
|
|
||||||
String groupName = file.getName().substring(1);
|
|
||||||
if(groupName == null || groupName.isEmpty()) continue; //defensive coding, avoid unlikely cases
|
|
||||||
|
|
||||||
BufferedReader inStream = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inStream = new BufferedReader(new FileReader(file.getAbsolutePath()));
|
|
||||||
String line = inStream.readLine();
|
|
||||||
|
|
||||||
int groupBonusBlocks = Integer.parseInt(line);
|
|
||||||
|
|
||||||
this.permissionToBonusBlocksMap.put(groupName, groupBonusBlocks);
|
|
||||||
}
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("Unable to load group bonus block data from file \"" + file.getName() + "\": " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(inStream != null) inStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//load claims data into memory
|
|
||||||
File claimDataFolder = new File(claimDataFolderPath);
|
|
||||||
|
|
||||||
//load next claim number from file
|
|
||||||
File nextClaimIdFile = new File(nextClaimIdFilePath);
|
|
||||||
if(nextClaimIdFile.exists())
|
|
||||||
{
|
|
||||||
BufferedReader inStream = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inStream = new BufferedReader(new FileReader(nextClaimIdFile.getAbsolutePath()));
|
|
||||||
|
|
||||||
//read the id
|
|
||||||
String line = inStream.readLine();
|
|
||||||
|
|
||||||
//try to parse into a long value
|
|
||||||
this.nextClaimID = Long.parseLong(line);
|
|
||||||
}
|
|
||||||
catch(Exception e){ }
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(inStream != null) inStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//get a list of all the files in the claims data folder
|
|
||||||
files = claimDataFolder.listFiles();
|
|
||||||
|
|
||||||
int loadedClaimCount = 0;
|
|
||||||
|
|
||||||
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.
|
|
||||||
if(files[i].getName().startsWith("_")) continue;
|
|
||||||
|
|
||||||
//the filename is the claim ID. try to parse it
|
|
||||||
long claimID;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
claimID = Long.parseLong(files[i].getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
//because some older versions used a different file name pattern before claim IDs were introduced,
|
|
||||||
//those files need to be "converted" by renaming them to a unique ID
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
claimID = this.nextClaimID;
|
|
||||||
this.incrementNextClaimID();
|
|
||||||
File newFile = new File(claimDataFolderPath + File.separator + String.valueOf(this.nextClaimID));
|
|
||||||
files[i].renameTo(newFile);
|
|
||||||
files[i] = newFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
BufferedReader inStream = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Claim topLevelClaim = null;
|
|
||||||
|
|
||||||
inStream = new BufferedReader(new FileReader(files[i].getAbsolutePath()));
|
|
||||||
String line = inStream.readLine();
|
|
||||||
|
|
||||||
while(line != null)
|
|
||||||
{
|
|
||||||
//first line is lesser boundary corner location
|
|
||||||
Location lesserBoundaryCorner = this.locationFromString(line);
|
|
||||||
|
|
||||||
//second line is greater boundary corner location
|
|
||||||
line = inStream.readLine();
|
|
||||||
Location greaterBoundaryCorner = this.locationFromString(line);
|
|
||||||
|
|
||||||
//third line is owner name
|
|
||||||
line = inStream.readLine();
|
|
||||||
String ownerName = line;
|
|
||||||
|
|
||||||
//fourth line is list of builders
|
|
||||||
line = inStream.readLine();
|
|
||||||
String [] builderNames = line.split(";");
|
|
||||||
|
|
||||||
//fifth line is list of players who can access containers
|
|
||||||
line = inStream.readLine();
|
|
||||||
String [] containerNames = line.split(";");
|
|
||||||
|
|
||||||
//sixth line is list of players who can use buttons and switches
|
|
||||||
line = inStream.readLine();
|
|
||||||
String [] accessorNames = line.split(";");
|
|
||||||
|
|
||||||
//seventh line is list of players who can grant permissions
|
|
||||||
line = inStream.readLine();
|
|
||||||
if(line == null) line = "";
|
|
||||||
String [] managerNames = line.split(";");
|
|
||||||
|
|
||||||
//skip any remaining extra lines, until the "===" string, indicating the end of this claim or subdivision
|
|
||||||
line = inStream.readLine();
|
|
||||||
while(line != null && !line.contains("=========="))
|
|
||||||
line = inStream.readLine();
|
|
||||||
|
|
||||||
//build a claim instance from those data
|
|
||||||
//if this is the first claim loaded from this file, it's the top level claim
|
|
||||||
if(topLevelClaim == null)
|
|
||||||
{
|
|
||||||
//instantiate
|
|
||||||
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, claimID);
|
|
||||||
|
|
||||||
//search for another claim overlapping this one
|
|
||||||
Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true, null);
|
|
||||||
|
|
||||||
//if there is such a claim, delete this file and move on to the next
|
|
||||||
if(conflictClaim != null)
|
|
||||||
{
|
|
||||||
inStream.close();
|
|
||||||
files[i].delete();
|
|
||||||
line = null;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
//otherwise, add this claim to the claims collection
|
|
||||||
else
|
|
||||||
{
|
|
||||||
topLevelClaim.modifiedDate = new Date(files[i].lastModified());
|
|
||||||
int j = 0;
|
|
||||||
while(j < this.claims.size() && !this.claims.get(j).greaterThan(topLevelClaim)) j++;
|
|
||||||
if(j < this.claims.size())
|
|
||||||
this.claims.add(j, topLevelClaim);
|
|
||||||
else
|
|
||||||
this.claims.add(this.claims.size(), topLevelClaim);
|
|
||||||
topLevelClaim.inDataStore = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//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);
|
|
||||||
|
|
||||||
//make sure there are no other subdivisions overlapping this one
|
|
||||||
|
|
||||||
subdivision.modifiedDate = new Date(files[i].lastModified());
|
|
||||||
subdivision.parent = topLevelClaim;
|
|
||||||
topLevelClaim.children.add(subdivision);
|
|
||||||
subdivision.inDataStore = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//move up to the first line in the next subdivision
|
|
||||||
line = inStream.readLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
inStream.close();
|
|
||||||
|
|
||||||
loadedClaimCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
//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());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(inStream != null) inStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
GriefPrevention.AddLogEntry(loadedClaimCount + " total claims loaded.");
|
|
||||||
|
|
||||||
//make a list of players who own claims
|
//make a list of players who own claims
|
||||||
Vector<String> playerNames = new Vector<String>();
|
Vector<String> playerNames = new Vector<String>();
|
||||||
|
|
@ -377,39 +165,14 @@ public class DataStore
|
||||||
currentValue += amount;
|
currentValue += amount;
|
||||||
this.permissionToBonusBlocksMap.put(groupName, currentValue);
|
this.permissionToBonusBlocksMap.put(groupName, currentValue);
|
||||||
|
|
||||||
//write changes to file to ensure they don't get lost
|
//write changes to storage to ensure they don't get lost
|
||||||
BufferedWriter outStream = null;
|
this.saveGroupBonusBlocks(groupName, currentValue);
|
||||||
try
|
|
||||||
{
|
|
||||||
//open the group's file
|
|
||||||
File groupDataFile = new File(playerDataFolderPath + File.separator + "$" + groupName);
|
|
||||||
groupDataFile.createNewFile();
|
|
||||||
outStream = new BufferedWriter(new FileWriter(groupDataFile));
|
|
||||||
|
|
||||||
//first line is number of bonus blocks
|
|
||||||
outStream.write(currentValue.toString());
|
|
||||||
outStream.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if any problem, log it
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("Unexpected exception saving data for group \"" + groupName + "\": " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//close the file
|
|
||||||
if(outStream != null)
|
|
||||||
{
|
|
||||||
outStream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(IOException exception){}
|
|
||||||
|
|
||||||
return currentValue;
|
return currentValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract void saveGroupBonusBlocks(String groupName, int amount);
|
||||||
|
|
||||||
public void changeClaimOwner(Claim claim, String newOwnerName) throws Exception
|
public void changeClaimOwner(Claim claim, String newOwnerName) throws Exception
|
||||||
{
|
{
|
||||||
//if it's a subdivision, throw an exception
|
//if it's a subdivision, throw an exception
|
||||||
|
|
@ -480,9 +243,9 @@ public class DataStore
|
||||||
this.saveClaim(newClaim);
|
this.saveClaim(newClaim);
|
||||||
}
|
}
|
||||||
|
|
||||||
//turns a location into a string, useful in data files and data file names
|
//turns a location into a string, useful in data storage
|
||||||
private String locationStringDelimiter = ";";
|
private String locationStringDelimiter = ";";
|
||||||
private String locationToString(Location location)
|
String locationToString(Location location)
|
||||||
{
|
{
|
||||||
StringBuilder stringBuilder = new StringBuilder(location.getWorld().getName());
|
StringBuilder stringBuilder = new StringBuilder(location.getWorld().getName());
|
||||||
stringBuilder.append(locationStringDelimiter);
|
stringBuilder.append(locationStringDelimiter);
|
||||||
|
|
@ -496,7 +259,7 @@ public class DataStore
|
||||||
}
|
}
|
||||||
|
|
||||||
//turns a location string back into a location
|
//turns a location string back into a location
|
||||||
private Location locationFromString(String string) throws Exception
|
Location locationFromString(String string) throws Exception
|
||||||
{
|
{
|
||||||
//split the input string on the space
|
//split the input string on the space
|
||||||
String [] elements = string.split(locationStringDelimiter);
|
String [] elements = string.split(locationStringDelimiter);
|
||||||
|
|
@ -527,7 +290,7 @@ public class DataStore
|
||||||
return new Location(world, x, y, z);
|
return new Location(world, x, y, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
//does the work of actually writing a claim to file
|
//saves any changes to a claim to secondary storage
|
||||||
public void saveClaim(Claim claim)
|
public void saveClaim(Claim claim)
|
||||||
{
|
{
|
||||||
//subdivisions don't save to their own files, but instead live in their parent claim's file
|
//subdivisions don't save to their own files, but instead live in their parent claim's file
|
||||||
|
|
@ -545,247 +308,27 @@ public class DataStore
|
||||||
this.incrementNextClaimID();
|
this.incrementNextClaimID();
|
||||||
}
|
}
|
||||||
|
|
||||||
String claimID = String.valueOf(claim.id);
|
this.writeClaimToStorage(claim);
|
||||||
|
|
||||||
BufferedWriter outStream = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//open the claim's file
|
|
||||||
File claimFile = new File(claimDataFolderPath + File.separator + claimID);
|
|
||||||
claimFile.createNewFile();
|
|
||||||
outStream = new BufferedWriter(new FileWriter(claimFile));
|
|
||||||
|
|
||||||
this.writeClaimData(claim, outStream);
|
|
||||||
|
|
||||||
for(int i = 0; i < claim.children.size(); i++)
|
|
||||||
{
|
|
||||||
//see below for details of writing data to file
|
|
||||||
this.writeClaimData(claim.children.get(i), outStream);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if any problem, log it
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("PopulationDensity: Unexpected exception saving data for claim \"" + claimID + "\": " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
//close the file
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(outStream != null) outStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void incrementNextClaimID()
|
abstract void writeClaimToStorage(Claim claim);
|
||||||
{
|
|
||||||
this.nextClaimID++;
|
|
||||||
|
|
||||||
BufferedWriter outStream = null;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//open the claim's file
|
|
||||||
File nextClaimIdFile = new File(nextClaimIdFilePath);
|
|
||||||
nextClaimIdFile.createNewFile();
|
|
||||||
outStream = new BufferedWriter(new FileWriter(nextClaimIdFile));
|
|
||||||
|
|
||||||
outStream.write(String.valueOf(this.nextClaimID));
|
|
||||||
}
|
|
||||||
|
|
||||||
//if any problem, log it
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("Unexpected exception saving next claim ID: " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
//close the file
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(outStream != null) outStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//actually writes claim data to an output stream
|
|
||||||
private void writeClaimData(Claim claim, BufferedWriter outStream) throws IOException
|
|
||||||
{
|
|
||||||
//first line is lesser boundary corner location
|
|
||||||
outStream.write(this.locationToString(claim.getLesserBoundaryCorner()));
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//second line is greater boundary corner location
|
|
||||||
outStream.write(this.locationToString(claim.getGreaterBoundaryCorner()));
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//third line is owner name
|
|
||||||
outStream.write(claim.ownerName);
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
ArrayList<String> builders = new ArrayList<String>();
|
|
||||||
ArrayList<String> containers = new ArrayList<String>();
|
|
||||||
ArrayList<String> accessors = new ArrayList<String>();
|
|
||||||
ArrayList<String> managers = new ArrayList<String>();
|
|
||||||
|
|
||||||
claim.getPermissions(builders, containers, accessors, managers);
|
|
||||||
|
|
||||||
//fourth line is list of players with build permission
|
|
||||||
for(int i = 0; i < builders.size(); i++)
|
|
||||||
{
|
|
||||||
outStream.write(builders.get(i) + ";");
|
|
||||||
}
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//fifth line is list of players with container permission
|
|
||||||
for(int i = 0; i < containers.size(); i++)
|
|
||||||
{
|
|
||||||
outStream.write(containers.get(i) + ";");
|
|
||||||
}
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//sixth line is list of players with access permission
|
|
||||||
for(int i = 0; i < accessors.size(); i++)
|
|
||||||
{
|
|
||||||
outStream.write(accessors.get(i) + ";");
|
|
||||||
}
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//seventh line is list of players who may grant permissions for others
|
|
||||||
for(int i = 0; i < managers.size(); i++)
|
|
||||||
{
|
|
||||||
outStream.write(managers.get(i) + ";");
|
|
||||||
}
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//cap each claim with "=========="
|
|
||||||
outStream.write("==========");
|
|
||||||
outStream.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
//retrieves player data from memory or file, as necessary
|
//increments the claim ID and updates secondary storage to be sure it's saved
|
||||||
|
abstract void incrementNextClaimID();
|
||||||
|
|
||||||
|
//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
|
//if the player has never been on the server before, this will return a fresh player data with default values
|
||||||
public PlayerData getPlayerData(String playerName)
|
public PlayerData getPlayerData(String playerName)
|
||||||
{
|
{
|
||||||
//first, look in memory
|
//first, look in memory
|
||||||
PlayerData playerData = this.playerNameToPlayerDataMap.get(playerName);
|
PlayerData playerData = this.playerNameToPlayerDataMap.get(playerName);
|
||||||
|
|
||||||
//if not there, look on disk
|
//if not there, look in secondary storage
|
||||||
if(playerData == null)
|
if(playerData == null)
|
||||||
{
|
{
|
||||||
File playerFile = new File(playerDataFolderPath + File.separator + playerName);
|
playerData = this.getPlayerDataFromStorage(playerName);
|
||||||
|
|
||||||
playerData = new PlayerData();
|
|
||||||
playerData.playerName = playerName;
|
playerData.playerName = playerName;
|
||||||
|
|
||||||
//if it doesn't exist as a file
|
|
||||||
if(!playerFile.exists())
|
|
||||||
{
|
|
||||||
//create a file with defaults
|
|
||||||
this.savePlayerData(playerName, playerData);
|
|
||||||
}
|
|
||||||
|
|
||||||
//otherwise, read the file
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BufferedReader inStream = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
inStream = new BufferedReader(new FileReader(playerFile.getAbsolutePath()));
|
|
||||||
|
|
||||||
//first line is last login timestamp
|
|
||||||
String lastLoginTimestampString = inStream.readLine();
|
|
||||||
|
|
||||||
//convert that to a date and store it
|
|
||||||
DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
|
|
||||||
try
|
|
||||||
{
|
|
||||||
playerData.lastLogin = dateFormat.parse(lastLoginTimestampString);
|
|
||||||
}
|
|
||||||
catch(ParseException parseException)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("Unable to load last login for \"" + playerFile.getName() + "\".");
|
|
||||||
playerData.lastLogin = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
//second line is accrued claim blocks
|
|
||||||
String accruedBlocksString = inStream.readLine();
|
|
||||||
|
|
||||||
//convert that to a number and store it
|
|
||||||
playerData.accruedClaimBlocks = Integer.parseInt(accruedBlocksString);
|
|
||||||
|
|
||||||
//third line is any bonus claim blocks granted by administrators
|
|
||||||
String bonusBlocksString = inStream.readLine();
|
|
||||||
|
|
||||||
//convert that to a number and store it
|
|
||||||
playerData.bonusClaimBlocks = Integer.parseInt(bonusBlocksString);
|
|
||||||
|
|
||||||
//fourth line is a double-semicolon-delimited list of claims, which is currently ignored
|
|
||||||
//String claimsString = inStream.readLine();
|
|
||||||
inStream.readLine();
|
|
||||||
/*
|
|
||||||
if(claimsString != null && claimsString.length() > 0)
|
|
||||||
{
|
|
||||||
String [] claimsStrings = claimsString.split(";;");
|
|
||||||
boolean missingClaim = false;
|
|
||||||
|
|
||||||
//search for each claim mentioned in the file
|
|
||||||
for(int i = 0; i < claimsStrings.length; i++)
|
|
||||||
{
|
|
||||||
String claimID = claimsStrings[i];
|
|
||||||
if(claimID != null)
|
|
||||||
{
|
|
||||||
Claim claim = this.getClaimAt(this.locationFromString(claimID), true, null);
|
|
||||||
|
|
||||||
//if the referenced claim exists, add it to the player data instance for later reference
|
|
||||||
if(claim != null)
|
|
||||||
{
|
|
||||||
playerData.claims.add(claim);
|
|
||||||
}
|
|
||||||
|
|
||||||
//if the claim doesn't seem to exist anymore, plan to drop the reference from the file
|
|
||||||
else
|
|
||||||
{
|
|
||||||
missingClaim = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//if any referenced claims no longer exist, write the player data back to file to eliminate those references
|
|
||||||
if(missingClaim)
|
|
||||||
{
|
|
||||||
this.savePlayerData(playerName, playerData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
//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))
|
|
||||||
{
|
|
||||||
playerData.claims.add(claim);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inStream.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
//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());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if(inStream != null) inStream.close();
|
|
||||||
}
|
|
||||||
catch(IOException exception) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
//shove that new player data into the hash map cache
|
//shove that new player data into the hash map cache
|
||||||
this.playerNameToPlayerDataMap.put(playerName, playerData);
|
this.playerNameToPlayerDataMap.put(playerName, playerData);
|
||||||
}
|
}
|
||||||
|
|
@ -794,6 +337,8 @@ public class DataStore
|
||||||
return this.playerNameToPlayerDataMap.get(playerName);
|
return this.playerNameToPlayerDataMap.get(playerName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract PlayerData getPlayerDataFromStorage(String playerName);
|
||||||
|
|
||||||
//deletes a claim or subdivision
|
//deletes a claim or subdivision
|
||||||
public void deleteClaim(Claim claim)
|
public void deleteClaim(Claim claim)
|
||||||
{
|
{
|
||||||
|
|
@ -806,9 +351,6 @@ public class DataStore
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//otherwise, need to update the data store and ensure the claim's file is deleted
|
|
||||||
String claimID = String.valueOf(claim.id);
|
|
||||||
|
|
||||||
//remove from memory
|
//remove from memory
|
||||||
for(int i = 0; i < this.claims.size(); i++)
|
for(int i = 0; i < this.claims.size(); i++)
|
||||||
{
|
{
|
||||||
|
|
@ -824,12 +366,8 @@ public class DataStore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//remove from disk
|
//remove from secondary storage
|
||||||
File claimFile = new File(claimDataFolderPath + File.separator + claimID);
|
this.deleteClaimFromSecondaryStorage(claim);
|
||||||
if(claimFile.exists() && !claimFile.delete())
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("Error: Unable to delete claim file \"" + claimFile.getAbsolutePath() + "\".");
|
|
||||||
}
|
|
||||||
|
|
||||||
//update player data, except for administrative claims, which have no owner
|
//update player data, except for administrative claims, which have no owner
|
||||||
if(!claim.isAdminClaim())
|
if(!claim.isAdminClaim())
|
||||||
|
|
@ -847,6 +385,8 @@ public class DataStore
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract void deleteClaimFromSecondaryStorage(Claim claim);
|
||||||
|
|
||||||
//gets the claim at a specific location
|
//gets the claim at a specific location
|
||||||
//ignoreHeight = TRUE means that a location UNDER an existing claim will return the claim
|
//ignoreHeight = TRUE means that a location UNDER an existing claim will return the claim
|
||||||
//cachedClaim can be NULL, but will help performance if you have a reasonable guess about which claim the location is in
|
//cachedClaim can be NULL, but will help performance if you have a reasonable guess about which claim the location is in
|
||||||
|
|
@ -990,62 +530,8 @@ public class DataStore
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
|
//saves changes to player data to secondary storage. MUST be called after you're done making changes, otherwise a reload will lose them
|
||||||
public void savePlayerData(String playerName, PlayerData playerData)
|
public abstract void savePlayerData(String playerName, PlayerData playerData);
|
||||||
{
|
|
||||||
//never save data for the "administrative" account. an empty string for claim owner indicates an administrative claim
|
|
||||||
if(playerName.length() == 0) return;
|
|
||||||
|
|
||||||
BufferedWriter outStream = null;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//open the player's file
|
|
||||||
File playerDataFile = new File(playerDataFolderPath + File.separator + playerName);
|
|
||||||
playerDataFile.createNewFile();
|
|
||||||
outStream = new BufferedWriter(new FileWriter(playerDataFile));
|
|
||||||
|
|
||||||
//first line is last login timestamp
|
|
||||||
if(playerData.lastLogin == null)playerData.lastLogin = new Date();
|
|
||||||
DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
|
|
||||||
outStream.write(dateFormat.format(playerData.lastLogin));
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//second line is accrued claim blocks
|
|
||||||
outStream.write(String.valueOf(playerData.accruedClaimBlocks));
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//third line is bonus claim blocks
|
|
||||||
outStream.write(String.valueOf(playerData.bonusClaimBlocks));
|
|
||||||
outStream.newLine();
|
|
||||||
|
|
||||||
//fourth line is a double-semicolon-delimited list of claims
|
|
||||||
if(playerData.claims.size() > 0)
|
|
||||||
{
|
|
||||||
outStream.write(this.locationToString(playerData.claims.get(0).getLesserBoundaryCorner()));
|
|
||||||
for(int i = 1; i < playerData.claims.size(); i++)
|
|
||||||
{
|
|
||||||
outStream.write(";;" + this.locationToString(playerData.claims.get(i).getLesserBoundaryCorner()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outStream.newLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
//if any problem, log it
|
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
GriefPrevention.AddLogEntry("PopulationDensity: Unexpected exception saving data for player \"" + playerName + "\": " + e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
//close the file
|
|
||||||
if(outStream != null)
|
|
||||||
{
|
|
||||||
outStream.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(IOException exception){}
|
|
||||||
}
|
|
||||||
|
|
||||||
//extends a claim to a new depth
|
//extends a claim to a new depth
|
||||||
//respects the max depth config variable
|
//respects the max depth config variable
|
||||||
|
|
@ -1500,6 +986,7 @@ public class DataStore
|
||||||
this.addDefault(defaults, Messages.InvalidPermissionID, "Please specify a player name, or a permission in [brackets].", null);
|
this.addDefault(defaults, Messages.InvalidPermissionID, "Please specify a player name, or a permission in [brackets].", null);
|
||||||
this.addDefault(defaults, Messages.UntrustOwnerOnly, "Only {0} can revoke permissions here.", "0: claim owner's name");
|
this.addDefault(defaults, Messages.UntrustOwnerOnly, "Only {0} can revoke permissions here.", "0: claim owner's name");
|
||||||
this.addDefault(defaults, Messages.HowToClaimRegex, "(^|.*\\W)how\\W.*\\W(claim|protect)(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land.");
|
this.addDefault(defaults, Messages.HowToClaimRegex, "(^|.*\\W)how\\W.*\\W(claim|protect)(\\W.*|$)", "This is a Java Regular Expression. Look it up before editing! It's used to tell players about the demo video when they ask how to claim land.");
|
||||||
|
this.addDefault(defaults, Messages.NoBuildOutsideClaims, "You can't build here unless you claim some land first.", null);
|
||||||
|
|
||||||
//load the config file
|
//load the config file
|
||||||
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));
|
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,9 @@ class DeliverClaimBlocksTask implements Runnable
|
||||||
playerData.accruedClaimBlocks = GriefPrevention.instance.config_claims_maxAccruedBlocks;
|
playerData.accruedClaimBlocks = GriefPrevention.instance.config_claims_maxAccruedBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
dataStore.savePlayerData(player.getName(), playerData);
|
//intentionally NOT saving data here to reduce overall secondary storage access frequency
|
||||||
|
//many other operations will cause this players data to save, including his eventual logout
|
||||||
|
//dataStore.savePlayerData(player.getName(), playerData);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception e) { }
|
catch(Exception e) { }
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@
|
||||||
|
|
||||||
package me.ryanhamshire.GriefPrevention;
|
package me.ryanhamshire.GriefPrevention;
|
||||||
|
|
||||||
import org.bukkit.Material;
|
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
//tells a player about how many claim blocks he has, etc
|
//tells a player about how many claim blocks he has, etc
|
||||||
|
|
@ -41,7 +40,7 @@ class EquipShovelProcessingTask implements Runnable
|
||||||
if(!player.isOnline()) return;
|
if(!player.isOnline()) return;
|
||||||
|
|
||||||
//if he's not holding the golden shovel anymore, do nothing
|
//if he's not holding the golden shovel anymore, do nothing
|
||||||
if(player.getItemInHand().getType() != Material.GOLD_SPADE) return;
|
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.getName());
|
||||||
|
|
||||||
|
|
|
||||||
574
src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java
Normal file
574
src/me/ryanhamshire/GriefPrevention/FlatFileDataStore.java
Normal file
|
|
@ -0,0 +1,574 @@
|
||||||
|
/*
|
||||||
|
GriefPrevention Server Plugin for Minecraft
|
||||||
|
Copyright (C) 2012 Ryan Hamshire
|
||||||
|
|
||||||
|
This program is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package me.ryanhamshire.GriefPrevention;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.text.DateFormat;
|
||||||
|
import java.text.ParseException;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import org.bukkit.*;
|
||||||
|
|
||||||
|
//manages data stored in the file system
|
||||||
|
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";
|
||||||
|
|
||||||
|
static boolean hasData()
|
||||||
|
{
|
||||||
|
File playerDataFolder = new File(playerDataFolderPath);
|
||||||
|
File claimsDataFolder = new File(claimDataFolderPath);
|
||||||
|
|
||||||
|
return playerDataFolder.exists() || claimsDataFolder.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
//initialization!
|
||||||
|
FlatFileDataStore()
|
||||||
|
{
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void initialize()
|
||||||
|
{
|
||||||
|
//ensure data folders exist
|
||||||
|
new File(playerDataFolderPath).mkdirs();
|
||||||
|
new File(claimDataFolderPath).mkdirs();
|
||||||
|
|
||||||
|
//load group data into memory
|
||||||
|
File playerDataFolder = new File(playerDataFolderPath);
|
||||||
|
File [] files = playerDataFolder.listFiles();
|
||||||
|
for(int i = 0; i < files.length; i++)
|
||||||
|
{
|
||||||
|
File file = files[i];
|
||||||
|
if(!file.isFile()) continue; //avoids folders
|
||||||
|
|
||||||
|
//all group data files start with a dollar sign. ignoring the rest, which are player data files.
|
||||||
|
if(!file.getName().startsWith("$")) continue;
|
||||||
|
|
||||||
|
String groupName = file.getName().substring(1);
|
||||||
|
if(groupName == null || groupName.isEmpty()) continue; //defensive coding, avoid unlikely cases
|
||||||
|
|
||||||
|
BufferedReader inStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
inStream = new BufferedReader(new FileReader(file.getAbsolutePath()));
|
||||||
|
String line = inStream.readLine();
|
||||||
|
|
||||||
|
int groupBonusBlocks = Integer.parseInt(line);
|
||||||
|
|
||||||
|
this.permissionToBonusBlocksMap.put(groupName, groupBonusBlocks);
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Unable to load group bonus block data from file \"" + file.getName() + "\": " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(inStream != null) inStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//load next claim number from file
|
||||||
|
File nextClaimIdFile = new File(nextClaimIdFilePath);
|
||||||
|
if(nextClaimIdFile.exists())
|
||||||
|
{
|
||||||
|
BufferedReader inStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
inStream = new BufferedReader(new FileReader(nextClaimIdFile.getAbsolutePath()));
|
||||||
|
|
||||||
|
//read the id
|
||||||
|
String line = inStream.readLine();
|
||||||
|
|
||||||
|
//try to parse into a long value
|
||||||
|
this.nextClaimID = Long.parseLong(line);
|
||||||
|
}
|
||||||
|
catch(Exception e){ }
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(inStream != null) inStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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.
|
||||||
|
if(files[i].getName().startsWith("_")) continue;
|
||||||
|
|
||||||
|
//the filename is the claim ID. try to parse it
|
||||||
|
long claimID;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
claimID = Long.parseLong(files[i].getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
//because some older versions used a different file name pattern before claim IDs were introduced,
|
||||||
|
//those files need to be "converted" by renaming them to a unique ID
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
claimID = this.nextClaimID;
|
||||||
|
this.incrementNextClaimID();
|
||||||
|
File newFile = new File(claimDataFolderPath + File.separator + String.valueOf(this.nextClaimID));
|
||||||
|
files[i].renameTo(newFile);
|
||||||
|
files[i] = newFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
BufferedReader inStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Claim topLevelClaim = null;
|
||||||
|
|
||||||
|
inStream = new BufferedReader(new FileReader(files[i].getAbsolutePath()));
|
||||||
|
String line = inStream.readLine();
|
||||||
|
|
||||||
|
while(line != null)
|
||||||
|
{
|
||||||
|
//first line is lesser boundary corner location
|
||||||
|
Location lesserBoundaryCorner = this.locationFromString(line);
|
||||||
|
|
||||||
|
//second line is greater boundary corner location
|
||||||
|
line = inStream.readLine();
|
||||||
|
Location greaterBoundaryCorner = this.locationFromString(line);
|
||||||
|
|
||||||
|
//third line is owner name
|
||||||
|
line = inStream.readLine();
|
||||||
|
String ownerName = line;
|
||||||
|
|
||||||
|
//fourth line is list of builders
|
||||||
|
line = inStream.readLine();
|
||||||
|
String [] builderNames = line.split(";");
|
||||||
|
|
||||||
|
//fifth line is list of players who can access containers
|
||||||
|
line = inStream.readLine();
|
||||||
|
String [] containerNames = line.split(";");
|
||||||
|
|
||||||
|
//sixth line is list of players who can use buttons and switches
|
||||||
|
line = inStream.readLine();
|
||||||
|
String [] accessorNames = line.split(";");
|
||||||
|
|
||||||
|
//seventh line is list of players who can grant permissions
|
||||||
|
line = inStream.readLine();
|
||||||
|
if(line == null) line = "";
|
||||||
|
String [] managerNames = line.split(";");
|
||||||
|
|
||||||
|
//skip any remaining extra lines, until the "===" string, indicating the end of this claim or subdivision
|
||||||
|
line = inStream.readLine();
|
||||||
|
while(line != null && !line.contains("=========="))
|
||||||
|
line = inStream.readLine();
|
||||||
|
|
||||||
|
//build a claim instance from those data
|
||||||
|
//if this is the first claim loaded from this file, it's the top level claim
|
||||||
|
if(topLevelClaim == null)
|
||||||
|
{
|
||||||
|
//instantiate
|
||||||
|
topLevelClaim = new Claim(lesserBoundaryCorner, greaterBoundaryCorner, ownerName, builderNames, containerNames, accessorNames, managerNames, claimID);
|
||||||
|
|
||||||
|
//search for another claim overlapping this one
|
||||||
|
Claim conflictClaim = this.getClaimAt(topLevelClaim.lesserBoundaryCorner, true, null);
|
||||||
|
|
||||||
|
//if there is such a claim, delete this file and move on to the next
|
||||||
|
if(conflictClaim != null)
|
||||||
|
{
|
||||||
|
inStream.close();
|
||||||
|
files[i].delete();
|
||||||
|
line = null;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise, add this claim to the claims collection
|
||||||
|
else
|
||||||
|
{
|
||||||
|
topLevelClaim.modifiedDate = new Date(files[i].lastModified());
|
||||||
|
int j = 0;
|
||||||
|
while(j < this.claims.size() && !this.claims.get(j).greaterThan(topLevelClaim)) j++;
|
||||||
|
if(j < this.claims.size())
|
||||||
|
this.claims.add(j, topLevelClaim);
|
||||||
|
else
|
||||||
|
this.claims.add(this.claims.size(), topLevelClaim);
|
||||||
|
topLevelClaim.inDataStore = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//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);
|
||||||
|
|
||||||
|
//make sure there are no other subdivisions overlapping this one
|
||||||
|
|
||||||
|
subdivision.modifiedDate = new Date(files[i].lastModified());
|
||||||
|
subdivision.parent = topLevelClaim;
|
||||||
|
topLevelClaim.children.add(subdivision);
|
||||||
|
subdivision.inDataStore = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//move up to the first line in the next subdivision
|
||||||
|
line = inStream.readLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//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());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(inStream != null) inStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void writeClaimToStorage(Claim claim)
|
||||||
|
{
|
||||||
|
String claimID = String.valueOf(claim.id);
|
||||||
|
|
||||||
|
BufferedWriter outStream = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//open the claim's file
|
||||||
|
File claimFile = new File(claimDataFolderPath + File.separator + claimID);
|
||||||
|
claimFile.createNewFile();
|
||||||
|
outStream = new BufferedWriter(new FileWriter(claimFile));
|
||||||
|
|
||||||
|
//write top level claim data to the file
|
||||||
|
this.writeClaimData(claim, outStream);
|
||||||
|
|
||||||
|
//for each subdivision
|
||||||
|
for(int i = 0; i < claim.children.size(); i++)
|
||||||
|
{
|
||||||
|
//write the subdivision's data to the file
|
||||||
|
this.writeClaimData(claim.children.get(i), outStream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//if any problem, log it
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Unexpected exception saving data for claim \"" + claimID + "\": " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
//close the file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(outStream != null) outStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//actually writes claim data to an output stream
|
||||||
|
private void writeClaimData(Claim claim, BufferedWriter outStream) throws IOException
|
||||||
|
{
|
||||||
|
//first line is lesser boundary corner location
|
||||||
|
outStream.write(this.locationToString(claim.getLesserBoundaryCorner()));
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//second line is greater boundary corner location
|
||||||
|
outStream.write(this.locationToString(claim.getGreaterBoundaryCorner()));
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//third line is owner name
|
||||||
|
outStream.write(claim.ownerName);
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
ArrayList<String> builders = new ArrayList<String>();
|
||||||
|
ArrayList<String> containers = new ArrayList<String>();
|
||||||
|
ArrayList<String> accessors = new ArrayList<String>();
|
||||||
|
ArrayList<String> managers = new ArrayList<String>();
|
||||||
|
|
||||||
|
claim.getPermissions(builders, containers, accessors, managers);
|
||||||
|
|
||||||
|
//fourth line is list of players with build permission
|
||||||
|
for(int i = 0; i < builders.size(); i++)
|
||||||
|
{
|
||||||
|
outStream.write(builders.get(i) + ";");
|
||||||
|
}
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//fifth line is list of players with container permission
|
||||||
|
for(int i = 0; i < containers.size(); i++)
|
||||||
|
{
|
||||||
|
outStream.write(containers.get(i) + ";");
|
||||||
|
}
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//sixth line is list of players with access permission
|
||||||
|
for(int i = 0; i < accessors.size(); i++)
|
||||||
|
{
|
||||||
|
outStream.write(accessors.get(i) + ";");
|
||||||
|
}
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//seventh line is list of players who may grant permissions for others
|
||||||
|
for(int i = 0; i < managers.size(); i++)
|
||||||
|
{
|
||||||
|
outStream.write(managers.get(i) + ";");
|
||||||
|
}
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//cap each claim with "=========="
|
||||||
|
outStream.write("==========");
|
||||||
|
outStream.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
//deletes a top level claim from the file system
|
||||||
|
@Override
|
||||||
|
void deleteClaimFromSecondaryStorage(Claim claim)
|
||||||
|
{
|
||||||
|
String claimID = String.valueOf(claim.id);
|
||||||
|
|
||||||
|
//remove from disk
|
||||||
|
File claimFile = new File(claimDataFolderPath + File.separator + claimID);
|
||||||
|
if(claimFile.exists() && !claimFile.delete())
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Error: Unable to delete claim file \"" + claimFile.getAbsolutePath() + "\".");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
PlayerData getPlayerDataFromStorage(String playerName)
|
||||||
|
{
|
||||||
|
File playerFile = new File(playerDataFolderPath + File.separator + playerName);
|
||||||
|
|
||||||
|
PlayerData playerData = new PlayerData();
|
||||||
|
playerData.playerName = playerName;
|
||||||
|
|
||||||
|
//if it doesn't exist as a file
|
||||||
|
if(!playerFile.exists())
|
||||||
|
{
|
||||||
|
//create a file with defaults
|
||||||
|
this.savePlayerData(playerName, playerData);
|
||||||
|
}
|
||||||
|
|
||||||
|
//otherwise, read the file
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BufferedReader inStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
inStream = new BufferedReader(new FileReader(playerFile.getAbsolutePath()));
|
||||||
|
|
||||||
|
//first line is last login timestamp
|
||||||
|
String lastLoginTimestampString = inStream.readLine();
|
||||||
|
|
||||||
|
//convert that to a date and store it
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
playerData.lastLogin = dateFormat.parse(lastLoginTimestampString);
|
||||||
|
}
|
||||||
|
catch(ParseException parseException)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Unable to load last login for \"" + playerFile.getName() + "\".");
|
||||||
|
playerData.lastLogin = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//second line is accrued claim blocks
|
||||||
|
String accruedBlocksString = inStream.readLine();
|
||||||
|
|
||||||
|
//convert that to a number and store it
|
||||||
|
playerData.accruedClaimBlocks = Integer.parseInt(accruedBlocksString);
|
||||||
|
|
||||||
|
//third line is any bonus claim blocks granted by administrators
|
||||||
|
String bonusBlocksString = inStream.readLine();
|
||||||
|
|
||||||
|
//convert that to a number and store it
|
||||||
|
playerData.bonusClaimBlocks = Integer.parseInt(bonusBlocksString);
|
||||||
|
|
||||||
|
//fourth line is a double-semicolon-delimited list of claims, which is currently ignored
|
||||||
|
//String claimsString = inStream.readLine();
|
||||||
|
inStream.readLine();
|
||||||
|
|
||||||
|
//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))
|
||||||
|
{
|
||||||
|
playerData.claims.add(claim);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inStream.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
//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());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(inStream != null) inStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
|
||||||
|
@Override
|
||||||
|
public void savePlayerData(String playerName, PlayerData playerData)
|
||||||
|
{
|
||||||
|
//never save data for the "administrative" account. an empty string for claim owner indicates administrative account
|
||||||
|
if(playerName.length() == 0) return;
|
||||||
|
|
||||||
|
BufferedWriter outStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//open the player's file
|
||||||
|
File playerDataFile = new File(playerDataFolderPath + File.separator + playerName);
|
||||||
|
playerDataFile.createNewFile();
|
||||||
|
outStream = new BufferedWriter(new FileWriter(playerDataFile));
|
||||||
|
|
||||||
|
//first line is last login timestamp
|
||||||
|
if(playerData.lastLogin == null)playerData.lastLogin = new Date();
|
||||||
|
DateFormat dateFormat = new SimpleDateFormat("yyyy.MM.dd.HH.mm.ss");
|
||||||
|
outStream.write(dateFormat.format(playerData.lastLogin));
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//second line is accrued claim blocks
|
||||||
|
outStream.write(String.valueOf(playerData.accruedClaimBlocks));
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//third line is bonus claim blocks
|
||||||
|
outStream.write(String.valueOf(playerData.bonusClaimBlocks));
|
||||||
|
outStream.newLine();
|
||||||
|
|
||||||
|
//fourth line is a double-semicolon-delimited list of claims
|
||||||
|
if(playerData.claims.size() > 0)
|
||||||
|
{
|
||||||
|
outStream.write(this.locationToString(playerData.claims.get(0).getLesserBoundaryCorner()));
|
||||||
|
for(int i = 1; i < playerData.claims.size(); i++)
|
||||||
|
{
|
||||||
|
outStream.write(";;" + this.locationToString(playerData.claims.get(i).getLesserBoundaryCorner()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outStream.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
//if any problem, log it
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("GriefPrevention: Unexpected exception saving data for player \"" + playerName + "\": " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//close the file
|
||||||
|
if(outStream != null)
|
||||||
|
{
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(IOException exception){}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void incrementNextClaimID()
|
||||||
|
{
|
||||||
|
//increment in memory
|
||||||
|
this.nextClaimID++;
|
||||||
|
|
||||||
|
BufferedWriter outStream = null;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//open the file and write the new value
|
||||||
|
File nextClaimIdFile = new File(nextClaimIdFilePath);
|
||||||
|
nextClaimIdFile.createNewFile();
|
||||||
|
outStream = new BufferedWriter(new FileWriter(nextClaimIdFile));
|
||||||
|
|
||||||
|
outStream.write(String.valueOf(this.nextClaimID));
|
||||||
|
}
|
||||||
|
|
||||||
|
//if any problem, log it
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Unexpected exception saving next claim ID: " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
//close the file
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(outStream != null) outStream.close();
|
||||||
|
}
|
||||||
|
catch(IOException exception) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
//grants a group (players with a specific permission) bonus claim blocks as long as they're still members of the group
|
||||||
|
@Override
|
||||||
|
void saveGroupBonusBlocks(String groupName, int currentValue)
|
||||||
|
{
|
||||||
|
//write changes to file to ensure they don't get lost
|
||||||
|
BufferedWriter outStream = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//open the group's file
|
||||||
|
File groupDataFile = new File(playerDataFolderPath + File.separator + "$" + groupName);
|
||||||
|
groupDataFile.createNewFile();
|
||||||
|
outStream = new BufferedWriter(new FileWriter(groupDataFile));
|
||||||
|
|
||||||
|
//first line is number of bonus blocks
|
||||||
|
outStream.write(String.valueOf(currentValue));
|
||||||
|
outStream.newLine();
|
||||||
|
}
|
||||||
|
|
||||||
|
//if any problem, log it
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("Unexpected exception saving data for group \"" + groupName + "\": " + e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
//close the file
|
||||||
|
if(outStream != null)
|
||||||
|
{
|
||||||
|
outStream.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(IOException exception){}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -79,9 +79,12 @@ public class GriefPrevention extends JavaPlugin
|
||||||
public int config_claims_claimsExtendIntoGroundDistance; //how far below the shoveled block a new claim will reach
|
public int config_claims_claimsExtendIntoGroundDistance; //how far below the shoveled block a new claim will reach
|
||||||
public int config_claims_minSize; //minimum width and height for non-admin claims
|
public int config_claims_minSize; //minimum width and height for non-admin claims
|
||||||
|
|
||||||
|
public boolean config_claims_noBuildOutsideClaims; //whether players can build in survival worlds outside their claimed areas
|
||||||
|
|
||||||
public int config_claims_trappedCooldownHours; //number of hours between uses of the /trapped command
|
public int config_claims_trappedCooldownHours; //number of hours between uses of the /trapped command
|
||||||
|
|
||||||
public Material config_claims_investigationTool; //which material will be used to investigate claims with a right click
|
public Material config_claims_investigationTool; //which material will be used to investigate claims with a right click
|
||||||
|
public Material config_claims_modificationTool; //which material will be used to create/resize claims with a right click
|
||||||
|
|
||||||
public ArrayList<World> config_siege_enabledWorlds; //whether or not /siege is enabled on this server
|
public ArrayList<World> config_siege_enabledWorlds; //whether or not /siege is enabled on this server
|
||||||
public ArrayList<Material> config_siege_blocks; //which blocks will be breakable in siege mode
|
public ArrayList<Material> config_siege_blocks; //which blocks will be breakable in siege mode
|
||||||
|
|
@ -227,6 +230,7 @@ public class GriefPrevention extends JavaPlugin
|
||||||
this.config_claims_maxDepth = config.getInt("GriefPrevention.Claims.MaximumDepth", 0);
|
this.config_claims_maxDepth = config.getInt("GriefPrevention.Claims.MaximumDepth", 0);
|
||||||
this.config_claims_expirationDays = config.getInt("GriefPrevention.Claims.IdleLimitDays", 0);
|
this.config_claims_expirationDays = config.getInt("GriefPrevention.Claims.IdleLimitDays", 0);
|
||||||
this.config_claims_trappedCooldownHours = config.getInt("GriefPrevention.Claims.TrappedCommandCooldownHours", 8);
|
this.config_claims_trappedCooldownHours = config.getInt("GriefPrevention.Claims.TrappedCommandCooldownHours", 8);
|
||||||
|
this.config_claims_noBuildOutsideClaims = config.getBoolean("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", false);
|
||||||
|
|
||||||
this.config_spam_enabled = config.getBoolean("GriefPrevention.Spam.Enabled", true);
|
this.config_spam_enabled = config.getBoolean("GriefPrevention.Spam.Enabled", true);
|
||||||
this.config_spam_loginCooldownMinutes = config.getInt("GriefPrevention.Spam.LoginCooldownMinutes", 2);
|
this.config_spam_loginCooldownMinutes = config.getInt("GriefPrevention.Spam.LoginCooldownMinutes", 2);
|
||||||
|
|
@ -276,6 +280,20 @@ public class GriefPrevention extends JavaPlugin
|
||||||
this.config_claims_investigationTool = Material.STICK;
|
this.config_claims_investigationTool = Material.STICK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//default for claim creation/modification tool
|
||||||
|
String modificationToolMaterialName = Material.GOLD_SPADE.name();
|
||||||
|
|
||||||
|
//get modification tool from config
|
||||||
|
modificationToolMaterialName = config.getString("GriefPrevention.Claims.ModificationTool", modificationToolMaterialName);
|
||||||
|
|
||||||
|
//validate modification tool
|
||||||
|
this.config_claims_modificationTool = Material.getMaterial(modificationToolMaterialName);
|
||||||
|
if(this.config_claims_modificationTool == null)
|
||||||
|
{
|
||||||
|
GriefPrevention.AddLogEntry("ERROR: Material " + modificationToolMaterialName + " not found. Defaulting to the golden shovel. Please update your config.yml.");
|
||||||
|
this.config_claims_modificationTool = Material.GOLD_SPADE;
|
||||||
|
}
|
||||||
|
|
||||||
//default for siege worlds list
|
//default for siege worlds list
|
||||||
ArrayList<String> defaultSiegeWorldNames = new ArrayList<String>();
|
ArrayList<String> defaultSiegeWorldNames = new ArrayList<String>();
|
||||||
|
|
||||||
|
|
@ -365,6 +383,8 @@ public class GriefPrevention extends JavaPlugin
|
||||||
config.set("GriefPrevention.Claims.IdleLimitDays", this.config_claims_expirationDays);
|
config.set("GriefPrevention.Claims.IdleLimitDays", this.config_claims_expirationDays);
|
||||||
config.set("GriefPrevention.Claims.TrappedCommandCooldownHours", this.config_claims_trappedCooldownHours);
|
config.set("GriefPrevention.Claims.TrappedCommandCooldownHours", this.config_claims_trappedCooldownHours);
|
||||||
config.set("GriefPrevention.Claims.InvestigationTool", this.config_claims_investigationTool.name());
|
config.set("GriefPrevention.Claims.InvestigationTool", this.config_claims_investigationTool.name());
|
||||||
|
config.set("GriefPrevention.Claims.ModificationTool", this.config_claims_modificationTool.name());
|
||||||
|
config.set("GriefPrevention.Claims.NoSurvivalBuildingOutsideClaims", this.config_claims_noBuildOutsideClaims);
|
||||||
|
|
||||||
config.set("GriefPrevention.Spam.Enabled", this.config_spam_enabled);
|
config.set("GriefPrevention.Spam.Enabled", this.config_spam_enabled);
|
||||||
config.set("GriefPrevention.Spam.LoginCooldownMinutes", this.config_spam_loginCooldownMinutes);
|
config.set("GriefPrevention.Spam.LoginCooldownMinutes", this.config_spam_loginCooldownMinutes);
|
||||||
|
|
@ -421,7 +441,7 @@ public class GriefPrevention extends JavaPlugin
|
||||||
}
|
}
|
||||||
|
|
||||||
//when datastore initializes, it loads player and claim data, and posts some stats to the log
|
//when datastore initializes, it loads player and claim data, and posts some stats to the log
|
||||||
this.dataStore = new DataStore();
|
this.dataStore = new FlatFileDataStore();
|
||||||
|
|
||||||
//unless claim block accrual is disabled, start the recurring per 5 minute event to give claim blocks to online players
|
//unless claim block accrual is disabled, start the recurring per 5 minute event to give claim blocks to online players
|
||||||
//20L ~ 1 second
|
//20L ~ 1 second
|
||||||
|
|
@ -1685,6 +1705,16 @@ public class GriefPrevention extends JavaPlugin
|
||||||
|
|
||||||
public void onDisable()
|
public void onDisable()
|
||||||
{
|
{
|
||||||
|
//save data for any online players
|
||||||
|
Player [] players = this.getServer().getOnlinePlayers();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
AddLogEntry("GriefPrevention disabled.");
|
AddLogEntry("GriefPrevention disabled.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2001,17 +2031,25 @@ public class GriefPrevention extends JavaPlugin
|
||||||
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
||||||
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
|
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
|
||||||
|
|
||||||
|
//exception: administrators in ignore claims mode
|
||||||
|
if(playerData.ignoreClaims) return null;
|
||||||
|
|
||||||
//wilderness rules
|
//wilderness rules
|
||||||
if(claim == null)
|
if(claim == null)
|
||||||
{
|
{
|
||||||
//no building in the wilderness in creative mode
|
//no building in the wilderness in creative mode
|
||||||
if(this.creativeRulesApply(location))
|
if(this.creativeRulesApply(location))
|
||||||
{
|
{
|
||||||
//exception: administrators in ignore claims mode
|
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement);
|
||||||
if(playerData.ignoreClaims) return null;
|
|
||||||
|
|
||||||
return "You can't build here. Use the golden shovel to claim some land first.";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//no building in survival wilderness when that is configured
|
||||||
|
else if(this.config_claims_noBuildOutsideClaims && this.config_claims_enabledWorlds.contains(location.getWorld()))
|
||||||
|
{
|
||||||
|
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.SurvivalBasicsDemoAdvertisement);
|
||||||
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//but it's fine in survival mode
|
//but it's fine in survival mode
|
||||||
|
|
@ -2033,16 +2071,21 @@ public class GriefPrevention extends JavaPlugin
|
||||||
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
||||||
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
|
Claim claim = this.dataStore.getClaimAt(location, false, playerData.lastClaim);
|
||||||
|
|
||||||
|
//exception: administrators in ignore claims mode
|
||||||
|
if(playerData.ignoreClaims) return null;
|
||||||
|
|
||||||
//wilderness rules
|
//wilderness rules
|
||||||
if(claim == null)
|
if(claim == null)
|
||||||
{
|
{
|
||||||
//no building in the wilderness in creative mode
|
//no building in the wilderness in creative mode
|
||||||
if(this.creativeRulesApply(location))
|
if(this.creativeRulesApply(location))
|
||||||
{
|
{
|
||||||
//exception: administrators in ignore claims mode
|
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.CreativeBasicsDemoAdvertisement);
|
||||||
if(playerData.ignoreClaims) return null;
|
}
|
||||||
|
|
||||||
return "You can only build where you have claimed land. To claim, watch this: http://tinyurl.com/c7bajb8";
|
else if(this.config_claims_noBuildOutsideClaims && this.config_claims_enabledWorlds.contains(location.getWorld()))
|
||||||
|
{
|
||||||
|
return this.dataStore.getMessage(Messages.NoBuildOutsideClaims) + " " + this.dataStore.getMessage(Messages.SurvivalBasicsDemoAdvertisement);
|
||||||
}
|
}
|
||||||
|
|
||||||
//but it's fine in survival mode
|
//but it's fine in survival mode
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@ package me.ryanhamshire.GriefPrevention;
|
||||||
|
|
||||||
public enum Messages
|
public enum Messages
|
||||||
{
|
{
|
||||||
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex
|
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,8 +137,8 @@ class PlayerEventHandler implements Listener
|
||||||
spam = true;
|
spam = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's very similar to the last message and less than 10 seconds have passed
|
//if it's very similar to the last message and less than 15 seconds have passed
|
||||||
if(!muted && this.stringsAreSimilar(message, playerData.lastMessage) && millisecondsSinceLastMessage < 10000)
|
if(!muted && this.stringsAreSimilar(message, playerData.lastMessage) && millisecondsSinceLastMessage < 15000)
|
||||||
{
|
{
|
||||||
playerData.spamCount++;
|
playerData.spamCount++;
|
||||||
spam = true;
|
spam = true;
|
||||||
|
|
@ -197,10 +197,18 @@ class PlayerEventHandler implements Listener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//very short messages close together are spam
|
||||||
|
if(!muted && message.length() < 5 && millisecondsSinceLastMessage < 5000)
|
||||||
|
{
|
||||||
|
spam = true;
|
||||||
|
if(playerData.spamCount > 4) muted = true;
|
||||||
|
playerData.spamCount++;
|
||||||
|
}
|
||||||
|
|
||||||
//if the message was determined to be a spam, consider taking action
|
//if the message was determined to be a spam, consider taking action
|
||||||
if(!player.hasPermission("griefprevention.spam") && spam)
|
if(!player.hasPermission("griefprevention.spam") && spam)
|
||||||
{
|
{
|
||||||
//anything above level 4 for a player which has received a warning... kick or if enabled, ban
|
//anything above level 8 for a player which has received a warning... kick or if enabled, ban
|
||||||
if(playerData.spamCount > 8 && playerData.spamWarned)
|
if(playerData.spamCount > 8 && playerData.spamWarned)
|
||||||
{
|
{
|
||||||
if(GriefPrevention.instance.config_spam_banOffenders)
|
if(GriefPrevention.instance.config_spam_banOffenders)
|
||||||
|
|
@ -463,8 +471,11 @@ class PlayerEventHandler implements Listener
|
||||||
playerData.lastLogin = new Date();
|
playerData.lastLogin = new Date();
|
||||||
this.dataStore.savePlayerData(playerName, playerData);
|
this.dataStore.savePlayerData(playerName, playerData);
|
||||||
|
|
||||||
//check inventory, may need pvp protection
|
//if player has never played on the server before, may need pvp protection
|
||||||
GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer());
|
if(!event.getPlayer().hasPlayedBefore())
|
||||||
|
{
|
||||||
|
GriefPrevention.instance.checkPvpProtectionNeeded(event.getPlayer());
|
||||||
|
}
|
||||||
|
|
||||||
//silence notifications when they're coming too fast
|
//silence notifications when they're coming too fast
|
||||||
if(event.getJoinMessage() != null && this.shouldSilenceNotification())
|
if(event.getJoinMessage() != null && this.shouldSilenceNotification())
|
||||||
|
|
@ -493,6 +504,9 @@ class PlayerEventHandler implements Listener
|
||||||
event.setQuitMessage(null);
|
event.setQuitMessage(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//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.onPlayerDisconnect(event.getPlayer(), event.getQuitMessage());
|
this.onPlayerDisconnect(event.getPlayer(), event.getQuitMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -717,7 +731,7 @@ class PlayerEventHandler implements Listener
|
||||||
|
|
||||||
//if he's switching to the golden shovel
|
//if he's switching to the golden shovel
|
||||||
ItemStack newItemStack = player.getInventory().getItem(event.getNewSlot());
|
ItemStack newItemStack = player.getInventory().getItem(event.getNewSlot());
|
||||||
if(newItemStack != null && newItemStack.getType() == Material.GOLD_SPADE)
|
if(newItemStack != null && newItemStack.getType() == GriefPrevention.instance.config_claims_modificationTool)
|
||||||
{
|
{
|
||||||
EquipShovelProcessingTask task = new EquipShovelProcessingTask(player);
|
EquipShovelProcessingTask task = new EquipShovelProcessingTask(player);
|
||||||
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 15L); //15L is approx. 3/4 of a second
|
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 15L); //15L is approx. 3/4 of a second
|
||||||
|
|
@ -1037,7 +1051,7 @@ class PlayerEventHandler implements Listener
|
||||||
GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockClaimed, claim.getOwnerName());
|
GriefPrevention.sendMessage(player, TextMode.Info, Messages.BlockClaimed, claim.getOwnerName());
|
||||||
|
|
||||||
//visualize boundary
|
//visualize boundary
|
||||||
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1045,7 +1059,7 @@ class PlayerEventHandler implements Listener
|
||||||
}
|
}
|
||||||
|
|
||||||
//if it's a golden shovel
|
//if it's a golden shovel
|
||||||
else if(materialInHand != Material.GOLD_SPADE) return;
|
else if(materialInHand != GriefPrevention.instance.config_claims_modificationTool) return;
|
||||||
|
|
||||||
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
|
||||||
|
|
||||||
|
|
@ -1074,7 +1088,7 @@ class PlayerEventHandler implements Listener
|
||||||
if(claim != null)
|
if(claim != null)
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.BlockClaimed, claim.getOwnerName());
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.BlockClaimed, claim.getOwnerName());
|
||||||
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
|
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -1359,7 +1373,7 @@ class PlayerEventHandler implements Listener
|
||||||
{
|
{
|
||||||
//inform and show the player
|
//inform and show the player
|
||||||
GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClaimResizeSuccess, String.valueOf(playerData.getRemainingClaimBlocks()));
|
GriefPrevention.sendMessage(player, TextMode.Success, Messages.ClaimResizeSuccess, String.valueOf(playerData.getRemainingClaimBlocks()));
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
|
|
||||||
//if resizing someone else's claim, make a log entry
|
//if resizing someone else's claim, make a log entry
|
||||||
|
|
@ -1378,7 +1392,7 @@ class PlayerEventHandler implements Listener
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlap);
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ResizeFailOverlap);
|
||||||
|
|
||||||
//show the player the conflicting claim
|
//show the player the conflicting claim
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1450,7 +1464,7 @@ class PlayerEventHandler implements Listener
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateSubdivisionOverlap);
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateSubdivisionOverlap);
|
||||||
|
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -1460,7 +1474,7 @@ class PlayerEventHandler implements Listener
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Success, Messages.SubdivisionSuccess);
|
GriefPrevention.sendMessage(player, TextMode.Success, Messages.SubdivisionSuccess);
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
playerData.lastShovelLocation = null;
|
playerData.lastShovelLocation = null;
|
||||||
playerData.claimSubdividing = null;
|
playerData.claimSubdividing = null;
|
||||||
|
|
@ -1473,7 +1487,7 @@ class PlayerEventHandler implements Listener
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlap);
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlap);
|
||||||
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1482,7 +1496,7 @@ class PlayerEventHandler implements Listener
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapOtherPlayer, claim.getOwnerName());
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapOtherPlayer, claim.getOwnerName());
|
||||||
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
|
Visualization visualization = Visualization.FromClaim(claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1559,7 +1573,7 @@ class PlayerEventHandler implements Listener
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapShort);
|
GriefPrevention.sendMessage(player, TextMode.Err, Messages.CreateClaimFailOverlapShort);
|
||||||
|
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.ErrorClaim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
|
@ -1569,7 +1583,7 @@ class PlayerEventHandler implements Listener
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
GriefPrevention.sendMessage(player, TextMode.Success, Messages.CreateClaimSuccess);
|
GriefPrevention.sendMessage(player, TextMode.Success, Messages.CreateClaimSuccess);
|
||||||
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim);
|
Visualization visualization = Visualization.FromClaim(result.claim, clickedBlock.getY(), VisualizationType.Claim, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
playerData.lastShovelLocation = null;
|
playerData.lastShovelLocation = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -91,7 +91,7 @@ class RestoreNatureExecutionTask implements Runnable
|
||||||
|
|
||||||
//show visualization to player
|
//show visualization to player
|
||||||
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
|
Claim claim = new Claim(lesserCorner, greaterCorner, "", new String[] {}, new String[] {}, new String[] {}, new String[] {}, null);
|
||||||
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature);
|
Visualization visualization = Visualization.FromClaim(claim, player.getLocation().getBlockY(), VisualizationType.RestoreNature, player.getLocation());
|
||||||
Visualization.Apply(player, visualization);
|
Visualization.Apply(player, visualization);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -77,12 +77,12 @@ public class Visualization
|
||||||
|
|
||||||
//convenience method to build a visualization from a claim
|
//convenience method to build a visualization from a claim
|
||||||
//visualizationType determines the style (gold blocks, silver, red, diamond, etc)
|
//visualizationType determines the style (gold blocks, silver, red, diamond, etc)
|
||||||
public static Visualization FromClaim(Claim claim, int height, VisualizationType visualizationType)
|
public static Visualization FromClaim(Claim claim, int height, VisualizationType visualizationType, Location locality)
|
||||||
{
|
{
|
||||||
//visualize only top level claims
|
//visualize only top level claims
|
||||||
if(claim.parent != null)
|
if(claim.parent != null)
|
||||||
{
|
{
|
||||||
return FromClaim(claim.parent, height, visualizationType);
|
return FromClaim(claim.parent, height, visualizationType, locality);
|
||||||
}
|
}
|
||||||
|
|
||||||
Visualization visualization = new Visualization();
|
Visualization visualization = new Visualization();
|
||||||
|
|
@ -90,18 +90,19 @@ public class Visualization
|
||||||
//add subdivisions first
|
//add subdivisions first
|
||||||
for(int i = 0; i < claim.children.size(); i++)
|
for(int i = 0; i < claim.children.size(); i++)
|
||||||
{
|
{
|
||||||
visualization.addClaimElements(claim.children.get(i), height, VisualizationType.Subdivision);
|
visualization.addClaimElements(claim.children.get(i), height, VisualizationType.Subdivision, locality);
|
||||||
}
|
}
|
||||||
|
|
||||||
//add top level last so that it takes precedence (it shows on top when the child claim boundaries overlap with its boundaries)
|
//add top level last so that it takes precedence (it shows on top when the child claim boundaries overlap with its boundaries)
|
||||||
visualization.addClaimElements(claim, height, visualizationType);
|
visualization.addClaimElements(claim, height, visualizationType, locality);
|
||||||
|
|
||||||
return visualization;
|
return visualization;
|
||||||
}
|
}
|
||||||
|
|
||||||
//adds a claim's visualization to the current visualization
|
//adds a claim's visualization to the current visualization
|
||||||
//handy for combining several visualizations together, as when visualization a top level claim with several subdivisions inside
|
//handy for combining several visualizations together, as when visualization a top level claim with several subdivisions inside
|
||||||
private void addClaimElements(Claim claim, int height, VisualizationType visualizationType)
|
//locality is a performance consideration. only create visualization blocks for around 100 blocks of the locality
|
||||||
|
private void addClaimElements(Claim claim, int height, VisualizationType visualizationType, Location locality)
|
||||||
{
|
{
|
||||||
Location smallXsmallZ = claim.getLesserBoundaryCorner();
|
Location smallXsmallZ = claim.getLesserBoundaryCorner();
|
||||||
Location bigXbigZ = claim.getGreaterBoundaryCorner();
|
Location bigXbigZ = claim.getGreaterBoundaryCorner();
|
||||||
|
|
@ -159,28 +160,38 @@ public class Visualization
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, bigz), accentMaterial, (byte)0));
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx + 1, height, bigz), accentMaterial, (byte)0));
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 1), accentMaterial, (byte)0));
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, bigz - 1), accentMaterial, (byte)0));
|
||||||
|
|
||||||
|
//locality
|
||||||
|
int minx = locality.getBlockX() - 100;
|
||||||
|
int minz = locality.getBlockZ() - 100;
|
||||||
|
int maxx = locality.getBlockX() + 100;
|
||||||
|
int maxz = locality.getBlockZ() + 100;
|
||||||
|
|
||||||
//top line
|
//top line
|
||||||
for(int x = smallx + 10; x < bigx - 10; x += 10)
|
for(int x = smallx + 10; x < bigx - 10; x += 10)
|
||||||
{
|
{
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, bigz), accentMaterial, (byte)0));
|
if(x > minx && x < maxx)
|
||||||
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, bigz), accentMaterial, (byte)0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//bottom line
|
//bottom line
|
||||||
for(int x = smallx + 10; x < bigx - 10; x += 10)
|
for(int x = smallx + 10; x < bigx - 10; x += 10)
|
||||||
{
|
{
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, smallz), accentMaterial, (byte)0));
|
if(x > minx && x < maxx)
|
||||||
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, x, height, smallz), accentMaterial, (byte)0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//left line
|
//left line
|
||||||
for(int z = smallz + 10; z < bigz - 10; z += 10)
|
for(int z = smallz + 10; z < bigz - 10; z += 10)
|
||||||
{
|
{
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, z), accentMaterial, (byte)0));
|
if(z > minz && z < maxz)
|
||||||
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, smallx, height, z), accentMaterial, (byte)0));
|
||||||
}
|
}
|
||||||
|
|
||||||
//right line
|
//right line
|
||||||
for(int z = smallz + 10; z < bigz - 10; z += 10)
|
for(int z = smallz + 10; z < bigz - 10; z += 10)
|
||||||
{
|
{
|
||||||
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, z), accentMaterial, (byte)0));
|
if(z > minz && z < maxz)
|
||||||
|
this.elements.add(new VisualizationElement(getVisibleLocation(world, bigx, height, z), accentMaterial, (byte)0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user