Implements #4
All checks were successful
KnarCraft/PlaceholderSigns/pipeline/head This commit looks good

This commit is contained in:
2024-04-29 19:29:55 +02:00
parent 14f9fa8833
commit a34c63b7e2
12 changed files with 567 additions and 109 deletions

View File

@@ -4,6 +4,7 @@ import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.Translator;
import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.placeholdersigns.command.CopySignCommand;
import net.knarcraft.placeholdersigns.command.CopySignTextCommand;
import net.knarcraft.placeholdersigns.command.EditSignCommand;
import net.knarcraft.placeholdersigns.command.UnWaxSignCommand;
import net.knarcraft.placeholdersigns.command.ViewSignCommand;
@@ -97,6 +98,7 @@ public final class PlaceholderSigns extends JavaPlugin {
registerCommand("viewSign", new ViewSignCommand());
registerCommand("copySign", new CopySignCommand());
registerCommand("unWaxSign", new UnWaxSignCommand());
registerCommand("copySignText", new CopySignTextCommand());
}
@Override

View File

@@ -0,0 +1,99 @@
package net.knarcraft.placeholdersigns.command;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.util.TabCompletionHelper;
import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.container.SignTextCopyRequest;
import net.knarcraft.placeholdersigns.util.TabCompleteHelper;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.List;
/**
* A command for copying a sign's text
*/
public class CopySignTextCommand implements TabExecutor {
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
PlaceholderSigns placeholderSigns = PlaceholderSigns.getInstance();
StringFormatter stringFormatter = placeholderSigns.getStringFormatter();
if (!(commandSender instanceof Player player)) {
stringFormatter.displayErrorMessage(commandSender, PlaceholderSignMessage.ERROR_PLAYER_ONLY);
return false;
}
Block targetBlock = player.getTargetBlockExact(7);
if (targetBlock == null || !(targetBlock.getState() instanceof Sign sign)) {
stringFormatter.displayErrorMessage(commandSender, PlaceholderSignMessage.ERROR_NOT_LOOKING_AT_SIGN);
return false;
}
Side side = null;
Integer sourceLine = null;
Integer destinationLine = null;
if (arguments.length > 0) {
try {
side = Side.valueOf(arguments[0]);
} catch (IllegalArgumentException exception) {
// Choose the side the player is currently looking at
if (arguments[0].equalsIgnoreCase("this")) {
SignSide standingOn = sign.getTargetSide(player);
side = sign.getSide(Side.FRONT).equals(standingOn) ? Side.FRONT : Side.BACK;
} else {
return false;
}
}
}
if (arguments.length > 1) {
try {
sourceLine = Integer.parseInt(arguments[1]) - 1;
} catch (NumberFormatException exception) {
return false;
}
}
if (arguments.length > 2) {
try {
destinationLine = Integer.parseInt(arguments[2]) - 1;
} catch (NumberFormatException exception) {
return false;
}
}
SignTextCopyRequest signCopyRequest = new SignTextCopyRequest(player, sign, side, sourceLine, destinationLine);
placeholderSigns.getRequestHandler().addSignTextCopyRequest(signCopyRequest);
stringFormatter.displaySuccessMessage(commandSender, PlaceholderSignMessage.SUCCESS_CLICK_SIGN_TO_PASTE);
return true;
}
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] arguments) {
if (arguments.length == 1) {
List<String> signSides = TabCompleteHelper.getSignSides();
signSides.add("this");
return TabCompletionHelper.filterMatchingStartsWith(signSides, arguments[0]);
} else if (arguments.length < 4) {
return TabCompletionHelper.filterMatchingStartsWith(TabCompleteHelper.getLineNumbers(),
arguments[arguments.length - 1]);
} else {
return new ArrayList<>();
}
}
}

View File

@@ -1,9 +1,11 @@
package net.knarcraft.placeholdersigns.command;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.util.TabCompletionHelper;
import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import net.knarcraft.placeholdersigns.util.TabCompleteHelper;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor;
@@ -19,15 +21,6 @@ import java.util.List;
*/
public class EditSignCommand implements TabExecutor {
private static final List<String> lineNumbers;
static {
lineNumbers = new ArrayList<>();
for (int i = 1; i < 5; i++) {
lineNumbers.add(String.valueOf(i));
}
}
@Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
@@ -77,9 +70,9 @@ public class EditSignCommand implements TabExecutor {
@Nullable
@Override
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
@NotNull String[] args) {
if (args.length == 1) {
return lineNumbers;
@NotNull String[] arguments) {
if (arguments.length == 1) {
return TabCompletionHelper.filterMatchingStartsWith(TabCompleteHelper.getLineNumbers(), arguments[0]);
} else {
return new ArrayList<>();
}

View File

@@ -0,0 +1,47 @@
package net.knarcraft.placeholdersigns.config;
import org.jetbrains.annotations.NotNull;
/**
* Permissions used by placeholdersigns
*/
public enum PlaceholderSignsPermission {
/**
* The permission for bypassing the restriction on pasting onto waxed signs
*/
BYPASS_WAXED_COPY("placeholdersigns.copy.bypass-waxed"),
/**
* The permission for bypassing the restriction on editing waxed signs
*/
BYPASS_WAXED_EDIT("placeholdersigns.edit.bypass-waxed"),
/**
* The permission for creating new placeholder signs
*/
USE_PLACEHOLDERS("placeholdersigns.placeholder"),
;
private final @NotNull String permissionNode;
/**
* Instantiates a new placeholder signs permission
*
* @param permissionNode <p>The permission node belonging to this permission</p>
*/
PlaceholderSignsPermission(@NotNull String permissionNode) {
this.permissionNode = permissionNode;
}
/**
* Gets this permission's permission node
*
* @return <p>This permission's permission node</p>
*/
@NotNull
public String getPermissionNode() {
return this.permissionNode;
}
}

View File

@@ -0,0 +1,20 @@
package net.knarcraft.placeholdersigns.container;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* A record of a player's request to copy a sign
*
* @param player <p>The player requesting the sign copy</p>
* @param sign <p>The sign the player wants to copy</p>
* @param side <p>The side of the sign top copy from (null = both)</p>
* @param sourceLine <p>The line on the source sign to copy (null = all)</p>
* @param destinationLine <p>The line on the destination sign to overwrite</p>
*/
public record SignTextCopyRequest(@NotNull Player player, @NotNull Sign sign, @Nullable Side side,
@Nullable Integer sourceLine, @Nullable Integer destinationLine) {
}

View File

@@ -2,6 +2,7 @@ package net.knarcraft.placeholdersigns.handler;
import net.knarcraft.placeholdersigns.container.SignCopyRequest;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import net.knarcraft.placeholdersigns.container.SignTextCopyRequest;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -15,7 +16,8 @@ import java.util.Map;
public class PlaceholderSignRequestHandler {
private final @NotNull Map<Player, SignLineChangeRequest> signChangeRequests;
private final Map<Player, SignCopyRequest> signCopyRequests;
private final @NotNull Map<Player, SignTextCopyRequest> signTextCopyRequests;
private final @NotNull Map<Player, SignCopyRequest> signCopyRequests;
/**
* Instantiates a new placeholder sign request handler
@@ -23,6 +25,7 @@ public class PlaceholderSignRequestHandler {
public PlaceholderSignRequestHandler() {
this.signChangeRequests = new HashMap<>();
this.signCopyRequests = new HashMap<>();
this.signTextCopyRequests = new HashMap<>();
}
/**
@@ -71,4 +74,24 @@ public class PlaceholderSignRequestHandler {
return this.signChangeRequests.remove(player);
}
/**
* Registers a sign text copy request
*
* @param signCopyRequest <p>The request to register</p>
*/
public void addSignTextCopyRequest(@NotNull SignTextCopyRequest signCopyRequest) {
this.signTextCopyRequests.put(signCopyRequest.player(), signCopyRequest);
}
/**
* Gets a sign text copy request
*
* @param player <p>The player to get the request for</p>
* @return <p>The sign text copy request, or null if not found</p>
*/
@Nullable
public SignTextCopyRequest getSignTextCopyRequest(@NotNull Player player) {
return this.signTextCopyRequests.remove(player);
}
}

View File

@@ -5,9 +5,11 @@ import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.ColorHelper;
import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.config.PlaceholderSignsPermission;
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
import net.knarcraft.placeholdersigns.container.SignCopyRequest;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import net.knarcraft.placeholdersigns.container.SignTextCopyRequest;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignRequestHandler;
import org.bukkit.Bukkit;
@@ -26,6 +28,9 @@ import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Objects;
import static net.knarcraft.placeholdersigns.util.SignSideHelper.getOpposite;
import static net.knarcraft.placeholdersigns.util.SignSideHelper.getSide;
/**
* A listener for placeholder signs being clicked
*/
@@ -44,7 +49,7 @@ public class SignClickListener implements Listener {
SignCopyRequest signCopyRequest = requestHandler.getSignCopyRequest(player);
if (signCopyRequest != null) {
if (checkWaxEdit(sign, player, "placeholdersigns.copy.bypass-waxed")) {
if (checkWaxEdit(sign, player, PlaceholderSignsPermission.BYPASS_WAXED_COPY.getPermissionNode())) {
return;
}
@@ -53,19 +58,167 @@ public class SignClickListener implements Listener {
return;
}
// Check if the player has run the /editSign command
SignLineChangeRequest request = requestHandler.getSignChangeRequest(player);
if (request != null) {
if (checkWaxEdit(sign, player, "placeholdersigns.edit.bypass-waxed")) {
// Check if the player has run the /setSignLine command
SignLineChangeRequest signChangeRequest = requestHandler.getSignChangeRequest(player);
if (signChangeRequest != null) {
if (checkWaxEdit(sign, player, PlaceholderSignsPermission.BYPASS_WAXED_EDIT.getPermissionNode())) {
return;
}
SignSide standingOn = sign.getTargetSide(player);
Side side = sign.getSide(Side.FRONT).equals(standingOn) ? Side.FRONT : Side.BACK;
doSignChange(sign, request, event, player, side);
doSignChange(sign, signChangeRequest.line(), player, getSide(sign, player), signChangeRequest.text());
event.setCancelled(true);
return;
}
SignTextCopyRequest signTextCopyRequest = requestHandler.getSignTextCopyRequest(player);
if (signTextCopyRequest != null) {
if (checkWaxEdit(sign, player, PlaceholderSignsPermission.BYPASS_WAXED_COPY.getPermissionNode())) {
return;
}
pasteSignText(sign, signTextCopyRequest, player, getSide(sign, player));
event.setCancelled(true);
}
}
/**
* Pastes sign text according to the given signTextCopyRequest
*
* @param targetSign <p>The sign to paste onto</p>
* @param signTextCopyRequest <p>The requested sign text copy request to fulfill</p>
* @param player <p>The player wanting to paste</p>
* @param clickedSide <p>The sign side the player wants to paste onto</p>
*/
private void pasteSignText(@NotNull Sign targetSign, @NotNull SignTextCopyRequest signTextCopyRequest,
@NotNull Player player, @NotNull Side clickedSide) {
Side sourceSide = signTextCopyRequest.side();
Sign sourceSign = signTextCopyRequest.sign();
PlaceholderSignHandler signHandler = PlaceholderSigns.getInstance().getSignHandler();
PlaceholderSign sourcePlaceholderSign = signHandler.getFromLocation(sourceSign.getLocation());
PlaceholderSign targetPlaceholderSign = signHandler.getFromLocation(targetSign.getLocation());
if (sourceSide == null) {
// Copy both sides
copySignText(signHandler, sourcePlaceholderSign, targetPlaceholderSign, clickedSide, sourceSign, targetSign,
player);
} else if (signTextCopyRequest.sourceLine() == null) {
// Copy the side the player looked at while executing the command
copySignSideText(signHandler, sourcePlaceholderSign, targetPlaceholderSign, sourceSide, clickedSide,
sourceSign, targetSign, player);
} else {
copySignLine(signTextCopyRequest, sourcePlaceholderSign, sourceSide, clickedSide, targetSign, player);
}
}
/**
* Copies sign line from one sign side to another
*
* @param signTextCopyRequest <p>The sign text copy request to handle</p>
* @param sourcePlaceholderSign <p>The source sign's placeholder sign, or null</p>
* @param sourceSide <p>The side of the source sign to copy text from</p>
* @param clickedSide <p>The side the player clicked to paste</p>
* @param targetSign <p>The sign to paste text onto</p>
* @param player <p>The player performing the copy paste</p>
*/
private void copySignLine(@NotNull SignTextCopyRequest signTextCopyRequest,
@Nullable PlaceholderSign sourcePlaceholderSign, @NotNull Side sourceSide,
@NotNull Side clickedSide, @NotNull Sign targetSign, @NotNull Player player) {
if (signTextCopyRequest.side() == null || signTextCopyRequest.sourceLine() == null) {
throw new RuntimeException("Non-null variable is null");
}
int sourceLine = signTextCopyRequest.sourceLine();
int destinationLine = signTextCopyRequest.destinationLine() != null ?
signTextCopyRequest.destinationLine() : sourceLine;
String text = signTextCopyRequest.sign().getSide(signTextCopyRequest.side()).getLine(sourceLine);
if (sourcePlaceholderSign != null) {
Map<Side, Map<Integer, String>> placeholders = sourcePlaceholderSign.placeholders();
if (placeholders.containsKey(sourceSide) && placeholders.get(sourceSide).containsKey(sourceLine)) {
text = placeholders.get(sourceSide).get(sourceLine);
}
}
doSignChange(targetSign, destinationLine, player, clickedSide, text);
}
/**
* Copies sign text from one sign side to another
*
* @param signHandler <p>The sign handler to use for dealing with placeholder signs</p>
* @param sourcePlaceholderSign <p>The source sign's placeholder sign, or null</p>
* @param targetPlaceholderSign <p>The destination's placeholder sign, or null</p>
* @param sourceSide <p>The side of the source sign to copy text from</p>
* @param clickedSide <p>The side the player clicked to paste</p>
* @param sourceSign <p>The sign to copy text from</p>
* @param targetSign <p>The sign to paste text onto</p>
* @param player <p>The player performing the copy paste</p>
*/
private void copySignSideText(@NotNull PlaceholderSignHandler signHandler,
@Nullable PlaceholderSign sourcePlaceholderSign,
@Nullable PlaceholderSign targetPlaceholderSign, @NotNull Side sourceSide,
@NotNull Side clickedSide, @NotNull Sign sourceSign, @NotNull Sign targetSign,
@NotNull Player player) {
// Remove old placeholders from the sign side
Map<Integer, String> oldPlaceholders = null;
if (targetPlaceholderSign != null) {
oldPlaceholders = targetPlaceholderSign.placeholders().remove(clickedSide);
}
if (pasteSignSide(sourceSide, clickedSide, sourceSign, targetSign,
sourcePlaceholderSign, player) && targetPlaceholderSign != null) {
// Restore the old placeholders if the sign change didn't finish
targetPlaceholderSign.placeholders().put(clickedSide, oldPlaceholders);
}
// Save any placeholder changes
signHandler.save();
// Apply changes
targetSign.update();
PlaceholderSigns.getInstance().getStringFormatter().displaySuccessMessage(player,
PlaceholderSignMessage.SUCCESS_SIGN_PASTED);
}
/**
* Copies sign text from one sign to another
*
* @param signHandler <p>The sign handler to use for dealing with placeholder signs</p>
* @param sourcePlaceholderSign <p>The source sign's placeholder sign, or null</p>
* @param targetPlaceholderSign <p>The destination's placeholder sign, or null</p>
* @param clickedSide <p>The side the player clicked to paste</p>
* @param sourceSign <p>The sign to copy text from</p>
* @param targetSign <p>The sign to paste text onto</p>
* @param player <p>The player performing the copy paste</p>
*/
private void copySignText(@NotNull PlaceholderSignHandler signHandler,
@Nullable PlaceholderSign sourcePlaceholderSign,
@Nullable PlaceholderSign targetPlaceholderSign, @NotNull Side clickedSide,
@NotNull Sign sourceSign, @NotNull Sign targetSign, @NotNull Player player) {
// Un-register the old placeholder sign to remove its data
if (targetPlaceholderSign != null) {
signHandler.unregisterSign(targetPlaceholderSign);
}
// Copy both sides of the sign. Paste the front to whichever side the player is currently looking at
if ((pasteSignSide(Side.FRONT, clickedSide, sourceSign, targetSign, sourcePlaceholderSign, player) ||
pasteSignSide(Side.BACK, getOpposite(clickedSide), sourceSign, targetSign, sourcePlaceholderSign, player)) &&
targetPlaceholderSign != null) {
// Re-register the old placeholder sign if the new text couldn't be applied
signHandler.registerSign(targetPlaceholderSign);
}
// Save any placeholder changes
signHandler.save();
// Apply changes
targetSign.update();
PlaceholderSigns.getInstance().getStringFormatter().displaySuccessMessage(player,
PlaceholderSignMessage.SUCCESS_SIGN_PASTED);
}
/**
* Checks if the player is trying to edit/modify a waxed sign without permission
*
@@ -86,68 +239,80 @@ public class SignClickListener implements Listener {
/**
* Pastes the data from the source sign to the target sign
*
* @param source <p>The source sign to copy data from</p>
* @param target <p>The target sign to paste to</p>
* @param player <p>The player pasting the sign</p>
* @param sourceSign <p>The source sign to copy data from</p>
* @param targetSign <p>The target sign to paste to</p>
* @param player <p>The player pasting the sign</p>
*/
private void pasteSign(@NotNull Sign source, @NotNull Sign target, @NotNull Player player) {
private void pasteSign(@NotNull Sign sourceSign, @NotNull Sign targetSign, @NotNull Player player) {
StringFormatter stringFormatter = PlaceholderSigns.getInstance().getStringFormatter();
PlaceholderSign placeholderSign = PlaceholderSigns.getInstance().getSignHandler().getFromLocation(source.getLocation());
SignSide sourceFront = source.getSide(Side.FRONT);
SignSide sourceBack = source.getSide(Side.BACK);
SignSide targetFront = target.getSide(Side.FRONT);
SignSide targetBack = target.getSide(Side.BACK);
PlaceholderSign placeholderSign = PlaceholderSigns.getInstance().getSignHandler().getFromLocation(
sourceSign.getLocation());
// Get the lines, with placeholders replaced, and the sign change event processed
String[] frontLines = getFinalLines(target, sourceFront, Side.FRONT, placeholderSign, player);
if (frontLines == null) {
stringFormatter.displayErrorMessage(player, PlaceholderSignMessage.ERROR_CANCELLED_BY_PROTECTION);
if (pasteSignSide(Side.FRONT, Side.FRONT, sourceSign, targetSign, placeholderSign, player) ||
pasteSignSide(Side.BACK, Side.BACK, sourceSign, targetSign, placeholderSign, player)) {
return;
}
String[] backLines = getFinalLines(target, sourceBack, Side.BACK, placeholderSign, player);
if (backLines == null) {
stringFormatter.displayErrorMessage(player, PlaceholderSignMessage.ERROR_CANCELLED_BY_PROTECTION);
return;
}
// Update the lines on both sides of the target sign
for (int i = 0; i < frontLines.length; i++) {
targetFront.setLine(i, ColorHelper.translateColorCodes(frontLines[i], ColorConversion.RGB));
}
for (int i = 0; i < backLines.length; i++) {
targetBack.setLine(i, ColorHelper.translateColorCodes(backLines[i], ColorConversion.RGB));
}
// Copy options
copySignOptions(source, target);
copySignOptions(sourceSign, targetSign);
// Apply changes
target.update();
targetSign.update();
stringFormatter.displaySuccessMessage(player, PlaceholderSignMessage.SUCCESS_SIGN_PASTED);
}
/**
* Pastes one side of a sign onto another
*
* @param sourceSide <p>The sign side to copy</p>
* @param destinationSide <p>The sign side to paste to</p>
* @param source <p>The source sign</p>
* @param target <p>The destination sign</p>
* @param placeholderSign <p>The placeholder sign belonging to the source sign, or null</p>
* @param player <p>The player performing the paste</p>
* @return <p>False if the pasting completed successfully. True if blocked by another plugin.</p>
*/
private boolean pasteSignSide(@NotNull Side sourceSide, @NotNull Side destinationSide, @NotNull Sign source,
@NotNull Sign target, @Nullable PlaceholderSign placeholderSign, @NotNull Player player) {
SignSide sourceSignSide = source.getSide(sourceSide);
SignSide targetSignSide = target.getSide(destinationSide);
String[] frontLines = getFinalLines(target, sourceSignSide, sourceSide, destinationSide, placeholderSign, player);
if (frontLines == null) {
PlaceholderSigns.getInstance().getStringFormatter().displayErrorMessage(player,
PlaceholderSignMessage.ERROR_CANCELLED_BY_PROTECTION);
return true;
}
for (int i = 0; i < frontLines.length; i++) {
targetSignSide.setLine(i, ColorHelper.translateColorCodes(frontLines[i], ColorConversion.RGB));
}
return false;
}
/**
* Gets the final lines from a sign side, after inserting placeholders and running a sign change event
*
* @param sign <p>The sign that's changed</p>
* @param signSide <p>The side of the sign to get lines from</p>
* @param side <p>The side that's processed</p>
* @param sourceSide <p>The side that text is taken from</p>
* @param targetSide <p>The side that text is changed for</p>
* @param placeholderSign <p>The placeholder sign corresponding to the sign, if any</p>
* @param player <p>The player attempting to paste the sign</p>
* @return <p>The final lines, or null if the event was cancelled</p>
*/
@Nullable
private String[] getFinalLines(@NotNull Sign sign, @NotNull SignSide signSide, @NotNull Side side,
@Nullable PlaceholderSign placeholderSign, @NotNull Player player) {
private String[] getFinalLines(@NotNull Sign sign, @NotNull SignSide signSide, @NotNull Side sourceSide,
@NotNull Side targetSide, @Nullable PlaceholderSign placeholderSign,
@NotNull Player player) {
String[] sideLines = signSide.getLines();
if (placeholderSign != null) {
Map<Side, Map<Integer, String>> placeholders = placeholderSign.placeholders();
loadPlaceholders(side, sideLines, placeholders);
loadPlaceholders(sourceSide, sideLines, placeholders);
}
// Run the sign change event to allow protection plugins to cancel, and allow the sign text listener to trigger
SignChangeEvent changeEvent = new SignChangeEvent(Objects.requireNonNull(sign.getBlock()), player, sideLines, side);
SignChangeEvent changeEvent = new SignChangeEvent(Objects.requireNonNull(sign.getBlock()), player, sideLines, targetSide);
Bukkit.getPluginManager().callEvent(changeEvent);
if (changeEvent.isCancelled()) {
return null;
@@ -202,39 +367,36 @@ public class SignClickListener implements Listener {
}
/**
* Perform the changing of a sign according to the given sign change request
* Alters the text on a sign, taking care of placeholders and sign change event triggers
*
* @param sign <p>The sign to be changed</p>
* @param request <p>The sign line change request to perform</p>
* @param event <p>The interaction event that triggered this</p>
* @param player <p>The player triggering the sign change</p>
* @param targetSign <p>The sign to be changed</p>
* @param destinationLine <p>The line to be changed on the sign</p>
* @param player <p>The player trying to change the sign</p>
* @param targetSide <p>The side of the sign to change the line for</p>
* @param newText <p>The new text to apply to the sign</p>
*/
private void doSignChange(@NotNull Sign sign, @NotNull SignLineChangeRequest request,
@NotNull PlayerInteractEvent event, @NotNull Player player, @NotNull Side side) {
// Cancel the event to prevent vanilla behavior
event.setCancelled(true);
SignSide signSide = sign.getSide(side);
String[] lines = signSide.getLines();
private void doSignChange(@NotNull Sign targetSign, int destinationLine, @NotNull Player player,
@NotNull Side targetSide, @NotNull String newText) {
SignSide targetSignSide = targetSign.getSide(targetSide);
String[] lines = targetSignSide.getLines();
PlaceholderSignHandler signHandler = PlaceholderSigns.getInstance().getSignHandler();
PlaceholderSign placeholderSign = PlaceholderSigns.getInstance().getSignHandler().getFromLocation(sign.getLocation());
PlaceholderSign targetPlaceholderSign = PlaceholderSigns.getInstance().getSignHandler().getFromLocation(targetSign.getLocation());
String oldPlaceholder = null;
if (placeholderSign != null) {
if (targetPlaceholderSign != null) {
// Remove the old placeholder
oldPlaceholder = placeholderSign.placeholders().get(side).remove(request.line());
oldPlaceholder = targetPlaceholderSign.placeholders().get(targetSide).remove(destinationLine);
}
lines[request.line()] = request.text();
lines[destinationLine] = newText;
// Run the sign change event to allow protection plugins to cancel, and allow the sign text listener to trigger
SignChangeEvent changeEvent = new SignChangeEvent(Objects.requireNonNull(event.getClickedBlock()),
player, lines, side);
SignChangeEvent changeEvent = new SignChangeEvent(targetSign.getBlock(), player, lines, targetSide);
Bukkit.getPluginManager().callEvent(changeEvent);
if (changeEvent.isCancelled()) {
if (placeholderSign != null) {
if (targetPlaceholderSign != null) {
// Restore the old placeholder if the action didn't complete
placeholderSign.placeholders().get(side).put(request.line(), oldPlaceholder);
targetPlaceholderSign.placeholders().get(targetSide).put(destinationLine, oldPlaceholder);
}
PlaceholderSigns.getInstance().getStringFormatter().displayErrorMessage(player,
PlaceholderSignMessage.ERROR_CANCELLED_BY_PROTECTION);
@@ -242,11 +404,9 @@ public class SignClickListener implements Listener {
}
// Update the sign with the new text
String[] finalLines = changeEvent.getLines();
for (int i = 0; i < finalLines.length; i++) {
signSide.setLine(i, ColorHelper.translateColorCodes(finalLines[i], ColorConversion.RGB));
}
sign.update();
targetSignSide.setLine(destinationLine, ColorHelper.translateColorCodes(changeEvent.getLines()[destinationLine],
ColorConversion.RGB));
targetSign.update();
// Save any placeholder changes
signHandler.save();

View File

@@ -2,6 +2,7 @@ package net.knarcraft.placeholdersigns.listener;
import me.clip.placeholderapi.PlaceholderAPI;
import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignsPermission;
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
import org.bukkit.Location;
@@ -23,7 +24,7 @@ public class SignTextListener implements Listener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onSignCreateOrEdit(@NotNull SignChangeEvent event) {
// Only check for placeholders if the player is allowed to
if (!event.getPlayer().hasPermission("placeholdersigns.placeholder")) {
if (!event.getPlayer().hasPermission(PlaceholderSignsPermission.USE_PLACEHOLDERS.getPermissionNode())) {
return;
}

View File

@@ -0,0 +1,39 @@
package net.knarcraft.placeholdersigns.util;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
public final class SignSideHelper {
private SignSideHelper() {
}
/**
* Gets the side of the given sign the given player is standing on (which side the player clicked)
*
* @param sign <p>The sign to check</p>
* @param player <p>The player to check</p>
* @return <p>The side of the sign the player is standing on</p>
*/
@NotNull
public static Side getSide(@NotNull Sign sign, @NotNull Player player) {
SignSide standingOn = sign.getTargetSide(player);
return sign.getSide(Side.FRONT).equals(standingOn) ? Side.FRONT : Side.BACK;
}
/**
* Gets the opposite sign side from the given sign side
*
* @param side <p>The side to get the opposite of</p>
* @return <p>The opposite side</p>
*/
@NotNull
public static Side getOpposite(@NotNull Side side) {
return side == Side.FRONT ? Side.BACK : Side.FRONT;
}
}

View File

@@ -0,0 +1,53 @@
package net.knarcraft.placeholdersigns.util;
import org.bukkit.block.sign.Side;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
/**
* A helper class for generating tab-completions
*/
public final class TabCompleteHelper {
private static final List<String> lineNumbers;
private static final List<String> signSides;
static {
lineNumbers = new ArrayList<>();
for (int i = 1; i < 5; i++) {
lineNumbers.add(String.valueOf(i));
}
signSides = new ArrayList<>();
for (Side side : Side.values()) {
signSides.add(side.name());
}
}
private TabCompleteHelper() {
}
/**
* Gets possible sign line numbers
*
* @return <p>Possible sign line numbers</p>
*/
@NotNull
public static List<String> getLineNumbers() {
return new ArrayList<>(lineNumbers);
}
/**
* Gets possible sign sides
*
* @return <p>Possible sign sides</p>
*/
@NotNull
public static List<String> getSignSides() {
return new ArrayList<>(signSides);
}
}