Move playerdata file format to permissions as meta.

All file player data which stores accrued and bonus claim block totals
will now be stored with permissions as meta. This allows servers that
share permissions data across multiple servers to also provide the same
GD player data across servers if configured to do so.

In order to migrate the file player data, the following must be
configured :

1. Under the 'playerdata' section in 'global.conf', the
'context-storage-type' needs to be set to 'global', 'server', or
'world'. Read comment for more information.
2. Under the 'migrator' section in 'global.conf', the 'playerdata'
setting needs to be set to true. Make sure to read the comment carefully
as there are things to check before turning on the migrator.

As always, backup your permissions data before enabling the migrator.

Note: GD will no longer use the file player data. If you do not
migrate, all players will have 0 accrued and 0 bonus claim blocks.
Simply enable the migrator and follow the steps above to maintain the
current player data.
This commit is contained in:
bloodshot 2020-01-25 01:07:02 -05:00
parent 6e45cd866a
commit 23e7daab72
49 changed files with 522 additions and 206 deletions

@ -1 +1 @@
Subproject commit 77a0a3f713aece41a2cccfbe4a13c87b4dd2d139
Subproject commit b95657786652905ed1da6cfe55db4d9eebe1881e

View File

@ -68,6 +68,7 @@ import com.griefdefender.permission.GDPermissionManager;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.GDPermissions;
import com.griefdefender.provider.VaultProvider;
import com.griefdefender.storage.BaseStorage;
import com.griefdefender.util.PermissionUtil;
import net.kyori.text.Component;
@ -76,9 +77,10 @@ public class GDPlayerData implements PlayerData {
public UUID playerID;
public UUID worldUniqueId;
private String worldName;
private WeakReference<GDPermissionUser> playerSubject;
private Set<Claim> claimList;
private PlayerStorageData playerStorage;
private Set<Context> optionContexts;
public Location lastAfkCheckLocation;
public Location lastShovelLocation;
public Location endShovelLocation;
@ -154,11 +156,26 @@ public class GDPlayerData implements PlayerData {
public boolean useRestoreSchematic = false;
private boolean checkedDimensionHeight = false;
public GDPlayerData(UUID worldUniqueId, UUID playerUniqueId, PlayerStorageData playerStorage, GriefDefenderConfig<?> activeConfig, Set<Claim> claims) {
public GDPlayerData(UUID worldUniqueId, String worldName, UUID playerUniqueId, Set<Claim> claims) {
this.worldUniqueId = worldUniqueId;
this.worldName = worldName;
this.playerID = playerUniqueId;
this.playerStorage = playerStorage;
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.optionContexts = contexts;
this.refreshPlayerOptions();
}
@ -377,7 +394,7 @@ public class GDPlayerData implements PlayerData {
@Override
public int getAccruedClaimBlocks() {
return this.playerStorage.getConfig().getAccruedClaimBlocks();
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.ACCRUED_BLOCKS, new HashSet<>(this.optionContexts));
}
public boolean addAccruedClaimBlocks(int newAccruedClaimBlocks) {
@ -386,7 +403,7 @@ public class GDPlayerData implements PlayerData {
return false;
}
this.playerStorage.getConfig().setAccruedClaimBlocks(currentTotal + newAccruedClaimBlocks);
this.setAccruedClaimBlocks(currentTotal + newAccruedClaimBlocks);
return true;
}
@ -395,16 +412,16 @@ public class GDPlayerData implements PlayerData {
return false;
}
this.playerStorage.getConfig().setAccruedClaimBlocks(newAccruedClaimBlocks);
GDPermissionManager.getInstance().setOption(Options.ACCRUED_BLOCKS, this.getSubject(), String.valueOf(newAccruedClaimBlocks), new HashSet<>(this.optionContexts));
return true;
}
public int getBonusClaimBlocks() {
return this.playerStorage.getConfig().getBonusClaimBlocks();
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.BONUS_BLOCKS, new HashSet<>(this.optionContexts));
}
public void setBonusClaimBlocks(int bonusClaimBlocks) {
this.playerStorage.getConfig().setBonusClaimBlocks(bonusClaimBlocks);
GDPermissionManager.getInstance().setOption(Options.BONUS_BLOCKS, this.getSubject(), String.valueOf(bonusClaimBlocks), new HashSet<>(this.optionContexts));
}
public CreateModeType getClaimCreateMode() {
@ -474,14 +491,6 @@ public class GDPlayerData implements PlayerData {
return true;
}
public void saveAllData() {
this.playerStorage.save();
}
public PlayerStorageData getStorageData() {
return this.playerStorage;
}
public Set<Claim> getClaims() {
return ImmutableSet.copyOf(this.claimList);
}

View File

@ -864,7 +864,7 @@ public class GriefDefenderPlugin {
MessageCache.getInstance().loadCache();
BaseStorage.globalConfig.getConfig().customFlags.initDefaults();
BaseStorage.globalConfig.save();
BaseStorage.USE_GLOBAL_PLAYER_STORAGE = BaseStorage.globalConfig.getConfig().playerdata.useGlobalPlayerDataStorage;
BaseStorage.USE_GLOBAL_PLAYER_STORAGE = !BaseStorage.globalConfig.getConfig().playerdata.useWorldPlayerData();
GDFlags.populateFlagStatus();
PermissionHolderCache.getInstance().getOrCreatePermissionCache(GriefDefenderPlugin.DEFAULT_HOLDER).invalidateAll();
CLAIM_BLOCK_SYSTEM = BaseStorage.globalConfig.getConfig().playerdata.claimBlockSystem;

View File

@ -80,6 +80,7 @@ public class GDClaimManager implements ClaimManager {
private static final BaseStorage DATASTORE = GriefDefenderPlugin.getInstance().dataStore;
private UUID worldUniqueId;
private String worldName;
private GriefDefenderConfig<?> activeConfig;
// Player UUID -> player data
@ -98,6 +99,7 @@ public class GDClaimManager implements ClaimManager {
public GDClaimManager(World world) {
this.worldUniqueId = world.getUID();
this.worldName = world.getName();
this.activeConfig = GriefDefenderPlugin.getActiveConfig(this.worldUniqueId);
this.playerIndexStorage = new PlayerIndexStorage(world);
}
@ -112,16 +114,8 @@ public class GDClaimManager implements ClaimManager {
}
private GDPlayerData createPlayerData(UUID playerUniqueId) {
Path playerFilePath = null;
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
playerFilePath = BaseStorage.globalPlayerDataPath.resolve(playerUniqueId.toString());
} else {
playerFilePath = BaseStorage.worldConfigMap.get(this.worldUniqueId).getPath().getParent().resolve("PlayerData").resolve(playerUniqueId.toString());
}
PlayerStorageData playerStorage = new PlayerStorageData(playerFilePath);
Set<Claim> claimList = this.createPlayerClaimList(playerUniqueId);
GDPlayerData playerData = new GDPlayerData(this.worldUniqueId, playerUniqueId, playerStorage, this.activeConfig, claimList);
GDPlayerData playerData = new GDPlayerData(this.worldUniqueId, this.worldName, playerUniqueId, claimList);
this.getPlayerDataMap().put(playerUniqueId, playerData);
return playerData;
}
@ -486,10 +480,6 @@ public class GDClaimManager implements ClaimManager {
gpClaim.save();
}
this.getWildernessClaim().save();
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
playerData.getStorageData().save();
}
}
public void unload() {
@ -604,14 +594,6 @@ public class GDClaimManager implements ClaimManager {
}
public void resetPlayerData() {
// check migration reset
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.resetMigrations) {
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
final PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setMigratedBlocks(false);
playerStorage.save();
}
}
// migrate playerdata to new claim block system
final int migration3dRate = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.migrateVolumeRate;
final int migration2dRate = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.migrateAreaRate;
@ -628,19 +610,16 @@ public class GDClaimManager implements ClaimManager {
}
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
final PlayerStorageData playerStorage = playerData.getStorageData();
final int accruedBlocks = playerStorage.getConfig().getAccruedClaimBlocks();
final int accruedBlocks = playerData.getAccruedClaimBlocks();
int newAccruedBlocks = accruedBlocks;
// first check reset
if (resetClaimBlockData) {
newAccruedBlocks = playerData.getTotalClaimsCost();
playerStorage.getConfig().setBonusClaimBlocks(0);
} else if (migration3dRate > -1 && !playerStorage.getConfig().hasMigratedBlocks()) {
playerData.setBonusClaimBlocks(0);
} else if (migration3dRate > -1) {
newAccruedBlocks = accruedBlocks * migration3dRate;
playerStorage.getConfig().setMigratedBlocks(true);
} else if (migration2dRate > -1 && !playerStorage.getConfig().hasMigratedBlocks()) {
} else if (migration2dRate > -1) {
newAccruedBlocks = accruedBlocks / migration2dRate;
playerStorage.getConfig().setMigratedBlocks(true);
}
if (newAccruedBlocks < 0) {
newAccruedBlocks = 0;
@ -649,8 +628,7 @@ public class GDClaimManager implements ClaimManager {
if (newAccruedBlocks > maxAccruedBlocks) {
newAccruedBlocks = maxAccruedBlocks;
}
playerStorage.getConfig().setAccruedClaimBlocks(newAccruedBlocks);
playerStorage.save();
playerData.setAccruedClaimBlocks(newAccruedBlocks);
}
}

View File

@ -77,7 +77,6 @@ public class CommandAdjustBonusClaimBlocks extends BaseCommand {
// give blocks to player
GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(world.getUID(), user.getUniqueId());
playerData.setBonusClaimBlocks(playerData.getBonusClaimBlocks() + adjustment);
playerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ADJUST_BONUS_BLOCKS_SUCCESS, ImmutableMap.of(
"player", user.getName(),
"amount", adjustment,

View File

@ -112,8 +112,6 @@ public class CommandClaimBuyBlocks extends BaseCommand {
final int bonusTotal = playerData.getBonusClaimBlocks();
playerData.setBonusClaimBlocks(bonusTotal + blockCount);
playerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_BLOCK_PURCHASE_CONFIRMATION, ImmutableMap.of(
"amount", totalCost,
"balance", playerData.getRemainingClaimBlocks()));

View File

@ -141,7 +141,7 @@ public class CommandClaimSellBlocks extends BaseCommand {
accruedBlocks = (int) (accruedBlocks - blockCount);
playerData.setAccruedClaimBlocks(accruedBlocks);
}
playerData.saveAllData();
GriefDefenderPlugin.sendMessage(player, message);
}
}

View File

@ -77,8 +77,6 @@ public class CommandGiveBlocks extends BaseCommand {
}
final GDPlayerData targetPlayerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(src.getWorld(), targetPlayer.getUniqueId());
targetPlayerData.setBonusClaimBlocks(targetPlayerData.getBonusClaimBlocks() + amount);
playerData.getStorageData().save();
targetPlayerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.COMMAND_GIVEBLOCKS_CONFIRMED);
TextAdapter.sendComponent(src, message);

View File

@ -102,7 +102,6 @@ public class CommandSetAccruedClaimBlocks extends BaseCommand {
return;
}
playerData.getStorageData().save();
GriefDefenderPlugin.sendMessage(src, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ADJUST_ACCRUED_BLOCKS_SUCCESS,
ImmutableMap.of(
"player", user.getName(),

View File

@ -77,6 +77,8 @@ public class DefaultPermissionCategory extends ConfigCategory {
final int maxAccruedBlocks = GriefDefenderPlugin.CLAIM_BLOCK_SYSTEM == ClaimBlockSystem.VOLUME ? 20480000 : 80000;
this.defaultUserOptions.put(Options.ABANDON_DELAY.getName(), "0");
this.defaultUserOptions.put(Options.ABANDON_RETURN_RATIO.getName(), "1.0");
this.defaultUserOptions.put(Options.ACCRUED_BLOCKS.getName(), "0");
this.defaultUserOptions.put(Options.BONUS_BLOCKS.getName(), "0");
this.defaultUserOptions.put(Options.BLOCKS_ACCRUED_PER_HOUR.getName(), "120");
this.defaultUserOptions.put(Options.CHEST_EXPIRATION.getName(), "7");
this.defaultUserOptions.put(Options.CREATE_LIMIT.getName(), "-1");

View File

@ -40,4 +40,11 @@ public class MigratorCategory extends ConfigCategory {
"\nNote: Only cuboid regions are supported." +
"\nNote: It is recommended to backup data before using.")
public boolean worldGuardMigrator = false;
@Setting(value = "playerdata", comment = "Set to true to enable the legacy playerdata file migrator."
+ "\nNote: Migrates legacy playerdata file format to permissions storage such as LuckPerms json or mysql storage."
+ "\nNote: Before turning this on, make sure you properly set 'context-storage-type' in the the playerdata section of this config."
+ "\nNote: It is HIGHLY recommended to backup your permissions database before running this migrator as all local playerdata files will be migrated to it."
+ "\nNote: Do NOT run this migrator on more than one server if multiple servers share the same permissions database.")
public boolean playerDataMigrator = false;
}

View File

@ -31,8 +31,12 @@ import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable
public class PlayerDataCategory extends ConfigCategory {
@Setting(value = "use-global-storage", comment = "Whether player data should be stored globally. False will store all data per world.")
public boolean useGlobalPlayerDataStorage = true;
@Setting(value = "context-storage-type", comment = "The context type used when storing playerdata within a permissions database."
+ "\nAvailable types are : global, server, world. (Default: global)"
+ "\nGlobal will store data globally shared by all servers."
+ "\nServer will store data per server. Note: This requires servername to be properly set in permissions config."
+ "\nWorld will store data per world.")
public String contextType = "global";
@Setting(value = "claim-block-system", comment = "Determines which claim block system to use for claims. (Default: AREA)\nIf set to VOLUME, claim blocks will use the chunk count system to balance 3d claiming."
+ "\nIf set to AREA, the standard 2d block count system will be used.")
public ClaimBlockSystem claimBlockSystem = ClaimBlockSystem.AREA;
@ -55,4 +59,8 @@ public class PlayerDataCategory extends ConfigCategory {
+ "\nExample: If a player has 5 basic claims with a total cost of 1000, this will set their accrued claim blocks to 1000."
+ "\nNote: This will also reset all bonus claim blocks to 0. It is highly recommended to backup before using.")
public boolean resetAccruedClaimBlocks = false;
public boolean useWorldPlayerData() {
return this.contextType.equalsIgnoreCase("world");
}
}

View File

@ -498,9 +498,8 @@ public class GriefPreventionMigrator {
final int bonusBlocks = Integer.parseInt(lines.get(2));
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(world, uuid);
// Set directly in storage as subject data has not been initialized
playerData.getStorageData().getConfig().setAccruedClaimBlocks(accruedBlocks);
playerData.getStorageData().getConfig().setBonusClaimBlocks(bonusBlocks);
playerData.saveAllData();
playerData.setAccruedClaimBlocks(accruedBlocks);
playerData.setBonusClaimBlocks(bonusBlocks);
} catch (NumberFormatException e) {
e.printStackTrace();
continue;

View File

@ -0,0 +1,163 @@
/*
* 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.migrator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.World;
import com.griefdefender.GriefDefenderPlugin;
import com.griefdefender.api.permission.Context;
import com.griefdefender.api.permission.option.Options;
import com.griefdefender.cache.PermissionHolderCache;
import com.griefdefender.configuration.PlayerStorageData;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.storage.BaseStorage;
import com.griefdefender.util.PermissionUtil;
public class PlayerDataMigrator {
private static int count;
public static void migrateGlobal() throws FileNotFoundException, ClassNotFoundException {
if (!GriefDefenderPlugin.getGlobalConfig().getConfig().migrator.playerDataMigrator) {
return;
}
if (BaseStorage.globalPlayerDataPath.resolve("_migrated").toFile().exists()) {
return;
}
count = 0;
GriefDefenderPlugin.getInstance().getLogger().info("Starting GriefDefender GlobalPlayerData migration...");
migratePlayerData(null);
try {
Files.createFile(BaseStorage.globalPlayerDataPath.resolve("_migrated"));
} catch (IOException e) {
e.printStackTrace();
}
GriefDefenderPlugin.getInstance().getLogger().info("Finished GriefDefender GlobalPlayerData migration. "
+ "Migrated a total of " + count + " playerdata files.");
}
public static void migrateWorld(World world, Path path) throws FileNotFoundException, ClassNotFoundException {
if (!GriefDefenderPlugin.getGlobalConfig().getConfig().migrator.playerDataMigrator) {
return;
}
if (path.resolve("_migrated").toFile().exists()) {
return;
}
count = 0;
GriefDefenderPlugin.getInstance().getLogger().info("Starting GriefDefender PlayerData migration for world " + world.getName() + "...");
migratePlayerData(world);
try {
Files.createFile(path.resolve("_migrated"));
} catch (IOException e) {
e.printStackTrace();
}
GriefDefenderPlugin.getInstance().getLogger().info("Finished GriefDefender PlayerData migration for world " + world.getName() + ". "
+ "Migrated a total of " + count + " playerdata files.");
}
private static void migratePlayerData(World world) {
Path path = null;
if (world == null) {
path = BaseStorage.globalPlayerDataPath;
} else {
path = BaseStorage.worldConfigMap.get(world.getUID()).getPath().getParent().resolve("PlayerData");
}
if (!path.toFile().exists()) {
return;
}
if (path.resolve("_migrated").toFile().exists()) {
return;
}
File[] files = path.toFile().listFiles();
if (files != null) {
GriefDefenderPlugin.getInstance().getLogger().info("Migrating " + files.length + " player data files...");
for (int i = 0; i < files.length; i++) {
final File file = files[i];
if (file.getName().startsWith("_")) {
continue;
}
GriefDefenderPlugin.getInstance().getLogger().info("Migrating playerdata " + file.getName() + "...");
UUID uuid = null;
try {
uuid = UUID.fromString(file.getName().replaceFirst("[.][^.]+$", ""));
} catch (IllegalArgumentException e) {
e.printStackTrace();
continue;
}
// ignore internal player uuid's
if (uuid.equals(GriefDefenderPlugin.PUBLIC_UUID) || uuid.equals(GriefDefenderPlugin.ADMIN_USER_UUID) || uuid.equals(GriefDefenderPlugin.WORLD_USER_UUID)) {
continue;
}
final PlayerStorageData playerStorage = createPlayerStorageData(world, uuid);
if (playerStorage == null) {
continue;
}
final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(uuid);
final String accruedClaimBlocks = String.valueOf(playerStorage.getConfig().getAccruedClaimBlocks());
final String bonusClaimBlocks = String.valueOf(playerStorage.getConfig().getBonusClaimBlocks());
final Set<Context> contexts = new HashSet<>();
if (world != null) {
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
contexts.add(new Context("world", world.getName().toLowerCase()));
} else {
final String contextType = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.contextType;
if (contextType.equalsIgnoreCase("world")) {
contexts.add(new Context("world", world.getName().toLowerCase()));
} else if (contextType.equalsIgnoreCase("global")) {
contexts.add(new Context("server", "global"));
} else {
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
}
}
GriefDefenderPlugin.getInstance().getPermissionProvider().setOptionValue(user, Options.ACCRUED_BLOCKS.getPermission(), accruedClaimBlocks, contexts);
GriefDefenderPlugin.getInstance().getPermissionProvider().setOptionValue(user, Options.BONUS_BLOCKS.getPermission(), bonusClaimBlocks, contexts);
count++;
}
}
}
private static PlayerStorageData createPlayerStorageData(World world, UUID playerUniqueId) {
Path playerFilePath = null;
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
playerFilePath = BaseStorage.globalPlayerDataPath.resolve(playerUniqueId.toString());
} else {
playerFilePath = BaseStorage.worldConfigMap.get(world.getUID()).getPath().getParent().resolve("PlayerData").resolve(playerUniqueId.toString());
}
PlayerStorageData playerStorage = new PlayerStorageData(playerFilePath);
return playerStorage;
}
}

View File

@ -1074,6 +1074,10 @@ public class GDPermissionManager implements PermissionManager {
return this.getInternalOptionValue(type, holder, option, (ClaimType) null);
}
public <T> T getInternalOptionValue(TypeToken<T> type, GDPermissionHolder holder, Option<T> option, Set<Context> contexts) {
return getInternalOptionValue(type, holder, option, null, null, contexts);
}
public <T> T getInternalOptionValue(TypeToken<T> type, GDPermissionHolder holder, Option<T> option, Claim claim, Set<Context> contexts) {
return getInternalOptionValue(type, holder, option, claim, null, contexts);
}
@ -1339,14 +1343,14 @@ public class GDPermissionManager implements PermissionManager {
@Override
public CompletableFuture<PermissionResult> setOption(Option option, String value, Set<Context> contexts) {
// TODO Auto-generated method stub
return null;
final PermissionResult result = PermissionUtil.getInstance().setOptionValue(GriefDefenderPlugin.DEFAULT_HOLDER, option.getPermission(), value, contexts);
return CompletableFuture.completedFuture(result);
}
@Override
public CompletableFuture<PermissionResult> setOption(Option option, Subject subject, String value, Set<Context> contexts) {
// TODO Auto-generated method stub
return null;
final PermissionResult result = PermissionUtil.getInstance().setOptionValue((GDPermissionHolder) subject, option.getPermission(), value, contexts);
return CompletableFuture.completedFuture(result);
}
@Override

View File

@ -48,7 +48,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class GDOption<T> implements Option<T> {
private static final List<String> GLOBAL_OPTIONS = Arrays.asList(
"abandon-return-ratio", "blocks-accrued-per-hour", "chest-expiration", "economy-block-cost",
"abandon-return-ratio", "accrued-blocks", "bonus-blocks", "blocks-accrued-per-hour", "chest-expiration", "economy-block-cost",
"economy-block-sell-return", "expiration", "initial-blocks", "max-accrued-blocks", "radius-list",
"radius-list");
private static final List<String> ADMIN_OPTIONS = Arrays.asList(

View File

@ -906,6 +906,13 @@ public class LuckPermsProvider implements PermissionProvider {
}
private void clearMeta(PermissionHolder holder, String metaKey, ContextSet set) {
if (set.size() == 1 && set.containsKey("server")) {
if (set.getAnyValue("server").get().equalsIgnoreCase("global")) {
// LP does not remove meta if passing only global context so we need to make sure to pass none
holder.data().clear(NodeType.META.predicate(node -> node.getMetaKey().equals(metaKey)));
return;
}
}
holder.data().clear(set, NodeType.META.predicate(node -> node.getMetaKey().equals(metaKey)));
}

View File

@ -90,6 +90,8 @@ public class OptionRegistryModule implements CatalogRegistryModule<Option> {
public void registerDefaults() {
this.createKey("griefdefender:abandon-delay", "abandon-delay", Integer.class);
this.createKey("griefdefender:abandon-return-ratio", "abandon-return-ratio", Double.class);
this.createKey("griefdefender:accrued-blocks", "accrued-blocks", Integer.class);
this.createKey("griefdefender:bonus-blocks", "bonus-blocks", Integer.class);
this.createKey("griefdefender:create-limit", "create-limit", Integer.class);
this.createKey("griefdefender:expiration", "expiration", Integer.class);
this.createKey("griefdefender:max-size-x", "max-size-x", Integer.class);

View File

@ -52,6 +52,7 @@ import com.griefdefender.configuration.type.GlobalConfig;
import com.griefdefender.event.GDCauseStackManager;
import com.griefdefender.event.GDRemoveClaimEvent;
import com.griefdefender.internal.util.VecHelper;
import com.griefdefender.migrator.PlayerDataMigrator;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.flag.FlagContexts;
import com.griefdefender.permission.option.GDOption;
@ -95,12 +96,10 @@ public abstract class BaseStorage {
public final static Path globalPlayerDataPath = dataLayerFolderPath.resolve("GlobalPlayerData");
public void initialize() throws Exception {
USE_GLOBAL_PLAYER_STORAGE = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useGlobalPlayerDataStorage;
if (USE_GLOBAL_PLAYER_STORAGE) {
File globalPlayerDataFolder = globalPlayerDataPath.toFile();
if (!globalPlayerDataFolder.exists()) {
globalPlayerDataFolder.mkdirs();
}
USE_GLOBAL_PLAYER_STORAGE = !GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useWorldPlayerData();
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.contextType.equalsIgnoreCase("global")) {
// migrate player data
PlayerDataMigrator.migrateGlobal();
}
// handle default flag/option permissions

View File

@ -44,6 +44,7 @@ import com.griefdefender.configuration.TownStorageData;
import com.griefdefender.configuration.type.ConfigBase;
import com.griefdefender.event.GDLoadClaimEvent;
import com.griefdefender.migrator.GriefPreventionMigrator;
import com.griefdefender.migrator.PlayerDataMigrator;
import com.griefdefender.migrator.WorldGuardMigrator;
import org.apache.commons.io.FileUtils;
@ -181,14 +182,6 @@ public class FileStorage extends BaseStorage {
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
GriefDefenderPlugin.getInstance().getWorldEditProvider().getSchematicWorldMap().put(world.getUID(), newWorldDataPath.resolve("SchematicData"));
}
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
if (Files.notExists(globalPlayerDataPath)) {
Files.createDirectories(globalPlayerDataPath);
}
} else if (Files.notExists(newWorldDataPath.resolve("PlayerData"))) {
Files.createDirectories(newWorldDataPath.resolve("PlayerData"));
}
} catch (Exception e) {
e.printStackTrace();
}
@ -227,13 +220,9 @@ public class FileStorage extends BaseStorage {
GriefDefenderPlugin.getInstance().getLogger().info("[" + worldName + "] " + this.claimLoadCount + " total claims loaded.");
}
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useGlobalPlayerDataStorage) {
files = globalPlayerDataPath.toFile().listFiles();
} else {
files = newWorldDataPath.resolve("PlayerData").toFile().listFiles();
}
if (files != null && files.length > 0) {
this.loadPlayerData(world, files);
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useWorldPlayerData()) {
// migrate player data
PlayerDataMigrator.migrateWorld(world, newWorldDataPath.resolve("PlayerData"));
}
// If a wilderness claim was not loaded, create a new one

View File

@ -31,7 +31,6 @@ import com.griefdefender.GriefDefenderPlugin;
import com.griefdefender.api.permission.option.Options;
import com.griefdefender.cache.PermissionHolderCache;
import com.griefdefender.claim.GDClaim;
import com.griefdefender.configuration.PlayerStorageData;
import com.griefdefender.internal.util.NMSUtil;
import com.griefdefender.permission.GDPermissionManager;
import com.griefdefender.permission.GDPermissionUser;
@ -77,14 +76,12 @@ public class ClaimBlockTask extends BukkitRunnable {
} else {
int currentTotal = playerData.getAccruedClaimBlocks();
if ((currentTotal + accruedBlocks) > playerData.getMaxAccruedClaimBlocks()) {
PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setAccruedClaimBlocks(playerData.getMaxAccruedClaimBlocks());
playerData.setAccruedClaimBlocks(playerData.getMaxAccruedClaimBlocks());
playerData.lastAfkCheckLocation = player.getLocation();
return;
}
PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setAccruedClaimBlocks(playerStorage.getConfig().getAccruedClaimBlocks() + accruedBlocks);
playerData.setAccruedClaimBlocks(playerData.getAccruedClaimBlocks() + accruedBlocks);
}
}

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -9,9 +9,9 @@
},
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",

View File

@ -47,6 +47,7 @@ import com.griefdefender.configuration.PlayerStorageData;
import com.griefdefender.permission.GDPermissionManager;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.GDPermissions;
import com.griefdefender.storage.BaseStorage;
import com.griefdefender.util.PermissionUtil;
import net.kyori.text.Component;
import org.spongepowered.api.Sponge;
@ -75,9 +76,10 @@ public class GDPlayerData implements PlayerData {
public UUID playerID;
public UUID worldUniqueId;
private String worldName;
private WeakReference<GDPermissionUser> playerSubject;
private Set<Claim> claimList;
private PlayerStorageData playerStorage;
private Set<Context> optionContexts;
public Location<World> lastAfkCheckLocation;
public Location<World> lastShovelLocation;
public Location<World> endShovelLocation;
@ -153,11 +155,26 @@ public class GDPlayerData implements PlayerData {
public boolean useRestoreSchematic = false;
private boolean checkedDimensionHeight = false;
public GDPlayerData(UUID worldUniqueId, UUID playerUniqueId, PlayerStorageData playerStorage, GriefDefenderConfig<?> activeConfig, Set<Claim> claims) {
public GDPlayerData(UUID worldUniqueId, String worldName, UUID playerUniqueId, Set<Claim> claims) {
this.worldUniqueId = worldUniqueId;
this.worldName = worldName;
this.playerID = playerUniqueId;
this.playerStorage = playerStorage;
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.optionContexts = contexts;
this.refreshPlayerOptions();
}
@ -377,7 +394,7 @@ public class GDPlayerData implements PlayerData {
@Override
public int getAccruedClaimBlocks() {
return this.playerStorage.getConfig().getAccruedClaimBlocks();
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.ACCRUED_BLOCKS, new HashSet<>(this.optionContexts));
}
public boolean addAccruedClaimBlocks(int newAccruedClaimBlocks) {
@ -386,7 +403,7 @@ public class GDPlayerData implements PlayerData {
return false;
}
this.playerStorage.getConfig().setAccruedClaimBlocks(currentTotal + newAccruedClaimBlocks);
this.setAccruedClaimBlocks(currentTotal + newAccruedClaimBlocks);
return true;
}
@ -395,16 +412,16 @@ public class GDPlayerData implements PlayerData {
return false;
}
this.playerStorage.getConfig().setAccruedClaimBlocks(newAccruedClaimBlocks);
GDPermissionManager.getInstance().setOption(Options.ACCRUED_BLOCKS, this.getSubject(), String.valueOf(newAccruedClaimBlocks), new HashSet<>(this.optionContexts));
return true;
}
public int getBonusClaimBlocks() {
return this.playerStorage.getConfig().getBonusClaimBlocks();
return GDPermissionManager.getInstance().getInternalOptionValue(TypeToken.of(Integer.class), this.getSubject(), Options.BONUS_BLOCKS, new HashSet<>(this.optionContexts));
}
public void setBonusClaimBlocks(int bonusClaimBlocks) {
this.playerStorage.getConfig().setBonusClaimBlocks(bonusClaimBlocks);
GDPermissionManager.getInstance().setOption(Options.BONUS_BLOCKS, this.getSubject(), String.valueOf(bonusClaimBlocks), new HashSet<>(this.optionContexts));
}
public CreateModeType getClaimCreateMode() {
@ -474,14 +491,6 @@ public class GDPlayerData implements PlayerData {
return true;
}
public void saveAllData() {
this.playerStorage.save();
}
public PlayerStorageData getStorageData() {
return this.playerStorage;
}
public Set<Claim> getClaims() {
return ImmutableSet.copyOf(this.claimList);
}

View File

@ -940,7 +940,7 @@ public class GriefDefenderPlugin {
MessageCache.getInstance().loadCache();
BaseStorage.globalConfig.getConfig().customFlags.initDefaults();
BaseStorage.globalConfig.save();
BaseStorage.USE_GLOBAL_PLAYER_STORAGE = BaseStorage.globalConfig.getConfig().playerdata.useGlobalPlayerDataStorage;
BaseStorage.USE_GLOBAL_PLAYER_STORAGE = !BaseStorage.globalConfig.getConfig().playerdata.useWorldPlayerData();
GDFlags.populateFlagStatus();
PermissionHolderCache.getInstance().getOrCreatePermissionCache(GriefDefenderPlugin.DEFAULT_HOLDER).invalidateAll();
CLAIM_BLOCK_SYSTEM = BaseStorage.globalConfig.getConfig().playerdata.claimBlockSystem;

View File

@ -78,6 +78,7 @@ public class GDClaimManager implements ClaimManager {
private static final BaseStorage DATASTORE = GriefDefenderPlugin.getInstance().dataStore;
private UUID worldUniqueId;
private String worldName;
private GriefDefenderConfig<?> activeConfig;
// Player UUID -> player data
@ -92,6 +93,7 @@ public class GDClaimManager implements ClaimManager {
public GDClaimManager(World world) {
this.worldUniqueId = world.getUniqueId();
this.worldName = world.getName();
this.activeConfig = GriefDefenderPlugin.getActiveConfig(this.worldUniqueId);
}
@ -105,16 +107,8 @@ public class GDClaimManager implements ClaimManager {
}
private GDPlayerData createPlayerData(UUID playerUniqueId) {
Path playerFilePath = null;
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
playerFilePath = BaseStorage.globalPlayerDataPath.resolve(playerUniqueId.toString());
} else {
playerFilePath = BaseStorage.worldConfigMap.get(this.worldUniqueId).getPath().getParent().resolve("PlayerData").resolve(playerUniqueId.toString());
}
PlayerStorageData playerStorage = new PlayerStorageData(playerFilePath);
Set<Claim> claimList = this.createPlayerClaimList(playerUniqueId);
GDPlayerData playerData = new GDPlayerData(this.worldUniqueId, playerUniqueId, playerStorage, this.activeConfig, claimList);
GDPlayerData playerData = new GDPlayerData(this.worldUniqueId, this.worldName, playerUniqueId, claimList);
this.getPlayerDataMap().put(playerUniqueId, playerData);
return playerData;
}
@ -483,10 +477,6 @@ public class GDClaimManager implements ClaimManager {
gpClaim.save();
}
this.getWildernessClaim().save();
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
playerData.getStorageData().save();
}
}
public void unload() {
@ -611,14 +601,6 @@ public class GDClaimManager implements ClaimManager {
}
public void resetPlayerData() {
// check migration reset
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.resetMigrations) {
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
final PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setMigratedBlocks(false);
playerStorage.save();
}
}
// migrate playerdata to new claim block system
final int migration3dRate = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.migrateVolumeRate;
final int migration2dRate = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.migrateAreaRate;
@ -635,19 +617,16 @@ public class GDClaimManager implements ClaimManager {
}
for (GDPlayerData playerData : this.getPlayerDataMap().values()) {
final PlayerStorageData playerStorage = playerData.getStorageData();
final int accruedBlocks = playerStorage.getConfig().getAccruedClaimBlocks();
final int accruedBlocks = playerData.getAccruedClaimBlocks();
int newAccruedBlocks = accruedBlocks;
// first check reset
if (resetClaimBlockData) {
newAccruedBlocks = playerData.getTotalClaimsCost();
playerStorage.getConfig().setBonusClaimBlocks(0);
} else if (migration3dRate > -1 && !playerStorage.getConfig().hasMigratedBlocks()) {
playerData.setBonusClaimBlocks(0);
} else if (migration3dRate > -1) {
newAccruedBlocks = accruedBlocks * migration3dRate;
playerStorage.getConfig().setMigratedBlocks(true);
} else if (migration2dRate > -1 && !playerStorage.getConfig().hasMigratedBlocks()) {
} else if (migration2dRate > -1) {
newAccruedBlocks = accruedBlocks / migration2dRate;
playerStorage.getConfig().setMigratedBlocks(true);
}
if (newAccruedBlocks < 0) {
newAccruedBlocks = 0;
@ -656,8 +635,7 @@ public class GDClaimManager implements ClaimManager {
if (newAccruedBlocks > maxAccruedBlocks) {
newAccruedBlocks = maxAccruedBlocks;
}
playerStorage.getConfig().setAccruedClaimBlocks(newAccruedBlocks);
playerStorage.save();
playerData.setAccruedClaimBlocks(newAccruedBlocks);
}
}

View File

@ -78,7 +78,6 @@ public class CommandAdjustBonusClaimBlocks extends BaseCommand {
// give blocks to player
GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(worldProperties.getUniqueId(), user.getUniqueId());
playerData.setBonusClaimBlocks(playerData.getBonusClaimBlocks() + adjustment);
playerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ADJUST_BONUS_BLOCKS_SUCCESS, ImmutableMap.of(
"player", user.getName(),
"amount", adjustment,

View File

@ -132,8 +132,6 @@ public class CommandClaimBuyBlocks extends BaseCommand {
final int bonusTotal = playerData.getBonusClaimBlocks();
playerData.setBonusClaimBlocks(bonusTotal + blockCount);
playerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ECONOMY_BLOCK_PURCHASE_CONFIRMATION, ImmutableMap.of(
"amount", totalCost,
"balance", playerData.getRemainingClaimBlocks()));

View File

@ -147,7 +147,7 @@ public class CommandClaimSellBlocks extends BaseCommand {
accruedBlocks = (int) (accruedBlocks - blockCount);
playerData.setAccruedClaimBlocks(accruedBlocks);
}
playerData.saveAllData();
GriefDefenderPlugin.sendMessage(player, message);
}
}

View File

@ -76,8 +76,6 @@ public class CommandGiveBlocks extends BaseCommand {
}
final GDPlayerData targetPlayerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(src.getWorld(), targetPlayer.getUniqueId());
targetPlayerData.setBonusClaimBlocks(targetPlayerData.getBonusClaimBlocks() + amount);
playerData.getStorageData().save();
targetPlayerData.getStorageData().save();
final Component message = GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.COMMAND_GIVEBLOCKS_CONFIRMED);
TextAdapter.sendComponent(src, message);

View File

@ -105,7 +105,6 @@ public class CommandSetAccruedClaimBlocks extends BaseCommand {
return;
}
playerData.getStorageData().save();
GriefDefenderPlugin.sendMessage(src, GriefDefenderPlugin.getInstance().messageData.getMessage(MessageStorage.ADJUST_ACCRUED_BLOCKS_SUCCESS,
ImmutableMap.of(
"player", user.getName(),

View File

@ -77,6 +77,8 @@ public class DefaultPermissionCategory extends ConfigCategory {
final int maxAccruedBlocks = GriefDefenderPlugin.CLAIM_BLOCK_SYSTEM == ClaimBlockSystem.VOLUME ? 20480000 : 80000;
this.defaultUserOptions.put(Options.ABANDON_DELAY.getName(), "0");
this.defaultUserOptions.put(Options.ABANDON_RETURN_RATIO.getName(), "1.0");
this.defaultUserOptions.put(Options.ACCRUED_BLOCKS.getName(), "0");
this.defaultUserOptions.put(Options.BONUS_BLOCKS.getName(), "0");
this.defaultUserOptions.put(Options.BLOCKS_ACCRUED_PER_HOUR.getName(), "120");
this.defaultUserOptions.put(Options.CHEST_EXPIRATION.getName(), "7");
this.defaultUserOptions.put(Options.CREATE_LIMIT.getName(), "-1");

View File

@ -50,4 +50,11 @@ public class MigratorCategory extends ConfigCategory {
"\nNote: Only cuboid regions are supported." +
"\nNote: It is recommended to backup data before using.")
public boolean worldGuardMigrator = false;
@Setting(value = "playerdata", comment = "Set to true to enable the legacy playerdata file migrator."
+ "\nNote: Migrates legacy playerdata file format to permissions storage such as LuckPerms json or mysql storage."
+ "\nNote: Before turning this on, make sure you properly set 'context-storage-type' in the the playerdata section of this config."
+ "\nNote: It is HIGHLY recommended to backup your permissions database before running this migrator as all local playerdata files will be migrated to it."
+ "\nNote: Do NOT run this migrator on more than one server if multiple servers share the same permissions database.")
public boolean playerDataMigrator = false;
}

View File

@ -31,8 +31,12 @@ import ninja.leaping.configurate.objectmapping.serialize.ConfigSerializable;
@ConfigSerializable
public class PlayerDataCategory extends ConfigCategory {
@Setting(value = "use-global-storage", comment = "Whether player data should be stored globally. False will store all data per world.")
public boolean useGlobalPlayerDataStorage = true;
@Setting(value = "context-storage-type", comment = "The context type used when storing playerdata within a permissions database."
+ "\nAvailable types are : global, server, world. (Default: global)"
+ "\nGlobal will store data globally shared by all servers."
+ "\nServer will store data per server. Note: This requires servername to be properly set in permissions config."
+ "\nWorld will store data per world.")
public String contextType = "global";
@Setting(value = "claim-block-system", comment = "Determines which claim block system to use for claims. (Default: AREA)\nIf set to VOLUME, claim blocks will use the chunk count system to balance 3d claiming."
+ "\nIf set to AREA, the standard 2d block count system will be used.")
public ClaimBlockSystem claimBlockSystem = ClaimBlockSystem.AREA;
@ -55,4 +59,8 @@ public class PlayerDataCategory extends ConfigCategory {
+ "\nExample: If a player has 5 basic claims with a total cost of 1000, this will set their accrued claim blocks to 1000."
+ "\nNote: This will also reset all bonus claim blocks to 0. It is highly recommended to backup before using.")
public boolean resetAccruedClaimBlocks = false;
public boolean useWorldPlayerData() {
return this.contextType.equalsIgnoreCase("world");
}
}

View File

@ -502,9 +502,8 @@ public class GPBukkitMigrator {
final int bonusBlocks = Integer.parseInt(lines.get(2));
final GDPlayerData playerData = GriefDefenderPlugin.getInstance().dataStore.getOrCreatePlayerData(world, uuid);
// Set directly in storage as subject data has not been initialized
playerData.getStorageData().getConfig().setAccruedClaimBlocks(accruedBlocks);
playerData.getStorageData().getConfig().setBonusClaimBlocks(bonusBlocks);
playerData.saveAllData();
playerData.setAccruedClaimBlocks(accruedBlocks);
playerData.setBonusClaimBlocks(bonusBlocks);
} catch (NumberFormatException e) {
e.printStackTrace();
continue;

View File

@ -0,0 +1,163 @@
/*
* 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.migrator;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import org.spongepowered.api.Sponge;
import org.spongepowered.api.world.World;
import com.griefdefender.GriefDefenderPlugin;
import com.griefdefender.api.permission.Context;
import com.griefdefender.api.permission.option.Options;
import com.griefdefender.cache.PermissionHolderCache;
import com.griefdefender.configuration.PlayerStorageData;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.storage.BaseStorage;
import com.griefdefender.util.PermissionUtil;
public class PlayerDataMigrator {
private static int count;
public static void migrateGlobal() throws FileNotFoundException, ClassNotFoundException {
if (!GriefDefenderPlugin.getGlobalConfig().getConfig().migrator.playerDataMigrator) {
return;
}
if (BaseStorage.globalPlayerDataPath.resolve("_migrated").toFile().exists()) {
return;
}
count = 0;
GriefDefenderPlugin.getInstance().getLogger().info("Starting GriefDefender GlobalPlayerData migration...");
migratePlayerData(null);
try {
Files.createFile(BaseStorage.globalPlayerDataPath.resolve("_migrated"));
} catch (IOException e) {
e.printStackTrace();
}
GriefDefenderPlugin.getInstance().getLogger().info("Finished GriefDefender GlobalPlayerData migration. "
+ "Migrated a total of " + count + " playerdata files.");
}
public static void migrateWorld(World world, Path path) throws FileNotFoundException, ClassNotFoundException {
if (!GriefDefenderPlugin.getGlobalConfig().getConfig().migrator.playerDataMigrator) {
return;
}
if (path.resolve("_migrated").toFile().exists()) {
return;
}
count = 0;
GriefDefenderPlugin.getInstance().getLogger().info("Starting GriefDefender PlayerData migration for world " + world.getName() + "...");
migratePlayerData(world);
try {
Files.createFile(path.resolve("_migrated"));
} catch (IOException e) {
e.printStackTrace();
}
GriefDefenderPlugin.getInstance().getLogger().info("Finished GriefDefender PlayerData migration for world " + world.getName() + ". "
+ "Migrated a total of " + count + " playerdata files.");
}
private static void migratePlayerData(World world) {
Path path = null;
if (world == null) {
path = BaseStorage.globalPlayerDataPath;
} else {
path = BaseStorage.worldConfigMap.get(world.getUniqueId()).getPath().getParent().resolve("PlayerData");
}
if (!path.toFile().exists()) {
return;
}
if (path.resolve("_migrated").toFile().exists()) {
return;
}
File[] files = path.toFile().listFiles();
if (files != null) {
GriefDefenderPlugin.getInstance().getLogger().info("Migrating " + files.length + " player data files...");
for (int i = 0; i < files.length; i++) {
final File file = files[i];
if (file.getName().startsWith("_")) {
continue;
}
GriefDefenderPlugin.getInstance().getLogger().info("Migrating playerdata " + file.getName() + "...");
UUID uuid = null;
try {
uuid = UUID.fromString(file.getName().replaceFirst("[.][^.]+$", ""));
} catch (IllegalArgumentException e) {
e.printStackTrace();
continue;
}
// ignore internal player uuid's
if (uuid.equals(GriefDefenderPlugin.PUBLIC_UUID) || uuid.equals(GriefDefenderPlugin.ADMIN_USER_UUID) || uuid.equals(GriefDefenderPlugin.WORLD_USER_UUID)) {
continue;
}
final PlayerStorageData playerStorage = createPlayerStorageData(world, uuid);
if (playerStorage == null) {
continue;
}
final GDPermissionUser user = PermissionHolderCache.getInstance().getOrCreateUser(uuid);
final String accruedClaimBlocks = String.valueOf(playerStorage.getConfig().getAccruedClaimBlocks());
final String bonusClaimBlocks = String.valueOf(playerStorage.getConfig().getBonusClaimBlocks());
final Set<Context> contexts = new HashSet<>();
if (world != null) {
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
contexts.add(new Context("world", world.getName().toLowerCase()));
} else {
final String contextType = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.contextType;
if (contextType.equalsIgnoreCase("world")) {
contexts.add(new Context("world", world.getName().toLowerCase()));
} else if (contextType.equalsIgnoreCase("global")) {
contexts.add(new Context("server", "global"));
} else {
contexts.add(new Context("server", PermissionUtil.getInstance().getServerName()));
}
}
GriefDefenderPlugin.getInstance().getPermissionProvider().setOptionValue(user, Options.ACCRUED_BLOCKS.getPermission(), accruedClaimBlocks, contexts);
GriefDefenderPlugin.getInstance().getPermissionProvider().setOptionValue(user, Options.BONUS_BLOCKS.getPermission(), bonusClaimBlocks, contexts);
count++;
}
}
}
private static PlayerStorageData createPlayerStorageData(World world, UUID playerUniqueId) {
Path playerFilePath = null;
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
playerFilePath = BaseStorage.globalPlayerDataPath.resolve(playerUniqueId.toString());
} else {
playerFilePath = BaseStorage.worldConfigMap.get(world.getUniqueId()).getPath().getParent().resolve("PlayerData").resolve(playerUniqueId.toString());
}
PlayerStorageData playerStorage = new PlayerStorageData(playerFilePath);
return playerStorage;
}
}

View File

@ -1273,6 +1273,10 @@ public class GDPermissionManager implements PermissionManager {
return this.getInternalOptionValue(type, holder, option, (ClaimType) null);
}
public <T> T getInternalOptionValue(TypeToken<T> type, GDPermissionHolder holder, Option<T> option, Set<Context> contexts) {
return getInternalOptionValue(type, holder, option, null, null, contexts);
}
public <T> T getInternalOptionValue(TypeToken<T> type, GDPermissionHolder holder, Option<T> option, Claim claim, Set<Context> contexts) {
return getInternalOptionValue(type, holder, option, claim, null, contexts);
}
@ -1538,14 +1542,14 @@ public class GDPermissionManager implements PermissionManager {
@Override
public CompletableFuture<PermissionResult> setOption(Option option, String value, Set<Context> contexts) {
// TODO Auto-generated method stub
return null;
final PermissionResult result = PermissionUtil.getInstance().setOptionValue(GriefDefenderPlugin.DEFAULT_HOLDER, option.getPermission(), value, contexts);
return CompletableFuture.completedFuture(result);
}
@Override
public CompletableFuture<PermissionResult> setOption(Option option, Subject subject, String value, Set<Context> contexts) {
// TODO Auto-generated method stub
return null;
final PermissionResult result = PermissionUtil.getInstance().setOptionValue((GDPermissionHolder) subject, option.getPermission(), value, contexts);
return CompletableFuture.completedFuture(result);
}
@Override

View File

@ -48,7 +48,7 @@ import org.checkerframework.checker.nullness.qual.Nullable;
public class GDOption<T> implements Option<T> {
private static final List<String> GLOBAL_OPTIONS = Arrays.asList(
"abandon-return-ratio", "blocks-accrued-per-hour", "chest-expiration", "economy-block-cost",
"abandon-return-ratio", "accrued-blocks", "bonus-blocks", "blocks-accrued-per-hour", "chest-expiration", "economy-block-cost",
"economy-block-sell-return", "expiration", "initial-blocks", "max-accrued-blocks", "radius-list",
"radius-list");
private static final List<String> ADMIN_OPTIONS = Arrays.asList(

View File

@ -900,6 +900,13 @@ public class LuckPermsProvider implements PermissionProvider {
}
private void clearMeta(PermissionHolder holder, String metaKey, ContextSet set) {
if (set.size() == 1 && set.containsKey("server")) {
if (set.getAnyValue("server").get().equalsIgnoreCase("global")) {
// LP does not remove meta if passing only global context so we need to make sure to pass none
holder.data().clear(NodeType.META.predicate(node -> node.getMetaKey().equals(metaKey)));
return;
}
}
holder.data().clear(set, NodeType.META.predicate(node -> node.getMetaKey().equals(metaKey)));
}

View File

@ -90,6 +90,8 @@ public class OptionRegistryModule implements CatalogRegistryModule<Option> {
public void registerDefaults() {
this.createKey("griefdefender:abandon-delay", "abandon-delay", Integer.class);
this.createKey("griefdefender:abandon-return-ratio", "abandon-return-ratio", Double.class);
this.createKey("griefdefender:accrued-blocks", "accrued-blocks", Integer.class);
this.createKey("griefdefender:bonus-blocks", "bonus-blocks", Integer.class);
this.createKey("griefdefender:create-limit", "create-limit", Integer.class);
this.createKey("griefdefender:expiration", "expiration", Integer.class);
this.createKey("griefdefender:max-size-x", "max-size-x", Integer.class);

View File

@ -51,6 +51,7 @@ import com.griefdefender.configuration.type.ConfigBase;
import com.griefdefender.configuration.type.GlobalConfig;
import com.griefdefender.event.GDCauseStackManager;
import com.griefdefender.event.GDRemoveClaimEvent;
import com.griefdefender.migrator.PlayerDataMigrator;
import com.griefdefender.permission.GDPermissionUser;
import com.griefdefender.permission.flag.FlagContexts;
import com.griefdefender.permission.option.GDOption;
@ -93,12 +94,10 @@ public abstract class BaseStorage {
public final static Path globalPlayerDataPath = dataLayerFolderPath.resolve("GlobalPlayerData");
public void initialize() throws Exception {
USE_GLOBAL_PLAYER_STORAGE = GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useGlobalPlayerDataStorage;
if (USE_GLOBAL_PLAYER_STORAGE) {
File globalPlayerDataFolder = globalPlayerDataPath.toFile();
if (!globalPlayerDataFolder.exists()) {
globalPlayerDataFolder.mkdirs();
}
USE_GLOBAL_PLAYER_STORAGE = !GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useWorldPlayerData();
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.contextType.equalsIgnoreCase("global")) {
// migrate player data
PlayerDataMigrator.migrateGlobal();
}
// handle default flag/option permissions

View File

@ -44,6 +44,7 @@ import com.griefdefender.configuration.TownStorageData;
import com.griefdefender.configuration.type.ConfigBase;
import com.griefdefender.event.GDLoadClaimEvent;
import com.griefdefender.migrator.GPBukkitMigrator;
import com.griefdefender.migrator.PlayerDataMigrator;
import com.griefdefender.migrator.WorldGuardMigrator;
import org.apache.commons.io.FileUtils;
import org.spongepowered.api.Sponge;
@ -182,14 +183,6 @@ public class FileStorage extends BaseStorage {
if (GriefDefenderPlugin.getInstance().getWorldEditProvider() != null) {
GriefDefenderPlugin.getInstance().getWorldEditProvider().getSchematicWorldMap().put(world.getUniqueId(), newWorldDataPath.resolve("SchematicData"));
}
if (BaseStorage.USE_GLOBAL_PLAYER_STORAGE) {
if (Files.notExists(globalPlayerDataPath)) {
Files.createDirectories(globalPlayerDataPath);
}
} else if (Files.notExists(newWorldDataPath.resolve("PlayerData"))) {
Files.createDirectories(newWorldDataPath.resolve("PlayerData"));
}
} catch (Exception e) {
e.printStackTrace();
}
@ -228,13 +221,9 @@ public class FileStorage extends BaseStorage {
GriefDefenderPlugin.getInstance().getLogger().info("[" + world.getName() + "] " + this.claimLoadCount + " total claims loaded.");
}
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useGlobalPlayerDataStorage) {
files = globalPlayerDataPath.toFile().listFiles();
} else {
files = newWorldDataPath.resolve("PlayerData").toFile().listFiles();
}
if (files != null && files.length > 0) {
this.loadPlayerData(world, files);
if (GriefDefenderPlugin.getGlobalConfig().getConfig().playerdata.useWorldPlayerData()) {
// migrate player data
PlayerDataMigrator.migrateWorld(world, newWorldDataPath.resolve("PlayerData"));
}
// If a wilderness claim was not loaded, create a new one

View File

@ -32,7 +32,6 @@ import com.griefdefender.api.claim.ClaimResultType;
import com.griefdefender.api.permission.option.Options;
import com.griefdefender.claim.GDClaim;
import com.griefdefender.claim.GDClaimResult;
import com.griefdefender.configuration.PlayerStorageData;
import com.griefdefender.permission.GDPermissionManager;
import com.griefdefender.storage.BaseStorage;
import org.spongepowered.api.Sponge;
@ -106,14 +105,12 @@ public class ClaimBlockTask implements Runnable {
} else {
int currentTotal = playerData.getAccruedClaimBlocks();
if ((currentTotal + accruedBlocks) > playerData.getMaxAccruedClaimBlocks()) {
PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setAccruedClaimBlocks(playerData.getMaxAccruedClaimBlocks());
playerData.setAccruedClaimBlocks(playerData.getMaxAccruedClaimBlocks());
playerData.lastAfkCheckLocation = player.getLocation();
return;
}
PlayerStorageData playerStorage = playerData.getStorageData();
playerStorage.getConfig().setAccruedClaimBlocks(playerStorage.getConfig().getAccruedClaimBlocks() + accruedBlocks);
playerData.setAccruedClaimBlocks(playerData.getAccruedClaimBlocks() + accruedBlocks);
}
}

View File

@ -3,9 +3,9 @@
"libraries": [
{
"name": "com.griefdefender:api:1.0.0",
"sha1": "a87c88ecf7f4aaa4cc18decef9f0cbb013a0e602",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20191230.224219-13.jar"
"sha1": "08d8fa30e0f8bbb43a2100e712bed2a815a8fd87",
"path": "com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar",
"url": "https://repo.glaremasters.me/repository/bloodshot/com/griefdefender/api/1.0.0-SNAPSHOT/api-1.0.0-20200125.004205-14.jar"
},
{
"name": "com.griefdefender:reflect-helper:1.0",