2012-03-30 00:27:12 +00:00
/ *
GriefPrevention Server Plugin for Minecraft
Copyright ( C ) 2011 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.File ;
import java.io.IOException ;
import java.util.ArrayList ;
import java.util.Calendar ;
import java.util.List ;
import java.util.concurrent.ConcurrentLinkedQueue ;
import java.util.logging.Logger ;
import net.milkbowl.vault.economy.Economy ;
import org.bukkit.ChatColor ;
import org.bukkit.Chunk ;
2012-05-23 03:31:42 +00:00
import org.bukkit.GameMode ;
2012-03-30 00:27:12 +00:00
import org.bukkit.Location ;
import org.bukkit.Material ;
import org.bukkit.OfflinePlayer ;
import org.bukkit.World ;
import org.bukkit.block.Block ;
import org.bukkit.block.BlockFace ;
import org.bukkit.command.* ;
import org.bukkit.configuration.file.FileConfiguration ;
import org.bukkit.configuration.file.YamlConfiguration ;
import org.bukkit.entity.Player ;
import org.bukkit.inventory.ItemStack ;
import org.bukkit.inventory.PlayerInventory ;
import org.bukkit.plugin.PluginManager ;
import org.bukkit.plugin.RegisteredServiceProvider ;
import org.bukkit.plugin.java.JavaPlugin ;
public class GriefPrevention extends JavaPlugin
{
//for convenience, a reference to the instance of this plugin
public static GriefPrevention instance ;
//for logging to the console and log file
private static Logger log = Logger . getLogger ( " Minecraft " ) ;
2012-05-31 02:16:46 +00:00
2012-03-30 00:27:12 +00:00
//this handles data storage, like player and region data
public DataStore dataStore ;
//configuration variables, loaded/saved from a config.yml
public ArrayList < World > config_claims_enabledWorlds ; //list of worlds where players can create GriefPrevention claims
2012-05-23 03:31:42 +00:00
public ArrayList < World > config_claims_enabledCreativeWorlds ; //list of worlds where additional creative mode anti-grief rules apply
2012-03-30 00:27:12 +00:00
public boolean config_claims_preventTheft ; //whether containers and crafting blocks are protectable
public boolean config_claims_preventButtonsSwitches ; //whether buttons and switches are protectable
public int config_claims_initialBlocks ; //the number of claim blocks a new player starts with
public int config_claims_blocksAccruedPerHour ; //how many additional blocks players get each hour of play (can be zero)
public int config_claims_maxAccruedBlocks ; //the limit on accrued blocks (over time). doesn't limit purchased or admin-gifted blocks
public int config_claims_maxDepth ; //limit on how deep claims can go
2012-05-31 02:16:46 +00:00
public int config_claims_expirationDays ; //how many days of inactivity before a player loses his claims
2012-03-30 00:27:12 +00:00
public int config_claims_automaticClaimsForNewPlayersRadius ; //how big automatic new player claims (when they place a chest) should be. 0 to disable
public boolean config_claims_creationRequiresPermission ; //whether creating claims with the shovel requires a permission
public int config_claims_claimsExtendIntoGroundDistance ; //how far below the shoveled block a new claim will reach
public int config_claims_minSize ; //minimum width and height for non-admin claims
public int config_claims_trappedCooldownHours ; //number of hours between uses of the /trapped command
public ArrayList < World > config_siege_enabledWorlds ; //whether or not /siege is enabled on this server
public ArrayList < Material > config_siege_blocks ; //which blocks will be breakable in siege mode
public boolean config_spam_enabled ; //whether or not to monitor for spam
public int config_spam_loginCooldownMinutes ; //how long players must wait between logins. combats login spam.
public ArrayList < String > config_spam_monitorSlashCommands ; //the list of slash commands monitored for spam
public boolean config_spam_banOffenders ; //whether or not to ban spammers automatically
public String config_spam_banMessage ; //message to show an automatically banned player
public String config_spam_warningMessage ; //message to show a player who is close to spam level
public String config_spam_allowedIpAddresses ; //IP addresses which will not be censored
public boolean config_pvp_protectFreshSpawns ; //whether to make newly spawned players immune until they pick up an item
public boolean config_pvp_punishLogout ; //whether to kill players who log out during PvP combat
2012-05-10 00:29:51 +00:00
public int config_pvp_combatTimeoutSeconds ; //how long combat is considered to continue after the most recent damage
public boolean config_pvp_allowCombatItemDrop ; //whether a player can drop items during combat to hide them
2012-03-30 00:27:12 +00:00
public boolean config_trees_removeFloatingTreetops ; //whether to automatically remove partially cut trees
public boolean config_trees_regrowGriefedTrees ; //whether to automatically replant partially cut trees
public double config_economy_claimBlocksPurchaseCost ; //cost to purchase a claim block. set to zero to disable purchase.
public double config_economy_claimBlocksSellValue ; //return on a sold claim block. set to zero to disable sale.
2012-05-31 02:16:46 +00:00
public boolean config_blockSurfaceExplosions ; //whether creeper/TNT explosions near or above the surface destroy blocks
2012-03-30 00:27:12 +00:00
2012-04-17 02:00:21 +00:00
public boolean config_fireSpreads ; //whether fire spreads outside of claims
public boolean config_fireDestroys ; //whether fire destroys blocks outside of claims
2012-05-10 00:29:51 +00:00
public boolean config_addItemsToClaimedChests ; //whether players may add items to claimed chests by left-clicking them
2012-05-23 03:31:42 +00:00
public boolean config_eavesdrop ; //whether whispered messages will be visible to administrators
2012-05-10 00:29:51 +00:00
2012-05-31 02:16:46 +00:00
public boolean config_smartBan ; //whether to ban accounts which very likely owned by a banned player
2012-03-30 00:27:12 +00:00
//reference to the economy plugin, if economy integration is enabled
public static Economy economy = null ;
//how far away to search from a tree trunk for its branch blocks
public static final int TREE_RADIUS = 5 ;
2012-05-31 02:16:46 +00:00
//how long to wait before deciding a player is staying online or staying offline, for notication messages
public static final int NOTIFICATION_SECONDS = 20 ;
2012-03-30 00:27:12 +00:00
//adds a server log entry
public static void AddLogEntry ( String entry )
{
log . info ( " GriefPrevention: " + entry ) ;
}
//initializes well... everything
public void onEnable ( )
{
AddLogEntry ( " Grief Prevention enabled. " ) ;
instance = this ;
//load the config if it exists
FileConfiguration config = YamlConfiguration . loadConfiguration ( new File ( DataStore . configFilePath ) ) ;
//read configuration settings (note defaults)
//default for claims worlds list
ArrayList < String > defaultClaimsWorldNames = new ArrayList < String > ( ) ;
List < World > worlds = this . getServer ( ) . getWorlds ( ) ;
for ( int i = 0 ; i < worlds . size ( ) ; i + + )
{
defaultClaimsWorldNames . add ( worlds . get ( i ) . getName ( ) ) ;
}
//get claims world names from the config file
List < String > claimsEnabledWorldNames = config . getStringList ( " GriefPrevention.Claims.Worlds " ) ;
if ( claimsEnabledWorldNames = = null | | claimsEnabledWorldNames . size ( ) = = 0 )
{
claimsEnabledWorldNames = defaultClaimsWorldNames ;
}
//validate that list
this . config_claims_enabledWorlds = new ArrayList < World > ( ) ;
for ( int i = 0 ; i < claimsEnabledWorldNames . size ( ) ; i + + )
{
String worldName = claimsEnabledWorldNames . get ( i ) ;
World world = this . getServer ( ) . getWorld ( worldName ) ;
if ( world = = null )
{
AddLogEntry ( " Error: Claims Configuration: There's no world named \" " + worldName + " \" . Please update your config.yml. " ) ;
}
else
{
this . config_claims_enabledWorlds . add ( world ) ;
}
}
2012-05-23 03:31:42 +00:00
//default creative claim world names
List < String > defaultCreativeWorldNames = new ArrayList < String > ( ) ;
//if default game mode for the server is creative, creative rules will apply to all worlds unless the config specifies otherwise
if ( this . getServer ( ) . getDefaultGameMode ( ) = = GameMode . CREATIVE )
{
for ( int i = 0 ; i < defaultClaimsWorldNames . size ( ) ; i + + )
{
defaultCreativeWorldNames . add ( defaultClaimsWorldNames . get ( i ) ) ;
}
}
//get creative world names from the config file
List < String > creativeClaimsEnabledWorldNames = config . getStringList ( " GriefPrevention.Claims.CreativeRulesWorlds " ) ;
if ( creativeClaimsEnabledWorldNames = = null | | creativeClaimsEnabledWorldNames . size ( ) = = 0 )
{
creativeClaimsEnabledWorldNames = defaultCreativeWorldNames ;
}
//validate that list
this . config_claims_enabledCreativeWorlds = new ArrayList < World > ( ) ;
for ( int i = 0 ; i < creativeClaimsEnabledWorldNames . size ( ) ; i + + )
{
String worldName = creativeClaimsEnabledWorldNames . get ( i ) ;
World world = this . getServer ( ) . getWorld ( worldName ) ;
if ( world = = null )
{
AddLogEntry ( " Error: Claims Configuration: There's no world named \" " + worldName + " \" . Please update your config.yml. " ) ;
}
else
{
this . config_claims_enabledCreativeWorlds . add ( world ) ;
}
}
2012-03-30 00:27:12 +00:00
this . config_claims_preventTheft = config . getBoolean ( " GriefPrevention.Claims.PreventTheft " , true ) ;
this . config_claims_preventButtonsSwitches = config . getBoolean ( " GriefPrevention.Claims.PreventButtonsSwitches " , true ) ;
this . config_claims_initialBlocks = config . getInt ( " GriefPrevention.Claims.InitialBlocks " , 100 ) ;
this . config_claims_blocksAccruedPerHour = config . getInt ( " GriefPrevention.Claims.BlocksAccruedPerHour " , 100 ) ;
this . config_claims_maxAccruedBlocks = config . getInt ( " GriefPrevention.Claims.MaxAccruedBlocks " , 80000 ) ;
this . config_claims_automaticClaimsForNewPlayersRadius = config . getInt ( " GriefPrevention.Claims.AutomaticNewPlayerClaimsRadius " , 4 ) ;
this . config_claims_claimsExtendIntoGroundDistance = config . getInt ( " GriefPrevention.Claims.ExtendIntoGroundDistance " , 5 ) ;
this . config_claims_creationRequiresPermission = config . getBoolean ( " GriefPrevention.Claims.CreationRequiresPermission " , false ) ;
this . config_claims_minSize = config . getInt ( " GriefPrevention.Claims.MinimumSize " , 10 ) ;
this . config_claims_maxDepth = config . getInt ( " GriefPrevention.Claims.MaximumDepth " , 0 ) ;
2012-05-31 02:16:46 +00:00
this . config_claims_expirationDays = config . getInt ( " GriefPrevention.Claims.IdleLimitDays " , 0 ) ;
2012-03-30 00:27:12 +00:00
this . config_claims_trappedCooldownHours = config . getInt ( " GriefPrevention.Claims.TrappedCommandCooldownHours " , 8 ) ;
this . config_spam_enabled = config . getBoolean ( " GriefPrevention.Spam.Enabled " , true ) ;
2012-05-31 02:16:46 +00:00
this . config_spam_loginCooldownMinutes = config . getInt ( " GriefPrevention.Spam.LoginCooldownMinutes " , 2 ) ;
this . config_spam_warningMessage = config . getString ( " GriefPrevention.Spam.WarningMessage " , " Please reduce your noise level. Spammers will be banned. " ) ;
2012-03-30 00:27:12 +00:00
this . config_spam_allowedIpAddresses = config . getString ( " GriefPrevention.Spam.AllowedIpAddresses " , " 1.2.3.4; 5.6.7.8 " ) ;
this . config_spam_banOffenders = config . getBoolean ( " GriefPrevention.Spam.BanOffenders " , true ) ;
this . config_spam_banMessage = config . getString ( " GriefPrevention.Spam.BanMessage " , " Banned for spam. " ) ;
String slashCommandsToMonitor = config . getString ( " GriefPrevention.Spam.MonitorSlashCommands " , " /me;/tell;/global;/local " ) ;
this . config_pvp_protectFreshSpawns = config . getBoolean ( " GriefPrevention.PvP.ProtectFreshSpawns " , true ) ;
this . config_pvp_punishLogout = config . getBoolean ( " GriefPrevention.PvP.PunishLogout " , true ) ;
2012-05-10 00:29:51 +00:00
this . config_pvp_combatTimeoutSeconds = config . getInt ( " GriefPrevention.PvP.CombatTimeoutSeconds " , 15 ) ;
this . config_pvp_allowCombatItemDrop = config . getBoolean ( " GriefPrevention.PvP.AllowCombatItemDrop " , false ) ;
2012-03-30 00:27:12 +00:00
this . config_trees_removeFloatingTreetops = config . getBoolean ( " GriefPrevention.Trees.RemoveFloatingTreetops " , true ) ;
this . config_trees_regrowGriefedTrees = config . getBoolean ( " GriefPrevention.Trees.RegrowGriefedTrees " , true ) ;
this . config_economy_claimBlocksPurchaseCost = config . getDouble ( " GriefPrevention.Economy.ClaimBlocksPurchaseCost " , 0 ) ;
this . config_economy_claimBlocksSellValue = config . getDouble ( " GriefPrevention.Economy.ClaimBlocksSellValue " , 0 ) ;
2012-05-31 02:16:46 +00:00
this . config_blockSurfaceExplosions = config . getBoolean ( " GriefPrevention.BlockSurfaceExplosions " , true ) ;
2012-03-30 00:27:12 +00:00
2012-04-17 02:00:21 +00:00
this . config_fireSpreads = config . getBoolean ( " GriefPrevention.FireSpreads " , false ) ;
this . config_fireDestroys = config . getBoolean ( " GriefPrevention.FireDestroys " , false ) ;
2012-05-10 00:29:51 +00:00
this . config_addItemsToClaimedChests = config . getBoolean ( " GriefPrevention.AddItemsToClaimedChests " , true ) ;
2012-05-23 03:31:42 +00:00
this . config_eavesdrop = config . getBoolean ( " GriefPrevention.EavesdropEnabled " , false ) ;
2012-05-10 00:29:51 +00:00
2012-05-31 02:16:46 +00:00
this . config_smartBan = config . getBoolean ( " GriefPrevention.SmartBan " , true ) ;
2012-05-23 03:31:42 +00:00
//default for siege worlds list
2012-03-30 00:27:12 +00:00
ArrayList < String > defaultSiegeWorldNames = new ArrayList < String > ( ) ;
//get siege world names from the config file
List < String > siegeEnabledWorldNames = config . getStringList ( " GriefPrevention.Siege.Worlds " ) ;
if ( siegeEnabledWorldNames = = null )
{
siegeEnabledWorldNames = defaultSiegeWorldNames ;
}
//validate that list
this . config_siege_enabledWorlds = new ArrayList < World > ( ) ;
for ( int i = 0 ; i < siegeEnabledWorldNames . size ( ) ; i + + )
{
String worldName = siegeEnabledWorldNames . get ( i ) ;
World world = this . getServer ( ) . getWorld ( worldName ) ;
if ( world = = null )
{
AddLogEntry ( " Error: Siege Configuration: There's no world named \" " + worldName + " \" . Please update your config.yml. " ) ;
}
else
{
this . config_siege_enabledWorlds . add ( world ) ;
}
}
//default siege blocks
this . config_siege_blocks = new ArrayList < Material > ( ) ;
this . config_siege_blocks . add ( Material . DIRT ) ;
this . config_siege_blocks . add ( Material . GRASS ) ;
this . config_siege_blocks . add ( Material . LONG_GRASS ) ;
this . config_siege_blocks . add ( Material . COBBLESTONE ) ;
this . config_siege_blocks . add ( Material . GRAVEL ) ;
this . config_siege_blocks . add ( Material . SAND ) ;
this . config_siege_blocks . add ( Material . GLASS ) ;
2012-04-17 02:00:21 +00:00
this . config_siege_blocks . add ( Material . THIN_GLASS ) ;
2012-03-30 00:27:12 +00:00
this . config_siege_blocks . add ( Material . WOOD ) ;
this . config_siege_blocks . add ( Material . WOOL ) ;
this . config_siege_blocks . add ( Material . SNOW ) ;
//build a default config entry
ArrayList < String > defaultBreakableBlocksList = new ArrayList < String > ( ) ;
for ( int i = 0 ; i < this . config_siege_blocks . size ( ) ; i + + )
{
defaultBreakableBlocksList . add ( this . config_siege_blocks . get ( i ) . name ( ) ) ;
}
//try to load the list from the config file
List < String > breakableBlocksList = config . getStringList ( " GriefPrevention.Siege.BreakableBlocks " ) ;
//if it fails, use default list instead
if ( breakableBlocksList = = null | | breakableBlocksList . size ( ) = = 0 )
{
breakableBlocksList = defaultBreakableBlocksList ;
}
//parse the list of siege-breakable blocks
this . config_siege_blocks = new ArrayList < Material > ( ) ;
for ( int i = 0 ; i < breakableBlocksList . size ( ) ; i + + )
{
String blockName = breakableBlocksList . get ( i ) ;
Material material = Material . getMaterial ( blockName ) ;
if ( material = = null )
{
GriefPrevention . AddLogEntry ( " Siege Configuration: Material not found: " + blockName + " . " ) ;
}
else
{
this . config_siege_blocks . add ( material ) ;
}
}
config . set ( " GriefPrevention.Claims.Worlds " , claimsEnabledWorldNames ) ;
2012-05-23 03:31:42 +00:00
config . set ( " GriefPrevention.Claims.CreativeRulesWorlds " , creativeClaimsEnabledWorldNames ) ;
2012-03-30 00:27:12 +00:00
config . set ( " GriefPrevention.Claims.PreventTheft " , this . config_claims_preventTheft ) ;
config . set ( " GriefPrevention.Claims.PreventButtonsSwitches " , this . config_claims_preventButtonsSwitches ) ;
config . set ( " GriefPrevention.Claims.InitialBlocks " , this . config_claims_initialBlocks ) ;
config . set ( " GriefPrevention.Claims.BlocksAccruedPerHour " , this . config_claims_blocksAccruedPerHour ) ;
config . set ( " GriefPrevention.Claims.MaxAccruedBlocks " , this . config_claims_maxAccruedBlocks ) ;
config . set ( " GriefPrevention.Claims.AutomaticNewPlayerClaimsRadius " , this . config_claims_automaticClaimsForNewPlayersRadius ) ;
config . set ( " GriefPrevention.Claims.ExtendIntoGroundDistance " , this . config_claims_claimsExtendIntoGroundDistance ) ;
config . set ( " GriefPrevention.Claims.CreationRequiresPermission " , this . config_claims_creationRequiresPermission ) ;
config . set ( " GriefPrevention.Claims.MinimumSize " , this . config_claims_minSize ) ;
config . set ( " GriefPrevention.Claims.MaximumDepth " , this . config_claims_maxDepth ) ;
2012-05-31 02:16:46 +00:00
config . set ( " GriefPrevention.Claims.IdleLimitDays " , this . config_claims_expirationDays ) ;
2012-03-30 00:27:12 +00:00
config . set ( " GriefPrevention.Claims.TrappedCommandCooldownHours " , this . config_claims_trappedCooldownHours ) ;
config . set ( " GriefPrevention.Spam.Enabled " , this . config_spam_enabled ) ;
config . set ( " GriefPrevention.Spam.LoginCooldownMinutes " , this . config_spam_loginCooldownMinutes ) ;
config . set ( " GriefPrevention.Spam.MonitorSlashCommands " , slashCommandsToMonitor ) ;
config . set ( " GriefPrevention.Spam.WarningMessage " , this . config_spam_warningMessage ) ;
config . set ( " GriefPrevention.Spam.BanOffenders " , this . config_spam_banOffenders ) ;
config . set ( " GriefPrevention.Spam.BanMessage " , this . config_spam_banMessage ) ;
config . set ( " GriefPrevention.Spam.AllowedIpAddresses " , this . config_spam_allowedIpAddresses ) ;
config . set ( " GriefPrevention.PvP.ProtectFreshSpawns " , this . config_pvp_protectFreshSpawns ) ;
config . set ( " GriefPrevention.PvP.PunishLogout " , this . config_pvp_punishLogout ) ;
2012-05-10 00:29:51 +00:00
config . set ( " GriefPrevention.PvP.CombatTimeoutSeconds " , this . config_pvp_combatTimeoutSeconds ) ;
config . set ( " GriefPrevention.PvP.AllowCombatItemDrop " , this . config_pvp_allowCombatItemDrop ) ;
2012-03-30 00:27:12 +00:00
config . set ( " GriefPrevention.Trees.RemoveFloatingTreetops " , this . config_trees_removeFloatingTreetops ) ;
config . set ( " GriefPrevention.Trees.RegrowGriefedTrees " , this . config_trees_regrowGriefedTrees ) ;
config . set ( " GriefPrevention.Economy.ClaimBlocksPurchaseCost " , this . config_economy_claimBlocksPurchaseCost ) ;
config . set ( " GriefPrevention.Economy.ClaimBlocksSellValue " , this . config_economy_claimBlocksSellValue ) ;
2012-05-31 02:16:46 +00:00
config . set ( " GriefPrevention.BlockSurfaceExplosions " , this . config_blockSurfaceExplosions ) ;
2012-03-30 00:27:12 +00:00
2012-04-17 02:00:21 +00:00
config . set ( " GriefPrevention.FireSpreads " , this . config_fireSpreads ) ;
config . set ( " GriefPrevention.FireDestroys " , this . config_fireDestroys ) ;
2012-05-10 00:29:51 +00:00
config . set ( " GriefPrevention.AddItemsToClaimedChests " , this . config_addItemsToClaimedChests ) ;
2012-05-23 03:31:42 +00:00
config . set ( " GriefPrevention.EavesdropEnabled " , this . config_eavesdrop ) ;
2012-05-10 00:29:51 +00:00
2012-05-31 02:16:46 +00:00
config . set ( " GriefPrevention.SmartBan " , this . config_smartBan ) ;
2012-04-17 02:00:21 +00:00
config . set ( " GriefPrevention.Siege.Worlds " , siegeEnabledWorldNames ) ;
2012-03-30 00:27:12 +00:00
config . set ( " GriefPrevention.Siege.BreakableBlocks " , breakableBlocksList ) ;
try
{
config . save ( DataStore . configFilePath ) ;
}
catch ( IOException exception )
{
AddLogEntry ( " Unable to write to the configuration file at \" " + DataStore . configFilePath + " \" " ) ;
}
//try to parse the list of commands which should be monitored for spam
this . config_spam_monitorSlashCommands = new ArrayList < String > ( ) ;
String [ ] commands = slashCommandsToMonitor . split ( " ; " ) ;
for ( int i = 0 ; i < commands . length ; i + + )
{
this . config_spam_monitorSlashCommands . add ( commands [ i ] . trim ( ) ) ;
}
//when datastore initializes, it loads player and claim data, and posts some stats to the log
this . dataStore = new DataStore ( ) ;
//unless claim block accrual is disabled, start the recurring per 5 minute event to give claim blocks to online players
//20L ~ 1 second
2012-04-17 02:00:21 +00:00
if ( this . config_claims_blocksAccruedPerHour > 0 )
{
DeliverClaimBlocksTask task = new DeliverClaimBlocksTask ( ) ;
this . getServer ( ) . getScheduler ( ) . scheduleSyncRepeatingTask ( this , task , 20L * 60 * 5 , 20L * 60 * 5 ) ;
}
2012-03-30 00:27:12 +00:00
//register for events
PluginManager pluginManager = this . getServer ( ) . getPluginManager ( ) ;
//player events
PlayerEventHandler playerEventHandler = new PlayerEventHandler ( this . dataStore , this ) ;
pluginManager . registerEvents ( playerEventHandler , this ) ;
//block events
BlockEventHandler blockEventHandler = new BlockEventHandler ( this . dataStore ) ;
pluginManager . registerEvents ( blockEventHandler , this ) ;
//entity events
EntityEventHandler entityEventHandler = new EntityEventHandler ( this . dataStore ) ;
pluginManager . registerEvents ( entityEventHandler , this ) ;
//if economy is enabled
if ( this . config_economy_claimBlocksPurchaseCost > 0 | | this . config_economy_claimBlocksSellValue > 0 )
{
//try to load Vault
GriefPrevention . AddLogEntry ( " GriefPrevention requires Vault for economy integration. " ) ;
GriefPrevention . AddLogEntry ( " Attempting to load Vault... " ) ;
RegisteredServiceProvider < Economy > economyProvider = getServer ( ) . getServicesManager ( ) . getRegistration ( net . milkbowl . vault . economy . Economy . class ) ;
GriefPrevention . AddLogEntry ( " Vault loaded successfully! " ) ;
//ask Vault to hook into an economy plugin
GriefPrevention . AddLogEntry ( " Looking for a Vault-compatible economy plugin... " ) ;
if ( economyProvider ! = null )
{
GriefPrevention . economy = economyProvider . getProvider ( ) ;
//on success, display success message
if ( GriefPrevention . economy ! = null )
{
GriefPrevention . AddLogEntry ( " Hooked into economy: " + GriefPrevention . economy . getName ( ) + " . " ) ;
GriefPrevention . AddLogEntry ( " Ready to buy/sell claim blocks! " ) ;
}
//otherwise error message
else
{
GriefPrevention . AddLogEntry ( " ERROR: Vault was unable to find a supported economy plugin. Either install a Vault-compatible economy plugin, or set both of the economy config variables to zero. " ) ;
}
}
//another error case
else
{
GriefPrevention . AddLogEntry ( " ERROR: Vault was unable to find a supported economy plugin. Either install a Vault-compatible economy plugin, or set both of the economy config variables to zero. " ) ;
}
}
}
//handles slash commands
public boolean onCommand ( CommandSender sender , Command cmd , String commandLabel , String [ ] args ) {
Player player = null ;
if ( sender instanceof Player )
{
player = ( Player ) sender ;
}
//abandonclaim
if ( cmd . getName ( ) . equalsIgnoreCase ( " abandonclaim " ) & & player ! = null )
{
2012-05-23 03:31:42 +00:00
return this . abandonClaimHandler ( player , false ) ;
2012-04-17 02:00:21 +00:00
}
//abandontoplevelclaim
if ( cmd . getName ( ) . equalsIgnoreCase ( " abandontoplevelclaim " ) & & player ! = null )
{
return this . abandonClaimHandler ( player , true ) ;
}
2012-03-30 00:27:12 +00:00
//ignoreclaims
if ( cmd . getName ( ) . equalsIgnoreCase ( " ignoreclaims " ) & & player ! = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . ignoreClaims = ! playerData . ignoreClaims ;
//toggle ignore claims mode on or off
if ( ! playerData . ignoreClaims )
{
GriefPrevention . sendMessage ( player , TextMode . Success , " Now respecting claims. " ) ;
}
else
{
GriefPrevention . sendMessage ( player , TextMode . Success , " Now ignoring claims. " ) ;
}
return true ;
}
//abandonallclaims
else if ( cmd . getName ( ) . equalsIgnoreCase ( " abandonallclaims " ) & & player ! = null )
{
2012-05-23 03:31:42 +00:00
if ( args . length ! = 0 ) return false ;
if ( creativeRulesApply ( player . getLocation ( ) ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Creative mode claims can't be abandoned. " ) ;
return true ;
}
2012-03-30 00:27:12 +00:00
//count claims
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
int originalClaimCount = playerData . claims . size ( ) ;
//check count
if ( originalClaimCount = = 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You haven't claimed any land. " ) ;
return true ;
}
//delete them
2012-05-23 03:31:42 +00:00
this . dataStore . deleteClaimsForPlayer ( player . getName ( ) , false ) ;
2012-03-30 00:27:12 +00:00
//inform the player
int remainingBlocks = playerData . getRemainingClaimBlocks ( ) ;
2012-05-23 03:31:42 +00:00
GriefPrevention . sendMessage ( player , TextMode . Success , " Claims abandoned. You now have " + String . valueOf ( remainingBlocks ) + " available claim blocks. " ) ;
2012-03-30 00:27:12 +00:00
//revert any current visualization
Visualization . Revert ( player ) ;
return true ;
}
//restore nature
else if ( cmd . getName ( ) . equalsIgnoreCase ( " restorenature " ) & & player ! = null )
{
//change shovel mode
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . RestoreNature ;
GriefPrevention . sendMessage ( player , TextMode . Instr , " Ready to restore some nature! Right click to restore nature, and use /BasicClaims to stop. " ) ;
return true ;
}
2012-05-31 02:16:46 +00:00
//restore nature aggressive mode
else if ( cmd . getName ( ) . equalsIgnoreCase ( " restorenatureaggressive " ) & & player ! = null )
{
//change shovel mode
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . RestoreNatureAggressive ;
GriefPrevention . sendMessage ( player , TextMode . Warn , " Aggressive mode activated. Do NOT use this underneath anything you want to keep! Right click to aggressively restore nature, and use /BasicClaims to stop. " ) ;
return true ;
}
//restore nature fill mode
else if ( cmd . getName ( ) . equalsIgnoreCase ( " restorenaturefill " ) & & player ! = null )
{
//change shovel mode
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . RestoreNatureFill ;
//set radius based on arguments
playerData . fillRadius = 2 ;
if ( args . length > 0 )
{
try
{
playerData . fillRadius = Integer . parseInt ( args [ 0 ] ) ;
}
catch ( Exception exception ) { }
}
if ( playerData . fillRadius < 0 ) playerData . fillRadius = 2 ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Fill mode activated with radius " + playerData . fillRadius + " . Right-click an area to fill. " ) ;
return true ;
}
2012-03-30 00:27:12 +00:00
//trust <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " trust " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
//most trust commands use this helper method, it keeps them consistent
this . handleTrustCommand ( player , ClaimPermission . Build , args [ 0 ] ) ;
return true ;
}
2012-05-01 03:11:39 +00:00
//transferclaim <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " transferclaim " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
//check additional permission
if ( ! player . hasPermission ( " griefprevention.adminclaims " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " That command requires the administrative claims permission. " ) ;
return true ;
}
//which claim is the user in?
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true , null ) ;
if ( claim = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Instr , " There's no claim here. Stand in the administrative claim you want to transfer. " ) ;
return true ;
}
else if ( ! claim . isAdminClaim ( ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Only administrative claims may be transferred to a player. " ) ;
return true ;
}
OfflinePlayer targetPlayer = this . resolvePlayer ( args [ 0 ] ) ;
if ( targetPlayer = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player not found. " ) ;
return true ;
}
//change ownerhsip
try
{
this . dataStore . changeClaimOwner ( claim , targetPlayer . getName ( ) ) ;
}
catch ( Exception e )
{
GriefPrevention . sendMessage ( player , TextMode . Instr , " Only top level claims (not subdivisions) may be transferred. Stand outside of the subdivision and try again. " ) ;
return true ;
}
//confirm
GriefPrevention . sendMessage ( player , TextMode . Success , " Claim transferred. " ) ;
2012-05-10 00:29:51 +00:00
GriefPrevention . AddLogEntry ( player . getName ( ) + " transferred a claim at " + GriefPrevention . getfriendlyLocationString ( claim . getLesserBoundaryCorner ( ) ) + " to " + targetPlayer . getName ( ) + " . " ) ;
2012-05-01 03:11:39 +00:00
return true ;
}
2012-03-30 00:27:12 +00:00
//trustlist
else if ( cmd . getName ( ) . equalsIgnoreCase ( " trustlist " ) & & player ! = null )
{
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true , null ) ;
//if no claim here, error message
if ( claim = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Stand inside the claim you're curious about. " ) ;
return true ;
}
//if no permission to manage permissions, error message
String errorMessage = claim . allowGrantPermission ( player ) ;
if ( errorMessage ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , errorMessage ) ;
return true ;
}
//otherwise build a list of explicit permissions by permission level
//and send that to the player
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 ) ;
player . sendMessage ( " Explicit permissions here: " ) ;
StringBuilder permissions = new StringBuilder ( ) ;
permissions . append ( ChatColor . GOLD + " M: " ) ;
if ( managers . size ( ) > 0 )
{
for ( int i = 0 ; i < managers . size ( ) ; i + + )
permissions . append ( managers . get ( i ) + " " ) ;
}
player . sendMessage ( permissions . toString ( ) ) ;
permissions = new StringBuilder ( ) ;
permissions . append ( ChatColor . YELLOW + " B: " ) ;
if ( builders . size ( ) > 0 )
{
for ( int i = 0 ; i < builders . size ( ) ; i + + )
permissions . append ( builders . get ( i ) + " " ) ;
}
player . sendMessage ( permissions . toString ( ) ) ;
permissions = new StringBuilder ( ) ;
permissions . append ( ChatColor . GREEN + " C: " ) ;
if ( containers . size ( ) > 0 )
{
for ( int i = 0 ; i < containers . size ( ) ; i + + )
permissions . append ( containers . get ( i ) + " " ) ;
}
player . sendMessage ( permissions . toString ( ) ) ;
permissions = new StringBuilder ( ) ;
permissions . append ( ChatColor . BLUE + " A : " ) ;
if ( accessors . size ( ) > 0 )
{
for ( int i = 0 ; i < accessors . size ( ) ; i + + )
permissions . append ( accessors . get ( i ) + " " ) ;
}
player . sendMessage ( permissions . toString ( ) ) ;
player . sendMessage ( " (M-anager, B-builder, C-ontainers, A-ccess) " ) ;
return true ;
}
//untrust <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " untrust " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
//determine which claim the player is standing in
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true /*ignore height*/ , null ) ;
//determine whether a single player or clearing permissions entirely
boolean clearPermissions = false ;
OfflinePlayer otherPlayer = null ;
if ( args [ 0 ] . equals ( " all " ) )
{
if ( claim = = null | | claim . allowEdit ( player ) = = null )
{
clearPermissions = true ;
}
else
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Only the claim owner can clear all permissions. " ) ;
return true ;
}
}
else
{
//validate player argument
otherPlayer = this . resolvePlayer ( args [ 0 ] ) ;
if ( ! clearPermissions & & otherPlayer = = null & & ! args [ 0 ] . equals ( " public " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player not found. " ) ;
return true ;
}
//correct to proper casing
if ( otherPlayer ! = null )
args [ 0 ] = otherPlayer . getName ( ) ;
}
//if no claim here, apply changes to all his claims
if ( claim = = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
for ( int i = 0 ; i < playerData . claims . size ( ) ; i + + )
{
claim = playerData . claims . get ( i ) ;
//if untrusting "all" drop all permissions
if ( clearPermissions )
{
claim . clearPermissions ( ) ;
}
//otherwise drop individual permissions
else
{
claim . dropPermission ( args [ 0 ] ) ;
claim . managers . remove ( args [ 0 ] ) ;
}
//save changes
this . dataStore . saveClaim ( claim ) ;
}
//beautify for output
if ( args [ 0 ] . equals ( " public " ) )
{
args [ 0 ] = " the public " ;
}
//confirmation message
if ( ! clearPermissions )
{
GriefPrevention . sendMessage ( player , TextMode . Success , " Revoked " + args [ 0 ] + " 's access to ALL your claims. To set permissions for a single claim, stand inside it. " ) ;
}
else
{
GriefPrevention . sendMessage ( player , TextMode . Success , " Cleared permissions in ALL your claims. To set permissions for a single claim, stand inside it. " ) ;
}
}
//otherwise, apply changes to only this claim
else if ( claim . allowGrantPermission ( player ) ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have " + claim . getOwnerName ( ) + " 's permission to manage permissions here. " ) ;
}
else
{
//if clearing all
if ( clearPermissions )
{
claim . clearPermissions ( ) ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Cleared permissions in this claim. To set permission for ALL your claims, stand outside them. " ) ;
}
//otherwise individual permission drop
else
{
claim . dropPermission ( args [ 0 ] ) ;
if ( claim . allowEdit ( player ) = = null )
{
claim . managers . remove ( args [ 0 ] ) ;
//beautify for output
if ( args [ 0 ] . equals ( " public " ) )
{
args [ 0 ] = " the public " ;
}
GriefPrevention . sendMessage ( player , TextMode . Success , " Revoked " + args [ 0 ] + " 's access to this claim. To set permissions for a ALL your claims, stand outside them. " ) ;
}
}
//save changes
this . dataStore . saveClaim ( claim ) ;
}
return true ;
}
//accesstrust <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " accesstrust " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
this . handleTrustCommand ( player , ClaimPermission . Access , args [ 0 ] ) ;
return true ;
}
//containertrust <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " containertrust " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
this . handleTrustCommand ( player , ClaimPermission . Inventory , args [ 0 ] ) ;
return true ;
}
//permissiontrust <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " permissiontrust " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
this . handleTrustCommand ( player , null , args [ 0 ] ) ; //null indicates permissiontrust to the helper method
return true ;
}
//buyclaimblocks
else if ( cmd . getName ( ) . equalsIgnoreCase ( " buyclaimblocks " ) & & player ! = null )
{
//if economy is disabled, don't do anything
if ( GriefPrevention . economy = = null ) return true ;
//if purchase disabled, send error message
if ( GriefPrevention . instance . config_economy_claimBlocksPurchaseCost = = 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Claim blocks may only be sold, not purchased. " ) ;
return true ;
}
//if no parameter, just tell player cost per block and balance
if ( args . length ! = 1 )
{
GriefPrevention . sendMessage ( player , TextMode . Info , " Each claim block costs " + GriefPrevention . instance . config_economy_claimBlocksPurchaseCost + " . Your balance is " + GriefPrevention . economy . getBalance ( player . getName ( ) ) + " . " ) ;
return false ;
}
else
{
2012-05-31 02:16:46 +00:00
//determine max purchasable blocks
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
int maxPurchasable = GriefPrevention . instance . config_claims_maxAccruedBlocks - playerData . accruedClaimBlocks ;
//if the player is at his max, tell him so
if ( maxPurchasable < = 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You've reached your claim block limit. You can't purchase more. " ) ;
return true ;
}
2012-03-30 00:27:12 +00:00
//try to parse number of blocks
int blockCount ;
try
{
blockCount = Integer . parseInt ( args [ 0 ] ) ;
}
catch ( NumberFormatException numberFormatException )
{
return false ; //causes usage to be displayed
}
2012-05-31 02:16:46 +00:00
//correct block count to max allowed
if ( blockCount > maxPurchasable )
{
blockCount = maxPurchasable ;
}
2012-03-30 00:27:12 +00:00
//if the player can't afford his purchase, send error message
double balance = economy . getBalance ( player . getName ( ) ) ;
double totalCost = blockCount * GriefPrevention . instance . config_economy_claimBlocksPurchaseCost ;
if ( totalCost > balance )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have enough money. You need " + totalCost + " , but you only have " + balance + " . " ) ;
}
//otherwise carry out transaction
else
{
//withdraw cost
economy . withdrawPlayer ( player . getName ( ) , totalCost ) ;
//add blocks
2012-05-31 02:16:46 +00:00
playerData . accruedClaimBlocks + = blockCount ;
2012-03-30 00:27:12 +00:00
this . dataStore . savePlayerData ( player . getName ( ) , playerData ) ;
//inform player
GriefPrevention . sendMessage ( player , TextMode . Success , " Withdrew " + totalCost + " from your account. You now have " + playerData . getRemainingClaimBlocks ( ) + " available claim blocks. " ) ;
}
return true ;
}
}
//sellclaimblocks <amount>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " sellclaimblocks " ) & & player ! = null )
{
//if economy is disabled, don't do anything
if ( GriefPrevention . economy = = null ) return true ;
//if disabled, error message
if ( GriefPrevention . instance . config_economy_claimBlocksSellValue = = 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Claim blocks may only be purchased, not sold. " ) ;
return true ;
}
//load player data
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
int availableBlocks = playerData . getRemainingClaimBlocks ( ) ;
//if no amount provided, just tell player value per block sold, and how many he can sell
if ( args . length ! = 1 )
{
GriefPrevention . sendMessage ( player , TextMode . Info , " Each claim block is worth " + GriefPrevention . instance . config_economy_claimBlocksSellValue + " . You have " + availableBlocks + " available for sale. " ) ;
return false ;
}
//parse number of blocks
int blockCount ;
try
{
blockCount = Integer . parseInt ( args [ 0 ] ) ;
}
catch ( NumberFormatException numberFormatException )
{
return false ; //causes usage to be displayed
}
//if he doesn't have enough blocks, tell him so
if ( blockCount > availableBlocks )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have that many claim blocks available for sale. " ) ;
}
//otherwise carry out the transaction
else
{
//compute value and deposit it
double totalValue = blockCount * GriefPrevention . instance . config_economy_claimBlocksSellValue ;
economy . depositPlayer ( player . getName ( ) , totalValue ) ;
//subtract blocks
2012-05-31 02:16:46 +00:00
playerData . accruedClaimBlocks - = blockCount ;
2012-03-30 00:27:12 +00:00
this . dataStore . savePlayerData ( player . getName ( ) , playerData ) ;
//inform player
GriefPrevention . sendMessage ( player , TextMode . Success , " Deposited " + totalValue + " in your account. You now have " + playerData . getRemainingClaimBlocks ( ) + " available claim blocks. " ) ;
}
return true ;
}
//adminclaims
else if ( cmd . getName ( ) . equalsIgnoreCase ( " adminclaims " ) & & player ! = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . Admin ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Administrative claims mode active. Any claims created will be free and editable by other administrators. " ) ;
return true ;
}
//basicclaims
else if ( cmd . getName ( ) . equalsIgnoreCase ( " basicclaims " ) & & player ! = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . Basic ;
playerData . claimSubdividing = null ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Returned to basic claim creation mode. " ) ;
return true ;
}
//subdivideclaims
else if ( cmd . getName ( ) . equalsIgnoreCase ( " subdivideclaims " ) & & player ! = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . shovelMode = ShovelMode . Subdivide ;
playerData . claimSubdividing = null ;
GriefPrevention . sendMessage ( player , TextMode . Instr , " Subdivision mode. Use your shovel to create subdivisions in your existing claims. Use /basicclaims to exit. " ) ;
return true ;
}
//deleteclaim
else if ( cmd . getName ( ) . equalsIgnoreCase ( " deleteclaim " ) & & player ! = null )
{
//determine which claim the player is standing in
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true /*ignore height*/ , null ) ;
if ( claim = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " There's no claim here. " ) ;
}
else
{
//deleting an admin claim additionally requires the adminclaims permission
if ( ! claim . isAdminClaim ( ) | | player . hasPermission ( " griefprevention.adminclaims " ) )
{
2012-05-31 02:16:46 +00:00
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
if ( claim . children . size ( ) > 0 & & ! playerData . warnedAboutMajorDeletion )
{
GriefPrevention . sendMessage ( player , TextMode . Warn , " This claim includes subdivisions. If you're sure you want to delete it, use /DeleteClaim again. " ) ;
playerData . warnedAboutMajorDeletion = true ;
}
else
{
claim . removeSurfaceFluids ( null ) ;
this . dataStore . deleteClaim ( claim ) ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Claim deleted. " ) ;
GriefPrevention . AddLogEntry ( player . getName ( ) + " deleted " + claim . getOwnerName ( ) + " 's claim at " + GriefPrevention . getfriendlyLocationString ( claim . getLesserBoundaryCorner ( ) ) ) ;
//revert any current visualization
Visualization . Revert ( player ) ;
playerData . warnedAboutMajorDeletion = false ;
}
2012-03-30 00:27:12 +00:00
}
else
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have permission to delete administrative claims. " ) ;
}
}
return true ;
}
//deleteallclaims <player>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " deleteallclaims " ) & & player ! = null )
{
//requires exactly one parameter, the other player's name
if ( args . length ! = 1 ) return false ;
//try to find that player
OfflinePlayer otherPlayer = this . resolvePlayer ( args [ 0 ] ) ;
if ( otherPlayer = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player not found. " ) ;
return true ;
}
//delete all that player's claims
2012-05-23 03:31:42 +00:00
this . dataStore . deleteClaimsForPlayer ( otherPlayer . getName ( ) , true ) ;
2012-03-30 00:27:12 +00:00
GriefPrevention . sendMessage ( player , TextMode . Success , " Deleted all of " + otherPlayer . getName ( ) + " 's claims. " ) ;
//revert any current visualization
Visualization . Revert ( player ) ;
return true ;
}
//deletealladminclaims
else if ( cmd . getName ( ) . equalsIgnoreCase ( " deletealladminclaims " ) & & player ! = null )
{
if ( ! player . hasPermission ( " griefprevention.deleteclaims " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have permission to delete claims. " ) ;
return true ;
}
//delete all admin claims
2012-05-23 03:31:42 +00:00
this . dataStore . deleteClaimsForPlayer ( " " , true ) ; //empty string for owner name indicates an administrative claim
2012-03-30 00:27:12 +00:00
GriefPrevention . sendMessage ( player , TextMode . Success , " Deleted all administrative claims. " ) ;
//revert any current visualization
Visualization . Revert ( player ) ;
return true ;
}
//adjustbonusclaimblocks <player> <amount>
else if ( cmd . getName ( ) . equalsIgnoreCase ( " adjustbonusclaimblocks " ) & & player ! = null )
{
//requires exactly two parameters, the other player's name and the adjustment
if ( args . length ! = 2 ) return false ;
//find the specified player
OfflinePlayer targetPlayer = this . resolvePlayer ( args [ 0 ] ) ;
if ( targetPlayer = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player \" " + args [ 0 ] + " \" not found. " ) ;
return true ;
}
//parse the adjustment amount
int adjustment ;
try
{
adjustment = Integer . parseInt ( args [ 1 ] ) ;
}
catch ( NumberFormatException numberFormatException )
{
return false ; //causes usage to be displayed
}
//give blocks to player
PlayerData playerData = this . dataStore . getPlayerData ( targetPlayer . getName ( ) ) ;
playerData . bonusClaimBlocks + = adjustment ;
this . dataStore . savePlayerData ( targetPlayer . getName ( ) , playerData ) ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Adjusted " + targetPlayer . getName ( ) + " 's bonus claim blocks by " + adjustment + " . New total bonus blocks: " + playerData . bonusClaimBlocks + " . " ) ;
2012-05-10 00:29:51 +00:00
GriefPrevention . AddLogEntry ( player . getName ( ) + " adjusted " + targetPlayer . getName ( ) + " 's bonus claim blocks by " + adjustment + " . " ) ;
2012-03-30 00:27:12 +00:00
return true ;
}
//trapped
else if ( cmd . getName ( ) . equalsIgnoreCase ( " trapped " ) & & player ! = null )
{
//FEATURE: empower players who get "stuck" in an area where they don't have permission to build to save themselves
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , false , playerData . lastClaim ) ;
//if another /trapped is pending, ignore this slash command
if ( playerData . pendingTrapped )
{
return true ;
}
//if the player isn't in a claim or has permission to build, tell him to man up
if ( claim = = null | | claim . allowBuild ( player ) = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You can build here. Save yourself. " ) ;
return true ;
}
//check cooldown
long lastTrappedUsage = playerData . lastTrappedUsage . getTime ( ) ;
long nextTrappedUsage = lastTrappedUsage + 1000 * 60 * 60 * this . config_claims_trappedCooldownHours ;
long now = Calendar . getInstance ( ) . getTimeInMillis ( ) ;
if ( now < nextTrappedUsage )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You used /trapped within the last " + this . config_claims_trappedCooldownHours + " hours. You have to wait about " + ( ( nextTrappedUsage - now ) / ( 1000 * 60 ) + 1 ) + " more minutes before using it again. " ) ;
return true ;
}
//send instructions
GriefPrevention . sendMessage ( player , TextMode . Instr , " If you stay put for 10 seconds, you'll be teleported out. Please wait. " ) ;
//create a task to rescue this player in a little while
PlayerRescueTask task = new PlayerRescueTask ( player , player . getLocation ( ) ) ;
this . getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( this , task , 200L ) ; //20L ~ 1 second
return true ;
}
//siege
else if ( cmd . getName ( ) . equalsIgnoreCase ( " siege " ) & & player ! = null )
{
//error message for when siege mode is disabled
2012-04-17 02:00:21 +00:00
if ( ! this . siegeEnabledForWorld ( player . getWorld ( ) ) )
2012-03-30 00:27:12 +00:00
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Siege is disabled here. " ) ;
return true ;
}
//requires one argument
if ( args . length > 1 )
{
return false ;
}
//can't start a siege when you're already involved in one
Player attacker = player ;
PlayerData attackerData = this . dataStore . getPlayerData ( attacker . getName ( ) ) ;
if ( attackerData . siegeData ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You're already involved in a siege. " ) ;
return true ;
}
//if a player name was specified, use that
Player defender = null ;
if ( args . length > = 1 )
{
defender = this . getServer ( ) . getPlayer ( args [ 0 ] ) ;
if ( defender = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player not found. " ) ;
return true ;
}
}
//otherwise use the last player this player was in pvp combat with
else if ( attackerData . lastPvpPlayer . length ( ) > 0 )
{
defender = this . getServer ( ) . getPlayer ( attackerData . lastPvpPlayer ) ;
if ( defender = = null )
{
return false ;
}
}
else
{
return false ;
}
//victim must not be under siege already
PlayerData defenderData = this . dataStore . getPlayerData ( defender . getName ( ) ) ;
if ( defenderData . siegeData ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , defender . getName ( ) + " is already under siege. Join the party! " ) ;
return true ;
}
2012-04-17 02:00:21 +00:00
//victim must not be pvp immune
if ( defenderData . pvpImmune )
{
GriefPrevention . sendMessage ( player , TextMode . Err , defender . getName ( ) + " is defenseless. Go pick on somebody else. " ) ;
return true ;
}
2012-03-30 00:27:12 +00:00
Claim defenderClaim = this . dataStore . getClaimAt ( defender . getLocation ( ) , false , null ) ;
2012-04-17 02:00:21 +00:00
//defender must have some level of permission there to be protected
if ( defenderClaim = = null | | defenderClaim . allowAccess ( defender ) ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , defender . getName ( ) + " isn't protected there. " ) ;
return true ;
}
2012-03-30 00:27:12 +00:00
//attacker must be close to the claim he wants to siege
if ( ! defenderClaim . isNear ( attacker . getLocation ( ) , 25 ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You're too far away from " + defender . getName ( ) + " to siege. " ) ;
return true ;
}
//claim can't be under siege already
if ( defenderClaim . siegeData ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " That area is already under siege. Join the party! " ) ;
return true ;
}
//can't siege admin claims
if ( defenderClaim . isAdminClaim ( ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Siege is disabled in this area. " ) ;
return true ;
}
//can't be on cooldown
if ( dataStore . onCooldown ( attacker , defender , defenderClaim ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You're still on siege cooldown for this defender or claim. Find another victim. " ) ;
return true ;
}
//start the siege
dataStore . startSiege ( attacker , defender , defenderClaim ) ;
//confirmation message for attacker, warning message for defender
2012-04-17 02:00:21 +00:00
GriefPrevention . sendMessage ( defender , TextMode . Warn , " You're under siege! If you log out now, you will die. You must defeat " + attacker . getName ( ) + " , wait for him to give up, or escape. " ) ;
2012-03-30 00:27:12 +00:00
GriefPrevention . sendMessage ( player , TextMode . Success , " The siege has begun! If you log out now, you will die. You must defeat " + defender . getName ( ) + " , chase him away, or admit defeat and walk away. " ) ;
}
return false ;
}
2012-05-10 00:29:51 +00:00
public static String getfriendlyLocationString ( Location location )
{
return location . getWorld ( ) . getName ( ) + " ( " + location . getBlockX ( ) + " , " + location . getBlockY ( ) + " , " + location . getBlockZ ( ) + " ) " ;
}
2012-04-17 02:00:21 +00:00
private boolean abandonClaimHandler ( Player player , boolean deleteTopLevelClaim )
{
//which claim is being abandoned?
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true /*ignore height*/ , null ) ;
if ( claim = = null )
{
GriefPrevention . sendMessage ( player , TextMode . Instr , " Stand in the claim you want to delete, or consider /AbandonAllClaims. " ) ;
2012-05-23 03:31:42 +00:00
}
else if ( this . creativeRulesApply ( player . getLocation ( ) ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Creative-mode claims can't be abandoned. " ) ;
}
2012-04-17 02:00:21 +00:00
//verify ownership
else if ( claim . allowEdit ( player ) ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " This isn't your claim. " ) ;
}
//warn if has children and we're not explicitly deleting a top level claim
else if ( claim . children . size ( ) > 0 & & ! deleteTopLevelClaim )
{
GriefPrevention . sendMessage ( player , TextMode . Instr , " To delete a subdivision, stand inside it. Otherwise, use /AbandonTopLevelClaim to delete this claim and all subdivisions. " ) ;
return true ;
}
else
{
//delete it
2012-05-31 02:16:46 +00:00
claim . removeSurfaceFluids ( null ) ;
2012-04-17 02:00:21 +00:00
this . dataStore . deleteClaim ( claim ) ;
//tell the player how many claim blocks he has left
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
int remainingBlocks = playerData . getRemainingClaimBlocks ( ) ;
GriefPrevention . sendMessage ( player , TextMode . Success , " Claim abandoned. You now have " + String . valueOf ( remainingBlocks ) + " available claim blocks. " ) ;
//revert any current visualization
Visualization . Revert ( player ) ;
}
return true ;
}
2012-03-30 00:27:12 +00:00
//helper method keeps the trust commands consistent and eliminates duplicate code
private void handleTrustCommand ( Player player , ClaimPermission permissionLevel , String recipientName )
{
//determine which claim the player is standing in
Claim claim = this . dataStore . getClaimAt ( player . getLocation ( ) , true /*ignore height*/ , null ) ;
//validate player argument
OfflinePlayer otherPlayer = this . resolvePlayer ( recipientName ) ;
if ( otherPlayer = = null & & ! recipientName . equals ( " public " ) )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Player not found. " ) ;
return ;
}
if ( otherPlayer ! = null )
{
recipientName = otherPlayer . getName ( ) ;
}
else
{
recipientName = " public " ;
}
//determine which claims should be modified
ArrayList < Claim > targetClaims = new ArrayList < Claim > ( ) ;
if ( claim = = null )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
for ( int i = 0 ; i < playerData . claims . size ( ) ; i + + )
{
targetClaims . add ( playerData . claims . get ( i ) ) ;
}
}
else
{
//check permission here
if ( claim . allowGrantPermission ( player ) ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " You don't have " + claim . getOwnerName ( ) + " 's permission to grant permissions here. " ) ;
return ;
}
//see if the player has the level of permission he's trying to grant
String errorMessage = null ;
//permission level null indicates granting permission trust
if ( permissionLevel = = null )
{
errorMessage = claim . allowEdit ( player ) ;
if ( errorMessage ! = null )
{
errorMessage = " Only " + claim . getOwnerName ( ) + " can grant /PermissionTrust here. " ;
}
}
//otherwise just use the ClaimPermission enum values
else
{
switch ( permissionLevel )
{
case Access :
errorMessage = claim . allowAccess ( player ) ;
break ;
case Inventory :
errorMessage = claim . allowContainers ( player ) ;
break ;
default :
errorMessage = claim . allowBuild ( player ) ;
}
}
//error message for trying to grant a permission the player doesn't have
if ( errorMessage ! = null )
{
GriefPrevention . sendMessage ( player , TextMode . Err , errorMessage + " You can't grant a permission you don't have yourself. " ) ;
return ;
}
targetClaims . add ( claim ) ;
}
//if we didn't determine which claims to modify, tell the player to be specific
if ( targetClaims . size ( ) = = 0 )
{
GriefPrevention . sendMessage ( player , TextMode . Err , " Stand inside the claim where you want to grant permission. " ) ;
return ;
}
//apply changes
for ( int i = 0 ; i < targetClaims . size ( ) ; i + + )
{
Claim currentClaim = targetClaims . get ( i ) ;
if ( permissionLevel = = null )
{
if ( ! currentClaim . managers . contains ( recipientName ) )
{
currentClaim . managers . add ( recipientName ) ;
}
}
else
{
currentClaim . setPermission ( recipientName , permissionLevel ) ;
}
this . dataStore . saveClaim ( currentClaim ) ;
}
//notify player
if ( recipientName . equals ( " public " ) ) recipientName = " the public " ;
StringBuilder resultString = new StringBuilder ( ) ;
resultString . append ( " Granted " + recipientName + " " ) ;
if ( permissionLevel = = null )
{
resultString . append ( " manager status " ) ;
}
else if ( permissionLevel = = ClaimPermission . Build )
{
resultString . append ( " permission to build in " ) ;
}
else if ( permissionLevel = = ClaimPermission . Access )
{
resultString . append ( " permission to use buttons and levers in " ) ;
}
else if ( permissionLevel = = ClaimPermission . Inventory )
{
resultString . append ( " permission to access containers in " ) ;
}
if ( claim = = null )
{
resultString . append ( " ALL your claims. To modify only one claim, stand inside it. " ) ;
}
else
{
resultString . append ( " this claim. To modify ALL your claims, stand outside them. " ) ;
}
GriefPrevention . sendMessage ( player , TextMode . Success , resultString . toString ( ) ) ;
}
//helper method to resolve a player by name
private OfflinePlayer resolvePlayer ( String name )
{
//try online players first
Player player = this . getServer ( ) . getPlayer ( name ) ;
if ( player ! = null ) return player ;
//then search offline players
OfflinePlayer [ ] offlinePlayers = this . getServer ( ) . getOfflinePlayers ( ) ;
for ( int i = 0 ; i < offlinePlayers . length ; i + + )
{
if ( offlinePlayers [ i ] . getName ( ) . equalsIgnoreCase ( name ) )
{
return offlinePlayers [ i ] ;
}
}
//if none found, return null
return null ;
}
public void onDisable ( )
{
AddLogEntry ( " GriefPrevention disabled. " ) ;
}
//called when a player spawns, applies protection for that player if necessary
public void checkPvpProtectionNeeded ( Player player )
{
//if pvp is disabled, do nothing
if ( ! player . getWorld ( ) . getPVP ( ) ) return ;
//if anti spawn camping feature is not enabled, do nothing
if ( ! this . config_pvp_protectFreshSpawns ) return ;
//check inventory for well, anything
PlayerInventory inventory = player . getInventory ( ) ;
ItemStack [ ] armorStacks = inventory . getArmorContents ( ) ;
//check armor slots, stop if any items are found
for ( int i = 0 ; i < armorStacks . length ; i + + )
{
if ( ! ( armorStacks [ i ] = = null | | armorStacks [ i ] . getType ( ) = = Material . AIR ) ) return ;
}
//check other slots, stop if any items are found
ItemStack [ ] generalStacks = inventory . getContents ( ) ;
for ( int i = 0 ; i < generalStacks . length ; i + + )
{
if ( ! ( generalStacks [ i ] = = null | | generalStacks [ i ] . getType ( ) = = Material . AIR ) ) return ;
}
//otherwise, apply immunity
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
playerData . pvpImmune = true ;
//inform the player
2012-04-17 02:00:21 +00:00
GriefPrevention . sendMessage ( player , TextMode . Success , " You're protected from attack by other players as long as your inventory is empty. " ) ;
2012-03-30 00:27:12 +00:00
}
//checks whether players can create claims in a world
public boolean claimsEnabledForWorld ( World world )
{
return this . config_claims_enabledWorlds . contains ( world ) ;
}
//checks whether players siege in a world
public boolean siegeEnabledForWorld ( World world )
{
return this . config_siege_enabledWorlds . contains ( world ) ;
}
//processes broken log blocks to automatically remove floating treetops
void handleLogBroken ( Block block )
{
//find the lowest log in the tree trunk including this log
Block rootBlock = this . getRootBlock ( block ) ;
//null indicates this block isn't part of a tree trunk
if ( rootBlock = = null ) return ;
//next step: scan for other log blocks and leaves in this tree
//set boundaries for the scan
int min_x = rootBlock . getX ( ) - GriefPrevention . TREE_RADIUS ;
int max_x = rootBlock . getX ( ) + GriefPrevention . TREE_RADIUS ;
int min_z = rootBlock . getZ ( ) - GriefPrevention . TREE_RADIUS ;
int max_z = rootBlock . getZ ( ) + GriefPrevention . TREE_RADIUS ;
int max_y = rootBlock . getWorld ( ) . getMaxHeight ( ) - 1 ;
//keep track of all the examined blocks, and all the log blocks found
ArrayList < Block > examinedBlocks = new ArrayList < Block > ( ) ;
ArrayList < Block > treeBlocks = new ArrayList < Block > ( ) ;
//queue the first block, which is the block immediately above the player-chopped block
ConcurrentLinkedQueue < Block > blocksToExamine = new ConcurrentLinkedQueue < Block > ( ) ;
blocksToExamine . add ( rootBlock ) ;
examinedBlocks . add ( rootBlock ) ;
boolean hasLeaves = false ;
while ( ! blocksToExamine . isEmpty ( ) )
{
//pop a block from the queue
Block currentBlock = blocksToExamine . remove ( ) ;
//if this is a log block, determine whether it should be chopped
if ( currentBlock . getType ( ) = = Material . LOG )
{
boolean partOfTree = false ;
//if it's stacked with the original chopped block, the answer is always yes
if ( currentBlock . getX ( ) = = block . getX ( ) & & currentBlock . getZ ( ) = = block . getZ ( ) )
{
partOfTree = true ;
}
//otherwise find the block underneath this stack of logs
else
{
Block downBlock = currentBlock . getRelative ( BlockFace . DOWN ) ;
while ( downBlock . getType ( ) = = Material . LOG )
{
downBlock = downBlock . getRelative ( BlockFace . DOWN ) ;
}
//if it's air or leaves, it's okay to chop this block
//this avoids accidentally chopping neighboring trees which are close enough to touch their leaves to ours
if ( downBlock . getType ( ) = = Material . AIR | | downBlock . getType ( ) = = Material . LEAVES )
{
partOfTree = true ;
}
//otherwise this is a stack of logs which touches a solid surface
//if it's close to the original block's stack, don't clean up this tree (just stop here)
else
{
if ( Math . abs ( downBlock . getX ( ) - block . getX ( ) ) < = 1 & & Math . abs ( downBlock . getZ ( ) - block . getZ ( ) ) < = 1 ) return ;
}
}
if ( partOfTree )
{
treeBlocks . add ( currentBlock ) ;
}
}
//if this block is a log OR a leaf block, also check its neighbors
if ( currentBlock . getType ( ) = = Material . LOG | | currentBlock . getType ( ) = = Material . LEAVES )
{
if ( currentBlock . getType ( ) = = Material . LEAVES )
{
hasLeaves = true ;
}
Block [ ] neighboringBlocks = new Block [ ]
{
currentBlock . getRelative ( BlockFace . EAST ) ,
currentBlock . getRelative ( BlockFace . WEST ) ,
currentBlock . getRelative ( BlockFace . NORTH ) ,
currentBlock . getRelative ( BlockFace . SOUTH ) ,
currentBlock . getRelative ( BlockFace . UP ) ,
currentBlock . getRelative ( BlockFace . DOWN )
} ;
for ( int i = 0 ; i < neighboringBlocks . length ; i + + )
{
Block neighboringBlock = neighboringBlocks [ i ] ;
//if the neighboringBlock is out of bounds, skip it
if ( neighboringBlock . getX ( ) < min_x | | neighboringBlock . getX ( ) > max_x | | neighboringBlock . getZ ( ) < min_z | | neighboringBlock . getZ ( ) > max_z | | neighboringBlock . getY ( ) > max_y ) continue ;
//if we already saw this block, skip it
if ( examinedBlocks . contains ( neighboringBlock ) ) continue ;
//mark the block as examined
examinedBlocks . add ( neighboringBlock ) ;
//if the neighboringBlock is a leaf or log, put it in the queue to be examined later
if ( neighboringBlock . getType ( ) = = Material . LOG | | neighboringBlock . getType ( ) = = Material . LEAVES )
{
blocksToExamine . add ( neighboringBlock ) ;
}
//if we encounter any player-placed block type, bail out (don't automatically remove parts of this tree, it might support a treehouse!)
else if ( this . isPlayerBlock ( neighboringBlock ) )
{
return ;
}
}
}
}
//if it doesn't have leaves, it's not a tree, so don't clean it up
if ( hasLeaves )
{
//schedule a cleanup task for later, in case the player leaves part of this tree hanging in the air
TreeCleanupTask cleanupTask = new TreeCleanupTask ( block , rootBlock , treeBlocks ) ;
2012-05-31 02:16:46 +00:00
//20L ~ 1 second, so 2 mins = 120 seconds ~ 2400L
GriefPrevention . instance . getServer ( ) . getScheduler ( ) . scheduleSyncDelayedTask ( GriefPrevention . instance , cleanupTask , 2400L ) ;
2012-03-30 00:27:12 +00:00
}
}
//helper for above, finds the "root" of a stack of logs
//will return null if the stack is determined to not be a natural tree
private Block getRootBlock ( Block logBlock )
{
if ( logBlock . getType ( ) ! = Material . LOG ) return null ;
//run down through log blocks until finding a non-log block
Block underBlock = logBlock . getRelative ( BlockFace . DOWN ) ;
while ( underBlock . getType ( ) = = Material . LOG )
{
underBlock = underBlock . getRelative ( BlockFace . DOWN ) ;
}
//if this is a standard tree, that block MUST be dirt
if ( underBlock . getType ( ) ! = Material . DIRT ) return null ;
//run up through log blocks until finding a non-log block
Block aboveBlock = logBlock . getRelative ( BlockFace . UP ) ;
while ( aboveBlock . getType ( ) = = Material . LOG )
{
aboveBlock = aboveBlock . getRelative ( BlockFace . UP ) ;
}
//if this is a standard tree, that block MUST be air or leaves
if ( aboveBlock . getType ( ) ! = Material . AIR & & aboveBlock . getType ( ) ! = Material . LEAVES ) return null ;
return underBlock . getRelative ( BlockFace . UP ) ;
}
//for sake of identifying trees ONLY, a cheap but not 100% reliable method for identifying player-placed blocks
private boolean isPlayerBlock ( Block block )
{
Material material = block . getType ( ) ;
//list of natural blocks which are OK to have next to a log block in a natural tree setting
if ( material = = Material . AIR | |
material = = Material . LEAVES | |
material = = Material . LOG | |
material = = Material . DIRT | |
material = = Material . GRASS | |
material = = Material . STATIONARY_WATER | |
material = = Material . BROWN_MUSHROOM | |
material = = Material . RED_MUSHROOM | |
material = = Material . RED_ROSE | |
material = = Material . LONG_GRASS | |
material = = Material . SNOW | |
material = = Material . STONE | |
material = = Material . VINE | |
material = = Material . WATER_LILY | |
material = = Material . YELLOW_FLOWER | |
material = = Material . CLAY )
{
return false ;
}
else
{
return true ;
}
}
//moves a player from the claim he's in to a nearby wilderness location
public Location ejectPlayer ( Player player )
{
//look for a suitable location
Location candidateLocation = player . getLocation ( ) ;
while ( true )
{
Claim claim = null ;
claim = GriefPrevention . instance . dataStore . getClaimAt ( candidateLocation , false , null ) ;
//if there's a claim here, keep looking
if ( claim ! = null )
{
candidateLocation = new Location ( claim . lesserBoundaryCorner . getWorld ( ) , claim . lesserBoundaryCorner . getBlockX ( ) - 1 , claim . lesserBoundaryCorner . getBlockY ( ) , claim . lesserBoundaryCorner . getBlockZ ( ) - 1 ) ;
continue ;
}
//otherwise find a safe place to teleport the player
else
{
//find a safe height, a couple of blocks above the surface
GuaranteeChunkLoaded ( candidateLocation ) ;
Block highestBlock = candidateLocation . getWorld ( ) . getHighestBlockAt ( candidateLocation . getBlockX ( ) , candidateLocation . getBlockZ ( ) ) ;
Location destination = new Location ( highestBlock . getWorld ( ) , highestBlock . getX ( ) , highestBlock . getY ( ) + 2 , highestBlock . getZ ( ) ) ;
player . teleport ( destination ) ;
return destination ;
}
}
}
//ensures a piece of the managed world is loaded into server memory
//(generates the chunk if necessary)
private static void GuaranteeChunkLoaded ( Location location )
{
Chunk chunk = location . getChunk ( ) ;
while ( ! chunk . isLoaded ( ) | | ! chunk . load ( true ) ) ;
}
//sends a color-coded message to a player
static void sendMessage ( Player player , ChatColor color , String message )
{
player . sendMessage ( color + message ) ;
}
2012-05-23 03:31:42 +00:00
//determines whether creative anti-grief rules apply at a location
boolean creativeRulesApply ( Location location )
{
return this . config_claims_enabledCreativeWorlds . contains ( location . getWorld ( ) ) ;
}
public String allowBuild ( Player player , Location location )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
Claim claim = this . dataStore . getClaimAt ( location , false , playerData . lastClaim ) ;
//wilderness rules
if ( claim = = null )
{
//no building in the wilderness in creative mode
if ( this . creativeRulesApply ( location ) )
{
//exception: administrators in ignore claims mode
if ( playerData . ignoreClaims ) return null ;
return " You can't build here. Use the golden shovel to claim some land first. " ;
}
//but it's fine in survival mode
else
{
//cache the claim for later reference
playerData . lastClaim = claim ;
return null ;
}
}
//if not in the wilderness, then apply claim rules (permissions, etc)
return claim . allowBuild ( player ) ;
}
public String allowBreak ( Player player , Location location )
{
PlayerData playerData = this . dataStore . getPlayerData ( player . getName ( ) ) ;
Claim claim = this . dataStore . getClaimAt ( location , false , playerData . lastClaim ) ;
//wilderness rules
if ( claim = = null )
{
//no building in the wilderness in creative mode
if ( this . creativeRulesApply ( location ) )
{
//exception: administrators in ignore claims mode
if ( playerData . ignoreClaims ) return null ;
return " You can't build here. Use the golden shovel to claim some land first. " ;
}
//but it's fine in survival mode
else
{
//cache the claim for later reference
playerData . lastClaim = claim ;
return null ;
}
}
//if not in the wilderness, then apply claim rules (permissions, etc)
return claim . allowBreak ( player , location . getBlock ( ) . getType ( ) ) ;
}
2012-03-30 00:27:12 +00:00
}