Implements #1
All checks were successful
KnarCraft/PlaceholderSigns/pipeline/head This commit looks good
All checks were successful
KnarCraft/PlaceholderSigns/pipeline/head This commit looks good
This commit is contained in:
parent
a34c63b7e2
commit
f8ca5705a5
18
README.md
18
README.md
@ -21,13 +21,14 @@ Note that commands have some restrictions in place, so giving the weakest permis
|
||||
- All sign changes are run through the SignChangeEvent, so the player cannot edit a sign if any protection plugin would
|
||||
prevent them from editing the sign normally.
|
||||
|
||||
| Command | Arguments | Description |
|
||||
|---------------|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| /setSignLine | \<line> \<text> \<text> ... | Sets the text of the sign line (1-4) to the given input. Then right-click the sign to update. |
|
||||
| /viewSign | \[raw true/false] \[placeholders true/false] | Shows the full contents and details of the sign you are currently looking at. If "raw" is true, formatting codes are displayed. If placeholders is true, stored placeholders are displayed. |
|
||||
| /copySign | | Copies the sign you are currently looking at to another sign, including placeholders, formatting codes, dye and waxed state. |
|
||||
| /copySignText | \[side] \[source line] \[target line] | Copies the text of the sign you are currently looking at to another sign, including placeholders and formatting codes. If no argument is given, both sides are copied, and the front text is copies to the side of the target sign you click. If a side is specified, the text of that side is copied, and pasted to the sign side you click (use `this` as the sign side to select the side you are looking at when executing the command). The source line argument is used to only copy a single line from the selected sign side. The target line argument is used to specify the line to paste to (defaults to same as the source line) on the clicked side. |
|
||||
| /unWaxSign | | Removes the wax from the sign you are currently looking at. |
|
||||
| Command | Arguments | Description |
|
||||
|----------------------------|----------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| /setSignLine | \<line> \<text> \<text> ... | Sets the text of the sign line (1-4) to the given input. Then right-click the sign to update. |
|
||||
| /viewSign | \[raw true/false] \[placeholders true/false] | Shows the full contents and details of the sign you are currently looking at. If "raw" is true, formatting codes are displayed. If placeholders is true, stored placeholders are displayed. |
|
||||
| /copySign | | Copies the sign you are currently looking at to another sign, including placeholders, formatting codes, dye and waxed state. |
|
||||
| /copySignText | \[side] \[source line] \[target line] | Copies the text of the sign you are currently looking at to another sign, including placeholders and formatting codes. If no argument is given, both sides are copied, and the front text is copies to the side of the target sign you click. If a side is specified, the text of that side is copied, and pasted to the sign side you click (use `this` as the sign side to select the side you are looking at when executing the command). The source line argument is used to only copy a single line from the selected sign side. The target line argument is used to specify the line to paste to (defaults to same as the source line) on the clicked side. |
|
||||
| /unWaxSign | | Removes the wax from the sign you are currently looking at. |
|
||||
| /setPlaceholderUpdateDelay | \<delay> | Sets the update delay in ticks for the placeholder sign you are currently looking at. Use "null" to un-set the value. 1 second = 20 ticks. |
|
||||
|
||||
## Permissions
|
||||
|
||||
@ -43,4 +44,5 @@ Note that commands have some restrictions in place, so giving the weakest permis
|
||||
| placeholdersigns.copy | false | Allows unrestricted use of the /copySign and /copySignText commands. |
|
||||
| placeholdersigns.copy.use | false | Allows use of the /copySign and /copySignText commands. |
|
||||
| placeholdersigns.copy.bypass-waxed | false | Allows pasting a sign copied with /copySign and /copySignText onto a waxed sign. |
|
||||
| placeholdersigns.unwax | false | Allows use of the /unWaxSign command |
|
||||
| placeholdersigns.unwax | false | Allows use of the /unWaxSign command |
|
||||
| placeholdersigns.setdelay | false | Allows use of the /setPlaceholderUpdateDelay command |
|
@ -6,11 +6,14 @@ 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.SetPlaceholderUpdateDelayCommand;
|
||||
import net.knarcraft.placeholdersigns.command.UnWaxSignCommand;
|
||||
import net.knarcraft.placeholdersigns.command.ViewSignCommand;
|
||||
import net.knarcraft.placeholdersigns.config.PlaceholderSignMessage;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignRequestHandler;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignUpdateQueueHandler;
|
||||
import net.knarcraft.placeholdersigns.listener.ChunkListener;
|
||||
import net.knarcraft.placeholdersigns.listener.SignBreakListener;
|
||||
import net.knarcraft.placeholdersigns.listener.SignClickListener;
|
||||
import net.knarcraft.placeholdersigns.listener.SignTextListener;
|
||||
@ -18,6 +21,7 @@ import net.knarcraft.placeholdersigns.runnable.SignUpdate;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
import org.bukkit.command.PluginCommand;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@ -31,7 +35,9 @@ public final class PlaceholderSigns extends JavaPlugin {
|
||||
private static PlaceholderSigns instance;
|
||||
private PlaceholderSignHandler signHandler;
|
||||
private PlaceholderSignRequestHandler requestHandler;
|
||||
private PlaceholderSignUpdateQueueHandler updateQueueHandler;
|
||||
private StringFormatter stringFormatter;
|
||||
private int signUpdateDelay;
|
||||
|
||||
/**
|
||||
* Gets an instance of this plugin
|
||||
@ -53,21 +59,51 @@ public final class PlaceholderSigns extends JavaPlugin {
|
||||
return this.signHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this instance's placeholder sign request handler
|
||||
*
|
||||
* @return <p>The request handler</p>
|
||||
*/
|
||||
@NotNull
|
||||
public PlaceholderSignRequestHandler getRequestHandler() {
|
||||
return this.requestHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets this instance's update queue handler
|
||||
*
|
||||
* @return <p>The update queue handler</p>
|
||||
*/
|
||||
@NotNull
|
||||
public PlaceholderSignUpdateQueueHandler getUpdateQueueHandler() {
|
||||
return this.updateQueueHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the string formatter to use for formatting messages
|
||||
*
|
||||
* @return <p>The string formatter</p>
|
||||
*/
|
||||
@NotNull
|
||||
public StringFormatter getStringFormatter() {
|
||||
return this.stringFormatter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default sign update delay
|
||||
*
|
||||
* @return <p>The sign update delay</p>
|
||||
*/
|
||||
public int getSignUpdateDelay() {
|
||||
return this.signUpdateDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
instance = this;
|
||||
getConfig().options().copyDefaults(true);
|
||||
saveConfig();
|
||||
|
||||
Translator translator = new Translator();
|
||||
translator.registerMessageCategory(PlaceholderSignMessage.SUCCESS_CLICK_SIGN_TO_EDIT);
|
||||
translator.setColorConversion(ColorConversion.RGB);
|
||||
@ -77,9 +113,15 @@ public final class PlaceholderSigns extends JavaPlugin {
|
||||
this.stringFormatter.setNamePrefix("#A5682A[&r&l");
|
||||
this.stringFormatter.setNameSuffix("&r#A5682A]");
|
||||
|
||||
signUpdateDelay = getConfig().getInt("defaultSignUpdateTicks", 100);
|
||||
if (signUpdateDelay < 1) {
|
||||
signUpdateDelay = 100;
|
||||
}
|
||||
|
||||
this.signHandler = new PlaceholderSignHandler();
|
||||
this.signHandler.load();
|
||||
this.requestHandler = new PlaceholderSignRequestHandler();
|
||||
this.updateQueueHandler = new PlaceholderSignUpdateQueueHandler();
|
||||
|
||||
if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) {
|
||||
getLogger().log(Level.WARNING, "Could not find PlaceholderAPI! This plugin is required.");
|
||||
@ -87,18 +129,20 @@ public final class PlaceholderSigns extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
// Update signs' placeholders every second
|
||||
Bukkit.getScheduler().runTaskTimer(this, new SignUpdate(this.signHandler), 20 * 10, 20 * 5);
|
||||
Bukkit.getScheduler().runTaskTimer(this, new SignUpdate(this.signHandler), 20, 1);
|
||||
|
||||
Bukkit.getPluginManager().registerEvents(new SignBreakListener(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new SignTextListener(), this);
|
||||
Bukkit.getPluginManager().registerEvents(new SignClickListener(), this);
|
||||
PluginManager pluginManager = Bukkit.getPluginManager();
|
||||
pluginManager.registerEvents(new SignBreakListener(), this);
|
||||
pluginManager.registerEvents(new SignTextListener(), this);
|
||||
pluginManager.registerEvents(new SignClickListener(), this);
|
||||
pluginManager.registerEvents(new ChunkListener(), this);
|
||||
|
||||
registerCommand("setSignLine", new EditSignCommand());
|
||||
registerCommand("viewSign", new ViewSignCommand());
|
||||
registerCommand("copySign", new CopySignCommand());
|
||||
registerCommand("unWaxSign", new UnWaxSignCommand());
|
||||
registerCommand("copySignText", new CopySignTextCommand());
|
||||
registerCommand("setPlaceholderUpdateDelay", new SetPlaceholderUpdateDelayCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,77 @@
|
||||
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.PlaceholderSign;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
|
||||
import net.knarcraft.placeholdersigns.util.TabCompleteHelper;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.Sign;
|
||||
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;
|
||||
|
||||
public class SetPlaceholderUpdateDelayCommand 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;
|
||||
}
|
||||
|
||||
if (arguments.length < 1) {
|
||||
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;
|
||||
}
|
||||
|
||||
Integer updateDelay = null;
|
||||
try {
|
||||
updateDelay = Integer.parseInt(arguments[0]);
|
||||
} catch (NumberFormatException exception) {
|
||||
if (!arguments[0].equalsIgnoreCase("null")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PlaceholderSignHandler signHandler = placeholderSigns.getSignHandler();
|
||||
PlaceholderSign placeholderSign = signHandler.getFromLocation(sign.getLocation());
|
||||
if (placeholderSign != null) {
|
||||
placeholderSign.setUpdateDelay(updateDelay);
|
||||
signHandler.save();
|
||||
stringFormatter.displaySuccessMessage(player, PlaceholderSignMessage.SUCCESS_UPDATE_DELAY_CHANGED);
|
||||
return true;
|
||||
} else {
|
||||
stringFormatter.displayErrorMessage(player, PlaceholderSignMessage.ERROR_NOT_LOOKING_AT_PLACEHOLDER_SIGN);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
|
||||
@NotNull String[] arguments) {
|
||||
if (arguments.length == 1) {
|
||||
return TabCompletionHelper.filterMatchingStartsWith(TabCompleteHelper.getDelays(), arguments[0]);
|
||||
} else {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -160,7 +160,7 @@ public class ViewSignCommand implements TabExecutor {
|
||||
return getSignText(lines, raw);
|
||||
}
|
||||
|
||||
Map<Integer, String> placeholders = placeholderSign.placeholders().get(side);
|
||||
Map<Integer, String> placeholders = placeholderSign.getPlaceholders().get(side);
|
||||
if (placeholders != null) {
|
||||
for (Map.Entry<Integer, String> entry : placeholders.entrySet()) {
|
||||
lines[entry.getKey()] = entry.getValue();
|
||||
|
@ -67,6 +67,16 @@ public enum PlaceholderSignMessage implements TranslatableMessage {
|
||||
* The message displayed when a sign has been successfully un-waxed
|
||||
*/
|
||||
SUCCESS_SIGN_UN_WAXED,
|
||||
|
||||
/**
|
||||
* The message displayed when the player isn't looking at a placeholder sign when required
|
||||
*/
|
||||
ERROR_NOT_LOOKING_AT_PLACEHOLDER_SIGN,
|
||||
|
||||
/**
|
||||
* The message displayed when a placeholder sign update delay has been changed
|
||||
*/
|
||||
SUCCESS_UPDATE_DELAY_CHANGED,
|
||||
;
|
||||
|
||||
@Override
|
||||
|
@ -3,15 +3,78 @@ package net.knarcraft.placeholdersigns.container;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.sign.Side;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A sign containing one or more placeholders
|
||||
*
|
||||
* @param location <p>The location of the sign</p>
|
||||
* @param placeholders <p>The original placeholders typed on the sign</p>
|
||||
*/
|
||||
public record PlaceholderSign(@NotNull Location location, @NotNull Map<Side, Map<Integer, String>> placeholders) {
|
||||
public final class PlaceholderSign {
|
||||
|
||||
private final @NotNull Location location;
|
||||
private final @NotNull Map<Side, Map<Integer, String>> placeholders;
|
||||
private @Nullable Integer updateDelay;
|
||||
|
||||
/**
|
||||
* Instantiates a new placeholder sign
|
||||
*
|
||||
* @param location <p>The location of the sign</p>
|
||||
* @param placeholders <p>The original placeholders typed on the sign</p>
|
||||
* @param updateDelay <p>The delay in ticks between each time this sign's placeholders are updated</p>
|
||||
*/
|
||||
public PlaceholderSign(@NotNull Location location, @NotNull Map<Side, Map<Integer, String>> placeholders,
|
||||
@Nullable Integer updateDelay) {
|
||||
this.location = location;
|
||||
this.placeholders = placeholders;
|
||||
this.updateDelay = updateDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the location of this placeholder sign
|
||||
*
|
||||
* @return <p>The location of this placeholder sign</p>
|
||||
*/
|
||||
@NotNull
|
||||
public Location getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the placeholders stored on this sign
|
||||
*
|
||||
* @return <p>The stored placeholders</p>
|
||||
*/
|
||||
@NotNull
|
||||
public Map<Side, Map<Integer, String>> getPlaceholders() {
|
||||
return placeholders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the update delay for this placeholder sign
|
||||
*
|
||||
* @return <p>The update delay</p>
|
||||
*/
|
||||
@Nullable
|
||||
public Integer getUpdateDelay() {
|
||||
return updateDelay;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the update delay for this placeholder sign
|
||||
*
|
||||
* @param updateDelay <p>The new update delay</p>
|
||||
*/
|
||||
public void setUpdateDelay(@Nullable Integer updateDelay) {
|
||||
this.updateDelay = updateDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@NotNull Object object) {
|
||||
if (object instanceof PlaceholderSign otherSign) {
|
||||
return this.location.equals(otherSign.location);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,19 @@
|
||||
package net.knarcraft.placeholdersigns.container;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* A placeholder sign that's queued to be updated
|
||||
*
|
||||
* @param placeholderSign <p>The queued placeholder sign</p>
|
||||
* @param updateTimestamp <p>The timestamp (long milliseconds) that the placeholder sign should be updated at</p>
|
||||
*/
|
||||
public record QueuedPlaceholderSign(@NotNull PlaceholderSign placeholderSign,
|
||||
long updateTimestamp) implements Comparable<QueuedPlaceholderSign> {
|
||||
|
||||
@Override
|
||||
public int compareTo(@NotNull QueuedPlaceholderSign other) {
|
||||
return Long.compare(this.updateTimestamp, other.updateTimestamp);
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,7 @@ package net.knarcraft.placeholdersigns.handler;
|
||||
import net.knarcraft.placeholdersigns.PlaceholderSigns;
|
||||
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Chunk;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.sign.Side;
|
||||
@ -29,15 +30,7 @@ public class PlaceholderSignHandler {
|
||||
|
||||
private Set<PlaceholderSign> placeholderSigns;
|
||||
private Map<Location, PlaceholderSign> locationLookup;
|
||||
|
||||
/**
|
||||
* Gets all registered signs
|
||||
*
|
||||
* @return <p>All registered signs</p>
|
||||
*/
|
||||
public @NotNull Set<PlaceholderSign> getSigns() {
|
||||
return new HashSet<>(placeholderSigns);
|
||||
}
|
||||
private Map<Chunk, Set<PlaceholderSign>> signsInChunk;
|
||||
|
||||
/**
|
||||
* Gets a placeholder sign from the given location
|
||||
@ -57,8 +50,11 @@ public class PlaceholderSignHandler {
|
||||
*/
|
||||
public void registerSign(@NotNull PlaceholderSign sign) {
|
||||
this.placeholderSigns.add(sign);
|
||||
locationLookup.put(sign.location(), sign);
|
||||
save();
|
||||
this.locationLookup.put(sign.getLocation(), sign);
|
||||
|
||||
Chunk chunk = sign.getLocation().getChunk();
|
||||
this.signsInChunk.putIfAbsent(chunk, new HashSet<>());
|
||||
this.signsInChunk.get(chunk).add(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -67,9 +63,24 @@ public class PlaceholderSignHandler {
|
||||
* @param sign <p>The sign to un-register</p>
|
||||
*/
|
||||
public void unregisterSign(@NotNull PlaceholderSign sign) {
|
||||
locationLookup.remove(sign.location());
|
||||
this.locationLookup.remove(sign.getLocation());
|
||||
this.placeholderSigns.remove(sign);
|
||||
save();
|
||||
this.signsInChunk.get(sign.getLocation().getChunk()).remove(sign);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all placeholder signs in the given chunk
|
||||
*
|
||||
* @param chunk <p>The chunk to check</p>
|
||||
* @return <p>All placeholder signs in the chunk</p>
|
||||
*/
|
||||
@NotNull
|
||||
public Set<PlaceholderSign> getFromChunk(@NotNull Chunk chunk) {
|
||||
if (this.signsInChunk.containsKey(chunk)) {
|
||||
return this.signsInChunk.get(chunk);
|
||||
} else {
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,6 +89,7 @@ public class PlaceholderSignHandler {
|
||||
public void load() {
|
||||
this.placeholderSigns = new HashSet<>();
|
||||
this.locationLookup = new HashMap<>();
|
||||
this.signsInChunk = new HashMap<>();
|
||||
|
||||
YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
|
||||
ConfigurationSection signSection = configuration.getConfigurationSection("signs");
|
||||
@ -104,9 +116,16 @@ public class PlaceholderSignHandler {
|
||||
allPlaceholders.put(Side.FRONT, frontPlaceholders);
|
||||
allPlaceholders.put(Side.BACK, backPlaceholders);
|
||||
|
||||
PlaceholderSign sign = new PlaceholderSign(signLocation, allPlaceholders);
|
||||
this.placeholderSigns.add(sign);
|
||||
this.locationLookup.put(signLocation, sign);
|
||||
String updateDelayKey = key + ".updateDelay";
|
||||
int updateDelay = -1;
|
||||
if (signSection.contains(updateDelayKey)) {
|
||||
updateDelay = signSection.getInt(updateDelayKey, -1);
|
||||
}
|
||||
if (updateDelay < 1) {
|
||||
updateDelay = PlaceholderSigns.getInstance().getSignUpdateDelay();
|
||||
}
|
||||
|
||||
registerSign(new PlaceholderSign(signLocation, allPlaceholders, updateDelay));
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,7 +172,7 @@ public class PlaceholderSignHandler {
|
||||
* @param sign <p>The sign to save</p>
|
||||
*/
|
||||
private void saveSign(@NotNull ConfigurationSection section, @NotNull PlaceholderSign sign) {
|
||||
Location location = sign.location();
|
||||
Location location = sign.getLocation();
|
||||
if (location.getWorld() == null) {
|
||||
return;
|
||||
}
|
||||
@ -163,19 +182,21 @@ public class PlaceholderSignHandler {
|
||||
String frontKey = key + ".placeholders.front";
|
||||
String backKey = key + ".placeholders.back";
|
||||
|
||||
Map<Integer, String> frontPlaceholders = sign.placeholders().get(Side.FRONT);
|
||||
Map<Integer, String> frontPlaceholders = sign.getPlaceholders().get(Side.FRONT);
|
||||
if (frontPlaceholders != null) {
|
||||
for (Map.Entry<Integer, String> entry : frontPlaceholders.entrySet()) {
|
||||
section.set(frontKey + "." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
Map<Integer, String> backPlaceholders = sign.placeholders().get(Side.BACK);
|
||||
Map<Integer, String> backPlaceholders = sign.getPlaceholders().get(Side.BACK);
|
||||
if (backPlaceholders != null) {
|
||||
for (Map.Entry<Integer, String> entry : backPlaceholders.entrySet()) {
|
||||
section.set(backKey + "." + entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
section.set(key + ".updateDelay", sign.getUpdateDelay());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,77 @@
|
||||
package net.knarcraft.placeholdersigns.handler;
|
||||
|
||||
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
|
||||
import net.knarcraft.placeholdersigns.container.QueuedPlaceholderSign;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.PriorityQueue;
|
||||
|
||||
/**
|
||||
* A handler for dealing with the placeholder sign update queue
|
||||
*/
|
||||
public class PlaceholderSignUpdateQueueHandler {
|
||||
|
||||
private final PriorityQueue<QueuedPlaceholderSign> signUpdateQueue;
|
||||
|
||||
/**
|
||||
* Instantiates a new placeholder sign update queue handler
|
||||
*/
|
||||
public PlaceholderSignUpdateQueueHandler() {
|
||||
this.signUpdateQueue = new PriorityQueue<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Polls the queue for any placeholder signs due for update
|
||||
*
|
||||
* <p>No placeholder sign will be returned unless they are due to be updated.</p>
|
||||
*
|
||||
* @return <p>The next queued placeholder sign, or null if no such placeholder sign exists</p>
|
||||
*/
|
||||
@Nullable
|
||||
public PlaceholderSign pollQueue() {
|
||||
QueuedPlaceholderSign nextSign = signUpdateQueue.peek();
|
||||
if (nextSign == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (nextSign.updateTimestamp() < currentTime) {
|
||||
nextSign = signUpdateQueue.poll();
|
||||
if (nextSign != null) {
|
||||
return nextSign.placeholderSign();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Peeks at the next item in the queue
|
||||
*
|
||||
* @return <p>The next item in the queue, or null if empty</p>
|
||||
*/
|
||||
@Nullable
|
||||
public QueuedPlaceholderSign peekQueue() {
|
||||
return signUpdateQueue.peek();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the specified queued sign to the queue
|
||||
*
|
||||
* @param queuedSign <p>The queued sign to queue</p>
|
||||
*/
|
||||
public void queueSign(@NotNull QueuedPlaceholderSign queuedSign) {
|
||||
this.signUpdateQueue.add(queuedSign);
|
||||
}
|
||||
|
||||
/**
|
||||
* '
|
||||
* Removes the specified placeholder sign from the queue
|
||||
*
|
||||
* @param placeholderSign <p>The placeholder sign to remove</p>
|
||||
*/
|
||||
public void unQueueSign(@NotNull PlaceholderSign placeholderSign) {
|
||||
this.signUpdateQueue.removeIf((item) -> item.placeholderSign().equals(placeholderSign));
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package net.knarcraft.placeholdersigns.listener;
|
||||
|
||||
import net.knarcraft.placeholdersigns.PlaceholderSigns;
|
||||
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
|
||||
import net.knarcraft.placeholdersigns.container.QueuedPlaceholderSign;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.world.ChunkLoadEvent;
|
||||
import org.bukkit.event.world.ChunkUnloadEvent;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* A listener for the loading and unloading of chunks with placeholder signs
|
||||
*/
|
||||
public class ChunkListener implements Listener {
|
||||
|
||||
@EventHandler
|
||||
public void onChunkLoad(@NotNull ChunkLoadEvent event) {
|
||||
PlaceholderSigns instance = PlaceholderSigns.getInstance();
|
||||
Set<PlaceholderSign> signsAtChunk = instance.getSignHandler().getFromChunk(event.getChunk());
|
||||
long queueTime = System.currentTimeMillis();
|
||||
for (PlaceholderSign sign : signsAtChunk) {
|
||||
instance.getUpdateQueueHandler().queueSign(new QueuedPlaceholderSign(sign, queueTime++));
|
||||
}
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
public void onChunkUnload(@NotNull ChunkUnloadEvent event) {
|
||||
PlaceholderSigns instance = PlaceholderSigns.getInstance();
|
||||
Set<PlaceholderSign> signsAtChunk = instance.getSignHandler().getFromChunk(event.getChunk());
|
||||
for (PlaceholderSign sign : signsAtChunk) {
|
||||
instance.getUpdateQueueHandler().unQueueSign(sign);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -27,6 +27,7 @@ public class SignBreakListener implements Listener {
|
||||
PlaceholderSign sign = signHandler.getFromLocation(block.getLocation());
|
||||
if (sign != null) {
|
||||
signHandler.unregisterSign(sign);
|
||||
signHandler.save();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,7 @@ public class SignClickListener implements Listener {
|
||||
|
||||
String text = signTextCopyRequest.sign().getSide(signTextCopyRequest.side()).getLine(sourceLine);
|
||||
if (sourcePlaceholderSign != null) {
|
||||
Map<Side, Map<Integer, String>> placeholders = sourcePlaceholderSign.placeholders();
|
||||
Map<Side, Map<Integer, String>> placeholders = sourcePlaceholderSign.getPlaceholders();
|
||||
if (placeholders.containsKey(sourceSide) && placeholders.get(sourceSide).containsKey(sourceLine)) {
|
||||
text = placeholders.get(sourceSide).get(sourceLine);
|
||||
}
|
||||
@ -162,12 +162,12 @@ public class SignClickListener implements Listener {
|
||||
// Remove old placeholders from the sign side
|
||||
Map<Integer, String> oldPlaceholders = null;
|
||||
if (targetPlaceholderSign != null) {
|
||||
oldPlaceholders = targetPlaceholderSign.placeholders().remove(clickedSide);
|
||||
oldPlaceholders = targetPlaceholderSign.getPlaceholders().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);
|
||||
targetPlaceholderSign.getPlaceholders().put(clickedSide, oldPlaceholders);
|
||||
}
|
||||
|
||||
// Save any placeholder changes
|
||||
@ -307,7 +307,7 @@ public class SignClickListener implements Listener {
|
||||
@NotNull Player player) {
|
||||
String[] sideLines = signSide.getLines();
|
||||
if (placeholderSign != null) {
|
||||
Map<Side, Map<Integer, String>> placeholders = placeholderSign.placeholders();
|
||||
Map<Side, Map<Integer, String>> placeholders = placeholderSign.getPlaceholders();
|
||||
loadPlaceholders(sourceSide, sideLines, placeholders);
|
||||
}
|
||||
|
||||
@ -385,7 +385,7 @@ public class SignClickListener implements Listener {
|
||||
String oldPlaceholder = null;
|
||||
if (targetPlaceholderSign != null) {
|
||||
// Remove the old placeholder
|
||||
oldPlaceholder = targetPlaceholderSign.placeholders().get(targetSide).remove(destinationLine);
|
||||
oldPlaceholder = targetPlaceholderSign.getPlaceholders().get(targetSide).remove(destinationLine);
|
||||
}
|
||||
|
||||
lines[destinationLine] = newText;
|
||||
@ -396,7 +396,7 @@ public class SignClickListener implements Listener {
|
||||
if (changeEvent.isCancelled()) {
|
||||
if (targetPlaceholderSign != null) {
|
||||
// Restore the old placeholder if the action didn't complete
|
||||
targetPlaceholderSign.placeholders().get(targetSide).put(destinationLine, oldPlaceholder);
|
||||
targetPlaceholderSign.getPlaceholders().get(targetSide).put(destinationLine, oldPlaceholder);
|
||||
}
|
||||
PlaceholderSigns.getInstance().getStringFormatter().displayErrorMessage(player,
|
||||
PlaceholderSignMessage.ERROR_CANCELLED_BY_PROTECTION);
|
||||
|
@ -61,11 +61,12 @@ public class SignTextListener implements Listener {
|
||||
placeholderSide.put(event.getSide(), placeholders);
|
||||
|
||||
// Register a new placeholder sign
|
||||
PlaceholderSign placeholderSign = new PlaceholderSign(event.getBlock().getLocation(), placeholderSide);
|
||||
PlaceholderSign placeholderSign = new PlaceholderSign(event.getBlock().getLocation(), placeholderSide, null);
|
||||
signHandler.registerSign(placeholderSign);
|
||||
signHandler.save();
|
||||
} else if (!placeholders.isEmpty()) {
|
||||
// Overwrite the placeholders of the existing placeholder sign
|
||||
Map<Integer, String> existing = existingSign.placeholders().computeIfAbsent(event.getSide(), k -> new HashMap<>());
|
||||
Map<Integer, String> existing = existingSign.getPlaceholders().computeIfAbsent(event.getSide(), k -> new HashMap<>());
|
||||
existing.putAll(placeholders);
|
||||
signHandler.save();
|
||||
}
|
||||
|
@ -3,8 +3,11 @@ 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.PlaceholderSigns;
|
||||
import net.knarcraft.placeholdersigns.container.PlaceholderSign;
|
||||
import net.knarcraft.placeholdersigns.container.QueuedPlaceholderSign;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
|
||||
import net.knarcraft.placeholdersigns.handler.PlaceholderSignUpdateQueueHandler;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.sign.Side;
|
||||
@ -31,40 +34,67 @@ public class SignUpdate implements Runnable {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
for (PlaceholderSign placeholderSign : signHandler.getSigns()) {
|
||||
// Ignore signs away from players
|
||||
Location location = placeholderSign.location();
|
||||
if (!location.getChunk().isLoaded()) {
|
||||
continue;
|
||||
PlaceholderSigns instance = PlaceholderSigns.getInstance();
|
||||
PlaceholderSignUpdateQueueHandler queueHandler = instance.getUpdateQueueHandler();
|
||||
|
||||
long startTime = System.nanoTime();
|
||||
long currentTime = System.currentTimeMillis();
|
||||
while (queueHandler.peekQueue() != null && System.nanoTime() - startTime < 25000000) {
|
||||
PlaceholderSign placeholderSign = instance.getUpdateQueueHandler().pollQueue();
|
||||
if (placeholderSign == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
updatePlaceholderSign(placeholderSign, currentTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the contents of a single placeholder sign
|
||||
*
|
||||
* @param placeholderSign <p>The placeholder sign to update</p>
|
||||
* @param currentTime <p>The current time, used for re-queuing the sign</p>
|
||||
*/
|
||||
private void updatePlaceholderSign(@NotNull PlaceholderSign placeholderSign, long currentTime) {
|
||||
PlaceholderSigns instance = PlaceholderSigns.getInstance();
|
||||
|
||||
// Ignore signs away from players
|
||||
Location location = placeholderSign.getLocation();
|
||||
|
||||
// If no longer a sign, remove
|
||||
if (!(location.getBlock().getState() instanceof Sign sign)) {
|
||||
this.signHandler.unregisterSign(placeholderSign);
|
||||
this.signHandler.save();
|
||||
return;
|
||||
}
|
||||
|
||||
// Update placeholders
|
||||
SignSide front = sign.getSide(Side.FRONT);
|
||||
SignSide back = sign.getSide(Side.BACK);
|
||||
Map<Side, Map<Integer, String>> placeholders = placeholderSign.getPlaceholders();
|
||||
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();
|
||||
}
|
||||
|
||||
Integer updateDelay = placeholderSign.getUpdateDelay();
|
||||
if (updateDelay == null) {
|
||||
updateDelay = instance.getSignUpdateDelay();
|
||||
}
|
||||
|
||||
instance.getUpdateQueueHandler().queueSign(new QueuedPlaceholderSign(placeholderSign, currentTime + (updateDelay * 50)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the values of placeholders on a sign
|
||||
*
|
||||
|
@ -13,6 +13,7 @@ public final class TabCompleteHelper {
|
||||
|
||||
private static final List<String> lineNumbers;
|
||||
private static final List<String> signSides;
|
||||
private static final List<String> updateDelays;
|
||||
|
||||
static {
|
||||
lineNumbers = new ArrayList<>();
|
||||
@ -24,12 +25,24 @@ public final class TabCompleteHelper {
|
||||
for (Side side : Side.values()) {
|
||||
signSides.add(side.name());
|
||||
}
|
||||
|
||||
updateDelays = List.of("null", "1", "5", "10", "20", "40", "60", "80", "100");
|
||||
}
|
||||
|
||||
private TabCompleteHelper() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets possible sign update delays
|
||||
*
|
||||
* @return <p>Possible sign update delays</p>
|
||||
*/
|
||||
@NotNull
|
||||
public static List<String> getDelays() {
|
||||
return new ArrayList<>(updateDelays);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets possible sign line numbers
|
||||
*
|
||||
|
@ -1,2 +1,8 @@
|
||||
# The chosen language for PlaceholderSigns. You can use "en" or any custom language specified in strings.yml
|
||||
language: en
|
||||
language: en
|
||||
|
||||
# How often to update placeholders by default in ticks. 1 second = 20 ticks. The default is 100 ticks = 5 seconds. Note
|
||||
# that only loaded chunks will have their signs updated to reduce lag and RAM usage from chunk loading. Still, it is
|
||||
# recommended to set this to a higher value, and only reduce the update delay for individual signs where updated
|
||||
# information is critical. 1 is the minimal accepted value.
|
||||
defaultSignUpdateTicks: 100
|
@ -21,6 +21,7 @@ commands:
|
||||
unWaxSign:
|
||||
usage: /<command>
|
||||
permission: placeholdersigns.unwax
|
||||
description: Removes the wax from a waxed sign
|
||||
copySignText:
|
||||
usage: |
|
||||
/<command> [side] [sourceLine] [destinationLine]
|
||||
@ -29,6 +30,10 @@ commands:
|
||||
destinationLine = The destination sign line to overwrite. If not set, it's the same as sourceLine
|
||||
permission: placeholdersigns.copy.use
|
||||
description: Copies all text, or a single line, from one sign to another, either the specified side or both
|
||||
setPlaceholderUpdateDelay:
|
||||
usage: /<command> <delay in ticks>
|
||||
permission: placeholdersigns.setdelay
|
||||
description: Sets the update delay for a placeholder sign
|
||||
|
||||
permissions:
|
||||
placeholdersigns.*:
|
||||
@ -39,6 +44,7 @@ permissions:
|
||||
- placeholdersigns.view
|
||||
- placeholdersigns.copy
|
||||
- placeholdersigns.unwax
|
||||
- placeholdersigns.setdelay
|
||||
default: op
|
||||
placeholdersigns.minimal:
|
||||
description: Allows minimal access to /setSignLine, /copySign, /copySignText and /viewSign
|
||||
@ -78,4 +84,7 @@ permissions:
|
||||
default: false
|
||||
placeholdersigns.unwax:
|
||||
description: Allows a player to use the /unWax command
|
||||
default: false
|
||||
placeholdersigns.setdelay:
|
||||
description: Allows a player to use the /setPlaceholderUpdateDelay command
|
||||
default: false
|
@ -18,4 +18,6 @@ en:
|
||||
SUCCESS_CLICK_SIGN_TO_PASTE: "&7Click the sign you want to paste onto"
|
||||
SUCCESS_SIGN_PASTED: "&7Sign pasted!"
|
||||
ERROR_CANCELLED_BY_PROTECTION: "A protection plugin blocked the sign change"
|
||||
SUCCESS_SIGN_UN_WAXED: "&7The sign was successfully un-waxed"
|
||||
SUCCESS_SIGN_UN_WAXED: "&7The sign was successfully un-waxed"
|
||||
ERROR_NOT_LOOKING_AT_PLACEHOLDER_SIGN: "You are not currently looking at a placeholder sign"
|
||||
SUCCESS_UPDATE_DELAY_CHANGED: "&7The placeholder sign's update delay was successfully updated"
|
Loading…
Reference in New Issue
Block a user