Add new placeholder system

This commit is contained in:
Alexander Söderberg 2020-07-14 13:14:02 +02:00
parent e88da3cea9
commit af7db08036
No known key found for this signature in database
GPG Key ID: C0207FF7EA146678
9 changed files with 455 additions and 131 deletions

View File

@ -27,17 +27,10 @@ package com.plotsquared.bukkit.placeholder;
import com.plotsquared.core.PlotSquared;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.util.MainUtil;
import me.clip.placeholderapi.PlaceholderAPIPlugin;
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import java.util.UUID;
public class Placeholders extends PlaceholderExpansion {
public Placeholders() {
@ -70,6 +63,7 @@ public class Placeholders extends PlaceholderExpansion {
return "";
}
// PAPI specific ones that don't translate well over into other placeholder APIs
if (identifier.startsWith("has_plot_")) {
identifier = identifier.substring("has_plot_".length());
if (identifier.isEmpty())
@ -88,126 +82,8 @@ public class Placeholders extends PlaceholderExpansion {
return String.valueOf(pl.getPlotCount(identifier));
}
switch (identifier) {
case "currentplot_world": {
return p.getWorld().getName();
}
case "has_plot": {
return (pl.getPlotCount() > 0) ?
PlaceholderAPIPlugin.booleanTrue() :
PlaceholderAPIPlugin.booleanFalse();
}
case "allowed_plot_count": {
return String.valueOf(pl.getAllowedPlots());
}
case "plot_count": {
return String.valueOf(pl.getPlotCount());
}
}
Plot plot = pl.getCurrentPlot();
if (plot == null) {
return "";
}
switch (identifier) {
case "currentplot_alias": {
return plot.getAlias();
}
case "currentplot_owner": {
final UUID plotOwner = plot.getOwnerAbs();
if (plotOwner == null) {
return "";
}
try {
return MainUtil.getName(plotOwner, false);
} catch (final Exception ignored) {}
final String name = Bukkit.getOfflinePlayer(plotOwner).getName();
return name != null ? name : "unknown";
}
case "currentplot_members": {
if (plot.getMembers() == null && plot.getTrusted() == null) {
return "0";
}
return String.valueOf(plot.getMembers().size() + plot.getTrusted().size());
}
case "currentplot_members_added": {
if (plot.getMembers() == null) {
return "0";
}
return String.valueOf(plot.getMembers().size());
}
case "currentplot_members_trusted": {
if (plot.getTrusted() == null) {
return "0";
}
return String.valueOf(plot.getTrusted().size());
}
case "currentplot_members_denied": {
if (plot.getDenied() == null) {
return "0";
}
return String.valueOf(plot.getDenied().size());
}
case "has_build_rights": {
return plot.isAdded(pl.getUUID()) ?
PlaceholderAPIPlugin.booleanTrue() :
PlaceholderAPIPlugin.booleanFalse();
}
case "currentplot_x": {
return String.valueOf(plot.getId().getX());
}
case "currentplot_y": {
return String.valueOf(plot.getId().getY());
}
case "currentplot_xy": {
return plot.getId().getX() + ";" + plot.getId().getY();
}
case "currentplot_rating": {
return String.valueOf(plot.getAverageRating());
}
case "currentplot_biome": {
return plot.getBiomeSynchronous() + "";
}
default:
break;
}
if (identifier.startsWith("currentplot_localflag_")) {
return getFlagValue(plot, identifier.substring("currentplot_localflag_".length()),
false);
}
if (identifier.startsWith("currentplot_flag_")) {
return getFlagValue(plot, identifier.substring("currentplot_flag_".length()), true);
}
return "";
// PlotSquared placeholders
return PlotSquared.get().getPlaceholderRegistry().getPlaceholderValue(identifier, pl);
}
/**
* Return the flag value from its name on the current plot.
* If the flag doesn't exist it returns an empty string.
* If the flag exists but it is not set on current plot and the parameter inherit is set to true,
* it returns the default value.
*
* @param plot Current plot where the player is
* @param flagName Name of flag to get from current plot
* @param inherit Define if it returns only the flag set on currentplot or also inherited flag
* @return The value of flag serialized in string
*/
private String getFlagValue(final Plot plot, final String flagName, final boolean inherit) {
if (flagName.isEmpty())
return "";
final PlotFlag<?, ?> flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName);
if (flag == null)
return "";
if (inherit) {
return plot.getFlag(flag).toString();
} else {
final PlotFlag<?, ?> plotFlag = plot.getFlagContainer().queryLocal(flag.getClass());
return (plotFlag != null) ? plotFlag.getValue().toString() : "";
}
}
}

View File

@ -62,6 +62,7 @@ import com.plotsquared.core.plot.PlotManager;
import com.plotsquared.core.plot.comment.CommentManager;
import com.plotsquared.core.plot.expiration.ExpireManager;
import com.plotsquared.core.plot.expiration.ExpiryTask;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.world.DefaultPlotAreaManager;
import com.plotsquared.core.plot.world.PlotAreaManager;
import com.plotsquared.core.plot.world.SinglePlotArea;
@ -82,6 +83,7 @@ import com.plotsquared.core.util.SetupUtils;
import com.plotsquared.core.util.StringMan;
import com.plotsquared.core.util.WorldUtil;
import com.plotsquared.core.util.logger.ILogger;
import com.plotsquared.core.util.placeholders.PlaceholderRegistry;
import com.plotsquared.core.util.query.PlotQuery;
import com.plotsquared.core.util.task.TaskManager;
import com.plotsquared.core.uuid.UUIDPipeline;
@ -171,6 +173,7 @@ public class PlotSquared {
private File storageFile;
@Getter private PlotAreaManager plotAreaManager;
@Getter private EventDispatcher eventDispatcher;
@Getter private PlaceholderRegistry placeholderRegistry;
/**
* Initialize PlotSquared with the desired Implementation class.
@ -194,6 +197,9 @@ public class PlotSquared {
//
ConfigurationSerialization.registerClass(BlockBucket.class, "BlockBucket");
// Setup the global flag container
GlobalFlagContainer.setup();
try {
new ReflectionUtils(this.IMP.getNMSPackage());
try {
@ -209,6 +215,7 @@ public class PlotSquared {
"PlotSquared-" + platform + ".jar");
}
}
TaskManager.IMP = this.IMP.getTaskManager();
// World Util. Has to be done before config files are loaded
@ -262,6 +269,8 @@ public class PlotSquared {
startExpiryTasks();
// Create Event utility class
eventDispatcher = new EventDispatcher();
// Create placeholder registry
placeholderRegistry = new PlaceholderRegistry(eventDispatcher);
// create Hybrid utility class
HybridUtils.manager = this.IMP.initHybridUtils();
// Inventory utility class

View File

@ -2256,7 +2256,7 @@ public class Plot {
*
* @return The plot alias
*/
public String getAlias() {
@NotNull public String getAlias() {
if (this.settings == null) {
return "";
}

View File

@ -25,6 +25,7 @@
*/
package com.plotsquared.core.plot.flag;
import com.google.common.base.Preconditions;
import com.plotsquared.core.plot.flag.implementations.AnalysisFlag;
import com.plotsquared.core.plot.flag.implementations.AnimalAttackFlag;
import com.plotsquared.core.plot.flag.implementations.AnimalCapFlag;
@ -114,7 +115,13 @@ import java.util.Map;
public final class GlobalFlagContainer extends FlagContainer {
@Getter private static final GlobalFlagContainer instance = new GlobalFlagContainer();
@Getter private static GlobalFlagContainer instance;
public static void setup() {
Preconditions.checkState(instance == null, "Cannot setup the container twice");
instance = new GlobalFlagContainer();
}
private static Map<String, Class<?>> stringClassMap;
private GlobalFlagContainer() {
@ -124,6 +131,7 @@ public final class GlobalFlagContainer extends FlagContainer {
}
});
stringClassMap = new HashMap<>();
// Register all default flags here
// Boolean flags
this.addFlag(ExplosionFlag.EXPLOSION_FALSE);

View File

@ -80,9 +80,9 @@ import java.util.UUID;
public class EventDispatcher {
private EventBus eventBus = new EventBus("PlotSquaredEvents");
private final EventBus eventBus = new EventBus("PlotSquaredEvents");
private List<Object> listeners = new ArrayList<>();
private final List<Object> listeners = new ArrayList<>();
public void registerListener(Object listener) {
eventBus.register(listener);
@ -100,6 +100,10 @@ public class EventDispatcher {
}
}
public void callGenericEvent(@NotNull final Object event) {
eventBus.post(event);
}
public void callEvent(@NotNull final PlotEvent event) {
eventBus.post(event);
}

View File

@ -0,0 +1,63 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util.placeholders;
import com.google.common.base.Preconditions;
import com.plotsquared.core.player.PlotPlayer;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import org.jetbrains.annotations.NotNull;
/**
* A placeholder is a keyed value that gets replaced by a {@link PlotPlayer player}-specific value at runtime
*/
@EqualsAndHashCode(of = "key") @ToString(of = "key")
public abstract class Placeholder {
private final String key;
public Placeholder(@NotNull final String key) {
this.key = Preconditions.checkNotNull(key, "Key may not be null");
}
/**
* Get the value of the placeholder for a particular player
*
* @param player Player
* @return Placeholder value. Return {@code ""} if no placeholder value can be returned
*/
@NotNull public abstract String getValue(@NotNull final PlotPlayer<?> player);
/**
* Get the placeholder key
*
* @return Placeholder key
*/
@NotNull public final String getKey() {
return this.key;
}
}

View File

@ -0,0 +1,230 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util.placeholders;
import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.PlotFlag;
import com.plotsquared.core.util.EventDispatcher;
import com.plotsquared.core.util.MainUtil;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.util.Map;
import java.util.UUID;
import java.util.function.BiFunction;
/**
* Registry that contains {@link Placeholder placeholders}
*/
public final class PlaceholderRegistry {
private final Map<String, Placeholder> placeholders;
private final EventDispatcher eventDispatcher;
public PlaceholderRegistry(@NotNull final EventDispatcher eventDispatcher) {
this.placeholders = Maps.newHashMap();
this.eventDispatcher = eventDispatcher;
this.registerDefault();
}
private void registerDefault() {
final GlobalFlagContainer globalFlagContainer = GlobalFlagContainer.getInstance();
for (final PlotFlag<?, ?> flag : globalFlagContainer.getRecognizedPlotFlags()) {
this.registerPlaceholder(new PlotFlagPlaceholder(flag, true));
this.registerPlaceholder(new PlotFlagPlaceholder(flag, false));
}
GlobalFlagContainer.getInstance().subscribe((flag, type) -> {
this.registerPlaceholder(new PlotFlagPlaceholder(flag, true));
this.registerPlaceholder(new PlotFlagPlaceholder(flag, false));
});
this.createPlaceholder("currentplot_world", player -> player.getLocation().getWorld());
this.createPlaceholder("has_plot", player -> player.getPlotCount() > 0 ? "true" : "false");
this.createPlaceholder("allowed_plot_count", player -> Integer.toString(player.getAllowedPlots()));
this.createPlaceholder("plot_count", player -> Integer.toString(player.getPlotCount()));
this.createPlaceholder("currentplot_alias", (player, plot) -> plot.getAlias());
this.createPlaceholder("currentplot_owner", (player, plot) -> {
final UUID plotOwner = plot.getOwnerAbs();
if (plotOwner == null) {
return "";
}
try {
return MainUtil.getName(plotOwner, false);
} catch (final Exception ignored) {}
return "unknown";
});
this.createPlaceholder("currentplot_members", (player, plot) -> {
if (plot.getMembers() == null && plot.getTrusted() == null) {
return "0";
}
return String.valueOf(plot.getMembers().size() + plot.getTrusted().size());
});
this.createPlaceholder("currentplot_members_added", (player, plot) -> {
if (plot.getMembers() == null) {
return "0";
}
return String.valueOf(plot.getMembers().size());
});
this.createPlaceholder("currentplot_members_trusted", (player, plot) -> {
if (plot.getTrusted() == null) {
return "0";
}
return String.valueOf(plot.getTrusted().size());
});
this.createPlaceholder("currentplot_members_denied", (player, plot) -> {
if (plot.getDenied() == null) {
return "0";
}
return String.valueOf(plot.getDenied().size());
});
this.createPlaceholder("has_build_rights", (player, plot) ->
plot.isAdded(player.getUUID()) ? "true" : "false");
this.createPlaceholder("currentplot_x", (player, plot) -> Integer.toString(plot.getId().getX()));
this.createPlaceholder("currentplot_y", (player, plot) -> Integer.toString(plot.getId().getY()));
this.createPlaceholder("currentplot_xy", (player, plot) -> plot.getId().toString());
this.createPlaceholder("currentplot_rating", (player, plot) -> Double.toString(plot.getAverageRating()));
this.createPlaceholder("currentplot_biome", (player, plot) -> plot.getBiomeSynchronous().toString());
}
/**
* Create a functional placeholder
*
* @param key Placeholder key
* @param placeholderFunction Placeholder generator. Cannot return null
*/
@SuppressWarnings("ALL") public void createPlaceholder(@NotNull final String key,
@NotNull final Function<PlotPlayer<?>, String> placeholderFunction) {
this.registerPlaceholder(new Placeholder(key) {
@Override @NotNull public String getValue(@NotNull final PlotPlayer<?> player) {
return placeholderFunction.apply(player);
}
});
}
/**
* Create a functional placeholder
*
* @param key Placeholder key
* @param placeholderFunction Placeholder generator. Cannot return null
*/
public void createPlaceholder(@NotNull final String key,
@NotNull final BiFunction<PlotPlayer<?>, Plot, String> placeholderFunction) {
this.registerPlaceholder(new PlotSpecificPlaceholder(key) {
@Override @NotNull public String getValue(@NotNull final PlotPlayer<?> player, @NotNull final Plot plot) {
return placeholderFunction.apply(player, plot);
}
});
}
/**
* Register a placeholder
*
* @param placeholder Placeholder instance
*/
public void registerPlaceholder(@NotNull final Placeholder placeholder) {
final Placeholder previous = this.placeholders
.put(placeholder.getKey().toLowerCase(Locale.ENGLISH),
Preconditions.checkNotNull(placeholder, "Placeholder may not be null"));
if (previous != null) {
this.eventDispatcher.callGenericEvent(new PlaceholderAddedEvent(placeholder));
}
}
/**
* Get a placeholder instance from its key
*
* @param key Placeholder key
* @return Placeholder value
*/
@Nullable public Placeholder getPlaceholder(@NotNull final String key) {
return this.placeholders.get(
Preconditions.checkNotNull(key, "Key may not be null").toLowerCase(Locale.ENGLISH));
}
/**
* Get the placeholder value evaluated for a player, and catch and deal with any problems
* occurring while doing so
*
* @param key Placeholder key
* @param player Player to evaluate for
* @return Replacement value
*/
@NotNull public String getPlaceholderValue(@NotNull final String key,
@NotNull final PlotPlayer<?> player) {
final Placeholder placeholder = getPlaceholder(key);
if (placeholder == null) {
return "";
}
String placeholderValue = "";
try {
placeholderValue = placeholder.getValue(player);
// If a placeholder for some reason decides to be disobedient, we catch it here
if (placeholderValue == null) {
new RuntimeException(String
.format("Placeholder '%s' returned null for player '%s'", placeholder.getKey(),
player.getName())).printStackTrace();
}
} catch (final Exception exception) {
new RuntimeException(String
.format("Placeholder '%s' failed to evalulate for player '%s'",
placeholder.getKey(), player.getName()), exception).printStackTrace();
}
return placeholderValue;
}
/**
* Get all placeholders
*
* @return Unmodifiable collection of placeholders
*/
@NotNull public Collection<Placeholder> getPlaceholders() {
return Collections.unmodifiableCollection(this.placeholders.values());
}
/**
* Event called when a new {@link Placeholder} has been added
*/
@RequiredArgsConstructor
@Getter
public static class PlaceholderAddedEvent {
private final Placeholder placeholder;
}
}

View File

@ -0,0 +1,75 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util.placeholders;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import com.plotsquared.core.plot.flag.GlobalFlagContainer;
import com.plotsquared.core.plot.flag.PlotFlag;
import org.jetbrains.annotations.NotNull;
public final class PlotFlagPlaceholder extends PlotSpecificPlaceholder {
private final PlotFlag<?, ?> flag;
private final boolean local;
public PlotFlagPlaceholder(@NotNull final PlotFlag<?, ?> flag, final boolean local) {
super(String.format("currentplot_%sflag_%s", local ? "local": "", flag.getName()));
this.flag = flag;
this.local = local;
}
@Override @NotNull public String getValue(@NotNull final PlotPlayer<?> player, @NotNull final Plot plot) {
return this.getFlagValue(plot, this.flag.getName(), !this.local);
}
/**
* Return the flag value from its name on the current plot.
* If the flag doesn't exist it returns an empty string.
* If the flag exists but it is not set on current plot and the parameter inherit is set to true,
* it returns the default value.
*
* @param plot Current plot where the player is
* @param flagName Name of flag to get from current plot
* @param inherit Define if it returns only the flag set on currentplot or also inherited flag
* @return The value of flag serialized in string
*/
private String getFlagValue(final Plot plot, final String flagName, final boolean inherit) {
if (flagName.isEmpty())
return "";
final PlotFlag<?, ?> flag = GlobalFlagContainer.getInstance().getFlagFromString(flagName);
if (flag == null)
return "";
if (inherit) {
return plot.getFlag(flag).toString();
} else {
final PlotFlag<?, ?> plotFlag = plot.getFlagContainer().queryLocal(flag.getClass());
return (plotFlag != null) ? plotFlag.getValue().toString() : "";
}
}
}

View File

@ -0,0 +1,59 @@
/*
* _____ _ _ _____ _
* | __ \| | | | / ____| | |
* | |__) | | ___ | |_| (___ __ _ _ _ __ _ _ __ ___ __| |
* | ___/| |/ _ \| __|\___ \ / _` | | | |/ _` | '__/ _ \/ _` |
* | | | | (_) | |_ ____) | (_| | |_| | (_| | | | __/ (_| |
* |_| |_|\___/ \__|_____/ \__, |\__,_|\__,_|_| \___|\__,_|
* | |
* |_|
* 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 <http://www.gnu.org/licenses/>.
*/
package com.plotsquared.core.util.placeholders;
import com.plotsquared.core.player.PlotPlayer;
import com.plotsquared.core.plot.Plot;
import org.jetbrains.annotations.NotNull;
/**
* A {@link Placeholder placeholder} that requires a {@link com.plotsquared.core.plot.Plot plot}
*/
public abstract class PlotSpecificPlaceholder extends Placeholder {
public PlotSpecificPlaceholder(@NotNull final String key) {
super(key);
}
@Override @NotNull public final String getValue(@NotNull final PlotPlayer<?> player) {
final Plot plot = player.getCurrentPlot();
if (plot == null) {
return "";
}
return this.getValue(player, plot);
}
/**
* Get the value of the placeholder for the {@link PlotPlayer player} in a specific {@link Plot plot}
*
* @param player Player that the placeholder is evaluated for
* @param plot Plot that the player is in
* @return Placeholder value, or {@code ""} if the placeholder does not apply
*/
@NotNull public abstract String getValue(@NotNull final PlotPlayer<?> player,
@NotNull final Plot plot);
}