This commit is contained in:
Ryan Hamshire 2012-11-14 17:33:22 -08:00
parent e09a6732ba
commit 7f600e7098
30 changed files with 1266 additions and 1087 deletions

View File

@ -2,7 +2,7 @@ name: GriefPrevention
main: me.ryanhamshire.GriefPrevention.GriefPrevention main: me.ryanhamshire.GriefPrevention.GriefPrevention
softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter] softdepend: [Vault, Multiverse-Core, My Worlds, MystCraft, Transporter]
dev-url: http://dev.bukkit.org/server-mods/grief-prevention dev-url: http://dev.bukkit.org/server-mods/grief-prevention
version: 6.9 version: 7.0
commands: commands:
abandonclaim: abandonclaim:
description: Deletes a claim. description: Deletes a claim.
@ -89,12 +89,12 @@ commands:
description: Purchases additional claim blocks with server money. Doesn't work on servers without a Vault-compatible economy plugin. description: Purchases additional claim blocks with server money. Doesn't work on servers without a Vault-compatible economy plugin.
usage: /BuyClaimBlocks <numberOfBlocks> usage: /BuyClaimBlocks <numberOfBlocks>
aliases: buyclaim aliases: buyclaim
permission: griefprevention.claims permission: griefprevention.buysellclaimblocks
sellclaimblocks: sellclaimblocks:
description: Sells your claim blocks for server money. Doesn't work on servers without a Vault-compatible economy plugin. description: Sells your claim blocks for server money. Doesn't work on servers without a Vault-compatible economy plugin.
usage: /SellClaimBlocks <numberOfBlocks> usage: /SellClaimBlocks <numberOfBlocks>
aliases: sellclaim aliases: sellclaim
permission: griefprevention.claims permission: griefprevention.buysellclaimblocks
trapped: trapped:
description: Ejects you to nearby unclaimed land. Has a substantial cooldown period. description: Ejects you to nearby unclaimed land. Has a substantial cooldown period.
usage: /Trapped usage: /Trapped
@ -124,8 +124,7 @@ commands:
permission: griefprevention.deathblow permission: griefprevention.deathblow
claimslist: claimslist:
description: Lists information about a player's claim blocks and claims. description: Lists information about a player's claim blocks and claims.
usage: /ClaimsList <player> usage: /ClaimsList or /ClaimsList <player>
permission: griefprevention.adjustclaimblocks
permissions: permissions:
griefprevention.createclaims: griefprevention.createclaims:
description: Grants permission to create claims. description: Grants permission to create claims.
@ -175,4 +174,7 @@ permissions:
default: op default: op
griefprevention.claims: griefprevention.claims:
description: Grants access to claim-related slash commands. description: Grants access to claim-related slash commands.
default: true
griefprevention.buysellclaimblocks:
description: Grants access to claim block buy/sell commands.
default: true default: true

View File

@ -150,6 +150,9 @@ public class BlockEventHandler implements Listener
return; return;
} }
//if a player is in pvp combat, he can't give away items
if(playerData.inPvpCombat()) return;
//NOTE: to eliminate accidental give-aways, first hit on a chest displays a confirmation message //NOTE: to eliminate accidental give-aways, first hit on a chest displays a confirmation message
//subsequent hits donate item to the chest //subsequent hits donate item to the chest
@ -266,7 +269,7 @@ public class BlockEventHandler implements Listener
//FEATURE: limit fire placement, to prevent PvP-by-fire //FEATURE: limit fire placement, to prevent PvP-by-fire
//if placed block is fire and pvp is off, apply rules for proximity to other players //if placed block is fire and pvp is off, apply rules for proximity to other players
if(block.getType() == Material.FIRE && !block.getWorld().getPVP() && !player.hasPermission("griefprevention.lava")) if(block.getType() == Material.FIRE && !GriefPrevention.instance.config_pvp_enabledWorlds.contains(block.getWorld()) && !player.hasPermission("griefprevention.lava"))
{ {
List<Player> players = block.getWorld().getPlayers(); List<Player> players = block.getWorld().getPlayers();
for(int i = 0; i < players.size(); i++) for(int i = 0; i < players.size(); i++)

View File

@ -82,7 +82,7 @@ public class Claim
//administrative claims are created and maintained by players with the griefprevention.adminclaims permission. //administrative claims are created and maintained by players with the griefprevention.adminclaims permission.
public boolean isAdminClaim() public boolean isAdminClaim()
{ {
return this.ownerName.isEmpty(); return (this.ownerName == null || this.ownerName.isEmpty());
} }
//accessor for ID //accessor for ID

View File

@ -1,6 +1,6 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@ -1,15 +1,33 @@
package me.ryanhamshire.GriefPrevention; /*
GriefPrevention Server Plugin for Minecraft
public class CustomizableMessage Copyright (C) 2012 Ryan Hamshire
{
public Messages id; This program is free software: you can redistribute it and/or modify
public String text; it under the terms of the GNU General Public License as published by
public String notes; the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
public CustomizableMessage(Messages id, String text, String notes)
{ This program is distributed in the hope that it will be useful,
this.id = id; but WITHOUT ANY WARRANTY; without even the implied warranty of
this.text = text; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
this.notes = notes; 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;
public class CustomizableMessage
{
public Messages id;
public String text;
public String notes;
public CustomizableMessage(Messages id, String text, String notes)
{
this.id = id;
this.text = text;
this.notes = notes;
}
} }

View File

@ -884,7 +884,7 @@ public abstract class DataStore
this.addDefault(defaults, Messages.AutomaticClaimNotification, "This chest and nearby blocks are protected from breakage and theft. The temporary gold and glowstone blocks mark the protected area. To toggle them on and off, right-click with a stick.", null); this.addDefault(defaults, Messages.AutomaticClaimNotification, "This chest and nearby blocks are protected from breakage and theft. The temporary gold and glowstone blocks mark the protected area. To toggle them on and off, right-click with a stick.", null);
this.addDefault(defaults, Messages.TrustCommandAdvertisement, "Use the /trust command to grant other players access.", null); this.addDefault(defaults, Messages.TrustCommandAdvertisement, "Use the /trust command to grant other players access.", null);
this.addDefault(defaults, Messages.GoldenShovelAdvertisement, "To claim more land, you need a golden shovel. When you equip one, you'll get more information.", null); this.addDefault(defaults, Messages.GoldenShovelAdvertisement, "To claim more land, you need a golden shovel. When you equip one, you'll get more information.", null);
this.addDefault(defaults, Messages.UnprotectedChestWarning, "This chest is NOT protected. Consider expanding an existing claim or creating a new one.", null); 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.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.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.NoDamageClaimedEntity, "That belongs to {0}.", "0: owner name");
@ -893,7 +893,7 @@ public abstract class DataStore
this.addDefault(defaults, Messages.CreativeBasicsDemoAdvertisement, "Land Claim Help: http://tinyurl.com/c7bajb8", null); this.addDefault(defaults, Messages.CreativeBasicsDemoAdvertisement, "Land Claim Help: http://tinyurl.com/c7bajb8", null);
this.addDefault(defaults, Messages.SurvivalBasicsDemoAdvertisement, "Land Claim Help: http://tinyurl.com/6nkwegj", null); this.addDefault(defaults, Messages.SurvivalBasicsDemoAdvertisement, "Land Claim Help: http://tinyurl.com/6nkwegj", null);
this.addDefault(defaults, Messages.TrappedChatKeyword, "trapped", "When mentioned in chat, players get information about the /trapped command."); 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 claim? Consider the /trapped command.", null); 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.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.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.BesiegedNoTeleport, "You can't teleport into a besieged area.", null);
@ -952,7 +952,7 @@ public abstract class DataStore
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.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.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"); this.addDefault(defaults, Messages.PlayerOfflineTime, " Last login: {0} days ago.", "0: number of full days since last login");
this.addDefault(defaults, Messages.BuildingOutsideClaims, "Other players can undo your work here! Consider claiming this area to protect your work.", null); this.addDefault(defaults, Messages.BuildingOutsideClaims, "Other players can undo your work here! Consider using a golden shovel to claim this area so that your work will be protected.", null);
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.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.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.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);
@ -961,6 +961,8 @@ public abstract class DataStore
this.addDefault(defaults, Messages.NoTNTDamageAboveSeaLevel, "Warning: TNT will not destroy blocks above sea level.", 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.NoTNTDamageClaims, "Warning: TNT will not destroy claimed blocks.", null);
this.addDefault(defaults, Messages.IgnoreClaimsAdvertisement, "To override, use /IgnoreClaims.", 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);
this.addDefault(defaults, Messages.ClaimsListNoPermission, "You don't have permission to get information about another player's land claims.", null);
//load the config file //load the config file
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath)); FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));

View File

@ -1,75 +1,75 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//FEATURE: give players claim blocks for playing, as long as they're not away from their computer //FEATURE: give players claim blocks for playing, as long as they're not away from their computer
//runs every 5 minutes in the main thread, grants blocks per hour / 12 to each online player who appears to be actively playing //runs every 5 minutes in the main thread, grants blocks per hour / 12 to each online player who appears to be actively playing
class DeliverClaimBlocksTask implements Runnable class DeliverClaimBlocksTask implements Runnable
{ {
@Override @Override
public void run() public void run()
{ {
Player [] players = GriefPrevention.instance.getServer().getOnlinePlayers(); Player [] players = GriefPrevention.instance.getServer().getOnlinePlayers();
//ensure players get at least 1 block (if accrual is totally disabled, this task won't even be scheduled) //ensure players get at least 1 block (if accrual is totally disabled, this task won't even be scheduled)
int accruedBlocks = GriefPrevention.instance.config_claims_blocksAccruedPerHour / 12; int accruedBlocks = GriefPrevention.instance.config_claims_blocksAccruedPerHour / 12;
if(accruedBlocks < 0) accruedBlocks = 1; if(accruedBlocks < 0) accruedBlocks = 1;
//for each online player //for each online player
for(int i = 0; i < players.length; i++) for(int i = 0; i < players.length; i++)
{ {
Player player = players[i]; Player player = players[i];
DataStore dataStore = GriefPrevention.instance.dataStore; DataStore dataStore = GriefPrevention.instance.dataStore;
PlayerData playerData = dataStore.getPlayerData(player.getName()); PlayerData playerData = dataStore.getPlayerData(player.getName());
Location lastLocation = playerData.lastAfkCheckLocation; Location lastLocation = playerData.lastAfkCheckLocation;
try //distance squared will throw an exception if the player has changed worlds try //distance squared will throw an exception if the player has changed worlds
{ {
//if he's not in a vehicle and has moved at least three blocks since the last check //if he's not in a vehicle and has moved at least three blocks since the last check
if(!player.isInsideVehicle() && (lastLocation == null || lastLocation.distanceSquared(player.getLocation()) >= 9)) if(!player.isInsideVehicle() && (lastLocation == null || lastLocation.distanceSquared(player.getLocation()) >= 9))
{ {
//if player is over accrued limit, accrued limit was probably reduced in config file AFTER he accrued //if player is over accrued limit, accrued limit was probably reduced in config file AFTER he accrued
//in that case, leave his blocks where they are //in that case, leave his blocks where they are
if(playerData.accruedClaimBlocks > GriefPrevention.instance.config_claims_maxAccruedBlocks) continue; if(playerData.accruedClaimBlocks > GriefPrevention.instance.config_claims_maxAccruedBlocks) continue;
//add blocks //add blocks
playerData.accruedClaimBlocks += accruedBlocks; playerData.accruedClaimBlocks += accruedBlocks;
//respect limits //respect limits
if(playerData.accruedClaimBlocks > GriefPrevention.instance.config_claims_maxAccruedBlocks) if(playerData.accruedClaimBlocks > GriefPrevention.instance.config_claims_maxAccruedBlocks)
{ {
playerData.accruedClaimBlocks = GriefPrevention.instance.config_claims_maxAccruedBlocks; playerData.accruedClaimBlocks = GriefPrevention.instance.config_claims_maxAccruedBlocks;
} }
//intentionally NOT saving data here to reduce overall secondary storage access frequency //intentionally NOT saving data here to reduce overall secondary storage access frequency
//many other operations will cause this players data to save, including his eventual logout //many other operations will cause this players data to save, including his eventual logout
//dataStore.savePlayerData(player.getName(), playerData); //dataStore.savePlayerData(player.getName(), playerData);
} }
} }
catch(Exception e) { } catch(Exception e) { }
//remember current location for next time //remember current location for next time
playerData.lastAfkCheckLocation = player.getLocation(); playerData.lastAfkCheckLocation = player.getLocation();
} }
} }
} }

View File

@ -1,143 +1,143 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.entity.Boat; import org.bukkit.entity.Boat;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.Vehicle; import org.bukkit.entity.Vehicle;
//FEATURE: creative mode worlds get a regular entity cleanup //FEATURE: creative mode worlds get a regular entity cleanup
//this main thread task revisits the location of a partially chopped tree from several minutes ago //this main thread task revisits the location of a partially chopped tree from several minutes ago
//if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts //if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts
class EntityCleanupTask implements Runnable class EntityCleanupTask implements Runnable
{ {
//where to start cleaning in the list of entities //where to start cleaning in the list of entities
private double percentageStart; private double percentageStart;
public EntityCleanupTask(double percentageStart) public EntityCleanupTask(double percentageStart)
{ {
this.percentageStart = percentageStart; this.percentageStart = percentageStart;
} }
@Override @Override
public void run() public void run()
{ {
ArrayList<World> worlds = GriefPrevention.instance.config_claims_enabledCreativeWorlds; ArrayList<World> worlds = GriefPrevention.instance.config_claims_enabledCreativeWorlds;
for(int i = 0; i < worlds.size(); i++) for(int i = 0; i < worlds.size(); i++)
{ {
World world = worlds.get(i); World world = worlds.get(i);
List<Entity> entities = world.getEntities(); List<Entity> entities = world.getEntities();
//starting and stopping point. each execution of the task scans 10% of the server's (loaded) entities //starting and stopping point. each execution of the task scans 10% of the server's (loaded) entities
int j = (int)(entities.size() * this.percentageStart); int j = (int)(entities.size() * this.percentageStart);
int k = (int)(entities.size() * (this.percentageStart + .1)); int k = (int)(entities.size() * (this.percentageStart + .1));
Claim cachedClaim = null; Claim cachedClaim = null;
for(; j < entities.size() && j < k; j++) for(; j < entities.size() && j < k; j++)
{ {
Entity entity = entities.get(j); Entity entity = entities.get(j);
boolean remove = false; boolean remove = false;
if(entity instanceof Boat) //boats must be occupied if(entity instanceof Boat) //boats must be occupied
{ {
Boat boat = (Boat)entity; Boat boat = (Boat)entity;
if(boat.isEmpty()) remove = true; if(boat.isEmpty()) remove = true;
} }
else if(entity instanceof Vehicle) else if(entity instanceof Vehicle)
{ {
Vehicle vehicle = (Vehicle)entity; Vehicle vehicle = (Vehicle)entity;
//minecarts in motion must be occupied by a player //minecarts in motion must be occupied by a player
if(vehicle.getVelocity().lengthSquared() != 0) if(vehicle.getVelocity().lengthSquared() != 0)
{ {
if(vehicle.isEmpty() || !(vehicle.getPassenger() instanceof Player)) if(vehicle.isEmpty() || !(vehicle.getPassenger() instanceof Player))
{ {
remove = true; remove = true;
} }
} }
//stationary carts must be on rails //stationary carts must be on rails
else else
{ {
Material material = world.getBlockAt(vehicle.getLocation()).getType(); Material material = world.getBlockAt(vehicle.getLocation()).getType();
if(material != Material.RAILS && material != Material.POWERED_RAIL && material != Material.DETECTOR_RAIL) if(material != Material.RAILS && material != Material.POWERED_RAIL && material != Material.DETECTOR_RAIL)
{ {
remove = true; remove = true;
} }
} }
} }
//all non-player entities must be in claims //all non-player entities must be in claims
else if(!(entity instanceof Player)) else if(!(entity instanceof Player))
{ {
Claim claim = GriefPrevention.instance.dataStore.getClaimAt(entity.getLocation(), false, cachedClaim); Claim claim = GriefPrevention.instance.dataStore.getClaimAt(entity.getLocation(), false, cachedClaim);
if(claim != null) if(claim != null)
{ {
cachedClaim = claim; cachedClaim = claim;
} }
else else
{ {
remove = true; remove = true;
} }
} }
if(remove) if(remove)
{ {
entity.remove(); entity.remove();
} }
} }
} }
//starting and stopping point. each execution of the task scans 5% of the server's claims //starting and stopping point. each execution of the task scans 5% of the server's claims
List<Claim> claims = GriefPrevention.instance.dataStore.claims; List<Claim> claims = GriefPrevention.instance.dataStore.claims;
int j = (int)(claims.size() * this.percentageStart); int j = (int)(claims.size() * this.percentageStart);
int k = (int)(claims.size() * (this.percentageStart + .05)); int k = (int)(claims.size() * (this.percentageStart + .05));
for(; j < claims.size() && j < k; j++) for(; j < claims.size() && j < k; j++)
{ {
Claim claim = claims.get(j); Claim claim = claims.get(j);
//if it's a creative mode claim //if it's a creative mode claim
if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner())) if(GriefPrevention.instance.creativeRulesApply(claim.getLesserBoundaryCorner()))
{ {
//check its entity count and remove any extras //check its entity count and remove any extras
claim.allowMoreEntities(); claim.allowMoreEntities();
} }
} }
//schedule the next run of this task, in 3 minutes (20L is approximately 1 second) //schedule the next run of this task, in 3 minutes (20L is approximately 1 second)
double nextRunPercentageStart = this.percentageStart + .05; double nextRunPercentageStart = this.percentageStart + .05;
if(nextRunPercentageStart > .99) if(nextRunPercentageStart > .99)
{ {
nextRunPercentageStart = 0; nextRunPercentageStart = 0;
System.gc(); //clean up every hour System.gc(); //clean up every hour
} }
EntityCleanupTask task = new EntityCleanupTask(nextRunPercentageStart); EntityCleanupTask task = new EntityCleanupTask(nextRunPercentageStart);
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L * 60 * 1); GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, task, 20L * 60 * 1);
} }
} }

View File

@ -35,6 +35,7 @@ import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster; import org.bukkit.entity.Monster;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.ThrownPotion; import org.bukkit.entity.ThrownPotion;
import org.bukkit.entity.Villager;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
@ -361,7 +362,7 @@ class EntityEventHandler implements Listener
} }
//if the attacker is a player and defender is a player (pvp combat) //if the attacker is a player and defender is a player (pvp combat)
if(attacker != null && event.getEntity() instanceof Player) if(attacker != null && event.getEntity() instanceof Player && GriefPrevention.instance.config_pvp_enabledWorlds.contains(attacker.getWorld()))
{ {
//FEATURE: prevent pvp in the first minute after spawn, and prevent pvp when one or both players have no inventory //FEATURE: prevent pvp in the first minute after spawn, and prevent pvp when one or both players have no inventory
@ -425,10 +426,21 @@ class EntityEventHandler implements Listener
//if it's claimed //if it's claimed
if(claim != null) if(claim != null)
{ {
//if damaged by anything other than a player, cancel the event //if damaged by anything other than a player (exception villagers injured by zombies in admin claims), cancel the event
//why exception? so admins can set up a village which can't be CHANGED by players, but must be "protected" by players.
if(attacker == null) if(attacker == null)
{ {
event.setCancelled(true); //exception case
if(event.getEntity() instanceof Villager && damageSource instanceof Monster && claim.isAdminClaim())
{
return;
}
//all other cases
else
{
event.setCancelled(true);
}
} }
//otherwise the player damaging the entity must have permission //otherwise the player damaging the entity must have permission

View File

@ -1,66 +1,66 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//tells a player about how many claim blocks he has, etc //tells a player about how many claim blocks he has, etc
//implemented as a task so that it can be delayed //implemented as a task so that it can be delayed
//otherwise, it's spammy when players mouse-wheel past the shovel in their hot bars //otherwise, it's spammy when players mouse-wheel past the shovel in their hot bars
class EquipShovelProcessingTask implements Runnable class EquipShovelProcessingTask implements Runnable
{ {
//player data //player data
private Player player; private Player player;
public EquipShovelProcessingTask(Player player) public EquipShovelProcessingTask(Player player)
{ {
this.player = player; this.player = player;
} }
@Override @Override
public void run() public void run()
{ {
//if he logged out, don't do anything //if he logged out, don't do anything
if(!player.isOnline()) return; if(!player.isOnline()) return;
//if he's not holding the golden shovel anymore, do nothing //if he's not holding the golden shovel anymore, do nothing
if(player.getItemInHand().getType() != GriefPrevention.instance.config_claims_modificationTool) return; if(player.getItemInHand().getType() != GriefPrevention.instance.config_claims_modificationTool) return;
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName()); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
int remainingBlocks = playerData.getRemainingClaimBlocks(); int remainingBlocks = playerData.getRemainingClaimBlocks();
//if in basic claims mode... //if in basic claims mode...
if(playerData.shovelMode == ShovelMode.Basic) if(playerData.shovelMode == ShovelMode.Basic)
{ {
//tell him how many claim blocks he has available //tell him how many claim blocks he has available
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RemainingBlocks, String.valueOf(remainingBlocks)); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.RemainingBlocks, String.valueOf(remainingBlocks));
//link to a video demo of land claiming, based on world type //link to a video demo of land claiming, based on world type
if(GriefPrevention.instance.creativeRulesApply(player.getLocation())) if(GriefPrevention.instance.creativeRulesApply(player.getLocation()))
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsDemoAdvertisement); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.CreativeBasicsDemoAdvertisement);
} }
else else
{ {
GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsDemoAdvertisement); GriefPrevention.sendMessage(player, TextMode.Instr, Messages.SurvivalBasicsDemoAdvertisement);
} }
} }
} }
} }

View File

@ -106,6 +106,7 @@ public class GriefPrevention extends JavaPlugin
public String config_spam_warningMessage; //message to show a player who is close to spam level 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 String config_spam_allowedIpAddresses; //IP addresses which will not be censored
public ArrayList<World> config_pvp_enabledWorlds; //list of worlds where pvp anti-grief rules apply
public boolean config_pvp_protectFreshSpawns; //whether to make newly spawned players immune until they pick up an item 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 public boolean config_pvp_punishLogout; //whether to kill players who log out during PvP combat
public int config_pvp_combatTimeoutSeconds; //how long combat is considered to continue after the most recent damage public int config_pvp_combatTimeoutSeconds; //how long combat is considered to continue after the most recent damage
@ -238,6 +239,40 @@ public class GriefPrevention extends JavaPlugin
} }
} }
//default for pvp worlds list
ArrayList<String> defaultPvpWorldNames = new ArrayList<String>();
for(int i = 0; i < worlds.size(); i++)
{
World world = worlds.get(i);
if(world.getPVP())
{
defaultPvpWorldNames.add(world.getName());
}
}
//get pvp world names from the config file
List<String> pvpEnabledWorldNames = config.getStringList("GriefPrevention.PvP.Worlds");
if(pvpEnabledWorldNames == null || pvpEnabledWorldNames.size() == 0)
{
pvpEnabledWorldNames = defaultPvpWorldNames;
}
//validate that list
this.config_pvp_enabledWorlds = new ArrayList<World>();
for(int i = 0; i < pvpEnabledWorldNames.size(); i++)
{
String worldName = pvpEnabledWorldNames.get(i);
World world = this.getServer().getWorld(worldName);
if(world == null)
{
AddLogEntry("Error: PvP Configuration: There's no world named \"" + worldName + "\". Please update your config.yml.");
}
else
{
this.config_pvp_enabledWorlds.add(world);
}
}
//sea level //sea level
this.config_seaLevelOverride = new HashMap<String, Integer>(); this.config_seaLevelOverride = new HashMap<String, Integer>();
for(int i = 0; i < worlds.size(); i++) for(int i = 0; i < worlds.size(); i++)
@ -525,6 +560,7 @@ public class GriefPrevention extends JavaPlugin
config.set("GriefPrevention.Spam.BanMessage", this.config_spam_banMessage); config.set("GriefPrevention.Spam.BanMessage", this.config_spam_banMessage);
config.set("GriefPrevention.Spam.AllowedIpAddresses", this.config_spam_allowedIpAddresses); config.set("GriefPrevention.Spam.AllowedIpAddresses", this.config_spam_allowedIpAddresses);
config.set("GriefPrevention.PvP.Worlds", pvpEnabledWorldNames);
config.set("GriefPrevention.PvP.ProtectFreshSpawns", this.config_pvp_protectFreshSpawns); config.set("GriefPrevention.PvP.ProtectFreshSpawns", this.config_pvp_protectFreshSpawns);
config.set("GriefPrevention.PvP.PunishLogout", this.config_pvp_punishLogout); config.set("GriefPrevention.PvP.PunishLogout", this.config_pvp_punishLogout);
config.set("GriefPrevention.PvP.CombatTimeoutSeconds", this.config_pvp_combatTimeoutSeconds); config.set("GriefPrevention.PvP.CombatTimeoutSeconds", this.config_pvp_combatTimeoutSeconds);
@ -1148,6 +1184,12 @@ public class GriefPrevention extends JavaPlugin
return true; return true;
} }
if(!player.hasPermission("griefprevention.buysellclaimblocks"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionForCommand);
return true;
}
//if purchase disabled, send error message //if purchase disabled, send error message
if(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost == 0) if(GriefPrevention.instance.config_economy_claimBlocksPurchaseCost == 0)
{ {
@ -1233,6 +1275,12 @@ public class GriefPrevention extends JavaPlugin
return true; return true;
} }
if(!player.hasPermission("griefprevention.buysellclaimblocks"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoPermissionForCommand);
return true;
}
//if disabled, error message //if disabled, error message
if(GriefPrevention.instance.config_economy_claimBlocksSellValue == 0) if(GriefPrevention.instance.config_economy_claimBlocksSellValue == 0)
{ {
@ -1404,21 +1452,40 @@ public class GriefPrevention extends JavaPlugin
return true; return true;
} }
//claimslist <player> //claimslist or claimslist <player>
else if(cmd.getName().equalsIgnoreCase("claimslist")) else if(cmd.getName().equalsIgnoreCase("claimslist"))
{ {
//requires exactly one parameter, the other player's name //at most one parameter
if(args.length != 1) return false; if(args.length > 1) return false;
//try to find that player //player whose claims will be listed
OfflinePlayer otherPlayer = this.resolvePlayer(args[0]); OfflinePlayer otherPlayer;
if(otherPlayer == null)
//if another player isn't specified, assume current player
if(args.length < 1)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound); otherPlayer = player;
return true;
} }
//load the player's data //otherwise if no permission to delve into another player's claims data
else if(!player.hasPermission("griefprevention.deleteclaims"))
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.ClaimsListNoPermission);
return true;
}
//otherwise try to find the specified player
else
{
otherPlayer = this.resolvePlayer(args[0]);
if(otherPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound);
return true;
}
}
//load the target player's data
PlayerData playerData = this.dataStore.getPlayerData(otherPlayer.getName()); PlayerData playerData = this.dataStore.getPlayerData(otherPlayer.getName());
GriefPrevention.sendMessage(player, TextMode.Instr, " " + playerData.accruedClaimBlocks + "(+" + playerData.bonusClaimBlocks + ")=" + (playerData.accruedClaimBlocks + playerData.bonusClaimBlocks)); GriefPrevention.sendMessage(player, TextMode.Instr, " " + playerData.accruedClaimBlocks + "(+" + playerData.bonusClaimBlocks + ")=" + (playerData.accruedClaimBlocks + playerData.bonusClaimBlocks));
for(int i = 0; i < playerData.claims.size(); i++) for(int i = 0; i < playerData.claims.size(); i++)
@ -1597,6 +1664,13 @@ public class GriefPrevention extends JavaPlugin
return true; return true;
} }
//if the player is in an administrative claim, he should contact an admin
if(claim.isAdminClaim())
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.TrappedWontWorkHere);
return true;
}
//check cooldown //check cooldown
long lastTrappedUsage = playerData.lastTrappedUsage.getTime(); long lastTrappedUsage = playerData.lastTrappedUsage.getTime();
long nextTrappedUsage = lastTrappedUsage + 1000 * 60 * 60 * this.config_claims_trappedCooldownHours; long nextTrappedUsage = lastTrappedUsage + 1000 * 60 * 60 * this.config_claims_trappedCooldownHours;
@ -2003,7 +2077,7 @@ public class GriefPrevention extends JavaPlugin
public void checkPvpProtectionNeeded(Player player) public void checkPvpProtectionNeeded(Player player)
{ {
//if pvp is disabled, do nothing //if pvp is disabled, do nothing
if(!player.getWorld().getPVP()) return; if(!this.config_pvp_enabledWorlds.contains(player.getWorld())) return;
//if player is in creative mode, do nothing //if player is in creative mode, do nothing
if(player.getGameMode() == GameMode.CREATIVE) return; if(player.getGameMode() == GameMode.CREATIVE) return;

View File

@ -1,17 +1,35 @@
package me.ryanhamshire.GriefPrevention; /*
GriefPrevention Server Plugin for Minecraft
import java.net.InetAddress; Copyright (C) 2012 Ryan Hamshire
public class IpBanInfo 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
InetAddress address; the Free Software Foundation, either version 3 of the License, or
long expirationTimestamp; (at your option) any later version.
String bannedAccountName;
This program is distributed in the hope that it will be useful,
IpBanInfo(InetAddress address, long expirationTimestamp, String bannedAccountName) but WITHOUT ANY WARRANTY; without even the implied warranty of
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
this.address = address; GNU General Public License for more details.
this.expirationTimestamp = expirationTimestamp;
this.bannedAccountName = bannedAccountName; 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.net.InetAddress;
public class IpBanInfo
{
InetAddress address;
long expirationTimestamp;
String bannedAccountName;
IpBanInfo(InetAddress address, long expirationTimestamp, String bannedAccountName)
{
this.address = address;
this.expirationTimestamp = expirationTimestamp;
this.bannedAccountName = bannedAccountName;
}
}

View File

@ -1,56 +1,74 @@
package me.ryanhamshire.GriefPrevention; /*
GriefPrevention Server Plugin for Minecraft
import java.util.ArrayList; Copyright (C) 2012 Ryan Hamshire
//ordered list of material info objects, for fast searching This program is free software: you can redistribute it and/or modify
public class MaterialCollection it under the terms of the GNU General Public License as published by
{ the Free Software Foundation, either version 3 of the License, or
ArrayList<MaterialInfo> materials = new ArrayList<MaterialInfo>(); (at your option) any later version.
void Add(MaterialInfo material) This program is distributed in the hope that it will be useful,
{ but WITHOUT ANY WARRANTY; without even the implied warranty of
int i; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
for(i = 0; i < this.materials.size() && this.materials.get(i).typeID <= material.typeID; i++); GNU General Public License for more details.
this.materials.add(i, material);
} You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
boolean Contains(MaterialInfo material) */
{
for(int i = 0; i < this.materials.size() ; i++) package me.ryanhamshire.GriefPrevention;
{
MaterialInfo thisMaterial = this.materials.get(i); import java.util.ArrayList;
if(material.typeID == thisMaterial.typeID && (thisMaterial.allDataValues || material.data == thisMaterial.data))
{ //ordered list of material info objects, for fast searching
return true; public class MaterialCollection
} {
else if(thisMaterial.typeID > material.typeID) ArrayList<MaterialInfo> materials = new ArrayList<MaterialInfo>();
{
return false; void Add(MaterialInfo material)
} {
} int i;
for(i = 0; i < this.materials.size() && this.materials.get(i).typeID <= material.typeID; i++);
return false; this.materials.add(i, material);
} }
@Override boolean Contains(MaterialInfo material)
public String toString() {
{ for(int i = 0; i < this.materials.size() ; i++)
StringBuilder stringBuilder = new StringBuilder(); {
for(int i = 0; i < this.materials.size(); i++) MaterialInfo thisMaterial = this.materials.get(i);
{ if(material.typeID == thisMaterial.typeID && (thisMaterial.allDataValues || material.data == thisMaterial.data))
stringBuilder.append(this.materials.get(i).toString() + " "); {
} return true;
}
return stringBuilder.toString(); else if(thisMaterial.typeID > material.typeID)
} {
return false;
public int size() }
{ }
return this.materials.size();
} return false;
}
public void clear()
{ @Override
this.materials.clear(); public String toString()
} {
} StringBuilder stringBuilder = new StringBuilder();
for(int i = 0; i < this.materials.size(); i++)
{
stringBuilder.append(this.materials.get(i).toString() + " ");
}
return stringBuilder.toString();
}
public int size()
{
return this.materials.size();
}
public void clear()
{
this.materials.clear();
}
}

View File

@ -1,75 +1,93 @@
package me.ryanhamshire.GriefPrevention; /*
GriefPrevention Server Plugin for Minecraft
//represents a material or collection of materials Copyright (C) 2012 Ryan Hamshire
public class MaterialInfo
{ This program is free software: you can redistribute it and/or modify
int typeID; it under the terms of the GNU General Public License as published by
byte data; the Free Software Foundation, either version 3 of the License, or
boolean allDataValues; (at your option) any later version.
String description;
This program is distributed in the hope that it will be useful,
public MaterialInfo(int typeID, byte data, String description) but WITHOUT ANY WARRANTY; without even the implied warranty of
{ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
this.typeID = typeID; GNU General Public License for more details.
this.data = data;
this.allDataValues = false; You should have received a copy of the GNU General Public License
this.description = description; along with this program. If not, see <http://www.gnu.org/licenses/>.
} */
public MaterialInfo(int typeID, String description) package me.ryanhamshire.GriefPrevention;
{
this.typeID = typeID; //represents a material or collection of materials
this.data = 0; public class MaterialInfo
this.allDataValues = true; {
this.description = description; int typeID;
} byte data;
boolean allDataValues;
private MaterialInfo(int typeID, byte data, boolean allDataValues, String description) String description;
{
this.typeID = typeID; public MaterialInfo(int typeID, byte data, String description)
this.data = data; {
this.allDataValues = allDataValues; this.typeID = typeID;
this.description = description; this.data = data;
} this.allDataValues = false;
this.description = description;
@Override }
public String toString()
{ public MaterialInfo(int typeID, String description)
String returnValue = String.valueOf(this.typeID) + ":" + (this.allDataValues?"*":String.valueOf(this.data)); {
if(this.description != null) returnValue += ":" + this.description; this.typeID = typeID;
this.data = 0;
return returnValue; this.allDataValues = true;
} this.description = description;
}
public static MaterialInfo fromString(String string)
{ private MaterialInfo(int typeID, byte data, boolean allDataValues, String description)
if(string == null || string.isEmpty()) return null; {
this.typeID = typeID;
String [] parts = string.split(":"); this.data = data;
if(parts.length < 3) return null; this.allDataValues = allDataValues;
this.description = description;
try }
{
int typeID = Integer.parseInt(parts[0]); @Override
public String toString()
byte data; {
boolean allDataValues; String returnValue = String.valueOf(this.typeID) + ":" + (this.allDataValues?"*":String.valueOf(this.data));
if(parts[1].equals("*")) if(this.description != null) returnValue += ":" + this.description;
{
allDataValues = true; return returnValue;
data = 0; }
}
else public static MaterialInfo fromString(String string)
{ {
allDataValues = false; if(string == null || string.isEmpty()) return null;
data = Byte.parseByte(parts[1]);
} String [] parts = string.split(":");
if(parts.length < 3) return null;
return new MaterialInfo(typeID, data, allDataValues, parts[2]);
} try
catch(NumberFormatException exception) {
{ int typeID = Integer.parseInt(parts[0]);
return null;
} byte data;
} boolean allDataValues;
} if(parts[1].equals("*"))
{
allDataValues = true;
data = 0;
}
else
{
allDataValues = false;
data = Byte.parseByte(parts[1]);
}
return new MaterialInfo(typeID, data, allDataValues, parts[2]);
}
catch(NumberFormatException exception)
{
return null;
}
}
}

View File

@ -1,6 +1,24 @@
/*
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; package me.ryanhamshire.GriefPrevention;
public enum Messages public enum Messages
{ {
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionDemo, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, TrappedOnCooldown, RescuePending, NonSiegeWorld, AlreadySieging, NotSiegableThere, SiegeTooFarAway, NoSiegeDefenseless, AlreadyUnderSiegePlayer, AlreadyUnderSiegeArea, NoSiegeAdminClaim, SiegeOnCooldown, SiegeAlert, SiegeConfirmed, AbandonClaimMissing, NotYourClaim, DeleteTopLevelClaim, AbandonSuccess, CantGrantThatPermission, GrantPermissionNoClaim, GrantPermissionConfirmation, ManageUniversalPermissionsInstruction, ManageOneClaimPermissionsInstruction, CollectivePublic, BuildPermission, ContainersPermission, AccessPermission, PermissionsPermission, LocationCurrentClaim, LocationAllClaims, PvPImmunityStart, SiegeNoDrop, DonateItemsInstruction, ChestFull, DonationSuccess, PlayerTooCloseForFire, TooDeepToClaim, ChestClaimConfirmation, AutomaticClaimNotification, TrustCommandAdvertisement, GoldenShovelAdvertisement, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsDemoAdvertisement, SurvivalBasicsDemoAdvertisement, TrappedChatKeyword, TrappedInstructions, PvPNoDrop, SiegeNoTeleport, BesiegedNoTeleport, SiegeNoContainers, PvPNoContainers, PvPImmunityEnd, NoBedPermission, NoWildernessBuckets, NoLavaNearOtherPlayer, TooFarAway, BlockNotClaimed, BlockClaimed, SiegeNoShovel, RestoreNaturePlayerInChunk, NoCreateClaimPermission, ResizeClaimTooSmall, ResizeNeedMoreBlocks, NoCreativeUnClaim, ClaimResizeSuccess, ResizeFailOverlap, ResizeStart, ResizeFailOverlapSubdivision, SubdivisionStart, CreateSubdivisionOverlap, SubdivisionSuccess, CreateClaimFailOverlap, CreateClaimFailOverlapOtherPlayer, ClaimsDisabledWorld, ClaimStart, NewClaimTooSmall, CreateClaimInsufficientBlocks, AbandonClaimAdvertisement, CreateClaimFailOverlapShort, CreateClaimSuccess, SiegeWinDoorsOpen, RescueAbortedMoved, SiegeDoorsLockedEjection, NoModifyDuringSiege, OnlyOwnersModifyClaims, NoBuildUnderSiege, NoBuildPvP, NoBuildPermission, NonSiegeMaterial, NoOwnerBuildUnderSiege, NoAccessPermission, NoContainersSiege, NoContainersPermission, OwnerNameForAdminClaims, ClaimTooSmallForEntities, TooManyEntitiesInClaim, YouHaveNoClaims, ConfirmFluidRemoval, AutoBanNotify, AdjustGroupBlocksSuccess, InvalidPermissionID, UntrustOwnerOnly, HowToClaimRegex, NoBuildOutsideClaims, PlayerOfflineTime, BuildingOutsideClaims, TrappedWontWorkHere, CommandBannedInPvP, UnclaimCleanupWarning, BuySellNotConfigured, NoTeleportPvPCombat, NoTNTDamageAboveSeaLevel, NoTNTDamageClaims, IgnoreClaimsAdvertisement, NoPermissionForCommand, ClaimsListNoPermission
} }

View File

@ -125,23 +125,26 @@ class PlayerEventHandler implements Listener
//if the player has permission to spam, don't bother even examining the message //if the player has permission to spam, don't bother even examining the message
if(player.hasPermission("griefprevention.spam")) return false; if(player.hasPermission("griefprevention.spam")) return false;
//remedy any CAPS SPAM without bothering to fault the player for it boolean spam = false;
boolean muted = false;
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
//remedy any CAPS SPAM, exception for very short messages which could be emoticons like =D or XD
if(message.length() > 4 && this.stringsAreSimilar(message.toUpperCase(), message)) if(message.length() > 4 && this.stringsAreSimilar(message.toUpperCase(), message))
{ {
if(event instanceof AsyncPlayerChatEvent) //exception for strings containing forward slash to avoid changing a case-sensitive URL
if(event instanceof AsyncPlayerChatEvent && !message.contains("/"))
{ {
((AsyncPlayerChatEvent)event).setMessage(message.toLowerCase()); ((AsyncPlayerChatEvent)event).setMessage(message.toLowerCase());
playerData.spamCount++;
spam = true;
} }
} }
//where other types of spam are concerned, casing isn't significant //where other types of spam are concerned, casing isn't significant
message = message.toLowerCase(); message = message.toLowerCase();
PlayerData playerData = this.dataStore.getPlayerData(player.getName());
boolean spam = false;
boolean muted = false;
//check message content and timing //check message content and timing
long millisecondsSinceLastMessage = (new Date()).getTime() - playerData.lastMessageTimestamp.getTime(); long millisecondsSinceLastMessage = (new Date()).getTime() - playerData.lastMessageTimestamp.getTime();
@ -363,7 +366,7 @@ class PlayerEventHandler implements Listener
//if in pvp, block any pvp-banned slash commands //if in pvp, block any pvp-banned slash commands
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName()); PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getName());
if(playerData.inPvpCombat() && GriefPrevention.instance.config_pvp_blockedCommands.contains(command)) if((playerData.inPvpCombat() || playerData.siegeData != null) && GriefPrevention.instance.config_pvp_blockedCommands.contains(command))
{ {
event.setCancelled(true); event.setCancelled(true);
GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, Messages.CommandBannedInPvP); GriefPrevention.sendMessage(event.getPlayer(), TextMode.Err, Messages.CommandBannedInPvP);
@ -642,17 +645,10 @@ class PlayerEventHandler implements Listener
if(event.getCause() == TeleportCause.ENDER_PEARL) return; if(event.getCause() == TeleportCause.ENDER_PEARL) return;
Player player = event.getPlayer(); Player player = event.getPlayer();
PlayerData playerData = this.dataStore.getPlayerData(player.getName()); PlayerData playerData = this.dataStore.getPlayerData(player.getName());
if(playerData.inPvpCombat())
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NoTeleportPvPCombat);
event.setCancelled(true);
return;
}
Location source = event.getFrom(); Location source = event.getFrom();
Claim sourceClaim = this.dataStore.getClaimAt(source, false, null); Claim sourceClaim = this.dataStore.getClaimAt(source, false, playerData.lastClaim);
if(sourceClaim != null && sourceClaim.siegeData != null) if(sourceClaim != null && sourceClaim.siegeData != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoTeleport); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeNoTeleport);
@ -875,7 +871,7 @@ class PlayerEventHandler implements Listener
} }
//lava buckets can't be dumped near other players unless pvp is on //lava buckets can't be dumped near other players unless pvp is on
if(!block.getWorld().getPVP() && !player.hasPermission("griefprevention.lava")) if(!GriefPrevention.instance.config_pvp_enabledWorlds.contains(block.getWorld()) && !player.hasPermission("griefprevention.lava"))
{ {
if(bucketEvent.getBucket() == Material.LAVA_BUCKET) if(bucketEvent.getBucket() == Material.LAVA_BUCKET)
{ {

View File

@ -1,69 +1,69 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.Calendar; import java.util.Calendar;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//tries to rescue a trapped player from a claim where he doesn't have permission to save himself //tries to rescue a trapped player from a claim where he doesn't have permission to save himself
//related to the /trapped slash command //related to the /trapped slash command
//this does run in the main thread, so it's okay to make non-thread-safe calls //this does run in the main thread, so it's okay to make non-thread-safe calls
class PlayerRescueTask implements Runnable class PlayerRescueTask implements Runnable
{ {
//original location where /trapped was used //original location where /trapped was used
private Location location; private Location location;
//player data //player data
private Player player; private Player player;
public PlayerRescueTask(Player player, Location location) public PlayerRescueTask(Player player, Location location)
{ {
this.player = player; this.player = player;
this.location = location; this.location = location;
} }
@Override @Override
public void run() public void run()
{ {
//if he logged out, don't do anything //if he logged out, don't do anything
if(!player.isOnline()) return; if(!player.isOnline()) return;
//he no longer has a pending /trapped slash command, so he can try to use it again now //he no longer has a pending /trapped slash command, so he can try to use it again now
PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName()); PlayerData playerData = GriefPrevention.instance.dataStore.getPlayerData(player.getName());
playerData.pendingTrapped = false; playerData.pendingTrapped = false;
//if the player moved three or more blocks from where he used /trapped, admonish him and don't save him //if the player moved three or more blocks from where he used /trapped, admonish him and don't save him
if(player.getLocation().distance(this.location) > 3) if(player.getLocation().distance(this.location) > 3)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, Messages.RescueAbortedMoved); GriefPrevention.sendMessage(player, TextMode.Err, Messages.RescueAbortedMoved);
return; return;
} }
//otherwise find a place to teleport him //otherwise find a place to teleport him
Location destination = GriefPrevention.instance.ejectPlayer(this.player); Location destination = GriefPrevention.instance.ejectPlayer(this.player);
//log entry, in case admins want to investigate the "trap" //log entry, in case admins want to investigate the "trap"
GriefPrevention.AddLogEntry("Rescued trapped player " + player.getName() + " from " + GriefPrevention.getfriendlyLocationString(this.location) + " to " + GriefPrevention.getfriendlyLocationString(destination) + "."); GriefPrevention.AddLogEntry("Rescued trapped player " + player.getName() + " from " + GriefPrevention.getfriendlyLocationString(this.location) + " to " + GriefPrevention.getfriendlyLocationString(destination) + ".");
//timestamp this successful save so that he can't use /trapped again for a while //timestamp this successful save so that he can't use /trapped again for a while
playerData.lastTrappedUsage = Calendar.getInstance().getTime(); playerData.lastTrappedUsage = Calendar.getInstance().getTime();
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@ -1,6 +1,6 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@ -1,56 +1,56 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//secures a claim after a siege looting window has closed //secures a claim after a siege looting window has closed
class SecureClaimTask implements Runnable class SecureClaimTask implements Runnable
{ {
private SiegeData siegeData; private SiegeData siegeData;
public SecureClaimTask(SiegeData siegeData) public SecureClaimTask(SiegeData siegeData)
{ {
this.siegeData = siegeData; this.siegeData = siegeData;
} }
@Override @Override
public void run() public void run()
{ {
//for each claim involved in this siege //for each claim involved in this siege
for(int i = 0; i < this.siegeData.claims.size(); i++) for(int i = 0; i < this.siegeData.claims.size(); i++)
{ {
//lock the doors //lock the doors
Claim claim = this.siegeData.claims.get(i); Claim claim = this.siegeData.claims.get(i);
claim.doorsOpen = false; claim.doorsOpen = false;
//eject bad guys //eject bad guys
Player [] onlinePlayers = GriefPrevention.instance.getServer().getOnlinePlayers(); Player [] onlinePlayers = GriefPrevention.instance.getServer().getOnlinePlayers();
for(int j = 0; j < onlinePlayers.length; j++) for(int j = 0; j < onlinePlayers.length; j++)
{ {
Player player = onlinePlayers[j]; Player player = onlinePlayers[j];
if(claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null) if(claim.contains(player.getLocation(), false, false) && claim.allowAccess(player) != null)
{ {
GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeDoorsLockedEjection); GriefPrevention.sendMessage(player, TextMode.Err, Messages.SiegeDoorsLockedEjection);
GriefPrevention.instance.ejectPlayer(player); GriefPrevention.instance.ejectPlayer(player);
} }
} }
} }
} }
} }

View File

@ -1,44 +1,44 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//sends a message to a player //sends a message to a player
//used to send delayed messages, for example help text triggered by a player's chat //used to send delayed messages, for example help text triggered by a player's chat
class SendPlayerMessageTask implements Runnable class SendPlayerMessageTask implements Runnable
{ {
private Player player; private Player player;
private ChatColor color; private ChatColor color;
private String message; private String message;
public SendPlayerMessageTask(Player player, ChatColor color, String message) public SendPlayerMessageTask(Player player, ChatColor color, String message)
{ {
this.player = player; this.player = player;
this.color = color; this.color = color;
this.message = message; this.message = message;
} }
@Override @Override
public void run() public void run()
{ {
GriefPrevention.sendMessage(this.player, this.color, this.message); GriefPrevention.sendMessage(this.player, this.color, this.message);
} }
} }

View File

@ -1,30 +1,30 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
//enumeration for golden shovel modes //enumeration for golden shovel modes
enum ShovelMode enum ShovelMode
{ {
Basic, Basic,
Admin, Admin,
Subdivide, Subdivide,
RestoreNature, RestoreNature,
RestoreNatureAggressive, RestoreNatureAggressive,
RestoreNatureFill RestoreNatureFill
} }

View File

@ -1,110 +1,110 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//checks to see whether or not a siege should end based on the locations of the players //checks to see whether or not a siege should end based on the locations of the players
//for example, defender escaped or attacker gave up and left //for example, defender escaped or attacker gave up and left
class SiegeCheckupTask implements Runnable class SiegeCheckupTask implements Runnable
{ {
private SiegeData siegeData; private SiegeData siegeData;
public SiegeCheckupTask(SiegeData siegeData) public SiegeCheckupTask(SiegeData siegeData)
{ {
this.siegeData = siegeData; this.siegeData = siegeData;
} }
@Override @Override
public void run() public void run()
{ {
DataStore dataStore = GriefPrevention.instance.dataStore; DataStore dataStore = GriefPrevention.instance.dataStore;
Player defender = this.siegeData.defender; Player defender = this.siegeData.defender;
Player attacker = this.siegeData.attacker; Player attacker = this.siegeData.attacker;
//where is the defender? //where is the defender?
Claim defenderClaim = dataStore.getClaimAt(defender.getLocation(), false, null); Claim defenderClaim = dataStore.getClaimAt(defender.getLocation(), false, null);
//if this is a new claim and he has some permission there, extend the siege to include it //if this is a new claim and he has some permission there, extend the siege to include it
if(defenderClaim != null) if(defenderClaim != null)
{ {
String noAccessReason = defenderClaim.allowAccess(defender); String noAccessReason = defenderClaim.allowAccess(defender);
if(defenderClaim.canSiege(defender) && noAccessReason == null) if(defenderClaim.canSiege(defender) && noAccessReason == null)
{ {
this.siegeData.claims.add(defenderClaim); this.siegeData.claims.add(defenderClaim);
defenderClaim.siegeData = this.siegeData; defenderClaim.siegeData = this.siegeData;
} }
} }
//determine who's close enough to the siege area to be considered "still here" //determine who's close enough to the siege area to be considered "still here"
boolean attackerRemains = this.playerRemains(attacker); boolean attackerRemains = this.playerRemains(attacker);
boolean defenderRemains = this.playerRemains(defender); boolean defenderRemains = this.playerRemains(defender);
//if they're both here, just plan to come check again later //if they're both here, just plan to come check again later
if(attackerRemains && defenderRemains) if(attackerRemains && defenderRemains)
{ {
this.scheduleAnotherCheck(); this.scheduleAnotherCheck();
} }
//otherwise attacker wins if the defender runs away //otherwise attacker wins if the defender runs away
else if(attackerRemains && !defenderRemains) else if(attackerRemains && !defenderRemains)
{ {
dataStore.endSiege(this.siegeData, attacker.getName(), defender.getName(), false); dataStore.endSiege(this.siegeData, attacker.getName(), defender.getName(), false);
} }
//or defender wins if the attacker leaves //or defender wins if the attacker leaves
else if(!attackerRemains && defenderRemains) else if(!attackerRemains && defenderRemains)
{ {
dataStore.endSiege(this.siegeData, defender.getName(), attacker.getName(), false); dataStore.endSiege(this.siegeData, defender.getName(), attacker.getName(), false);
} }
//if they both left, but are still close together, the battle continues (check again later) //if they both left, but are still close together, the battle continues (check again later)
else if(attacker.getLocation().distanceSquared(defender.getLocation()) < 2500) //50-block radius for chasing else if(attacker.getLocation().distanceSquared(defender.getLocation()) < 2500) //50-block radius for chasing
{ {
this.scheduleAnotherCheck(); this.scheduleAnotherCheck();
} }
//otherwise they both left and aren't close to each other, so call the attacker the winner (defender escaped, possibly after a chase) //otherwise they both left and aren't close to each other, so call the attacker the winner (defender escaped, possibly after a chase)
else else
{ {
dataStore.endSiege(this.siegeData, attacker.getName(), defender.getName(), false); dataStore.endSiege(this.siegeData, attacker.getName(), defender.getName(), false);
} }
} }
//a player has to be within 25 blocks of the edge of a besieged claim to be considered still in the fight //a player has to be within 25 blocks of the edge of a besieged claim to be considered still in the fight
private boolean playerRemains(Player player) private boolean playerRemains(Player player)
{ {
for(int i = 0; i < this.siegeData.claims.size(); i++) for(int i = 0; i < this.siegeData.claims.size(); i++)
{ {
Claim claim = this.siegeData.claims.get(i); Claim claim = this.siegeData.claims.get(i);
if(claim.isNear(player.getLocation(), 25)) if(claim.isNear(player.getLocation(), 25))
{ {
return true; return true;
} }
} }
return false; return false;
} }
//schedules another checkup later //schedules another checkup later
private void scheduleAnotherCheck() private void scheduleAnotherCheck()
{ {
this.siegeData.checkupTaskID = GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 20L * 30); this.siegeData.checkupTaskID = GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 20L * 30);
} }
} }

View File

@ -1,40 +1,40 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList; import java.util.ArrayList;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//information about an ongoing siege //information about an ongoing siege
public class SiegeData public class SiegeData
{ {
public Player defender; public Player defender;
public Player attacker; public Player attacker;
public ArrayList<Claim> claims; public ArrayList<Claim> claims;
public int checkupTaskID; public int checkupTaskID;
public SiegeData(Player attacker, Player defender, Claim claim) public SiegeData(Player attacker, Player defender, Claim claim)
{ {
this.defender = defender; this.defender = defender;
this.attacker = attacker; this.attacker = attacker;
this.claims = new ArrayList<Claim>(); this.claims = new ArrayList<Claim>();
this.claims.add(claim); this.claims.add(claim);
} }
} }

View File

@ -1,31 +1,31 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
//just a few constants for chat color codes //just a few constants for chat color codes
class TextMode class TextMode
{ {
final static ChatColor Info = ChatColor.BLUE; final static ChatColor Info = ChatColor.BLUE;
final static ChatColor Instr = ChatColor.YELLOW; final static ChatColor Instr = ChatColor.YELLOW;
final static ChatColor Warn = ChatColor.GOLD; final static ChatColor Warn = ChatColor.GOLD;
final static ChatColor Err = ChatColor.RED; final static ChatColor Err = ChatColor.RED;
final static ChatColor Success = ChatColor.GREEN; final static ChatColor Success = ChatColor.GREEN;
} }

View File

@ -1,100 +1,100 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import java.util.ArrayList; import java.util.ArrayList;
import org.bukkit.Chunk; import org.bukkit.Chunk;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
//FEATURE: treetops left unnaturally hanging will be automatically cleaned up //FEATURE: treetops left unnaturally hanging will be automatically cleaned up
//this main thread task revisits the location of a partially chopped tree from several minutes ago //this main thread task revisits the location of a partially chopped tree from several minutes ago
//if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts //if any part of the tree is still there and nothing else has been built in its place, remove the remaining parts
class TreeCleanupTask implements Runnable class TreeCleanupTask implements Runnable
{ {
private Block originalChoppedBlock; //first block chopped in the tree private Block originalChoppedBlock; //first block chopped in the tree
private Block originalRootBlock; //where the root of the tree used to be private Block originalRootBlock; //where the root of the tree used to be
private ArrayList<Block> originalTreeBlocks; //a list of other log blocks determined to be part of this tree private ArrayList<Block> originalTreeBlocks; //a list of other log blocks determined to be part of this tree
public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList<Block> originalTreeBlocks) public TreeCleanupTask(Block originalChoppedBlock, Block originalRootBlock, ArrayList<Block> originalTreeBlocks)
{ {
this.originalChoppedBlock = originalChoppedBlock; this.originalChoppedBlock = originalChoppedBlock;
this.originalRootBlock = originalRootBlock; this.originalRootBlock = originalRootBlock;
this.originalTreeBlocks = originalTreeBlocks; this.originalTreeBlocks = originalTreeBlocks;
} }
@Override @Override
public void run() public void run()
{ {
//if this chunk is no longer loaded, load it and come back in a few seconds //if this chunk is no longer loaded, load it and come back in a few seconds
Chunk chunk = this.originalChoppedBlock.getWorld().getChunkAt(this.originalChoppedBlock); Chunk chunk = this.originalChoppedBlock.getWorld().getChunkAt(this.originalChoppedBlock);
if(!chunk.isLoaded()) if(!chunk.isLoaded())
{ {
chunk.load(); chunk.load();
GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 100L); GriefPrevention.instance.getServer().getScheduler().scheduleSyncDelayedTask(GriefPrevention.instance, this, 100L);
return; return;
} }
//if the block originally chopped has been replaced with anything but air, something has been built (or has grown here) //if the block originally chopped has been replaced with anything but air, something has been built (or has grown here)
//in that case, don't do any cleanup //in that case, don't do any cleanup
if(this.originalChoppedBlock.getWorld().getBlockAt(this.originalChoppedBlock.getLocation()).getType() != Material.AIR) return; if(this.originalChoppedBlock.getWorld().getBlockAt(this.originalChoppedBlock.getLocation()).getType() != Material.AIR) return;
//scan the original tree block locations to see if any of them have been replaced //scan the original tree block locations to see if any of them have been replaced
for(int i = 0; i < this.originalTreeBlocks.size(); i++) for(int i = 0; i < this.originalTreeBlocks.size(); i++)
{ {
Location location = this.originalTreeBlocks.get(i).getLocation(); Location location = this.originalTreeBlocks.get(i).getLocation();
Block currentBlock = location.getBlock(); Block currentBlock = location.getBlock();
//if the block has been replaced, stop here, we won't do any cleanup //if the block has been replaced, stop here, we won't do any cleanup
if(currentBlock.getType() != Material.LOG && currentBlock.getType() != Material.AIR) if(currentBlock.getType() != Material.LOG && currentBlock.getType() != Material.AIR)
{ {
return; return;
} }
} }
//otherwise scan again, this time removing any remaining log blocks //otherwise scan again, this time removing any remaining log blocks
boolean logsRemaining = false; boolean logsRemaining = false;
for(int i = 0; i < this.originalTreeBlocks.size(); i++) for(int i = 0; i < this.originalTreeBlocks.size(); i++)
{ {
Location location = this.originalTreeBlocks.get(i).getLocation(); Location location = this.originalTreeBlocks.get(i).getLocation();
Block currentBlock = location.getBlock(); Block currentBlock = location.getBlock();
if(currentBlock.getType() == Material.LOG) if(currentBlock.getType() == Material.LOG)
{ {
logsRemaining = true; logsRemaining = true;
currentBlock.setType(Material.AIR); currentBlock.setType(Material.AIR);
} }
} }
//if any were actually removed and we're set to automatically replant griefed trees, place a sapling where the root block was previously //if any were actually removed and we're set to automatically replant griefed trees, place a sapling where the root block was previously
if(logsRemaining && GriefPrevention.instance.config_trees_regrowGriefedTrees) if(logsRemaining && GriefPrevention.instance.config_trees_regrowGriefedTrees)
{ {
Block currentBlock = this.originalRootBlock.getLocation().getBlock(); Block currentBlock = this.originalRootBlock.getLocation().getBlock();
//make sure there's grass or dirt underneath //make sure there's grass or dirt underneath
if(currentBlock.getType() == Material.AIR && (currentBlock.getRelative(BlockFace.DOWN).getType() == Material.DIRT || currentBlock.getRelative(BlockFace.DOWN).getType() == Material.GRASS)) if(currentBlock.getType() == Material.AIR && (currentBlock.getRelative(BlockFace.DOWN).getType() == Material.DIRT || currentBlock.getRelative(BlockFace.DOWN).getType() == Material.GRASS))
{ {
currentBlock.setType(Material.SAPLING); currentBlock.setType(Material.SAPLING);
currentBlock.setData(this.originalRootBlock.getData()); //makes the sapling type match the original tree type currentBlock.setData(this.originalRootBlock.getData()); //makes the sapling type match the original tree type
} }
} }
} }
} }

View File

@ -1,6 +1,6 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by

View File

@ -1,52 +1,52 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
//applies a visualization for a player by sending him block change packets //applies a visualization for a player by sending him block change packets
class VisualizationApplicationTask implements Runnable class VisualizationApplicationTask implements Runnable
{ {
private Visualization visualization; private Visualization visualization;
private Player player; private Player player;
private PlayerData playerData; private PlayerData playerData;
public VisualizationApplicationTask(Player player, PlayerData playerData, Visualization visualization) public VisualizationApplicationTask(Player player, PlayerData playerData, Visualization visualization)
{ {
this.visualization = visualization; this.visualization = visualization;
this.playerData = playerData; this.playerData = playerData;
this.player = player; this.player = player;
} }
@Override @Override
public void run() public void run()
{ {
//for each element (=block) of the visualization //for each element (=block) of the visualization
for(int i = 0; i < visualization.elements.size(); i++) for(int i = 0; i < visualization.elements.size(); i++)
{ {
VisualizationElement element = visualization.elements.get(i); VisualizationElement element = visualization.elements.get(i);
//send the player a fake block change event //send the player a fake block change event
player.sendBlockChange(element.location, element.visualizedMaterial, element.visualizedData); player.sendBlockChange(element.location, element.visualizedMaterial, element.visualizedData);
} }
//remember the visualization applied to this player for later (so it can be inexpensively reverted) //remember the visualization applied to this player for later (so it can be inexpensively reverted)
playerData.currentVisualization = visualization; playerData.currentVisualization = visualization;
} }
} }

View File

@ -1,36 +1,36 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
//represents a "fake" block sent to a player as part of a visualization //represents a "fake" block sent to a player as part of a visualization
public class VisualizationElement public class VisualizationElement
{ {
public Location location; public Location location;
public Material visualizedMaterial; public Material visualizedMaterial;
public byte visualizedData; public byte visualizedData;
public VisualizationElement(Location location, Material visualizedMaterial, byte visualizedData) public VisualizationElement(Location location, Material visualizedMaterial, byte visualizedData)
{ {
this.location = location; this.location = location;
this.visualizedMaterial= visualizedMaterial; this.visualizedMaterial= visualizedMaterial;
this.visualizedData = visualizedData; this.visualizedData = visualizedData;
} }
} }

View File

@ -1,28 +1,28 @@
/* /*
GriefPrevention Server Plugin for Minecraft GriefPrevention Server Plugin for Minecraft
Copyright (C) 2011 Ryan Hamshire Copyright (C) 2012 Ryan Hamshire
This program is free software: you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or the Free Software Foundation, either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
package me.ryanhamshire.GriefPrevention; package me.ryanhamshire.GriefPrevention;
//just an enumeration of the visualization types, which determine what materials will be for the fake blocks //just an enumeration of the visualization types, which determine what materials will be for the fake blocks
public enum VisualizationType public enum VisualizationType
{ {
Claim, Claim,
Subdivision, Subdivision,
ErrorClaim, ErrorClaim,
RestoreNature RestoreNature
} }