diff --git a/Bukkit/build.gradle b/Bukkit/build.gradle index fef272b7a..8378e37d2 100644 --- a/Bukkit/build.gradle +++ b/Bukkit/build.gradle @@ -110,6 +110,8 @@ shadowJar { include(dependency("javax.annotation:javax-annotation-api")) include(dependency('org.apache.logging.log4j:log4j-slf4j-impl')) include(dependency('org.slf4j:slf4j-api')) + include(dependency('javax.inject:javax.inject:1')) + include(dependency('aopalliance:aopalliance:1.0')) } relocate('net.kyori.text', 'com.plotsquared.formatting.text') diff --git a/Bukkit/pom.xml b/Bukkit/pom.xml index d4848ae84..b9e6fbb23 100644 --- a/Bukkit/pom.xml +++ b/Bukkit/pom.xml @@ -51,7 +51,7 @@ io.papermc paperlib - 1.0.2 + 1.0.4 compile diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java index ab810d9a6..5a1d7c8ef 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/BukkitPlatform.java @@ -30,9 +30,11 @@ import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Stage; +import com.google.inject.TypeLiteral; import com.plotsquared.bukkit.generator.BukkitPlotGenerator; import com.plotsquared.bukkit.inject.BackupModule; import com.plotsquared.bukkit.inject.BukkitModule; +import com.plotsquared.bukkit.inject.PermissionModule; import com.plotsquared.bukkit.inject.WorldManagerModule; import com.plotsquared.bukkit.listener.ChunkListener; import com.plotsquared.bukkit.listener.EntitySpawnListener; @@ -42,6 +44,7 @@ import com.plotsquared.bukkit.listener.SingleWorldListener; import com.plotsquared.bukkit.listener.WorldEvents; import com.plotsquared.bukkit.placeholder.PlaceholderFormatter; import com.plotsquared.bukkit.placeholder.Placeholders; +import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.bukkit.player.BukkitPlayerManager; import com.plotsquared.bukkit.util.task.BukkitTaskManager; import com.plotsquared.bukkit.util.BukkitUtil; @@ -99,8 +102,8 @@ import com.plotsquared.core.util.ConsoleColors; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.FileUtils; -import com.plotsquared.core.util.PermHandler; import com.plotsquared.core.util.PlatformWorldManager; +import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.PremiumVerification; import com.plotsquared.core.util.ReflectionUtils; import com.plotsquared.core.util.SetupUtils; @@ -118,7 +121,6 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Chunk; import org.bukkit.Location; -import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.command.PluginCommand; import org.bukkit.entity.Entity; @@ -178,7 +180,6 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; private boolean methodUnloadSetup = false; private boolean metricsStarted; private EconHandler econ; - private PermHandler perm; private Injector injector; @@ -244,8 +245,11 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // We create the injector after PlotSquared has been initialized, so that we have access // to generated instances and settings - this.injector = Guice.createInjector(Stage.PRODUCTION, new WorldManagerModule(), new PlotSquaredModule(), - new BukkitModule(this), new BackupModule()); + this.injector = Guice.createInjector(Stage.PRODUCTION, new PermissionModule(), + new WorldManagerModule(), + new PlotSquaredModule(), + new BukkitModule(this), + new BackupModule()); this.injector.injectMembers(this); this.serverLocale = Locale.forLanguageTag(Settings.Enabled_Components.DEFAULT_LOCALE); @@ -334,10 +338,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; // Economy if (Settings.Enabled_Components.ECONOMY) { TaskManager.runTask(() -> { - final PermHandler permHandler = getInjector().getInstance(PermHandler.class); - if (permHandler != null) { - permHandler.init(); - } + this.getPermissionHandler().initialize(); final EconHandler econHandler = getInjector().getInstance(EconHandler.class); if (econHandler != null) { econHandler.init(); @@ -569,7 +570,8 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } final Plot plot = area.getOwnedPlot(id); if (plot != null) { - if (!plot.getFlag(ServerPlotFlag.class) || PlotPlayer.wrap(plot.getOwner()) == null) { + if (!plot.getFlag(ServerPlotFlag.class) || PlotSquared.platform().getPlayerManager() + .getPlayerIfExists(plot.getOwner()) == null) { if (world.getKeepSpawnInMemory()) { world.setKeepSpawnInMemory(false); return; @@ -1077,39 +1079,6 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; } } - /** - * Attempt to retrieve a {@link PlotPlayer} from a player identifier. - * This method accepts: - * - {@link Player} objects, - * - {@link OfflinePlayer} objects, - * - {@link String} usernames for online players, and - * - {@link UUID} UUIDs for online players - *

- * In the case of offline players, a fake {@link Player} instance will be created. - * This is a rather expensive operation, and should be avoided if possible. - * - * @param player The player to convert to a PlotPlayer - * @return The plot player instance that corresponds to the identifier, or null - * if no such player object could be created - */ - @Override @Nullable public PlotPlayer wrapPlayer(final Object player) { - if (player instanceof Player) { - return BukkitUtil.adapt((Player) player); - } - if (player instanceof OfflinePlayer) { - return BukkitUtil.adapt((OfflinePlayer) player); - } - if (player instanceof String) { - return (PlotPlayer) PlotSquared.platform().getPlayerManager() - .getPlayerIfExists((String) player); - } - if (player instanceof UUID) { - return (PlotPlayer) PlotSquared.platform().getPlayerManager() - .getPlayerIfExists((UUID) player); - } - return null; - } - @Override public String getNMSPackage() { final String name = Bukkit.getServer().getClass().getPackage().getName(); return name.substring(name.lastIndexOf('.') + 1); @@ -1130,7 +1099,7 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; return names; } - @Override public com.plotsquared.core.location.World getPlatformWorld(@Nonnull final String worldName) { + @Override @Nonnull public com.plotsquared.core.location.World getPlatformWorld(@Nonnull final String worldName) { return BukkitWorld.of(worldName); } @@ -1158,4 +1127,13 @@ import static com.plotsquared.core.util.ReflectionUtils.getRefClass; throw new UnsupportedOperationException("Cannot replace server locale"); } + @Override @Nonnull public PlatformWorldManager getWorldManager() { + return getInjector().getInstance(Key.get(new TypeLiteral>() {})); + } + + @Override @Nonnull @SuppressWarnings("ALL") + public PlayerManager, ? extends Player> getPlayerManager() { + return (PlayerManager) getInjector().getInstance(PlayerManager.class); + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java index c9231110b..cbd5dc213 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/BukkitModule.java @@ -29,7 +29,6 @@ import com.google.inject.AbstractModule; import com.google.inject.Provides; import com.google.inject.Singleton; import com.google.inject.assistedinject.FactoryModuleBuilder; -import com.google.inject.util.Providers; import com.plotsquared.bukkit.BukkitPlatform; import com.plotsquared.bukkit.player.BukkitPlayerManager; import com.plotsquared.bukkit.queue.BukkitLocalQueue; @@ -37,12 +36,9 @@ import com.plotsquared.bukkit.schematic.BukkitSchematicHandler; import com.plotsquared.bukkit.util.BukkitChunkManager; import com.plotsquared.bukkit.util.BukkitEconHandler; import com.plotsquared.bukkit.util.BukkitInventoryUtil; -import com.plotsquared.bukkit.util.BukkitPermHandler; import com.plotsquared.bukkit.util.BukkitRegionManager; import com.plotsquared.bukkit.util.BukkitSetupUtils; import com.plotsquared.bukkit.util.BukkitUtil; -import com.plotsquared.bukkit.util.task.PaperTimeConverter; -import com.plotsquared.bukkit.util.task.SpigotTimeConverter; import com.plotsquared.core.PlotPlatform; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.generator.HybridGen; @@ -58,7 +54,6 @@ import com.plotsquared.core.queue.QueueProvider; import com.plotsquared.core.util.ChunkManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.InventoryUtil; -import com.plotsquared.core.util.PermHandler; import com.plotsquared.core.util.PlayerManager; import com.plotsquared.core.util.RegionManager; import com.plotsquared.core.util.SchematicHandler; @@ -71,6 +66,7 @@ import org.bukkit.command.ConsoleCommandSender; import org.bukkit.plugin.java.JavaPlugin; import javax.annotation.Nonnull; +import javax.annotation.Nullable; public class BukkitModule extends AbstractModule { @@ -97,7 +93,6 @@ public class BukkitModule extends AbstractModule { bind(ChunkManager.class).to(BukkitChunkManager.class); bind(RegionManager.class).to(BukkitRegionManager.class); bind(SchematicHandler.class).to(BukkitSchematicHandler.class); - this.setupVault(); if (Settings.Enabled_Components.WORLDS) { bind(PlotAreaManager.class).to(SinglePlotAreaManager.class); } else { @@ -106,25 +101,14 @@ public class BukkitModule extends AbstractModule { install(new FactoryModuleBuilder().build(HybridPlotWorldFactory.class)); } - private void setupVault() { + @Provides @Singleton @Nullable EconHandler provideEconHandler() { if (Bukkit.getPluginManager().isPluginEnabled("Vault")) { - BukkitPermHandler bukkitPermHandler = null; try { - bukkitPermHandler = new BukkitPermHandler(); - bind(PermHandler.class).toInstance(bukkitPermHandler); + return new BukkitEconHandler(); } catch (final Exception ignored) { - bind(PermHandler.class).toProvider(Providers.of(null)); } - try { - final BukkitEconHandler bukkitEconHandler = new BukkitEconHandler(bukkitPermHandler); - bind(EconHandler.class).toInstance(bukkitEconHandler); - } catch (final Exception ignored) { - bind(EconHandler.class).toProvider(Providers.of(null)); - } - } else { - bind(PermHandler.class).toProvider(Providers.of(null)); - bind(EconHandler.class).toProvider(Providers.of(null)); } + return null; } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/PermissionModule.java similarity index 57% rename from Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java rename to Bukkit/src/main/java/com/plotsquared/bukkit/inject/PermissionModule.java index 8987e3527..de42d884a 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitPermHandler.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/inject/PermissionModule.java @@ -23,38 +23,26 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.bukkit.util; +package com.plotsquared.bukkit.inject; +import com.google.inject.AbstractModule; +import com.google.inject.Provides; import com.google.inject.Singleton; -import com.plotsquared.core.util.PermHandler; -import net.milkbowl.vault.permission.Permission; +import com.plotsquared.bukkit.permissions.BukkitPermissionHandler; +import com.plotsquared.bukkit.permissions.VaultPermissionHandler; +import com.plotsquared.core.permissions.PermissionHandler; import org.bukkit.Bukkit; -import org.bukkit.plugin.RegisteredServiceProvider; -@Singleton public class BukkitPermHandler extends PermHandler { +public class PermissionModule extends AbstractModule { - private Permission perms; - - @Override - public boolean init() { - if (this.perms == null) { - setupPermissions(); + @Provides @Singleton PermissionHandler providePermissionHandler() { + try { + if (Bukkit.getPluginManager().isPluginEnabled("Vault")) { + return new VaultPermissionHandler(); + } + } catch (final Exception ignored) { } - return this.perms != null; + return new BukkitPermissionHandler(); } - private void setupPermissions() { - if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) { - return; - } - RegisteredServiceProvider permissionProvider = - Bukkit.getServer().getServicesManager().getRegistration(Permission.class); - if (permissionProvider != null) { - this.perms = permissionProvider.getProvider(); - } - } - - @Override public boolean hasPermission(String world, String player, String perm) { - return this.perms.playerHas(world, Bukkit.getOfflinePlayer(player), perm); - } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java index 1715f3b95..23dd207ba 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/listener/PlayerEvents.java @@ -39,6 +39,8 @@ import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.listener.PlayerBlockEventType; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -731,34 +733,38 @@ import java.util.regex.Pattern; public void onTeleport(PlayerTeleportEvent event) { Player player = event.getPlayer(); BukkitPlayer pp = BukkitUtil.adapt(player); - Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); - org.bukkit.Location to = event.getTo(); - //noinspection ConstantConditions - if (to != null) { - Location location = BukkitUtil.adapt(to); - PlotArea area = location.getPlotArea(); - if (area == null) { - if (lastPlot != null) { - plotExit(pp, lastPlot); - pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + Plot lastPlot = lastPlotAccess.get().orElse(null); + org.bukkit.Location to = event.getTo(); + //noinspection ConstantConditions + if (to != null) { + Location location = BukkitUtil.adapt(to); + PlotArea area = location.getPlotArea(); + if (area == null) { + if (lastPlot != null) { + plotExit(pp, lastPlot); + lastPlotAccess.remove(); + } + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } + return; } - pp.deleteMeta(PlotPlayer.META_LOCATION); - return; - } - Plot plot = area.getPlot(location); - if (plot != null) { - final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot); - // there is one possibility to still allow teleportation: - // to is identical to the plot's home location, and untrusted-visit is true - // i.e. untrusted-visit can override deny-teleport - // this is acceptable, because otherwise it wouldn't make sense to have both flags set - if (!result && !(plot.getFlag(UntrustedVisitFlag.class) && plot.getHomeSynchronous() - .equals(BukkitUtil.adaptComplete(to)))) { - pp.sendMessage( + Plot plot = area.getPlot(location); + if (plot != null) { + final boolean result = DenyTeleportFlag.allowsTeleport(pp, plot); + // there is one possibility to still allow teleportation: + // to is identical to the plot's home location, and untrusted-visit is true + // i.e. untrusted-visit can override deny-teleport + // this is acceptable, because otherwise it wouldn't make sense to have both flags set + if (!result && !(plot.getFlag(UntrustedVisitFlag.class) && plot.getHomeSynchronous().equals(BukkitUtil.adaptComplete(to)))) { + pp.sendMessage( TranslatableCaption.of("permission.no_permission_event"), Template.of("node", "plots.admin.entry.denied") ); - event.setCancelled(true); + event.setCancelled(true);} } } } @@ -849,18 +855,29 @@ import java.util.regex.Pattern; } // Set last location Location location = BukkitUtil.adapt(to); - pp.setMeta(PlotPlayer.META_LOCATION, location); + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } PlotArea area = location.getPlotArea(); if (area == null) { - pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlotAccess.remove(); + } return; } Plot now = area.getPlot(location); - Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); + Plot lastPlot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlot = lastPlotAccess.get().orElse(null); + } if (now == null) { - if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp - .getMeta("kick", false)) { - pp.sendMessage( + try (final MetaDataAccess kickAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { + pp.sendMessage( TranslatableCaption.of("permission.no_permission_event"), Template.of("node", "plots.admin.exit.denied") ); @@ -872,7 +889,7 @@ import java.util.regex.Pattern; } this.tmpTeleport = true; event.setCancelled(true); - return; + return;} } } else if (now.equals(lastPlot)) { ForceFieldListener.handleForcefield(player, pp, now); @@ -915,18 +932,29 @@ import java.util.regex.Pattern; } // Set last location Location location = BukkitUtil.adapt(to); - pp.setMeta(PlotPlayer.META_LOCATION, location); + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.set(location); + } PlotArea area = location.getPlotArea(); if (area == null) { - pp.deleteMeta(PlotPlayer.META_LAST_PLOT); + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlotAccess.remove(); + } return; } Plot now = area.getPlot(location); - Plot lastPlot = pp.getMeta(PlotPlayer.META_LAST_PLOT); + Plot lastPlot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlot = lastPlotAccess.get().orElse(null); + } if (now == null) { - if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !pp - .getMeta("kick", false)) { - pp.sendMessage( + try (final MetaDataAccess kickAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { + if (lastPlot != null && !plotExit(pp, lastPlot) && this.tmpTeleport && !kickAccess.get().orElse(false)) { + pp.sendMessage( TranslatableCaption.of("permission.no_permission_event"), Template.of("node", "plots.admin.exit.denied") ); @@ -938,7 +966,7 @@ import java.util.regex.Pattern; } this.tmpTeleport = true; event.setCancelled(true); - return; + return;} } } else if (now.equals(lastPlot)) { ForceFieldListener.handleForcefield(player, pp, now); @@ -1175,8 +1203,15 @@ import java.util.regex.Pattern; Player player = event.getPlayer(); BukkitPlayer pp = BukkitUtil.adapt(player); // Delete last location - Plot plot = (Plot) pp.deleteMeta(PlotPlayer.META_LAST_PLOT); - pp.deleteMeta(PlotPlayer.META_LOCATION); + Plot plot; + try (final MetaDataAccess lastPlotAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + plot = lastPlotAccess.remove(); + } + try (final MetaDataAccess lastLocationAccess = + pp.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + lastLocationAccess.remove(); + } if (plot != null) { plotExit(pp, plot); } @@ -1187,9 +1222,6 @@ import java.util.regex.Pattern; } } } - if (Settings.Enabled_Components.PERMISSION_CACHE) { - pp.deleteMeta("perm"); - } Location location = pp.getLocation(); PlotArea area = location.getPlotArea(); if (location.isPlotArea()) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/BukkitPermissionHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/BukkitPermissionHandler.java new file mode 100644 index 000000000..6aca7ea62 --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/BukkitPermissionHandler.java @@ -0,0 +1,86 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.permissions; + +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.core.permissions.ConsolePermissionProfile; +import com.plotsquared.core.permissions.PermissionHandler; +import com.plotsquared.core.permissions.PermissionProfile; +import com.plotsquared.core.player.ConsolePlayer; +import com.plotsquared.core.player.OfflinePlotPlayer; +import com.plotsquared.core.player.PlotPlayer; +import org.bukkit.entity.Player; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.util.EnumSet; +import java.util.Optional; +import java.util.Set; + +public class BukkitPermissionHandler implements PermissionHandler { + + @Override public void initialize() { + } + + @Nonnull @Override public Optional getPermissionProfile( + @Nonnull PlotPlayer playerPlotPlayer) { + if (playerPlotPlayer instanceof BukkitPlayer) { + final BukkitPlayer bukkitPlayer = (BukkitPlayer) playerPlotPlayer; + return Optional.of(new BukkitPermissionProfile(bukkitPlayer.getPlatformPlayer())); + } else if (playerPlotPlayer instanceof ConsolePlayer) { + return Optional.of(ConsolePermissionProfile.INSTANCE); + } + return Optional.empty(); + } + + @Nonnull @Override public Optional getPermissionProfile( + @Nonnull OfflinePlotPlayer offlinePlotPlayer) { + return Optional.empty(); + } + + @Nonnull @Override public Set getCapabilities() { + return EnumSet.of(PermissionHandlerCapability.ONLINE_PERMISSIONS); + } + + + private static final class BukkitPermissionProfile implements PermissionProfile { + + private final WeakReference playerReference; + + private BukkitPermissionProfile(@Nonnull final Player player) { + this.playerReference = new WeakReference<>(player); + } + + @Override public boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + final Player player = this.playerReference.get(); + return player != null && player.hasPermission(permission); + } + + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/VaultPermissionHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/VaultPermissionHandler.java new file mode 100644 index 000000000..b7b08a49f --- /dev/null +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/permissions/VaultPermissionHandler.java @@ -0,0 +1,109 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.bukkit.permissions; + +import com.plotsquared.bukkit.player.BukkitOfflinePlayer; +import com.plotsquared.bukkit.player.BukkitPlayer; +import com.plotsquared.core.permissions.ConsolePermissionProfile; +import com.plotsquared.core.permissions.PermissionHandler; +import com.plotsquared.core.permissions.PermissionProfile; +import com.plotsquared.core.player.ConsolePlayer; +import com.plotsquared.core.player.OfflinePlotPlayer; +import com.plotsquared.core.player.PlotPlayer; +import net.milkbowl.vault.permission.Permission; +import org.bukkit.Bukkit; +import org.bukkit.OfflinePlayer; +import org.bukkit.plugin.RegisteredServiceProvider; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.EnumSet; +import java.util.Optional; +import java.util.Set; + +public class VaultPermissionHandler implements PermissionHandler { + + private Permission permissions; + + @Override public void initialize() { + if (Bukkit.getServer().getPluginManager().getPlugin("Vault") == null) { + throw new IllegalStateException("Vault is not present on the server"); + } + RegisteredServiceProvider permissionProvider = + Bukkit.getServer().getServicesManager().getRegistration(Permission.class); + if (permissionProvider != null) { + this.permissions = permissionProvider.getProvider(); + } + } + + @Nonnull @Override public Optional getPermissionProfile( + @Nonnull PlotPlayer playerPlotPlayer) { + if (playerPlotPlayer instanceof BukkitPlayer) { + final BukkitPlayer bukkitPlayer = (BukkitPlayer) playerPlotPlayer; + return Optional.of(new VaultPermissionProfile(bukkitPlayer.getPlatformPlayer())); + } else if (playerPlotPlayer instanceof ConsolePlayer) { + return Optional.of(ConsolePermissionProfile.INSTANCE); + } + return Optional.empty(); + } + + @Nonnull @Override public Optional getPermissionProfile( + @Nonnull OfflinePlotPlayer offlinePlotPlayer) { + if (offlinePlotPlayer instanceof BukkitOfflinePlayer) { + return Optional.of(new VaultPermissionProfile(((BukkitOfflinePlayer) offlinePlotPlayer).player)); + } + return Optional.empty(); + } + + @Nonnull @Override public Set getCapabilities() { + return EnumSet.of(PermissionHandlerCapability.PER_WORLD_PERMISSIONS, + PermissionHandlerCapability.ONLINE_PERMISSIONS, + PermissionHandlerCapability.OFFLINE_PERMISSIONS); + } + + + private final class VaultPermissionProfile implements PermissionProfile { + + private final OfflinePlayer offlinePlayer; + + private VaultPermissionProfile(@Nonnull final OfflinePlayer offlinePlayer) { + this.offlinePlayer = offlinePlayer; + } + + @Override public boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + if (permissions == null) { + return false; + } + if (world == null && offlinePlayer instanceof BukkitPlayer) { + return permissions.playerHas(((BukkitPlayer) offlinePlayer).getPlatformPlayer(), permission); + } + return permissions.playerHas(world, offlinePlayer, permission); + } + + } + +} diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitOfflinePlayer.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitOfflinePlayer.java index 238081a0c..799fbf2b1 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitOfflinePlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitOfflinePlayer.java @@ -25,39 +25,49 @@ */ package com.plotsquared.bukkit.player; +import com.plotsquared.core.permissions.NullPermissionProfile; +import com.plotsquared.core.permissions.PermissionHandler; +import com.plotsquared.core.permissions.PermissionProfile; import com.plotsquared.core.player.OfflinePlotPlayer; import org.bukkit.OfflinePlayer; +import javax.annotation.Nonnegative; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.UUID; public class BukkitOfflinePlayer implements OfflinePlotPlayer { public final OfflinePlayer player; + private final PermissionProfile permissionProfile; /** * Please do not use this method. Instead use BukkitUtil.getPlayer(Player), * as it caches player objects. - * - * @param player */ - public BukkitOfflinePlayer(OfflinePlayer player) { + public BukkitOfflinePlayer(@Nonnull final OfflinePlayer player, @Nonnull final + PermissionHandler permissionHandler) { this.player = player; + this.permissionProfile = permissionHandler.getPermissionProfile(this) + .orElse(NullPermissionProfile.INSTANCE); } @Nonnull @Override public UUID getUUID() { return this.player.getUniqueId(); } - @Override public long getLastPlayed() { - return this.player.getLastPlayed(); - } - - @Override public boolean isOnline() { - return this.player.isOnline(); + @Override @Nonnegative public long getLastPlayed() { + return this.player.getLastSeen(); } @Override public String getName() { return this.player.getName(); } + + @Override public boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + return this.permissionProfile.hasPermission(world, permission); + } + } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java index c7f45d1f3..3c6293a22 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayer.java @@ -32,6 +32,7 @@ import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.PermissionHandler; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotWeather; import com.plotsquared.core.plot.world.PlotAreaManager; @@ -54,6 +55,8 @@ import org.bukkit.event.player.PlayerTeleportEvent; import org.bukkit.permissions.PermissionAttachmentInfo; import org.bukkit.plugin.RegisteredListener; +import javax.annotation.Nonnegative; + import javax.annotation.Nonnull; import javax.annotation.Nullable; import java.util.Arrays; @@ -69,13 +72,11 @@ import static com.sk89q.worldedit.world.gamemode.GameModes.SURVIVAL; public class BukkitPlayer extends PlotPlayer { private static boolean CHECK_EFFECTIVE = true; - - private final EconHandler econHandler; public final Player player; - private boolean offline; + private final EconHandler econHandler; private String name; - - + private String lastMessage = ""; + private long lastMessageTime = 0L; /** *

Please do not use this method. Instead use * BukkitUtil.getPlayer(Player), as it caches player objects.

@@ -83,22 +84,18 @@ public class BukkitPlayer extends PlotPlayer { * @param player Bukkit player instance */ public BukkitPlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, - @Nonnull final Player player, @Nullable final EconHandler econHandler) { - this(plotAreaManager, eventDispatcher, player, false, econHandler); - } - - public BukkitPlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, - @Nonnull final Player player, final boolean offline, @Nullable final EconHandler econHandler) { - this(plotAreaManager, eventDispatcher, player, offline, true, econHandler); + @Nonnull final Player player, @Nullable final EconHandler econHandler, @Nonnull final PermissionHandler permissionHandler) { + this(plotAreaManager, eventDispatcher, player, false, econHandler, permissionHandler); } public BukkitPlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final - EventDispatcher eventDispatcher, @Nonnull final Player player, final boolean offline, - final boolean realPlayer, @Nullable final EconHandler econHandler) { - super(plotAreaManager, eventDispatcher, econHandler); + EventDispatcher eventDispatcher, @Nonnull final Player player, + final boolean realPlayer, @Nullable final EconHandler econHandler, + @Nonnull final PermissionHandler permissionHandler) { + super(plotAreaManager, eventDispatcher, econHandler, permissionHandler); this.player = player; - this.offline = offline; this.econHandler = econHandler; + this.setupPermissionProfile(); if (realPlayer) { super.populatePersistentMetaMap(); } @@ -125,8 +122,8 @@ public class BukkitPlayer extends PlotPlayer { return player.getUniqueId(); } - @Override public long getLastPlayed() { - return this.player.getLastPlayed(); + @Override @Nonnegative public long getLastPlayed() { + return this.player.getLastSeen(); } @Override public boolean canTeleport(@Nonnull final Location location) { @@ -163,7 +160,8 @@ public class BukkitPlayer extends PlotPlayer { return this.player.hasPermission(permission); } - @Override public int hasPermissionRange(final String stub, final int range) { + @Override @Nonnegative public int hasPermissionRange(@Nonnull final String stub, + @Nonnegative final int range) { if (hasPermission(Captions.PERMISSION_ADMIN.getTranslated())) { return Integer.MAX_VALUE; } @@ -223,10 +221,6 @@ public class BukkitPlayer extends PlotPlayer { return max; } - @Override public boolean isPermissionSet(@Nonnull final String permission) { - return this.player.isPermissionSet(permission); - } - @Override public void teleport(@Nonnull final Location location, @Nonnull final TeleportCause cause) { if (Math.abs(location.getX()) >= 30000000 || Math.abs(location.getZ()) >= 30000000) { @@ -245,10 +239,6 @@ public class BukkitPlayer extends PlotPlayer { return this.name; } - @Override public boolean isOnline() { - return !this.offline && this.player.isOnline(); - } - @Override public void setCompassTarget(Location location) { this.player.setCompassTarget( new org.bukkit.Location(BukkitUtil.getWorld(location.getWorldName()), location.getX(), diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java index 3b1539980..3666f407b 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/player/BukkitPlayerManager.java @@ -27,6 +27,7 @@ package com.plotsquared.bukkit.player; import com.google.inject.Inject; import com.google.inject.Singleton; +import com.plotsquared.core.permissions.PermissionHandler; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; @@ -46,21 +47,26 @@ import java.util.UUID; private final PlotAreaManager plotAreaManager; private final EventDispatcher eventDispatcher; private final EconHandler econHandler; + private final PermissionHandler permissionHandler; @Inject public BukkitPlayerManager(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, - @Nullable final EconHandler econHandler) { + @Nullable final EconHandler econHandler, + @Nonnull final PermissionHandler permissionHandler) { this.plotAreaManager = plotAreaManager; this.eventDispatcher = eventDispatcher; this.econHandler = econHandler; + this.permissionHandler = permissionHandler; } @Nonnull @Override public BukkitPlayer getPlayer(@Nonnull final Player object) { + if (!object.isOnline()) { + throw new NoSuchPlayerException(object.getUniqueId()); + } try { return getPlayer(object.getUniqueId()); } catch (final NoSuchPlayerException exception) { - return new BukkitPlayer(this.plotAreaManager, this.eventDispatcher, object, - object.isOnline(), false, this.econHandler); + return new BukkitPlayer(this.plotAreaManager, this.eventDispatcher, object, false, this.econHandler, this.permissionHandler); } } @@ -69,18 +75,18 @@ import java.util.UUID; if (player == null || !player.isOnline()) { throw new NoSuchPlayerException(uuid); } - return new BukkitPlayer(this.plotAreaManager, this.eventDispatcher, player, this.econHandler); + return new BukkitPlayer(this.plotAreaManager, this.eventDispatcher, player, this.econHandler, this.permissionHandler); } @Nullable @Override public BukkitOfflinePlayer getOfflinePlayer(@Nullable final UUID uuid) { if (uuid == null) { return null; } - return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid)); + return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(uuid), this.permissionHandler); } @Nonnull @Override public BukkitOfflinePlayer getOfflinePlayer(@Nonnull final String username) { - return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(username)); + return new BukkitOfflinePlayer(Bukkit.getOfflinePlayer(username), this.permissionHandler); } } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java index d073b10e1..a1bf7bee7 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/queue/BukkitLocalQueue.java @@ -29,6 +29,7 @@ import com.plotsquared.bukkit.schematic.StateWrapper; import com.plotsquared.bukkit.util.BukkitBlockUtil; import com.plotsquared.core.queue.BasicLocalBlockQueue; import com.plotsquared.core.util.BlockUtil; +import com.plotsquared.core.util.ChunkUtil; import com.sk89q.jnbt.CompoundTag; import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.WorldEdit; @@ -124,9 +125,9 @@ public class BukkitLocalQueue extends BasicLocalBlockQueue { for (int j = 0; j < blocksLayer.length; j++) { if (blocksLayer[j] != null) { BaseBlock block = blocksLayer[j]; - int x = MainUtil.x_loc[layer][j]; - int y = MainUtil.y_loc[layer][j]; - int z = MainUtil.z_loc[layer][j]; + int x = ChunkUtil.getX(j); + int y = ChunkUtil.getY(layer, j); + int z = ChunkUtil.getZ(j); BlockData blockData = BukkitAdapter.adapt(block); diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java index a1965fccd..ae42296b9 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitEconHandler.java @@ -25,14 +25,12 @@ */ package com.plotsquared.bukkit.util; -import com.google.inject.Inject; import com.google.inject.Singleton; import com.plotsquared.bukkit.player.BukkitOfflinePlayer; import com.plotsquared.bukkit.player.BukkitPlayer; import com.plotsquared.core.player.OfflinePlotPlayer; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.EconHandler; -import com.plotsquared.core.util.PermHandler; import net.milkbowl.vault.economy.Economy; import org.bukkit.Bukkit; import org.bukkit.plugin.RegisteredServiceProvider; @@ -43,14 +41,7 @@ import javax.annotation.Nullable; private Economy econ; - private final PermHandler permHandler; - - @Inject public BukkitEconHandler(@Nullable final PermHandler permHandler) { - this.permHandler = permHandler; - } - - @Override - public boolean init() { + @Override public boolean init() { if (this.econ == null) { setupEconomy(); } @@ -88,17 +79,6 @@ import javax.annotation.Nullable; this.econ.depositPlayer(((BukkitOfflinePlayer) player).player, amount); } - /** - * @deprecated Use {@link PermHandler#hasPermission(String, String, String)} instead - */ - @Deprecated @Override public boolean hasPermission(String world, String player, String perm) { - if (this.permHandler != null) { - return this.permHandler.hasPermission(world, player, perm); - } else { - return false; - } - } - @Override public double getBalance(PlotPlayer player) { return this.econ.getBalance(player.getName()); } diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java index 8c110157c..1b2224a27 100644 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java +++ b/Bukkit/src/main/java/com/plotsquared/bukkit/util/BukkitUtil.java @@ -59,7 +59,6 @@ import net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer; import org.bukkit.Bukkit; import org.bukkit.Chunk; import org.bukkit.Material; -import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.block.Biome; import org.bukkit.block.Block; @@ -107,7 +106,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Objects; import java.util.Set; -import java.util.UUID; import java.util.function.Consumer; import java.util.function.IntConsumer; import java.util.stream.Stream; @@ -127,24 +125,6 @@ import java.util.stream.Stream; super(regionManager); } - /** - * Get a {@link PlotPlayer} from an {@link OfflinePlayer}. If the player is - * online, it returns a complete player. If the player is offline, it creates - * a fake player - * - * @param op Offline player - * @return Plot player instance - */ - @Nonnull public static PlotPlayer adapt(@Nonnull final OfflinePlayer op) { - if (op.isOnline()) { - return adapt(Objects.requireNonNull(op.getPlayer())); - } - final Player player = OfflinePlayerUtil.loadPlayer(op); - player.loadData(); - return new BukkitPlayer(PlotSquared.get().getPlotAreaManager(), - PlotSquared.get().getEventDispatcher(), player, true, PlotSquared.platform().getEconHandler()); - } - /** * Turn a Bukkit {@link Player} into a PlotSquared {@link PlotPlayer} * @@ -225,18 +205,6 @@ import java.util.stream.Stream; } } - /** - * Gets the PlotPlayer for a UUID. The PlotPlayer is usually cached and - * will provide useful functions relating to players. - * - * @param uuid the uuid to wrap - * @return a {@code PlotPlayer} - * @see PlotPlayer#wrap(Object) - */ - @Override @Nonnull public PlotPlayer getPlayer(@Nonnull final UUID uuid) { - return PlotPlayer.wrap(Bukkit.getOfflinePlayer(uuid)); - } - @Override public boolean isBlockSame(@Nonnull final BlockState block1, @Nonnull final BlockState block2) { if (block1.equals(block2)) { diff --git a/Bukkit/src/main/java/com/plotsquared/bukkit/util/OfflinePlayerUtil.java b/Bukkit/src/main/java/com/plotsquared/bukkit/util/OfflinePlayerUtil.java deleted file mode 100644 index 41ae4dedd..000000000 --- a/Bukkit/src/main/java/com/plotsquared/bukkit/util/OfflinePlayerUtil.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * _____ _ _ _____ _ - * | __ \| | | | / ____| | | - * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | - * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | - * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | - * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| - * | | - * |_| - * PlotSquared plot management system for Minecraft - * Copyright (C) 2020 IntellectualSites - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ -package com.plotsquared.bukkit.util; - -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Method; -import java.util.UUID; - -import static com.plotsquared.core.util.ReflectionUtils.callConstructor; -import static com.plotsquared.core.util.ReflectionUtils.callMethod; -import static com.plotsquared.core.util.ReflectionUtils.getCbClass; -import static com.plotsquared.core.util.ReflectionUtils.getField; -import static com.plotsquared.core.util.ReflectionUtils.getNmsClass; -import static com.plotsquared.core.util.ReflectionUtils.getUtilClass; -import static com.plotsquared.core.util.ReflectionUtils.makeConstructor; -import static com.plotsquared.core.util.ReflectionUtils.makeField; -import static com.plotsquared.core.util.ReflectionUtils.makeMethod; - -public class OfflinePlayerUtil { - - public static Player loadPlayer(OfflinePlayer player) { - if (player == null) { - return null; - } - if (player instanceof Player) { - return (Player) player; - } - return loadPlayer(player.getUniqueId(), player.getName()); - } - - private static Player loadPlayer(UUID id, String name) { - Object server = getMinecraftServer(); - Object interactManager = newPlayerInteractManager(); - Object worldServer = getWorldServer(); - Object profile = newGameProfile(id, name); - Class entityPlayerClass = getNmsClass("EntityPlayer"); - Constructor entityPlayerConstructor = - makeConstructor(entityPlayerClass, getNmsClass("MinecraftServer"), - getNmsClass("WorldServer"), getUtilClass("com.mojang.authlib.GameProfile"), - getNmsClass("PlayerInteractManager")); - Object entityPlayer = - callConstructor(entityPlayerConstructor, server, worldServer, profile, interactManager); - return (Player) getBukkitEntity(entityPlayer); - } - - private static Object newGameProfile(UUID id, String name) { - Class gameProfileClass = getUtilClass("com.mojang.authlib.GameProfile"); - if (gameProfileClass == null) { //Before uuids - return name; - } - Constructor gameProfileConstructor = - makeConstructor(gameProfileClass, UUID.class, String.class); - if (gameProfileConstructor == null) { //Version has string constructor - gameProfileConstructor = makeConstructor(gameProfileClass, String.class, String.class); - return callConstructor(gameProfileConstructor, id.toString(), name); - } else { //Version has uuid constructor - return callConstructor(gameProfileConstructor, id, name); - } - } - - private static Object newPlayerInteractManager() { - Object worldServer = getWorldServer(); - Class playerInteractClass = getNmsClass("PlayerInteractManager"); - Class worldClass = getNmsClass("World"); - Constructor c = makeConstructor(playerInteractClass, worldClass); - if (c == null) { - c = makeConstructor(playerInteractClass, getNmsClass("WorldServer")); - } - return callConstructor(c, worldServer); - } - - public static Object getWorldServerNew() { - Object server = getMinecraftServer(); - Class minecraftServerClass = getNmsClass("MinecraftServer"); - Class dimensionManager = getNmsClass("DimensionManager"); - Object overworld = getField(makeField(dimensionManager, "OVERWORLD"), null); - Method getWorldServer = - makeMethod(minecraftServerClass, "getWorldServer", dimensionManager); - return callMethod(getWorldServer, server, overworld); - } - - private static Object getWorldServer() { - Object server = getMinecraftServer(); - Class minecraftServerClass = getNmsClass("MinecraftServer"); - Method getWorldServer = makeMethod(minecraftServerClass, "getWorldServer", int.class); - Object o; - try { - o = callMethod(getWorldServer, server, 0); - } catch (final RuntimeException e) { - o = getWorldServerNew(); - } - return o; - } - - //NMS Utils - - private static Object getMinecraftServer() { - return callMethod(makeMethod(getCbClass("CraftServer"), "getServer"), Bukkit.getServer()); - } - - private static Entity getBukkitEntity(Object o) { - Method getBukkitEntity = makeMethod(o.getClass(), "getBukkitEntity"); - return callMethod(getBukkitEntity, o); - } -} diff --git a/Core/build.gradle b/Core/build.gradle index 59a1cddf0..a500ee5a0 100644 --- a/Core/build.gradle +++ b/Core/build.gradle @@ -19,6 +19,8 @@ dependencies { compile("com.google.inject:guice:4.2.3") compile("com.google.inject.extensions:guice-assistedinject:4.2.3") compile group: 'com.google.code.findbugs', name: 'annotations', version: '3.0.1' + compile group: 'javax.inject', name: 'javax.inject', version: '1' + compile group: 'aopalliance', name: 'aopalliance', version: '1.0' // logging implementation("org.apache.logging.log4j:log4j-slf4j-impl:2.8.1") } diff --git a/Core/pom.xml b/Core/pom.xml index 62dfeeb84..05142d3a8 100644 --- a/Core/pom.xml +++ b/Core/pom.xml @@ -36,6 +36,24 @@ 3.0.1 compile
+ + javax.inject + javax.inject + 1 + compile + + + aopalliance + aopalliance + 1.0 + compile + + + org.projectlombok + lombok + 1.18.12 + runtime + com.sk89q.worldedit worldedit-core diff --git a/Core/src/main/java/com/plotsquared/core/PlotAPI.java b/Core/src/main/java/com/plotsquared/core/PlotAPI.java index 75be2a0e5..3dc756732 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotAPI.java +++ b/Core/src/main/java/com/plotsquared/core/PlotAPI.java @@ -40,6 +40,7 @@ import com.plotsquared.core.util.query.PlotQuery; import net.kyori.adventure.text.minimessage.Template; import javax.annotation.Nonnull; +import javax.annotation.Nullable; import java.util.Collections; import java.util.Set; import java.util.UUID; @@ -182,10 +183,9 @@ import java.util.UUID; * * @param uuid the uuid of the player to wrap * @return a {@code PlotPlayer} - * @see PlotPlayer#wrap(Object) */ - public PlotPlayer wrapPlayer(UUID uuid) { - return PlotPlayer.wrap(uuid); + @Nullable public PlotPlayer wrapPlayer(@Nonnull final UUID uuid) { + return PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); } /** @@ -193,10 +193,9 @@ import java.util.UUID; * * @param player the player to wrap * @return a {@code PlotPlayer} - * @see PlotPlayer#wrap(Object) */ - public PlotPlayer wrapPlayer(String player) { - return PlotPlayer.wrap(player); + @Nullable public PlotPlayer wrapPlayer(@Nonnull final String player) { + return PlotSquared.platform().getPlayerManager().getPlayerIfExists(player); } /** diff --git a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java index f48ca17ef..4e0f41170 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotPlatform.java +++ b/Core/src/main/java/com/plotsquared/core/PlotPlatform.java @@ -27,6 +27,7 @@ package com.plotsquared.core; import com.google.inject.Injector; import com.google.inject.Key; +import com.google.inject.TypeLiteral; import com.plotsquared.core.backup.BackupManager; import com.plotsquared.core.configuration.caption.LocaleHolder; import com.plotsquared.core.generator.GeneratorWrapper; @@ -34,6 +35,7 @@ import com.plotsquared.core.generator.HybridUtils; import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.inject.annotations.DefaultGenerator; import com.plotsquared.core.location.World; +import com.plotsquared.core.permissions.PermissionHandler; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.queue.GlobalBlockQueue; import com.plotsquared.core.util.ChunkManager; @@ -79,14 +81,6 @@ public interface PlotPlatform

extends LocaleHolder { */ File getWorldContainer(); - /** - * Wraps a player into a PlotPlayer object. - * - * @param player The player to convert to a PlotPlayer - * @return A PlotPlayer - */ - @Nullable PlotPlayer

wrapPlayer(Object player); - /** * Completely shuts down the plugin. */ @@ -178,7 +172,7 @@ public interface PlotPlatform

extends LocaleHolder { * @return Player manager */ @Nonnull default PlayerManager, ? extends P> getPlayerManager() { - return getInjector().getInstance(PlayerManager.class); + return getInjector().getInstance(Key.get(new TypeLiteral, ? extends P>>() {})); } /** @@ -266,4 +260,13 @@ public interface PlotPlatform

extends LocaleHolder { */ @Nonnull Audience getConsoleAudience(); + /** + * Get the {@link PermissionHandler} implementation for the platform + * + * @return Permission handler + */ + @Nonnull default PermissionHandler getPermissionHandler() { + return getInjector().getInstance(PermissionHandler.class); + } + } diff --git a/Core/src/main/java/com/plotsquared/core/PlotSquared.java b/Core/src/main/java/com/plotsquared/core/PlotSquared.java index bcd9cfcdd..6dc1bb08c 100644 --- a/Core/src/main/java/com/plotsquared/core/PlotSquared.java +++ b/Core/src/main/java/com/plotsquared/core/PlotSquared.java @@ -50,6 +50,7 @@ import com.plotsquared.core.generator.IndependentPlotGenerator; import com.plotsquared.core.inject.factory.HybridPlotWorldFactory; import com.plotsquared.core.listener.PlotListener; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.plot.BlockBucket; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -170,7 +171,8 @@ public class PlotSquared { this.platform = iPlotMain; Settings.PLATFORM = platform; - MainUtil.initCache(); // TODO: REMOVE!! + // Initialize the class + PlayerMetaDataKeys.load(); // // Register configuration serializable classes diff --git a/Core/src/main/java/com/plotsquared/core/command/Area.java b/Core/src/main/java/com/plotsquared/core/command/Area.java index 6c7e4369c..72ca92da2 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Area.java +++ b/Core/src/main/java/com/plotsquared/core/command/Area.java @@ -79,9 +79,12 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.UUID; @CommandDeclaration(command = "area", permission = "plots.area", @@ -101,6 +104,8 @@ public class Area extends SubCommand { private final WorldUtil worldUtil; private final RegionManager regionManager; + private final Map> metaData = new HashMap<>(); + @Inject public Area(@Nonnull final PlotAreaManager plotAreaManager, @WorldConfig @Nonnull final YamlConfiguration worldConfiguration, @WorldFile @Nonnull final File worldFile, @@ -267,14 +272,16 @@ public class Area extends SubCommand { case 2: switch (args[1].toLowerCase()) { case "pos1": { // Set position 1 - HybridPlotWorld area = player.getMeta("area_create_area"); + HybridPlotWorld area = (HybridPlotWorld) metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()) + .get("area_create_area"); if (area == null) { player.sendMessage(TranslatableCaption.of("commandconfig.command_syntax"), Templates.of("value", "/plot area create [world[:id]] [=]...")); return false; } Location location = player.getLocation(); - player.setMeta("area_pos1", location); + metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()) + .put("area_pos1", location); player.sendMessage(TranslatableCaption.of("set.set_attribute"), Template.of("attribute", "area_pos1"), Template.of("value", location.getX() + "," + location.getZ())); @@ -282,14 +289,15 @@ public class Area extends SubCommand { return true; } case "pos2": // Set position 2 and finish creation for type=2 (partial) - final HybridPlotWorld area = player.getMeta("area_create_area"); + final HybridPlotWorld area = (HybridPlotWorld) metaData + .computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()).get("area_create_area"); if (area == null) { player.sendMessage(TranslatableCaption.of("commandconfig.command_syntax"), Templates.of("value", "/plot area create [world[:id]] [=]...")); return false; } Location pos1 = player.getLocation(); - Location pos2 = player.getMeta("area_pos1"); + Location pos2 = (Location) metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()).get("area_pos1"); int dx = Math.abs(pos1.getX() - pos2.getX()); int dz = Math.abs(pos1.getZ() - pos2.getZ()); int numX = Math.max(1, @@ -518,7 +526,7 @@ public class Area extends SubCommand { player.teleport(this.worldUtil.getSpawn(pa.getWorldName()), TeleportCause.COMMAND); } - player.setMeta("area_create_area", pa); + metaData.computeIfAbsent(player.getUUID(), missingUUID -> new HashMap<>()).put("area_create_area", pa); player.sendMessage( TranslatableCaption.of("single.get_position"), Template.of("command", getCommandString()) diff --git a/Core/src/main/java/com/plotsquared/core/command/Auto.java b/Core/src/main/java/com/plotsquared/core/command/Auto.java index f9dd3ab2c..a1ee88222 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Auto.java +++ b/Core/src/main/java/com/plotsquared/core/command/Auto.java @@ -26,7 +26,6 @@ package com.plotsquared.core.command; import com.google.common.collect.Lists; -import com.google.common.primitives.Ints; import com.google.inject.Inject; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.caption.CaptionUtility; @@ -38,6 +37,9 @@ import com.plotsquared.core.events.PlayerAutoPlotEvent; import com.plotsquared.core.events.PlotAutoMergeEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.events.TeleportCause; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; +import com.plotsquared.core.permissions.PermissionHandler; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -92,28 +94,31 @@ public class Auto extends SubCommand { } int diff = allowedPlots - currentPlots; if (diff - sizeX * sizeZ < 0) { - if (player.hasPersistentMeta("grantedPlots")) { - int grantedPlots = Ints.fromByteArray(player.getPersistentMeta("grantedPlots")); - if (diff < 0 && grantedPlots < sizeX * sizeZ) { - player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); - return false; - } else if (diff >= 0 && grantedPlots + diff < sizeX * sizeZ) { - player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); - return false; - } else { - int left = grantedPlots + diff < 0 ? 0 : diff - sizeX * sizeZ; - if (left == 0) { - player.removePersistentMeta("grantedPlots"); + try (final MetaDataAccess metaDataAccess = player.accessPersistentMetaData( + PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { + if (metaDataAccess.isPresent()) { + int grantedPlots = metaDataAccess.get().orElse(0); + if (diff < 0 && grantedPlots < sizeX * sizeZ) { + player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); + return false; + } else if (diff >= 0 && grantedPlots + diff < sizeX * sizeZ) { + player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); + return false; } else { - player.setPersistentMeta("grantedPlots", Ints.toByteArray(left)); - } - player.sendMessage(TranslatableCaption.of("economy.removed_granted_plot"), + int left = grantedPlots + diff < 0 ? 0 : diff - sizeX * sizeZ; + if (left == 0) { + metaDataAccess.remove(); + } else { + metaDataAccess.set(left); + } + player.sendMessage(TranslatableCaption.of("economy.removed_granted_plot"), Template.of("usedGrants", String.valueOf(grantedPlots - left)), Template.of("remainingGrants", String.valueOf(left))); + } + } else { + player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); + return false; } - } else { - player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); - return false; } } return true; @@ -148,7 +153,10 @@ public class Auto extends SubCommand { */ public static void autoClaimSafe(final PlotPlayer player, final PlotArea area, PlotId start, final String schematic) { - player.setMeta(Auto.class.getName(), true); + try (final MetaDataAccess metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) { + metaDataAccess.set(true); + } autoClaimFromDatabase(player, area, start, new RunnableVal() { @Override public void run(final Plot plot) { try { @@ -177,9 +185,11 @@ public class Auto extends SubCommand { @Override public boolean onCommand(final PlotPlayer player, String[] args) { PlotArea plotarea = player.getApplicablePlotArea(); if (plotarea == null) { - if (this.econHandler != null) { - for (PlotArea area : this.plotAreaManager.getAllPlotAreas()) { - if (this.econHandler.hasPermission(area.getWorldName(), player.getName(), "plots.auto")) { + final PermissionHandler permissionHandler = PlotSquared.platform().getPermissionHandler(); + if (permissionHandler.hasCapability( + PermissionHandler.PermissionHandlerCapability.PER_WORLD_PERMISSIONS)) { + for (final PlotArea area : this.plotAreaManager.getAllPlotAreas()) { + if (player.hasPermission(area.getWorldName(), "plots.auto")) { if (plotarea != null) { plotarea = null; break; @@ -257,9 +267,12 @@ public class Auto extends SubCommand { return false; } final int allowed_plots = player.getAllowedPlots(); - if (!force && (player.getMeta(Auto.class.getName(), false) || !checkAllowedPlots(player, - plotarea, allowed_plots, size_x, size_z))) { - return false; + try (final MetaDataAccess metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) { + if (!force && (metaDataAccess.get().orElse(false) || !checkAllowedPlots(player, + plotarea, allowed_plots, size_x, size_z))) { + return false; + } } if (schematic != null && !schematic.isEmpty()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Buy.java b/Core/src/main/java/com/plotsquared/core/command/Buy.java index 612f9f499..c6f753564 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Buy.java +++ b/Core/src/main/java/com/plotsquared/core/command/Buy.java @@ -101,7 +101,7 @@ public class Buy extends Command { this.econHandler.depositMoney(PlotSquared.platform().getPlayerManager().getOfflinePlayer(plot.getOwnerAbs()), price); - PlotPlayer owner = PlotSquared.platform().getPlayerManager().getPlayerIfExists(plot.getOwnerAbs()); + PlotPlayer owner = PlotSquared.platform().getPlayerManager().getPlayerIfExists(plot.getOwnerAbs()); if (owner != null) { owner.sendMessage( TranslatableCaption.of("economy.plot_sold"), diff --git a/Core/src/main/java/com/plotsquared/core/command/Claim.java b/Core/src/main/java/com/plotsquared/core/command/Claim.java index dece94348..a4ba9b576 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Claim.java +++ b/Core/src/main/java/com/plotsquared/core/command/Claim.java @@ -25,7 +25,6 @@ */ package com.plotsquared.core.command; -import com.google.common.primitives.Ints; import com.google.inject.Inject; import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.Captions; @@ -37,6 +36,8 @@ import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.location.Direction; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -96,36 +97,40 @@ public class Claim extends SubCommand { int currentPlots = Settings.Limit.GLOBAL ? player.getPlotCount() : player.getPlotCount(location.getWorldName()); - int grants = 0; - if (currentPlots >= player.getAllowedPlots() && !force) { - if (player.hasPersistentMeta("grantedPlots")) { - grants = Ints.fromByteArray(player.getPersistentMeta("grantedPlots")); - if (grants <= 0) { - player.removePersistentMeta("grantedPlots"); + + final PlotArea area = plot.getArea(); + + try (final MetaDataAccess metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { + int grants = 0; + if (currentPlots >= player.getAllowedPlots() && !force) { + if (metaDataAccess.isPresent()) { + grants = metaDataAccess.get().orElse(0); + if (grants <= 0) { + metaDataAccess.remove(); + player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); + } + } else { player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); } - } else { - player.sendMessage(TranslatableCaption.of("permission.cant_claim_more_plots")); } - } - if (!plot.canClaim(player)) { - player.sendMessage(TranslatableCaption.of("working.plot_is_claimed")); - } - final PlotArea area = plot.getArea(); - if (schematic != null && !schematic.isEmpty()) { - if (area.isSchematicClaimSpecify()) { - if (!area.hasSchematic(schematic)) { - player.sendMessage( + + if (!plot.canClaim(player)) { + player.sendMessage(TranslatableCaption.of("working.plot_is_claimed")); + } + if (schematic != null && !schematic.isEmpty()) { + if (area.isSchematicClaimSpecify()) { + if (!area.hasSchematic(schematic)) { + player.sendMessage( TranslatableCaption.of("schematics.schematic_invalid_named"), Template.of("schemname", schematic), Template.of("reason", "non-existant") ); } if (!Permissions.hasPermission(player, CaptionUtility - .format(player, Captions.PERMISSION_CLAIM_SCHEMATIC.getTranslated(), schematic)) - && !Permissions - .hasPermission(player, "plots.admin.command.schematic") && !force) { - player.sendMessage( + .format(player, Captions.PERMISSION_CLAIM_SCHEMATIC.getTranslated(), + schematic)) && !Permissions.hasPermission(player, "plots.admin.command.schematic") + && !force) { + player.sendMessage( TranslatableCaption.of("permission.no_schematic_permission"), Template.of("value", schematic) ); @@ -141,7 +146,7 @@ public class Claim extends SubCommand { TranslatableCaption.of("economy.cannot_afford_plot"), Template.of("money", String.valueOf(cost)) ); - } + } this.econHandler.withdrawMoney(player, cost); player.sendMessage( TranslatableCaption.of("economy.removed_balance"), @@ -151,15 +156,16 @@ public class Claim extends SubCommand { } if (grants > 0) { if (grants == 1) { - player.removePersistentMeta("grantedPlots"); - } else { - player.setPersistentMeta("grantedPlots", Ints.toByteArray(grants - 1)); - } - player.sendMessage( + metaDataAccess.remove(); + } else { + metaDataAccess.set(grants - 1); + } + player.sendMessage( TranslatableCaption.of("economy.removed_granted_plot"), Template.of("usedGrants", String.valueOf((grants -1))), Template.of("remainingGrants", String.valueOf(grants)) ); + } } int border = area.getBorder(); if (border != Integer.MAX_VALUE && plot.getDistanceFromOrigin() > border && !force) { diff --git a/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java b/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java index 61cbe1d4b..b809b63d7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java +++ b/Core/src/main/java/com/plotsquared/core/command/CmdConfirm.java @@ -26,19 +26,29 @@ package com.plotsquared.core.command; import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.task.TaskManager; import com.plotsquared.core.util.task.TaskTime; import net.kyori.adventure.text.minimessage.Template; +import javax.annotation.Nullable; + public class CmdConfirm { - public static CmdInstance getPending(PlotPlayer player) { - return player.getMeta("cmdConfirm"); + @Nullable public static CmdInstance getPending(PlotPlayer player) { + try (final MetaDataAccess metaDataAccess = player.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_CONFIRM)) { + return metaDataAccess.get().orElse(null); + } } public static void removePending(PlotPlayer player) { - player.deleteMeta("cmdConfirm"); + try (final MetaDataAccess metaDataAccess = player.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_CONFIRM)) { + metaDataAccess.remove(); + } } public static void addPending(final PlotPlayer player, String commandStr, @@ -52,7 +62,10 @@ public class CmdConfirm { } TaskManager.runTaskLater(() -> { CmdInstance cmd = new CmdInstance(runnable); - player.setMeta("cmdConfirm", cmd); + try (final MetaDataAccess metaDataAccess = player.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_CONFIRM)) { + metaDataAccess.set(cmd); + } }, TaskTime.ticks(1L)); } } diff --git a/Core/src/main/java/com/plotsquared/core/command/Command.java b/Core/src/main/java/com/plotsquared/core/command/Command.java index 16c6cdf78..3f4adbd97 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Command.java +++ b/Core/src/main/java/com/plotsquared/core/command/Command.java @@ -36,6 +36,7 @@ import com.plotsquared.core.util.StringComparison; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.task.RunnableVal2; import com.plotsquared.core.util.task.RunnableVal3; +import com.plotsquared.core.permissions.PermissionHolder; import net.kyori.adventure.text.minimessage.Template; import javax.annotation.Nullable; @@ -159,7 +160,7 @@ public abstract class Command { return this.allCommands; } - public boolean hasConfirmation(CommandCaller player) { + public boolean hasConfirmation(PermissionHolder player) { return this.confirmation && !player.hasPermission(getPermission() + ".confirm.bypass"); } diff --git a/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java b/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java index 4d1047310..fe517fc9a 100644 --- a/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java +++ b/Core/src/main/java/com/plotsquared/core/command/CommandCaller.java @@ -65,6 +65,6 @@ public interface CommandCaller { * * @return Caller type */ - @Nonnull RequiredType getSuperCaller(); + RequiredType getSuperCaller(); } diff --git a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java index 8c9fef529..e7d81b2d7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/DebugExec.java +++ b/Core/src/main/java/com/plotsquared/core/command/DebugExec.java @@ -423,48 +423,6 @@ public class DebugExec extends SubCommand { } }, "/plot debugexec list-scripts", "List of scripts"); return true; - case "allcmd": - if (args.length < 3) { - player.sendMessage( - TranslatableCaption.of("commandconfig.command_syntax"), - Template.of("value", "/plot debugexec allcmd ") - ); - return false; - } - long start = System.currentTimeMillis(); - Command cmd = MainCommand.getInstance().getCommand(args[3]); - String[] params = Arrays.copyOfRange(args, 4, args.length); - if ("true".equals(args[1])) { - Location location = player.getMeta(PlotPlayer.META_LOCATION); - Plot plot = player.getMeta(PlotPlayer.META_LAST_PLOT); - for (Plot current : PlotSquared.get().getBasePlots()) { - player.setMeta(PlotPlayer.META_LOCATION, current.getBottomAbs()); - player.setMeta(PlotPlayer.META_LAST_PLOT, current); - cmd.execute(player, params, null, null); - } - if (location == null) { - player.deleteMeta(PlotPlayer.META_LOCATION); - } else { - player.setMeta(PlotPlayer.META_LOCATION, location); - } - if (plot == null) { - player.deleteMeta(PlotPlayer.META_LAST_PLOT); - } else { - player.setMeta(PlotPlayer.META_LAST_PLOT, plot); - } - player.sendMessage(StaticCaption.of("&c> " + (System.currentTimeMillis() - start))); - return true; - } - init(); - this.scope.put("_2", params); - this.scope.put("_3", cmd); - script = - "_1=PS.getBasePlots().iterator();while(_1.hasNext()){plot=_1.next();if(" - + args[1] - + "){PlotPlayer.setMeta(\"location\",plot.getBottomAbs());PlotPlayer.setMeta(\"lastplot\",plot);_3.onCommand" - + "(PlotPlayer,_2)}}"; - - break; case "all": if (args.length < 3) { player.sendMessage( diff --git a/Core/src/main/java/com/plotsquared/core/command/Grant.java b/Core/src/main/java/com/plotsquared/core/command/Grant.java index 04abe3d07..413f910ea 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Grant.java +++ b/Core/src/main/java/com/plotsquared/core/command/Grant.java @@ -31,6 +31,8 @@ import com.plotsquared.core.configuration.caption.CaptionUtility; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.database.DBFunc; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.Permissions; import com.plotsquared.core.util.PlayerManager; @@ -43,7 +45,6 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; @CommandDeclaration(command = "grant", category = CommandCategory.CLAIMING, @@ -84,44 +85,43 @@ public class Grant extends Command { ); } else { final UUID uuid = uuids.toArray(new UUID[0])[0]; - final Consumer result = array -> { - if (arg0.equals("check")) { // check - int granted; - if (array == null) { - granted = 0; - } else { - granted = Ints.fromByteArray(array); - } - player.sendMessage( - TranslatableCaption.of("grants.granted_plots"), - Template.of("amount", String.valueOf(granted)) - ); - } else { // add - int amount; - if (array == null) { - amount = 1; - } else { - amount = 1 + Ints.fromByteArray(array); - } - boolean replace = array != null; - String key = "grantedPlots"; - byte[] rawData = Ints.toByteArray(amount); - - PlotPlayer online = PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); - if (online != null) { - online.setPersistentMeta(key, rawData); - } else { - DBFunc.addPersistentMeta(uuid, key, rawData, replace); - } - } - }; PlotPlayer pp = PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); if (pp != null) { - result.accept(player.getPersistentMeta("grantedPlots")); + try (final MetaDataAccess access = pp.accessPersistentMetaData( + PlayerMetaDataKeys.PERSISTENT_GRANTED_PLOTS)) { + if (args[0].equalsIgnoreCase("check")) { + Captions.GRANTED_PLOTS.send(player, access.get().orElse(0)); + } else { + access.set(access.get().orElse(0) + 1); + } + } } else { DBFunc.getPersistentMeta(uuid, new RunnableVal>() { @Override public void run(Map value) { - result.accept(value.get("grantedPlots")); + final byte[] array = value.get("grantedPlots"); + if (arg0.equals("check")) { // check + int granted; + if (array == null) { + granted = 0; + } else { + granted = Ints.fromByteArray(array); + } + player.sendMessage( + TranslatableCaption.of("grants.granted_plots"), + Template.of("amount", String.valueOf(granted)) + ); + } else { // add + int amount; + if (array == null) { + amount = 1; + } else { + amount = 1 + Ints.fromByteArray(array); + } + boolean replace = array != null; + String key = "grantedPlots"; + byte[] rawData = Ints.toByteArray(amount); + DBFunc.addPersistentMeta(uuid, key, rawData, replace); + } } }); } diff --git a/Core/src/main/java/com/plotsquared/core/command/Inbox.java b/Core/src/main/java/com/plotsquared/core/command/Inbox.java index ff533f102..3aa8fd9b1 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Inbox.java +++ b/Core/src/main/java/com/plotsquared/core/command/Inbox.java @@ -25,7 +25,9 @@ */ package com.plotsquared.core.command; +import com.google.inject.TypeLiteral; import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.player.PlotPlayer; @@ -35,6 +37,7 @@ import com.plotsquared.core.plot.comment.CommentManager; import com.plotsquared.core.plot.comment.PlotComment; import com.plotsquared.core.util.StringMan; import com.plotsquared.core.util.task.RunnableVal; +import com.plotsquared.core.player.MetaDataKey; import net.kyori.adventure.text.minimessage.Template; import java.util.List; @@ -151,7 +154,10 @@ public class Inbox extends SubCommand { ); return false; } - player.setMeta("inbox:" + inbox.toString(), System.currentTimeMillis()); + final MetaDataKey metaDataKey = MetaDataKey.of(String.format("inbox:%s", inbox.toString()), new TypeLiteral() {}); + try (final MetaDataAccess metaDataAccess = player.accessTemporaryMetaData(metaDataKey)) { + metaDataAccess.set(System.currentTimeMillis()); + } final int page; if (args.length > 1) { switch (args[1].toLowerCase()) { diff --git a/Core/src/main/java/com/plotsquared/core/command/Load.java b/Core/src/main/java/com/plotsquared/core/command/Load.java index c86cbe244..8a98ae072 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Load.java +++ b/Core/src/main/java/com/plotsquared/core/command/Load.java @@ -30,6 +30,8 @@ import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -45,6 +47,7 @@ import net.kyori.adventure.text.minimessage.Template; import javax.annotation.Nonnull; import java.net.MalformedURLException; import java.net.URL; +import java.util.Collections; import java.util.List; @CommandDeclaration(command = "load", @@ -89,48 +92,50 @@ public class Load extends SubCommand { return false; } - if (args.length != 0) { - if (args.length == 1) { - List schematics = player.getMeta("plot_schematics"); - if (schematics == null) { - // No schematics found: - player.sendMessage(TranslatableCaption.of("web.load_null")); - return false; - } - String schematic; - try { - schematic = schematics.get(Integer.parseInt(args[0]) - 1); - } catch (Exception ignored) { - // use /plot load - player.sendMessage( + try (final MetaDataAccess> metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) { + if (args.length != 0) { + if (args.length == 1) { + List schematics = metaDataAccess.get().orElse(null); + if (schematics == null) { + // No schematics found: + player.sendMessage(TranslatableCaption.of("web.load_null")); + return false; + } + String schematic; + try { + schematic = schematics.get(Integer.parseInt(args[0]) - 1); + } catch (Exception ignored) { + // use /plot load + player.sendMessage( TranslatableCaption.of("invalid.not_valid_number"), Template.of("value", "(1, " + schematics.size() + ')') ); - return false; - } - final URL url; - try { - url = new URL(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic); - } catch (MalformedURLException e) { - e.printStackTrace(); - player.sendMessage(TranslatableCaption.of("web.load_failed")); - return false; - } - plot.addRunning(); - player.sendMessage(TranslatableCaption.of("working.generating_component")); - TaskManager.runTaskAsync(() -> { - Schematic taskSchematic = this.schematicHandler.getSchematic(url); - if (taskSchematic == null) { - plot.removeRunning(); - player.sendMessage( + return false; + } + final URL url; + try { + url = new URL(Settings.Web.URL + "saves/" + player.getUUID() + '/' + schematic); + } catch (MalformedURLException e) { + e.printStackTrace(); + player.sendMessage(TranslatableCaption.of("web.load_failed")); + return false; + } + plot.addRunning(); + player.sendMessage(TranslatableCaption.of("working.generating_component")); + TaskManager.runTaskAsync(() -> { + Schematic taskSchematic = this.schematicHandler.getSchematic(url); + if (taskSchematic == null) { + plot.removeRunning(); + player.sendMessage( TranslatableCaption.of("schematics.schematic_invalid"), Template.of("reason", "non-existent or not in gzip format") ); - return; - } - PlotArea area = plot.getArea(); - this.schematicHandler.paste(taskSchematic, plot, 0, area.getMinBuildHeight(), 0, false, - new RunnableVal() { + return; + } + PlotArea area = plot.getArea(); + this.schematicHandler + .paste(taskSchematic, plot, 0, area.getMinBuildHeight(), 0, false, new RunnableVal() { @Override public void run(Boolean value) { plot.removeRunning(); if (value) { @@ -140,60 +145,63 @@ public class Load extends SubCommand { } } }); - }); - return true; - } - plot.removeRunning(); - player.sendMessage( + }); + return true; + } + plot.removeRunning(); + player.sendMessage( TranslatableCaption.of("commandconfig.command_syntax"), Template.of("value", "/plot load ") ); - return false; - } + return false; + } - // list schematics + // list schematics - List schematics = player.getMeta("plot_schematics"); - if (schematics == null) { - plot.addRunning(); - TaskManager.runTaskAsync(() -> { - List schematics1 = this.schematicHandler.getSaves(player.getUUID()); - plot.removeRunning(); - if ((schematics1 == null) || schematics1.isEmpty()) { - player.sendMessage(TranslatableCaption.of("web.load_failed")); - return; - } - player.setMeta("plot_schematics", schematics1); + List schematics = metaDataAccess.get().orElse(null); + if (schematics == null) { + plot.addRunning(); + TaskManager.runTaskAsync(() -> { + List schematics1 = this.schematicHandler.getSaves(player.getUUID()); + plot.removeRunning(); + if ((schematics1 == null) || schematics1.isEmpty()) { + player.sendMessage(TranslatableCaption.of("web.load_failed")); + return; + } + metaDataAccess.set(schematics1); + displaySaves(player); + }); + } else { displaySaves(player); - }); - } else { - displaySaves(player); + } } return true; } public void displaySaves(PlotPlayer player) { - List schematics = player.getMeta("plot_schematics"); - for (int i = 0; i < Math.min(schematics.size(), 32); i++) { - try { - String schematic = schematics.get(i).split("\\.")[0]; - String[] split = schematic.split("_"); - if (split.length < 5) { - continue; - } - String time = - secToTime((System.currentTimeMillis() / 1000) - Long.parseLong(split[0])); - String world = split[1]; - PlotId id = PlotId.fromString(split[2] + ';' + split[3]); - String size = split[4]; - String color = ""; - player.sendMessage(StaticCaption.of("[" + (i + 1) + "] " + color + time + " | " + color + world + ';' + id + try (final MetaDataAccess> metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) { + List schematics = metaDataAccess.get().orElse(Collections.emptyList()); + for (int i = 0; i < Math.min(schematics.size(), 32); i++) { + try { + String schematic = schematics.get(i).split("\\.")[0]; + String[] split = schematic.split("_"); + if (split.length < 5) { + continue; + } + String time = secToTime((System.currentTimeMillis() / 1000) - Long.parseLong(split[0])); + String world = split[1]; + PlotId id = PlotId.fromString(split[2] + ';' + split[3]); + String size = split[4]; + String color = ""; + player.sendMessage(StaticCaption.of("[" + (i + 1) + "] " + color + time + " | " + color + world + ';' + id + " | " + color + size + 'x' + size)); - } catch (Exception e) { - e.printStackTrace(); + } catch (Exception e) { + e.printStackTrace(); + } } + player.sendMessage(TranslatableCaption.of("web.load_list")); } - player.sendMessage(TranslatableCaption.of("web.load_list")); } public String secToTime(long time) { diff --git a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java index 86a2185d6..0f1f457b7 100644 --- a/Core/src/main/java/com/plotsquared/core/command/MainCommand.java +++ b/Core/src/main/java/com/plotsquared/core/command/MainCommand.java @@ -32,6 +32,8 @@ import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.location.Location; import com.plotsquared.core.player.ConsolePlayer; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -231,8 +233,6 @@ public class MainCommand extends Command { public CompletableFuture execute(final PlotPlayer player, String[] args, RunnableVal3 confirm, RunnableVal2 whenDone) { - // Clear perm caching // - player.deleteMeta("perm"); // Optional command scope // Location location = null; Plot plot = null; @@ -247,12 +247,17 @@ public class MainCommand extends Command { Location newLoc = newPlot.getCenterSynchronous(); if (player.canTeleport(newLoc)) { // Save meta - location = player.getMeta(PlotPlayer.META_LOCATION); - plot = player.getMeta(PlotPlayer.META_LAST_PLOT); + try (final MetaDataAccess locationMetaDataAccess + = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + location = locationMetaDataAccess.get().orElse(null); + locationMetaDataAccess.set(newLoc); + } + try (final MetaDataAccess plotMetaDataAccess + = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + plot = plotMetaDataAccess.get().orElse(null); + plotMetaDataAccess.set(newPlot); + } tp = true; - // Set loc - player.setMeta(PlotPlayer.META_LOCATION, newLoc); - player.setMeta(PlotPlayer.META_LAST_PLOT, newPlot); } else { player.sendMessage(TranslatableCaption.of("border.border")); } @@ -306,15 +311,21 @@ public class MainCommand extends Command { } // Reset command scope // if (tp && !(player instanceof ConsolePlayer)) { - if (location == null) { - player.deleteMeta(PlotPlayer.META_LOCATION); - } else { - player.setMeta(PlotPlayer.META_LOCATION, location); + try (final MetaDataAccess locationMetaDataAccess + = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + if (location == null) { + locationMetaDataAccess.remove(); + } else { + locationMetaDataAccess.set(location); + } } - if (plot == null) { - player.deleteMeta(PlotPlayer.META_LAST_PLOT); - } else { - player.setMeta(PlotPlayer.META_LAST_PLOT, plot); + try (final MetaDataAccess plotMetaDataAccess + = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + if (plot == null) { + plotMetaDataAccess.remove(); + } else { + plotMetaDataAccess.set(plot); + } } } return CompletableFuture.completedFuture(true); diff --git a/Core/src/main/java/com/plotsquared/core/command/Save.java b/Core/src/main/java/com/plotsquared/core/command/Save.java index a898d2570..080118bb9 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Save.java +++ b/Core/src/main/java/com/plotsquared/core/command/Save.java @@ -29,6 +29,8 @@ import com.google.inject.Inject; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotId; @@ -105,9 +107,9 @@ public class Save extends SubCommand { return; } player.sendMessage(TranslatableCaption.of("web.save_success")); - List schematics = player.getMeta("plot_schematics"); - if (schematics != null) { - schematics.add(file + ".schem"); + try (final MetaDataAccess> schematicAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SCHEMATICS)) { + schematicAccess.get().ifPresent(schematics -> schematics.add(file + ".schem")); } } }); diff --git a/Core/src/main/java/com/plotsquared/core/command/Setup.java b/Core/src/main/java/com/plotsquared/core/command/Setup.java index 68c9be4a1..95911468b 100644 --- a/Core/src/main/java/com/plotsquared/core/command/Setup.java +++ b/Core/src/main/java/com/plotsquared/core/command/Setup.java @@ -31,6 +31,8 @@ import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.generator.GeneratorWrapper; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.setup.SetupProcess; import com.plotsquared.core.setup.SetupStep; @@ -74,10 +76,12 @@ public class Setup extends SubCommand { } @Override public boolean onCommand(PlotPlayer player, String[] args) { - SetupProcess process = player.getMeta("setup"); - if (process == null) { - if (args.length > 0) { - player.sendMessage(TranslatableCaption.of("setup.setup_not_started")); + try (final MetaDataAccess metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SETUP)) { + SetupProcess process = metaDataAccess.get().orElse(null); + if (process == null) { + if (args.length > 0) { + player.sendMessage(TranslatableCaption.of("setup.setup_not_started")); player.sendMessage( TranslatableCaption.of("commandconfig.command_syntax"), Template.of("value", "Use /plot setup to start a setup process.") @@ -85,35 +89,39 @@ public class Setup extends SubCommand { return true; } process = new SetupProcess(); - player.setMeta("setup", process); - this.setupUtils.updateGenerators(); - SetupStep step = process.getCurrentStep(); - step.announce(player); - displayGenerators(player); + metaDataAccess.set(process); + this.setupUtils.updateGenerators(); + SetupStep step = process.getCurrentStep(); + step.announce(player); + displayGenerators(player); + return true; + } + if (args.length == 1) { + if ("back".equalsIgnoreCase(args[0])) { + process.back(); + process.getCurrentStep().announce(player); + } else if ("cancel".equalsIgnoreCase(args[0])) { + metaDataAccess.remove(); + player.sendMessage(TranslatableCaption.of("setup.setup_cancelled")); + } else { + process.handleInput(player, args[0]); + if (process.getCurrentStep() != null) { + process.getCurrentStep().announce(player); + } + } + } else { + process.getCurrentStep().announce(player); + } return true; } - if (args.length == 1) { - if ("back".equalsIgnoreCase(args[0])) { - process.back(); - process.getCurrentStep().announce(player); - } else if ("cancel".equalsIgnoreCase(args[0])) { - player.deleteMeta("setup"); - player.sendMessage(TranslatableCaption.of("setup.setup_cancelled")); - } else { - process.handleInput(player, args[0]); - if (process.getCurrentStep() != null) { - process.getCurrentStep().announce(player); - } - } - } else { - process.getCurrentStep().announce(player); - } - return true; - } @Override public Collection tab(PlotPlayer player, String[] args, boolean space) { - SetupProcess process = (SetupProcess) player.getMeta("setup"); // TODO use generics -> auto cast + SetupProcess process; + try (final MetaDataAccess metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_SETUP)) { + process = metaDataAccess.get().orElse(null); + } if (process == null) { return Collections.emptyList(); } diff --git a/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java b/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java index c417fa927..2f61759c9 100644 --- a/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java +++ b/Core/src/main/java/com/plotsquared/core/listener/PlotListener.java @@ -26,7 +26,6 @@ package com.plotsquared.core.listener; import com.plotsquared.core.PlotSquared; -import com.plotsquared.core.collection.ByteArrayUtilities; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.Templates; @@ -34,6 +33,9 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.events.PlotFlagRemoveEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.MetaDataKey; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -72,6 +74,7 @@ import javax.annotation.Nullable; import java.util.HashMap; import java.util.Iterator; import java.util.Map; +import java.util.Optional; import java.util.UUID; public class PlotListener { @@ -95,7 +98,7 @@ public class PlotListener { ++value.count; if (value.count == value.interval) { value.count = 0; - PlotPlayer player = PlotPlayer.wrap(entry.getKey()); + final PlotPlayer player = PlotSquared.platform().getPlayerManager().getPlayerIfExists(entry.getKey()); if (player == null) { iterator.remove(); continue; @@ -115,7 +118,7 @@ public class PlotListener { ++value.count; if (value.count == value.interval) { value.count = 0; - PlotPlayer player = PlotSquared.platform().getWorldUtil().getPlayer(entry.getKey()); + final PlotPlayer player = PlotSquared.platform().getPlayerManager().getPlayerIfExists(entry.getKey()); if (player == null) { iterator.remove(); continue; @@ -135,14 +138,16 @@ public class PlotListener { .hasPermission(player, "plots.admin.entry.denied")) { return false; } - Plot last = player.getMeta(PlotPlayer.META_LAST_PLOT); - if ((last != null) && !last.getId().equals(plot.getId())) { - plotExit(player, last); + try (final MetaDataAccess lastPlot = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + Plot last = lastPlot.get().orElse(null); + if ((last != null) && !last.getId().equals(plot.getId())) { + plotExit(player, last); + } + if (ExpireManager.IMP != null) { + ExpireManager.IMP.handleEntry(player, plot); + } + lastPlot.set(plot); } - if (ExpireManager.IMP != null) { - ExpireManager.IMP.handleEntry(player, plot); - } - player.setMeta(PlotPlayer.META_LAST_PLOT, plot); this.eventDispatcher.callEntry(player, plot); if (plot.hasOwner()) { // This will inherit values from PlotArea @@ -180,8 +185,9 @@ public class PlotListener { boolean flight = player.getFlight(); GameMode gamemode = player.getGameMode(); if (flight != (gamemode == GameModes.CREATIVE || gamemode == GameModes.SPECTATOR)) { - player.setPersistentMeta("flight", - ByteArrayUtilities.booleanToBytes(player.getFlight())); + try (final MetaDataAccess metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_FLIGHT)) { + metaDataAccess.set(player.getFlight()); + } } player.setFlight(flyStatus == FlyFlag.FlyStatus.ENABLED); } @@ -234,39 +240,47 @@ public class PlotListener { player.setWeather(plot.getFlag(WeatherFlag.class)); ItemType musicFlag = plot.getFlag(MusicFlag.class); - if (musicFlag != null) { - final String rawId = musicFlag.getId(); - if (rawId.contains("disc") || musicFlag == ItemTypes.AIR) { - Location location = player.getLocation(); - Location lastLocation = player.getMeta("music"); - if (lastLocation != null) { - player.playMusic(lastLocation, musicFlag); - if (musicFlag == ItemTypes.AIR) { - player.deleteMeta("music"); + + try (final MetaDataAccess musicMeta = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_MUSIC)) { + if (musicFlag != null) { + final String rawId = musicFlag.getId(); + if (rawId.contains("disc") || musicFlag == ItemTypes.AIR) { + Location location = player.getLocation(); + Location lastLocation = musicMeta.get().orElse(null); + if (lastLocation != null) { + player.playMusic(lastLocation, musicFlag); + if (musicFlag == ItemTypes.AIR) { + musicMeta.remove(); + } + } + if (musicFlag != ItemTypes.AIR) { + try { + musicMeta.set(location); + player.playMusic(location, musicFlag); + } catch (Exception ignored) { + } } } - if (musicFlag != ItemTypes.AIR) { - try { - player.setMeta("music", location); - player.playMusic(location, musicFlag); - } catch (Exception ignored) { - } - } - } - } else { - Location lastLoc = player.getMeta("music"); - if (lastLoc != null) { - player.deleteMeta("music"); - player.playMusic(lastLoc, ItemTypes.AIR); + } else { + musicMeta.get().ifPresent(lastLoc -> { + musicMeta.remove(); + player.playMusic(lastLoc, ItemTypes.AIR); + }); } } + CommentManager.sendTitle(player, plot); if (titles && !player.getAttribute("disabletitles")) { if (!Captions.TITLE_ENTERED_PLOT.getTranslated().isEmpty() || !Captions.TITLE_ENTERED_PLOT_SUB.getTranslated().isEmpty()) { TaskManager.runTaskLaterAsync(() -> { - Plot lastPlot = player.getMeta(PlotPlayer.META_LAST_PLOT); + Plot lastPlot = null; + try (final MetaDataAccess lastPlotAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + lastPlot = lastPlotAccess.get().orElse(null); + } if ((lastPlot != null) && plot.getId().equals(lastPlot.getId())) { player.sendTitle( TranslatableCaption.of("titles.title_entered_plot"), @@ -299,48 +313,52 @@ public class PlotListener { } public boolean plotExit(final PlotPlayer player, Plot plot) { - Object previous = player.deleteMeta(PlotPlayer.META_LAST_PLOT); - this.eventDispatcher.callLeave(player, plot); - if (plot.hasOwner()) { - PlotArea pw = plot.getArea(); - if (pw == null) { - return true; - } - if (plot.getFlag(DenyExitFlag.class) && !Permissions - .hasPermission(player, Captions.PERMISSION_ADMIN_EXIT_DENIED) && !player - .getMeta("kick", false)) { - if (previous != null) { - player.setMeta(PlotPlayer.META_LAST_PLOT, previous); + try (final MetaDataAccess lastPlot = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + final Plot previous = lastPlot.remove(); + this.eventDispatcher.callLeave(player, plot); + if (plot.hasOwner()) { + PlotArea pw = plot.getArea(); + if (pw == null) { + return true; } - return false; - } - if (!plot.getFlag(GamemodeFlag.class).equals(GamemodeFlag.DEFAULT) || !plot - .getFlag(GuestGamemodeFlag.class).equals(GamemodeFlag.DEFAULT)) { - if (player.getGameMode() != pw.getGameMode()) { - if (!Permissions.hasPermission(player, "plots.gamemode.bypass")) { - player.setGameMode(pw.getGameMode()); - } else { - player.sendMessage( - TranslatableCaption.of("gamemode.gamemode_was_bypassed"), - Template.of("gamemode", pw.getGameMode().getName().toLowerCase()), + try (final MetaDataAccess kickAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_KICK)) { + if (plot.getFlag(DenyExitFlag.class) && !Permissions + .hasPermission(player, Captions.PERMISSION_ADMIN_EXIT_DENIED) && + !kickAccess.get().orElse(false)) { + if (previous != null) { + lastPlot.set(previous); + } + return false; + } + } + if (!plot.getFlag(GamemodeFlag.class).equals(GamemodeFlag.DEFAULT) || !plot + .getFlag(GuestGamemodeFlag.class).equals(GamemodeFlag.DEFAULT)) { + if (player.getGameMode() != pw.getGameMode()) { + if (!Permissions.hasPermission(player, "plots.gamemode.bypass")) { + player.setGameMode(pw.getGameMode()); + } else { + player.sendMessage( + TranslatableCaption.of("gamemode.gamemode_was_bypassed"), + Template.of("gamemode", pw.getGameMode().getName().toLowerCase()), Template.of("plot", plot.toString()) ); } } } - final String farewell = plot.getFlag(FarewellFlag.class); - if (!farewell.isEmpty()) { - plot.format(Captions.PREFIX_FAREWELL.getTranslated() + farewell, player, false) - .thenAcceptAsync(player::sendMessage); - } + final String farewell = plot.getFlag(FarewellFlag.class); + if (!farewell.isEmpty()) { + plot.format(Captions.PREFIX_FAREWELL.getTranslated() + farewell, player, false) + .thenAcceptAsync(player::sendMessage); + } - if (plot.getFlag(NotifyLeaveFlag.class)) { - if (!Permissions.hasPermission(player, "plots.flag.notify-enter.bypass")) { - for (UUID uuid : plot.getOwners()) { - final PlotPlayer owner = PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); - if ((owner != null) && !owner.getUUID().equals(player.getUUID())) { - player.sendMessage( + if (plot.getFlag(NotifyLeaveFlag.class)) { + if (!Permissions.hasPermission(player, "plots.flag.notify-enter.bypass")) { + for (UUID uuid : plot.getOwners()) { + final PlotPlayer owner = PlotSquared.platform().getPlayerManager().getPlayerIfExists(uuid); + if ((owner != null) && !owner.getUUID().equals(player.getUUID())) { + player.sendMessage( TranslatableCaption.of("notification.notify_leave"), Template.of("player", player.getName()), Template.of("plot", plot.getId().toString()) @@ -350,39 +368,44 @@ public class PlotListener { } } - final FlyFlag.FlyStatus flyStatus = plot.getFlag(FlyFlag.class); - if (flyStatus != FlyFlag.FlyStatus.DEFAULT) { - if (player.hasPersistentMeta("flight")) { - player.setFlight( - ByteArrayUtilities.bytesToBoolean(player.getPersistentMeta("flight"))); - player.removePersistentMeta("flight"); - } else { - GameMode gameMode = player.getGameMode(); - if (gameMode == GameModes.SURVIVAL || gameMode == GameModes.ADVENTURE) { - player.setFlight(false); - } else if (!player.getFlight()) { - player.setFlight(true); + final FlyFlag.FlyStatus flyStatus = plot.getFlag(FlyFlag.class); + if (flyStatus != FlyFlag.FlyStatus.DEFAULT) { + try (final MetaDataAccess metaDataAccess = player.accessPersistentMetaData(PlayerMetaDataKeys.PERSISTENT_FLIGHT)) { + final Optional value = metaDataAccess.get(); + if (value.isPresent()) { + player.setFlight(value.get()); + metaDataAccess.remove(); + } else { + GameMode gameMode = player.getGameMode(); + if (gameMode == GameModes.SURVIVAL || gameMode == GameModes.ADVENTURE) { + player.setFlight(false); + } else if (!player.getFlight()) { + player.setFlight(true); + } + } } } - } - if (plot.getFlag(TimeFlag.class) != TimeFlag.TIME_DISABLED.getValue().longValue()) { - player.setTime(Long.MAX_VALUE); - } + if (plot.getFlag(TimeFlag.class) != TimeFlag.TIME_DISABLED.getValue().longValue()) { + player.setTime(Long.MAX_VALUE); + } - final PlotWeather plotWeather = plot.getFlag(WeatherFlag.class); - if (plotWeather != PlotWeather.CLEAR) { - player.setWeather(PlotWeather.RESET); - } + final PlotWeather plotWeather = plot.getFlag(WeatherFlag.class); + if (plotWeather != PlotWeather.CLEAR) { + player.setWeather(PlotWeather.RESET); + } - Location lastLoc = player.getMeta("music"); - if (lastLoc != null) { - player.deleteMeta("music"); - player.playMusic(lastLoc, ItemTypes.AIR); - } + try (final MetaDataAccess musicAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_MUSIC)) { + musicAccess.get().ifPresent(lastLoc -> { + musicAccess.remove(); + player.playMusic(lastLoc, ItemTypes.AIR); + }); + } - feedRunnable.remove(player.getUUID()); - healRunnable.remove(player.getUUID()); + feedRunnable.remove(player.getUUID()); + healRunnable.remove(player.getUUID()); + } } return true; } diff --git a/Core/src/main/java/com/plotsquared/core/listener/WESubscriber.java b/Core/src/main/java/com/plotsquared/core/listener/WESubscriber.java index cdc72a030..25da1995d 100644 --- a/Core/src/main/java/com/plotsquared/core/listener/WESubscriber.java +++ b/Core/src/main/java/com/plotsquared/core/listener/WESubscriber.java @@ -26,6 +26,7 @@ package com.plotsquared.core.listener; import com.google.inject.Inject; +import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; @@ -72,7 +73,7 @@ public class WESubscriber { Actor actor = event.getActor(); if (actor != null && actor.isPlayer()) { String name = actor.getName(); - PlotPlayer plotPlayer = PlotPlayer.wrap(name); + final PlotPlayer plotPlayer = PlotSquared.platform().getPlayerManager().getPlayerIfExists(name); Set mask; if (plotPlayer == null) { Player player = (Player) actor; diff --git a/Core/src/main/java/com/plotsquared/core/permissions/ConsolePermissionProfile.java b/Core/src/main/java/com/plotsquared/core/permissions/ConsolePermissionProfile.java new file mode 100644 index 000000000..783f605a7 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/permissions/ConsolePermissionProfile.java @@ -0,0 +1,39 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.permissions; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public enum ConsolePermissionProfile implements PermissionProfile { + INSTANCE; + + @Override public boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + return true; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/PermHandler.java b/Core/src/main/java/com/plotsquared/core/permissions/NullPermissionProfile.java similarity index 78% rename from Core/src/main/java/com/plotsquared/core/util/PermHandler.java rename to Core/src/main/java/com/plotsquared/core/permissions/NullPermissionProfile.java index 1dec45fd4..fbf7d8a03 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PermHandler.java +++ b/Core/src/main/java/com/plotsquared/core/permissions/NullPermissionProfile.java @@ -23,15 +23,17 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ -package com.plotsquared.core.util; +package com.plotsquared.core.permissions; -public abstract class PermHandler { +import javax.annotation.Nonnull; +import javax.annotation.Nullable; - public abstract boolean init(); +public enum NullPermissionProfile implements PermissionProfile { + INSTANCE; - public abstract boolean hasPermission(String world, String player, String perm); - - public boolean hasPermission(String player, String perm) { - return hasPermission(null, player, perm); + @Override public boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + return false; } + } diff --git a/Core/src/main/java/com/plotsquared/core/permissions/PermissionHandler.java b/Core/src/main/java/com/plotsquared/core/permissions/PermissionHandler.java new file mode 100644 index 000000000..4a273c743 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/permissions/PermissionHandler.java @@ -0,0 +1,99 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.permissions; + +import com.plotsquared.core.player.OfflinePlotPlayer; +import com.plotsquared.core.player.PlotPlayer; + +import javax.annotation.Nonnull; +import java.util.Optional; +import java.util.Set; + +/** + * Permission handler + */ +public interface PermissionHandler { + + /** + * Initialize the permission handler + */ + void initialize(); + + /** + * Attempt to construct a permission profile for a plot player + * + * @param playerPlotPlayer Plot player + * @return Permission profile, if one was able to be constructed + */ + @Nonnull Optional getPermissionProfile( + @Nonnull PlotPlayer playerPlotPlayer); + + /** + * Attempt to construct a permission profile for an offline plot player + * + * @param offlinePlotPlayer Offline player + * @return Permission profile, if one was able to be constructed + */ + @Nonnull Optional getPermissionProfile( + @Nonnull OfflinePlotPlayer offlinePlotPlayer); + + /** + * Get all capabilities that the permission handler has + * + * @return Immutable set of capabilities + */ + @Nonnull Set getCapabilities(); + + /** + * Check whether or not the permission handler has a given capability + * + * @param capability Capability + * @return {@code true} if the handler has the capability, else {@code false} + */ + default boolean hasCapability(@Nonnull final PermissionHandlerCapability capability) { + return this.getCapabilities().contains(capability); + } + + + /** + * Permission handler capabilities + */ + enum PermissionHandlerCapability { + /** + * The ability to check for online (player) permissions + */ + ONLINE_PERMISSIONS, + /** + * The ability to check for offline (player) permissions + */ + OFFLINE_PERMISSIONS, + /** + * Per world permissions + */ + PER_WORLD_PERMISSIONS + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/permissions/PermissionHolder.java b/Core/src/main/java/com/plotsquared/core/permissions/PermissionHolder.java new file mode 100644 index 000000000..7f42c24f0 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/permissions/PermissionHolder.java @@ -0,0 +1,94 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.permissions; + +import com.plotsquared.core.configuration.Captions; +import com.plotsquared.core.configuration.Settings; + +import javax.annotation.Nonnegative; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Any object which can hold permissions + */ +public interface PermissionHolder { + + /** + * Check if the owner of the profile has a given (global) permission + * + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} + */ + default boolean hasPermission(@Nonnull final String permission) { + return hasPermission(null ,permission); + } + + /** + * Check the the highest permission a PlotPlayer has within a specified range.
+ * - Excessively high values will lag
+ * - The default range that is checked is {@link Settings.Limit#MAX_PLOTS}
+ * + * @param stub The permission stub to check e.g. for `plots.plot.#` the stub is `plots.plot` + * @param range The range to check + * @return The highest permission they have within that range + */ + @Nonnegative default int hasPermissionRange(@Nonnull final String stub, + @Nonnegative final int range) { + if (hasPermission(Captions.PERMISSION_ADMIN.getTranslated())) { + return Integer.MAX_VALUE; + } + String[] nodes = stub.split("\\."); + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < (nodes.length - 1); i++) { + builder.append(nodes[i]).append("."); + if (!stub.equals(builder + Captions.PERMISSION_STAR.getTranslated())) { + if (hasPermission(builder + Captions.PERMISSION_STAR.getTranslated())) { + return Integer.MAX_VALUE; + } + } + } + if (hasPermission(stub + ".*")) { + return Integer.MAX_VALUE; + } + for (int i = range; i > 0; i--) { + if (hasPermission(stub + "." + i)) { + return i; + } + } + return 0; + } + + /** + * Check if the owner of the profile has a given permission + * + * @param world World name + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} + */ + boolean hasPermission(@Nullable String world, @Nonnull String permission); + +} diff --git a/Core/src/main/java/com/plotsquared/core/permissions/PermissionProfile.java b/Core/src/main/java/com/plotsquared/core/permissions/PermissionProfile.java new file mode 100644 index 000000000..b7aad8e63 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/permissions/PermissionProfile.java @@ -0,0 +1,55 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.permissions; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * A permission profile that can be used to check for permissions + */ +public interface PermissionProfile { + + /** + * Check if the owner of the profile has a given (global) permission + * + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} + */ + default boolean hasPermission(@Nonnull final String permission) { + return hasPermission(null ,permission); + } + + /** + * Check if the owner of the profile has a given permission + * + * @param world World name + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} + */ + boolean hasPermission(@Nullable final String world, @Nonnull String permission); + +} diff --git a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java index 187068e33..5edf2d0ef 100644 --- a/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/ConsolePlayer.java @@ -35,6 +35,8 @@ import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.inject.annotations.ConsoleActor; import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.PermissionHandler; +import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotWeather; import com.plotsquared.core.plot.world.PlotAreaManager; @@ -68,9 +70,11 @@ public class ConsolePlayer extends PlotPlayer { @Inject private ConsolePlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, @ConsoleActor @Nonnull final Actor actor, - @Nullable final EconHandler econHandler) { - super(plotAreaManager, eventDispatcher, econHandler); + @Nullable final EconHandler econHandler, + @Nonnull final PermissionHandler permissionHandler) { + super(plotAreaManager, eventDispatcher, econHandler, permissionHandler); this.actor = actor; + this.setupPermissionProfile(); final PlotArea[] areas = plotAreaManager.getAllPlotAreas(); final PlotArea area; if (areas.length > 0) { @@ -128,7 +132,7 @@ public class ConsolePlayer extends PlotPlayer { } @Override public long getLastPlayed() { - return 0; + return System.currentTimeMillis(); } @Override public boolean hasPermission(@Nonnull String permission) { @@ -157,12 +161,16 @@ public class ConsolePlayer extends PlotPlayer { } @Override public void teleport(Location location, TeleportCause cause) { - setMeta(META_LAST_PLOT, location.getPlot()); - setMeta(META_LOCATION, location); - } - - @Override public boolean isOnline() { - return true; + try (final MetaDataAccess lastPlot = accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + if (location.getPlot() == null) { + lastPlot.remove(); + } else { + lastPlot.set(location.getPlot()); + } + } + try (final MetaDataAccess locationMetaDataAccess = accessPersistentMetaData(PlayerMetaDataKeys.TEMPORARY_LOCATION)) { + locationMetaDataAccess.set(location); + } } @Override public String getName() { diff --git a/Core/src/main/java/com/plotsquared/core/player/MetaDataAccess.java b/Core/src/main/java/com/plotsquared/core/player/MetaDataAccess.java new file mode 100644 index 000000000..800f1c080 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/player/MetaDataAccess.java @@ -0,0 +1,129 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.player; + +import com.plotsquared.core.synchronization.LockRepository; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Optional; + +/** + * Access to player meta data + * + * @param Meta data type + */ +public abstract class MetaDataAccess implements AutoCloseable { + + private final PlotPlayer player; + private final MetaDataKey metaDataKey; + private final LockRepository.LockAccess lockAccess; + private boolean closed = false; + + MetaDataAccess(@Nonnull final PlotPlayer player, @Nonnull final MetaDataKey metaDataKey, + @Nonnull final LockRepository.LockAccess lockAccess) { + this.player = player; + this.metaDataKey = metaDataKey; + this.lockAccess = lockAccess; + } + + /** + * Check if the player has meta data stored with the given key + * + * @return {@code true} if player has meta data with this key, or + * {@code false} + */ + public abstract boolean isPresent(); + + /** + * Remove the stored value meta data + * + * @return Old value, or {@code null} + */ + @Nullable public abstract T remove(); + + /** + * Set the meta data value + * + * @param value New value + */ + public abstract void set(@Nonnull final T value); + + /** + * Get the stored meta data value + * + * @return Stored value, or {@link Optional#empty()} + */ + @Nonnull public abstract Optional get(); + + @Override public final void close() { + this.lockAccess.close(); + this.closed = true; + } + + /** + * Get the owner of the meta data + * + * @return Player + */ + @Nonnull public PlotPlayer getPlayer() { + return this.player; + } + + /** + * Get the meta data key + * + * @return Meta data key + */ + @Nonnull public MetaDataKey getMetaDataKey() { + return this.metaDataKey; + } + + /** + * Check whether or not the meta data access has been closed. + * After being closed, all attempts to access the meta data + * through the instance, will lead to {@link IllegalAccessException} + * being thrown + * + * @return {@code true} if the access has been closed + */ + public boolean isClosed() { + return this.closed; + } + + protected void checkClosed() { + if (this.closed) { + sneakyThrow(new IllegalAccessException("The meta data access instance has been closed")); + } + } + + @SuppressWarnings("ALL") + private static void sneakyThrow(final Throwable e) throws E { + throw (E) e; + } + + +} diff --git a/Core/src/main/java/com/plotsquared/core/player/MetaDataKey.java b/Core/src/main/java/com/plotsquared/core/player/MetaDataKey.java new file mode 100644 index 000000000..ab013e9c9 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/player/MetaDataKey.java @@ -0,0 +1,108 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.player; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.inject.TypeLiteral; +import com.plotsquared.core.synchronization.LockKey; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; + +/** + * Key used to access meta data + * + * @param Meta data type + */ +public final class MetaDataKey { + + private static final Map keyMap = new HashMap<>(); + private static final Object keyMetaData = new Object(); + + private final String key; + private final TypeLiteral type; + private final LockKey lockKey; + + private MetaDataKey(@Nonnull final String key, @Nonnull final TypeLiteral type) { + this.key = Preconditions.checkNotNull(key, "Key may not be null"); + this.type = Preconditions.checkNotNull(type, "Type may not be null"); + this.lockKey = LockKey.of(this.key); + } + + /** + * Get a new named lock key + * + * @param key Key name + * @param Type + * @return MetaData key instance + */ + @Nonnull public static MetaDataKey of(@Nonnull final String key, @Nonnull final TypeLiteral type) { + synchronized (keyMetaData) { + return (MetaDataKey) + keyMap.computeIfAbsent(key, missingKey -> new MetaDataKey<>(missingKey, type)); + } + } + + @Override public String toString() { + return this.key; + } + + @Override public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final MetaDataKey lockKey = (MetaDataKey) o; + return Objects.equal(this.key, lockKey.key); + } + + @Override public int hashCode() { + return Objects.hashCode(this.key); + } + + /** + * Get the {@link LockKey} associated with this key + * + * @return Lock key + */ + @Nonnull public LockKey getLockKey() { + return this.lockKey; + } + + /** + * Get the meta data type + * + * @return Meta data type + */ + @Nonnull public TypeLiteral getType() { + return this.type; + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/player/OfflinePlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/OfflinePlotPlayer.java index f48079f67..24d83514a 100644 --- a/Core/src/main/java/com/plotsquared/core/player/OfflinePlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/OfflinePlotPlayer.java @@ -25,9 +25,12 @@ */ package com.plotsquared.core.player; +import com.plotsquared.core.permissions.PermissionHolder; + +import javax.annotation.Nonnegative; import java.util.UUID; -public interface OfflinePlotPlayer { +public interface OfflinePlotPlayer extends PermissionHolder { /** * Gets the {@code UUID} of this player @@ -40,16 +43,8 @@ public interface OfflinePlotPlayer { * Gets the time in milliseconds when the player was last seen online. * * @return the time in milliseconds when last online - * @deprecated This method may be inconsistent across platforms. The javadoc may be wrong depending on which platform is used. */ - @SuppressWarnings("DeprecatedIsStillUsed") @Deprecated long getLastPlayed(); - - /** - * Checks if this player is online. - * - * @return {@code true} if this player is online - */ - boolean isOnline(); + @Nonnegative long getLastPlayed(); /** * Gets the name of this player. @@ -57,4 +52,5 @@ public interface OfflinePlotPlayer { * @return the player name */ String getName(); + } diff --git a/Core/src/main/java/com/plotsquared/core/player/PersistentMetaDataAccess.java b/Core/src/main/java/com/plotsquared/core/player/PersistentMetaDataAccess.java new file mode 100644 index 000000000..1e3767c7d --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/player/PersistentMetaDataAccess.java @@ -0,0 +1,66 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.player; + +import com.plotsquared.core.synchronization.LockRepository; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Optional; + +final class PersistentMetaDataAccess extends MetaDataAccess { + + PersistentMetaDataAccess(@Nonnull final PlotPlayer player, + @Nonnull final MetaDataKey metaDataKey, + @Nonnull final LockRepository.LockAccess lockAccess) { + super(player, metaDataKey, lockAccess); + } + + @Override public boolean isPresent() { + this.checkClosed(); + return this.getPlayer().hasPersistentMeta(getMetaDataKey().toString()); + } + + @Override @Nullable public T remove() { + this.checkClosed(); + final Object old = this.getPlayer().removePersistentMeta(this.getMetaDataKey().toString()); + if (old == null) { + return null; + } + return (T) old; + } + + @Override public void set(@Nonnull T value) { + this.checkClosed(); + this.getPlayer().setPersistentMeta(this.getMetaDataKey(), value); + } + + @Nonnull @Override public Optional get() { + this.checkClosed(); + return Optional.ofNullable(this.getPlayer().getPersistentMeta(this.getMetaDataKey())); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/player/PlayerMetaDataKeys.java b/Core/src/main/java/com/plotsquared/core/player/PlayerMetaDataKeys.java new file mode 100644 index 000000000..f936d17a1 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/player/PlayerMetaDataKeys.java @@ -0,0 +1,64 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.player; + +import com.google.inject.TypeLiteral; +import com.plotsquared.core.command.Auto; +import com.plotsquared.core.command.CmdInstance; +import com.plotsquared.core.location.Location; +import com.plotsquared.core.plot.Plot; +import com.plotsquared.core.plot.PlotInventory; +import com.plotsquared.core.setup.SetupProcess; + +import java.util.List; + +public final class PlayerMetaDataKeys { + + //@formatter:off + public static final MetaDataKey PERSISTENT_FLIGHT = MetaDataKey.of("flight", new TypeLiteral() {}); + public static final MetaDataKey PERSISTENT_GRANTED_PLOTS = MetaDataKey.of("grantedPlots", new TypeLiteral() {}); + + public static final MetaDataKey TEMPORARY_LAST_PLOT = MetaDataKey.of("lastplot", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_MUSIC = MetaDataKey.of("music", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_KICK = MetaDataKey.of("kick", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_SETUP = MetaDataKey.of("setup", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_INVENTORY = MetaDataKey.of("inventory", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_IGNORE_EXPIRE_TASK = MetaDataKey.of("ignoreExpireTask", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_WORLD_EDIT_REGION_PLOT = MetaDataKey.of("WorldEditRegionPlot", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_AUTO = MetaDataKey.of(Auto.class.getName(), new TypeLiteral() {}); + public static final MetaDataKey> TEMPORARY_SCHEMATICS = MetaDataKey.of("plot_schematics", new TypeLiteral>() {}); + public static final MetaDataKey TEMPORARY_LOCATION = MetaDataKey.of("location", new TypeLiteral() {}); + public static final MetaDataKey TEMPORARY_CONFIRM = MetaDataKey.of("cmdConfirm", new TypeLiteral() {}); + //@formatter:on + + public static void load() { + // Do nothing :D + } + + private PlayerMetaDataKeys() { + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java index a10c878cf..7aa5320bf 100644 --- a/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java +++ b/Core/src/main/java/com/plotsquared/core/player/PlotPlayer.java @@ -27,7 +27,9 @@ package com.plotsquared.core.player; import com.google.common.base.Objects; import com.google.common.base.Preconditions; +import com.google.common.primitives.Ints; import com.plotsquared.core.PlotSquared; +import com.plotsquared.core.collection.ByteArrayUtilities; import com.plotsquared.core.command.CommandCaller; import com.plotsquared.core.command.RequiredType; import com.plotsquared.core.configuration.caption.Caption; @@ -41,6 +43,9 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.location.Location; +import com.plotsquared.core.permissions.NullPermissionProfile; +import com.plotsquared.core.permissions.PermissionHandler; +import com.plotsquared.core.permissions.PermissionProfile; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotCluster; @@ -51,6 +56,7 @@ import com.plotsquared.core.plot.flag.implementations.DoneFlag; import com.plotsquared.core.plot.world.PlotAreaManager; import com.plotsquared.core.plot.world.SinglePlotArea; import com.plotsquared.core.plot.world.SinglePlotAreaManager; +import com.plotsquared.core.synchronization.LockRepository; import com.plotsquared.core.util.EconHandler; import com.plotsquared.core.util.EventDispatcher; import com.plotsquared.core.util.Permissions; @@ -97,9 +103,6 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, private static final Logger logger = LoggerFactory.getLogger("P2/" + PlotPlayer.class.getSimpleName()); - public static final String META_LAST_PLOT = "lastplot"; - public static final String META_LOCATION = "location"; - // Used to track debug mode private static final Set> debugModeEnabled = Collections.synchronizedSet(new HashSet<>()); @@ -113,14 +116,26 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, private int hash; private Locale locale; + private final LockRepository lockRepository = new LockRepository(); + private final PlotAreaManager plotAreaManager; private final EventDispatcher eventDispatcher; private final EconHandler econHandler; + private final PermissionHandler permissionHandler; + // Delayed initialisation + private PermissionProfile permissionProfile; - public PlotPlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, @Nullable final EconHandler econHandler) { + public PlotPlayer(@Nonnull final PlotAreaManager plotAreaManager, @Nonnull final EventDispatcher eventDispatcher, @Nullable final EconHandler econHandler, + @Nonnull final PermissionHandler permissionHandler) { this.plotAreaManager = plotAreaManager; this.eventDispatcher = eventDispatcher; this.econHandler = econHandler; + this.permissionHandler = permissionHandler; + } + + protected void setupPermissionProfile() { + this.permissionProfile = permissionHandler.getPermissionProfile(this).orElse( + NullPermissionProfile.INSTANCE); } public static PlotPlayer from(@Nonnull final T object) { @@ -154,18 +169,9 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, return players; } - /** - * Efficiently wrap a Player, or OfflinePlayer object to get a PlotPlayer (or fetch if it's already cached)
- * - Accepts sponge/bukkit Player (online) - * - Accepts player name (online) - * - Accepts UUID - * - Accepts bukkit OfflinePlayer (offline) - * - * @param player Player object to wrap - * @return Wrapped player - */ - public static PlotPlayer wrap(Object player) { - return PlotSquared.platform().wrapPlayer(player); + @Override public final boolean hasPermission(@Nullable final String world, + @Nonnull final String permission) { + return this.permissionProfile.hasPermission(world, permission); } public abstract Actor toActor(); @@ -178,7 +184,7 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, * @param key * @param value */ - public void setMeta(String key, Object value) { + void setMeta(String key, Object value) { if (value == null) { deleteMeta(key); } else { @@ -196,14 +202,14 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, * @param the object type to return * @return the value assigned to the key or null if it does not exist */ - public T getMeta(String key) { + T getMeta(String key) { if (this.meta != null) { return (T) this.meta.get(key); } return null; } - public T getMeta(String key, T defaultValue) { + T getMeta(String key, T defaultValue) { T meta = getMeta(key); if (meta == null) { return defaultValue; @@ -222,7 +228,7 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, * * @param key */ - public Object deleteMeta(String key) { + Object deleteMeta(String key) { return this.meta == null ? null : this.meta.remove(key); } @@ -241,11 +247,13 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, * @return the plot the player is standing on or null if standing on a road or not in a {@link PlotArea} */ public Plot getCurrentPlot() { - Plot value = getMeta(PlotPlayer.META_LAST_PLOT); - if (value == null && !Settings.Enabled_Components.EVENTS) { - return getLocation().getPlot(); + try (final MetaDataAccess lastPlotAccess = + this.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + if (lastPlotAccess.get().orElse(null) == null && !Settings.Enabled_Components.EVENTS) { + return this.getLocation().getPlot(); + } + return lastPlotAccess.get().orElse(null); } - return value; } /** @@ -267,31 +275,6 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, return Permissions.hasPermissionRange(this, "plots.cluster", Settings.Limit.MAX_PLOTS); } - public int hasPermissionRange(String stub, int range) { - if (hasPermission(Captions.PERMISSION_ADMIN.getTranslated())) { - return Integer.MAX_VALUE; - } - String[] nodes = stub.split("\\."); - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < (nodes.length - 1); i++) { - builder.append(nodes[i]).append("."); - if (!stub.equals(builder + Captions.PERMISSION_STAR.getTranslated())) { - if (hasPermission(builder + Captions.PERMISSION_STAR.getTranslated())) { - return Integer.MAX_VALUE; - } - } - } - if (hasPermission(stub + ".*")) { - return Integer.MAX_VALUE; - } - for (int i = range; i > 0; i--) { - if (hasPermission(stub + "." + i)) { - return i; - } - } - return 0; - } - /** * Get the number of plots this player owns. * @@ -732,18 +715,85 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, } } - public byte[] getPersistentMeta(String key) { + byte[] getPersistentMeta(String key) { return this.metaMap.get(key); } - public void removePersistentMeta(String key) { - this.metaMap.remove(key); + Object removePersistentMeta(String key) { + final Object old = this.metaMap.remove(key); if (Settings.Enabled_Components.PERSISTENT_META) { DBFunc.removePersistentMeta(getUUID(), key); } + return old; } - public void setPersistentMeta(String key, byte[] value) { + /** + * Access keyed persistent meta data for this player. This returns a meta data + * access instance, that MUST be closed. It is meant to be used with try-with-resources, + * like such: + *

{@code
+     * try (final MetaDataAccess access = player.accessPersistentMetaData(PlayerMetaKeys.GRANTS)) {
+     *     int grants = access.get();
+     *     access.set(grants + 1);
+     * }
+     * }
+ * + * @param key Meta data key + * @param Meta data type + * @return Meta data access. MUST be closed after being used + */ + @Nonnull public MetaDataAccess accessPersistentMetaData(@Nonnull final MetaDataKey key) { + return new PersistentMetaDataAccess<>(this, key, this.lockRepository.lock(key.getLockKey())); + } + + /** + * Access keyed temporary meta data for this player. This returns a meta data + * access instance, that MUST be closed. It is meant to be used with try-with-resources, + * like such: + *
{@code
+     * try (final MetaDataAccess access = player.accessTemporaryMetaData(PlayerMetaKeys.GRANTS)) {
+     *     int grants = access.get();
+     *     access.set(grants + 1);
+     * }
+     * }
+ * + * @param key Meta data key + * @param Meta data type + * @return Meta data access. MUST be closed after being used + */ + @Nonnull public MetaDataAccess accessTemporaryMetaData(@Nonnull final MetaDataKey key) { + return new TemporaryMetaDataAccess<>(this, key, this.lockRepository.lock(key.getLockKey())); + } + + void setPersistentMeta(@Nonnull final MetaDataKey key, + @Nonnull final T value) { + final Object rawValue = value; + if (key.getType().getRawType().equals(Integer.class)) { + this.setPersistentMeta(key.toString(), Ints.toByteArray((int) rawValue)); + } else if (key.getType().getRawType().equals(Boolean.class)) { + this.setPersistentMeta(key.toString(), ByteArrayUtilities.booleanToBytes((boolean) rawValue)); + } else { + throw new IllegalArgumentException(String.format("Unknown meta data type '%s'", key.getType().toString())); + } + } + + @Nullable T getPersistentMeta(@Nonnull final MetaDataKey key) { + final byte[] value = this.getPersistentMeta(key.toString()); + if (value == null) { + return null; + } + final Object returnValue; + if (key.getType().getRawType().equals(Integer.class)) { + returnValue = Ints.fromByteArray(value); + } else if (key.getType().getRawType().equals(Boolean.class)) { + returnValue = ByteArrayUtilities.bytesToBoolean(value); + } else { + throw new IllegalArgumentException(String.format("Unknown meta data type '%s'", key.getType().toString())); + } + return (T) returnValue; + } + + void setPersistentMeta(String key, byte[] value) { boolean delete = hasPersistentMeta(key); this.metaMap.put(key, value); if (Settings.Enabled_Components.PERSISTENT_META) { @@ -817,7 +867,7 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, } } - public boolean hasPersistentMeta(String key) { + boolean hasPersistentMeta(String key) { return this.metaMap.containsKey(key); } @@ -885,6 +935,15 @@ public abstract class PlotPlayer

implements CommandCaller, OfflinePlotPlayer, } } + /** + * Get this player's {@link LockRepository} + * + * @return Lock repository instance + */ + @Nonnull public LockRepository getLockRepository() { + return this.lockRepository; + } + @FunctionalInterface public interface PlotPlayerConverter { PlotPlayer convert(BaseObject object); diff --git a/Core/src/main/java/com/plotsquared/core/player/TemporaryMetaDataAccess.java b/Core/src/main/java/com/plotsquared/core/player/TemporaryMetaDataAccess.java new file mode 100644 index 000000000..2d1beb060 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/player/TemporaryMetaDataAccess.java @@ -0,0 +1,66 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.player; + +import com.plotsquared.core.synchronization.LockRepository; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import java.util.Optional; + +final class TemporaryMetaDataAccess extends MetaDataAccess { + + TemporaryMetaDataAccess(@Nonnull final PlotPlayer player, + @Nonnull final MetaDataKey metaDataKey, + @Nonnull final LockRepository.LockAccess lockAccess) { + super(player, metaDataKey, lockAccess); + } + + @Override public boolean isPresent() { + this.checkClosed(); + return this.getPlayer().getMeta(this.getMetaDataKey().toString()) != null; + } + + @Override @Nullable public T remove() { + this.checkClosed(); + final Object old = getPlayer().deleteMeta(this.getMetaDataKey().toString()); + if (old == null) { + return null; + } + return (T) old; + } + + @Override public void set(@Nonnull final T value) { + this.checkClosed(); + this.getPlayer().setMeta(this.getMetaDataKey().toString(), value); + } + + @Nonnull @Override public Optional get() { + this.checkClosed(); + return Optional.ofNullable(this.getPlayer().getMeta(this.getMetaDataKey().toString())); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/plot/Plot.java b/Core/src/main/java/com/plotsquared/core/plot/Plot.java index 4cc0cbb18..cfa4d5108 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/Plot.java +++ b/Core/src/main/java/com/plotsquared/core/plot/Plot.java @@ -1924,13 +1924,17 @@ public class Plot { DBFunc.createPlotAndSettings(this, () -> { PlotArea plotworld = Plot.this.area; if (notify && plotworld.isAutoMerge()) { - PlotPlayer player = this.worldUtil.getPlayer(uuid); + final PlotPlayer player = PlotSquared.platform().getPlayerManager() + .getPlayerIfExists(uuid); + PlotMergeEvent event = this.eventDispatcher .callMerge(this, Direction.ALL, Integer.MAX_VALUE, player); + if (event.getEventResult() == Result.DENY) { - player.sendMessage( - TranslatableCaption.of("events.event_denied"), - Template.of("value", "Auto merge on claim")); + if (player != null) { + player.sendMessage(TranslatableCaption.of("events.event_denied"), + Template.of("value", "Auto merge on claim")); + } return; } Plot.this.autoMerge(event.getDir(), event.getMax(), uuid, true); @@ -3087,10 +3091,10 @@ public class Plot { if (!TaskManager.removeFromTeleportQueue(name)) { return; } - if (player.isOnline()) { + try { player.sendMessage(TranslatableCaption.of("teleport.teleported_to_plot")); player.teleport(location, cause); - } + } catch (final Exception ignored) {} }, TaskTime.seconds(Settings.Teleport.DELAY)); resultConsumer.accept(true); }; diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java index 6003e19a7..8b4517bbb 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotArea.java @@ -42,6 +42,8 @@ import com.plotsquared.core.inject.annotations.WorldConfig; import com.plotsquared.core.location.Direction; import com.plotsquared.core.location.Location; import com.plotsquared.core.location.PlotLoc; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.flag.FlagContainer; import com.plotsquared.core.plot.flag.FlagParseException; @@ -784,8 +786,11 @@ public abstract class PlotArea { } public boolean addPlot(@Nonnull final Plot plot) { - for (PlotPlayer pp : plot.getPlayersInPlot()) { - pp.setMeta(PlotPlayer.META_LAST_PLOT, plot); + for (final PlotPlayer pp : plot.getPlayersInPlot()) { + try (final MetaDataAccess metaDataAccess = pp.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + metaDataAccess.set(plot); + } } return this.plots.put(plot.getId(), plot) == null; } @@ -823,8 +828,11 @@ public abstract class PlotArea { public boolean addPlotIfAbsent(@Nonnull final Plot plot) { if (this.plots.putIfAbsent(plot.getId(), plot) == null) { - for (PlotPlayer pp : plot.getPlayersInPlot()) { - pp.setMeta(PlotPlayer.META_LAST_PLOT, plot); + for (PlotPlayer pp : plot.getPlayersInPlot()) { + try (final MetaDataAccess metaDataAccess = pp.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_LAST_PLOT)) { + metaDataAccess.set(plot); + } } return true; } diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotId.java b/Core/src/main/java/com/plotsquared/core/plot/PlotId.java index 061a16578..71a62c760 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotId.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotId.java @@ -35,7 +35,7 @@ import java.util.Iterator; * Plot (X,Y) tuples for plot locations * within a plot area */ -public class PlotId { +public final class PlotId { private final int x; private final int y; @@ -47,7 +47,7 @@ public class PlotId { * @param x The plot x coordinate * @param y The plot y coordinate */ - private PlotId(int x, int y) { + private PlotId(final int x, final int y) { this.x = x; this.y = y; this.hash = (this.getX() << 16) | (this.getY() & 0xFFFF); @@ -60,20 +60,21 @@ public class PlotId { * @param y The plot y coordinate */ @Nonnull public static PlotId of(final int x, final int y) { - return PlotId.of(x, y); + return new PlotId(x, y); } /** * Get a Plot Id based on a string * * @param string to create id from - * @return the PlotId representation of the arguement + * @return the PlotId representation of the argument * @throws IllegalArgumentException if the string does not contain a valid PlotId */ - @Nonnull public static PlotId fromString(@Nonnull String string) { - PlotId plot = fromStringOrNull(string); - if (plot == null) + @Nonnull public static PlotId fromString(@Nonnull final String string) { + final PlotId plot = fromStringOrNull(string); + if (plot == null) { throw new IllegalArgumentException("Cannot create PlotID. String invalid."); + } return plot; } @@ -83,8 +84,8 @@ public class PlotId { * @param string ID string * @return Plot ID, or {@code null} if none could be parsed */ - @Nullable public static PlotId fromStringOrNull(@Nonnull String string) { - String[] parts = string.split("[;,.]"); + @Nullable public static PlotId fromStringOrNull(@Nonnull final String string) { + final String[] parts = string.split("[;,.]"); if (parts.length < 2) { return null; } @@ -93,7 +94,7 @@ public class PlotId { try { x = Integer.parseInt(parts[0]); y = Integer.parseInt(parts[1]); - } catch (NumberFormatException ignored) { + } catch (final NumberFormatException ignored) { return null; } return of(x, y); @@ -125,7 +126,7 @@ public class PlotId { * @return X component */ public int getX() { - return this.getX(); + return this.x; } /** @@ -134,7 +135,7 @@ public class PlotId { * @return Y component */ public int getY() { - return this.getY(); + return this.y; } /** @@ -143,8 +144,8 @@ public class PlotId { * @return Next plot ID */ @Nonnull public PlotId getNextId() { - int absX = Math.abs(x); - int absY = Math.abs(y); + final int absX = Math.abs(x); + final int absY = Math.abs(y); if (absX > absY) { if (x > 0) { return PlotId.of(x, y + 1); diff --git a/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java b/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java index 159cb71a0..d843030c3 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java +++ b/Core/src/main/java/com/plotsquared/core/plot/PlotInventory.java @@ -25,6 +25,8 @@ */ package com.plotsquared.core.plot; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.util.InventoryUtil; import org.slf4j.Logger; @@ -36,7 +38,6 @@ public class PlotInventory { private static final Logger logger = LoggerFactory.getLogger("P2/" + PlotInventory.class.getSimpleName()); - private static final String META_KEY = "inventory"; public final PlotPlayer player; public final int size; private final PlotItemStack[] items; @@ -58,16 +59,25 @@ public class PlotInventory { } public static PlotInventory getOpenPlotInventory(@Nonnull final PlotPlayer plotPlayer) { - return plotPlayer.getMeta(META_KEY, null); + try (final MetaDataAccess inventoryAccess = plotPlayer.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_INVENTORY)) { + return inventoryAccess.get().orElse(null); + } } public static void setPlotInventoryOpen(@Nonnull final PlotPlayer plotPlayer, @Nonnull final PlotInventory plotInventory) { - plotPlayer.setMeta(META_KEY, plotInventory); + try (final MetaDataAccess inventoryAccess = plotPlayer.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_INVENTORY)) { + inventoryAccess.set(plotInventory); + } } public static void removePlotInventoryOpen(@Nonnull final PlotPlayerplotPlayer) { - plotPlayer.deleteMeta(META_KEY); + try (final MetaDataAccess inventoryAccess = plotPlayer.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_INVENTORY)) { + inventoryAccess.remove(); + } } public boolean onClick(int index) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java index 0376da696..3a32056c9 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/comment/CommentManager.java @@ -26,9 +26,13 @@ package com.plotsquared.core.plot.comment; import com.google.common.annotations.Beta; +import com.google.inject.TypeLiteral; +import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.StaticCaption; import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.MetaDataKey; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.util.task.RunnableVal; @@ -82,7 +86,10 @@ import java.util.concurrent.atomic.AtomicInteger; } public static long getTimestamp(PlotPlayer player, String inbox) { - return player.getMeta("inbox:" + inbox, player.getLastPlayed()); + final MetaDataKey inboxKey = MetaDataKey.of(String.format("inbox:%s", inbox), new TypeLiteral() {}); + try (final MetaDataAccess inboxAccess = player.accessTemporaryMetaData(inboxKey)) { + return inboxAccess.get().orElse(player.getLastPlayed()); + } } public static void addInbox(CommentInbox inbox) { diff --git a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java index 38d04f7e5..83fbc2235 100644 --- a/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java +++ b/Core/src/main/java/com/plotsquared/core/plot/expiration/ExpireManager.java @@ -32,7 +32,9 @@ import com.plotsquared.core.database.DBFunc; import com.plotsquared.core.events.PlotFlagAddEvent; import com.plotsquared.core.events.PlotUnlinkEvent; import com.plotsquared.core.events.Result; +import com.plotsquared.core.player.MetaDataAccess; import com.plotsquared.core.player.OfflinePlotPlayer; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -136,44 +138,42 @@ public class ExpireManager { } } - public void confirmExpiry(final PlotPlayer pp) { - if (pp.getMeta("ignoreExpireTask") != null) { - return; - } - if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp - .hasPermission("plots.admin.command.autoclear")) { - final int num = plotsToDelete.size(); - while (!plotsToDelete.isEmpty()) { - Iterator iter = plotsToDelete.iterator(); - final Plot current = iter.next(); - if (!isExpired(new ArrayDeque<>(tasks), current).isEmpty()) { - TaskManager.runTask(() -> { - pp.setMeta("ignoreExpireTask", true); - current.getCenter(pp::teleport); - pp.deleteMeta("ignoreExpireTask"); - PlotMessage msg = new PlotMessage() - .text(num + " " + (num > 1 ? "plots are" : "plot is") + " expired: ") - .color("$1").text(current.toString()).color("$2") - .command("/plot list expired").tooltip("/plot list expired") - //.text("\n - ").color("$3").text("Delete all (/plot delete expired)").color("$2").command("/plot delete expired") - .text("\n - ").color("$3").text("Delete this (/plot delete)") - .color("$2").command("/plot delete").tooltip("/plot delete") - .text("\n - ").color("$3").text("Remind later (/plot flag set keep 1d)") - .color("$2").command("/plot flag set keep 1d").tooltip("/plot flag set keep 1d") - .text("\n - ").color("$3").text("Keep this (/plot flag set keep true)") - .color("$2").command("/plot flag set keep true") - .tooltip("/plot flag set keep true").text("\n - ").color("$3") - .text("Don't show me this").color("$2") - .command("/plot toggle clear-confirmation") - .tooltip("/plot toggle clear-confirmation"); - msg.send(pp); - }); - return; - } else { - iter.remove(); - } + public void confirmExpiry(final PlotPlayer pp) { + try (final MetaDataAccess metaDataAccess = pp.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_IGNORE_EXPIRE_TASK)) { + if (metaDataAccess.isPresent()) { + return; + } + if (plotsToDelete != null && !plotsToDelete.isEmpty() && pp.hasPermission("plots.admin.command.autoclear")) { + final int num = plotsToDelete.size(); + while (!plotsToDelete.isEmpty()) { + Iterator iter = plotsToDelete.iterator(); + final Plot current = iter.next(); + if (!isExpired(new ArrayDeque<>(tasks), current).isEmpty()) { + TaskManager.runTask(() -> { + metaDataAccess.set(true); + current.getCenter(pp::teleport); + metaDataAccess.remove(); + PlotMessage msg = new PlotMessage().text( + num + " " + (num > 1 ? "plots are" : "plot is") + " expired: ").color("$1").text(current.toString()).color("$2") + .command("/plot list expired").tooltip("/plot list expired") + //.text("\n - ").color("$3").text("Delete all (/plot delete expired)").color("$2").command("/plot delete expired") + .text("\n - ").color("$3").text("Delete this (/plot delete)").color("$2").command("/plot delete").tooltip("/plot delete") + .text("\n - ").color("$3").text("Remind later (/plot flag set keep 1d)").color("$2") + .command("/plot flag set keep 1d").tooltip("/plot flag set keep 1d") + .text("\n - ").color("$3").text("Keep this (/plot flag set keep true)").color("$2") + .command("/plot flag set keep true").tooltip("/plot flag set keep true").text("\n - ").color("$3") + .text("Don't show me this").color("$2").command("/plot toggle clear-confirmation") + .tooltip("/plot toggle clear-confirmation"); + msg.send(pp); + }); + return; + } else { + iter.remove(); + } + } + plotsToDelete.clear(); } - plotsToDelete.clear(); } } diff --git a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java b/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java index 03aa8b437..487cfaf7a 100644 --- a/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java +++ b/Core/src/main/java/com/plotsquared/core/queue/BasicLocalBlockQueue.java @@ -25,7 +25,7 @@ */ package com.plotsquared.core.queue; -import com.plotsquared.core.util.MainUtil; +import com.plotsquared.core.util.ChunkUtil; import com.plotsquared.core.util.MathMan; import com.plotsquared.core.util.PatternUtil; import com.plotsquared.core.util.task.TaskManager; @@ -262,8 +262,8 @@ public abstract class BasicLocalBlockQueue extends LocalBlockQueue { } private void setInternal(final int x, final int y, final int z, final BaseBlock baseBlock) { - final int i = MainUtil.CACHE_I[y][x][z]; - final int j = MainUtil.CACHE_J[y][x][z]; + final int i = y >> 4; + final int j = ChunkUtil.getJ(x, y, z); BaseBlock[] array = baseblocks[i]; if (array == null) { array = (baseblocks[i] = new BaseBlock[4096]); diff --git a/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java b/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java index 2c50ee898..80b3ca3fb 100644 --- a/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java +++ b/Core/src/main/java/com/plotsquared/core/setup/CommonSetupSteps.java @@ -30,6 +30,8 @@ import com.plotsquared.core.configuration.caption.Caption; import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.events.TeleportCause; import com.plotsquared.core.generator.GeneratorWrapper; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.PlotArea; import com.plotsquared.core.plot.PlotAreaTerrainType; @@ -204,7 +206,10 @@ public enum CommonSetupSteps implements SetupStep { plotPlayer.sendMessage(TranslatableCaption.of("setup.setup_world_apply_plotsquared")); } builder.worldName(argument); - plotPlayer.deleteMeta("setup"); + try (final MetaDataAccess setupAccess = plotPlayer.accessTemporaryMetaData( + PlayerMetaDataKeys.TEMPORARY_SETUP)) { + setupAccess.remove(); + } String world; if (builder.setupManager() == null) { world = PlotSquared.platform().getInjector().getInstance(SetupUtils.class).setupWorld(builder); diff --git a/Core/src/main/java/com/plotsquared/core/synchronization/LockKey.java b/Core/src/main/java/com/plotsquared/core/synchronization/LockKey.java new file mode 100644 index 000000000..0062d4da6 --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/synchronization/LockKey.java @@ -0,0 +1,92 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.synchronization; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; + +import javax.annotation.Nonnull; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Key used to access {@link java.util.concurrent.locks.Lock locks} + * from a {@link LockRepository} + */ +public final class LockKey { + + private static final Map keyMap = new HashMap<>(); + private static final Object keyLock = new Object(); + + private final String key; + + private LockKey(@Nonnull final String key) { + this.key = Preconditions.checkNotNull(key, "Key may not be null"); + } + + /** + * Get a new named lock key + * + * @param key Key name + * @return Lock key instance + */ + @Nonnull public static LockKey of(@Nonnull final String key) { + synchronized (keyLock) { + return keyMap.computeIfAbsent(key, LockKey::new); + } + } + + /** + * Get all currently recognized lock keys + * + * @return Currently recognized lock keys + */ + @Nonnull static Collection recognizedKeys() { + return Collections.unmodifiableCollection(keyMap.values()); + } + + @Override public String toString() { + return "LockKey{" + "key='" + key + '\'' + '}'; + } + + @Override public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + final LockKey lockKey = (LockKey) o; + return Objects.equal(this.key, lockKey.key); + } + + @Override public int hashCode() { + return Objects.hashCode(this.key); + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/synchronization/LockRepository.java b/Core/src/main/java/com/plotsquared/core/synchronization/LockRepository.java new file mode 100644 index 000000000..373f3694c --- /dev/null +++ b/Core/src/main/java/com/plotsquared/core/synchronization/LockRepository.java @@ -0,0 +1,116 @@ +/* + * _____ _ _ _____ _ + * | __ \| | | | / ____| | | + * | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| | + * | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` | + * | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| | + * |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_| + * | | + * |_| + * PlotSquared plot management system for Minecraft + * Copyright (C) 2020 IntellectualSites + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.plotsquared.core.synchronization; + +import com.google.common.util.concurrent.Striped; + +import javax.annotation.Nonnull; +import java.util.concurrent.locks.Lock; +import java.util.function.Consumer; + +/** + * A repository for keyed {@link java.util.concurrent.locks.Lock locks} + */ +public final class LockRepository { + + private final Striped striped; + + public LockRepository() { + this.striped = Striped.lock(LockKey.recognizedKeys().size()); + } + + /** + * Get the lock corresponding to the given lock key + * + * @param key Lock key + * @return Lock + */ + @Nonnull public Lock getLock(@Nonnull final LockKey key) { + return this.striped.get(key); + } + + /** + * Consume a lock + * + * @param key Lock key + * @param consumer Lock consumer + */ + public void useLock(@Nonnull final LockKey key, @Nonnull final Consumer consumer) { + consumer.accept(this.getLock(key)); + } + + /** + * Wait for the lock to become available, and run + * the given runnable, then unlock the lock. This is + * a blocking method. + * + * @param key Lock key + * @param runnable Action to run when the lock is available + */ + public void useLock(@Nonnull final LockKey key, @Nonnull final Runnable runnable) { + this.useLock(key, lock -> { + lock.lock(); + runnable.run(); + lock.unlock(); + }); + } + + /** + * Wait for a lock to be available, lock it and return + * an {@link AutoCloseable} instance that locks the key. + *

+ * This is meant to be used with try-with-resources, like such: + *

{@code
+     * try (final LockAccess lockAccess = lockRepository.lock(LockKey.of("your.key"))) {
+     *      // use lock
+     * }
+     * }
+ * + * @param key Lock key + * @return Lock access. Must be closed. + */ + @Nonnull public LockAccess lock(@Nonnull final LockKey key) { + final Lock lock = this.getLock(key); + lock.lock(); + return new LockAccess(lock); + } + + + public static class LockAccess implements AutoCloseable { + + private final Lock lock; + + private LockAccess(@Nonnull final Lock lock) { + this.lock = lock; + } + + @Override public void close() { + this.lock.unlock(); + } + + } + +} diff --git a/Core/src/main/java/com/plotsquared/core/util/BlockUtil.java b/Core/src/main/java/com/plotsquared/core/util/BlockUtil.java index a9f1e89db..6d4c4079a 100644 --- a/Core/src/main/java/com/plotsquared/core/util/BlockUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/BlockUtil.java @@ -36,12 +36,19 @@ import com.sk89q.worldedit.world.block.BlockTypes; import com.sk89q.worldedit.world.block.FuzzyBlockState; import com.sk89q.worldedit.world.registry.LegacyMapper; +import javax.annotation.Nonnegative; import javax.annotation.Nonnull; +import javax.annotation.Nullable; + import java.util.Map; +/** + * {@link BlockState} related utility methods + */ public final class BlockUtil { - private static ParserContext PARSER_CONTEXT = new ParserContext(); - private static InputParser PARSER; + + private static final ParserContext PARSER_CONTEXT = new ParserContext(); + private static final InputParser PARSER; static { PARSER_CONTEXT.setRestricted(false); @@ -53,15 +60,35 @@ public final class BlockUtil { private BlockUtil() { } - public static BlockState get(int id) { + /** + * Get a {@link BlockState} from a legacy id + * + * @param id Legacy ID + * @return Block state, or {@code null} + */ + @Nullable public static BlockState get(@Nonnegative final int id) { return LegacyMapper.getInstance().getBlockFromLegacy(id); } - public static BlockState get(int id, int data) { + /** + * Get a {@link BlockState} from a legacy id-data pair + * + * @param id Legacy ID + * @param data Legacy data + * @return Block state, or {@code null} + */ + @Nullable public static BlockState get(@Nonnegative final int id, final int data) { return LegacyMapper.getInstance().getBlockFromLegacy(id, data); } - public static BlockState get(String id) { + /** + * Get a {@link BlockState} from its ID + * + * @param id String or integer ID + * @return Parsed block state, or {@code null} if none + * could be parsed + */ + @Nullable public static BlockState get(@Nonnull String id) { if (id.length() == 1 && id.charAt(0) == '*') { return FuzzyBlockState.builder().type(BlockTypes.AIR).build(); } @@ -90,16 +117,29 @@ public final class BlockUtil { } } - public static BlockState[] parse(String commaDelimited) { - String[] split = commaDelimited.split(",(?![^\\(\\[]*[\\]\\)])"); - BlockState[] result = new BlockState[split.length]; + /** + * Parse a comma delimited list of block states + * + * @param commaDelimited List of block states + * @return Parsed block states + */ + @Nonnull public static BlockState[] parse(@Nonnull final String commaDelimited) { + final String[] split = commaDelimited.split(",(?![^\\(\\[]*[\\]\\)])"); + final BlockState[] result = new BlockState[split.length]; for (int i = 0; i < split.length; i++) { result[i] = get(split[i]); } return result; } - public static BlockState deserialize(@Nonnull final Map map) { + /** + * Deserialize a serialized {@link BlockState} + * + * @param map Serialized block state + * @return Deserialized block state, or {@code null} if the map is + * not a properly serialized block state + */ + @Nullable public static BlockState deserialize(@Nonnull final Map map) { if (map.containsKey("material")) { final Object object = map.get("material"); return get(object.toString()); diff --git a/Core/src/main/java/com/plotsquared/core/util/EconHandler.java b/Core/src/main/java/com/plotsquared/core/util/EconHandler.java index 69363079f..508fe8f57 100644 --- a/Core/src/main/java/com/plotsquared/core/util/EconHandler.java +++ b/Core/src/main/java/com/plotsquared/core/util/EconHandler.java @@ -48,16 +48,4 @@ public abstract class EconHandler { public abstract void depositMoney(OfflinePlotPlayer player, double amount); - /** - * @deprecated Use {@link PermHandler#hasPermission(String, String, String)} instead - */ - @Deprecated public abstract boolean hasPermission(String world, String player, String perm); - - /** - * @deprecated Use {@link PermHandler#hasPermission(String, String)} instead - */ - @Deprecated public boolean hasPermission(String player, String perm) { - return hasPermission(null, player, perm); - } - } diff --git a/Core/src/main/java/com/plotsquared/core/util/Permissions.java b/Core/src/main/java/com/plotsquared/core/util/Permissions.java index 8cec42db9..5ba260daf 100644 --- a/Core/src/main/java/com/plotsquared/core/util/Permissions.java +++ b/Core/src/main/java/com/plotsquared/core/util/Permissions.java @@ -25,14 +25,15 @@ */ package com.plotsquared.core.util; -import com.plotsquared.core.command.CommandCaller; +import com.plotsquared.core.configuration.Caption; import com.plotsquared.core.configuration.Captions; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.configuration.caption.TranslatableCaption; +import com.plotsquared.core.permissions.PermissionHolder; import com.plotsquared.core.player.PlotPlayer; import net.kyori.adventure.text.minimessage.Template; -import java.util.HashMap; +import javax.annotation.Nonnull; /** * The Permissions class handles checking user permissions.
@@ -41,78 +42,28 @@ import java.util.HashMap; */ public class Permissions { - public static boolean hasPermission(PlotPlayer player, Captions caption, boolean notify) { + public static boolean hasPermission(PlotPlayer player, Captions caption, boolean notify) { return hasPermission(player, caption.getTranslated(), notify); } /** - * Check if a player has a permission (Captions class helps keep track of permissions). + * Check if the owner of the profile has a given (global) permission * - * @param player - * @param caption - * @return + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} */ - public static boolean hasPermission(PlotPlayer player, Captions caption) { - return hasPermission(player, caption.getTranslated()); + public static boolean hasPermission(@Nonnull final PermissionHolder caller, @Nonnull final Caption permission) { + return caller.hasPermission(permission.getTranslated()); } /** - * Check if a {@link PlotPlayer} has a permission. + * Check if the owner of the profile has a given (global) permission * - * @param player - * @param permission - * @return + * @param permission Permission + * @return {@code true} if the owner has the given permission, else {@code false} */ - public static boolean hasPermission(PlotPlayer player, String permission) { - if (!Settings.Enabled_Components.PERMISSION_CACHE) { - return hasPermission((CommandCaller) player, permission); - } - HashMap map = player.getMeta("perm"); - if (map != null) { - Boolean result = map.get(permission); - if (result != null) { - return result; - } - } else { - map = new HashMap<>(); - player.setMeta("perm", map); - } - boolean result = hasPermission((CommandCaller) player, permission); - map.put(permission, result); - return result; - } - - /** - * Check if a {@code CommandCaller} has a permission. - * - * @param caller - * @param permission - * @return - */ - public static boolean hasPermission(CommandCaller caller, String permission) { - if (caller.hasPermission(permission)) { - return true; - } else if (caller.isPermissionSet(permission)) { - return false; - } - if (caller.hasPermission(Captions.PERMISSION_ADMIN.getTranslated())) { - return true; - } - permission = permission.toLowerCase().replaceAll("^[^a-z|0-9|\\.|_|-]", ""); - String[] nodes = permission.split("\\."); - StringBuilder n = new StringBuilder(); - for (int i = 0; i <= (nodes.length - 1); i++) { - n.append(nodes[i] + "."); - String combined = n + Captions.PERMISSION_STAR.getTranslated(); - if (!permission.equals(combined)) { - if (caller.hasPermission(combined)) { - return true; - } else if (caller.isPermissionSet(combined)) { - return false; - } - } - } - return false; + public static boolean hasPermission(@Nonnull final PermissionHolder caller, @Nonnull final String permission) { + return caller.hasPermission(permission); } /** @@ -123,7 +74,7 @@ public class Permissions { * @param notify * @return */ - public static boolean hasPermission(PlotPlayer player, String permission, boolean notify) { + public static boolean hasPermission(PlotPlayer player, String permission, boolean notify) { if (!hasPermission(player, permission)) { if (notify) { player.sendMessage( @@ -136,7 +87,7 @@ public class Permissions { return true; } - public static int hasPermissionRange(PlotPlayer player, Captions perm, int range) { + public static int hasPermissionRange(PlotPlayer player, Captions perm, int range) { return hasPermissionRange(player, perm.getTranslated(), range); } @@ -145,12 +96,12 @@ public class Permissions { * - Excessively high values will lag
* - The default range that is checked is {@link Settings.Limit#MAX_PLOTS}
* - * @param player + * @param player Player to check for * @param stub The permission stub to check e.g. for `plots.plot.#` the stub is `plots.plot` * @param range The range to check * @return The highest permission they have within that range */ - public static int hasPermissionRange(PlotPlayer player, String stub, int range) { + public static int hasPermissionRange(PlotPlayer player, String stub, int range) { return player.hasPermissionRange(stub, range); } } diff --git a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java index f7eaa941a..c45479bea 100644 --- a/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/PlayerManager.java @@ -238,7 +238,7 @@ public abstract class PlayerManager

, T> { /** * Get a plot player from a platform player object. This method requires - * that the caller actually knows that the player exists. + * that the caller actually knows that the player exists and is online. *

* The method will throw an exception if there is no such * player online. diff --git a/Core/src/main/java/com/plotsquared/core/util/WEManager.java b/Core/src/main/java/com/plotsquared/core/util/WEManager.java index ea5d98ab8..ce065063d 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WEManager.java +++ b/Core/src/main/java/com/plotsquared/core/util/WEManager.java @@ -28,6 +28,8 @@ package com.plotsquared.core.util; import com.plotsquared.core.PlotSquared; import com.plotsquared.core.configuration.Settings; import com.plotsquared.core.location.Location; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -100,19 +102,22 @@ public class WEManager { } boolean allowMember = player.hasPermission("plots.worldedit.member"); Plot plot = player.getCurrentPlot(); - if (plot == null) { - plot = player.getMeta("WorldEditRegionPlot"); - } - if (plot != null && (!Settings.Done.RESTRICT_BUILDING || !DoneFlag.isDone(plot)) && ( - (allowMember && plot.isAdded(uuid)) || (!allowMember && (plot.isOwner(uuid)) || plot - .getTrusted().contains(uuid))) && !plot.getFlag(NoWorldeditFlag.class)) { - for (CuboidRegion region : plot.getRegions()) { - BlockVector3 pos1 = region.getMinimumPoint().withY(area.getMinBuildHeight()); - BlockVector3 pos2 = region.getMaximumPoint().withY(area.getMaxBuildHeight()); - CuboidRegion copy = new CuboidRegion(pos1, pos2); - regions.add(copy); + try (final MetaDataAccess metaDataAccess = + player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_WORLD_EDIT_REGION_PLOT)) { + if (plot == null) { + plot = metaDataAccess.get().orElse(null); + } + if (plot != null && (!Settings.Done.RESTRICT_BUILDING || !DoneFlag.isDone(plot)) && ( + (allowMember && plot.isAdded(uuid)) || (!allowMember && (plot.isOwner(uuid)) || plot + .getTrusted().contains(uuid))) && !plot.getFlag(NoWorldeditFlag.class)) { + for (CuboidRegion region : plot.getRegions()) { + BlockVector3 pos1 = region.getMinimumPoint().withY(area.getMinBuildHeight()); + BlockVector3 pos2 = region.getMaximumPoint().withY(area.getMaxBuildHeight()); + CuboidRegion copy = new CuboidRegion(pos1, pos2); + regions.add(copy); + } + metaDataAccess.set(plot); } - player.setMeta("WorldEditRegionPlot", plot); } return regions; } diff --git a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java index f02b1c19a..b0d9b9158 100644 --- a/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java +++ b/Core/src/main/java/com/plotsquared/core/util/WorldUtil.java @@ -329,14 +329,6 @@ public abstract class WorldUtil { */ public abstract boolean isBlockSame(@Nonnull BlockState block1, @Nonnull BlockState block2); - /** - * Get a player object for the player with the given UUID - * - * @param uuid Player UUID - * @return Player object - */ - @Nonnull public abstract PlotPlayer getPlayer(@Nonnull UUID uuid); - /** * Get the player health * diff --git a/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java b/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java index 725bca79e..1382e2293 100644 --- a/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java +++ b/Core/src/main/java/com/plotsquared/core/util/task/AutoClaimFinishTask.java @@ -31,6 +31,8 @@ import com.plotsquared.core.configuration.caption.TranslatableCaption; import com.plotsquared.core.events.PlotMergeEvent; import com.plotsquared.core.events.Result; import com.plotsquared.core.location.Direction; +import com.plotsquared.core.player.MetaDataAccess; +import com.plotsquared.core.player.PlayerMetaDataKeys; import com.plotsquared.core.player.PlotPlayer; import com.plotsquared.core.plot.Plot; import com.plotsquared.core.plot.PlotArea; @@ -56,7 +58,10 @@ public final class AutoClaimFinishTask implements Callable { } @Override public Boolean call() { - player.deleteMeta(Auto.class.getName()); + try (final MetaDataAccess autoAccess + = player.accessTemporaryMetaData(PlayerMetaDataKeys.TEMPORARY_AUTO)) { + autoAccess.remove(); + } if (plot == null) { player.sendMessage(TranslatableCaption.of("errors.no_free_plots")); return false; diff --git a/build.gradle b/build.gradle index 32f1b0b5e..32b17ef31 100644 --- a/build.gradle +++ b/build.gradle @@ -29,8 +29,8 @@ ext { git = Grgit.open(dir: new File(rootDir.toString() + "/.git")) } -def ver = "5.12.5" -def versuffix = "" +def ver = "6.0.0" +def versuffix = "-SUPER-SNAPSHOT" ext { if (project.hasProperty("versionsuffix")) { versuffix = "-$versionsuffix"