2013-01-05 16:19:42 +00:00
/ *
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.* ;
2015-09-18 02:14:36 +00:00
import java.nio.charset.Charset ;
2013-01-05 16:19:42 +00:00
import java.util.* ;
2013-01-25 03:45:39 +00:00
import java.util.concurrent.ConcurrentHashMap ;
2014-09-22 20:46:13 +00:00
import java.util.regex.Pattern ;
2013-01-05 16:19:42 +00:00
2015-01-11 23:33:05 +00:00
import me.ryanhamshire.GriefPrevention.events.ClaimDeletedEvent ;
2013-01-05 16:19:42 +00:00
import org.bukkit.* ;
import org.bukkit.configuration.file.FileConfiguration ;
import org.bukkit.configuration.file.YamlConfiguration ;
2016-03-31 03:07:38 +00:00
import org.bukkit.entity.AnimalTamer ;
2015-12-16 22:44:34 +00:00
import org.bukkit.entity.Entity ;
2013-01-05 16:19:42 +00:00
import org.bukkit.entity.Player ;
2015-12-16 22:44:34 +00:00
import org.bukkit.entity.Tameable ;
2016-04-14 03:12:21 +00:00
import org.bukkit.inventory.InventoryHolder ;
2013-01-05 16:19:42 +00:00
import org.bukkit.inventory.ItemStack ;
2015-05-16 20:00:55 +00:00
import com.google.common.io.Files ;
2013-01-05 16:19:42 +00:00
//singleton class which manages all GriefPrevention data (except for config options)
public abstract class DataStore
{
//in-memory cache for player data
2014-09-22 20:46:13 +00:00
protected ConcurrentHashMap < UUID , PlayerData > playerNameToPlayerDataMap = new ConcurrentHashMap < UUID , PlayerData > ( ) ;
2013-01-05 16:19:42 +00:00
//in-memory cache for group (permission-based) data
2013-01-25 03:45:39 +00:00
protected ConcurrentHashMap < String , Integer > permissionToBonusBlocksMap = new ConcurrentHashMap < String , Integer > ( ) ;
2013-01-05 16:19:42 +00:00
//in-memory cache for claim data
ArrayList < Claim > claims = new ArrayList < Claim > ( ) ;
2016-01-28 17:28:48 +00:00
ConcurrentHashMap < Long , ArrayList < Claim > > chunksToClaimsMap = new ConcurrentHashMap < Long , ArrayList < Claim > > ( ) ;
2013-01-05 16:19:42 +00:00
//in-memory cache for messages
private String [ ] messages ;
2014-09-22 20:46:13 +00:00
//pattern for unique user identifiers (UUIDs)
protected final static Pattern uuidpattern = Pattern . compile ( " [0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12} " ) ;
2013-01-05 16:19:42 +00:00
//next claim ID
Long nextClaimID = ( long ) 0 ;
//path information, for where stuff stored on disk is well... stored
protected final static String dataLayerFolderPath = " plugins " + File . separator + " GriefPreventionData " ;
2015-05-16 20:00:55 +00:00
final static String playerDataFolderPath = dataLayerFolderPath + File . separator + " PlayerData " ;
final static String configFilePath = dataLayerFolderPath + File . separator + " config.yml " ;
2013-01-05 16:19:42 +00:00
final static String messagesFilePath = dataLayerFolderPath + File . separator + " messages.yml " ;
2014-11-02 02:18:27 +00:00
final static String softMuteFilePath = dataLayerFolderPath + File . separator + " softMute.txt " ;
2015-09-18 02:14:36 +00:00
final static String bannedWordsFilePath = dataLayerFolderPath + File . separator + " bannedWords.txt " ;
2014-09-22 20:46:13 +00:00
//the latest version of the data schema implemented here
2015-09-12 21:17:00 +00:00
protected static final int latestSchemaVersion = 2 ;
2014-09-22 20:46:13 +00:00
//reading and writing the schema version to the data store
abstract int getSchemaVersionFromStorage ( ) ;
abstract void updateSchemaVersionInStorage ( int versionToSet ) ;
//current version of the schema of data in secondary storage
private int currentSchemaVersion = - 1 ; //-1 means not determined yet
2014-09-23 01:40:52 +00:00
//video links
2015-07-23 02:03:11 +00:00
static final String SURVIVAL_VIDEO_URL = " " + ChatColor . DARK_AQUA + ChatColor . UNDERLINE + " bit.ly/mcgpuser " + ChatColor . RESET ;
static final String CREATIVE_VIDEO_URL = " " + ChatColor . DARK_AQUA + ChatColor . UNDERLINE + " bit.ly/mcgpcrea " + ChatColor . RESET ;
static final String SUBDIVISION_VIDEO_URL = " " + ChatColor . DARK_AQUA + ChatColor . UNDERLINE + " bit.ly/mcgpsub " + ChatColor . RESET ;
2014-09-23 01:40:52 +00:00
2014-11-02 02:18:27 +00:00
//list of UUIDs which are soft-muted
2014-12-30 03:37:12 +00:00
ConcurrentHashMap < UUID , Boolean > softMuteMap = new ConcurrentHashMap < UUID , Boolean > ( ) ;
//world guard reference, if available
2015-01-07 22:53:19 +00:00
private WorldGuardWrapper worldGuard = null ;
2014-11-02 02:18:27 +00:00
2014-09-22 20:46:13 +00:00
protected int getSchemaVersion ( )
{
if ( this . currentSchemaVersion > = 0 )
{
return this . currentSchemaVersion ;
}
else
{
this . currentSchemaVersion = this . getSchemaVersionFromStorage ( ) ;
return this . currentSchemaVersion ;
}
}
protected void setSchemaVersion ( int versionToSet )
{
this . currentSchemaVersion = versionToSet ;
this . updateSchemaVersionInStorage ( versionToSet ) ;
}
2013-01-05 16:19:42 +00:00
//initialization!
void initialize ( ) throws Exception
{
GriefPrevention . AddLogEntry ( this . claims . size ( ) + " total claims loaded. " ) ;
2015-05-16 20:00:55 +00:00
//ensure data folders exist
File playerDataFolder = new File ( playerDataFolderPath ) ;
if ( ! playerDataFolder . exists ( ) )
{
playerDataFolder . mkdirs ( ) ;
}
2013-01-05 16:19:42 +00:00
//load up all the messages from messages.yml
this . loadMessages ( ) ;
2014-09-29 23:12:32 +00:00
GriefPrevention . AddLogEntry ( " Customizable messages loaded. " ) ;
2013-01-05 16:19:42 +00:00
2014-09-22 20:46:13 +00:00
//if converting up from an earlier schema version, write all claims back to storage using the latest format
2014-09-29 23:12:32 +00:00
if ( this . getSchemaVersion ( ) < latestSchemaVersion )
2014-09-22 20:46:13 +00:00
{
GriefPrevention . AddLogEntry ( " Please wait. Updating data format. " ) ;
for ( Claim claim : this . claims )
{
this . saveClaim ( claim ) ;
2015-09-12 21:17:00 +00:00
for ( Claim subClaim : claim . children )
{
this . saveClaim ( subClaim ) ;
}
2014-09-22 20:46:13 +00:00
}
2014-09-29 23:12:32 +00:00
2014-10-09 22:13:19 +00:00
//clean up any UUID conversion work
if ( UUIDFetcher . lookupCache ! = null )
{
UUIDFetcher . lookupCache . clear ( ) ;
2015-01-20 01:57:52 +00:00
UUIDFetcher . correctedNames . clear ( ) ;
2014-10-09 22:13:19 +00:00
}
2014-09-29 23:12:32 +00:00
GriefPrevention . AddLogEntry ( " Update finished. " ) ;
2014-09-22 20:46:13 +00:00
}
2014-11-02 02:18:27 +00:00
//load list of soft mutes
this . loadSoftMutes ( ) ;
//make a note of the data store schema version
2014-09-29 23:12:32 +00:00
this . setSchemaVersion ( latestSchemaVersion ) ;
2014-12-30 03:37:12 +00:00
//try to hook into world guard
2015-01-07 22:53:19 +00:00
try
2014-12-30 03:37:12 +00:00
{
2015-01-07 22:53:19 +00:00
this . worldGuard = new WorldGuardWrapper ( ) ;
2014-12-30 03:37:12 +00:00
GriefPrevention . AddLogEntry ( " Successfully hooked into WorldGuard. " ) ;
}
2015-01-07 22:53:19 +00:00
//if failed, world guard compat features will just be disabled.
catch ( ClassNotFoundException exception ) { }
2015-01-08 04:08:04 +00:00
catch ( NoClassDefFoundError exception ) { }
2013-01-05 16:19:42 +00:00
}
2014-11-02 02:18:27 +00:00
private void loadSoftMutes ( )
{
File softMuteFile = new File ( softMuteFilePath ) ;
if ( softMuteFile . exists ( ) )
{
BufferedReader inStream = null ;
try
{
//open the file
inStream = new BufferedReader ( new FileReader ( softMuteFile . getAbsolutePath ( ) ) ) ;
//while there are lines left
String nextID = inStream . readLine ( ) ;
while ( nextID ! = null )
{
//parse line into a UUID
UUID playerID ;
try
{
playerID = UUID . fromString ( nextID ) ;
}
catch ( Exception e )
{
playerID = null ;
GriefPrevention . AddLogEntry ( " Failed to parse soft mute entry as a UUID: " + nextID ) ;
}
//push it into the map
if ( playerID ! = null )
{
this . softMuteMap . put ( playerID , true ) ;
}
//move to the next
nextID = inStream . readLine ( ) ;
}
}
catch ( Exception e )
{
GriefPrevention . AddLogEntry ( " Failed to read from the soft mute data file: " + e . toString ( ) ) ;
e . printStackTrace ( ) ;
}
try
{
if ( inStream ! = null ) inStream . close ( ) ;
}
catch ( IOException exception ) { }
}
}
2016-04-03 17:19:32 +00:00
public List < String > loadBannedWords ( )
2015-09-18 02:14:36 +00:00
{
try
{
File bannedWordsFile = new File ( bannedWordsFilePath ) ;
if ( ! bannedWordsFile . exists ( ) )
{
Files . touch ( bannedWordsFile ) ;
String defaultWords =
" nigger \ nniggers \ nniger \ nnigga \ nnigers \ nniggas \ n " +
" fag \ nfags \ nfaggot \ nfaggots \ nfeggit \ nfeggits \ nfaggit \ nfaggits \ n " +
" cunt \ ncunts \ nwhore \ nwhores \ nslut \ nsluts \ n " ;
Files . append ( defaultWords , bannedWordsFile , Charset . forName ( " UTF-8 " ) ) ;
}
return Files . readLines ( bannedWordsFile , Charset . forName ( " UTF-8 " ) ) ;
}
catch ( Exception e )
{
GriefPrevention . AddLogEntry ( " Failed to read from the banned words data file: " + e . toString ( ) ) ;
e . printStackTrace ( ) ;
return new ArrayList < String > ( ) ;
}
}
2014-11-02 02:18:27 +00:00
//updates soft mute map and data file
boolean toggleSoftMute ( UUID playerID )
{
boolean newValue = ! this . isSoftMuted ( playerID ) ;
this . softMuteMap . put ( playerID , newValue ) ;
this . saveSoftMutes ( ) ;
return newValue ;
}
2015-07-17 04:03:24 +00:00
public boolean isSoftMuted ( UUID playerID )
2014-11-02 02:18:27 +00:00
{
Boolean mapEntry = this . softMuteMap . get ( playerID ) ;
if ( mapEntry = = null | | mapEntry = = Boolean . FALSE )
{
return false ;
}
return true ;
}
private void saveSoftMutes ( )
{
BufferedWriter outStream = null ;
try
{
//open the file and write the new value
File softMuteFile = new File ( softMuteFilePath ) ;
softMuteFile . createNewFile ( ) ;
outStream = new BufferedWriter ( new FileWriter ( softMuteFile ) ) ;
for ( Map . Entry < UUID , Boolean > entry : softMuteMap . entrySet ( ) )
{
if ( entry . getValue ( ) . booleanValue ( ) )
{
outStream . write ( entry . getKey ( ) . toString ( ) ) ;
outStream . newLine ( ) ;
}
}
}
//if any problem, log it
catch ( Exception e )
{
GriefPrevention . AddLogEntry ( " Unexpected exception saving soft mute data: " + e . getMessage ( ) ) ;
e . printStackTrace ( ) ;
}
//close the file
try
{
if ( outStream ! = null ) outStream . close ( ) ;
}
catch ( IOException exception ) { }
}
//removes cached player data from memory
2014-09-22 20:46:13 +00:00
synchronized void clearCachedPlayerData ( UUID playerID )
2013-01-05 16:19:42 +00:00
{
2014-09-22 20:46:13 +00:00
this . playerNameToPlayerDataMap . remove ( playerID ) ;
2013-01-05 16:19:42 +00:00
}
//gets the number of bonus blocks a player has from his permissions
2014-09-22 20:46:13 +00:00
//Bukkit doesn't allow for checking permissions of an offline player.
//this will return 0 when he's offline, and the correct number when online.
synchronized int getGroupBonusBlocks ( UUID playerID )
2013-01-05 16:19:42 +00:00
{
int bonusBlocks = 0 ;
Set < String > keys = permissionToBonusBlocksMap . keySet ( ) ;
Iterator < String > iterator = keys . iterator ( ) ;
while ( iterator . hasNext ( ) )
{
String groupName = iterator . next ( ) ;
2014-09-22 20:46:13 +00:00
Player player = GriefPrevention . instance . getServer ( ) . getPlayer ( playerID ) ;
2013-01-05 16:19:42 +00:00
if ( player ! = null & & player . hasPermission ( groupName ) )
{
bonusBlocks + = this . permissionToBonusBlocksMap . get ( groupName ) ;
}
}
return bonusBlocks ;
}
//grants a group (players with a specific permission) bonus claim blocks as long as they're still members of the group
synchronized public int adjustGroupBonusBlocks ( String groupName , int amount )
{
Integer currentValue = this . permissionToBonusBlocksMap . get ( groupName ) ;
if ( currentValue = = null ) currentValue = 0 ;
currentValue + = amount ;
this . permissionToBonusBlocksMap . put ( groupName , currentValue ) ;
//write changes to storage to ensure they don't get lost
this . saveGroupBonusBlocks ( groupName , currentValue ) ;
return currentValue ;
}
abstract void saveGroupBonusBlocks ( String groupName , int amount ) ;
2015-04-24 04:17:45 +00:00
class NoTransferException extends Exception
{
2016-01-20 21:56:31 +00:00
private static final long serialVersionUID = 1L ;
NoTransferException ( String message )
2015-04-24 04:17:45 +00:00
{
super ( message ) ;
}
}
synchronized public void changeClaimOwner ( Claim claim , UUID newOwnerID ) throws NoTransferException
2013-01-05 16:19:42 +00:00
{
//if it's a subdivision, throw an exception
if ( claim . parent ! = null )
{
2015-04-24 04:17:45 +00:00
throw new NoTransferException ( " Subdivisions can't be transferred. Only top-level claims may change owners. " ) ;
2013-01-05 16:19:42 +00:00
}
//otherwise update information
//determine current claim owner
PlayerData ownerData = null ;
if ( ! claim . isAdminClaim ( ) )
{
2014-09-22 20:46:13 +00:00
ownerData = this . getPlayerData ( claim . ownerID ) ;
2013-01-05 16:19:42 +00:00
}
//determine new owner
2015-02-12 01:24:40 +00:00
PlayerData newOwnerData = null ;
if ( newOwnerID ! = null )
{
newOwnerData = this . getPlayerData ( newOwnerID ) ;
}
2013-01-05 16:19:42 +00:00
//transfer
2014-09-22 20:46:13 +00:00
claim . ownerID = newOwnerID ;
2013-01-05 16:19:42 +00:00
this . saveClaim ( claim ) ;
//adjust blocks and other records
if ( ownerData ! = null )
{
2014-10-31 02:24:07 +00:00
ownerData . getClaims ( ) . remove ( claim ) ;
2013-01-05 16:19:42 +00:00
}
2015-02-12 01:24:40 +00:00
if ( newOwnerData ! = null )
{
newOwnerData . getClaims ( ) . add ( claim ) ;
}
2013-01-05 16:19:42 +00:00
}
//adds a claim to the datastore, making it an effective claim
2014-10-05 02:48:03 +00:00
synchronized void addClaim ( Claim newClaim , boolean writeToStorage )
2013-01-05 16:19:42 +00:00
{
2015-09-12 21:17:00 +00:00
//subdivisions are added under their parent, not directly to the hash map for direct search
2013-01-05 16:19:42 +00:00
if ( newClaim . parent ! = null )
{
2015-05-22 04:12:47 +00:00
if ( ! newClaim . parent . children . contains ( newClaim ) )
{
newClaim . parent . children . add ( newClaim ) ;
}
2013-01-05 16:19:42 +00:00
newClaim . inDataStore = true ;
2014-10-08 02:28:56 +00:00
if ( writeToStorage )
{
this . saveClaim ( newClaim ) ;
}
2013-01-05 16:19:42 +00:00
return ;
}
//add it and mark it as added
2014-10-05 02:48:03 +00:00
this . claims . add ( newClaim ) ;
2016-01-28 17:28:48 +00:00
ArrayList < Long > chunkHashes = newClaim . getChunkHashes ( ) ;
for ( Long chunkHash : chunkHashes )
2014-10-05 02:48:03 +00:00
{
2016-01-28 17:28:48 +00:00
ArrayList < Claim > claimsInChunk = this . chunksToClaimsMap . get ( chunkHash ) ;
2014-10-05 02:48:03 +00:00
if ( claimsInChunk = = null )
{
claimsInChunk = new ArrayList < Claim > ( ) ;
2016-01-28 17:28:48 +00:00
this . chunksToClaimsMap . put ( chunkHash , claimsInChunk ) ;
2014-10-05 02:48:03 +00:00
}
claimsInChunk . add ( newClaim ) ;
}
2013-01-05 16:19:42 +00:00
newClaim . inDataStore = true ;
//except for administrative claims (which have no owner), update the owner's playerData with the new claim
2014-10-08 02:28:56 +00:00
if ( ! newClaim . isAdminClaim ( ) & & writeToStorage )
2013-01-05 16:19:42 +00:00
{
2014-09-22 20:46:13 +00:00
PlayerData ownerData = this . getPlayerData ( newClaim . ownerID ) ;
2014-10-31 02:24:07 +00:00
ownerData . getClaims ( ) . add ( newClaim ) ;
2013-01-05 16:19:42 +00:00
}
//make sure the claim is saved to disk
2014-10-05 02:48:03 +00:00
if ( writeToStorage )
{
this . saveClaim ( newClaim ) ;
}
2013-01-05 16:19:42 +00:00
}
//turns a location into a string, useful in data storage
private String locationStringDelimiter = " ; " ;
String locationToString ( Location location )
{
StringBuilder stringBuilder = new StringBuilder ( location . getWorld ( ) . getName ( ) ) ;
stringBuilder . append ( locationStringDelimiter ) ;
stringBuilder . append ( location . getBlockX ( ) ) ;
stringBuilder . append ( locationStringDelimiter ) ;
stringBuilder . append ( location . getBlockY ( ) ) ;
stringBuilder . append ( locationStringDelimiter ) ;
stringBuilder . append ( location . getBlockZ ( ) ) ;
return stringBuilder . toString ( ) ;
}
//turns a location string back into a location
2015-09-12 21:17:00 +00:00
Location locationFromString ( String string , List < World > validWorlds ) throws Exception
2013-01-05 16:19:42 +00:00
{
//split the input string on the space
String [ ] elements = string . split ( locationStringDelimiter ) ;
//expect four elements - world name, X, Y, and Z, respectively
2014-11-14 03:45:40 +00:00
if ( elements . length < 4 )
2013-01-05 16:19:42 +00:00
{
2014-11-14 03:45:40 +00:00
throw new Exception ( " Expected four distinct parts to the location string: \" " + string + " \" " ) ;
2013-01-05 16:19:42 +00:00
}
String worldName = elements [ 0 ] ;
String xString = elements [ 1 ] ;
String yString = elements [ 2 ] ;
String zString = elements [ 3 ] ;
//identify world the claim is in
2015-09-12 21:17:00 +00:00
World world = null ;
for ( World w : validWorlds )
{
if ( w . getName ( ) . equalsIgnoreCase ( worldName ) )
{
world = w ;
break ;
}
}
2013-01-05 16:19:42 +00:00
if ( world = = null )
{
throw new Exception ( " World not found: \" " + worldName + " \" " ) ;
}
//convert those numerical strings to integer values
int x = Integer . parseInt ( xString ) ;
int y = Integer . parseInt ( yString ) ;
int z = Integer . parseInt ( zString ) ;
return new Location ( world , x , y , z ) ;
}
//saves any changes to a claim to secondary storage
synchronized public void saveClaim ( Claim claim )
{
2015-09-12 21:17:00 +00:00
//ensure a unique identifier for the claim which will be used to name the file on disk
2015-12-10 21:52:45 +00:00
if ( claim . id = = null | | claim . id = = - 1 )
2013-01-05 16:19:42 +00:00
{
claim . id = this . nextClaimID ;
this . incrementNextClaimID ( ) ;
}
this . writeClaimToStorage ( claim ) ;
}
abstract void writeClaimToStorage ( Claim claim ) ;
//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
2014-09-22 20:46:13 +00:00
synchronized public PlayerData getPlayerData ( UUID playerID )
2013-01-05 16:19:42 +00:00
{
//first, look in memory
2014-09-22 20:46:13 +00:00
PlayerData playerData = this . playerNameToPlayerDataMap . get ( playerID ) ;
2013-01-05 16:19:42 +00:00
2014-10-31 02:24:07 +00:00
//if not there, build a fresh instance with some blanks for what may be in secondary storage
2013-01-05 16:19:42 +00:00
if ( playerData = = null )
{
2014-10-31 02:24:07 +00:00
playerData = new PlayerData ( ) ;
2014-09-22 20:46:13 +00:00
playerData . playerID = playerID ;
2013-01-05 16:19:42 +00:00
//shove that new player data into the hash map cache
2014-09-22 20:46:13 +00:00
this . playerNameToPlayerDataMap . put ( playerID , playerData ) ;
2013-01-05 16:19:42 +00:00
}
2014-11-16 22:17:40 +00:00
return playerData ;
2013-01-05 16:19:42 +00:00
}
2014-09-22 20:46:13 +00:00
abstract PlayerData getPlayerDataFromStorage ( UUID playerID ) ;
2013-01-05 16:19:42 +00:00
//deletes a claim or subdivision
2015-01-11 23:33:05 +00:00
synchronized public void deleteClaim ( Claim claim )
{
2015-12-16 22:44:34 +00:00
this . deleteClaim ( claim , true , false ) ;
}
//deletes a claim or subdivision
synchronized public void deleteClaim ( Claim claim , boolean releasePets )
{
this . deleteClaim ( claim , true , releasePets ) ;
2015-01-11 23:33:05 +00:00
}
2015-12-16 22:44:34 +00:00
synchronized void deleteClaim ( Claim claim , boolean fireEvent , boolean releasePets )
2013-01-05 16:19:42 +00:00
{
2015-09-12 21:17:00 +00:00
//delete any children
for ( int j = 0 ; j < claim . children . size ( ) ; j + + )
{
this . deleteClaim ( claim . children . get ( j - - ) , true ) ;
}
//subdivisions must also be removed from the parent claim child list
2013-01-05 16:19:42 +00:00
if ( claim . parent ! = null )
{
Claim parentClaim = claim . parent ;
parentClaim . children . remove ( claim ) ;
}
2015-09-12 21:17:00 +00:00
//mark as deleted so any references elsewhere can be ignored
2014-11-06 00:27:06 +00:00
claim . inDataStore = false ;
2013-01-05 16:19:42 +00:00
//remove from memory
for ( int i = 0 ; i < this . claims . size ( ) ; i + + )
{
if ( claims . get ( i ) . id . equals ( claim . id ) )
{
this . claims . remove ( i ) ;
break ;
}
}
2016-01-28 17:28:48 +00:00
ArrayList < Long > chunkHashes = claim . getChunkHashes ( ) ;
for ( Long chunkHash : chunkHashes )
2014-11-06 00:27:06 +00:00
{
2016-01-28 17:28:48 +00:00
ArrayList < Claim > claimsInChunk = this . chunksToClaimsMap . get ( chunkHash ) ;
2016-03-15 23:17:51 +00:00
if ( claimsInChunk ! = null )
2014-11-06 00:27:06 +00:00
{
2016-03-15 23:17:51 +00:00
for ( int j = 0 ; j < claimsInChunk . size ( ) ; j + + )
2014-11-06 00:27:06 +00:00
{
2016-03-15 23:17:51 +00:00
if ( claimsInChunk . get ( j ) . id . equals ( claim . id ) )
{
claimsInChunk . remove ( j ) ;
break ;
}
2014-11-06 00:27:06 +00:00
}
}
}
2013-01-05 16:19:42 +00:00
//remove from secondary storage
this . deleteClaimFromSecondaryStorage ( claim ) ;
2015-09-12 21:17:00 +00:00
//update player data
if ( claim . ownerID ! = null )
2013-01-05 16:19:42 +00:00
{
2014-09-22 20:46:13 +00:00
PlayerData ownerData = this . getPlayerData ( claim . ownerID ) ;
2014-10-31 02:24:07 +00:00
for ( int i = 0 ; i < ownerData . getClaims ( ) . size ( ) ; i + + )
2013-01-05 16:19:42 +00:00
{
2014-10-31 02:24:07 +00:00
if ( ownerData . getClaims ( ) . get ( i ) . id . equals ( claim . id ) )
2013-01-05 16:19:42 +00:00
{
2014-10-31 02:24:07 +00:00
ownerData . getClaims ( ) . remove ( i ) ;
2013-01-05 16:19:42 +00:00
break ;
}
}
2014-09-22 20:46:13 +00:00
this . savePlayerData ( claim . ownerID , ownerData ) ;
2013-01-05 16:19:42 +00:00
}
2015-01-11 23:33:05 +00:00
if ( fireEvent )
{
ClaimDeletedEvent ev = new ClaimDeletedEvent ( claim ) ;
Bukkit . getPluginManager ( ) . callEvent ( ev ) ;
}
2015-12-16 22:44:34 +00:00
//optionally set any pets free which belong to the claim owner
if ( releasePets & & claim . ownerID ! = null & & claim . parent = = null )
{
for ( Chunk chunk : claim . getChunks ( ) )
{
Entity [ ] entities = chunk . getEntities ( ) ;
for ( Entity entity : entities )
{
if ( entity instanceof Tameable )
{
Tameable pet = ( Tameable ) entity ;
2016-03-31 03:07:38 +00:00
if ( pet . isTamed ( ) )
2015-12-16 22:44:34 +00:00
{
2016-03-31 03:07:38 +00:00
AnimalTamer owner = pet . getOwner ( ) ;
if ( owner ! = null )
{
UUID ownerID = owner . getUniqueId ( ) ;
if ( ownerID ! = null )
{
if ( ownerID . equals ( claim . ownerID ) )
{
pet . setTamed ( false ) ;
2016-04-14 03:12:21 +00:00
pet . setOwner ( null ) ;
if ( pet instanceof InventoryHolder )
{
InventoryHolder holder = ( InventoryHolder ) pet ;
holder . getInventory ( ) . clear ( ) ;
}
2016-03-31 03:07:38 +00:00
}
}
}
2015-12-16 22:44:34 +00:00
}
}
}
}
}
2013-01-05 16:19:42 +00:00
}
abstract void deleteClaimFromSecondaryStorage ( Claim claim ) ;
//gets the claim at a specific location
//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
synchronized public Claim getClaimAt ( Location location , boolean ignoreHeight , Claim cachedClaim )
{
//check cachedClaim guess first. if it's in the datastore and the location is inside it, we're done
if ( cachedClaim ! = null & & cachedClaim . inDataStore & & cachedClaim . contains ( location , ignoreHeight , true ) ) return cachedClaim ;
2014-10-05 02:48:03 +00:00
//find a top level claim
2016-01-28 17:28:48 +00:00
Long chunkID = getChunkHash ( location ) ;
2014-10-05 02:48:03 +00:00
ArrayList < Claim > claimsInChunk = this . chunksToClaimsMap . get ( chunkID ) ;
if ( claimsInChunk = = null ) return null ;
2013-01-05 16:19:42 +00:00
2014-10-05 02:48:03 +00:00
for ( Claim claim : claimsInChunk )
2013-01-05 16:19:42 +00:00
{
2015-09-12 21:17:00 +00:00
if ( claim . inDataStore & & claim . contains ( location , ignoreHeight , false ) )
2014-10-05 02:48:03 +00:00
{
//when we find a top level claim, if the location is in one of its subdivisions,
//return the SUBDIVISION, not the top level claim
for ( int j = 0 ; j < claim . children . size ( ) ; j + + )
{
Claim subdivision = claim . children . get ( j ) ;
2015-09-12 21:17:00 +00:00
if ( subdivision . inDataStore & & subdivision . contains ( location , ignoreHeight , false ) ) return subdivision ;
2014-10-05 02:48:03 +00:00
}
return claim ;
}
2013-01-05 16:19:42 +00:00
}
//if no claim found, return null
return null ;
}
2015-01-11 23:08:40 +00:00
//finds a claim by ID
public synchronized Claim getClaim ( long id )
{
for ( Claim claim : this . claims )
{
2015-09-12 21:17:00 +00:00
if ( claim . inDataStore & & claim . getID ( ) = = id ) return claim ;
2015-01-11 23:08:40 +00:00
}
return null ;
}
2015-01-11 23:15:52 +00:00
//returns a read-only access point for the list of all land claims
//if you need to make changes, use provided methods like .deleteClaim() and .createClaim().
//this will ensure primary memory (RAM) and secondary memory (disk, database) stay in sync
public Collection < Claim > getClaims ( )
{
return Collections . unmodifiableCollection ( this . claims ) ;
}
2015-10-21 20:09:14 +00:00
public Collection < Claim > getClaims ( int chunkx , int chunkz )
{
2016-01-28 17:28:48 +00:00
ArrayList < Claim > chunkClaims = this . chunksToClaimsMap . get ( getChunkHash ( chunkx , chunkz ) ) ;
2015-10-21 20:09:14 +00:00
if ( chunkClaims ! = null )
{
return Collections . unmodifiableCollection ( chunkClaims ) ;
}
else
{
return Collections . unmodifiableCollection ( new ArrayList < Claim > ( ) ) ;
}
}
2016-01-28 17:28:48 +00:00
//gets an almost-unique, persistent identifier for a chunk
static Long getChunkHash ( long chunkx , long chunkz )
2015-10-21 20:09:14 +00:00
{
2016-01-28 17:28:48 +00:00
return ( chunkz ^ ( chunkx < < 32 ) ) ;
2015-10-21 20:09:14 +00:00
}
2016-01-28 17:28:48 +00:00
//gets an almost-unique, persistent identifier for a chunk
static Long getChunkHash ( Location location )
2014-10-05 02:48:03 +00:00
{
2016-01-28 17:28:48 +00:00
return getChunkHash ( location . getBlockX ( ) > > 4 , location . getBlockZ ( ) > > 4 ) ;
2014-10-05 02:48:03 +00:00
}
//creates a claim.
2013-01-05 16:19:42 +00:00
//if the new claim would overlap an existing claim, returns a failure along with a reference to the existing claim
2014-12-30 03:37:12 +00:00
//if the new claim would overlap a WorldGuard region where the player doesn't have permission to build, returns a failure with NULL for claim
2013-01-05 16:19:42 +00:00
//otherwise, returns a success along with a reference to the new claim
//use ownerName == "" for administrative claims
//for top level claims, pass parent == NULL
//DOES adjust claim blocks available on success (players can go into negative quantity available)
2014-12-30 03:37:12 +00:00
//DOES check for world guard regions where the player doesn't have permission
2013-01-05 16:19:42 +00:00
//does NOT check a player has permission to create a claim, or enough claim blocks.
//does NOT check minimum claim size constraints
//does NOT visualize the new claim for any players
2014-12-30 03:37:12 +00:00
synchronized public CreateClaimResult createClaim ( World world , int x1 , int x2 , int y1 , int y2 , int z1 , int z2 , UUID ownerID , Claim parent , Long id , Player creatingPlayer )
2013-01-05 16:19:42 +00:00
{
CreateClaimResult result = new CreateClaimResult ( ) ;
int smallx , bigx , smally , bigy , smallz , bigz ;
2016-01-15 18:06:34 +00:00
if ( y1 < GriefPrevention . instance . config_claims_maxDepth ) y1 = GriefPrevention . instance . config_claims_maxDepth ;
if ( y2 < GriefPrevention . instance . config_claims_maxDepth ) y2 = GriefPrevention . instance . config_claims_maxDepth ;
2013-01-05 16:19:42 +00:00
//determine small versus big inputs
if ( x1 < x2 )
{
smallx = x1 ;
bigx = x2 ;
}
else
{
smallx = x2 ;
bigx = x1 ;
}
if ( y1 < y2 )
{
smally = y1 ;
bigy = y2 ;
}
else
{
smally = y2 ;
bigy = y1 ;
}
if ( z1 < z2 )
{
smallz = z1 ;
bigz = z2 ;
}
else
{
smallz = z2 ;
bigz = z1 ;
}
//creative mode claims always go to bedrock
2014-10-19 20:19:53 +00:00
if ( GriefPrevention . instance . config_claims_worldModes . get ( world ) = = ClaimsMode . Creative )
2013-01-05 16:19:42 +00:00
{
smally = 2 ;
}
//create a new claim instance (but don't save it, yet)
Claim newClaim = new Claim (
new Location ( world , smallx , smally , smallz ) ,
new Location ( world , bigx , bigy , bigz ) ,
2014-09-22 20:46:13 +00:00
ownerID ,
2015-09-12 21:17:00 +00:00
new ArrayList < String > ( ) ,
new ArrayList < String > ( ) ,
new ArrayList < String > ( ) ,
new ArrayList < String > ( ) ,
2013-01-05 16:19:42 +00:00
id ) ;
newClaim . parent = parent ;
//ensure this new claim won't overlap any existing claims
ArrayList < Claim > claimsToCheck ;
if ( newClaim . parent ! = null )
{
2015-09-12 21:17:00 +00:00
claimsToCheck = newClaim . parent . children ;
2013-01-05 16:19:42 +00:00
}
else
{
claimsToCheck = this . claims ;
}
for ( int i = 0 ; i < claimsToCheck . size ( ) ; i + + )
{
Claim otherClaim = claimsToCheck . get ( i ) ;
//if we find an existing claim which will be overlapped
2015-09-12 21:17:00 +00:00
if ( otherClaim . id ! = newClaim . id & & otherClaim . inDataStore & & otherClaim . overlaps ( newClaim ) )
2013-01-05 16:19:42 +00:00
{
//result = fail, return conflicting claim
result . succeeded = false ;
result . claim = otherClaim ;
return result ;
}
}
2014-12-30 03:37:12 +00:00
//if worldguard is installed, also prevent claims from overlapping any worldguard regions
2015-01-12 21:24:09 +00:00
if ( GriefPrevention . instance . config_claims_respectWorldGuard & & this . worldGuard ! = null & & creatingPlayer ! = null )
2014-12-30 03:37:12 +00:00
{
2015-01-07 22:53:19 +00:00
if ( ! this . worldGuard . canBuild ( newClaim . lesserBoundaryCorner , newClaim . greaterBoundaryCorner , creatingPlayer ) )
2014-12-31 20:20:18 +00:00
{
2015-01-07 22:53:19 +00:00
result . succeeded = false ;
result . claim = null ;
return result ;
}
2014-12-30 03:37:12 +00:00
}
2013-01-05 16:19:42 +00:00
//otherwise add this new claim to the data store to make it effective
2014-10-05 02:48:03 +00:00
this . addClaim ( newClaim , true ) ;
2013-01-05 16:19:42 +00:00
//then return success along with reference to new claim
result . succeeded = true ;
result . claim = newClaim ;
return result ;
}
2014-10-17 02:17:44 +00:00
//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 savePlayerDataSync ( UUID playerID , PlayerData playerData )
{
2014-11-02 02:18:27 +00:00
//ensure player data is already read from file before trying to save
playerData . getAccruedClaimBlocks ( ) ;
playerData . getClaims ( ) ;
2014-11-16 23:13:25 +00:00
2014-10-17 02:17:44 +00:00
this . asyncSavePlayerData ( playerID , playerData ) ;
}
2013-01-05 16:19:42 +00:00
//saves changes to player data to secondary storage. MUST be called after you're done making changes, otherwise a reload will lose them
2014-10-03 02:27:15 +00:00
public void savePlayerData ( UUID playerID , PlayerData playerData )
{
new SavePlayerDataThread ( playerID , playerData ) . start ( ) ;
}
2015-05-16 20:00:55 +00:00
public void asyncSavePlayerData ( UUID playerID , PlayerData playerData )
{
//save everything except the ignore list
this . overrideSavePlayerData ( playerID , playerData ) ;
//save the ignore list
if ( playerData . ignoreListChanged )
{
StringBuilder fileContent = new StringBuilder ( ) ;
try
{
for ( UUID uuidKey : playerData . ignoredPlayers . keySet ( ) )
{
Boolean value = playerData . ignoredPlayers . get ( uuidKey ) ;
if ( value = = null ) continue ;
//admin-enforced ignores begin with an asterisk
if ( value )
{
fileContent . append ( " * " ) ;
}
fileContent . append ( uuidKey ) ;
fileContent . append ( " \ n " ) ;
}
//write data to file
File playerDataFile = new File ( playerDataFolderPath + File . separator + playerID + " .ignore " ) ;
Files . write ( fileContent . toString ( ) . trim ( ) . getBytes ( " UTF-8 " ) , playerDataFile ) ;
}
//if any problem, log it
catch ( Exception e )
{
GriefPrevention . AddLogEntry ( " GriefPrevention: Unexpected exception saving data for player \" " + playerID . toString ( ) + " \" : " + e . getMessage ( ) ) ;
e . printStackTrace ( ) ;
}
}
}
abstract void overrideSavePlayerData ( UUID playerID , PlayerData playerData ) ;
2013-01-05 16:19:42 +00:00
//extends a claim to a new depth
//respects the max depth config variable
synchronized public void extendClaim ( Claim claim , int newDepth )
{
if ( newDepth < GriefPrevention . instance . config_claims_maxDepth ) newDepth = GriefPrevention . instance . config_claims_maxDepth ;
if ( claim . parent ! = null ) claim = claim . parent ;
2015-09-12 21:17:00 +00:00
//adjust to new depth
2013-01-05 16:19:42 +00:00
claim . lesserBoundaryCorner . setY ( newDepth ) ;
claim . greaterBoundaryCorner . setY ( newDepth ) ;
2015-09-12 21:17:00 +00:00
for ( Claim subdivision : claim . children )
2013-01-05 16:19:42 +00:00
{
2015-01-11 07:16:47 +00:00
subdivision . lesserBoundaryCorner . setY ( newDepth ) ;
subdivision . greaterBoundaryCorner . setY ( newDepth ) ;
2015-09-12 21:17:00 +00:00
this . saveClaim ( subdivision ) ;
2013-01-05 16:19:42 +00:00
}
//save changes
2015-09-12 21:17:00 +00:00
this . saveClaim ( claim ) ;
2013-01-05 16:19:42 +00:00
}
//starts a siege on a claim
//does NOT check siege cooldowns, see onCooldown() below
synchronized public void startSiege ( Player attacker , Player defender , Claim defenderClaim )
{
//fill-in the necessary SiegeData instance
SiegeData siegeData = new SiegeData ( attacker , defender , defenderClaim ) ;
2014-09-22 20:46:13 +00:00
PlayerData attackerData = this . getPlayerData ( attacker . getUniqueId ( ) ) ;
PlayerData defenderData = this . getPlayerData ( defender . getUniqueId ( ) ) ;
2013-01-05 16:19:42 +00:00
attackerData . siegeData = siegeData ;
defenderData . siegeData = siegeData ;
defenderClaim . siegeData = siegeData ;
//start a task to monitor the siege
//why isn't this a "repeating" task?
//because depending on the status of the siege at the time the task runs, there may or may not be a reason to run the task again
SiegeCheckupTask task = new SiegeCheckupTask ( siegeData ) ;
siegeData . checkupTaskID = GriefPrevention . instance . getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( GriefPrevention . instance , task , 20L * 30 ) ;
}
//ends a siege
//either winnerName or loserName can be null, but not both
2016-05-05 15:39:20 +00:00
synchronized public void endSiege ( SiegeData siegeData , String winnerName , String loserName , List < ItemStack > drops )
2013-01-05 16:19:42 +00:00
{
boolean grantAccess = false ;
//determine winner and loser
if ( winnerName = = null & & loserName ! = null )
{
if ( siegeData . attacker . getName ( ) . equals ( loserName ) )
{
winnerName = siegeData . defender . getName ( ) ;
}
else
{
winnerName = siegeData . attacker . getName ( ) ;
}
}
else if ( winnerName ! = null & & loserName = = null )
{
if ( siegeData . attacker . getName ( ) . equals ( winnerName ) )
{
loserName = siegeData . defender . getName ( ) ;
}
else
{
loserName = siegeData . attacker . getName ( ) ;
}
}
//if the attacker won, plan to open the doors for looting
if ( siegeData . attacker . getName ( ) . equals ( winnerName ) )
{
grantAccess = true ;
}
2014-09-22 20:46:13 +00:00
PlayerData attackerData = this . getPlayerData ( siegeData . attacker . getUniqueId ( ) ) ;
2013-01-05 16:19:42 +00:00
attackerData . siegeData = null ;
2014-09-22 20:46:13 +00:00
PlayerData defenderData = this . getPlayerData ( siegeData . defender . getUniqueId ( ) ) ;
2013-01-05 16:19:42 +00:00
defenderData . siegeData = null ;
2015-04-28 01:29:09 +00:00
defenderData . lastSiegeEndTimeStamp = System . currentTimeMillis ( ) ;
2013-01-05 16:19:42 +00:00
//start a cooldown for this attacker/defender pair
Long now = Calendar . getInstance ( ) . getTimeInMillis ( ) ;
Long cooldownEnd = now + 1000 * 60 * 60 ; //one hour from now
this . siegeCooldownRemaining . put ( siegeData . attacker . getName ( ) + " _ " + siegeData . defender . getName ( ) , cooldownEnd ) ;
//start cooldowns for every attacker/involved claim pair
for ( int i = 0 ; i < siegeData . claims . size ( ) ; i + + )
{
Claim claim = siegeData . claims . get ( i ) ;
claim . siegeData = null ;
2014-09-22 20:46:13 +00:00
this . siegeCooldownRemaining . put ( siegeData . attacker . getName ( ) + " _ " + claim . getOwnerName ( ) , cooldownEnd ) ;
2013-01-05 16:19:42 +00:00
//if doors should be opened for looting, do that now
if ( grantAccess )
{
claim . doorsOpen = true ;
}
}
//cancel the siege checkup task
GriefPrevention . instance . getServer ( ) . getScheduler ( ) . cancelTask ( siegeData . checkupTaskID ) ;
//notify everyone who won and lost
if ( winnerName ! = null & & loserName ! = null )
{
GriefPrevention . instance . getServer ( ) . broadcastMessage ( winnerName + " defeated " + loserName + " in siege warfare! " ) ;
}
//if the claim should be opened to looting
if ( grantAccess )
{
2016-01-20 21:56:31 +00:00
@SuppressWarnings ( " deprecation " )
Player winner = GriefPrevention . instance . getServer ( ) . getPlayer ( winnerName ) ;
2013-01-05 16:19:42 +00:00
if ( winner ! = null )
{
//notify the winner
GriefPrevention . sendMessage ( winner , TextMode . Success , Messages . SiegeWinDoorsOpen ) ;
//schedule a task to secure the claims in about 5 minutes
SecureClaimTask task = new SecureClaimTask ( siegeData ) ;
GriefPrevention . instance . getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( GriefPrevention . instance , task , 20L * 60 * 5 ) ;
}
}
//if the siege ended due to death, transfer inventory to winner
2016-05-05 15:39:20 +00:00
if ( drops ! = null )
2013-01-05 16:19:42 +00:00
{
2016-01-20 21:56:31 +00:00
@SuppressWarnings ( " deprecation " )
Player winner = GriefPrevention . instance . getServer ( ) . getPlayer ( winnerName ) ;
@SuppressWarnings ( " deprecation " )
Player loser = GriefPrevention . instance . getServer ( ) . getPlayer ( loserName ) ;
2013-01-05 16:19:42 +00:00
if ( winner ! = null & & loser ! = null )
{
2016-05-05 15:39:20 +00:00
//try to add any drops to the winner's inventory
for ( ItemStack stack : drops )
2013-01-05 16:19:42 +00:00
{
2016-05-05 15:39:20 +00:00
if ( stack = = null | | stack . getType ( ) = = Material . AIR | | stack . getAmount ( ) = = 0 ) continue ;
2013-01-05 16:19:42 +00:00
2016-05-05 15:39:20 +00:00
HashMap < Integer , ItemStack > wontFitItems = winner . getInventory ( ) . addItem ( stack ) ;
2013-01-05 16:19:42 +00:00
//drop any remainder on the ground at his feet
Object [ ] keys = wontFitItems . keySet ( ) . toArray ( ) ;
Location winnerLocation = winner . getLocation ( ) ;
for ( int i = 0 ; i < keys . length ; i + + )
{
Integer key = ( Integer ) keys [ i ] ;
winnerLocation . getWorld ( ) . dropItemNaturally ( winnerLocation , wontFitItems . get ( key ) ) ;
}
}
}
}
}
//timestamp for each siege cooldown to end
private HashMap < String , Long > siegeCooldownRemaining = new HashMap < String , Long > ( ) ;
//whether or not a sieger can siege a particular victim or claim, considering only cooldowns
synchronized public boolean onCooldown ( Player attacker , Player defender , Claim defenderClaim )
{
Long cooldownEnd = null ;
//look for an attacker/defender cooldown
if ( this . siegeCooldownRemaining . get ( attacker . getName ( ) + " _ " + defender . getName ( ) ) ! = null )
{
cooldownEnd = this . siegeCooldownRemaining . get ( attacker . getName ( ) + " _ " + defender . getName ( ) ) ;
if ( Calendar . getInstance ( ) . getTimeInMillis ( ) < cooldownEnd )
{
return true ;
}
//if found but expired, remove it
this . siegeCooldownRemaining . remove ( attacker . getName ( ) + " _ " + defender . getName ( ) ) ;
}
2015-04-28 01:29:09 +00:00
//look for genderal defender cooldown
PlayerData defenderData = this . getPlayerData ( defender . getUniqueId ( ) ) ;
if ( defenderData . lastSiegeEndTimeStamp > 0 )
{
long now = System . currentTimeMillis ( ) ;
if ( now - defenderData . lastSiegeEndTimeStamp > 1000 * 60 * 15 ) //15 minutes in milliseconds
{
return true ;
}
}
2013-01-05 16:19:42 +00:00
//look for an attacker/claim cooldown
2014-09-22 20:46:13 +00:00
if ( cooldownEnd = = null & & this . siegeCooldownRemaining . get ( attacker . getName ( ) + " _ " + defenderClaim . getOwnerName ( ) ) ! = null )
2013-01-05 16:19:42 +00:00
{
2014-09-22 20:46:13 +00:00
cooldownEnd = this . siegeCooldownRemaining . get ( attacker . getName ( ) + " _ " + defenderClaim . getOwnerName ( ) ) ;
2013-01-05 16:19:42 +00:00
if ( Calendar . getInstance ( ) . getTimeInMillis ( ) < cooldownEnd )
{
return true ;
}
//if found but expired, remove it
2014-09-22 20:46:13 +00:00
this . siegeCooldownRemaining . remove ( attacker . getName ( ) + " _ " + defenderClaim . getOwnerName ( ) ) ;
2013-01-05 16:19:42 +00:00
}
return false ;
}
//extend a siege, if it's possible to do so
synchronized void tryExtendSiege ( Player player , Claim claim )
{
2014-09-22 20:46:13 +00:00
PlayerData playerData = this . getPlayerData ( player . getUniqueId ( ) ) ;
2013-01-05 16:19:42 +00:00
//player must be sieged
if ( playerData . siegeData = = null ) return ;
//claim isn't already under the same siege
if ( playerData . siegeData . claims . contains ( claim ) ) return ;
//admin claims can't be sieged
if ( claim . isAdminClaim ( ) ) return ;
//player must have some level of permission to be sieged in a claim
if ( claim . allowAccess ( player ) ! = null ) return ;
//otherwise extend the siege
playerData . siegeData . claims . add ( claim ) ;
claim . siegeData = playerData . siegeData ;
}
//deletes all claims owned by a player
2014-09-22 20:46:13 +00:00
synchronized public void deleteClaimsForPlayer ( UUID playerID , boolean deleteCreativeClaims )
2013-01-05 16:19:42 +00:00
{
//make a list of the player's claims
ArrayList < Claim > claimsToDelete = new ArrayList < Claim > ( ) ;
for ( int i = 0 ; i < this . claims . size ( ) ; i + + )
{
Claim claim = this . claims . get ( i ) ;
2014-12-05 03:14:38 +00:00
if ( ( playerID = = claim . ownerID | | ( playerID ! = null & & playerID . equals ( claim . ownerID ) ) ) & & ( deleteCreativeClaims | | ! GriefPrevention . instance . creativeRulesApply ( claim . getLesserBoundaryCorner ( ) ) ) )
2013-01-05 16:19:42 +00:00
claimsToDelete . add ( claim ) ;
}
//delete them one by one
for ( int i = 0 ; i < claimsToDelete . size ( ) ; i + + )
{
Claim claim = claimsToDelete . get ( i ) ;
claim . removeSurfaceFluids ( null ) ;
2015-01-11 23:33:05 +00:00
this . deleteClaim ( claim , true ) ;
2013-01-05 16:19:42 +00:00
//if in a creative mode world, delete the claim
if ( GriefPrevention . instance . creativeRulesApply ( claim . getLesserBoundaryCorner ( ) ) )
{
GriefPrevention . instance . restoreClaim ( claim , 0 ) ;
}
}
}
//tries to resize a claim
//see CreateClaim() for details on return value
2014-12-30 03:37:12 +00:00
synchronized public CreateClaimResult resizeClaim ( Claim claim , int newx1 , int newx2 , int newy1 , int newy2 , int newz1 , int newz2 , Player resizingPlayer )
2013-01-05 16:19:42 +00:00
{
//try to create this new claim, ignoring the original when checking for overlap
2014-12-30 03:37:12 +00:00
CreateClaimResult result = this . createClaim ( claim . getLesserBoundaryCorner ( ) . getWorld ( ) , newx1 , newx2 , newy1 , newy2 , newz1 , newz2 , claim . ownerID , claim . parent , claim . id , resizingPlayer ) ;
2013-01-05 16:19:42 +00:00
//if succeeded
if ( result . succeeded )
{
//copy permissions from old claim
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 ) ;
for ( int i = 0 ; i < builders . size ( ) ; i + + )
result . claim . setPermission ( builders . get ( i ) , ClaimPermission . Build ) ;
for ( int i = 0 ; i < containers . size ( ) ; i + + )
result . claim . setPermission ( containers . get ( i ) , ClaimPermission . Inventory ) ;
for ( int i = 0 ; i < accessors . size ( ) ; i + + )
result . claim . setPermission ( accessors . get ( i ) , ClaimPermission . Access ) ;
for ( int i = 0 ; i < managers . size ( ) ; i + + )
{
result . claim . managers . add ( managers . get ( i ) ) ;
}
2014-12-12 03:39:22 +00:00
//restore subdivisions
2015-09-12 21:17:00 +00:00
for ( Claim subdivision : claim . children )
2015-01-11 07:16:47 +00:00
{
subdivision . parent = result . claim ;
2015-09-12 21:17:00 +00:00
result . claim . children . add ( subdivision ) ;
2015-01-11 07:16:47 +00:00
}
2013-01-05 16:19:42 +00:00
//save those changes
this . saveClaim ( result . claim ) ;
2015-09-12 21:17:00 +00:00
//make original claim ineffective (it's still in the hash map, so let's make it ignored)
claim . inDataStore = false ;
2013-01-05 16:19:42 +00:00
}
return result ;
}
2015-12-18 05:09:08 +00:00
void resizeClaimWithChecks ( Player player , PlayerData playerData , int newx1 , int newx2 , int newy1 , int newy2 , int newz1 , int newz2 )
{
//for top level claims, apply size rules and claim blocks requirement
if ( playerData . claimResizing . parent = = null )
{
//measure new claim, apply size rules
int newWidth = ( Math . abs ( newx1 - newx2 ) + 1 ) ;
int newHeight = ( Math . abs ( newz1 - newz2 ) + 1 ) ;
boolean smaller = newWidth < playerData . claimResizing . getWidth ( ) | | newHeight < playerData . claimResizing . getHeight ( ) ;
if ( ! player . hasPermission ( " griefprevention.adminclaims " ) & & ! playerData . claimResizing . isAdminClaim ( ) & & smaller )
{
if ( newWidth < GriefPrevention . instance . config_claims_minWidth | | newHeight < GriefPrevention . instance . config_claims_minWidth )
{
GriefPrevention . sendMessage ( player , TextMode . Err , Messages . ResizeClaimTooNarrow , String . valueOf ( GriefPrevention . instance . config_claims_minWidth ) ) ;
return ;
}
int newArea = newWidth * newHeight ;
if ( newArea < GriefPrevention . instance . config_claims_minArea )
{
GriefPrevention . sendMessage ( player , TextMode . Err , Messages . ResizeClaimInsufficientArea , String . valueOf ( GriefPrevention . instance . config_claims_minArea ) ) ;
return ;
}
}
//make sure player has enough blocks to make up the difference
if ( ! playerData . claimResizing . isAdminClaim ( ) & & player . getName ( ) . equals ( playerData . claimResizing . getOwnerName ( ) ) )
{
int newArea = newWidth * newHeight ;
int blocksRemainingAfter = playerData . getRemainingClaimBlocks ( ) + playerData . claimResizing . getArea ( ) - newArea ;
if ( blocksRemainingAfter < 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , Messages . ResizeNeedMoreBlocks , String . valueOf ( Math . abs ( blocksRemainingAfter ) ) ) ;
this . tryAdvertiseAdminAlternatives ( player ) ;
return ;
}
}
}
//special rule for making a top-level claim smaller. to check this, verifying the old claim's corners are inside the new claim's boundaries.
//rule: in any mode, shrinking a claim removes any surface fluids
Claim oldClaim = playerData . claimResizing ;
boolean smaller = false ;
if ( oldClaim . parent = = null )
{
//temporary claim instance, just for checking contains()
Claim newClaim = new Claim (
new Location ( oldClaim . getLesserBoundaryCorner ( ) . getWorld ( ) , newx1 , newy1 , newz1 ) ,
new Location ( oldClaim . getLesserBoundaryCorner ( ) . getWorld ( ) , newx2 , newy2 , newz2 ) ,
null , new ArrayList < String > ( ) , new ArrayList < String > ( ) , new ArrayList < String > ( ) , new ArrayList < String > ( ) , null ) ;
//if the new claim is smaller
if ( ! newClaim . contains ( oldClaim . getLesserBoundaryCorner ( ) , true , false ) | | ! newClaim . contains ( oldClaim . getGreaterBoundaryCorner ( ) , true , false ) )
{
smaller = true ;
//remove surface fluids about to be unclaimed
oldClaim . removeSurfaceFluids ( newClaim ) ;
}
}
//ask the datastore to try and resize the claim, this checks for conflicts with other claims
CreateClaimResult result = GriefPrevention . instance . dataStore . resizeClaim ( playerData . claimResizing , newx1 , newx2 , newy1 , newy2 , newz1 , newz2 , player ) ;
if ( result . succeeded )
{
//decide how many claim blocks are available for more resizing
int claimBlocksRemaining = 0 ;
if ( ! playerData . claimResizing . isAdminClaim ( ) )
{
UUID ownerID = playerData . claimResizing . ownerID ;
if ( playerData . claimResizing . parent ! = null )
{
ownerID = playerData . claimResizing . parent . ownerID ;
}
if ( ownerID = = player . getUniqueId ( ) )
{
claimBlocksRemaining = playerData . getRemainingClaimBlocks ( ) ;
}
else
{
PlayerData ownerData = this . getPlayerData ( ownerID ) ;
claimBlocksRemaining = ownerData . getRemainingClaimBlocks ( ) ;
OfflinePlayer owner = GriefPrevention . instance . getServer ( ) . getOfflinePlayer ( ownerID ) ;
if ( ! owner . isOnline ( ) )
{
this . clearCachedPlayerData ( ownerID ) ;
}
}
}
//inform about success, visualize, communicate remaining blocks available
GriefPrevention . sendMessage ( player , TextMode . Success , Messages . ClaimResizeSuccess , String . valueOf ( claimBlocksRemaining ) ) ;
Visualization visualization = Visualization . FromClaim ( result . claim , player . getEyeLocation ( ) . getBlockY ( ) , VisualizationType . Claim , player . getLocation ( ) ) ;
Visualization . Apply ( player , visualization ) ;
//if resizing someone else's claim, make a log entry
if ( ! player . getUniqueId ( ) . equals ( playerData . claimResizing . ownerID ) & & playerData . claimResizing . parent = = null )
{
GriefPrevention . AddLogEntry ( player . getName ( ) + " resized " + playerData . claimResizing . getOwnerName ( ) + " 's claim at " + GriefPrevention . getfriendlyLocationString ( playerData . claimResizing . lesserBoundaryCorner ) + " . " ) ;
}
//if increased to a sufficiently large size and no subdivisions yet, send subdivision instructions
if ( oldClaim . getArea ( ) < 1000 & & result . claim . getArea ( ) > = 1000 & & result . claim . children . size ( ) = = 0 & & ! player . hasPermission ( " griefprevention.adminclaims " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Info , Messages . BecomeMayor , 200L ) ;
GriefPrevention . sendMessage ( player , TextMode . Instr , Messages . SubdivisionVideo2 , 201L , DataStore . SUBDIVISION_VIDEO_URL ) ;
}
//if in a creative mode world and shrinking an existing claim, restore any unclaimed area
if ( smaller & & GriefPrevention . instance . creativeRulesApply ( oldClaim . getLesserBoundaryCorner ( ) ) )
{
GriefPrevention . sendMessage ( player , TextMode . Warn , Messages . UnclaimCleanupWarning ) ;
GriefPrevention . instance . restoreClaim ( oldClaim , 20L * 60 * 2 ) ; //2 minutes
GriefPrevention . AddLogEntry ( player . getName ( ) + " shrank a claim @ " + GriefPrevention . getfriendlyLocationString ( playerData . claimResizing . getLesserBoundaryCorner ( ) ) ) ;
}
//clean up
playerData . claimResizing = null ;
playerData . lastShovelLocation = null ;
}
else
{
if ( result . claim ! = null )
{
//inform player
GriefPrevention . sendMessage ( player , TextMode . Err , Messages . ResizeFailOverlap ) ;
//show the player the conflicting claim
Visualization visualization = Visualization . FromClaim ( result . claim , player . getEyeLocation ( ) . getBlockY ( ) , VisualizationType . ErrorClaim , player . getLocation ( ) ) ;
Visualization . Apply ( player , visualization ) ;
}
else
{
GriefPrevention . sendMessage ( player , TextMode . Err , Messages . ResizeFailOverlapRegion ) ;
}
}
}
//educates a player about /adminclaims and /acb, if he can use them
void tryAdvertiseAdminAlternatives ( Player player )
{
if ( player . hasPermission ( " griefprevention.adminclaims " ) & & player . hasPermission ( " griefprevention.adjustclaimblocks " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Info , Messages . AdvertiseACandACB ) ;
}
else if ( player . hasPermission ( " griefprevention.adminclaims " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Info , Messages . AdvertiseAdminClaims ) ;
}
else if ( player . hasPermission ( " griefprevention.adjustclaimblocks " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Info , Messages . AdvertiseACB ) ;
}
}
2013-01-05 16:19:42 +00:00
private void loadMessages ( )
{
Messages [ ] messageIDs = Messages . values ( ) ;
this . messages = new String [ Messages . values ( ) . length ] ;
HashMap < String , CustomizableMessage > defaults = new HashMap < String , CustomizableMessage > ( ) ;
//initialize defaults
this . addDefault ( defaults , Messages . RespectingClaims , " Now respecting claims. " , null ) ;
this . addDefault ( defaults , Messages . IgnoringClaims , " Now ignoring claims. " , null ) ;
this . addDefault ( defaults , Messages . NoCreativeUnClaim , " You can't unclaim this land. You can only make this claim larger or create additional claims. " , null ) ;
this . addDefault ( defaults , Messages . SuccessfulAbandon , " Claims abandoned. You now have {0} available claim blocks. " , " 0: remaining blocks " ) ;
this . addDefault ( defaults , Messages . RestoreNatureActivate , " Ready to restore some nature! Right click to restore nature, and use /BasicClaims to stop. " , null ) ;
this . addDefault ( defaults , Messages . RestoreNatureAggressiveActivate , " Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /BasicClaims to stop. " , null ) ;
this . addDefault ( defaults , Messages . FillModeActive , " Fill mode activated with radius {0}. Right click an area to fill. " , " 0: fill radius " ) ;
this . addDefault ( defaults , Messages . TransferClaimPermission , " That command requires the administrative claims permission. " , null ) ;
this . addDefault ( defaults , Messages . TransferClaimMissing , " There's no claim here. Stand in the administrative claim you want to transfer. " , null ) ;
this . addDefault ( defaults , Messages . TransferClaimAdminOnly , " Only administrative claims may be transferred to a player. " , null ) ;
2014-11-21 21:35:59 +00:00
this . addDefault ( defaults , Messages . PlayerNotFound2 , " No player by that name has logged in recently. " , null ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . TransferTopLevel , " Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again. " , null ) ;
this . addDefault ( defaults , Messages . TransferSuccess , " Claim transferred. " , null ) ;
this . addDefault ( defaults , Messages . TrustListNoClaim , " Stand inside the claim you're curious about. " , null ) ;
this . addDefault ( defaults , Messages . ClearPermsOwnerOnly , " Only the claim owner can clear all permissions. " , null ) ;
this . addDefault ( defaults , Messages . UntrustIndividualAllClaims , " Revoked {0}'s access to ALL your claims. To set permissions for a single claim, stand inside it. " , " 0: untrusted player " ) ;
this . addDefault ( defaults , Messages . UntrustEveryoneAllClaims , " Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it. " , null ) ;
this . addDefault ( defaults , Messages . NoPermissionTrust , " You don't have {0}'s permission to manage permissions here. " , " 0: claim owner's name " ) ;
this . addDefault ( defaults , Messages . ClearPermissionsOneClaim , " Cleared permissions in this claim. To set permission for ALL your claims, stand outside them. " , null ) ;
this . addDefault ( defaults , Messages . UntrustIndividualSingleClaim , " Revoked {0}'s access to this claim. To set permissions for a ALL your claims, stand outside them. " , " 0: untrusted player " ) ;
this . addDefault ( defaults , Messages . OnlySellBlocks , " Claim blocks may only be sold, not purchased. " , null ) ;
this . addDefault ( defaults , Messages . BlockPurchaseCost , " Each claim block costs {0}. Your balance is {1}. " , " 0: cost of one block; 1: player's account balance " ) ;
this . addDefault ( defaults , Messages . ClaimBlockLimit , " You've reached your claim block limit. You can't purchase more. " , null ) ;
this . addDefault ( defaults , Messages . InsufficientFunds , " You don't have enough money. You need {0}, but you only have {1}. " , " 0: total cost; 1: player's account balance " ) ;
this . addDefault ( defaults , Messages . PurchaseConfirmation , " Withdrew {0} from your account. You now have {1} available claim blocks. " , " 0: total cost; 1: remaining blocks " ) ;
this . addDefault ( defaults , Messages . OnlyPurchaseBlocks , " Claim blocks may only be purchased, not sold. " , null ) ;
this . addDefault ( defaults , Messages . BlockSaleValue , " Each claim block is worth {0}. You have {1} available for sale. " , " 0: block value; 1: available blocks " ) ;
this . addDefault ( defaults , Messages . NotEnoughBlocksForSale , " You don't have that many claim blocks available for sale. " , null ) ;
this . addDefault ( defaults , Messages . BlockSaleConfirmation , " Deposited {0} in your account. You now have {1} available claim blocks. " , " 0: amount deposited; 1: remaining blocks " ) ;
this . addDefault ( defaults , Messages . AdminClaimsMode , " Administrative claims mode active. Any claims created will be free and editable by other administrators. " , null ) ;
this . addDefault ( defaults , Messages . BasicClaimsMode , " Returned to basic claim creation mode. " , null ) ;
this . addDefault ( defaults , Messages . SubdivisionMode , " Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit. " , null ) ;
2014-12-23 00:31:22 +00:00
this . addDefault ( defaults , Messages . SubdivisionVideo2 , " Click for Subdivision Help: {0} " , " 0:video URL " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . DeleteClaimMissing , " There's no claim here. " , null ) ;
this . addDefault ( defaults , Messages . DeletionSubdivisionWarning , " This claim includes subdivisions. If you're sure you want to delete it, use /DeleteClaim again. " , null ) ;
this . addDefault ( defaults , Messages . DeleteSuccess , " Claim deleted. " , null ) ;
this . addDefault ( defaults , Messages . CantDeleteAdminClaim , " You don't have permission to delete administrative claims. " , null ) ;
this . addDefault ( defaults , Messages . DeleteAllSuccess , " Deleted all of {0}'s claims. " , " 0: owner's name " ) ;
this . addDefault ( defaults , Messages . NoDeletePermission , " You don't have permission to delete claims. " , null ) ;
this . addDefault ( defaults , Messages . AllAdminDeleted , " Deleted all administrative claims. " , null ) ;
this . addDefault ( defaults , Messages . AdjustBlocksSuccess , " Adjusted {0}'s bonus claim blocks by {1}. New total bonus blocks: {2}. " , " 0: player; 1: adjustment; 2: new total " ) ;
2016-06-04 21:03:33 +00:00
this . addDefault ( defaults , Messages . AdjustBlocksAllSuccess , " Adjusted all online players' bonus claim blocks by {0}. " , " 0: adjustment amount " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . NotTrappedHere , " You can build here. Save yourself. " , null ) ;
this . addDefault ( defaults , Messages . RescuePending , " If you stay put for 10 seconds, you'll be teleported out. Please wait. " , null ) ;
this . addDefault ( defaults , Messages . NonSiegeWorld , " Siege is disabled here. " , null ) ;
this . addDefault ( defaults , Messages . AlreadySieging , " You're already involved in a siege. " , null ) ;
this . addDefault ( defaults , Messages . AlreadyUnderSiegePlayer , " {0} is already under siege. Join the party! " , " 0: defending player " ) ;
this . addDefault ( defaults , Messages . NotSiegableThere , " {0} isn't protected there. " , " 0: defending player " ) ;
this . addDefault ( defaults , Messages . SiegeTooFarAway , " You're too far away to siege. " , null ) ;
this . addDefault ( defaults , Messages . NoSiegeDefenseless , " That player is defenseless. Go pick on somebody else. " , null ) ;
this . addDefault ( defaults , Messages . AlreadyUnderSiegeArea , " That area is already under siege. Join the party! " , null ) ;
this . addDefault ( defaults , Messages . NoSiegeAdminClaim , " Siege is disabled in this area. " , null ) ;
this . addDefault ( defaults , Messages . SiegeOnCooldown , " You're still on siege cooldown for this defender or claim. Find another victim. " , null ) ;
this . addDefault ( defaults , Messages . SiegeAlert , " You're under siege! If you log out now, you will die. You must defeat {0}, wait for him to give up, or escape. " , " 0: attacker name " ) ;
this . addDefault ( defaults , Messages . SiegeConfirmed , " The siege has begun! If you log out now, you will die. You must defeat {0}, chase him away, or admit defeat and walk away. " , " 0: defender name " ) ;
this . addDefault ( defaults , Messages . AbandonClaimMissing , " Stand in the claim you want to delete, or consider /AbandonAllClaims. " , null ) ;
this . addDefault ( defaults , Messages . NotYourClaim , " This isn't your claim. " , null ) ;
this . addDefault ( defaults , Messages . DeleteTopLevelClaim , " To delete a subdivision, stand inside it. Otherwise, use /AbandonTopLevelClaim to delete this claim and all subdivisions. " , null ) ;
this . addDefault ( defaults , Messages . AbandonSuccess , " Claim abandoned. You now have {0} available claim blocks. " , " 0: remaining claim blocks " ) ;
this . addDefault ( defaults , Messages . CantGrantThatPermission , " You can't grant a permission you don't have yourself. " , null ) ;
this . addDefault ( defaults , Messages . GrantPermissionNoClaim , " Stand inside the claim where you want to grant permission. " , null ) ;
this . addDefault ( defaults , Messages . GrantPermissionConfirmation , " Granted {0} permission to {1} {2}. " , " 0: target player; 1: permission description; 2: scope (changed claims) " ) ;
this . addDefault ( defaults , Messages . ManageUniversalPermissionsInstruction , " To manage permissions for ALL your claims, stand outside them. " , null ) ;
this . addDefault ( defaults , Messages . ManageOneClaimPermissionsInstruction , " To manage permissions for a specific claim, stand inside it. " , null ) ;
this . addDefault ( defaults , Messages . CollectivePublic , " the public " , " as in 'granted the public permission to...' " ) ;
this . addDefault ( defaults , Messages . BuildPermission , " build " , null ) ;
this . addDefault ( defaults , Messages . ContainersPermission , " access containers and animals " , null ) ;
this . addDefault ( defaults , Messages . AccessPermission , " use buttons and levers " , null ) ;
this . addDefault ( defaults , Messages . PermissionsPermission , " manage permissions " , null ) ;
this . addDefault ( defaults , Messages . LocationCurrentClaim , " in this claim " , null ) ;
this . addDefault ( defaults , Messages . LocationAllClaims , " in all your claims " , null ) ;
this . addDefault ( defaults , Messages . PvPImmunityStart , " You're protected from attack by other players as long as your inventory is empty. " , null ) ;
this . addDefault ( defaults , Messages . SiegeNoDrop , " You can't give away items while involved in a siege. " , null ) ;
this . addDefault ( defaults , Messages . DonateItemsInstruction , " To give away the item(s) in your hand, left-click the chest again. " , null ) ;
this . addDefault ( defaults , Messages . ChestFull , " This chest is full. " , null ) ;
this . addDefault ( defaults , Messages . DonationSuccess , " Item(s) transferred to chest! " , null ) ;
2015-12-21 04:53:05 +00:00
this . addDefault ( defaults , Messages . PlayerTooCloseForFire2 , " You can't start a fire this close to another player. " , null ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . TooDeepToClaim , " This chest can't be protected because it's too deep underground. Consider moving it. " , null ) ;
this . addDefault ( defaults , Messages . ChestClaimConfirmation , " This chest is protected. " , null ) ;
2014-10-13 21:42:50 +00:00
this . addDefault ( defaults , Messages . AutomaticClaimNotification , " This chest and nearby blocks are protected from breakage and theft. " , null ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . UnprotectedChestWarning , " This chest is NOT protected. Consider using a golden shovel to expand an existing claim or to create a new one. " , null ) ;
this . addDefault ( defaults , Messages . ThatPlayerPvPImmune , " You can't injure defenseless players. " , null ) ;
this . addDefault ( defaults , Messages . CantFightWhileImmune , " You can't fight someone while you're protected from PvP. " , null ) ;
this . addDefault ( defaults , Messages . NoDamageClaimedEntity , " That belongs to {0}. " , " 0: owner name " ) ;
this . addDefault ( defaults , Messages . ShovelBasicClaimMode , " Shovel returned to basic claims mode. " , null ) ;
this . addDefault ( defaults , Messages . RemainingBlocks , " You may claim up to {0} more blocks. " , " 0: remaining blocks " ) ;
2014-12-23 00:31:22 +00:00
this . addDefault ( defaults , Messages . CreativeBasicsVideo2 , " Click for Land Claim Help: {0} " , " {0}: video URL " ) ;
this . addDefault ( defaults , Messages . SurvivalBasicsVideo2 , " Click for Land Claim Help: {0} " , " {0}: video URL " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . TrappedChatKeyword , " trapped " , " When mentioned in chat, players get information about the /trapped command. " ) ;
this . addDefault ( defaults , Messages . TrappedInstructions , " Are you trapped in someone's land claim? Try the /trapped command. " , null ) ;
this . addDefault ( defaults , Messages . PvPNoDrop , " You can't drop items while in PvP combat. " , null ) ;
this . addDefault ( defaults , Messages . SiegeNoTeleport , " You can't teleport out of a besieged area. " , null ) ;
this . addDefault ( defaults , Messages . BesiegedNoTeleport , " You can't teleport into a besieged area. " , null ) ;
this . addDefault ( defaults , Messages . SiegeNoContainers , " You can't access containers while involved in a siege. " , null ) ;
this . addDefault ( defaults , Messages . PvPNoContainers , " You can't access containers during PvP combat. " , null ) ;
this . addDefault ( defaults , Messages . PvPImmunityEnd , " Now you can fight with other players. " , null ) ;
this . addDefault ( defaults , Messages . NoBedPermission , " {0} hasn't given you permission to sleep here. " , " 0: claim owner " ) ;
this . addDefault ( defaults , Messages . NoWildernessBuckets , " You may only dump buckets inside your claim(s) or underground. " , null ) ;
this . addDefault ( defaults , Messages . NoLavaNearOtherPlayer , " You can't place lava this close to {0}. " , " 0: nearby player " ) ;
this . addDefault ( defaults , Messages . TooFarAway , " That's too far away. " , null ) ;
this . addDefault ( defaults , Messages . BlockNotClaimed , " No one has claimed this block. " , null ) ;
this . addDefault ( defaults , Messages . BlockClaimed , " That block has been claimed by {0}. " , " 0: claim owner " ) ;
this . addDefault ( defaults , Messages . SiegeNoShovel , " You can't use your shovel tool while involved in a siege. " , null ) ;
this . addDefault ( defaults , Messages . RestoreNaturePlayerInChunk , " Unable to restore. {0} is in that chunk. " , " 0: nearby player " ) ;
this . addDefault ( defaults , Messages . NoCreateClaimPermission , " You don't have permission to claim land. " , null ) ;
2015-08-02 02:18:36 +00:00
this . addDefault ( defaults , Messages . ResizeClaimTooNarrow , " This new size would be too small. Claims must be at least {0} blocks wide. " , " 0: minimum claim width " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . ResizeNeedMoreBlocks , " You don't have enough blocks for this size. You need {0} more. " , " 0: how many needed " ) ;
2015-01-09 04:26:47 +00:00
this . addDefault ( defaults , Messages . ClaimResizeSuccess , " Claim resized. {0} available claim blocks remaining. " , " 0: remaining blocks " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . ResizeFailOverlap , " Can't resize here because it would overlap another nearby claim. " , null ) ;
this . addDefault ( defaults , Messages . ResizeStart , " Resizing claim. Use your shovel again at the new location for this corner. " , null ) ;
this . addDefault ( defaults , Messages . ResizeFailOverlapSubdivision , " You can't create a subdivision here because it would overlap another subdivision. Consider /abandonclaim to delete it, or use your shovel at a corner to resize it. " , null ) ;
this . addDefault ( defaults , Messages . SubdivisionStart , " Subdivision corner set! Use your shovel at the location for the opposite corner of this new subdivision. " , null ) ;
this . addDefault ( defaults , Messages . CreateSubdivisionOverlap , " Your selected area overlaps another subdivision. " , null ) ;
this . addDefault ( defaults , Messages . SubdivisionSuccess , " Subdivision created! Use /trust to share it with friends. " , null ) ;
this . addDefault ( defaults , Messages . CreateClaimFailOverlap , " You can't create a claim here because it would overlap your other claim. Use /abandonclaim to delete it, or use your shovel at a corner to resize it. " , null ) ;
this . addDefault ( defaults , Messages . CreateClaimFailOverlapOtherPlayer , " You can't create a claim here because it would overlap {0}'s claim. " , " 0: other claim owner " ) ;
this . addDefault ( defaults , Messages . ClaimsDisabledWorld , " Land claims are disabled in this world. " , null ) ;
this . addDefault ( defaults , Messages . ClaimStart , " Claim corner set! Use the shovel again at the opposite corner to claim a rectangle of land. To cancel, put your shovel away. " , null ) ;
2015-08-02 02:18:36 +00:00
this . addDefault ( defaults , Messages . NewClaimTooNarrow , " This claim would be too small. Any claim must be at least {0} blocks wide. " , " 0: minimum claim width " ) ;
this . addDefault ( defaults , Messages . ResizeClaimInsufficientArea , " This claim would be too small. Any claim must use at least {0} total claim blocks. " , " 0: minimum claim area " ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . CreateClaimInsufficientBlocks , " You don't have enough blocks to claim that entire area. You need {0} more blocks. " , " 0: additional blocks needed " ) ;
this . addDefault ( defaults , Messages . AbandonClaimAdvertisement , " To delete another claim and free up some blocks, use /AbandonClaim. " , null ) ;
this . addDefault ( defaults , Messages . CreateClaimFailOverlapShort , " Your selected area overlaps an existing claim. " , null ) ;
this . addDefault ( defaults , Messages . CreateClaimSuccess , " Claim created! Use /trust to share it with friends. " , null ) ;
this . addDefault ( defaults , Messages . SiegeWinDoorsOpen , " Congratulations! Buttons and levers are temporarily unlocked (five minutes). " , null ) ;
this . addDefault ( defaults , Messages . RescueAbortedMoved , " You moved! Rescue cancelled. " , null ) ;
this . addDefault ( defaults , Messages . SiegeDoorsLockedEjection , " Looting time is up! Ejected from the claim. " , null ) ;
this . addDefault ( defaults , Messages . NoModifyDuringSiege , " Claims can't be modified while under siege. " , null ) ;
this . addDefault ( defaults , Messages . OnlyOwnersModifyClaims , " Only {0} can modify this claim. " , " 0: owner name " ) ;
this . addDefault ( defaults , Messages . NoBuildUnderSiege , " This claim is under siege by {0}. No one can build here. " , " 0: attacker name " ) ;
this . addDefault ( defaults , Messages . NoBuildPvP , " You can't build in claims during PvP combat. " , null ) ;
this . addDefault ( defaults , Messages . NoBuildPermission , " You don't have {0}'s permission to build here. " , " 0: owner name " ) ;
this . addDefault ( defaults , Messages . NonSiegeMaterial , " That material is too tough to break. " , null ) ;
this . addDefault ( defaults , Messages . NoOwnerBuildUnderSiege , " You can't make changes while under siege. " , null ) ;
this . addDefault ( defaults , Messages . NoAccessPermission , " You don't have {0}'s permission to use that. " , " 0: owner name. access permission controls buttons, levers, and beds " ) ;
this . addDefault ( defaults , Messages . NoContainersSiege , " This claim is under siege by {0}. No one can access containers here right now. " , " 0: attacker name " ) ;
this . addDefault ( defaults , Messages . NoContainersPermission , " You don't have {0}'s permission to use that. " , " 0: owner's name. containers also include crafting blocks " ) ;
this . addDefault ( defaults , Messages . OwnerNameForAdminClaims , " an administrator " , " as in 'You don't have an administrator's permission to build here.' " ) ;
this . addDefault ( defaults , Messages . ClaimTooSmallForEntities , " This claim isn't big enough for that. Try enlarging it. " , null ) ;
this . addDefault ( defaults , Messages . TooManyEntitiesInClaim , " This claim has too many entities already. Try enlarging the claim or removing some animals, monsters, paintings, or minecarts. " , null ) ;
this . addDefault ( defaults , Messages . YouHaveNoClaims , " You don't have any land claims. " , null ) ;
2014-11-11 03:08:11 +00:00
this . addDefault ( defaults , Messages . ConfirmFluidRemoval , " Abandoning this claim will remove lava inside the claim. If you're sure, use /AbandonClaim again. " , null ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . AutoBanNotify , " Auto-banned {0}({1}). See logs for details. " , null ) ;
this . addDefault ( defaults , Messages . AdjustGroupBlocksSuccess , " Adjusted bonus claim blocks for players with the {0} permission by {1}. New total: {2}. " , " 0: permission; 1: adjustment amount; 2: new total bonus " ) ;
this . addDefault ( defaults , Messages . InvalidPermissionID , " Please specify a player name, or a permission in [brackets]. " , null ) ;
this . addDefault ( defaults , Messages . HowToClaimRegex , " (^|.* \\ W)how \\ W.* \\ W(claim|protect|lock)( \\ 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 ) ;
this . addDefault ( defaults , Messages . PlayerOfflineTime , " Last login: {0} days ago. " , " 0: number of full days since last login " ) ;
2014-10-14 02:16:51 +00:00
this . addDefault ( defaults , Messages . BuildingOutsideClaims , " Other players can build here, too. Consider creating a land claim to protect your work! " , null ) ;
2013-01-05 16:19:42 +00:00
this . addDefault ( defaults , Messages . TrappedWontWorkHere , " Sorry, unable to find a safe location to teleport you to. Contact an admin, or consider /kill if you don't want to wait. " , null ) ;
this . addDefault ( defaults , Messages . CommandBannedInPvP , " You can't use that command while in PvP combat. " , null ) ;
this . addDefault ( defaults , Messages . UnclaimCleanupWarning , " The land you've unclaimed may be changed by other players or cleaned up by administrators. If you've built something there you want to keep, you should reclaim it. " , null ) ;
this . addDefault ( defaults , Messages . BuySellNotConfigured , " Sorry, buying anhd selling claim blocks is disabled. " , null ) ;
this . addDefault ( defaults , Messages . NoTeleportPvPCombat , " You can't teleport while fighting another player. " , null ) ;
this . addDefault ( defaults , Messages . NoTNTDamageAboveSeaLevel , " Warning: TNT will not destroy blocks above sea level. " , null ) ;
this . addDefault ( defaults , Messages . NoTNTDamageClaims , " Warning: TNT will not destroy claimed blocks. " , null ) ;
this . addDefault ( defaults , Messages . IgnoreClaimsAdvertisement , " To override, use /IgnoreClaims. " , null ) ;
this . addDefault ( defaults , Messages . NoPermissionForCommand , " You don't have permission to do that. " , null ) ;
2013-02-07 05:26:00 +00:00
this . addDefault ( defaults , Messages . ClaimsListNoPermission , " You don't have permission to get information about another player's land claims. " , null ) ;
this . addDefault ( defaults , Messages . ExplosivesDisabled , " This claim is now protected from explosions. Use /ClaimExplosions again to disable. " , null ) ;
this . addDefault ( defaults , Messages . ExplosivesEnabled , " This claim is now vulnerable to explosions. Use /ClaimExplosions again to re-enable protections. " , null ) ;
this . addDefault ( defaults , Messages . ClaimExplosivesAdvertisement , " To allow explosives to destroy blocks in this land claim, use /ClaimExplosions. " , null ) ;
this . addDefault ( defaults , Messages . PlayerInPvPSafeZone , " That player is in a PvP safe zone. " , null ) ;
2014-10-02 02:14:11 +00:00
this . addDefault ( defaults , Messages . NoPistonsOutsideClaims , " Warning: Pistons won't move blocks outside land claims. " , null ) ;
2014-11-20 18:52:26 +00:00
this . addDefault ( defaults , Messages . SoftMuted , " Soft-muted {0}. " , " 0: The changed player's name. " ) ;
this . addDefault ( defaults , Messages . UnSoftMuted , " Un-soft-muted {0}. " , " 0: The changed player's name. " ) ;
2014-12-09 02:58:19 +00:00
this . addDefault ( defaults , Messages . DropUnlockAdvertisement , " Other players can't pick up your dropped items unless you /UnlockDrops first. " , null ) ;
this . addDefault ( defaults , Messages . PickupBlockedExplanation , " You can't pick this up unless {0} uses /UnlockDrops. " , " 0: The item stack's owner. " ) ;
this . addDefault ( defaults , Messages . DropUnlockConfirmation , " Unlocked your drops. Other players may now pick them up (until you die again). " , null ) ;
2014-12-09 23:03:02 +00:00
this . addDefault ( defaults , Messages . AdvertiseACandACB , " You may use /ACB to give yourself more claim blocks, or /AdminClaims to create a free administrative claim. " , null ) ;
this . addDefault ( defaults , Messages . AdvertiseAdminClaims , " You could create an administrative land claim instead using /AdminClaims, which you'd share with other administrators. " , null ) ;
this . addDefault ( defaults , Messages . AdvertiseACB , " You may use /ACB to give yourself more claim blocks. " , null ) ;
2014-12-18 05:19:47 +00:00
this . addDefault ( defaults , Messages . NotYourPet , " That belongs to {0} until it's given to you with /GivePet. " , " 0: owner name " ) ;
this . addDefault ( defaults , Messages . PetGiveawayConfirmation , " Pet transferred. " , null ) ;
this . addDefault ( defaults , Messages . PetTransferCancellation , " Pet giveaway cancelled. " , null ) ;
this . addDefault ( defaults , Messages . ReadyToTransferPet , " Ready to transfer! Right-click the pet you'd like to give away, or cancel with /GivePet cancel. " , null ) ;
2014-12-23 00:31:22 +00:00
this . addDefault ( defaults , Messages . AvoidGriefClaimLand , " Prevent grief! If you claim your land, you will be grief-proof. " , null ) ;
this . addDefault ( defaults , Messages . BecomeMayor , " Subdivide your land claim and become a mayor! " , null ) ;
this . addDefault ( defaults , Messages . ClaimCreationFailedOverClaimCountLimit , " You've reached your limit on land claims. Use /AbandonClaim to remove one before creating another. " , null ) ;
2014-12-30 03:37:12 +00:00
this . addDefault ( defaults , Messages . CreateClaimFailOverlapRegion , " You can't claim all of this because you're not allowed to build here. " , null ) ;
this . addDefault ( defaults , Messages . ResizeFailOverlapRegion , " You don't have permission to build there, so you can't claim that area. " , null ) ;
2015-01-05 22:05:53 +00:00
this . addDefault ( defaults , Messages . NoBuildPortalPermission , " You can't use this portal because you don't have {0}'s permission to build an exit portal in the destination land claim. " , " 0: Destination land claim owner's name. " ) ;
2015-01-09 04:12:58 +00:00
this . addDefault ( defaults , Messages . ShowNearbyClaims , " Found {0} land claims. " , " 0: Number of claims found. " ) ;
2015-01-16 02:48:00 +00:00
this . addDefault ( defaults , Messages . NoChatUntilMove , " Sorry, but you have to move a little more before you can chat. We get lots of spam bots here. :) " , null ) ;
2015-02-22 05:34:20 +00:00
this . addDefault ( defaults , Messages . SiegeImmune , " That player is immune to /siege. " , null ) ;
2015-02-22 06:19:44 +00:00
this . addDefault ( defaults , Messages . SetClaimBlocksSuccess , " Updated accrued claim blocks. " , null ) ;
2015-05-16 20:00:55 +00:00
this . addDefault ( defaults , Messages . IgnoreConfirmation , " You're now ignoring chat messages from that player. " , null ) ;
this . addDefault ( defaults , Messages . UnIgnoreConfirmation , " You're no longer ignoring chat messages from that player. " , null ) ;
this . addDefault ( defaults , Messages . NotIgnoringPlayer , " You're not ignoring that player. " , null ) ;
this . addDefault ( defaults , Messages . SeparateConfirmation , " Those players will now ignore each other in chat. " , null ) ;
this . addDefault ( defaults , Messages . UnSeparateConfirmation , " Those players will no longer ignore each other in chat. " , null ) ;
2015-05-18 22:17:07 +00:00
this . addDefault ( defaults , Messages . NotIgnoringAnyone , " You're not ignoring anyone. " , null ) ;
this . addDefault ( defaults , Messages . TrustListHeader , " Explicit permissions here: " , null ) ;
2015-05-22 02:24:55 +00:00
this . addDefault ( defaults , Messages . Manage , " Manage " , null ) ;
2015-05-18 22:17:07 +00:00
this . addDefault ( defaults , Messages . Build , " Build " , null ) ;
this . addDefault ( defaults , Messages . Containers , " Containers " , null ) ;
this . addDefault ( defaults , Messages . Access , " Access " , null ) ;
this . addDefault ( defaults , Messages . StartBlockMath , " {0} blocks from play + {1} bonus = {2} total. " , null ) ;
this . addDefault ( defaults , Messages . ClaimsListHeader , " Claims: " , null ) ;
this . addDefault ( defaults , Messages . ContinueBlockMath , " (-{0} blocks) " , null ) ;
this . addDefault ( defaults , Messages . EndBlockMath , " = {0} blocks left to spend " , null ) ;
2015-05-18 23:03:28 +00:00
this . addDefault ( defaults , Messages . NoClaimDuringPvP , " You can't claim lands during PvP combat. " , null ) ;
2015-07-17 03:51:31 +00:00
this . addDefault ( defaults , Messages . UntrustAllOwnerOnly , " Only the claim owner can clear all its permissions. " , null ) ;
this . addDefault ( defaults , Messages . ManagersDontUntrustManagers , " Only the claim owner can demote a manager. " , null ) ;
2015-10-03 21:15:02 +00:00
this . addDefault ( defaults , Messages . PlayerNotIgnorable , " You can't ignore that player. " , null ) ;
2015-10-12 22:18:33 +00:00
this . addDefault ( defaults , Messages . NoEnoughBlocksForChestClaim , " Because you don't have any claim blocks available, no automatic land claim was created for you. You can use /ClaimsList to monitor your available claim block total. " , null ) ;
2015-12-18 05:09:08 +00:00
this . addDefault ( defaults , Messages . MustHoldModificationToolForThat , " You must be holding a golden shovel to do that. " , null ) ;
this . addDefault ( defaults , Messages . StandInClaimToResize , " Stand inside the land claim you want to resize. " , null ) ;
this . addDefault ( defaults , Messages . ClaimsExtendToSky , " Land claims always extend to max build height. " , null ) ;
this . addDefault ( defaults , Messages . ClaimsAutoExtendDownward , " Land claims auto-extend deeper into the ground when you place blocks under them. " , null ) ;
2015-12-23 16:36:56 +00:00
this . addDefault ( defaults , Messages . MinimumRadius , " Minimum radius is {0}. " , " 0: minimum radius " ) ;
2015-12-23 17:25:01 +00:00
this . addDefault ( defaults , Messages . RadiusRequiresGoldenShovel , " You must be holding a golden shovel when specifying a radius. " , null ) ;
2016-01-20 21:40:30 +00:00
this . addDefault ( defaults , Messages . ClaimTooSmallForActiveBlocks , " This claim isn't big enough to support any active block types (hoppers, spawners, beacons...). Make the claim bigger first. " , null ) ;
this . addDefault ( defaults , Messages . TooManyActiveBlocksInClaim , " This claim is at its limit for active block types (hoppers, spawners, beacons...). Either make it bigger, or remove other active blocks first. " , null ) ;
2013-01-05 16:19:42 +00:00
2015-07-23 02:03:11 +00:00
this . addDefault ( defaults , Messages . BookAuthor , " BigScary " , null ) ;
this . addDefault ( defaults , Messages . BookTitle , " How to Claim Land " , null ) ;
this . addDefault ( defaults , Messages . BookLink , " Click: {0} " , " {0}: video URL " ) ;
this . addDefault ( defaults , Messages . BookIntro , " Claim land to protect your stuff! Click the link above to learn land claims in 3 minutes or less. :) " , null ) ;
this . addDefault ( defaults , Messages . BookTools , " Our claim tools are {0} and {1}. " , " 0: claim modification tool name; 1:claim information tool name " ) ;
this . addDefault ( defaults , Messages . BookDisabledChestClaims , " On this server, placing a chest will NOT claim land for you. " , null ) ;
this . addDefault ( defaults , Messages . BookUsefulCommands , " Useful Commands: " , null ) ;
2015-09-18 02:14:36 +00:00
this . addDefault ( defaults , Messages . NoProfanity , " Please moderate your language. " , null ) ;
2015-12-16 04:07:08 +00:00
this . addDefault ( defaults , Messages . IsIgnoringYou , " That player is ignoring you. " , null ) ;
2016-04-08 18:35:35 +00:00
this . addDefault ( defaults , Messages . ConsoleOnlyCommand , " That command may only be executed from the server console. " , null ) ;
this . addDefault ( defaults , Messages . WorldNotFound , " World not found. " , null ) ;
2015-07-23 02:03:11 +00:00
2013-01-05 16:19:42 +00:00
//load the config file
FileConfiguration config = YamlConfiguration . loadConfiguration ( new File ( messagesFilePath ) ) ;
//for each message ID
for ( int i = 0 ; i < messageIDs . length ; i + + )
{
//get default for this message
Messages messageID = messageIDs [ i ] ;
CustomizableMessage messageData = defaults . get ( messageID . name ( ) ) ;
//if default is missing, log an error and use some fake data for now so that the plugin can run
if ( messageData = = null )
{
GriefPrevention . AddLogEntry ( " Missing message for " + messageID . name ( ) + " . Please contact the developer. " ) ;
messageData = new CustomizableMessage ( messageID , " Missing message! ID: " + messageID . name ( ) + " . Please contact a server admin. " , null ) ;
}
//read the message from the file, use default if necessary
this . messages [ messageID . ordinal ( ) ] = config . getString ( " Messages. " + messageID . name ( ) + " .Text " , messageData . text ) ;
config . set ( " Messages. " + messageID . name ( ) + " .Text " , this . messages [ messageID . ordinal ( ) ] ) ;
2015-12-04 01:18:50 +00:00
//support color codes
2016-01-14 18:25:41 +00:00
if ( messageID ! = Messages . HowToClaimRegex )
{
this . messages [ messageID . ordinal ( ) ] = this . messages [ messageID . ordinal ( ) ] . replace ( '$' , ( char ) 0x00A7 ) ;
}
2015-12-04 01:18:50 +00:00
2013-01-05 16:19:42 +00:00
if ( messageData . notes ! = null )
{
messageData . notes = config . getString ( " Messages. " + messageID . name ( ) + " .Notes " , messageData . notes ) ;
config . set ( " Messages. " + messageID . name ( ) + " .Notes " , messageData . notes ) ;
}
}
//save any changes
try
{
2015-12-04 01:23:42 +00:00
config . options ( ) . header ( " Use a YAML editor like NotepadPlusPlus to edit this file. \ nAfter editing, back up your changes before reloading the server in case you made a syntax error. \ nUse dollar signs ($) for formatting codes, which are documented here: http://minecraft.gamepedia.com/Formatting_codes " ) ;
config . save ( DataStore . messagesFilePath ) ;
2013-01-05 16:19:42 +00:00
}
catch ( IOException exception )
{
GriefPrevention . AddLogEntry ( " Unable to write to the configuration file at \" " + DataStore . messagesFilePath + " \" " ) ;
}
defaults . clear ( ) ;
System . gc ( ) ;
}
private void addDefault ( HashMap < String , CustomizableMessage > defaults ,
Messages id , String text , String notes )
{
CustomizableMessage message = new CustomizableMessage ( id , text , notes ) ;
defaults . put ( id . name ( ) , message ) ;
}
synchronized public String getMessage ( Messages messageID , String . . . args )
{
String message = messages [ messageID . ordinal ( ) ] ;
for ( int i = 0 ; i < args . length ; i + + )
{
String param = args [ i ] ;
message = message . replace ( " { " + i + " } " , param ) ;
}
return message ;
}
2014-09-22 20:46:13 +00:00
//used in updating the data schema from 0 to 1.
//converts player names in a list to uuids
2015-09-12 21:17:00 +00:00
protected List < String > convertNameListToUUIDList ( List < String > names )
2014-09-22 20:46:13 +00:00
{
//doesn't apply after schema has been updated to version 1
if ( this . getSchemaVersion ( ) > = 1 ) return names ;
//list to build results
List < String > resultNames = new ArrayList < String > ( ) ;
for ( String name : names )
{
//skip non-player-names (groups and "public"), leave them as-is
if ( name . startsWith ( " [ " ) | | name . equals ( " public " ) )
{
resultNames . add ( name ) ;
continue ;
}
//otherwise try to convert to a UUID
UUID playerID = null ;
try
{
playerID = UUIDFetcher . getUUIDOf ( name ) ;
}
catch ( Exception ex ) { }
//if successful, replace player name with corresponding UUID
if ( playerID ! = null )
{
resultNames . add ( playerID . toString ( ) ) ;
}
}
2015-09-12 21:17:00 +00:00
return resultNames ;
2014-09-22 20:46:13 +00:00
}
abstract void close ( ) ;
2014-10-03 02:27:15 +00:00
private class SavePlayerDataThread extends Thread
{
private UUID playerID ;
private PlayerData playerData ;
SavePlayerDataThread ( UUID playerID , PlayerData playerData )
{
this . playerID = playerID ;
this . playerData = playerData ;
}
public void run ( )
{
2014-11-16 23:13:25 +00:00
//ensure player data is already read from file before trying to save
playerData . getAccruedClaimBlocks ( ) ;
playerData . getClaims ( ) ;
2014-10-03 02:27:15 +00:00
asyncSavePlayerData ( this . playerID , this . playerData ) ;
}
}
2014-12-14 04:52:26 +00:00
//gets all the claims "near" a location
2015-01-09 04:12:58 +00:00
Set < Claim > getNearbyClaims ( Location location )
2014-12-14 04:52:26 +00:00
{
2015-01-09 04:12:58 +00:00
Set < Claim > claims = new HashSet < Claim > ( ) ;
2014-12-14 04:52:26 +00:00
Chunk lesserChunk = location . getWorld ( ) . getChunkAt ( location . subtract ( 150 , 0 , 150 ) ) ;
Chunk greaterChunk = location . getWorld ( ) . getChunkAt ( location . add ( 300 , 0 , 300 ) ) ;
for ( int chunk_x = lesserChunk . getX ( ) ; chunk_x < = greaterChunk . getX ( ) ; chunk_x + + )
{
for ( int chunk_z = lesserChunk . getZ ( ) ; chunk_z < = greaterChunk . getZ ( ) ; chunk_z + + )
{
Chunk chunk = location . getWorld ( ) . getChunkAt ( chunk_x , chunk_z ) ;
2016-01-28 17:28:48 +00:00
Long chunkID = getChunkHash ( chunk . getBlock ( 0 , 0 , 0 ) . getLocation ( ) ) ;
2014-12-14 04:52:26 +00:00
ArrayList < Claim > claimsInChunk = this . chunksToClaimsMap . get ( chunkID ) ;
if ( claimsInChunk ! = null )
{
2015-12-15 21:48:21 +00:00
for ( Claim claim : claimsInChunk )
{
2015-12-18 05:09:08 +00:00
if ( claim . inDataStore & & claim . getLesserBoundaryCorner ( ) . getWorld ( ) . equals ( location . getWorld ( ) ) )
2015-12-15 21:48:21 +00:00
{
claims . add ( claim ) ;
}
}
2014-12-14 04:52:26 +00:00
}
}
}
2015-01-09 04:12:58 +00:00
return claims ;
2014-12-14 04:52:26 +00:00
}
2016-04-08 18:35:35 +00:00
//deletes all the land claims in a specified world
2016-05-05 16:02:27 +00:00
void deleteClaimsInWorld ( World world , boolean deleteAdminClaims )
2016-04-08 18:35:35 +00:00
{
for ( int i = 0 ; i < claims . size ( ) ; i + + )
{
Claim claim = claims . get ( i ) ;
if ( claim . getLesserBoundaryCorner ( ) . getWorld ( ) . equals ( world ) )
{
2016-05-05 16:02:27 +00:00
if ( ! deleteAdminClaims & & claim . isAdminClaim ( ) ) continue ;
2016-04-08 18:35:35 +00:00
this . deleteClaim ( claim , false , false ) ;
i - - ;
}
}
}
2013-01-05 16:19:42 +00:00
}