diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Claim.java b/src/main/java/com/intellectualcrafters/plot/commands/Claim.java index 0a105c143..4b91241c2 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/Claim.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/Claim.java @@ -28,11 +28,7 @@ import com.intellectualcrafters.plot.object.Plot; import com.intellectualcrafters.plot.object.PlotPlayer; import com.intellectualcrafters.plot.object.PlotWorld; import com.intellectualcrafters.plot.object.RunnableVal; -import com.intellectualcrafters.plot.util.EconHandler; -import com.intellectualcrafters.plot.util.EventUtil; -import com.intellectualcrafters.plot.util.MainUtil; -import com.intellectualcrafters.plot.util.Permissions; -import com.intellectualcrafters.plot.util.SchematicHandler; +import com.intellectualcrafters.plot.util.*; import com.intellectualcrafters.plot.util.SchematicHandler.Schematic; import com.plotsquared.general.commands.CommandDeclaration; @@ -104,8 +100,21 @@ public class Claim extends SubCommand { return sendMessage(plr, C.NOT_IN_PLOT); } final int currentPlots = Settings.GLOBAL_LIMIT ? MainUtil.getPlayerPlotCount(plr) : MainUtil.getPlayerPlotCount(loc.getWorld(), plr); + + boolean removeGrantedPlot = false; + if (currentPlots >= MainUtil.getAllowedPlots(plr)) { - return sendMessage(plr, C.CANT_CLAIM_MORE_PLOTS); + if (plr.hasPersistentMeta("grantedPlots")) { + int grantedPlots = ByteArrayUtilities.bytesToInteger(plr.getPersistentMeta("grantedPlots")); + if (grantedPlots < 1) { + plr.removePersistentMeta("grantedPlots"); + return sendMessage(plr, C.CANT_CLAIM_MORE_PLOTS); + } else { + removeGrantedPlot = true; + } + } else { + return sendMessage(plr, C.CANT_CLAIM_MORE_PLOTS); + } } if (!MainUtil.canClaim(plr, plot)) { return sendMessage(plr, C.PLOT_IS_CLAIMED); @@ -121,6 +130,11 @@ public class Claim extends SubCommand { sendMessage(plr, C.REMOVED_BALANCE, cost + ""); } } + if (removeGrantedPlot) { + int grantedPlots = ByteArrayUtilities.bytesToInteger(plr.getPersistentMeta("grantedPlots")); + plr.setPersistentMeta("grantedPlots", ByteArrayUtilities.integerToBytes(grantedPlots - 1)); + sendMessage(plr, C.REMOVED_GRANTED_PLOT, "" + (grantedPlots - 1)); + } if (!schematic.equals("")) { if (world.SCHEMATIC_CLAIM_SPECIFY) { if (!world.SCHEMATICS.contains(schematic.toLowerCase())) { diff --git a/src/main/java/com/intellectualcrafters/plot/commands/Grant.java b/src/main/java/com/intellectualcrafters/plot/commands/Grant.java new file mode 100644 index 000000000..efc281d4f --- /dev/null +++ b/src/main/java/com/intellectualcrafters/plot/commands/Grant.java @@ -0,0 +1,71 @@ +package com.intellectualcrafters.plot.commands; + +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.object.ConsolePlayer; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.util.ByteArrayUtilities; +import com.intellectualcrafters.plot.util.MainUtil; +import com.intellectualcrafters.plot.util.UUIDHandler; +import com.plotsquared.general.commands.CommandDeclaration; + +@CommandDeclaration( + command = "grant", + category = CommandCategory.CLAIMING, + usage = "/plot grant [...]", + permission = "plots.grant", + requiredType = RequiredType.NONE +) +public class Grant extends SubCommand { + + void grantPlayer(PlotPlayer plr, String enteredName) { + PlotPlayer player = UUIDHandler.getPlayer(enteredName); + if (player == null) { + sendMessage(plr, C.GRANTED_PLOT_FAILED, "Player not found"); + } else { + int n = 1; + if (player.hasPersistentMeta("grantedPlots")) { + n += ByteArrayUtilities.bytesToInteger(player.getPersistentMeta("grantedPlots")); + } + player.setPersistentMeta("grantedPlots", ByteArrayUtilities.integerToBytes(n)); + sendMessage(plr, C.GRANTED_PLOT, enteredName); + } + } + + @Override + public boolean onCommand(PlotPlayer plr, String[] arguments) { + if (plr == null || plr instanceof ConsolePlayer) { + if (arguments.length != 1) { + MainUtil.sendMessage(null, "Usage: /plot grant "); + } else { + grantPlayer(null, arguments[0]); + return true; + } + } else { + if (arguments.length < 1) { + arguments = new String[] { "check" }; + } + switch (arguments[0]) { + case "check": { + int grantedPlots = 0; + if (plr.hasPersistentMeta("grantedPlots")) { + grantedPlots = ByteArrayUtilities.bytesToInteger(plr.getPersistentMeta("grantedPlots")); + } + return sendMessage(plr, C.GRANTED_PLOTS, "" + grantedPlots); + } + case "add": { + if (!plr.hasPermission("plots.grant.add")) { + return sendMessage(plr, C.NO_PERMISSION, "plots.grant.add"); + } + if (arguments.length < 2) { + plr.sendMessage("&cUsage: /plot grant add "); + } else { + grantPlayer(plr, arguments[1]); + } + } break; + default: return onCommand(plr, new String[] { "check" }); + } + } + return true; + } + +} diff --git a/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java b/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java index e7973c086..124cde014 100644 --- a/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java +++ b/src/main/java/com/intellectualcrafters/plot/commands/MainCommand.java @@ -129,6 +129,7 @@ public class MainCommand extends CommandManager { createCommand(new Continue()); createCommand(new BO3()); createCommand(new Middle()); + createCommand(new Grant()); // set commands createCommand(new Owner()); createCommand(new Desc()); diff --git a/src/main/java/com/intellectualcrafters/plot/config/C.java b/src/main/java/com/intellectualcrafters/plot/config/C.java index f4aa447d7..0fabce5e2 100644 --- a/src/main/java/com/intellectualcrafters/plot/config/C.java +++ b/src/main/java/com/intellectualcrafters/plot/config/C.java @@ -20,14 +20,6 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// package com.intellectualcrafters.plot.config; -import java.io.File; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.Set; - import com.intellectualcrafters.configuration.ConfigurationSection; import com.intellectualcrafters.configuration.file.YamlConfiguration; import com.intellectualcrafters.plot.PS; @@ -35,6 +27,9 @@ import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.StringMan; import com.plotsquared.general.commands.CommandCaller; +import java.io.File; +import java.util.*; + /** * Captions class. * @@ -263,6 +258,7 @@ public enum C { CANNOT_AFFORD_MERGE("$2You cannot afford to merge the plots. It costs $1%s", "Economy"), ADDED_BALANCE("$1%s $2has been added to your balance", "Economy"), REMOVED_BALANCE("$1%s $2has been taken from your balance", "Economy"), + REMOVED_GRANTED_PLOT("$2You used a plot grant, you've got $1%s $2left", "Economy"), /* * Setup Stuff */ @@ -608,6 +604,9 @@ public enum C { * Direction */ DIRECTION("$1Current direction: %dir%", "Help"), + GRANTED_PLOTS("$1You've got $2%s $1grants left", "Grants"), + GRANTED_PLOT("$1You granted 1 plot to $2%s", "Grants"), + GRANTED_PLOT_FAILED("$1Grant failed: $2%s", "Grants"), /* * Custom */ diff --git a/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java b/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java index aabaa9879..9dc23bf7c 100644 --- a/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java +++ b/src/main/java/com/intellectualcrafters/plot/database/AbstractDB.java @@ -20,23 +20,14 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// package com.intellectualcrafters.plot.database; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - import com.intellectualcrafters.plot.flag.Flag; -import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotCluster; -import com.intellectualcrafters.plot.object.PlotClusterId; -import com.intellectualcrafters.plot.object.PlotId; -import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.object.*; import com.intellectualcrafters.plot.object.comment.PlotComment; +import java.sql.SQLException; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + /** @@ -97,7 +88,13 @@ public interface AbstractDB { void deleteRatings(Plot plot); void delete(final PlotCluster cluster); - + + void addPersistentMeta(UUID uuid, String key, byte[] meta, boolean delete); + + void removePersistentMeta(UUID uuid, String key); + + void getPersistentMeta(PlotPlayer player); + /** * Create plot settings * diff --git a/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java b/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java index e9ce62fb8..a485773ad 100644 --- a/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java +++ b/src/main/java/com/intellectualcrafters/plot/database/SQLManager.java @@ -20,44 +20,24 @@ //////////////////////////////////////////////////////////////////////////////////////////////////// package com.intellectualcrafters.plot.database; -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Timestamp; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map.Entry; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.atomic.AtomicInteger; - import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.Settings; import com.intellectualcrafters.plot.flag.Flag; import com.intellectualcrafters.plot.flag.FlagManager; -import com.intellectualcrafters.plot.object.BlockLoc; -import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotCluster; -import com.intellectualcrafters.plot.object.PlotClusterId; -import com.intellectualcrafters.plot.object.PlotId; -import com.intellectualcrafters.plot.object.PlotSettings; -import com.intellectualcrafters.plot.object.RunnableVal; +import com.intellectualcrafters.plot.object.*; import com.intellectualcrafters.plot.object.comment.PlotComment; import com.intellectualcrafters.plot.util.MainUtil; import com.intellectualcrafters.plot.util.StringMan; import com.intellectualcrafters.plot.util.TaskManager; +import java.lang.reflect.Field; +import java.sql.*; +import java.util.*; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.atomic.AtomicInteger; + /** */ @@ -997,9 +977,9 @@ public class SQLManager implements AbstractDB { public void createTables() throws SQLException { final String[] tables; if (Settings.ENABLE_CLUSTERS) { - tables = new String[] { "plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", "plot_rating", "plot_settings", "cluster" }; + tables = new String[] { "plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", "plot_rating", "plot_settings", "cluster", "player_meta" }; } else { - tables = new String[] { "plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", "plot_rating", "plot_settings" }; + tables = new String[] { "plot", "plot_denied", "plot_helpers", "plot_comments", "plot_trusted", "plot_rating", "plot_settings", "player_meta" }; } final DatabaseMetaData meta = connection.getMetaData(); int create = 0; @@ -1121,6 +1101,15 @@ public class SQLManager implements AbstractDB { + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + " PRIMARY KEY (`cluster_id`)" + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + + prefix + + "player_meta` (" + + " `meta_id` INT(11) NOT NULL AUTO_INCREMENT," + + " `uuid` VARCHAR(40) NOT NULL," + + " `key` VARCHAR(32) NOT NULL," + + " `value` blob NOT NULL," + + " PRIMARY KEY (`meta_id`)" + + ") ENGINE=InnoDB DEFAULT CHARSET=utf8"); } else { stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + prefix @@ -1187,6 +1176,14 @@ public class SQLManager implements AbstractDB { + " `position` VARCHAR(50) NOT NULL DEFAULT 'DEFAULT'," + " PRIMARY KEY (`cluster_id`)" + ")"); + stmt.addBatch("CREATE TABLE IF NOT EXISTS `" + + prefix + + "player_meta` (" + + " `meta_id` INTEGER PRIMARY KEY AUTOINCREMENT," + + " `uuid` VARCHAR(40) NOT NULL," + + " `key` VARCHAR(32) NOT NULL," + + " `value` blob NOT NULL," + + ")"); } stmt.executeBatch(); stmt.clearBatch(); @@ -2341,7 +2338,86 @@ public class SQLManager implements AbstractDB { } }); } - + + @Override + public void addPersistentMeta(final UUID uuid, final String key, final byte[] meta, final boolean delete) { + addGlobalTask(new Runnable() { + @Override + public void run() { + try { + if (delete) { + final PreparedStatement statement = connection.prepareStatement("DELETE FROM `" + prefix + "player_meta` WHERE `uuid` = ? AND `key` = ?"); + statement.setString(1, uuid.toString()); + statement.setString(2, key); + statement.executeUpdate(); + statement.close(); + } + final Blob blob = connection.createBlob(); + blob.setBytes(1, meta); + final PreparedStatement statement = connection.prepareStatement("INSERT INTO `" + prefix + "player_meta`(`uuid`, `key`, `value`) VALUES(?, ? ,?)"); + statement.setString(1, uuid.toString()); + statement.setString(2, key); + statement.setBlob(3, blob); + statement.executeUpdate(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + }); + } + + @Override + public void removePersistentMeta(final UUID uuid, final String key) { + addGlobalTask(new Runnable() { + @Override + public void run() { + try { + final PreparedStatement statement = connection.prepareStatement("DELETE FROM `" + prefix + "player_meta` WHERE `uuid` = ? AND `key` = ?"); + statement.setString(1, uuid.toString()); + statement.setString(2, key); + statement.executeUpdate(); + statement.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + }); + } + + @Override + public void getPersistentMeta(final PlotPlayer player) { + addGlobalTask(new Runnable() { + @Override + public void run() { + try { + PreparedStatement statement = connection.prepareStatement("SELECT * FROM `" + prefix + "player_meta` WHERE `uuid` = ?"); + statement.setString(1, player.getUUID().toString()); + ResultSet resultSet = statement.executeQuery(); + + final Map metaMap = new HashMap<>(); + + while (resultSet.next()) { + String key = resultSet.getString("key"); + Blob rawValue = resultSet.getBlob("value"); + byte[] bytes = rawValue.getBytes(1, (int) rawValue.length()); + metaMap.put(key, bytes); + } + + resultSet.close(); + statement.close(); + + Field field = PlotPlayer.class.getDeclaredField("metaMap"); + field.setAccessible(true); + field.set(player, metaMap); + field.setAccessible(false); + } catch(Exception e) { + e.printStackTrace(); + } + } + }); + } + @Override public HashMap> getClusters() { final LinkedHashMap> newClusters = new LinkedHashMap<>(); diff --git a/src/main/java/com/intellectualcrafters/plot/object/PlotPlayer.java b/src/main/java/com/intellectualcrafters/plot/object/PlotPlayer.java index ba11a78f2..8f3f96884 100644 --- a/src/main/java/com/intellectualcrafters/plot/object/PlotPlayer.java +++ b/src/main/java/com/intellectualcrafters/plot/object/PlotPlayer.java @@ -1,27 +1,25 @@ package com.intellectualcrafters.plot.object; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.commands.RequiredType; import com.intellectualcrafters.plot.config.Settings; -import com.intellectualcrafters.plot.util.CmdConfirm; -import com.intellectualcrafters.plot.util.EventUtil; -import com.intellectualcrafters.plot.util.ExpireManager; -import com.intellectualcrafters.plot.util.MainUtil; -import com.intellectualcrafters.plot.util.PlotGamemode; -import com.intellectualcrafters.plot.util.PlotWeather; -import com.intellectualcrafters.plot.util.SetupUtils; -import com.intellectualcrafters.plot.util.UUIDHandler; +import com.intellectualcrafters.plot.database.DBFunc; +import com.intellectualcrafters.plot.util.*; import com.plotsquared.general.commands.CommandCaller; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + /** * The PlotPlayer class
* - Can cast to: BukkitPlayer / SpongePlayer, which are the current implementations
*/ public abstract class PlotPlayer implements CommandCaller { + + protected final Map metaMap = new HashMap<>(); /** * The metadata map @@ -337,4 +335,29 @@ public abstract class PlotPlayer implements CommandCaller { UUIDHandler.getPlayers().remove(name); PS.get().IMP.unregister(this); } + + public void populatePersistentMetaMap() { + DBFunc.dbManager.getPersistentMeta(this); + } + + public byte[] getPersistentMeta(String key) { + return metaMap.get(key); + } + + public void removePersistentMeta(String key) { + if (metaMap.containsKey(key)) { + metaMap.remove(key); + } + DBFunc.dbManager.removePersistentMeta(getUUID(), key); + } + + public void setPersistentMeta(String key, byte[] value) { + boolean delete = hasPersistentMeta(key); + metaMap.put(key, value); + DBFunc.dbManager.addPersistentMeta(getUUID(), key, value, delete); + } + + public boolean hasPersistentMeta(String key) { + return metaMap.containsKey(key); + } } diff --git a/src/main/java/com/intellectualcrafters/plot/util/ByteArrayUtilities.java b/src/main/java/com/intellectualcrafters/plot/util/ByteArrayUtilities.java new file mode 100644 index 000000000..17ac001f0 --- /dev/null +++ b/src/main/java/com/intellectualcrafters/plot/util/ByteArrayUtilities.java @@ -0,0 +1,18 @@ +package com.intellectualcrafters.plot.util; + +public class ByteArrayUtilities { + + public static byte[] integerToBytes(int i) { + byte[] bytes = new byte[4]; + bytes[0] = (byte) (i >> 24); + bytes[1] = (byte) (i >> 16); + bytes[2] = (byte) (i >> 8); + bytes[3] = (byte) (i); + return bytes; + } + + public static int bytesToInteger(byte[] bytes) { + return (bytes[0]<<24)&0xff000000|(bytes[1]<<16)&0x00ff0000|(bytes[2]<<8)&0x0000ff00|(bytes[3])&0x000000ff; + } + +} diff --git a/src/main/java/com/intellectualcrafters/plot/util/UUIDHandlerImplementation.java b/src/main/java/com/intellectualcrafters/plot/util/UUIDHandlerImplementation.java index f36c0ef21..67d548abe 100644 --- a/src/main/java/com/intellectualcrafters/plot/util/UUIDHandlerImplementation.java +++ b/src/main/java/com/intellectualcrafters/plot/util/UUIDHandlerImplementation.java @@ -1,12 +1,5 @@ package com.intellectualcrafters.plot.util; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; - import com.google.common.base.Charsets; import com.google.common.collect.BiMap; import com.google.common.collect.HashBiMap; @@ -14,14 +7,12 @@ import com.intellectualcrafters.plot.PS; import com.intellectualcrafters.plot.config.C; import com.intellectualcrafters.plot.config.Settings; import com.intellectualcrafters.plot.database.DBFunc; -import com.intellectualcrafters.plot.object.ConsolePlayer; -import com.intellectualcrafters.plot.object.OfflinePlotPlayer; -import com.intellectualcrafters.plot.object.Plot; -import com.intellectualcrafters.plot.object.PlotPlayer; -import com.intellectualcrafters.plot.object.RunnableVal; -import com.intellectualcrafters.plot.object.StringWrapper; +import com.intellectualcrafters.plot.object.*; import com.intellectualcrafters.plot.uuid.UUIDWrapper; +import java.util.*; +import java.util.concurrent.ConcurrentHashMap; + public abstract class UUIDHandlerImplementation { private BiMap uuidMap = HashBiMap.create(new HashMap()); diff --git a/src/main/java/com/plotsquared/bukkit/object/BukkitPlayer.java b/src/main/java/com/plotsquared/bukkit/object/BukkitPlayer.java index 851e2c995..158560fd9 100644 --- a/src/main/java/com/plotsquared/bukkit/object/BukkitPlayer.java +++ b/src/main/java/com/plotsquared/bukkit/object/BukkitPlayer.java @@ -1,7 +1,10 @@ package com.plotsquared.bukkit.object; -import java.util.UUID; - +import com.intellectualcrafters.plot.config.C; +import com.intellectualcrafters.plot.object.Location; +import com.intellectualcrafters.plot.object.PlotPlayer; +import com.intellectualcrafters.plot.util.*; +import com.plotsquared.bukkit.util.BukkitUtil; import org.bukkit.Bukkit; import org.bukkit.Effect; import org.bukkit.GameMode; @@ -12,15 +15,7 @@ import org.bukkit.permissions.Permission; import org.bukkit.permissions.PermissionDefault; import org.bukkit.plugin.PluginManager; -import com.intellectualcrafters.plot.config.C; -import com.intellectualcrafters.plot.object.Location; -import com.intellectualcrafters.plot.object.PlotPlayer; -import com.intellectualcrafters.plot.util.EconHandler; -import com.intellectualcrafters.plot.util.MainUtil; -import com.intellectualcrafters.plot.util.PlotGamemode; -import com.intellectualcrafters.plot.util.PlotWeather; -import com.intellectualcrafters.plot.util.UUIDHandler; -import com.plotsquared.bukkit.util.BukkitUtil; +import java.util.UUID; public class BukkitPlayer extends PlotPlayer { @@ -36,11 +31,13 @@ public class BukkitPlayer extends PlotPlayer { */ public BukkitPlayer(final Player player) { this.player = player; + super.populatePersistentMetaMap(); } public BukkitPlayer(final Player player, final boolean offline) { this.player = player; this.offline = offline; + super.populatePersistentMetaMap(); } @Override diff --git a/src/main/java/com/plotsquared/sponge/object/SpongePlayer.java b/src/main/java/com/plotsquared/sponge/object/SpongePlayer.java index d012eb860..0d0029857 100644 --- a/src/main/java/com/plotsquared/sponge/object/SpongePlayer.java +++ b/src/main/java/com/plotsquared/sponge/object/SpongePlayer.java @@ -40,6 +40,7 @@ public class SpongePlayer extends PlotPlayer { public SpongePlayer(final Player player) { this.player = player; + super.populatePersistentMetaMap(); } @Override