Added /ignore and /separate.

Also companion commands like /unseparate, /unignore, and /ignorelist.
This commit is contained in:
ryanhamshire 2015-05-16 13:00:55 -07:00
parent 02dee1f21e
commit 14717bd4c7
9 changed files with 430 additions and 33 deletions

View File

@ -152,6 +152,26 @@ commands:
description: Allows an administrator to get technical information about blocks in the world and items in hand.
usage: /GPBlockInfo
permission: griefprevention.gpblockinfo
ignoreplayer:
description: Ignores another player's chat messages.
usage: /IgnorePlayer <player name>
aliases: [ignore]
unignoreplayer:
description: Unignores another player's chat messages.
usage: /UnIgnorePlayer <player name>
aliases: [unignore]
ignoredplayerlist:
description: Lists the players you're ignoring in chat.
usage: /IgnoredPlayerList
aliases: [ignores, ignored, ignorelist, ignoredlist, listignores, listignored, ignoring]
separate:
description: Forces two players to ignore each other in chat.
usage: /Separate
permission: griefprevention.separate
unseparate:
description: Reverses /separate.
usage: /UnSeparate
permission: griefprevention.separate
permissions:
griefprevention.createclaims:
description: Grants permission to create claims.
@ -176,6 +196,7 @@ permissions:
griefprevention.transferclaim: true
griefprevention.claimslistother: true
griefprevention.siegeimmune: true
griefprevention.separate: true
griefprevention.siegeimmune:
description: Makes a player immune to /Siege.
default: op
@ -239,3 +260,6 @@ permissions:
griefprevention.overrideclaimcountlimit:
description: Allows players to create more claims than the limit specified by the config.
default: op
griefprevention.separate:
description: Grants access to /Separate and /UnSeparate.
default: op

View File

@ -19,6 +19,9 @@
package me.ryanhamshire.GriefPrevention;
import java.io.*;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
@ -31,6 +34,8 @@ import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import com.google.common.io.Files;
//singleton class which manages all GriefPrevention data (except for config options)
public abstract class DataStore
{
@ -55,7 +60,8 @@ public abstract class DataStore
//path information, for where stuff stored on disk is well... stored
protected final static String dataLayerFolderPath = "plugins" + File.separator + "GriefPreventionData";
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
final static String configFilePath = dataLayerFolderPath + File.separator + "config.yml";
final static String messagesFilePath = dataLayerFolderPath + File.separator + "messages.yml";
final static String softMuteFilePath = dataLayerFolderPath + File.separator + "softMute.txt";
@ -104,6 +110,13 @@ public abstract class DataStore
{
GriefPrevention.AddLogEntry(this.claims.size() + " total claims loaded.");
//ensure data folders exist
File playerDataFolder = new File(playerDataFolderPath);
if(!playerDataFolder.exists())
{
playerDataFolder.mkdirs();
}
//load up all the messages from messages.yml
this.loadMessages();
GriefPrevention.AddLogEntry("Customizable messages loaded.");
@ -756,7 +769,47 @@ public abstract class DataStore
new SavePlayerDataThread(playerID, playerData).start();
}
public abstract void asyncSavePlayerData(UUID playerID, PlayerData playerData);
public void asyncSavePlayerData(UUID playerID, PlayerData playerData)
{
//save everything except the ignore list
this.overrideSavePlayerData(playerID, playerData);
//save the ignore list
if(playerData.ignoreListChanged)
{
StringBuilder fileContent = new StringBuilder();
try
{
for(UUID uuidKey : playerData.ignoredPlayers.keySet())
{
Boolean value = playerData.ignoredPlayers.get(uuidKey);
if(value == null) continue;
//admin-enforced ignores begin with an asterisk
if(value)
{
fileContent.append("*");
}
fileContent.append(uuidKey);
fileContent.append("\n");
}
//write data to file
File playerDataFile = new File(playerDataFolderPath + File.separator + playerID + ".ignore");
Files.write(fileContent.toString().trim().getBytes("UTF-8"), playerDataFile);
}
//if any problem, log it
catch(Exception e)
{
GriefPrevention.AddLogEntry("GriefPrevention: Unexpected exception saving data for player \"" + playerID.toString() + "\": " + e.getMessage());
e.printStackTrace();
}
}
}
abstract void overrideSavePlayerData(UUID playerID, PlayerData playerData);
//extends a claim to a new depth
//respects the max depth config variable
@ -1275,6 +1328,12 @@ public abstract class DataStore
this.addDefault(defaults, Messages.NoChatUntilMove, "Sorry, but you have to move a little more before you can chat. We get lots of spam bots here. :)", null);
this.addDefault(defaults, Messages.SiegeImmune, "That player is immune to /siege.", null);
this.addDefault(defaults, Messages.SetClaimBlocksSuccess, "Updated accrued claim blocks.", null);
this.addDefault(defaults, Messages.IgnoreConfirmation, "You're now ignoring chat messages from that player.", null);
this.addDefault(defaults, Messages.UnIgnoreConfirmation, "You're no longer ignoring chat messages from that player.", null);
this.addDefault(defaults, Messages.NotIgnoringPlayer, "You're not ignoring that player.", null);
this.addDefault(defaults, Messages.SeparateConfirmation, "Those players will now ignore each other in chat.", null);
this.addDefault(defaults, Messages.UnSeparateConfirmation, "Those players will no longer ignore each other in chat.", null);
this.addDefault(defaults, Messages.NotIgnoringAnyone, "You're not ignoring anyone.", null);
//load the config file
FileConfiguration config = YamlConfiguration.loadConfiguration(new File(messagesFilePath));

View File

@ -524,7 +524,7 @@ public class DatabaseDataStore extends DataStore
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
@Override
public void asyncSavePlayerData(UUID playerID, PlayerData playerData)
public void overrideSavePlayerData(UUID playerID, PlayerData playerData)
{
//never save data for the "administrative" account. an empty string for player name indicates administrative account
if(playerID == null) return;

View File

@ -32,17 +32,15 @@ import com.google.common.io.Files;
//manages data stored in the file system
public class FlatFileDataStore extends DataStore
{
private final static String playerDataFolderPath = dataLayerFolderPath + File.separator + "PlayerData";
private final static String claimDataFolderPath = dataLayerFolderPath + File.separator + "ClaimData";
private final static String nextClaimIdFilePath = claimDataFolderPath + File.separator + "_nextClaimID";
private final static String schemaVersionFilePath = dataLayerFolderPath + File.separator + "_schemaVersion";
static boolean hasData()
{
File playerDataFolder = new File(playerDataFolderPath);
File claimsDataFolder = new File(claimDataFolderPath);
return playerDataFolder.exists() || claimsDataFolder.exists();
return claimsDataFolder.exists();
}
//initialization!
@ -554,7 +552,7 @@ public class FlatFileDataStore extends DataStore
//saves changes to player data. MUST be called after you're done making changes, otherwise a reload will lose them
@Override
public void asyncSavePlayerData(UUID playerID, PlayerData playerData)
public void overrideSavePlayerData(UUID playerID, PlayerData playerData)
{
//never save data for the "administrative" account. null for claim owner ID indicates administrative account
if(playerID == null) return;
@ -596,6 +594,7 @@ public class FlatFileDataStore extends DataStore
catch(Exception e)
{
GriefPrevention.AddLogEntry("GriefPrevention: Unexpected exception saving data for player \"" + playerID.toString() + "\": " + e.getMessage());
e.printStackTrace();
}
}

View File

@ -24,6 +24,7 @@ import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map.Entry;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
@ -281,7 +282,7 @@ public class GriefPrevention extends JavaPlugin
String dataMode = (this.dataStore instanceof FlatFileDataStore)?"(File Mode)":"(Database Mode)";
AddLogEntry("Finished loading data " + dataMode + ".");
//unless claim block accrual is disabled, start the recurring per 5 minute event to give claim blocks to online players
//unless claim block accrual is disabled, start the recurring per 10 minute event to give claim blocks to online players
//20L ~ 1 second
if(this.config_claims_blocksAccruedPerHour > 0)
{
@ -354,6 +355,13 @@ public class GriefPrevention extends JavaPlugin
namesThread.setPriority(Thread.MIN_PRIORITY);
namesThread.start();
//load ignore lists for any already-online players
Collection<Player> players = (Collection<Player>)GriefPrevention.instance.getServer().getOnlinePlayers();
for(Player player : players)
{
new IgnoreLoaderThread(player.getUniqueId(), this.dataStore.getPlayerData(player.getUniqueId()).ignoredPlayers).start();
}
AddLogEntry("Boot finished.");
}
@ -2049,9 +2057,169 @@ public class GriefPrevention extends JavaPlugin
return true;
}
//ignoreplayer
else if(cmd.getName().equalsIgnoreCase("ignoreplayer") && player != null)
{
//requires target player name
if(args.length < 1) return false;
//validate target player
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
this.setIgnoreStatus(player, targetPlayer, IgnoreMode.StandardIgnore);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.IgnoreConfirmation);
return true;
}
//unignoreplayer
else if(cmd.getName().equalsIgnoreCase("unignoreplayer") && player != null)
{
//requires target player name
if(args.length < 1) return false;
//validate target player
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
Boolean ignoreStatus = playerData.ignoredPlayers.get(targetPlayer.getUniqueId());
if(ignoreStatus == null || ignoreStatus == true)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.NotIgnoringPlayer);
return true;
}
this.setIgnoreStatus(player, targetPlayer, IgnoreMode.None);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.UnIgnoreConfirmation);
return true;
}
//ignoredplayerlist
else if(cmd.getName().equalsIgnoreCase("ignoredplayerlist") && player != null)
{
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
StringBuilder builder = new StringBuilder();
for(Entry<UUID, Boolean> entry : playerData.ignoredPlayers.entrySet())
{
if(entry.getValue() != null)
{
//if not an admin ignore, add it to the list
if(!entry.getValue())
{
builder.append(GriefPrevention.lookupPlayerName(entry.getKey()));
builder.append(" ");
}
}
}
String list = builder.toString().trim();
if(list.isEmpty())
{
GriefPrevention.sendMessage(player, TextMode.Info, Messages.NotIgnoringAnyone);
}
else
{
GriefPrevention.sendMessage(player, TextMode.Info, list);
}
return true;
}
//separateplayers
else if(cmd.getName().equalsIgnoreCase("separate") && player != null)
{
//requires two player names
if(args.length < 2) return false;
//validate target players
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
OfflinePlayer targetPlayer2 = this.resolvePlayerByName(args[1]);
if(targetPlayer2 == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
this.setIgnoreStatus(targetPlayer, targetPlayer2, IgnoreMode.AdminIgnore);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.SeparateConfirmation);
return true;
}
//unseparateplayers
else if(cmd.getName().equalsIgnoreCase("unseparate") && player != null)
{
//requires two player names
if(args.length < 2) return false;
//validate target players
OfflinePlayer targetPlayer = this.resolvePlayerByName(args[0]);
if(targetPlayer == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
OfflinePlayer targetPlayer2 = this.resolvePlayerByName(args[1]);
if(targetPlayer2 == null)
{
GriefPrevention.sendMessage(player, TextMode.Err, Messages.PlayerNotFound2);
return true;
}
this.setIgnoreStatus(targetPlayer, targetPlayer2, IgnoreMode.None);
this.setIgnoreStatus(targetPlayer2, targetPlayer, IgnoreMode.None);
GriefPrevention.sendMessage(player, TextMode.Success, Messages.UnSeparateConfirmation);
return true;
}
return false;
}
void setIgnoreStatus(OfflinePlayer ignorer, OfflinePlayer ignoree, IgnoreMode mode)
{
PlayerData playerData = this.dataStore.getPlayerData(ignorer.getUniqueId());
if(mode == IgnoreMode.None)
{
playerData.ignoredPlayers.remove(ignoree.getUniqueId());
}
else
{
playerData.ignoredPlayers.put(ignoree.getUniqueId(), mode == IgnoreMode.StandardIgnore ? false : true);
}
playerData.ignoreListChanged = true;
if(!ignorer.isOnline())
{
this.dataStore.savePlayerData(ignorer.getUniqueId(), playerData);
this.dataStore.clearCachedPlayerData(ignorer.getUniqueId());
}
}
enum IgnoreMode {None, StandardIgnore, AdminIgnore}
private String trustEntryToPlayerName(String entry)
{
if(entry.startsWith("[") || entry.equals("public"))

View File

@ -0,0 +1,85 @@
package me.ryanhamshire.GriefPrevention;
import java.io.File;
import java.nio.charset.Charset;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import com.google.common.io.Files;
//loads ignore data from file into a hash map
class IgnoreLoaderThread extends Thread
{
private UUID playerToLoad;
private ConcurrentHashMap<UUID, Boolean> destinationMap;
IgnoreLoaderThread(UUID playerToLoad, ConcurrentHashMap<UUID, Boolean> destinationMap)
{
this.playerToLoad = playerToLoad;
this.destinationMap = destinationMap;
this.setPriority(MIN_PRIORITY);
}
@Override
public void run()
{
File ignoreFile = new File(DataStore.playerDataFolderPath + File.separator + this.playerToLoad + ".ignore");
//if the file doesn't exist, there's nothing to do here
if(!ignoreFile.exists()) return;
boolean needRetry = false;
int retriesRemaining = 5;
Exception latestException = null;
do
{
try
{
needRetry = false;
//read the file content and immediately close it
List<String> lines = Files.readLines(ignoreFile, Charset.forName("UTF-8"));
//each line is one ignore. asterisks indicate administrative ignores
for(String line : lines)
{
boolean adminIgnore = false;
if(line.startsWith("*"))
{
adminIgnore = true;
line = line.substring(1);
}
try
{
UUID ignoredUUID = UUID.fromString(line);
this.destinationMap.put(ignoredUUID, adminIgnore);
}
catch(IllegalArgumentException e){} //if a bad UUID, ignore the line
}
}
//if there's any problem with the file's content, retry up to 5 times with 5 milliseconds between
catch(Exception e)
{
latestException = e;
needRetry = true;
retriesRemaining--;
}
try
{
if(needRetry) Thread.sleep(5);
}
catch(InterruptedException exception) {}
}while(needRetry && retriesRemaining >= 0);
//if last attempt failed, log information about the problem
if(needRetry)
{
GriefPrevention.AddLogEntry("Retry attempts exhausted. Unable to load ignore data for player \"" + playerToLoad.toString() + "\": " + latestException.toString());
latestException.printStackTrace();
}
}
}

View File

@ -20,5 +20,5 @@ package me.ryanhamshire.GriefPrevention;
public enum Messages
{
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound2, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo2, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, 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, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo2, SurvivalBasicsVideo2, 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, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone, NoPistonsOutsideClaims, SoftMuted, UnSoftMuted, DropUnlockAdvertisement, PickupBlockedExplanation, DropUnlockConfirmation, AdvertiseACandACB, AdvertiseAdminClaims, AdvertiseACB, NotYourPet, PetGiveawayConfirmation, PetTransferCancellation, ReadyToTransferPet, AvoidGriefClaimLand, BecomeMayor, ClaimCreationFailedOverClaimCountLimit, CreateClaimFailOverlapRegion, ResizeFailOverlapRegion, NoBuildPortalPermission, ShowNearbyClaims, NoChatUntilMove, SiegeImmune, SetClaimBlocksSuccess
RespectingClaims, IgnoringClaims, SuccessfulAbandon, RestoreNatureActivate, RestoreNatureAggressiveActivate, FillModeActive, TransferClaimPermission, TransferClaimMissing, TransferClaimAdminOnly, PlayerNotFound2, TransferTopLevel, TransferSuccess, TrustListNoClaim, ClearPermsOwnerOnly, UntrustIndividualAllClaims, UntrustEveryoneAllClaims, NoPermissionTrust, ClearPermissionsOneClaim, UntrustIndividualSingleClaim, OnlySellBlocks, BlockPurchaseCost, ClaimBlockLimit, InsufficientFunds, PurchaseConfirmation, OnlyPurchaseBlocks, BlockSaleValue, NotEnoughBlocksForSale, BlockSaleConfirmation, AdminClaimsMode, BasicClaimsMode, SubdivisionMode, SubdivisionVideo2, DeleteClaimMissing, DeletionSubdivisionWarning, DeleteSuccess, CantDeleteAdminClaim, DeleteAllSuccess, NoDeletePermission, AllAdminDeleted, AdjustBlocksSuccess, NotTrappedHere, 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, UnprotectedChestWarning, ThatPlayerPvPImmune, CantFightWhileImmune, NoDamageClaimedEntity, ShovelBasicClaimMode, RemainingBlocks, CreativeBasicsVideo2, SurvivalBasicsVideo2, 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, ExplosivesDisabled, ExplosivesEnabled, ClaimExplosivesAdvertisement, PlayerInPvPSafeZone, NoPistonsOutsideClaims, SoftMuted, UnSoftMuted, DropUnlockAdvertisement, PickupBlockedExplanation, DropUnlockConfirmation, AdvertiseACandACB, AdvertiseAdminClaims, AdvertiseACB, NotYourPet, PetGiveawayConfirmation, PetTransferCancellation, ReadyToTransferPet, AvoidGriefClaimLand, BecomeMayor, ClaimCreationFailedOverClaimCountLimit, CreateClaimFailOverlapRegion, ResizeFailOverlapRegion, NoBuildPortalPermission, ShowNearbyClaims, NoChatUntilMove, SiegeImmune, SetClaimBlocksSuccess, IgnoreConfirmation, NotIgnoringPlayer, UnIgnoreConfirmation, SeparateConfirmation, UnSeparateConfirmation, NotIgnoringAnyone
}

View File

@ -19,9 +19,12 @@
package me.ryanhamshire.GriefPrevention;
import java.net.InetAddress;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.Set;
import java.util.UUID;
import java.util.Vector;
import java.util.concurrent.ConcurrentHashMap;
import me.ryanhamshire.GriefPrevention.Claim;
import me.ryanhamshire.GriefPrevention.GriefPrevention;
@ -136,6 +139,11 @@ public class PlayerData
//this is an anti-bot strategy.
Location noChatLocation = null;
//ignore list
//true means invisible (admin-forced ignore), false means player-created ignore
ConcurrentHashMap<UUID, Boolean> ignoredPlayers = new ConcurrentHashMap<UUID, Boolean>();
boolean ignoreListChanged = false;
//whether or not this player is "in" pvp combat
public boolean inPvpCombat()
{

View File

@ -30,6 +30,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
import org.bukkit.Achievement;
import org.bukkit.ChatColor;
import org.bukkit.Chunk;
@ -134,10 +135,32 @@ class PlayerEventHandler implements Listener
GriefPrevention.AddLogEntry(notificationMessage, CustomLogEntryTypes.Debug, true);
}
//unfiltered messages go to the abridged chat logs
//remaining messages
else
{
//enter in abridged chat logs
this.makeSocialLogEntry(player.getName(), message);
//based on ignore lists, remove some of the audience
Set<Player> recipientsToRemove = new HashSet<Player>();
PlayerData playerData = this.dataStore.getPlayerData(player.getUniqueId());
for(Player recipient : recipients)
{
if(playerData.ignoredPlayers.containsKey(recipient.getUniqueId()))
{
recipientsToRemove.add(recipient);
}
else
{
PlayerData targetPlayerData = this.dataStore.getPlayerData(recipient.getUniqueId());
if(targetPlayerData.ignoredPlayers.containsKey(player.getUniqueId()))
{
recipientsToRemove.add(recipient);
}
}
}
recipients.removeAll(recipientsToRemove);
}
}
@ -419,32 +442,61 @@ class PlayerEventHandler implements Listener
{
String [] args = event.getMessage().split(" ");
//if eavesdrop enabled, eavesdrop
String command = args[0].toLowerCase();
if(GriefPrevention.instance.config_whisperNotifications && GriefPrevention.instance.config_eavesdrop_whisperCommands.contains(command) && !event.getPlayer().hasPermission("griefprevention.eavesdrop") && args.length > 1)
{
StringBuilder logMessageBuilder = new StringBuilder();
logMessageBuilder.append("[[").append(event.getPlayer().getName()).append("]] ");
for(int i = 1; i < args.length; i++)
{
logMessageBuilder.append(args[i]).append(" ");
}
String logMessage = logMessageBuilder.toString();
Collection<Player> players = (Collection<Player>)GriefPrevention.instance.getServer().getOnlinePlayers();
for(Player player : players)
{
if(player.hasPermission("griefprevention.eavesdrop") && !player.getName().equalsIgnoreCase(args[1]))
{
player.sendMessage(ChatColor.GRAY + logMessage);
}
}
Player player = event.getPlayer();
PlayerData playerData = null;
//if a whisper
if(GriefPrevention.instance.config_eavesdrop_whisperCommands.contains(command) && args.length > 1)
{
//if eavesdrop enabled, eavesdrop
if(GriefPrevention.instance.config_whisperNotifications && !event.getPlayer().hasPermission("griefprevention.eavesdrop"))
{
StringBuilder logMessageBuilder = new StringBuilder();
logMessageBuilder.append("[[").append(event.getPlayer().getName()).append("]] ");
for(int i = 1; i < args.length; i++)
{
logMessageBuilder.append(args[i]).append(" ");
}
String logMessage = logMessageBuilder.toString();
Collection<Player> players = (Collection<Player>)GriefPrevention.instance.getServer().getOnlinePlayers();
for(Player onlinePlayer : players)
{
if(onlinePlayer.hasPermission("griefprevention.eavesdrop") && !onlinePlayer.getName().equalsIgnoreCase(args[1]))
{
onlinePlayer.sendMessage(ChatColor.GRAY + logMessage);
}
}
}
//determine target player
Player targetPlayer = GriefPrevention.instance.getServer().getPlayer(args[1]);
if(targetPlayer != null && targetPlayer.isOnline())
{
//if either is ignoring the other, cancel this command
playerData = this.dataStore.getPlayerData(player.getUniqueId());
if(playerData.ignoredPlayers.containsKey(targetPlayer.getUniqueId()))
{
event.setCancelled(true);
return;
}
PlayerData targetPlayerData = this.dataStore.getPlayerData(targetPlayer.getUniqueId());
if(targetPlayerData.ignoredPlayers.containsKey(player.getUniqueId()))
{
event.setCancelled(true);
return;
}
}
}
//if in pvp, block any pvp-banned slash commands
PlayerData playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
if(playerData == null) playerData = this.dataStore.getPlayerData(event.getPlayer().getUniqueId());
if((playerData.inPvpCombat() || playerData.siegeData != null) && GriefPrevention.instance.config_pvp_blockedCommands.contains(command))
{
event.setCancelled(true);
@ -497,7 +549,6 @@ class PlayerEventHandler implements Listener
if(isMonitoredCommand)
{
Player player = event.getPlayer();
Claim claim = this.dataStore.getClaimAt(player.getLocation(), false, playerData.lastClaim);
if(claim != null)
{
@ -713,6 +764,9 @@ class PlayerEventHandler implements Listener
}
}
}
//create a thread to load ignore information
new IgnoreLoaderThread(playerID, playerData.ignoredPlayers).start();
}
//when a player spawns, conditionally apply temporary pvp protection