Initial commit
This commit is contained in:
		
							
								
								
									
										113
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,113 @@
 | 
				
			|||||||
 | 
					# User-specific stuff
 | 
				
			||||||
 | 
					.idea/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*.iml
 | 
				
			||||||
 | 
					*.ipr
 | 
				
			||||||
 | 
					*.iws
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# IntelliJ
 | 
				
			||||||
 | 
					out/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Compiled class file
 | 
				
			||||||
 | 
					*.class
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Log file
 | 
				
			||||||
 | 
					*.log
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# BlueJ files
 | 
				
			||||||
 | 
					*.ctxt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Package Files #
 | 
				
			||||||
 | 
					*.jar
 | 
				
			||||||
 | 
					*.war
 | 
				
			||||||
 | 
					*.nar
 | 
				
			||||||
 | 
					*.ear
 | 
				
			||||||
 | 
					*.zip
 | 
				
			||||||
 | 
					*.tar.gz
 | 
				
			||||||
 | 
					*.rar
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
 | 
				
			||||||
 | 
					hs_err_pid*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*~
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# temporary files which can be created if a process still has a handle open of a deleted file
 | 
				
			||||||
 | 
					.fuse_hidden*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# KDE directory preferences
 | 
				
			||||||
 | 
					.directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Linux trash folder which might appear on any partition or disk
 | 
				
			||||||
 | 
					.Trash-*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# .nfs files are created when an open file is removed but is still being accessed
 | 
				
			||||||
 | 
					.nfs*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# General
 | 
				
			||||||
 | 
					.DS_Store
 | 
				
			||||||
 | 
					.AppleDouble
 | 
				
			||||||
 | 
					.LSOverride
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Icon must end with two \r
 | 
				
			||||||
 | 
					Icon
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Thumbnails
 | 
				
			||||||
 | 
					._*
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Files that might appear in the root of a volume
 | 
				
			||||||
 | 
					.DocumentRevisions-V100
 | 
				
			||||||
 | 
					.fseventsd
 | 
				
			||||||
 | 
					.Spotlight-V100
 | 
				
			||||||
 | 
					.TemporaryItems
 | 
				
			||||||
 | 
					.Trashes
 | 
				
			||||||
 | 
					.VolumeIcon.icns
 | 
				
			||||||
 | 
					.com.apple.timemachine.donotpresent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Directories potentially created on remote AFP share
 | 
				
			||||||
 | 
					.AppleDB
 | 
				
			||||||
 | 
					.AppleDesktop
 | 
				
			||||||
 | 
					Network Trash Folder
 | 
				
			||||||
 | 
					Temporary Items
 | 
				
			||||||
 | 
					.apdisk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows thumbnail cache files
 | 
				
			||||||
 | 
					Thumbs.db
 | 
				
			||||||
 | 
					Thumbs.db:encryptable
 | 
				
			||||||
 | 
					ehthumbs.db
 | 
				
			||||||
 | 
					ehthumbs_vista.db
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dump file
 | 
				
			||||||
 | 
					*.stackdump
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Folder config file
 | 
				
			||||||
 | 
					[Dd]esktop.ini
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Recycle Bin used on file shares
 | 
				
			||||||
 | 
					$RECYCLE.BIN/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows Installer files
 | 
				
			||||||
 | 
					*.cab
 | 
				
			||||||
 | 
					*.msi
 | 
				
			||||||
 | 
					*.msix
 | 
				
			||||||
 | 
					*.msm
 | 
				
			||||||
 | 
					*.msp
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Windows shortcuts
 | 
				
			||||||
 | 
					*.lnk
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					target/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pom.xml.tag
 | 
				
			||||||
 | 
					pom.xml.releaseBackup
 | 
				
			||||||
 | 
					pom.xml.versionsBackup
 | 
				
			||||||
 | 
					pom.xml.next
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					release.properties
 | 
				
			||||||
 | 
					dependency-reduced-pom.xml
 | 
				
			||||||
 | 
					buildNumber.properties
 | 
				
			||||||
 | 
					.mvn/timing.properties
 | 
				
			||||||
 | 
					.mvn/wrapper/maven-wrapper.jar
 | 
				
			||||||
 | 
					.flattened-pom.xml
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Common working directory
 | 
				
			||||||
 | 
					run/
 | 
				
			||||||
							
								
								
									
										28
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,28 @@
 | 
				
			|||||||
 | 
					# Placeholder Signs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is a minimal plugin created for a single purpose: Displaying placeholders from PlaceholderAPI on signs. Note that
 | 
				
			||||||
 | 
					this plugin only works for placeholders which do not require a player, as the same text will be displayed to everyone!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					How it works: After installing this plugin, whenever a sign is changed to contain a placeholder replaced by
 | 
				
			||||||
 | 
					PlaceholderAPI, the location of the sign, and the lines containing placeholders are saved. Those lines are updated at a
 | 
				
			||||||
 | 
					set pace by using the saved original lines, and letting PlaceholderAPI replace them. Any color, formatting or RGB color
 | 
				
			||||||
 | 
					codes in the original text will be converted each time the sign is updated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The /editSign command is basically just a command to allow placeholders that won't fit on a sign to be used. As an
 | 
				
			||||||
 | 
					additional benefit, formatting, color and RGB color codes are automatically converted whenever the command is used to
 | 
				
			||||||
 | 
					change sign text.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Note that when clicking a sign after using /editSign, a SignChangeEvent is triggered. This means that the sign text
 | 
				
			||||||
 | 
					won't be changed unless the player passes all world protection checks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Commands
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Command   | Arguments                   | Description                                                                                   |
 | 
				
			||||||
 | 
					|-----------|-----------------------------|-----------------------------------------------------------------------------------------------|
 | 
				
			||||||
 | 
					| /editSign | \<line> \<text> \<text> ... | Sets the text of the sign line (1-4) to the given input. Then right-click the sign to update. |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Permissions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Permission            | Description                             |
 | 
				
			||||||
 | 
					|-----------------------|-----------------------------------------|
 | 
				
			||||||
 | 
					| placeholdersigns.edit | Allows the use of the /editSign command |
 | 
				
			||||||
							
								
								
									
										90
									
								
								pom.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								pom.xml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,90 @@
 | 
				
			|||||||
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
 | 
					<project xmlns="http://maven.apache.org/POM/4.0.0"
 | 
				
			||||||
 | 
					         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 | 
				
			||||||
 | 
					         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 | 
				
			||||||
 | 
					    <modelVersion>4.0.0</modelVersion>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <groupId>net.knarcraft</groupId>
 | 
				
			||||||
 | 
					    <artifactId>PlaceholderSigns</artifactId>
 | 
				
			||||||
 | 
					    <version>1.0-SNAPSHOT</version>
 | 
				
			||||||
 | 
					    <packaging>jar</packaging>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <name>PlaceholderSigns</name>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <properties>
 | 
				
			||||||
 | 
					        <java.version>16</java.version>
 | 
				
			||||||
 | 
					        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
 | 
				
			||||||
 | 
					    </properties>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <build>
 | 
				
			||||||
 | 
					        <plugins>
 | 
				
			||||||
 | 
					            <plugin>
 | 
				
			||||||
 | 
					                <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					                <artifactId>maven-compiler-plugin</artifactId>
 | 
				
			||||||
 | 
					                <version>3.8.1</version>
 | 
				
			||||||
 | 
					                <configuration>
 | 
				
			||||||
 | 
					                    <source>16</source>
 | 
				
			||||||
 | 
					                    <target>16</target>
 | 
				
			||||||
 | 
					                </configuration>
 | 
				
			||||||
 | 
					            </plugin>
 | 
				
			||||||
 | 
					            <plugin>
 | 
				
			||||||
 | 
					                <groupId>org.apache.maven.plugins</groupId>
 | 
				
			||||||
 | 
					                <artifactId>maven-shade-plugin</artifactId>
 | 
				
			||||||
 | 
					                <version>3.2.4</version>
 | 
				
			||||||
 | 
					                <executions>
 | 
				
			||||||
 | 
					                    <execution>
 | 
				
			||||||
 | 
					                        <phase>package</phase>
 | 
				
			||||||
 | 
					                        <goals>
 | 
				
			||||||
 | 
					                            <goal>shade</goal>
 | 
				
			||||||
 | 
					                        </goals>
 | 
				
			||||||
 | 
					                        <configuration>
 | 
				
			||||||
 | 
					                            <createDependencyReducedPom>false</createDependencyReducedPom>
 | 
				
			||||||
 | 
					                        </configuration>
 | 
				
			||||||
 | 
					                    </execution>
 | 
				
			||||||
 | 
					                </executions>
 | 
				
			||||||
 | 
					            </plugin>
 | 
				
			||||||
 | 
					        </plugins>
 | 
				
			||||||
 | 
					        <resources>
 | 
				
			||||||
 | 
					            <resource>
 | 
				
			||||||
 | 
					                <directory>src/main/resources</directory>
 | 
				
			||||||
 | 
					                <filtering>true</filtering>
 | 
				
			||||||
 | 
					            </resource>
 | 
				
			||||||
 | 
					        </resources>
 | 
				
			||||||
 | 
					    </build>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <repositories>
 | 
				
			||||||
 | 
					        <repository>
 | 
				
			||||||
 | 
					            <id>spigotmc-repo</id>
 | 
				
			||||||
 | 
					            <url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
 | 
				
			||||||
 | 
					        </repository>
 | 
				
			||||||
 | 
					        <repository>
 | 
				
			||||||
 | 
					            <id>sonatype</id>
 | 
				
			||||||
 | 
					            <url>https://oss.sonatype.org/content/groups/public/</url>
 | 
				
			||||||
 | 
					        </repository>
 | 
				
			||||||
 | 
					        <repository>
 | 
				
			||||||
 | 
					            <id>placeholderapi</id>
 | 
				
			||||||
 | 
					            <url>https://repo.extendedclip.com/content/repositories/placeholderapi/</url>
 | 
				
			||||||
 | 
					        </repository>
 | 
				
			||||||
 | 
					    </repositories>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <dependencies>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.spigotmc</groupId>
 | 
				
			||||||
 | 
					            <artifactId>spigot-api</artifactId>
 | 
				
			||||||
 | 
					            <version>1.19.4-R0.1-SNAPSHOT</version>
 | 
				
			||||||
 | 
					            <scope>provided</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>org.jetbrains</groupId>
 | 
				
			||||||
 | 
					            <artifactId>annotations</artifactId>
 | 
				
			||||||
 | 
					            <version>24.0.1</version>
 | 
				
			||||||
 | 
					            <scope>provided</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					        <dependency>
 | 
				
			||||||
 | 
					            <groupId>me.clip</groupId>
 | 
				
			||||||
 | 
					            <artifactId>placeholderapi</artifactId>
 | 
				
			||||||
 | 
					            <version>2.10.0</version>
 | 
				
			||||||
 | 
					            <scope>provided</scope>
 | 
				
			||||||
 | 
					        </dependency>
 | 
				
			||||||
 | 
					    </dependencies>
 | 
				
			||||||
 | 
					</project>
 | 
				
			||||||
@@ -0,0 +1,181 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import me.clip.placeholderapi.PlaceholderAPI;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.command.EditSignCommand;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.LineChangeRequest;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.PlaceholderSign;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.listener.SignBreakListener;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.listener.SignClickListener;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.listener.SignTextListener;
 | 
				
			||||||
 | 
					import net.md_5.bungee.api.ChatColor;
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.block.Sign;
 | 
				
			||||||
 | 
					import org.bukkit.command.PluginCommand;
 | 
				
			||||||
 | 
					import org.bukkit.configuration.serialization.ConfigurationSerialization;
 | 
				
			||||||
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
 | 
					import org.bukkit.plugin.java.JavaPlugin;
 | 
				
			||||||
 | 
					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.regex.Matcher;
 | 
				
			||||||
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * This plugin's main class
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public final class PlaceholderSigns extends JavaPlugin {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static PlaceholderSigns instance;
 | 
				
			||||||
 | 
					    private PlaceholderSignHandler signHandler;
 | 
				
			||||||
 | 
					    private Map<Player, LineChangeRequest> changeRequests;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets an instance of this plugin
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>A plugin instance</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public static @NotNull PlaceholderSigns getInstance() {
 | 
				
			||||||
 | 
					        return instance;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets this instance's placeholder sign handler
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return <p>The sign handler</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public @NotNull PlaceholderSignHandler getSignHandler() {
 | 
				
			||||||
 | 
					        return this.signHandler;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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 addChangeRequest(@NotNull LineChangeRequest request) {
 | 
				
			||||||
 | 
					        changeRequests.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>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public @Nullable LineChangeRequest getChangeRequest(@NotNull Player player) {
 | 
				
			||||||
 | 
					        return changeRequests.remove(player);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onLoad() {
 | 
				
			||||||
 | 
					        super.onLoad();
 | 
				
			||||||
 | 
					        // Register serialization classes
 | 
				
			||||||
 | 
					        ConfigurationSerialization.registerClass(PlaceholderSign.class);
 | 
				
			||||||
 | 
					        ConfigurationSerialization.registerClass(PlaceholderSignHandler.class);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onEnable() {
 | 
				
			||||||
 | 
					        instance = this;
 | 
				
			||||||
 | 
					        signHandler = new PlaceholderSignHandler();
 | 
				
			||||||
 | 
					        changeRequests = new HashMap<>();
 | 
				
			||||||
 | 
					        signHandler.load();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") == null) {
 | 
				
			||||||
 | 
					            getLogger().log(Level.WARNING, "Could not find PlaceholderAPI! This plugin is required.");
 | 
				
			||||||
 | 
					            Bukkit.getPluginManager().disablePlugin(this);
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update signs' placeholders every second
 | 
				
			||||||
 | 
					        Bukkit.getScheduler().runTaskTimer(this, this::updateSigns, 20 * 10, 20 * 5);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Bukkit.getPluginManager().registerEvents(new SignBreakListener(), this);
 | 
				
			||||||
 | 
					        Bukkit.getPluginManager().registerEvents(new SignTextListener(), this);
 | 
				
			||||||
 | 
					        Bukkit.getPluginManager().registerEvents(new SignClickListener(), this);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        PluginCommand editCommand = Bukkit.getPluginCommand("editSign");
 | 
				
			||||||
 | 
					        if (editCommand != null) {
 | 
				
			||||||
 | 
					            editCommand.setExecutor(new EditSignCommand());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public void onDisable() {
 | 
				
			||||||
 | 
					        // Plugin shutdown logic
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Updates all loaded and registered placeholder signs
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    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
 | 
				
			||||||
 | 
					            Map<Integer, String> placeholders = placeholderSign.placeholders();
 | 
				
			||||||
 | 
					            String[] lines = sign.getLines();
 | 
				
			||||||
 | 
					            boolean updateRequired = false;
 | 
				
			||||||
 | 
					            for (int i = 0; i < lines.length; i++) {
 | 
				
			||||||
 | 
					                String oldText = sign.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 = translateAllColorCodes(newText);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Only change the line if the text has changed
 | 
				
			||||||
 | 
					                if (!newText.equals(oldText)) {
 | 
				
			||||||
 | 
					                    sign.setLine(i, newText);
 | 
				
			||||||
 | 
					                    updateRequired = true;
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            // Only update the sign if the text has changed
 | 
				
			||||||
 | 
					            if (updateRequired) {
 | 
				
			||||||
 | 
					                sign.update();
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 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>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    private static String translateAllColorCodes(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;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,72 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.command;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.PlaceholderSigns;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.LineChangeRequest;
 | 
				
			||||||
 | 
					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 setting a sign's text to anything longer than normally possible
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					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) {
 | 
				
			||||||
 | 
					        if (args.length < 2 || !(commandSender instanceof Player player)) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Parse the specified line number
 | 
				
			||||||
 | 
					        int lineNumber;
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            lineNumber = Integer.parseInt(args[0]);
 | 
				
			||||||
 | 
					            if (lineNumber < 0 || lineNumber > 4) {
 | 
				
			||||||
 | 
					                return false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        } catch (NumberFormatException exception) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Get all arguments as a space-separated string
 | 
				
			||||||
 | 
					        StringBuilder builder = new StringBuilder(args[1]);
 | 
				
			||||||
 | 
					        for (int i = 2; i < args.length; i++) {
 | 
				
			||||||
 | 
					            builder.append(" ").append(args[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Register the line change request
 | 
				
			||||||
 | 
					        LineChangeRequest request = new LineChangeRequest(player, lineNumber - 1, builder.toString());
 | 
				
			||||||
 | 
					        PlaceholderSigns.getInstance().addChangeRequest(request);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        commandSender.sendMessage("Please click the sign you want to change.");
 | 
				
			||||||
 | 
					        return true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Nullable
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public List<String> onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s,
 | 
				
			||||||
 | 
					                                      @NotNull String[] args) {
 | 
				
			||||||
 | 
					        if (args.length == 1) {
 | 
				
			||||||
 | 
					            return lineNumbers;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return new ArrayList<>();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,13 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.entity.Player;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A record of a player's request to change a sign
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param player <p>The player requesting the sign change</p>
 | 
				
			||||||
 | 
					 * @param line   <p>The line the player wants to change</p>
 | 
				
			||||||
 | 
					 * @param text   <p>The new text the player provided for the line</p>
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public record LineChangeRequest(Player player, int line, String text) {
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,39 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.container;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.configuration.serialization.ConfigurationSerializable;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					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(Location location,
 | 
				
			||||||
 | 
					                              Map<Integer, String> placeholders) implements ConfigurationSerializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    public Map<String, Object> serialize() {
 | 
				
			||||||
 | 
					        Map<String, Object> data = new HashMap<>();
 | 
				
			||||||
 | 
					        data.put("location", location);
 | 
				
			||||||
 | 
					        data.put("placeholders", placeholders);
 | 
				
			||||||
 | 
					        return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Deserializes the placeholder-sign specified in the given data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param data <p>The data to deserialize</p>
 | 
				
			||||||
 | 
					     * @return <p>The deserialized placeholder sign</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @SuppressWarnings({"unchecked", "unused"})
 | 
				
			||||||
 | 
					    public static PlaceholderSign deserialize(Map<String, Object> data) {
 | 
				
			||||||
 | 
					        return new PlaceholderSign((Location) data.get("location"), (Map<Integer, String>) data.get("placeholders"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,118 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.handler;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.PlaceholderSigns;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.PlaceholderSign;
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.configuration.file.YamlConfiguration;
 | 
				
			||||||
 | 
					import org.bukkit.configuration.serialization.ConfigurationSerializable;
 | 
				
			||||||
 | 
					import org.jetbrains.annotations.NotNull;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.io.File;
 | 
				
			||||||
 | 
					import java.io.IOException;
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.HashSet;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					import java.util.Set;
 | 
				
			||||||
 | 
					import java.util.logging.Level;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A handler for keeping track of placeholder signs
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class PlaceholderSignHandler implements ConfigurationSerializable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    private static final File signsFile = new File(PlaceholderSigns.getInstance().getDataFolder(), "signs.yml");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    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);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Gets a placeholder sign from the given location
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param location <p>The location of the sign</p>
 | 
				
			||||||
 | 
					     * @return <p>The sign at the location, or null if no such sign exists</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public PlaceholderSign getFromLocation(@NotNull Location location) {
 | 
				
			||||||
 | 
					        return locationLookup.get(location);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Registers a new placeholder sign
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param sign <p>The sign to register</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void registerSign(@NotNull PlaceholderSign sign) {
 | 
				
			||||||
 | 
					        this.placeholderSigns.add(sign);
 | 
				
			||||||
 | 
					        locationLookup.put(sign.location(), sign);
 | 
				
			||||||
 | 
					        save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Un-registers a placeholder sign
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param sign <p>The sign to un-register</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void unregisterSign(@NotNull PlaceholderSign sign) {
 | 
				
			||||||
 | 
					        locationLookup.remove(sign.location());
 | 
				
			||||||
 | 
					        this.placeholderSigns.remove(sign);
 | 
				
			||||||
 | 
					        save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Loads all placeholder signs from disk
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void load() {
 | 
				
			||||||
 | 
					        YamlConfiguration configuration = YamlConfiguration.loadConfiguration(signsFile);
 | 
				
			||||||
 | 
					        PlaceholderSignHandler loadedHandler = (PlaceholderSignHandler) configuration.get("signHandler");
 | 
				
			||||||
 | 
					        this.placeholderSigns = loadedHandler != null ? loadedHandler.placeholderSigns : new HashSet<>();
 | 
				
			||||||
 | 
					        this.locationLookup = loadedHandler != null ? loadedHandler.locationLookup : new HashMap<>();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Saves all current placeholder signs
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public void save() {
 | 
				
			||||||
 | 
					        try {
 | 
				
			||||||
 | 
					            YamlConfiguration configuration = new YamlConfiguration();
 | 
				
			||||||
 | 
					            configuration.set("signHandler", this);
 | 
				
			||||||
 | 
					            configuration.save(signsFile);
 | 
				
			||||||
 | 
					        } catch (IOException exception) {
 | 
				
			||||||
 | 
					            PlaceholderSigns.getInstance().getLogger().log(Level.SEVERE, "Unable to save placeholder signs!");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @NotNull
 | 
				
			||||||
 | 
					    @Override
 | 
				
			||||||
 | 
					    public Map<String, Object> serialize() {
 | 
				
			||||||
 | 
					        Map<String, Object> data = new HashMap<>();
 | 
				
			||||||
 | 
					        data.put("signs", this.placeholderSigns);
 | 
				
			||||||
 | 
					        return data;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * Deserializes the given placeholder sign handler data
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @param data <p>The data to deserialize</p>
 | 
				
			||||||
 | 
					     * @return <p>The deserialized sign handler</p>
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    @SuppressWarnings({"unchecked", "unused"})
 | 
				
			||||||
 | 
					    public static PlaceholderSignHandler deserialize(@NotNull Map<String, Object> data) {
 | 
				
			||||||
 | 
					        PlaceholderSignHandler placeholderSignHandler = new PlaceholderSignHandler();
 | 
				
			||||||
 | 
					        placeholderSignHandler.placeholderSigns = (Set<PlaceholderSign>) data.get("signs");
 | 
				
			||||||
 | 
					        Map<Location, PlaceholderSign> lookup = new HashMap<>();
 | 
				
			||||||
 | 
					        for (PlaceholderSign sign : placeholderSignHandler.placeholderSigns) {
 | 
				
			||||||
 | 
					            lookup.put(sign.location(), sign);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        placeholderSignHandler.locationLookup = lookup;
 | 
				
			||||||
 | 
					        return placeholderSignHandler;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,32 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.PlaceholderSigns;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.PlaceholderSign;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
 | 
				
			||||||
 | 
					import org.bukkit.block.Block;
 | 
				
			||||||
 | 
					import org.bukkit.block.Sign;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventHandler;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventPriority;
 | 
				
			||||||
 | 
					import org.bukkit.event.Listener;
 | 
				
			||||||
 | 
					import org.bukkit.event.block.BlockBreakEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A listener for placeholder signs being broken
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SignBreakListener implements Listener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @EventHandler(ignoreCancelled = true, priority = EventPriority.MONITOR)
 | 
				
			||||||
 | 
					    public void onSignBreak(BlockBreakEvent event) {
 | 
				
			||||||
 | 
					        Block block = event.getBlock();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (!(block.getState() instanceof Sign)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        PlaceholderSignHandler signHandler = PlaceholderSigns.getInstance().getSignHandler();
 | 
				
			||||||
 | 
					        PlaceholderSign sign = signHandler.getFromLocation(block.getLocation());
 | 
				
			||||||
 | 
					        if (sign != null) {
 | 
				
			||||||
 | 
					            signHandler.unregisterSign(sign);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.PlaceholderSigns;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.LineChangeRequest;
 | 
				
			||||||
 | 
					import org.bukkit.Bukkit;
 | 
				
			||||||
 | 
					import org.bukkit.block.Sign;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventHandler;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventPriority;
 | 
				
			||||||
 | 
					import org.bukkit.event.Listener;
 | 
				
			||||||
 | 
					import org.bukkit.event.block.SignChangeEvent;
 | 
				
			||||||
 | 
					import org.bukkit.event.player.PlayerInteractEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A listener for placeholder signs being clicked
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SignClickListener implements Listener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @EventHandler(priority = EventPriority.MONITOR)
 | 
				
			||||||
 | 
					    public void onSignClick(PlayerInteractEvent event) {
 | 
				
			||||||
 | 
					        // Ignore if not a clicked sign
 | 
				
			||||||
 | 
					        if (!event.hasBlock() || event.getClickedBlock() == null ||
 | 
				
			||||||
 | 
					                !(event.getClickedBlock().getState() instanceof Sign sign)) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Check if the player has run the /editSign command
 | 
				
			||||||
 | 
					        LineChangeRequest request = PlaceholderSigns.getInstance().getChangeRequest(event.getPlayer());
 | 
				
			||||||
 | 
					        if (request == null) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        String[] lines = sign.getLines();
 | 
				
			||||||
 | 
					        lines[request.line()] = request.text();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Run the sign change event to allow protection plugins to cancel, and allow the sign text listener to trigger
 | 
				
			||||||
 | 
					        SignChangeEvent changeEvent = new SignChangeEvent(event.getClickedBlock(), event.getPlayer(), lines);
 | 
				
			||||||
 | 
					        Bukkit.getPluginManager().callEvent(changeEvent);
 | 
				
			||||||
 | 
					        if (changeEvent.isCancelled()) {
 | 
				
			||||||
 | 
					            return;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Update the sign with the new text
 | 
				
			||||||
 | 
					        String[] finalLines = changeEvent.getLines();
 | 
				
			||||||
 | 
					        for (int i = 0; i < finalLines.length; i++) {
 | 
				
			||||||
 | 
					            sign.setLine(i, finalLines[i]);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sign.update();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        event.getPlayer().sendMessage("The sign line was successfully changed.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@@ -0,0 +1,53 @@
 | 
				
			|||||||
 | 
					package net.knarcraft.placeholdersigns.listener;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import me.clip.placeholderapi.PlaceholderAPI;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.PlaceholderSigns;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.container.PlaceholderSign;
 | 
				
			||||||
 | 
					import net.knarcraft.placeholdersigns.handler.PlaceholderSignHandler;
 | 
				
			||||||
 | 
					import org.bukkit.Location;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventHandler;
 | 
				
			||||||
 | 
					import org.bukkit.event.EventPriority;
 | 
				
			||||||
 | 
					import org.bukkit.event.Listener;
 | 
				
			||||||
 | 
					import org.bukkit.event.block.SignChangeEvent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import java.util.HashMap;
 | 
				
			||||||
 | 
					import java.util.Map;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * A listener for signs being changed to contain on or more placeholders
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					public class SignTextListener implements Listener {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
 | 
				
			||||||
 | 
					    public void onSignCreate(SignChangeEvent event) {
 | 
				
			||||||
 | 
					        String[] lines = event.getLines();
 | 
				
			||||||
 | 
					        Map<Integer, String> placeholders = new HashMap<>();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Register any lines PlaceholderAPI wants to change
 | 
				
			||||||
 | 
					        for (int i = 0; i < lines.length; i++) {
 | 
				
			||||||
 | 
					            String line = lines[i];
 | 
				
			||||||
 | 
					            String replaced = PlaceholderAPI.setPlaceholders(null, line);
 | 
				
			||||||
 | 
					            if (line.equalsIgnoreCase(replaced)) {
 | 
				
			||||||
 | 
					                continue;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            placeholders.put(i, line);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        Location location = event.getBlock().getLocation();
 | 
				
			||||||
 | 
					        PlaceholderSignHandler signHandler = PlaceholderSigns.getInstance().getSignHandler();
 | 
				
			||||||
 | 
					        PlaceholderSign existingSign = signHandler.getFromLocation(location);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Register the placeholder sign
 | 
				
			||||||
 | 
					        if (!placeholders.isEmpty() && existingSign == null) {
 | 
				
			||||||
 | 
					            PlaceholderSign placeholderSign = new PlaceholderSign(event.getBlock().getLocation(), placeholders);
 | 
				
			||||||
 | 
					            signHandler.registerSign(placeholderSign);
 | 
				
			||||||
 | 
					        } else if (!placeholders.isEmpty()) {
 | 
				
			||||||
 | 
					            // Overwrite the placeholders of the existing placeholder sign
 | 
				
			||||||
 | 
					            for (Map.Entry<Integer, String> entry : placeholders.entrySet()) {
 | 
				
			||||||
 | 
					                existingSign.placeholders().put(entry.getKey(), entry.getValue());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            signHandler.save();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										0
									
								
								src/main/resources/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								src/main/resources/config.yml
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										17
									
								
								src/main/resources/plugin.yml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								src/main/resources/plugin.yml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,17 @@
 | 
				
			|||||||
 | 
					name: PlaceholderSigns
 | 
				
			||||||
 | 
					version: '${project.version}'
 | 
				
			||||||
 | 
					main: net.knarcraft.placeholdersigns.PlaceholderSigns
 | 
				
			||||||
 | 
					api-version: 1.19
 | 
				
			||||||
 | 
					depend:
 | 
				
			||||||
 | 
					  - PlaceholderAPI
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					commands:
 | 
				
			||||||
 | 
					  editSign:
 | 
				
			||||||
 | 
					    usage: /<command> <line> <text> [text] ...
 | 
				
			||||||
 | 
					    permission: placeholdersigns.edit
 | 
				
			||||||
 | 
					    description: Changes the line of a sign without a text limit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					permissions:
 | 
				
			||||||
 | 
					  placeholdersigns.edit:
 | 
				
			||||||
 | 
					    description: Allows a player to use the /editSign command
 | 
				
			||||||
 | 
					    default: op
 | 
				
			||||||
		Reference in New Issue
	
	Block a user