920 lines
38 KiB
Java
920 lines
38 KiB
Java
/*
|
|
* This file is part of GriefDefender, licensed under the MIT License (MIT).
|
|
*
|
|
* Copyright (c) bloodmc
|
|
* Copyright (c) contributors
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
package com.griefdefender;
|
|
|
|
import java.lang.ref.WeakReference;
|
|
import java.time.Duration;
|
|
import java.time.Instant;
|
|
import java.util.ArrayList;
|
|
import java.util.HashMap;
|
|
import java.util.HashSet;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.UUID;
|
|
import java.util.function.Consumer;
|
|
|
|
import org.bukkit.Bukkit;
|
|
import org.bukkit.Location;
|
|
import org.bukkit.World;
|
|
import org.bukkit.command.CommandSender;
|
|
import org.bukkit.entity.Player;
|
|
import org.bukkit.scheduler.BukkitTask;
|
|
|
|
import com.google.common.collect.ImmutableMap;
|
|
import com.google.common.collect.ImmutableSet;
|
|
import com.google.common.reflect.TypeToken;
|
|
import com.griefdefender.api.Tristate;
|
|
import com.griefdefender.api.User;
|
|
import com.griefdefender.api.claim.Claim;
|
|
import com.griefdefender.api.claim.ClaimType;
|
|
import com.griefdefender.api.claim.ShovelType;
|
|
import com.griefdefender.api.claim.ShovelTypes;
|
|
import com.griefdefender.api.data.PlayerData;
|
|
import com.griefdefender.api.permission.Context;
|
|
import com.griefdefender.api.permission.option.Options;
|
|
import com.griefdefender.api.permission.option.type.CreateModeType;
|
|
import com.griefdefender.api.permission.option.type.CreateModeTypes;
|
|
import com.griefdefender.api.permission.option.type.GameModeType;
|
|
import com.griefdefender.api.permission.option.type.GameModeTypes;
|
|
import com.griefdefender.api.permission.option.type.WeatherType;
|
|
import com.griefdefender.cache.EventResultCache;
|
|
import com.griefdefender.cache.MessageCache;
|
|
import com.griefdefender.cache.PermissionHolderCache;
|
|
import com.griefdefender.claim.GDClaim;
|
|
import com.griefdefender.configuration.MessageStorage;
|
|
import com.griefdefender.internal.block.BlockSnapshot;
|
|
import com.griefdefender.internal.block.BlockTransaction;
|
|
import com.griefdefender.internal.util.NMSUtil;
|
|
import com.griefdefender.permission.GDPermissionManager;
|
|
import com.griefdefender.permission.GDPermissionUser;
|
|
import com.griefdefender.permission.GDPermissions;
|
|
import com.griefdefender.permission.option.GDOptions;
|
|
import com.griefdefender.provider.VaultProvider;
|
|
import com.griefdefender.storage.BaseStorage;
|
|
import com.griefdefender.task.ClaimVisualRevertTask;
|
|
import com.griefdefender.util.PermissionUtil;
|
|
|
|
import net.kyori.text.Component;
|
|
|
|
public class GDPlayerData implements PlayerData {
|
|
|
|
public UUID playerID;
|
|
public UUID worldUniqueId;
|
|
private String worldName;
|
|
private WeakReference<GDPermissionUser> playerSubject;
|
|
private Set<Claim> claimList;
|
|
private Set<Context> optionContexts;
|
|
public Location lastAfkCheckLocation;
|
|
public Location lastShovelLocation;
|
|
public Location endShovelLocation;
|
|
public Location lastValidInspectLocation;
|
|
public Location lastNonAirInspectLocation;
|
|
public boolean isInvestigating = false;
|
|
public boolean claimMode = false;
|
|
public boolean claimTool = true;
|
|
public ShovelType shovelMode = ShovelTypes.BASIC;
|
|
|
|
public GDClaim claimResizing;
|
|
public GDClaim claimSubdividing;
|
|
public Map<UUID, Runnable> createBlockVisualRevertRunnables = new HashMap<>();
|
|
public Map<UUID, List<BlockTransaction>> createBlockVisualTransactions = new HashMap<>();
|
|
public Map<UUID, BukkitTask> claimVisualRevertTasks = new HashMap<>();
|
|
public Map<UUID, List<BlockTransaction>> visualClaimBlocks = new HashMap<>();
|
|
public List<BlockSnapshot> queuedVisuals = new ArrayList<>();
|
|
public UUID tempVisualUniqueId = null;
|
|
public UUID petRecipientUniqueId;
|
|
private final VaultProvider vaultProvider = GriefDefenderPlugin.getInstance().getVaultProvider();
|
|
|
|
public boolean ignoreClaims = false;
|
|
public boolean debugClaimPermissions = false;
|
|
public boolean inTown = false;
|
|
public boolean townChat = false;
|
|
public boolean lockPlayerDeathDrops = false;
|
|
public boolean trappedRequest = false;
|
|
public List<Component> chatLines = new ArrayList<>();
|
|
public Instant recordChatTimestamp;
|
|
public Instant commandInputTimestamp;
|
|
public String commandInput;
|
|
public Consumer<CommandSender> commandConsumer;
|
|
|
|
// Always ignore active contexts by default
|
|
// This prevents protection issues when other plugins call getActiveContext
|
|
public boolean ignoreActiveContexts = true;
|
|
|
|
public EventResultCache eventResultCache;
|
|
|
|
// collide event cache
|
|
public int lastCollideEntityId = 0;
|
|
public boolean lastCollideEntityResult = false;
|
|
|
|
private String playerName;
|
|
|
|
public boolean allowFlight = false;
|
|
public boolean ignoreFallDamage = false;
|
|
public boolean inLiquid = false;
|
|
|
|
public GameModeType lastGameMode = GameModeTypes.UNDEFINED;
|
|
|
|
// teleport data
|
|
public int teleportDelay = 0;
|
|
public Location teleportSourceLocation;
|
|
public Location teleportLocation;
|
|
|
|
public Instant lastPvpTimestamp;
|
|
public Instant lastTrappedTimestamp;
|
|
|
|
// cached global option values
|
|
public int minClaimLevel;
|
|
private CreateModeType optionClaimCreateMode;
|
|
|
|
// cached permission values
|
|
// admin cache
|
|
public boolean canManageAdminClaims = false;
|
|
public boolean canManageWilderness = false;
|
|
public boolean canManageGlobalOptions = false;
|
|
public boolean canManageAdminOptions = false;
|
|
public boolean canManageOverrideOptions = false;
|
|
public boolean canManageFlagDefaults = false;
|
|
public boolean canManageFlagOverrides = false;
|
|
public boolean bypassBorderCheck = false;
|
|
public boolean ignoreAdminClaims = false;
|
|
public boolean ignoreBasicClaims = false;
|
|
public boolean ignoreTowns = false;
|
|
public boolean ignoreWilderness = false;
|
|
// user cache
|
|
public boolean userOptionPerkFlyOwner = false;
|
|
public boolean userOptionPerkFlyAccessor = false;
|
|
public boolean userOptionPerkFlyBuilder = false;
|
|
public boolean userOptionPerkFlyContainer = false;
|
|
public boolean userOptionPerkFlyManager = false;
|
|
public boolean userOptionBypassPlayerDenyFlight = false;
|
|
public boolean userOptionBypassPlayerDenyGodmode = false;
|
|
public boolean userOptionBypassPlayerGamemode = false;
|
|
|
|
// option cache
|
|
public Boolean optionNoGodMode = null;
|
|
public Double optionFlySpeed = null;
|
|
public Double optionWalkSpeed = null;
|
|
public GameModeType optionGameModeType = null;
|
|
public WeatherType optionWeatherType = null;
|
|
|
|
public boolean dataInitialized = false;
|
|
public boolean showNoClaimsFoundMessage = true;
|
|
public boolean useRestoreSchematic = false;
|
|
private final int worldMaxHeight;
|
|
|
|
public GDPlayerData(UUID worldUniqueId, String worldName, UUID playerUniqueId, Set<Claim> claims) {
|
|
this.worldUniqueId = worldUniqueId;
|
|
this.worldName = worldName;
|
|
this.playerID = playerUniqueId;
|
|
this.claimList = claims;
|
|
final Set<Context> contexts = new HashSet<>();
|
|
if (!BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
|
|
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
|
|
contexts.add(new Context("world", this.worldName.toLowerCase()));
|
|
} else {
|
|
final String contextType = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.contextType;
|
|
if (contextType.equalsIgnoreCase("world")) {
|
|
contexts.add(new Context("world", this.worldName.toLowerCase()));
|
|
} else if (contextType.equalsIgnoreCase("global")) {
|
|
contexts.add(new Context("server", "global"));
|
|
} else {
|
|
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
|
|
}
|
|
}
|
|
this.worldMaxHeight = GriefDefenderPlugin.getInstance().dataStore.getClaimWorldManager(this.worldUniqueId).getWorldMaxHeight();
|
|
this.optionContexts = contexts;
|
|
this.refreshPlayerOptions();
|
|
}
|
|
|
|
// Run async
|
|
public void refreshPlayerOptions() {
|
|
//final GriefDefenderConfig<?> activeConfig = GriefDefenderPlugin.getActiveConfig(this.worldUniqueId);
|
|
GriefDefenderPlugin.getInstance().executor.execute(() -> {
|
|
if (this.playerSubject == null || this.playerSubject.get() == null) {
|
|
GDPermissionUser subject = PermissionHolderCache.getInstance().getOrCreateUser(this.playerID);
|
|
this.playerSubject = new WeakReference<>(subject);
|
|
}
|
|
final GDPermissionUser subject = this.playerSubject.get();
|
|
final Set<Context> activeContexts = new HashSet<>();
|
|
PermissionUtil.getInstance().addActiveContexts(activeContexts, subject);
|
|
// admin permissions
|
|
this.bypassBorderCheck = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.BYPASS_BORDER_CHECK, activeContexts).asBoolean();
|
|
this.ignoreAdminClaims = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.IGNORE_CLAIMS_ADMIN, activeContexts).asBoolean();
|
|
this.ignoreTowns = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.IGNORE_CLAIMS_TOWN, activeContexts).asBoolean();
|
|
this.ignoreWilderness = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.IGNORE_CLAIMS_WILDERNESS, activeContexts).asBoolean();
|
|
this.ignoreBasicClaims = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.IGNORE_CLAIMS_BASIC, activeContexts).asBoolean();
|
|
this.canManageAdminClaims = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.COMMAND_ADMIN_CLAIMS, activeContexts).asBoolean();
|
|
this.canManageWilderness = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_WILDERNESS, activeContexts).asBoolean();
|
|
this.canManageOverrideOptions = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_OVERRIDE_OPTIONS, activeContexts).asBoolean();
|
|
this.canManageGlobalOptions = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_GLOBAL_OPTIONS, activeContexts).asBoolean();
|
|
this.canManageAdminOptions = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_ADMIN_OPTIONS, activeContexts).asBoolean();
|
|
this.canManageFlagDefaults = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_FLAG_DEFAULTS, activeContexts).asBoolean();
|
|
this.canManageFlagOverrides = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.MANAGE_FLAG_OVERRIDES, activeContexts).asBoolean();
|
|
// user permissions
|
|
this.userOptionPerkFlyOwner = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.USER_OPTION_PERK_FLY_OWNER, activeContexts).asBoolean();
|
|
this.userOptionPerkFlyManager = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.USER_OPTION_PERK_FLY_MANAGER, activeContexts).asBoolean();
|
|
this.userOptionPerkFlyBuilder = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.USER_OPTION_PERK_FLY_BUILDER, activeContexts).asBoolean();
|
|
this.userOptionPerkFlyContainer = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.USER_OPTION_PERK_FLY_CONTAINER, activeContexts).asBoolean();
|
|
this.userOptionPerkFlyAccessor = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.USER_OPTION_PERK_FLY_ACCESSOR, activeContexts).asBoolean();
|
|
this.userOptionBypassPlayerDenyFlight = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.BYPASS_OPTION + "." + Options.PLAYER_DENY_FLIGHT.getName().toLowerCase(), activeContexts).asBoolean();
|
|
this.userOptionBypassPlayerDenyGodmode = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.BYPASS_OPTION + "." + Options.PLAYER_DENY_GODMODE.getName().toLowerCase(), activeContexts).asBoolean();
|
|
this.userOptionBypassPlayerGamemode = PermissionUtil.getInstance().getPermissionValue(subject, GDPermissions.BYPASS_OPTION + "." + Options.PLAYER_GAMEMODE.getName().toLowerCase(), activeContexts).asBoolean();
|
|
this.playerID = subject.getUniqueId();
|
|
this.dataInitialized = true;
|
|
});
|
|
}
|
|
|
|
@Override
|
|
public User getUser() {
|
|
return this.getSubject();
|
|
}
|
|
|
|
@Override
|
|
public String getName() {
|
|
if (this.playerName == null) {
|
|
GDPermissionUser user = null;
|
|
if (this.playerSubject != null) {
|
|
user = this.playerSubject.get();
|
|
}
|
|
if (user == null) {
|
|
user = PermissionHolderCache.getInstance().getOrCreateUser(this.playerID);
|
|
}
|
|
if (user != null) {
|
|
this.playerName = user.getFriendlyName();
|
|
}
|
|
if (this.playerName == null) {
|
|
this.playerName = "[unknown]";
|
|
}
|
|
}
|
|
|
|
return this.playerName;
|
|
}
|
|
|
|
@Override
|
|
public void revertAllVisuals() {
|
|
this.lastShovelLocation = null;
|
|
this.claimResizing = null;
|
|
this.claimSubdividing = null;
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (player == null) {
|
|
return;
|
|
}
|
|
if (this.visualClaimBlocks.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
for (Map.Entry<UUID, BukkitTask> mapEntry : this.claimVisualRevertTasks.entrySet()) {
|
|
mapEntry.getValue().cancel();
|
|
}
|
|
|
|
final List<UUID> visualIds = new ArrayList<>(this.visualClaimBlocks.keySet());
|
|
for (UUID visualUniqueId : visualIds) {
|
|
final Claim claim = GriefDefenderPlugin.getInstance().dataStore.getClaim(player.getWorld().getUID(), visualUniqueId);
|
|
this.revertVisualBlocks(player, (GDClaim) claim, visualUniqueId);
|
|
}
|
|
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
|
|
GriefDefenderPlugin.getInstance().getWorldEditProvider().revertAllVisuals(this.playerID);
|
|
}
|
|
// Revert any temp visuals
|
|
this.revertTempVisuals();
|
|
}
|
|
|
|
public void revertTempVisuals() {
|
|
if (this.tempVisualUniqueId != null) {
|
|
this.revertClaimVisual(null, this.tempVisualUniqueId);
|
|
this.tempVisualUniqueId = null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void revertVisual(UUID uuid) {
|
|
final Claim claim = GriefDefenderPlugin.getInstance().dataStore.getClaim(this.worldUniqueId, uuid);
|
|
this.revertClaimVisual((GDClaim) claim, uuid);
|
|
}
|
|
|
|
@Override
|
|
public void revertVisual(Claim claim) {
|
|
this.revertClaimVisual((GDClaim) claim);
|
|
}
|
|
|
|
public void revertClaimVisual(GDClaim claim) {
|
|
this.revertClaimVisual(claim, claim.getUniqueId());
|
|
}
|
|
|
|
public void revertClaimVisual(GDClaim claim, UUID visualUniqueId) {
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (player == null) {
|
|
return;
|
|
}
|
|
|
|
for (Map.Entry<UUID, BukkitTask> mapEntry : this.claimVisualRevertTasks.entrySet()) {
|
|
if (visualUniqueId.equals(mapEntry.getKey())) {
|
|
mapEntry.getValue().cancel();
|
|
break;
|
|
}
|
|
}
|
|
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
|
|
GriefDefenderPlugin.getInstance().getWorldEditProvider().revertClaimCUIVisual(visualUniqueId, this.playerID);
|
|
}
|
|
|
|
this.revertVisualBlocks(player, claim, visualUniqueId);
|
|
}
|
|
|
|
private void revertVisualBlocks(Player player, GDClaim claim, UUID visualUniqueId) {
|
|
final List<BlockTransaction> visualTransactions = this.visualClaimBlocks.get(visualUniqueId);
|
|
if (visualTransactions == null || visualTransactions.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
// Gather create block visuals
|
|
final List<BlockTransaction> createBlockVisualTransactions = new ArrayList<>();
|
|
for (Runnable runnable : this.createBlockVisualRevertRunnables.values()) {
|
|
final ClaimVisualRevertTask revertTask = (ClaimVisualRevertTask) runnable;
|
|
if (revertTask.getVisualUniqueId().equals(visualUniqueId)) {
|
|
continue;
|
|
}
|
|
final List<BlockTransaction> blockTransactions = this.createBlockVisualTransactions.get(revertTask.getVisualUniqueId());
|
|
if (blockTransactions != null) {
|
|
createBlockVisualTransactions.addAll(blockTransactions);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < visualTransactions.size(); i++) {
|
|
BlockSnapshot snapshot = visualTransactions.get(i).getOriginal();
|
|
// If original block does not exist or chunk is not loaded, do not send to player
|
|
if (!snapshot.matchesWorldState()) {
|
|
if (claim != null) {
|
|
claim.markVisualDirty = true;
|
|
}
|
|
continue;
|
|
}
|
|
boolean ignoreVisual = false;
|
|
for (BlockTransaction createVisualTransaction : createBlockVisualTransactions) {
|
|
if (createVisualTransaction.getOriginal().getLocation().equals(snapshot.getLocation())) {
|
|
ignoreVisual = true;
|
|
break;
|
|
}
|
|
}
|
|
if (ignoreVisual) {
|
|
continue;
|
|
}
|
|
NMSUtil.getInstance().sendBlockChange(player, snapshot);
|
|
}
|
|
if (claim != null) {
|
|
claim.playersWatching.remove(this.playerID);
|
|
}
|
|
|
|
this.claimVisualRevertTasks.remove(visualUniqueId);
|
|
this.visualClaimBlocks.remove(visualUniqueId);
|
|
this.createBlockVisualRevertRunnables.remove(visualUniqueId);
|
|
this.createBlockVisualTransactions.remove(visualUniqueId);
|
|
}
|
|
|
|
@Override
|
|
public int getBlocksAccruedPerHour() {
|
|
final Integer value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.BLOCKS_ACCRUED_PER_HOUR);
|
|
if (value == null) {
|
|
return Options.BLOCKS_ACCRUED_PER_HOUR.getDefaultValue();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public int getChestClaimExpiration() {
|
|
final Integer value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.CHEST_EXPIRATION);
|
|
if (value == null) {
|
|
return Options.CHEST_EXPIRATION.getDefaultValue();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public int getCreateClaimLimit(ClaimType type) {
|
|
final Integer value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.CREATE_LIMIT, type);
|
|
if (value == null) {
|
|
return Options.CREATE_LIMIT.getDefaultValue();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public CreateModeType getCreateMode() {
|
|
final CreateModeType value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(CreateModeType.class), this.getSubject(), Options.CREATE_MODE);
|
|
if (value == null || value == CreateModeTypes.UNDEFINED) {
|
|
return CreateModeTypes.AREA;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
@Override
|
|
public int getInitialClaimBlocks() {
|
|
final Integer value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.INITIAL_BLOCKS);
|
|
if (value == null) {
|
|
return Options.INITIAL_BLOCKS.getDefaultValue();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public double getInternalEconomyBlockCost() {
|
|
final Double value = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), this.getSubject(), Options.ECONOMY_BLOCK_COST);
|
|
if (value == null) {
|
|
return Options.ECONOMY_BLOCK_COST.getDefaultValue();
|
|
}
|
|
return value;
|
|
}
|
|
|
|
public int getInternalRemainingClaimBlocks() {
|
|
final int initialClaimBlocks = this.getInitialClaimBlocks();
|
|
int remainingBlocks = initialClaimBlocks + this.getAccruedClaimBlocks() + this.getBonusClaimBlocks();
|
|
|
|
for (Claim claim : this.claimList) {
|
|
if (claim.isSubdivision()) {
|
|
continue;
|
|
}
|
|
|
|
GDClaim gpClaim = (GDClaim) claim;
|
|
if ((gpClaim.parent == null || gpClaim.parent.isAdminClaim()) && claim.getData().requiresClaimBlocks()) {
|
|
remainingBlocks -= claim.getClaimBlocks();
|
|
}
|
|
}
|
|
|
|
return remainingBlocks;
|
|
}
|
|
|
|
@Override
|
|
public int getRemainingClaimBlocks() {
|
|
final int initialClaimBlocks = this.getInitialClaimBlocks();
|
|
int remainingBlocks = initialClaimBlocks + this.getAccruedClaimBlocks() + this.getBonusClaimBlocks();
|
|
|
|
if (GriefDefenderPlugin.getInstance().isEconomyModeEnabled()) {
|
|
return this.getInternalEconomyAvailablePurchaseCost();
|
|
} else {
|
|
for (Claim claim : this.claimList) {
|
|
if (claim.isSubdivision()) {
|
|
continue;
|
|
}
|
|
|
|
GDClaim gpClaim = (GDClaim) claim;
|
|
if ((gpClaim.parent == null || gpClaim.parent.isAdminClaim()) && claim.getData().requiresClaimBlocks()) {
|
|
remainingBlocks -= claim.getClaimBlocks();
|
|
}
|
|
}
|
|
}
|
|
|
|
return remainingBlocks;
|
|
}
|
|
|
|
public int getInternalEconomyAvailablePurchaseCost() {
|
|
if (GriefDefenderPlugin.getInstance().isEconomyModeEnabled()) {
|
|
if (!this.vaultProvider.getApi().hasAccount(this.getSubject().getOfflinePlayer())) {
|
|
return 0;
|
|
}
|
|
|
|
final double currentFunds = this.vaultProvider.getApi().getBalance(this.getSubject().getOfflinePlayer());
|
|
final Double economyBlockCost = this.getInternalEconomyBlockCost();
|
|
return (int) Math.round((currentFunds / economyBlockCost));
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
public int getTotalClaimsCost() {
|
|
int totalCost = 0;
|
|
for (Claim claim : this.claimList) {
|
|
if (claim.isSubdivision()) {
|
|
continue;
|
|
}
|
|
|
|
final GDClaim gpClaim = (GDClaim) claim;
|
|
if ((gpClaim.parent == null || gpClaim.parent.isAdminClaim()) && claim.getData().requiresClaimBlocks()) {
|
|
totalCost += claim.getClaimBlocks();
|
|
}
|
|
}
|
|
|
|
return totalCost;
|
|
}
|
|
|
|
public double getRemainingChunks() {
|
|
final double remainingChunks = this.getRemainingClaimBlocks() / 65536.0;
|
|
return Math.round(remainingChunks * 100.0)/100.0;
|
|
}
|
|
|
|
@Override
|
|
public int getAccruedClaimBlocks() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.ACCRUED_BLOCKS, new HashSet<>(this.optionContexts));
|
|
}
|
|
|
|
public boolean addAccruedClaimBlocks(int newAccruedClaimBlocks) {
|
|
int currentTotal = this.getAccruedClaimBlocks();
|
|
if ((currentTotal + newAccruedClaimBlocks) > this.getMaxAccruedClaimBlocks()) {
|
|
return false;
|
|
}
|
|
|
|
this.setAccruedClaimBlocks(currentTotal + newAccruedClaimBlocks);
|
|
return true;
|
|
}
|
|
|
|
public boolean setAccruedClaimBlocks(int newAccruedClaimBlocks) {
|
|
return this.setAccruedClaimBlocks(newAccruedClaimBlocks, true);
|
|
}
|
|
|
|
public boolean setAccruedClaimBlocks(int newAccruedClaimBlocks, boolean checkMax) {
|
|
if (checkMax && newAccruedClaimBlocks > this.getMaxAccruedClaimBlocks()) {
|
|
return false;
|
|
}
|
|
|
|
GDPermissionManager.getInstance().setOption(Options.ACCRUED_BLOCKS, this.getSubject(), String.valueOf(newAccruedClaimBlocks), new HashSet<>(this.optionContexts));
|
|
return true;
|
|
}
|
|
|
|
public int getBonusClaimBlocks() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.BONUS_BLOCKS, new HashSet<>(this.optionContexts));
|
|
}
|
|
|
|
public void setBonusClaimBlocks(int bonusClaimBlocks) {
|
|
GDPermissionManager.getInstance().setOption(Options.BONUS_BLOCKS, this.getSubject(), String.valueOf(bonusClaimBlocks), new HashSet<>(this.optionContexts));
|
|
}
|
|
|
|
public CreateModeType getClaimCreateMode() {
|
|
if (this.optionClaimCreateMode == null) {
|
|
CreateModeType mode = this.getCreateMode();
|
|
// default to 0 if invalid
|
|
if (mode == null) {
|
|
mode = CreateModeTypes.AREA;
|
|
}
|
|
this.optionClaimCreateMode = mode;
|
|
}
|
|
|
|
return this.optionClaimCreateMode;
|
|
}
|
|
|
|
public void setClaimCreateMode(CreateModeType mode) {
|
|
this.optionClaimCreateMode = mode;
|
|
}
|
|
|
|
public boolean canCreateClaim(Player player) {
|
|
return canCreateClaim(player, false);
|
|
}
|
|
|
|
public boolean canCreateClaim(Player player, boolean sendMessage) {
|
|
final CreateModeType createMode = this.getClaimCreateMode();
|
|
if (this.shovelMode == ShovelTypes.BASIC) {
|
|
if (createMode == CreateModeTypes.AREA && !player.hasPermission(GDPermissions.CLAIM_CREATE_BASIC)) {
|
|
if (sendMessage) {
|
|
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_CLAIM_CREATE);
|
|
}
|
|
return false;
|
|
}
|
|
if (createMode == CreateModeTypes.VOLUME && !player.hasPermission(GDPermissions.CLAIM_CUBOID_BASIC)) {
|
|
if (sendMessage) {
|
|
GriefDefenderPlugin.sendMessage(player,MessageCache.getInstance().PERMISSION_CUBOID);
|
|
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().COMMAND_CUBOID_DISABLED);
|
|
}
|
|
return false;
|
|
}
|
|
} else if (this.shovelMode == ShovelTypes.SUBDIVISION) {
|
|
if (createMode == CreateModeTypes.AREA && !player.hasPermission(GDPermissions.CLAIM_CREATE_SUBDIVISION)) {
|
|
if (sendMessage) {
|
|
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_CLAIM_CREATE);
|
|
}
|
|
return false;
|
|
} else if (createMode == CreateModeTypes.VOLUME && !player.hasPermission(GDPermissions.CLAIM_CUBOID_SUBDIVISION)) {
|
|
if (sendMessage) {
|
|
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().PERMISSION_CUBOID);
|
|
GriefDefenderPlugin.sendMessage(player, MessageCache.getInstance().COMMAND_CUBOID_DISABLED);
|
|
}
|
|
return false;
|
|
}
|
|
} else if (this.shovelMode == ShovelTypes.ADMIN) {
|
|
if (createMode == CreateModeTypes.AREA && !player.hasPermission(GDPermissions.COMMAND_ADMIN_CLAIMS)) {
|
|
return false;
|
|
} else if (!player.hasPermission(GDPermissions.CLAIM_CUBOID_ADMIN)) {
|
|
return false;
|
|
}
|
|
} else if (this.shovelMode == ShovelTypes.TOWN) {
|
|
if (createMode == CreateModeTypes.AREA && !player.hasPermission(GDPermissions.CLAIM_CREATE_TOWN)) {
|
|
return false;
|
|
} else if (!player.hasPermission(GDPermissions.CLAIM_CUBOID_TOWN)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public Set<Claim> getClaims() {
|
|
return ImmutableSet.copyOf(this.claimList);
|
|
}
|
|
|
|
public Set<Claim> getInternalClaims() {
|
|
return this.claimList;
|
|
}
|
|
|
|
public int getClaimTypeCount(ClaimType type) {
|
|
int count = 0;
|
|
for (Claim claim : this.claimList) {
|
|
if (claim.getType() == type) {
|
|
count++;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
public void setLastCollideEntityData(int entityId, boolean result) {
|
|
this.lastCollideEntityId = entityId;
|
|
this.lastCollideEntityResult = result;
|
|
}
|
|
|
|
public void setIgnoreClaims(boolean flag) {
|
|
this.ignoreClaims = flag;
|
|
}
|
|
|
|
@Override
|
|
public boolean canIgnoreClaim(Claim claim) {
|
|
if (claim == null || this.ignoreClaims == false) {
|
|
return false;
|
|
}
|
|
|
|
if (claim.isAdminClaim()) {
|
|
return this.ignoreAdminClaims;
|
|
} else if (claim.isWilderness()) {
|
|
return this.ignoreWilderness;
|
|
} else if (claim.isTown()) {
|
|
return this.ignoreTowns;
|
|
}
|
|
return this.ignoreBasicClaims;
|
|
}
|
|
|
|
@Override
|
|
public int getMaxAccruedClaimBlocks() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MAX_ACCRUED_BLOCKS);
|
|
}
|
|
|
|
@Override
|
|
public double getAbandonedReturnRatio(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), this.getSubject(), Options.ABANDON_RETURN_RATIO);
|
|
}
|
|
|
|
@Override
|
|
public int getMaxClaimX(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MAX_SIZE_X, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMaxClaimY(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MAX_SIZE_Y, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMaxClaimZ(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MAX_SIZE_Z, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMinClaimX(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MIN_SIZE_X, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMinClaimY(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MIN_SIZE_Y, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMinClaimZ(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MIN_SIZE_Z, type);
|
|
}
|
|
|
|
@Override
|
|
public int getMaxClaimLevel() {
|
|
int maxClaimLevel = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MAX_LEVEL);
|
|
if (this.worldMaxHeight > -1 && this.worldMaxHeight < maxClaimLevel) {
|
|
maxClaimLevel = this.worldMaxHeight;
|
|
}
|
|
return maxClaimLevel;
|
|
}
|
|
|
|
@Override
|
|
public int getMinClaimLevel() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.MIN_LEVEL);
|
|
}
|
|
|
|
@Override
|
|
public double getEconomyClaimBlockCost() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), this.getSubject(), Options.ECONOMY_BLOCK_COST);
|
|
}
|
|
|
|
@Override
|
|
public double getEconomyClaimBlockReturn() {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), this.getSubject(), Options.ECONOMY_BLOCK_SELL_RETURN);
|
|
}
|
|
|
|
@Override
|
|
public double getTaxRate(ClaimType type) {
|
|
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), this.getSubject(), Options.TAX_RATE, type);
|
|
}
|
|
|
|
@Override
|
|
public UUID getUniqueId() {
|
|
return this.getSubject().getUniqueId();
|
|
}
|
|
|
|
public GDPermissionUser getSubject() {
|
|
if (this.playerSubject == null || this.playerSubject.get() == null) {
|
|
GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(this.playerID);
|
|
this.playerSubject = new WeakReference<>(user);
|
|
}
|
|
|
|
return this.playerSubject.get();
|
|
}
|
|
|
|
public void sendTaxExpireMessage(Player player, GDClaim claim) {
|
|
final double taxRate = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), player, Options.TAX_RATE, claim);
|
|
final double taxOwed = claim.getClaimBlocks() * taxRate;
|
|
final double remainingDays = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), player, Options.TAX_EXPIRATION_DAYS_KEEP, claim);
|
|
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.TAX_EXPIRED, ImmutableMap.of(
|
|
"days", remainingDays,
|
|
"amount", taxOwed));
|
|
GriefDefenderPlugin.sendClaimDenyMessage(claim, player, message);
|
|
}
|
|
|
|
public double getTotalTax() {
|
|
double totalTax = 0;
|
|
final GDPermissionUser subject = this.getSubject();
|
|
for (Claim claim : this.getInternalClaims()) {
|
|
double playerTaxRate = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Double.class), subject, Options.TAX_RATE, claim);
|
|
totalTax += (claim.getClaimBlocks() / 256) * playerTaxRate;
|
|
}
|
|
|
|
return totalTax;
|
|
}
|
|
|
|
@Override
|
|
public boolean canPvp(Claim claim) {
|
|
if (!((GDClaim) claim).getWorld().getPVP()) {
|
|
return false;
|
|
}
|
|
if (!claim.isPvpAllowed()) {
|
|
return false;
|
|
}
|
|
|
|
if (GDOptions.PVP) {
|
|
final Tristate result = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Tristate.class), this.getSubject(), Options.PVP, claim);
|
|
if (result != Tristate.UNDEFINED) {
|
|
return result.asBoolean();
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public boolean inPvpCombat() {
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (this.lastPvpTimestamp == null || player == null) {
|
|
return false;
|
|
}
|
|
|
|
final Instant now = Instant.now();
|
|
final int combatTimeout = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), player, Options.PVP_COMBAT_TIMEOUT);
|
|
if (combatTimeout <= 0) {
|
|
return false;
|
|
}
|
|
|
|
if (this.lastPvpTimestamp.plusSeconds(combatTimeout).isBefore(now)) {
|
|
this.lastPvpTimestamp = null;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
@Override
|
|
public int getRemainingPvpCombatTime(Claim claim) {
|
|
return this.getPvpCombatTimeRemaining((GDClaim) claim);
|
|
}
|
|
|
|
public int getPvpCombatTimeRemaining(GDClaim claim) {
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (this.lastPvpTimestamp == null || player == null) {
|
|
return 0;
|
|
}
|
|
|
|
final Instant now = Instant.now();
|
|
int combatTimeout = 0;
|
|
if (GDOptions.PVP_COMBAT_TIMEOUT) {
|
|
combatTimeout = GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), player, Options.PVP_COMBAT_TIMEOUT, claim);
|
|
}
|
|
if (combatTimeout <= 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (this.lastPvpTimestamp.plusSeconds(combatTimeout).isBefore(now)) {
|
|
this.lastPvpTimestamp = null;
|
|
return 0;
|
|
}
|
|
|
|
final int duration = (int) Duration.between(this.lastPvpTimestamp, now).getSeconds();
|
|
return combatTimeout - duration;
|
|
}
|
|
|
|
public void updateRecordChat() {
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (this.recordChatTimestamp == null || player == null) {
|
|
return;
|
|
}
|
|
|
|
final Instant now = Instant.now();
|
|
final int timeout = GriefDefenderPlugin.getGlobalConfig().getConfig().gui.chatCaptureIdleTimeout;
|
|
if (timeout <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (this.recordChatTimestamp.plusSeconds(timeout).isBefore(now)) {
|
|
this.recordChatTimestamp = null;
|
|
}
|
|
}
|
|
|
|
public boolean isRecordingChat() {
|
|
return this.recordChatTimestamp != null;
|
|
}
|
|
|
|
public void updateCommandInput() {
|
|
final Player player = this.getSubject().getOnlinePlayer();
|
|
if (this.commandInputTimestamp == null || player == null) {
|
|
return;
|
|
}
|
|
|
|
final Instant now = Instant.now();
|
|
final int timeout = GriefDefenderPlugin.getGlobalConfig().getConfig().gui.commandInputIdleTimeout;
|
|
if (timeout <= 0) {
|
|
return;
|
|
}
|
|
|
|
if (this.commandInputTimestamp.plusSeconds(timeout).isBefore(now)) {
|
|
this.commandInputTimestamp = null;
|
|
}
|
|
}
|
|
|
|
public boolean isWaitingForInput() {
|
|
return this.commandInputTimestamp != null;
|
|
}
|
|
|
|
public void onClaimDelete() {
|
|
this.lastShovelLocation = null;
|
|
this.eventResultCache = null;
|
|
this.claimResizing = null;
|
|
this.claimSubdividing = null;
|
|
}
|
|
|
|
public void resetOptionCache() {
|
|
this.optionNoGodMode = null;
|
|
this.optionFlySpeed = null;
|
|
this.optionWalkSpeed = null;
|
|
this.optionGameModeType = null;
|
|
this.optionWeatherType = null;
|
|
}
|
|
|
|
public void onDisconnect() {
|
|
this.claimVisualRevertTasks.clear();
|
|
this.visualClaimBlocks.clear();
|
|
this.createBlockVisualTransactions.clear();
|
|
this.createBlockVisualRevertRunnables.clear();
|
|
this.queuedVisuals.clear();
|
|
this.claimMode = false;
|
|
this.claimTool = true;
|
|
this.debugClaimPermissions = false;
|
|
this.ignoreClaims = false;
|
|
this.lastShovelLocation = null;
|
|
this.eventResultCache = null;
|
|
this.claimResizing = null;
|
|
this.claimSubdividing = null;
|
|
this.commandInputTimestamp = null;
|
|
this.recordChatTimestamp = null;
|
|
this.tempVisualUniqueId = null;
|
|
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
|
|
GriefDefenderPlugin.getInstance().getWorldEditProvider().revertAllVisuals(this.playerID);
|
|
}
|
|
}
|
|
} |