Greatly improves display of text

Makes output text configurable
Adds improved formatting and colors when displaying sign contents
Adds information about applied dye and glow status for signs
Properly cancels the default event when using the viewSign and viewSignRaw commands
This commit is contained in:
Kristian Knarvik 2024-04-21 21:26:16 +02:00
parent 6129eda989
commit e8c93baac4
12 changed files with 413 additions and 196 deletions

10
pom.xml
View File

@ -65,6 +65,10 @@
<id>placeholder-api</id> <id>placeholder-api</id>
<url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url> <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
</repository> </repository>
<repository>
<id>knarcraft-repo</id>
<url>https://git.knarcraft.net/api/packages/EpicKnarvik97/maven</url>
</repository>
</repositories> </repositories>
<distributionManagement> <distributionManagement>
<repository> <repository>
@ -97,5 +101,11 @@
<version>2.10.0</version> <version>2.10.0</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>net.knarcraft</groupId>
<artifactId>knarlib</artifactId>
<version>1.2.5</version>
<scope>compile</scope>
</dependency>
</dependencies> </dependencies>
</project> </project>

View File

@ -1,28 +1,23 @@
package net.knarcraft.placeholdersigns; package net.knarcraft.placeholdersigns;
import me.clip.placeholderapi.PlaceholderAPI; import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.Translator;
import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.placeholdersigns.command.EditSignCommand; import net.knarcraft.placeholdersigns.command.EditSignCommand;
import net.knarcraft.placeholdersigns.command.ViewSignCommand; import net.knarcraft.placeholdersigns.command.ViewSignCommand;
import net.knarcraft.placeholdersigns.container.PlaceholderSign; import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler; import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignRequestHandler;
import net.knarcraft.placeholdersigns.listener.SignBreakListener; import net.knarcraft.placeholdersigns.listener.SignBreakListener;
import net.knarcraft.placeholdersigns.listener.SignClickListener; import net.knarcraft.placeholdersigns.listener.SignClickListener;
import net.knarcraft.placeholdersigns.listener.SignTextListener; import net.knarcraft.placeholdersigns.listener.SignTextListener;
import net.knarcraft.placeholdersigns.util.ColorHelper; import net.knarcraft.placeholdersigns.runnable.SignUpdate;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Location; import org.bukkit.command.CommandExecutor;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.bukkit.command.PluginCommand; import org.bukkit.command.PluginCommand;
import org.bukkit.entity.Player;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level; import java.util.logging.Level;
/** /**
@ -32,15 +27,16 @@ public final class PlaceholderSigns extends JavaPlugin {
private static PlaceholderSigns instance; private static PlaceholderSigns instance;
private PlaceholderSignHandler signHandler; private PlaceholderSignHandler signHandler;
private Map<Player, SignLineChangeRequest> signChangeRequests; private PlaceholderSignRequestHandler requestHandler;
private Map<Player, Void> signViewRequests; private StringFormatter stringFormatter;
/** /**
* Gets an instance of this plugin * Gets an instance of this plugin
* *
* @return <p>A plugin instance</p> * @return <p>A plugin instance</p>
*/ */
public static @NotNull PlaceholderSigns getInstance() { @NotNull
public static PlaceholderSigns getInstance() {
return instance; return instance;
} }
@ -49,63 +45,38 @@ public final class PlaceholderSigns extends JavaPlugin {
* *
* @return <p>The sign handler</p> * @return <p>The sign handler</p>
*/ */
public @NotNull PlaceholderSignHandler getSignHandler() { @NotNull
public PlaceholderSignHandler getSignHandler() {
return this.signHandler; return this.signHandler;
} }
/** @NotNull
* Registers a sign change request public PlaceholderSignRequestHandler getRequestHandler() {
* return this.requestHandler;
* <p>A sign change request is basically the result of running the editSign command, which must be stored until the
* player clicks a sign.</p>
*
* @param request <p>The sign change request to register</p>
*/
public void addSignChangeRequest(@NotNull SignLineChangeRequest request) {
signChangeRequests.put(request.player(), request);
} }
/** @NotNull
* Gets a sign change request public StringFormatter getStringFormatter() {
* return this.stringFormatter;
* @param player <p>The player to get the request for</p>
* @return <p>The sign change request, or null if not found</p>
*/
public @Nullable SignLineChangeRequest getSignChangeRequest(@NotNull Player player) {
return signChangeRequests.remove(player);
}
/**
* Registers a sign view request
*
* @param player <p>The player requesting to view a sign</p>
*/
public void addSignViewRequest(@NotNull Player player) {
signViewRequests.put(player, null);
}
/**
* Checks whether the given player has a sign view request
*
* @param player <p>The player to check</p>
* @return <p>True if the player has requested to view a sign</p>
*/
public boolean hasSignViewRequest(@NotNull Player player) {
if (signViewRequests.containsKey(player)) {
signViewRequests.remove(player);
return true;
} else {
return false;
}
} }
@Override @Override
public void onEnable() { public void onEnable() {
instance = this; instance = this;
signHandler = new PlaceholderSignHandler(); getConfig().options().copyDefaults(true);
signChangeRequests = new HashMap<>(); saveConfig();
signViewRequests = new HashMap<>(); Translator translator = new Translator();
signHandler.load(); translator.registerMessageCategory(PlaceholderSignMessage.SUCCESS_CLICK_SIGN_TO_EDIT);
translator.setColorConversion(ColorConversion.RGB);
translator.loadLanguages(this.getDataFolder(), "en", getConfig().getString("language", "en"));
this.stringFormatter = new StringFormatter(this.getDescription().getName(), translator);
this.stringFormatter.setColorConversion(ColorConversion.RGB);
this.stringFormatter.setNamePrefix("#A5682A[&r&l");
this.stringFormatter.setNameSuffix("&r#A5682A]");
this.signHandler = new PlaceholderSignHandler();
this.signHandler.load();
this.requestHandler = new PlaceholderSignRequestHandler();
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) { if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) {
getLogger().log(Level.WARNING, "Could not find PlaceholderAPI! This plugin is required."); getLogger().log(Level.WARNING, "Could not find PlaceholderAPI! This plugin is required.");
@ -114,21 +85,15 @@ public final class PlaceholderSigns extends JavaPlugin {
} }
// Update signs' placeholders every second // Update signs' placeholders every second
Bukkit.getScheduler().runTaskTimer(this, this::updateSigns, 20 * 10, 20 * 5); Bukkit.getScheduler().runTaskTimer(this, new SignUpdate(this.signHandler), 20 * 10, 20 * 5);
Bukkit.getPluginManager().registerEvents(new SignBreakListener(), this); Bukkit.getPluginManager().registerEvents(new SignBreakListener(), this);
Bukkit.getPluginManager().registerEvents(new SignTextListener(), this); Bukkit.getPluginManager().registerEvents(new SignTextListener(), this);
Bukkit.getPluginManager().registerEvents(new SignClickListener(), this); Bukkit.getPluginManager().registerEvents(new SignClickListener(), this);
PluginCommand editCommand = Bukkit.getPluginCommand("editSign"); registerCommand("editSign", new EditSignCommand());
if (editCommand != null) { registerCommand("viewSign", new ViewSignCommand(false));
editCommand.setExecutor(new EditSignCommand()); registerCommand("viewSignRaw", new ViewSignCommand(true));
}
PluginCommand viewCommand = Bukkit.getPluginCommand("viewSign");
if (viewCommand != null) {
viewCommand.setExecutor(new ViewSignCommand());
}
} }
@Override @Override
@ -137,77 +102,18 @@ public final class PlaceholderSigns extends JavaPlugin {
} }
/** /**
* Updates all loaded and registered placeholder signs * Registers a command executor
*/
private void updateSigns() {
for (PlaceholderSign placeholderSign : signHandler.getSigns()) {
// Ignore signs away from players
Location location = placeholderSign.location();
if (!location.getChunk().isLoaded()) {
continue;
}
// If no longer a sign, remove
if (!(location.getBlock().getState() instanceof Sign sign)) {
signHandler.unregisterSign(placeholderSign);
continue;
}
// Update placeholders
SignSide front = sign.getSide(Side.FRONT);
SignSide back = sign.getSide(Side.BACK);
Map<Side, Map<Integer, String>> placeholders = placeholderSign.placeholders();
String[] frontLines = front.getLines();
String[] backLines = back.getLines();
// Only update the sign if the text has changed
boolean updateNecessary = false;
if (placeholders.get(Side.FRONT) != null) {
updateNecessary |= updatePlaceholders(frontLines, placeholders.get(Side.FRONT), front);
}
if (placeholders.get(Side.BACK) != null) {
updateNecessary |= updatePlaceholders(backLines, placeholders.get(Side.BACK), back);
}
if (updateNecessary) {
sign.update();
}
}
}
/**
* Updates the values of placeholders on a sign
* *
* @param lines <p>The sign's current lines</p> * @param commandName <p>The name of the command</p>
* @param placeholders <p>The sign's original placeholder lines</p> * @param executor <p>The command's executor</p>
* @param signSide <p>The side of the sign to update placeholders for</p>
* @return <p>True if text has been changed, and the sign needs to be updated</p>
*/ */
private boolean updatePlaceholders(@NotNull String[] lines, @NotNull Map<Integer, String> placeholders, private void registerCommand(@NotNull String commandName, @NotNull CommandExecutor executor) {
@NotNull SignSide signSide) { PluginCommand command = Bukkit.getPluginCommand(commandName);
boolean changed = false; if (command != null) {
for (int i = 0; i < lines.length; i++) { command.setExecutor(executor);
String oldText = signSide.getLine(i);
// The new text of the sign is either the same, or the original placeholder
String newText;
if (!placeholders.containsKey(i) || placeholders.get(i) == null) {
newText = oldText;
} else { } else {
newText = PlaceholderAPI.setPlaceholders(null, placeholders.get(i)); getLogger().log(Level.SEVERE, "Unable to register command " + commandName);
}
// Convert color codes
newText = ColorHelper.translateAllColorCodes(newText);
// Only change the line if the text has changed
if (!newText.equals(oldText)) {
signSide.setLine(i, newText);
changed = true;
} }
} }
return changed;
}
} }

View File

@ -1,6 +1,7 @@
package net.knarcraft.placeholdersigns.command; package net.knarcraft.placeholdersigns.command;
import net.knarcraft.placeholdersigns.PlaceholderSigns; import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest; import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
@ -60,9 +61,10 @@ public class EditSignCommand implements TabExecutor {
// Register the line change request // Register the line change request
SignLineChangeRequest request = new SignLineChangeRequest(player, lineNumber - 1, builder.toString()); SignLineChangeRequest request = new SignLineChangeRequest(player, lineNumber - 1, builder.toString());
PlaceholderSigns.getInstance().addSignChangeRequest(request); PlaceholderSigns.getInstance().getRequestHandler().addSignChangeRequest(request);
commandSender.sendMessage("Please click the sign you want to change."); PlaceholderSigns.getInstance().getStringFormatter().displaySuccessMessage(commandSender,
PlaceholderSignMessage.SUCCESS_CLICK_SIGN_TO_EDIT);
return true; return true;
} }

View File

@ -1,6 +1,7 @@
package net.knarcraft.placeholdersigns.command; package net.knarcraft.placeholdersigns.command;
import net.knarcraft.placeholdersigns.PlaceholderSigns; import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.TabExecutor; import org.bukkit.command.TabExecutor;
@ -15,6 +16,18 @@ import java.util.List;
* A command for viewing lines on a sign * A command for viewing lines on a sign
*/ */
public class ViewSignCommand implements TabExecutor { public class ViewSignCommand implements TabExecutor {
boolean raw;
/**
* Instantiates a new view sign command
*
* @param raw <p>Whether this sign displays the raw text or not</p>
*/
public ViewSignCommand(boolean raw) {
this.raw = raw;
}
@Override @Override
public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label, public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label,
@NotNull String[] args) { @NotNull String[] args) {
@ -23,9 +36,10 @@ public class ViewSignCommand implements TabExecutor {
} }
// Register the sign view request // Register the sign view request
PlaceholderSigns.getInstance().addSignViewRequest(player); PlaceholderSigns.getInstance().getRequestHandler().addSignViewRequest(player, this.raw);
commandSender.sendMessage("Please click the sign you want to view."); PlaceholderSigns.getInstance().getStringFormatter().displaySuccessMessage(commandSender,
PlaceholderSignMessage.SUCCESS_CLICK_SIGN_TO_VIEW);
return true; return true;
} }
@ -35,4 +49,5 @@ public class ViewSignCommand implements TabExecutor {
@NotNull String[] args) { @NotNull String[] args) {
return new ArrayList<>(); return new ArrayList<>();
} }
} }

View File

@ -0,0 +1,52 @@
package net.knarcraft.placeholdersigns.config;
import net.knarcraft.knarlib.formatting.TranslatableMessage;
import org.jetbrains.annotations.NotNull;
/**
* Translatable plugin messages
*/
public enum PlaceholderSignMessage implements TranslatableMessage {
/**
* The message to display when waiting for a sign selection (edit)
*/
SUCCESS_CLICK_SIGN_TO_EDIT,
/**
* The message to display when waiting for a sign selection (view)
*/
SUCCESS_CLICK_SIGN_TO_VIEW,
/**
* The message displayed when a player tries to edit a waxed sign without the necessary permission
*/
ERROR_WAXED_NO_PERMISSION,
/**
* The message displayed when a sign line has been successfully changed
*/
SUCCESS_SIGN_CHANGED,
/**
* The format used when printing current sign lines
*/
SUCCESS_SIGN_CONTENTS,
/**
* The string displayed when a sign is confirmed to be glowing
*/
GLOWING_CONFIRM,
/**
* The string displayed when a sign is not glowing
*/
GLOWING_DENY,
;
@Override
public @NotNull TranslatableMessage[] getAllMessages() {
return PlaceholderSignMessage.values();
}
}

View File

@ -0,0 +1,75 @@
package net.knarcraft.placeholdersigns.handler;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
/**
* A class for keeping track of placeholder sign requests
*/
public class PlaceholderSignRequestHandler {
private final Map<Player, SignLineChangeRequest> signChangeRequests;
private final Map<Player, Boolean> signViewRequests;
/**
* Instantiates a new placeholder sign request handler
*/
public PlaceholderSignRequestHandler() {
this.signChangeRequests = new HashMap<>();
this.signViewRequests = new HashMap<>();
}
/**
* Registers a sign change request
*
* <p>A sign change request is basically the result of running the editSign command, which must be stored until the
* player clicks a sign.</p>
*
* @param request <p>The sign change request to register</p>
*/
public void addSignChangeRequest(@NotNull SignLineChangeRequest request) {
signChangeRequests.put(request.player(), request);
}
/**
* Gets a sign change request
*
* @param player <p>The player to get the request for</p>
* @return <p>The sign change request, or null if not found</p>
*/
@Nullable
public SignLineChangeRequest getSignChangeRequest(@NotNull Player player) {
return signChangeRequests.remove(player);
}
/**
* Registers a sign view request
*
* @param player <p>The player requesting to view a sign</p>
* @param raw <p>Whether to display the raw text (visible formatting codes)</p>
*/
public void addSignViewRequest(@NotNull Player player, boolean raw) {
signViewRequests.put(player, raw);
}
/**
* Checks whether the given player has a sign view request
*
* @param player <p>The player to check</p>
* @return <p>True if the player has requested to view a sign</p>
*/
@Nullable
public Boolean getSignViewRequest(@NotNull Player player) {
if (signViewRequests.containsKey(player)) {
return signViewRequests.remove(player);
} else {
return null;
}
}
}

View File

@ -1,10 +1,16 @@
package net.knarcraft.placeholdersigns.listener; package net.knarcraft.placeholdersigns.listener;
import net.knarcraft.knarlib.formatting.StringFormatter;
import net.knarcraft.knarlib.formatting.StringReplacer;
import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.ColorHelper;
import net.knarcraft.placeholdersigns.PlaceholderSigns; import net.knarcraft.placeholdersigns.PlaceholderSigns;
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
import net.knarcraft.placeholdersigns.container.SignLineChangeRequest; import net.knarcraft.placeholdersigns.container.SignLineChangeRequest;
import net.knarcraft.placeholdersigns.util.ColorHelper; import net.knarcraft.placeholdersigns.handler.PlaceholderSignRequestHandler;
import net.md_5.bungee.api.ChatColor; import net.md_5.bungee.api.ChatColor;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.DyeColor;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side; import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide; import org.bukkit.block.sign.SignSide;
@ -32,18 +38,24 @@ public class SignClickListener implements Listener {
} }
Player player = event.getPlayer(); Player player = event.getPlayer();
boolean hasSignViewRequest = PlaceholderSigns.getInstance().hasSignViewRequest(player); PlaceholderSignRequestHandler requestHandler = PlaceholderSigns.getInstance().getRequestHandler();
if (hasSignViewRequest) { Boolean hasSignViewRequest = requestHandler.getSignViewRequest(player);
printSign(sign, player);
if (hasSignViewRequest != null) {
printSign(sign, player, hasSignViewRequest);
// Cancel the event to prevent vanilla behavior
event.setCancelled(true);
return;
} }
if (sign.isWaxed() && !player.hasPermission("placeholdersigns.edit.bypass-waxed")) { if (sign.isWaxed() && !player.hasPermission("placeholdersigns.edit.bypass-waxed")) {
player.sendMessage(ChatColor.RED + "You do not have the necessary permissions to edit a waxed sign."); PlaceholderSigns.getInstance().getStringFormatter().displayErrorMessage(player,
PlaceholderSignMessage.ERROR_WAXED_NO_PERMISSION);
return; return;
} }
// Check if the player has run the /editSign command // Check if the player has run the /editSign command
SignLineChangeRequest request = PlaceholderSigns.getInstance().getSignChangeRequest(player); SignLineChangeRequest request = requestHandler.getSignChangeRequest(player);
if (request != null) { if (request != null) {
SignSide standingOn = sign.getTargetSide(player); SignSide standingOn = sign.getTargetSide(player);
Side side = sign.getSide(Side.FRONT).equals(standingOn) ? Side.FRONT : Side.BACK; Side side = sign.getSide(Side.FRONT).equals(standingOn) ? Side.FRONT : Side.BACK;
@ -56,26 +68,80 @@ public class SignClickListener implements Listener {
* *
* @param sign <p>The sign to print</p> * @param sign <p>The sign to print</p>
* @param player <p>The player to display the contents to</p> * @param player <p>The player to display the contents to</p>
* @param raw <p>Whether to get the raw text with used formatting codes</p>
*/ */
private void printSign(@NotNull Sign sign, @NotNull Player player) { private void printSign(@NotNull Sign sign, @NotNull Player player, boolean raw) {
StringBuilder builder = new StringBuilder(); SignSide front = sign.getSide(Side.FRONT);
getSignText(sign.getSide(Side.FRONT), "Front:", builder); SignSide back = sign.getSide(Side.BACK);
getSignText(sign.getSide(Side.BACK), "Back:", builder); String frontLines = getSignText(front, raw);
player.sendMessage(builder.toString()); String backLines = getSignText(back, raw);
StringFormatter stringFormatter = PlaceholderSigns.getInstance().getStringFormatter();
StringReplacer replacer = new StringReplacer(stringFormatter.getUnformattedColoredMessage(
PlaceholderSignMessage.SUCCESS_SIGN_CONTENTS));
replacer.add("{frontLines}", frontLines);
replacer.add("{backLines}", backLines);
replacer.add("{frontDye}", getDye(front));
replacer.add("{frontGlow}", getGlow(front));
replacer.add("{backDye}", getDye(back));
replacer.add("{backGlow}", getGlow(back));
player.sendMessage(replacer.replace());
}
/**
* Gets a description of the glow of a sign
*
* @param signSide <p>The sign side to get the dye of</p>
* @return <p>The description of the applied dye</p>
*/
@NotNull
private String getGlow(@NotNull SignSide signSide) {
boolean glowing = signSide.isGlowingText();
StringFormatter stringFormatter = PlaceholderSigns.getInstance().getStringFormatter();
if (glowing) {
return stringFormatter.getUnformattedColoredMessage(PlaceholderSignMessage.GLOWING_CONFIRM);
} else {
return stringFormatter.getUnformattedColoredMessage(PlaceholderSignMessage.GLOWING_DENY);
}
}
/**
* Gets a description of a dye applied to a sign
*
* @param signSide <p>The sign side to get the dye of</p>
* @return <p>The description of the applied dye</p>
*/
@NotNull
private String getDye(@NotNull SignSide signSide) {
DyeColor dyeColor = signSide.getColor();
if (dyeColor == null) {
return "None";
}
ChatColor color = ColorHelper.fromColor(dyeColor.getColor());
return color + signSide.getColor().name();
} }
/** /**
* Gets text from a sign side, and appends it to the given string builder * Gets text from a sign side, and appends it to the given string builder
* *
* @param signSide <p>The sign side to get text from</p> * @param signSide <p>The sign side to get text from</p>
* @param header <p>The header to display before printing the sign test</p> * @param raw <p>Whether to get the raw text with used formatting codes</p>
* @param builder <p>The string builder to append the text to</p>
*/ */
private void getSignText(@NotNull SignSide signSide, @NotNull String header, @NotNull StringBuilder builder) { @NotNull
builder.append(header).append("\n"); private String getSignText(@NotNull SignSide signSide, boolean raw) {
StringBuilder output = new StringBuilder();
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
builder.append(signSide.getLine(i)).append("\n"); output.append(i + 1).append(". ");
String line = signSide.getLine(i);
if (raw) {
output.append(line.replace(ChatColor.COLOR_CHAR, '&'));
} else {
output.append(line);
} }
output.append("\n");
}
return output.toString();
} }
/** /**
@ -107,11 +173,12 @@ public class SignClickListener implements Listener {
// Update the sign with the new text // Update the sign with the new text
String[] finalLines = changeEvent.getLines(); String[] finalLines = changeEvent.getLines();
for (int i = 0; i < finalLines.length; i++) { for (int i = 0; i < finalLines.length; i++) {
signSide.setLine(i, ColorHelper.translateAllColorCodes(finalLines[i])); signSide.setLine(i, ColorHelper.translateColorCodes(finalLines[i], ColorConversion.RGB));
} }
sign.update(); sign.update();
player.sendMessage("The sign line was successfully changed."); PlaceholderSigns.getInstance().getStringFormatter().displaySuccessMessage(player,
PlaceholderSignMessage.SUCCESS_SIGN_CHANGED);
} }
} }

View File

@ -0,0 +1,103 @@
package net.knarcraft.placeholdersigns.runnable;
import me.clip.placeholderapi.PlaceholderAPI;
import net.knarcraft.knarlib.property.ColorConversion;
import net.knarcraft.knarlib.util.ColorHelper;
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
import org.bukkit.Location;
import org.bukkit.block.Sign;
import org.bukkit.block.sign.Side;
import org.bukkit.block.sign.SignSide;
import org.jetbrains.annotations.NotNull;
import java.util.Map;
/**
* A runnable that updates signs
*/
public class SignUpdate implements Runnable {
private final @NotNull PlaceholderSignHandler signHandler;
/**
* Instantiates a new sign update runnable
*
* @param signHandler <p>The sign handler to get signs from</p>
*/
public SignUpdate(@NotNull PlaceholderSignHandler signHandler) {
this.signHandler = signHandler;
}
@Override
public void run() {
for (PlaceholderSign placeholderSign : signHandler.getSigns()) {
// Ignore signs away from players
Location location = placeholderSign.location();
if (!location.getChunk().isLoaded()) {
continue;
}
// If no longer a sign, remove
if (!(location.getBlock().getState() instanceof Sign sign)) {
signHandler.unregisterSign(placeholderSign);
continue;
}
// Update placeholders
SignSide front = sign.getSide(Side.FRONT);
SignSide back = sign.getSide(Side.BACK);
Map<Side, Map<Integer, String>> placeholders = placeholderSign.placeholders();
String[] frontLines = front.getLines();
String[] backLines = back.getLines();
// Only update the sign if the text has changed
boolean updateNecessary = false;
if (placeholders.get(Side.FRONT) != null) {
updateNecessary |= updatePlaceholders(frontLines, placeholders.get(Side.FRONT), front);
}
if (placeholders.get(Side.BACK) != null) {
updateNecessary |= updatePlaceholders(backLines, placeholders.get(Side.BACK), back);
}
if (updateNecessary) {
sign.update();
}
}
}
/**
* Updates the values of placeholders on a sign
*
* @param lines <p>The sign's current lines</p>
* @param placeholders <p>The sign's original placeholder lines</p>
* @param signSide <p>The side of the sign to update placeholders for</p>
* @return <p>True if text has been changed, and the sign needs to be updated</p>
*/
private boolean updatePlaceholders(@NotNull String[] lines, @NotNull Map<Integer, String> placeholders,
@NotNull SignSide signSide) {
boolean changed = false;
for (int i = 0; i < lines.length; i++) {
String oldText = signSide.getLine(i);
// The new text of the sign is either the same, or the original placeholder
String newText;
if (!placeholders.containsKey(i) || placeholders.get(i) == null) {
newText = oldText;
} else {
newText = PlaceholderAPI.setPlaceholders(null, placeholders.get(i));
}
// Convert color codes
newText = ColorHelper.translateColorCodes(newText, ColorConversion.RGB);
// Only change the line if the text has changed
if (!newText.equals(oldText)) {
signSide.setLine(i, newText);
changed = true;
}
}
return changed;
}
}

View File

@ -1,34 +0,0 @@
package net.knarcraft.placeholdersigns.util;
import net.md_5.bungee.api.ChatColor;
import org.jetbrains.annotations.NotNull;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A helper class for dealing with colors and formatting codes
*/
public final class ColorHelper {
private ColorHelper() {
}
/**
* Translates all found color codes to formatting in a string
*
* @param message <p>The string to search for color codes</p>
* @return <p>The message with color codes translated</p>
*/
public static String translateAllColorCodes(@NotNull String message) {
message = ChatColor.translateAlternateColorCodes('&', message);
Pattern pattern = Pattern.compile("&?(#[a-fA-F0-9]{6})");
Matcher matcher = pattern.matcher(message);
while (matcher.find()) {
message = message.replace(matcher.group(), "" + ChatColor.of(matcher.group(1)));
}
return message;
}
}

View File

@ -0,0 +1,2 @@
# The chosen language for PlaceholderSigns. You can use "en" or any custom language specified in strings.yml
language: en

View File

@ -14,6 +14,10 @@ commands:
usage: /<command> usage: /<command>
permission: placeholdersigns.view permission: placeholdersigns.view
description: Displays the contents of a sign in the chat (useful for lines exceeding the viewable area) description: Displays the contents of a sign in the chat (useful for lines exceeding the viewable area)
viewSignRaw:
usage: /<command>
permission: placeholdersigns.view
description: Displays the raw contents of a sign in the chat (useful for lines exceeding the viewable area, or to see formatting used)
permissions: permissions:
placeholdersigns.*: placeholdersigns.*:

View File

@ -0,0 +1,15 @@
en:
SUCCESS_CLICK_SIGN_TO_EDIT: "Please click the sign you want to change."
SUCCESS_CLICK_SIGN_TO_VIEW: "Please click the sign you want to view."
ERROR_WAXED_NO_PERMISSION: "You do not have the necessary permissions to edit a waxed sign."
SUCCESS_SIGN_CHANGED: "The sign line was successfully changed."
SUCCESS_SIGN_CONTENTS: |
#17A057Front:&r
{frontLines}
#8899A5Dye&r {frontDye}&r, #8899A5Glowing&r {frontGlow}&r
#A01760Back:&r
{backLines}
#8899A5Dye&r {backDye}&r, #8899A5Glowing&r {backGlow}&r
GLOWING_CONFIRM: "#FDFFC8Yes"
GLOWING_DENY: "#CAC8FFNo"