argsArray = new LinkedList<>(Arrays.asList(args));
73 | selectedLines = NO_LINES_SELECTED;
74 | remainder = argsArray;
75 |
76 | if (argsArray.size() == 0) {
77 | subcommand = SignCommand.SUBCOMMAND_NAME_HELP;
78 | return;
79 | }
80 |
81 | String maybeSubcommandOrShorthandLines = remainder.remove(0);
82 | String maybeSubcommand = maybeSubcommandOrShorthandLines.toLowerCase();
83 | if (subcommandNames.contains(maybeSubcommand)) {
84 | subcommand = maybeSubcommand;
85 | }
86 | if (subcommand == null) {
87 | try {
88 | parseLineSelection(maybeSubcommandOrShorthandLines);
89 | if (selectedLines.length > 0) {
90 | if (remainder.size() == 0) subcommand = "clear";
91 | else subcommand = "set";
92 | }
93 | return;
94 | } catch (NumberParseLineSelectionException e) {
95 | remainder.add(0, maybeSubcommandOrShorthandLines);
96 | } catch (LineSelectionException e) {
97 | remainder.add(0, maybeSubcommandOrShorthandLines);
98 | subcommand = "set";
99 | }
100 | }
101 | if (subcommand == null) {
102 | subcommand = SignCommand.SUBCOMMAND_NAME_HELP;
103 | }
104 | if (remainder.size() == 0 || subcommand.equals(SignCommand.SUBCOMMAND_NAME_HELP)) {
105 | return;
106 | }
107 |
108 | try {
109 | parseLineSelection(remainder.get(0));
110 | remainder.remove(0);
111 | } catch (LineSelectionException e) {
112 | selectedLines = NO_LINES_SELECTED;
113 | selectedLinesError = e;
114 | }
115 | }
116 |
117 | private void parseLineSelection(String rawLineGroups) {
118 | LineSelectorParser lineSelectorParser = new LineSelectorParser(config);
119 | this.selectedLines = lineSelectorParser.toSelectedLines(rawLineGroups);
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/ArgParserArgs.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import javax.inject.Qualifier;
23 | import java.lang.annotation.Documented;
24 | import java.lang.annotation.Retention;
25 | import java.lang.annotation.RetentionPolicy;
26 |
27 | @Qualifier
28 | @Documented
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface ArgParserArgs {
31 | }
32 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/ChatCommsModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import dagger.BindsInstance;
23 | import dagger.Module;
24 | import dagger.Subcomponent;
25 | import org.bukkit.command.CommandSender;
26 |
27 | @Module(subcomponents = {
28 | ChatCommsModule.ChatCommsComponent.class
29 | })
30 | public abstract class ChatCommsModule {
31 | @Subcomponent
32 | public interface ChatCommsComponent {
33 | ChatComms comms();
34 |
35 | @Subcomponent.Builder
36 | abstract class Builder {
37 | public abstract ChatCommsComponent build();
38 |
39 | @BindsInstance
40 | public abstract Builder commandSender(CommandSender commandSender);
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/ConfigurationWatcher.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.bukkit.plugin.Plugin;
23 |
24 | import javax.inject.Inject;
25 | import javax.inject.Singleton;
26 | import java.io.File;
27 | import java.io.IOException;
28 | import java.nio.file.*;
29 | import java.nio.file.attribute.FileTime;
30 | import java.util.concurrent.atomic.AtomicBoolean;
31 |
32 | import static org.bukkit.Bukkit.getLogger;
33 |
34 | @Singleton
35 | public class ConfigurationWatcher extends Thread {
36 | private final Configuration config;
37 | private final WatchService watcher;
38 | private final AtomicBoolean halt = new AtomicBoolean(false);
39 | private final SignEditPlugin plugin;
40 |
41 | private Path configPath;
42 | private FileTime lastModifiedTime;
43 |
44 | @Inject
45 | public ConfigurationWatcher(Plugin plugin, Configuration config) {
46 | this.plugin = (SignEditPlugin) plugin;
47 | this.config = config;
48 | File file = this.config.getConfigFile();
49 |
50 | WatchService watcher;
51 | try {
52 | watcher = FileSystems.getDefault().newWatchService();
53 |
54 | Path fileBasedir = file.toPath().getParent();
55 | fileBasedir.register(watcher, StandardWatchEventKinds.ENTRY_MODIFY);
56 |
57 | configPath = file.toPath();
58 | lastModifiedTime = Files.getLastModifiedTime(configPath);
59 | } catch (IOException e) {
60 | watcher = null;
61 | end();
62 |
63 | getLogger().warning(
64 | "Could not set up SignEdit configuration watcher. " +
65 | "Configuration changes will require a Bukkit server restart to apply."
66 | );
67 | getLogger().warning(SignEditPlugin.getStackTrace(e));
68 | }
69 | this.watcher = watcher;
70 | }
71 |
72 | public boolean isHalted() {
73 | return halt.get();
74 | }
75 |
76 | public void end() {
77 | halt.set(true);
78 | }
79 |
80 | @Override
81 | public void run() {
82 | while (!isHalted()) {
83 | WatchKey watchKey;
84 | try {
85 | watchKey = watcher.take();
86 | } catch (InterruptedException e) {
87 | return;
88 | }
89 | if (watchKey == null) {
90 | Thread.yield();
91 | continue;
92 | }
93 | try {
94 | // noinspection BusyWait
95 | Thread.sleep(50);
96 | } catch (InterruptedException e) {
97 | return;
98 | }
99 | for (WatchEvent> watchEvent : watchKey.pollEvents()) {
100 | Object context = watchEvent.context();
101 | if (!(context instanceof Path)) continue;
102 |
103 | Path pathContext = (Path) context;
104 | if (!pathContext.equals(configPath.getFileName())) continue;
105 | try {
106 | FileTime newLastModifiedTime = Files.getLastModifiedTime(configPath);
107 | if (newLastModifiedTime.equals(lastModifiedTime) && newLastModifiedTime.toMillis() != 0) continue;
108 |
109 | lastModifiedTime = newLastModifiedTime;
110 | } catch (IOException e) {
111 | getLogger().warning(
112 | "SignEdit could not determine the file modification time of configuration file: "
113 | + configPath.toString()
114 | );
115 | }
116 |
117 | if (isHalted()) return;
118 | getLogger().info("SignEdit detected a configuration file change. Reloading configuration...");
119 | this.config.reloadConfig();
120 | plugin.reregisterListeners();
121 | break;
122 | }
123 | watchKey.reset();
124 | Thread.yield();
125 | }
126 | }
127 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/CraftBukkitReflector.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.bukkit.Bukkit;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | import javax.inject.Inject;
26 | import java.lang.reflect.Field;
27 | import java.lang.reflect.Method;
28 | import java.util.Arrays;
29 |
30 | public class CraftBukkitReflector {
31 | public String BUKKIT_SERVER_VERSION;
32 |
33 | @Inject
34 | public CraftBukkitReflector() {
35 | BUKKIT_SERVER_VERSION = getBukkitServerVersion();
36 | }
37 |
38 | private static String getBukkitServerVersion() {
39 | String bukkitPackageName = Bukkit.getServer().getClass().getPackage().getName();
40 | return bukkitPackageName.substring(bukkitPackageName.lastIndexOf('.') + 1);
41 | }
42 |
43 | public static Method getDeclaredMethodRecursive(Class> whateverClass, String name, Class>... parameterTypes)
44 | throws NoSuchMethodException {
45 | try {
46 | Method method = whateverClass.getDeclaredMethod(name, parameterTypes);
47 | method.setAccessible(true);
48 | return method;
49 | } catch (NoSuchMethodException e) {
50 | Class> superClass = whateverClass.getSuperclass();
51 | if (superClass != null) {
52 | return getDeclaredMethodRecursive(superClass, name, parameterTypes);
53 | }
54 | throw e;
55 | }
56 | }
57 |
58 | /**
59 | * Find the first method that accepts the provided parameters
60 | *
61 | * Performs a breadth-first search up the class ancestry until there are no more parents
62 | *
63 | * @param whateverClass The class to check for a matching method
64 | * @param parameterTypes The parameter types that the method accepts
65 | * @return The first matching method
66 | * @throws NoSuchMethodException if no methods match
67 | */
68 | public static Method findMethodByParameterTypes(Class> whateverClass, Class>... parameterTypes)
69 | throws NoSuchMethodException {
70 | try {
71 | for (Method maybeMethod : whateverClass.getMethods()) {
72 | Class>[] candidateParameterTypes = maybeMethod.getParameterTypes();
73 | if (Arrays.equals(parameterTypes, candidateParameterTypes)) {
74 | maybeMethod.setAccessible(true);
75 | return maybeMethod;
76 | }
77 | }
78 | throw new NoSuchMethodException();
79 | } catch (NoSuchMethodException e) {
80 | Class> superClass = whateverClass.getSuperclass();
81 | if (superClass != null) {
82 | return findMethodByParameterTypes(superClass, parameterTypes);
83 | }
84 | throw e;
85 | }
86 | }
87 |
88 | public static Field getFirstFieldOfType(Object source, Class> desiredType) throws NoSuchFieldException {
89 | return getFirstFieldOfType(source, desiredType, ~0x0);
90 | }
91 |
92 | public static Field getFirstFieldOfType(
93 | Object source,
94 | Class> desiredType,
95 | int modifierMask
96 | ) throws NoSuchFieldException {
97 | return getFirstFieldOfType(source.getClass(), desiredType, modifierMask);
98 | }
99 |
100 | public static Field getFirstFieldOfType(
101 | @NotNull Class> source,
102 | @NotNull Class> desiredType,
103 | int modifierMask
104 | ) throws NoSuchFieldException {
105 | Class> ancestor = source;
106 | while (ancestor != null) {
107 | Field[] fields = ancestor.getDeclaredFields();
108 | for (Field field : fields) {
109 | Class> candidateType = field.getType();
110 | if (desiredType.isAssignableFrom(candidateType) && (field.getModifiers() & modifierMask) > 0) {
111 | field.setAccessible(true);
112 | return field;
113 | }
114 | }
115 | ancestor = ancestor.getSuperclass();
116 | }
117 | throw new NoSuchFieldException("Cannot match " + desiredType.getName() + " in ancestry of " + source.getName());
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/ResourceList.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import java.io.File;
23 | import java.io.IOException;
24 | import java.util.ArrayList;
25 | import java.util.Collection;
26 | import java.util.Enumeration;
27 | import java.util.regex.Pattern;
28 | import java.util.zip.ZipEntry;
29 | import java.util.zip.ZipFile;
30 |
31 | // https://web.archive.org/web/20191230162038/http://forums.devx.com/showthread.php?153784-how-to-list-resources-in-a-package&p=457686#post457686
32 | public class ResourceList {
33 |
34 | /**
35 | * for all elements of java.class.path get a Collection of resources Pattern
36 | * pattern = Pattern.compile(".*"); gets all resources
37 | *
38 | * @param pattern the pattern to match
39 | * @return the resources in the order they are found
40 | */
41 | public static Collection getResources(
42 | final Pattern pattern) {
43 | final ArrayList retval = new ArrayList<>();
44 | final String classPath = System.getProperty("java.class.path", ".");
45 | final String[] classPathElements = classPath.split(System.getProperty("path.separator"));
46 | for (final String element : classPathElements) {
47 | retval.addAll(getResources(element, pattern));
48 | }
49 | return retval;
50 | }
51 |
52 | public static Collection getResources(
53 | final String element,
54 | final Pattern pattern) {
55 | final ArrayList retval = new ArrayList<>();
56 | final File file = new File(element);
57 | if (file.isDirectory()) {
58 | retval.addAll(getResourcesFromDirectory(file, pattern));
59 | } else {
60 | retval.addAll(getResourcesFromJarFile(file, pattern));
61 | }
62 | return retval;
63 | }
64 |
65 | private static Collection getResourcesFromJarFile(
66 | final File file,
67 | final Pattern pattern) {
68 | final ArrayList retval = new ArrayList<>();
69 | ZipFile zf;
70 | try {
71 | zf = new ZipFile(file);
72 | } catch (final IOException e) {
73 | throw new Error(e);
74 | }
75 | final Enumeration extends ZipEntry> e = zf.entries();
76 | while (e.hasMoreElements()) {
77 | final ZipEntry ze = e.nextElement();
78 | final String fileName = ze.getName();
79 | final boolean accept = pattern.matcher(fileName).matches();
80 | if (accept) {
81 | retval.add(fileName);
82 | }
83 | }
84 | try {
85 | zf.close();
86 | } catch (final IOException e1) {
87 | throw new Error(e1);
88 | }
89 | return retval;
90 | }
91 |
92 | private static Collection getResourcesFromDirectory(
93 | final File directory,
94 | final Pattern pattern) {
95 | final ArrayList retval = new ArrayList<>();
96 | final File[] fileList = directory.listFiles();
97 | if (fileList == null) return retval;
98 |
99 | for (final File file : fileList) {
100 | if (file.isDirectory()) {
101 | retval.addAll(getResourcesFromDirectory(file, pattern));
102 | } else {
103 | try {
104 | final String fileName = file.getCanonicalPath();
105 | final boolean accept = pattern.matcher(fileName).matches();
106 | if (accept) {
107 | retval.add(fileName);
108 | }
109 | } catch (final IOException e) {
110 | throw new Error(e);
111 | }
112 | }
113 | }
114 | return retval;
115 | }
116 |
117 | /**
118 | * list the resources that match args[0]
119 | *
120 | * @param args args[0] is the pattern to match, or list all resources if
121 | * there are no args
122 | */
123 | public static void main(final String[] args) {
124 | Pattern pattern;
125 | if (args.length < 1) {
126 | pattern = Pattern.compile(".*");
127 | } else {
128 | pattern = Pattern.compile(args[0]);
129 | }
130 | final Collection list = ResourceList.getResources(pattern);
131 | for (final String name : list) {
132 | System.out.println(name);
133 | }
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/SignEditPlugin.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import net.deltik.mc.signedit.commands.SignCommand;
23 | import net.deltik.mc.signedit.commands.SignCommandTabCompleter;
24 | import net.deltik.mc.signedit.listeners.SignEditListener;
25 | import org.bukkit.command.PluginCommand;
26 | import org.bukkit.event.HandlerList;
27 | import org.bukkit.plugin.java.JavaPlugin;
28 |
29 | import javax.inject.Inject;
30 | import javax.inject.Provider;
31 | import java.io.IOException;
32 | import java.io.PrintWriter;
33 | import java.io.StringWriter;
34 | import java.util.Set;
35 |
36 | public class SignEditPlugin extends JavaPlugin {
37 | @Inject
38 | public Configuration config;
39 | @Inject
40 | public ConfigurationWatcher configWatcher;
41 | @Inject
42 | UserComms userComms;
43 |
44 | @Inject
45 | public Provider> listenersProvider;
46 |
47 | @Inject
48 | public SignCommand signCommand;
49 | @Inject
50 | public SignCommandTabCompleter signCommandTabCompleter;
51 |
52 | @Override
53 | public void onEnable() {
54 | DaggerSignEditPluginComponent.builder().plugin(this).build().injectSignEditPlugin(this);
55 |
56 | for (String alias : new String[]{"sign", "signedit", "editsign", "se"}) {
57 | PluginCommand pluginCommand = this.getCommand(alias);
58 | pluginCommand.setExecutor(signCommand);
59 | pluginCommand.setTabCompleter(signCommandTabCompleter);
60 | }
61 |
62 | reregisterListeners();
63 |
64 | try {
65 | userComms.deploy();
66 | } catch (IOException e) {
67 | getLogger().warning("Cannot enable user-defined locales due to error:");
68 | getLogger().warning(getStackTrace(e));
69 | }
70 |
71 | configWatcher.start();
72 | }
73 |
74 | @Override
75 | public void onDisable() {
76 | try {
77 | configWatcher.end();
78 | config.configHighstate();
79 | } catch (IOException e) {
80 | getLogger().severe(getStackTrace(e));
81 | throw new IllegalStateException("Unrecoverable error while sanity checking plugin configuration");
82 | }
83 | }
84 |
85 | public void reregisterListeners() {
86 | HandlerList.unregisterAll(this);
87 |
88 | Set listeners = listenersProvider.get();
89 | for (SignEditListener listener : listeners) {
90 | getServer().getPluginManager().registerEvents(listener, this);
91 | }
92 | }
93 |
94 | /**
95 | * Returns the stack trace of the given {@link Throwable} as a {@link String}
96 | *
97 | * @param throwable the {@link Throwable} to be examined
98 | * @return the stack trace as generated by {@link Throwable#printStackTrace(PrintWriter)}
99 | */
100 | public static String getStackTrace(final Throwable throwable) {
101 | final StringWriter sw = new StringWriter();
102 | final PrintWriter pw = new PrintWriter(sw, true);
103 | throwable.printStackTrace(pw);
104 | return sw.getBuffer().toString();
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/SignEditPluginComponent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import dagger.BindsInstance;
23 | import dagger.Component;
24 | import net.deltik.mc.signedit.commands.SignCommandModule;
25 | import net.deltik.mc.signedit.listeners.SignEditListenerModule;
26 | import org.bukkit.plugin.Plugin;
27 |
28 | import javax.inject.Singleton;
29 |
30 | @Component(modules = {
31 | SignEditListenerModule.class,
32 | SignCommandModule.class,
33 | ChatCommsModule.class
34 | })
35 | @Singleton
36 | public interface SignEditPluginComponent {
37 | void injectSignEditPlugin(SignEditPlugin plugin);
38 |
39 | @Component.Builder
40 | interface Builder {
41 | SignEditPluginComponent build();
42 |
43 | @BindsInstance
44 | Builder plugin(Plugin plugin);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/SignTextClipboardManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.bukkit.entity.Player;
23 |
24 | import javax.inject.Inject;
25 | import javax.inject.Singleton;
26 | import java.util.HashMap;
27 | import java.util.Map;
28 |
29 | @Singleton
30 | public class SignTextClipboardManager {
31 | private final Map playerSignTextMap = new HashMap<>();
32 |
33 | @Inject
34 | public SignTextClipboardManager() {
35 | }
36 |
37 | public void forgetPlayer(Player player) {
38 | playerSignTextMap.remove(player);
39 | }
40 |
41 | public SignText getClipboard(Player player) {
42 | return playerSignTextMap.get(player);
43 | }
44 |
45 | public void setClipboard(Player player, SignText clipboard) {
46 | playerSignTextMap.put(player, clipboard);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/SignTextHistory.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import net.deltik.mc.signedit.exceptions.SignTextHistoryStackBoundsException;
23 | import org.bukkit.entity.Player;
24 |
25 | import java.util.LinkedList;
26 |
27 | public class SignTextHistory {
28 | private final Player player;
29 | private final LinkedList history = new LinkedList<>();
30 | int tailPosition = 0;
31 |
32 | public SignTextHistory(Player player) {
33 | this.player = player;
34 | }
35 |
36 | public void push(SignText signText) {
37 | while (history.size() > tailPosition) {
38 | history.removeLast();
39 | }
40 | history.addLast(signText);
41 | tailPosition = history.size();
42 | }
43 |
44 | public int undosRemaining() {
45 | return tailPosition;
46 | }
47 |
48 | public int redosRemaining() {
49 | return history.size() - tailPosition;
50 | }
51 |
52 | public SignText undo(ChatComms comms) {
53 | if (tailPosition <= 0) {
54 | throw new SignTextHistoryStackBoundsException("nothing_to_undo");
55 | }
56 | SignText previousSignText = history.get(tailPosition - 1);
57 | previousSignText.applySignAutoWax(player, comms, previousSignText::revertSign);
58 | tailPosition--;
59 | return previousSignText;
60 | }
61 |
62 | public SignText redo(ChatComms comms) {
63 | if (tailPosition == history.size()) {
64 | throw new SignTextHistoryStackBoundsException("nothing_to_redo");
65 | }
66 | SignText nextSignText = history.get(tailPosition);
67 | nextSignText.applySignAutoWax(player, comms, nextSignText::applySign);
68 | tailPosition++;
69 | return nextSignText;
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/SignTextHistoryManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.bukkit.entity.Player;
23 |
24 | import javax.inject.Inject;
25 | import javax.inject.Singleton;
26 | import java.util.HashMap;
27 | import java.util.Map;
28 |
29 | @Singleton
30 | public class SignTextHistoryManager {
31 | private final Map playerHistoryMap = new HashMap<>();
32 |
33 | @Inject
34 | public SignTextHistoryManager() {
35 | }
36 |
37 | public void forgetPlayer(Player player) {
38 | playerHistoryMap.remove(player);
39 | }
40 |
41 | public SignTextHistory getHistory(Player player) {
42 | SignTextHistory history = playerHistoryMap.get(player);
43 | if (history == null) {
44 | history = new SignTextHistory(player);
45 | playerHistoryMap.put(player, history);
46 | }
47 | return history;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/commands/SignCommandModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.commands;
21 |
22 | import dagger.Binds;
23 | import dagger.Module;
24 | import dagger.Provides;
25 | import dagger.multibindings.IntoMap;
26 | import dagger.multibindings.StringKey;
27 | import net.deltik.mc.signedit.integrations.SignEditValidatorModule;
28 | import net.deltik.mc.signedit.interactions.InteractionCommand;
29 | import net.deltik.mc.signedit.subcommands.*;
30 |
31 | import java.util.Set;
32 | import java.util.stream.Collectors;
33 | import java.util.stream.Stream;
34 |
35 | @Module(subcomponents = {
36 | SignSubcommandComponent.class,
37 | },
38 | includes = {
39 | SignEditValidatorModule.class,
40 | })
41 | public abstract class SignCommandModule {
42 |
43 | /**
44 | * FIXME: Find a way not to hard-code this Set.
45 | */
46 | @Provides
47 | @SubcommandName
48 | public static Set provideSubcommandNames() {
49 | return Stream.of(
50 | "help",
51 | "set",
52 | "clear",
53 | "ui",
54 | "cancel",
55 | "status",
56 | "copy",
57 | "cut",
58 | "paste",
59 | "undo",
60 | "redo",
61 | "unwax",
62 | "wax",
63 | "version"
64 | ).collect(Collectors.toSet());
65 | }
66 |
67 | @Binds
68 | @IntoMap
69 | @StringKey("help")
70 | abstract InteractionCommand BindHelpSignSubcommand(HelpSignSubcommand command);
71 |
72 | @Binds
73 | @IntoMap
74 | @StringKey("set")
75 | abstract InteractionCommand BindSetSignSubcommand(SetSignSubcommand command);
76 |
77 | @Binds
78 | @IntoMap
79 | @StringKey("clear")
80 | abstract InteractionCommand BindClearSignSubcommand(ClearSignSubcommand command);
81 |
82 | @Binds
83 | @IntoMap
84 | @StringKey("ui")
85 | abstract InteractionCommand BindUiSignSubcommand(UiSignSubcommand command);
86 |
87 | @Binds
88 | @IntoMap
89 | @StringKey("cancel")
90 | abstract InteractionCommand BindCancelSignSubcommand(CancelSignSubcommand command);
91 |
92 | @Binds
93 | @IntoMap
94 | @StringKey("status")
95 | abstract InteractionCommand BindStatusSignSubcommand(StatusSignSubcommand command);
96 |
97 | @Binds
98 | @IntoMap
99 | @StringKey("copy")
100 | abstract InteractionCommand BindCopySignSubcommand(CopySignSubcommand command);
101 |
102 | @Binds
103 | @IntoMap
104 | @StringKey("cut")
105 | abstract InteractionCommand BindCutSignSubcommand(CutSignSubcommand command);
106 |
107 | @Binds
108 | @IntoMap
109 | @StringKey("paste")
110 | abstract InteractionCommand BindPasteSignSubcommand(PasteSignSubcommand command);
111 |
112 | @Binds
113 | @IntoMap
114 | @StringKey("undo")
115 | abstract InteractionCommand BindUndoSignSubcommand(UndoSignSubcommand command);
116 |
117 | @Binds
118 | @IntoMap
119 | @StringKey("redo")
120 | abstract InteractionCommand BindRedoSignSubcommand(RedoSignSubcommand command);
121 |
122 | @Binds
123 | @IntoMap
124 | @StringKey("unwax")
125 | abstract InteractionCommand BindUnwaxSignSubcommand(UnwaxSignSubcommand command);
126 |
127 | @Binds
128 | @IntoMap
129 | @StringKey("wax")
130 | abstract InteractionCommand BindWaxSignSubcommand(WaxSignSubcommand command);
131 |
132 | @Binds
133 | @IntoMap
134 | @StringKey("version")
135 | abstract InteractionCommand BindVersionSignSubcommand(VersionSignSubcommand command);
136 | }
137 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/BlockStateNotPlacedException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class BlockStateNotPlacedException extends RuntimeException {
23 | public BlockStateNotPlacedException() {
24 | super();
25 | }
26 |
27 | public BlockStateNotPlacedException(String s) {
28 | super(s);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/ForbiddenSignEditException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class ForbiddenSignEditException extends RuntimeException {
23 | public ForbiddenSignEditException() {
24 | super();
25 | }
26 |
27 | public ForbiddenSignEditException(String s) {
28 | super(s);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/ForbiddenWaxedSignEditException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class ForbiddenWaxedSignEditException extends ForbiddenSignEditException {
23 | }
24 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/LineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | abstract public class LineSelectionException extends IllegalArgumentException {
23 | public LineSelectionException() {
24 | }
25 |
26 | public LineSelectionException(String var1) {
27 | super(var1);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/MissingLineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class MissingLineSelectionException extends LineSelectionException {
23 | public MissingLineSelectionException() {
24 | super();
25 | }
26 |
27 | public MissingLineSelectionException(String s) {
28 | super(s);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/NullClipboardException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class NullClipboardException extends NullPointerException {
23 | public NullClipboardException() {
24 | }
25 |
26 | public NullClipboardException(String s) {
27 | super(s);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/NumberParseLineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class NumberParseLineSelectionException extends LineSelectionException {
23 | public NumberParseLineSelectionException(String s) {
24 | super(s);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/OutOfBoundsLineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class OutOfBoundsLineSelectionException extends LineSelectionException {
23 | public OutOfBoundsLineSelectionException(String s) {
24 | super(s);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/RangeOrderLineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class RangeOrderLineSelectionException extends LineSelectionException {
23 | private final String wholeSelection;
24 | private final String invalidLowerBound;
25 | private final String invalidUpperBound;
26 |
27 | public RangeOrderLineSelectionException(String wholeSelection, String invalidLowerBound, String invalidUpperBound) {
28 | this.wholeSelection = wholeSelection;
29 | this.invalidLowerBound = invalidLowerBound;
30 | this.invalidUpperBound = invalidUpperBound;
31 | }
32 |
33 | @Override
34 | public String getMessage() {
35 | return this.wholeSelection;
36 | }
37 |
38 | public String getInvalidLowerBound() {
39 | return invalidLowerBound;
40 | }
41 |
42 | public String getInvalidUpperBound() {
43 | return invalidUpperBound;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/RangeParseLineSelectionException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class RangeParseLineSelectionException extends LineSelectionException {
23 | private final String wholeSelection;
24 | private final String badRange;
25 |
26 | public RangeParseLineSelectionException(String wholeSelection, String badRange) {
27 | this.wholeSelection = wholeSelection;
28 | this.badRange = badRange;
29 | }
30 |
31 | @Override
32 | public String getMessage() {
33 | return this.wholeSelection;
34 | }
35 |
36 | public String getBadRange() {
37 | return badRange;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/SignEditorInvocationException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class SignEditorInvocationException extends RuntimeException {
23 | private final Exception originalException;
24 |
25 | public SignEditorInvocationException(Exception originalException) {
26 | this.originalException = originalException;
27 | }
28 |
29 | public Exception getOriginalException() {
30 | return originalException;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/exceptions/SignTextHistoryStackBoundsException.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.exceptions;
21 |
22 | public class SignTextHistoryStackBoundsException extends IndexOutOfBoundsException {
23 | public SignTextHistoryStackBoundsException(String s) {
24 | super(s);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/integrations/NoopSignEditValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.integrations;
21 |
22 | import net.deltik.mc.signedit.shims.SideShim;
23 | import net.deltik.mc.signedit.shims.SignShim;
24 | import org.bukkit.entity.Player;
25 | import org.bukkit.event.block.SignChangeEvent;
26 |
27 | import javax.inject.Inject;
28 |
29 | public class NoopSignEditValidator implements SignEditValidator {
30 | @Inject
31 | public NoopSignEditValidator() {
32 | }
33 |
34 | @Override
35 | public void validate(SignShim proposedSign, SideShim signSide, Player player) {
36 | }
37 |
38 | @Override
39 | public void validate(SignChangeEvent signChangeEvent) {
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/integrations/SignEditValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.integrations;
21 |
22 | import net.deltik.mc.signedit.shims.SideShim;
23 | import net.deltik.mc.signedit.shims.SignShim;
24 | import org.bukkit.block.Sign;
25 | import org.bukkit.entity.Player;
26 | import org.bukkit.event.EventHandler;
27 | import org.bukkit.event.EventPriority;
28 | import org.bukkit.event.block.SignChangeEvent;
29 |
30 | public interface SignEditValidator {
31 | /**
32 | * Ensure that the changed sign passes checks before saving
33 | *
34 | * @param proposedSign A changed sign that has not had {@link Sign#update()} called yet
35 | * @param side The side of the sign that has staged changes
36 | * @param player The player that is trying to edit the sign
37 | */
38 | void validate(SignShim proposedSign, SideShim side, Player player);
39 |
40 | /**
41 | * Import sign changes from a {@link SignChangeEvent} and ensure that they pass checks before saving
42 | *
43 | * @param signChangeEvent A sign change event in the validation phase (i.e. not passed in by an {@link EventHandler}
44 | * with {@link EventPriority#MONITOR})
45 | */
46 | void validate(SignChangeEvent signChangeEvent);
47 | }
48 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/integrations/SignEditValidatorModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.integrations;
21 |
22 | import dagger.Binds;
23 | import dagger.Module;
24 | import dagger.Provides;
25 | import dagger.multibindings.IntoMap;
26 | import dagger.multibindings.StringKey;
27 | import net.deltik.mc.signedit.Configuration;
28 | import org.bukkit.plugin.Plugin;
29 | import org.bukkit.plugin.PluginManager;
30 |
31 | import javax.inject.Provider;
32 | import java.util.Map;
33 |
34 | @Module
35 | public abstract class SignEditValidatorModule {
36 | @Provides
37 | static PluginManager providePluginManager(Plugin plugin) {
38 | return plugin.getServer().getPluginManager();
39 | }
40 |
41 | @Provides
42 | static SignEditValidator provideSignEditValidator(
43 | Configuration config,
44 | Map> validatorProviders
45 | ) {
46 | return validatorProviders.get(config.getEditValidation().toLowerCase()).get();
47 | }
48 |
49 | @Binds
50 | @IntoMap
51 | @StringKey("standard")
52 | abstract SignEditValidator bindStandard(StandardSignEditValidator integration);
53 |
54 | @Binds
55 | @IntoMap
56 | @StringKey("extra")
57 | abstract SignEditValidator bindExtra(BreakReplaceSignEditValidator integration);
58 |
59 | @Binds
60 | @IntoMap
61 | @StringKey("none")
62 | abstract SignEditValidator bindNone(NoopSignEditValidator integration);
63 | }
64 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/integrations/StandardSignEditValidator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.integrations;
21 |
22 | import net.deltik.mc.signedit.exceptions.ForbiddenSignEditException;
23 | import net.deltik.mc.signedit.listeners.CoreSignEditListener;
24 | import net.deltik.mc.signedit.shims.SideShim;
25 | import net.deltik.mc.signedit.shims.SignShim;
26 | import org.bukkit.block.Block;
27 | import org.bukkit.block.Sign;
28 | import org.bukkit.entity.Player;
29 | import org.bukkit.event.block.SignChangeEvent;
30 | import org.bukkit.plugin.PluginManager;
31 | import org.jetbrains.annotations.NotNull;
32 |
33 | import javax.inject.Inject;
34 | import java.lang.reflect.Constructor;
35 | import java.lang.reflect.InvocationTargetException;
36 | import java.lang.reflect.Method;
37 | import java.util.Arrays;
38 |
39 | public class StandardSignEditValidator implements SignEditValidator {
40 | protected final PluginManager pluginManager;
41 |
42 | @Inject
43 | public StandardSignEditValidator(
44 | PluginManager pluginManager
45 | ) {
46 | this.pluginManager = pluginManager;
47 | }
48 |
49 | @Override
50 | public void validate(SignShim proposedSign, SideShim side, Player player) {
51 | SignChangeEvent signChangeEvent;
52 | try {
53 | Constructor> constructor = Arrays.stream(SignChangeEvent.class.getConstructors())
54 | .filter(c -> c.getParameterCount() == 4)
55 | .filter(c -> {
56 | Class>[] parameterTypes = c.getParameterTypes();
57 | return parameterTypes[0].equals(Block.class)
58 | && parameterTypes[1].equals(Player.class)
59 | && parameterTypes[2].equals(String[].class)
60 | && parameterTypes[3].isEnum();
61 | })
62 | .findFirst()
63 | .orElseThrow(() -> new NoSuchMethodException("No such constructor exists for SignChangeEvent"));
64 |
65 | Method enumValueOf = constructor.getParameterTypes()[3].getMethod("valueOf", String.class);
66 | Enum> enumValue = (Enum>) enumValueOf.invoke(null, side.name());
67 |
68 | signChangeEvent = (SignChangeEvent) constructor.newInstance(
69 | proposedSign.getImplementation().getBlock(),
70 | player,
71 | proposedSign.getSide(side).getLines(),
72 | enumValue
73 | );
74 | } catch (
75 | NoSuchMethodException |
76 | IllegalAccessException |
77 | InvocationTargetException |
78 | InstantiationException e
79 | ) {
80 | signChangeEvent = makeOldSignChangeEvent(proposedSign, side, player);
81 | }
82 |
83 | pluginManager.callEvent(signChangeEvent);
84 | validate(signChangeEvent);
85 | }
86 |
87 | /**
88 | * Creates a Bukkit 1.8-compatible {@link SignChangeEvent} without {@link Sign} sides
89 | *
90 | * @param proposedSign The {@link Sign} with new values that hasn't been updated with {@link Sign#update()} yet
91 | * @param side Which side of the {@link Sign} changed
92 | * (must be {@link SideShim#FRONT} because that was the only side before Bukkit 1.20)
93 | * @param player The {@link Player} who intends to change the {@link Sign}
94 | * @return A new {@link SignChangeEvent} that should be sent to
95 | * {@link PluginManager#callEvent(org.bukkit.event.Event)}
96 | */
97 | @SuppressWarnings("deprecation")
98 | @NotNull
99 | private SignChangeEvent makeOldSignChangeEvent(SignShim proposedSign, SideShim side, Player player) {
100 | if (side != SideShim.FRONT) {
101 | throw new IllegalArgumentException("Bug: Event support missing for editing back of sign");
102 | }
103 | return new SignChangeEvent(
104 | proposedSign.getImplementation().getBlock(),
105 | player,
106 | proposedSign.getSide(side).getLines()
107 | );
108 | }
109 |
110 | @Override
111 | public void validate(SignChangeEvent signChangeEvent) {
112 | Sign bukkitSign = CoreSignEditListener.getPlacedSignFromBlockEvent(signChangeEvent);
113 | SignShim proposedSign = new SignShim(bukkitSign);
114 | if (signChangeEvent.isCancelled()) {
115 | throw new ForbiddenSignEditException();
116 | }
117 | SideShim side = SideShim.fromSignChangeEvent(signChangeEvent);
118 | String[] newLines = signChangeEvent.getLines();
119 | for (int i = 0; i < newLines.length; i++) {
120 | proposedSign.getSide(side).setLine(i, newLines[i]);
121 | }
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/BookUiSignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.SignText;
25 | import net.deltik.mc.signedit.SignTextHistoryManager;
26 | import net.deltik.mc.signedit.shims.SideShim;
27 | import net.deltik.mc.signedit.shims.SignShim;
28 | import org.bukkit.Bukkit;
29 | import org.bukkit.Material;
30 | import org.bukkit.entity.Player;
31 | import org.bukkit.event.Event;
32 | import org.bukkit.event.inventory.InventoryClickEvent;
33 | import org.bukkit.event.player.PlayerEditBookEvent;
34 | import org.bukkit.inventory.ItemStack;
35 | import org.bukkit.inventory.PlayerInventory;
36 | import org.bukkit.inventory.meta.BookMeta;
37 | import org.bukkit.plugin.Plugin;
38 |
39 | import javax.inject.Inject;
40 |
41 | public class BookUiSignEditInteraction implements SignEditInteraction {
42 | private final Plugin plugin;
43 | private final SignEditInteractionManager interactionManager;
44 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
45 | private final SignText signText;
46 | private final SignTextHistoryManager historyManager;
47 | protected ItemStack originalItem;
48 | protected int originalItemIndex;
49 | protected Player player;
50 |
51 | @Inject
52 | public BookUiSignEditInteraction(
53 | Plugin plugin,
54 | SignEditInteractionManager interactionManager,
55 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
56 | SignText signText,
57 | SignTextHistoryManager historyManager
58 | ) {
59 | this.plugin = plugin;
60 | this.interactionManager = interactionManager;
61 | this.commsBuilder = commsBuilder;
62 | this.signText = signText;
63 | this.historyManager = historyManager;
64 | }
65 |
66 | @Override
67 | public String getName() {
68 | return "open_sign_editor";
69 | }
70 |
71 | @Override
72 | public void interact(Player player, SignShim sign, SideShim side) {
73 | interactionManager.setPendingInteraction(player, this);
74 |
75 | if (originalItem == null) {
76 | signText.setTargetSign(sign, side);
77 | signText.importSign();
78 | formatSignTextForEdit(signText);
79 | openSignEditor(player);
80 | return;
81 | }
82 |
83 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
84 | comms.tell(comms.t("right_click_air_to_open_sign_editor"));
85 | }
86 |
87 | @Override
88 | public String getActionHint(ChatComms comms) {
89 | if (originalItem == null) {
90 | return SignEditInteraction.super.getActionHint(comms);
91 | }
92 | return comms.t("right_click_air_to_apply_action_hint");
93 | }
94 |
95 | protected void openSignEditor(Player player) {
96 | this.player = player;
97 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
98 | PlayerInventory inventory = player.getInventory();
99 | ItemStack book = new ItemStack(Material.WRITABLE_BOOK, 1);
100 | BookMeta bookMeta = (BookMeta) book.getItemMeta();
101 | bookMeta.setDisplayName(comms.t("sign_editor_item_name"));
102 | bookMeta.setPages(String.join("\n", signText.getLines()));
103 | book.setItemMeta(bookMeta);
104 | originalItem = inventory.getItemInMainHand();
105 | originalItemIndex = inventory.getHeldItemSlot();
106 | inventory.setItemInMainHand(book);
107 | comms.tell(comms.t("right_click_air_to_open_sign_editor"));
108 | interactionManager.removePendingInteraction(player);
109 | interactionManager.setPendingInteraction(player, this);
110 | }
111 |
112 | @Override
113 | public void cleanup(Event event) {
114 | if (originalItem == null) return;
115 |
116 | if (event instanceof InventoryClickEvent) cleanupInventoryClickEvent((InventoryClickEvent) event);
117 | player.getInventory().setItem(originalItemIndex, originalItem);
118 |
119 | if (!(event instanceof PlayerEditBookEvent)) {
120 | return;
121 | }
122 |
123 | PlayerEditBookEvent editBookEvent = (PlayerEditBookEvent) event;
124 | editBookEvent.setCancelled(true);
125 | Bukkit.getScheduler().scheduleSyncDelayedTask(
126 | plugin,
127 | () -> player.getInventory().setItem(originalItemIndex, originalItem),
128 | 0
129 | );
130 | BookMeta meta = editBookEvent.getNewBookMeta();
131 | String[] newLines;
132 | if (meta.hasPages()) {
133 | String page = meta.getPage(1);
134 | newLines = page.split("\n");
135 | } else {
136 | newLines = new String[]{};
137 | }
138 | for (int i = 0; i < signText.getLines().length; i++) {
139 | String newLine;
140 | if (i >= newLines.length) {
141 | newLine = "";
142 | } else {
143 | newLine = newLines[i];
144 | }
145 | signText.setLine(i, newLine);
146 | }
147 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
148 |
149 | signText.applySignAutoWax(player, comms, signText::applySign);
150 | if (signText.signTextChanged()) {
151 | historyManager.getHistory(player).push(signText);
152 | }
153 |
154 | comms.compareSignText(signText);
155 | }
156 |
157 | private void cleanupInventoryClickEvent(InventoryClickEvent event) {
158 | if (originalItemIndex == event.getSlot()) {
159 | interactionManager.setPendingInteraction(player, this);
160 | event.setCancelled(true);
161 | }
162 | }
163 |
164 | protected void formatSignTextForEdit(SignText signText) {
165 | for (int i = 0; i < 4; i++) {
166 | signText.setLineLiteral(i, signText.getLineParsed(i));
167 | }
168 | }
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/CopySignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.shims.ISignSide;
24 | import net.deltik.mc.signedit.shims.SideShim;
25 | import net.deltik.mc.signedit.shims.SignShim;
26 | import org.bukkit.entity.Player;
27 |
28 | import javax.inject.Inject;
29 | import java.util.Arrays;
30 |
31 | import static net.deltik.mc.signedit.LineSelectorParser.ALL_LINES_SELECTED;
32 | import static net.deltik.mc.signedit.LineSelectorParser.NO_LINES_SELECTED;
33 |
34 | public class CopySignEditInteraction implements SignEditInteraction {
35 | private final ArgParser argParser;
36 | private final SignText signText;
37 | private final SignTextClipboardManager clipboardManager;
38 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
39 |
40 | @Inject
41 | public CopySignEditInteraction(
42 | ArgParser argParser,
43 | SignText signText,
44 | SignTextClipboardManager clipboardManager,
45 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder
46 | ) {
47 | this.argParser = argParser;
48 | this.signText = signText;
49 | this.clipboardManager = clipboardManager;
50 | this.commsBuilder = commsBuilder;
51 | }
52 |
53 | @Override
54 | public void interact(Player player, SignShim sign, SideShim side) {
55 | int[] selectedLines = argParser.getLinesSelection();
56 | if (Arrays.equals(selectedLines, NO_LINES_SELECTED)) {
57 | selectedLines = ALL_LINES_SELECTED;
58 | }
59 | ISignSide signSide = sign.getSide(side);
60 | for (int selectedLine : selectedLines) {
61 | signText.setLineLiteral(selectedLine, signSide.getLine(selectedLine));
62 | }
63 |
64 | clipboardManager.setClipboard(player, signText);
65 |
66 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
67 | comms.tell(comms.t("lines_copied_section"));
68 | comms.dumpLines(signText.getLines());
69 | }
70 |
71 | @Override
72 | public String getName() {
73 | return "copy_sign_text";
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/CutSignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.integrations.SignEditValidator;
24 | import net.deltik.mc.signedit.shims.ISignSide;
25 | import net.deltik.mc.signedit.shims.SideShim;
26 | import net.deltik.mc.signedit.shims.SignShim;
27 | import org.bukkit.entity.Player;
28 |
29 | import javax.inject.Inject;
30 | import java.util.Arrays;
31 |
32 | import static net.deltik.mc.signedit.LineSelectorParser.ALL_LINES_SELECTED;
33 | import static net.deltik.mc.signedit.LineSelectorParser.NO_LINES_SELECTED;
34 |
35 | public class CutSignEditInteraction implements SignEditInteraction {
36 | private final ArgParser argParser;
37 | private final SignText sourceSign;
38 | private final SignText clipboard;
39 | private final SignTextClipboardManager clipboardManager;
40 | private final SignTextHistoryManager historyManager;
41 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
42 |
43 | @Inject
44 | public CutSignEditInteraction(
45 | ArgParser argParser,
46 | SignText signText,
47 | SignEditValidator validator,
48 | SignTextClipboardManager clipboardManager,
49 | SignTextHistoryManager historyManager,
50 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder
51 | ) {
52 | this.argParser = argParser;
53 | this.sourceSign = signText;
54 | this.clipboard = new SignText(validator);
55 | this.clipboardManager = clipboardManager;
56 | this.historyManager = historyManager;
57 | this.commsBuilder = commsBuilder;
58 | }
59 |
60 | @Override
61 | public void interact(Player player, SignShim sign, SideShim side) {
62 | int[] selectedLines = argParser.getLinesSelection();
63 | if (Arrays.equals(selectedLines, NO_LINES_SELECTED)) {
64 | selectedLines = ALL_LINES_SELECTED;
65 | }
66 |
67 | sourceSign.setTargetSign(sign, side);
68 |
69 | ISignSide signSide = sign.getSide(side);
70 | for (int selectedLine : selectedLines) {
71 | clipboard.setLineLiteral(selectedLine, signSide.getLine(selectedLine));
72 | sourceSign.setLineLiteral(selectedLine, "");
73 | }
74 |
75 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
76 |
77 | sourceSign.applySignAutoWax(player, comms, sourceSign::applySign);
78 | if (sourceSign.signTextChanged()) {
79 | historyManager.getHistory(player).push(sourceSign);
80 | }
81 | clipboardManager.setClipboard(player, clipboard);
82 |
83 | comms.tell(comms.t("lines_cut_section"));
84 | comms.dumpLines(clipboard.getLines());
85 | }
86 |
87 | @Override
88 | public String getName() {
89 | return "cut_sign_text";
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/InteractionCommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | public interface InteractionCommand {
23 | SignEditInteraction execute();
24 |
25 | /**
26 | * @return Whether this interaction is permitted to execute
27 | */
28 | boolean isPermitted();
29 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/PasteSignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.shims.SideShim;
24 | import net.deltik.mc.signedit.shims.SignShim;
25 | import org.bukkit.entity.Player;
26 |
27 | import javax.inject.Inject;
28 | import javax.inject.Provider;
29 |
30 | public class PasteSignEditInteraction implements SignEditInteraction {
31 | private final SignTextClipboardManager clipboardManager;
32 | private final Provider signTextProvider;
33 | private final SignTextHistoryManager historyManager;
34 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
35 |
36 | @Inject
37 | public PasteSignEditInteraction(
38 | SignTextClipboardManager clipboardManager,
39 | Provider signTextProvider,
40 | SignTextHistoryManager historyManager,
41 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder
42 | ) {
43 | this.clipboardManager = clipboardManager;
44 | this.signTextProvider = signTextProvider;
45 | this.historyManager = historyManager;
46 | this.commsBuilder = commsBuilder;
47 | }
48 |
49 | @Override
50 | public void interact(Player player, SignShim sign, SideShim side) {
51 | SignText clipboard = clipboardManager.getClipboard(player);
52 | SignText signText = signTextProvider.get();
53 | signText.setTargetSign(sign, side);
54 |
55 | for (int i = 0; i < clipboard.getLines().length; i++) {
56 | signText.setLineLiteral(i, clipboard.getLine(i));
57 | }
58 |
59 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
60 |
61 | signText.applySignAutoWax(player, comms, signText::applySign);
62 | if (signText.signTextChanged()) {
63 | historyManager.getHistory(player).push(signText);
64 | }
65 |
66 | comms.compareSignText(signText);
67 | }
68 |
69 | @Override
70 | public String getName() {
71 | return "paste_lines_from_clipboard";
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/SetSignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.SignText;
25 | import net.deltik.mc.signedit.SignTextHistoryManager;
26 | import net.deltik.mc.signedit.shims.SideShim;
27 | import net.deltik.mc.signedit.shims.SignShim;
28 | import org.bukkit.entity.Player;
29 |
30 | import javax.inject.Inject;
31 |
32 | public class SetSignEditInteraction implements SignEditInteraction {
33 | private final SignText signText;
34 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
35 | private final SignTextHistoryManager historyManager;
36 |
37 | @Inject
38 | public SetSignEditInteraction(
39 | SignText signText,
40 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
41 | SignTextHistoryManager historyManager
42 | ) {
43 | this.signText = signText;
44 | this.commsBuilder = commsBuilder;
45 | this.historyManager = historyManager;
46 | }
47 |
48 | @Override
49 | public String getName() {
50 | return "change_sign_text";
51 | }
52 |
53 | @Override
54 | public void interact(Player player, SignShim sign, SideShim side) {
55 | signText.setTargetSign(sign, side);
56 |
57 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
58 |
59 | signText.applySignAutoWax(player, comms, signText::applySign);
60 | if (signText.signTextChanged()) {
61 | historyManager.getHistory(player).push(signText);
62 | }
63 |
64 | comms.compareSignText(signText);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/SignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.shims.SideShim;
24 | import net.deltik.mc.signedit.shims.SignShim;
25 | import org.bukkit.entity.Player;
26 | import org.bukkit.event.Event;
27 | import org.bukkit.event.HandlerList;
28 | import org.jetbrains.annotations.NotNull;
29 |
30 | public interface SignEditInteraction {
31 | void interact(Player player, SignShim sign, SideShim side);
32 |
33 | default String getName() {
34 | return this.getClass().getSimpleName();
35 | }
36 |
37 | default String getActionHint(ChatComms comms) {
38 | return comms.t("right_click_sign_to_apply_action_hint");
39 | }
40 |
41 | default void cleanup(Event event) {
42 | }
43 |
44 | default void cleanup() {
45 | cleanup(new Event() {
46 | @NotNull
47 | @Override
48 | public HandlerList getHandlers() {
49 | return new HandlerList();
50 | }
51 | });
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/SignEditInteractionManager.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import org.bukkit.entity.Player;
25 | import org.bukkit.event.Event;
26 |
27 | import javax.inject.Inject;
28 | import javax.inject.Provider;
29 | import javax.inject.Singleton;
30 | import java.util.HashMap;
31 | import java.util.Map;
32 |
33 | @Singleton
34 | public class SignEditInteractionManager {
35 | protected final Provider commsBuilderProvider;
36 | protected final Map pendingInteractions = new HashMap<>();
37 |
38 | @Inject
39 | public SignEditInteractionManager(
40 | Provider commsBuilderProvider
41 | ) {
42 | this.commsBuilderProvider = commsBuilderProvider;
43 | }
44 |
45 | public void endInteraction(Player player, Event event) {
46 | try {
47 | removePendingInteraction(player).cleanup(event);
48 | } catch (Throwable e) {
49 | ChatComms comms = commsBuilderProvider.get().commandSender(player).build().comms();
50 | comms.reportException(e);
51 | }
52 | }
53 |
54 | public void setPendingInteraction(Player player, SignEditInteraction interaction) {
55 | if (pendingInteractions.get(player) != null) {
56 | removePendingInteraction(player).cleanup();
57 | }
58 | pendingInteractions.put(player, interaction);
59 | }
60 |
61 | public boolean isInteractionPending(Player player) {
62 | return pendingInteractions.containsKey(player);
63 | }
64 |
65 | public SignEditInteraction removePendingInteraction(Player player) {
66 | return pendingInteractions.remove(player);
67 | }
68 |
69 | public SignEditInteraction getPendingInteraction(Player player) {
70 | return pendingInteractions.get(player);
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/SignEditInteractionModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import dagger.Binds;
23 | import dagger.Module;
24 | import dagger.multibindings.IntoMap;
25 | import dagger.multibindings.StringKey;
26 |
27 | @Module
28 | public abstract class SignEditInteractionModule {
29 | public static final String UI_NATIVE = "NativeUi";
30 | public static final String UI_EDITABLE_BOOK = "EditableBookUi";
31 |
32 | @Binds
33 | @IntoMap
34 | @StringKey("Set")
35 | abstract SignEditInteraction bindSet(SetSignEditInteraction interaction);
36 |
37 | @Binds
38 | @IntoMap
39 | @StringKey(UI_EDITABLE_BOOK)
40 | abstract SignEditInteraction bindEditableBookUi(BookUiSignEditInteraction interaction);
41 |
42 | @Binds
43 | @IntoMap
44 | @StringKey(UI_NATIVE)
45 | abstract SignEditInteraction bindNativeUi(UiSignEditInteraction interaction);
46 |
47 | @Binds
48 | @IntoMap
49 | @StringKey("Copy")
50 | abstract SignEditInteraction bindCopy(CopySignEditInteraction interaction);
51 |
52 | @Binds
53 | @IntoMap
54 | @StringKey("Cut")
55 | abstract SignEditInteraction bindCut(CutSignEditInteraction interaction);
56 |
57 | @Binds
58 | @IntoMap
59 | @StringKey("Paste")
60 | abstract SignEditInteraction bindPaste(PasteSignEditInteraction interaction);
61 |
62 | @Binds
63 | @IntoMap
64 | @StringKey("Wax")
65 | abstract SignEditInteraction bindWax(WaxSignEditInteraction interaction);
66 | }
67 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/interactions/WaxSignEditInteraction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.interactions;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.SignText;
25 | import net.deltik.mc.signedit.exceptions.BlockStateNotPlacedException;
26 | import net.deltik.mc.signedit.exceptions.ForbiddenSignEditException;
27 | import net.deltik.mc.signedit.shims.SideShim;
28 | import net.deltik.mc.signedit.shims.SignHelpers;
29 | import net.deltik.mc.signedit.shims.SignShim;
30 | import org.bukkit.Location;
31 | import org.bukkit.Particle;
32 | import org.bukkit.Sound;
33 | import org.bukkit.World;
34 | import org.bukkit.block.BlockState;
35 | import org.bukkit.block.Sign;
36 | import org.bukkit.entity.Player;
37 | import org.jetbrains.annotations.NotNull;
38 | import org.jetbrains.annotations.Nullable;
39 |
40 | import javax.inject.Inject;
41 |
42 | public class WaxSignEditInteraction implements SignEditInteraction {
43 | private final SignText signText;
44 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
45 |
46 | @Inject
47 | public WaxSignEditInteraction(
48 | SignText signText,
49 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder
50 | ) {
51 | this.signText = signText;
52 | this.commsBuilder = commsBuilder;
53 | }
54 |
55 | @Override
56 | public void interact(Player player, SignShim sign, SideShim side) {
57 | signText.setTargetSign(sign, side);
58 |
59 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
60 |
61 | Sign signImplementation = sign.getImplementation();
62 | BlockState realSign = signImplementation.getBlock().getState();
63 | if (!(realSign instanceof Sign)) {
64 | throw new BlockStateNotPlacedException();
65 | }
66 |
67 | boolean stagedEditable = Boolean.TRUE.equals(signText.shouldBeEditable());
68 | boolean realEditable = SignHelpers.isEditable((Sign) realSign);
69 |
70 | if (stagedEditable == realEditable) {
71 | comms.tell(comms.t("sign_did_not_change"));
72 | return;
73 | }
74 |
75 | signText.applySign(player);
76 |
77 | realSign = signImplementation.getBlock().getState();
78 | realEditable = SignHelpers.isEditable((Sign) realSign);
79 |
80 | if (stagedEditable != realEditable) {
81 | throw new ForbiddenSignEditException();
82 | } else if (realEditable) {
83 | comms.tell(comms.t("wax_removed"));
84 | playWaxOff(signImplementation);
85 | } else {
86 | comms.tell(comms.t("wax_applied"));
87 | playWaxOn(signImplementation);
88 | }
89 | }
90 |
91 | @Override
92 | public String getName() {
93 | if (Boolean.TRUE.equals(signText.shouldBeEditable())) {
94 | return "unwax_sign";
95 | } else {
96 | return "wax_sign";
97 | }
98 | }
99 |
100 | /**
101 | * Send a firework-like burst initiating from the middle of the specified {@link BlockState} to its {@link World}
102 | *
103 | * @param block The block state from where the burst should originate
104 | * @param particle The kind of particle to spawn in the firework, or none if null
105 | * @param sound The sound to play at the block, or none if null
106 | * @throws BlockStateNotPlacedException if the block state is not placed or somehow isn't in the {@link World}
107 | */
108 | private static void sendAudioVisualBurst(
109 | @NotNull BlockState block,
110 | @Nullable Particle particle,
111 | @Nullable Sound sound
112 | ) {
113 | Location signLocation = block.getLocation().add(0.5, 0.5, 0.5);
114 | World world = signLocation.getWorld();
115 | if (world == null || !block.isPlaced()) {
116 | throw new BlockStateNotPlacedException();
117 | }
118 | if (particle != null) {
119 | world.spawnParticle(particle, signLocation, 20, 0.3, 0.3, 0.3, 0.5);
120 | }
121 | if (sound != null) {
122 | world.playSound(signLocation, sound, 1, 1);
123 | }
124 | }
125 |
126 | /**
127 | * Play the "wax off" animation on the specified {@link Sign} by spawning particle effects and playing a sound
128 | *
129 | * @param sign The sign on which to play the "wax off" animation
130 | */
131 | public static void playWaxOff(Sign sign) {
132 | Particle confirmationParticle = Particle.valueOf("WAX_OFF");
133 | Sound confirmationSound = Sound.valueOf("BLOCK_SIGN_WAXED_INTERACT_FAIL");
134 | sendAudioVisualBurst(sign, confirmationParticle, confirmationSound);
135 | }
136 |
137 | /**
138 | * Play the "wax on" animation on the specified {@link Sign} by spawning particle effects and playing a sound
139 | *
140 | * @param sign The sign on which to play the "wax on" animation
141 | */
142 | public static void playWaxOn(Sign sign) {
143 | Particle confirmationParticle = Particle.valueOf("WAX_ON");
144 | Sound confirmationSound = Sound.valueOf("ITEM_HONEYCOMB_WAX_ON");
145 | sendAudioVisualBurst(sign, confirmationParticle, confirmationSound);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/listeners/BookUiSignEditListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.listeners;
21 |
22 | import net.deltik.mc.signedit.interactions.BookUiSignEditInteraction;
23 | import net.deltik.mc.signedit.interactions.SignEditInteractionManager;
24 | import org.bukkit.Material;
25 | import org.bukkit.entity.HumanEntity;
26 | import org.bukkit.entity.Player;
27 | import org.bukkit.event.EventHandler;
28 | import org.bukkit.event.inventory.InventoryClickEvent;
29 | import org.bukkit.event.player.PlayerDropItemEvent;
30 | import org.bukkit.event.player.PlayerEditBookEvent;
31 | import org.bukkit.event.player.PlayerItemHeldEvent;
32 | import org.bukkit.inventory.ItemStack;
33 |
34 | import javax.inject.Inject;
35 | import javax.inject.Singleton;
36 |
37 | @Singleton
38 | public class BookUiSignEditListener extends SignEditListener {
39 | private final SignEditInteractionManager interactionManager;
40 |
41 | @Inject
42 | public BookUiSignEditListener(
43 | SignEditInteractionManager interactionManager
44 | ) {
45 | this.interactionManager = interactionManager;
46 | }
47 |
48 | @EventHandler
49 | public void onSignChangeBookMode(PlayerEditBookEvent event) {
50 | Player player = event.getPlayer();
51 |
52 | if (interactionManager.getPendingInteraction(player) instanceof BookUiSignEditInteraction) {
53 | interactionManager.endInteraction(player, event);
54 | }
55 | }
56 |
57 | @EventHandler
58 | public void onLeaveSignEditorBook(PlayerItemHeldEvent event) {
59 | Player player = event.getPlayer();
60 |
61 | if (interactionManager.getPendingInteraction(player) instanceof BookUiSignEditInteraction) {
62 | interactionManager.endInteraction(player, event);
63 | }
64 | }
65 |
66 | @EventHandler
67 | public void onDropSignEditorBook(PlayerDropItemEvent event) {
68 | Player player = event.getPlayer();
69 | if (!interactionManager.isInteractionPending(player)) return;
70 |
71 | ItemStack droppedItem = event.getItemDrop().getItemStack();
72 | Material droppedItemType = droppedItem.getType();
73 | if (droppedItemType == Material.WRITABLE_BOOK || droppedItemType == Material.WRITTEN_BOOK) {
74 | ItemStack item = event.getItemDrop().getItemStack();
75 | event.getItemDrop().remove();
76 | player.getInventory().setItemInMainHand(item);
77 | interactionManager.endInteraction(player, event);
78 | }
79 | }
80 |
81 | @EventHandler
82 | public void onClickSignEditorBook(InventoryClickEvent event) {
83 | HumanEntity human = event.getWhoClicked();
84 | if (!(human instanceof Player)) return;
85 | Player player = (Player) human;
86 | if (!interactionManager.isInteractionPending(player)) return;
87 |
88 | interactionManager.endInteraction(player, event);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/listeners/SignEditListener.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.listeners;
21 |
22 | import org.bukkit.event.Listener;
23 |
24 | import javax.inject.Singleton;
25 |
26 | @Singleton
27 | public abstract class SignEditListener implements Listener {
28 | }
29 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/listeners/SignEditListenerModule.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.listeners;
21 |
22 | import dagger.Binds;
23 | import dagger.Module;
24 | import dagger.Provides;
25 | import dagger.multibindings.ElementsIntoSet;
26 | import dagger.multibindings.IntoMap;
27 | import dagger.multibindings.StringKey;
28 | import net.deltik.mc.signedit.Configuration;
29 | import net.deltik.mc.signedit.CraftBukkitReflector;
30 | import net.deltik.mc.signedit.interactions.SignEditInteractionModule;
31 | import net.deltik.mc.signedit.subcommands.UiSignSubcommand;
32 |
33 | import javax.inject.Provider;
34 | import java.util.HashSet;
35 | import java.util.Map;
36 | import java.util.Set;
37 |
38 | @Module
39 | public abstract class SignEditListenerModule {
40 | private static final String CORE = "Core";
41 |
42 | @Provides
43 | @ElementsIntoSet
44 | static Set provideSignEditListeners(
45 | Map> listenerProviders,
46 | Configuration config,
47 | CraftBukkitReflector reflector
48 | ) {
49 | Set listeners = new HashSet<>();
50 | listeners.add(listenerProviders.get(CORE).get());
51 | String implementationName = UiSignSubcommand.getImplementationName(config, reflector);
52 | if (listenerProviders.containsKey(implementationName)) {
53 | listeners.add(listenerProviders.get(implementationName).get());
54 | }
55 | return listeners;
56 | }
57 |
58 | @Binds
59 | @IntoMap
60 | @StringKey(CORE)
61 | abstract SignEditListener bindCore(CoreSignEditListener listener);
62 |
63 | @Binds
64 | @IntoMap
65 | @StringKey(SignEditInteractionModule.UI_EDITABLE_BOOK)
66 | abstract SignEditListener bindBookUi(BookUiSignEditListener listener);
67 | }
68 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/CalculatedBlockHitResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.Location;
23 | import org.bukkit.block.Block;
24 | import org.bukkit.block.BlockFace;
25 | import org.bukkit.entity.LivingEntity;
26 | import org.bukkit.util.Vector;
27 |
28 | public class CalculatedBlockHitResult implements IBlockHitResult {
29 | private final LivingEntity entity;
30 | private final Block targetBlock;
31 | private final Location targetBlockLocation;
32 |
33 | public CalculatedBlockHitResult(LivingEntity entity, int maxDistance) {
34 | this.entity = entity;
35 | this.targetBlock = entity.getTargetBlock(null, maxDistance);
36 | this.targetBlockLocation = targetBlock.getLocation();
37 | }
38 |
39 | @Override
40 | public Block getHitBlock() {
41 | return targetBlock;
42 | }
43 |
44 | @Override
45 | public BlockFace getHitBlockFace() {
46 | Vector direction = entity.getLocation().toVector().subtract(targetBlockLocation.toVector()).normalize();
47 | double x = direction.getX();
48 | double z = direction.getZ();
49 |
50 | if (Math.abs(x) > Math.abs(z)) {
51 | if (x > 0) {
52 | return BlockFace.WEST;
53 | } else {
54 | return BlockFace.EAST;
55 | }
56 | } else {
57 | if (z > 0) {
58 | return BlockFace.NORTH;
59 | } else {
60 | return BlockFace.SOUTH;
61 | }
62 | }
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/IBlockHitResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.block.Block;
23 | import org.bukkit.block.BlockFace;
24 |
25 | public interface IBlockHitResult {
26 | Block getHitBlock();
27 |
28 | BlockFace getHitBlockFace();
29 | }
30 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/ISignSide.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.DyeColor;
23 | import org.jetbrains.annotations.Nullable;
24 |
25 | public interface ISignSide {
26 | /**
27 | * Gets the line of text at the specified index on this side of the sign.
28 | *
29 | * For example, getLine(0)
will return the first line of text.
30 | *
31 | * @param index Line number to get the text from, starting at 0
32 | * @return Text on the given line
33 | * @throws IndexOutOfBoundsException Thrown when the line does not exist
34 | */
35 | String getLine(int index) throws IndexOutOfBoundsException;
36 |
37 | /**
38 | * Gets all the lines of text currently on this side of the sign.
39 | *
40 | * @return Array of Strings containing each line of text
41 | */
42 | String[] getLines();
43 |
44 | /**
45 | * Sets the line of text at the specified index on this side of the sign.
46 | *
47 | * For example, setLine(0, "Line One")
will set the first
48 | * line of text to "Line One".
49 | *
50 | * @param index Line number to set the text at, starting from 0
51 | * @param line New text to set at the specified index
52 | * @throws IndexOutOfBoundsException If the index is out of the range 0..3
53 | */
54 | void setLine(int index, String line) throws IndexOutOfBoundsException;
55 |
56 | /**
57 | * Gets whether this side of the sign has glowing text.
58 | *
59 | * @return if this side of the sign has glowing text
60 | */
61 | boolean isGlowingText();
62 |
63 | /**
64 | * Sets whether this side of the sign has glowing text.
65 | *
66 | * @param glowing if this side of the sign has glowing text
67 | */
68 | void setGlowingText(boolean glowing);
69 |
70 | /**
71 | * Gets the color of this object.
72 | * This may be null to represent the default color of an object if the object has a special default color.
73 | *
74 | * @return The {@link DyeColor} of this object.
75 | */
76 | @Nullable
77 | DyeColor getColor();
78 |
79 | /**
80 | * Sets the color of this object to the specified {@link DyeColor}.
81 | * This may be null to represent the default color of an object if the object has a special default color.
82 | *
83 | * @param color The color of the object as a {@link DyeColor}
84 | * @throws NullPointerException if argument is null and this implementation does not support null
85 | */
86 | void setColor(@Nullable DyeColor color);
87 | }
88 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/PreciseBlockHitResult.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.block.Block;
23 | import org.bukkit.block.BlockFace;
24 |
25 | import java.lang.reflect.InvocationTargetException;
26 |
27 | public class PreciseBlockHitResult implements IBlockHitResult {
28 | private final Object rayTraceResultLike;
29 | private final Class> rayTraceResultLikeClass;
30 |
31 | public PreciseBlockHitResult(Object rayTraceResultLike) {
32 | this.rayTraceResultLike = rayTraceResultLike;
33 | if (rayTraceResultLike == null) {
34 | this.rayTraceResultLikeClass = null;
35 | } else {
36 | this.rayTraceResultLikeClass = rayTraceResultLike.getClass();
37 | }
38 | }
39 |
40 | @Override
41 | public Block getHitBlock() {
42 | if (rayTraceResultLike == null) {
43 | return null;
44 | }
45 |
46 | try {
47 | return (Block) rayTraceResultLikeClass.getMethod("getHitBlock").invoke(rayTraceResultLike);
48 | } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
49 | throw new IllegalStateException("Unexpected structure of RayTraceResult-like object");
50 | }
51 | }
52 |
53 | @Override
54 | public BlockFace getHitBlockFace() {
55 | if (rayTraceResultLike == null) {
56 | return null;
57 | }
58 |
59 | try {
60 | return (BlockFace) rayTraceResultLikeClass.getMethod("getHitBlockFace").invoke(rayTraceResultLike);
61 | } catch (InvocationTargetException | NoSuchMethodException | IllegalAccessException e) {
62 | throw new IllegalStateException("Unexpected structure of RayTraceResult-like object");
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/SideShim.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.block.BlockFace;
23 | import org.bukkit.block.Sign;
24 | import org.bukkit.block.data.BlockData;
25 | import org.bukkit.block.data.Directional;
26 | import org.bukkit.block.data.Rotatable;
27 | import org.bukkit.entity.LivingEntity;
28 | import org.bukkit.event.block.SignChangeEvent;
29 | import org.bukkit.util.Vector;
30 | import org.jetbrains.annotations.NotNull;
31 |
32 | import java.lang.reflect.InvocationTargetException;
33 |
34 | public enum SideShim {
35 | FRONT,
36 | BACK;
37 |
38 | public static SideShim fromRelativePosition(@NotNull Sign sign, @NotNull LivingEntity entity) {
39 | if (!SignHelpers.hasSignSideFeature()) {
40 | return FRONT; // Compatibility with Bukkit 1.19.4
41 | }
42 |
43 | Vector vector = entity.getEyeLocation().toVector().subtract(sign.getLocation().add(0.5, 0.5, 0.5).toVector());
44 | BlockData blockData;
45 | try {
46 | blockData = sign.getBlockData();
47 | } catch (NoSuchMethodError e) {
48 | return FRONT; // Compatibility with Bukkit 1.12.2 and older
49 | }
50 |
51 | Vector signDirection = getSignDirection(blockData);
52 | return vector.dot(signDirection) > 0 ? FRONT : BACK;
53 | }
54 |
55 | public static SideShim fromSignChangeEvent(SignChangeEvent event) {
56 | try {
57 | Object getSide = SignChangeEvent.class.getMethod("getSide").invoke(event);
58 | String enumValue = (String) getSide.getClass().getMethod("name").invoke(getSide);
59 | return valueOf(enumValue);
60 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
61 | return FRONT;
62 | }
63 | }
64 |
65 | @NotNull
66 | private static Vector getSignDirection(BlockData blockData) {
67 | BlockFace signFace;
68 |
69 | if (blockData instanceof Directional) {
70 | Directional directional = (Directional) blockData;
71 | signFace = directional.getFacing();
72 | } else if (blockData instanceof Rotatable) {
73 | Rotatable rotatable = (Rotatable) blockData;
74 | signFace = rotatable.getRotation();
75 | } else {
76 | signFace = BlockFace.NORTH;
77 | }
78 |
79 | return new Vector(signFace.getModX(), signFace.getModY(), signFace.getModZ());
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/SignShim.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.block.Sign;
23 | import org.jetbrains.annotations.NotNull;
24 |
25 | import java.lang.reflect.InvocationTargetException;
26 |
27 | public class SignShim {
28 | @NotNull
29 | private final Sign implementation;
30 |
31 | public SignShim(@NotNull Sign implementation) {
32 | this.implementation = implementation;
33 | }
34 |
35 | @NotNull
36 | public ISignSide getSide(@NotNull SideShim side) {
37 | try {
38 | Object rawGetSide = SignHelpers.rawGetSide(implementation, side.toString());
39 | if (rawGetSide == null) {
40 | return getFrontSignSide();
41 | }
42 | return new SignSideShim(rawGetSide);
43 | } catch (InvocationTargetException e) {
44 | throw new IllegalStateException("Unable to call method: getSide", e);
45 | }
46 | }
47 |
48 | @NotNull
49 | public Sign getImplementation() {
50 | return implementation;
51 | }
52 |
53 | /**
54 | * Proxy this {@link Sign} as the front side only for Bukkit 1.19.4 and below
55 | *
56 | * @return The front sign side as the {@link SignSideShim} adapter
57 | */
58 | @NotNull
59 | private SignSideShim getFrontSignSide() {
60 | return new SignSideShim(implementation);
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/shims/SignSideShim.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.shims;
21 |
22 | import org.bukkit.DyeColor;
23 | import org.jetbrains.annotations.NotNull;
24 | import org.jetbrains.annotations.Nullable;
25 |
26 | import java.lang.reflect.InvocationTargetException;
27 | import java.lang.reflect.Method;
28 |
29 | public class SignSideShim implements ISignSide {
30 | private final Object signSideLike;
31 | private final Class> signSideLikeClass;
32 |
33 | public SignSideShim(@NotNull Object signSideLike) {
34 | this.signSideLike = signSideLike;
35 | this.signSideLikeClass = signSideLike.getClass();
36 | }
37 |
38 | @NotNull
39 | public String[] getLines() {
40 | try {
41 | Method getLines = signSideLikeClass.getMethod("getLines");
42 | return (String[]) getLines.invoke(signSideLike);
43 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
44 | throw new IllegalStateException("Unexpected structure of Sign-like object");
45 | }
46 | }
47 |
48 | @NotNull
49 | public String getLine(int index) throws IndexOutOfBoundsException {
50 | try {
51 | Method getLine = signSideLikeClass.getMethod("getLine", int.class);
52 | return (String) getLine.invoke(signSideLike, index);
53 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
54 | throw new IllegalStateException("Unexpected structure of Sign-like object");
55 | }
56 | }
57 |
58 | public void setLine(int index, @NotNull String line) throws IndexOutOfBoundsException {
59 | try {
60 | Method setLine = signSideLikeClass.getMethod("setLine", int.class, String.class);
61 | setLine.invoke(signSideLike, index, line);
62 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
63 | throw new IllegalStateException("Unexpected structure of Sign-like object");
64 | }
65 | }
66 |
67 | public boolean isGlowingText() {
68 | try {
69 | Method isGlowingText = signSideLikeClass.getMethod("isGlowingText");
70 | return (boolean) isGlowingText.invoke(signSideLike);
71 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
72 | throw new IllegalStateException("Unexpected structure of Sign-like object");
73 | }
74 | }
75 |
76 | public void setGlowingText(boolean glowing) {
77 | try {
78 | Method setGlowingText = signSideLikeClass.getMethod("setGlowingText", boolean.class);
79 | setGlowingText.invoke(signSideLike, glowing);
80 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
81 | throw new IllegalStateException("Unexpected structure of Sign-like object");
82 | }
83 | }
84 |
85 | @Nullable
86 | public DyeColor getColor() {
87 | try {
88 | Method getColor = signSideLikeClass.getMethod("getColor");
89 | return (DyeColor) getColor.invoke(signSideLike);
90 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
91 | throw new IllegalStateException("Unexpected structure of Sign-like object");
92 | }
93 | }
94 |
95 | public void setColor(@Nullable DyeColor color) {
96 | try {
97 | Method setColor = signSideLikeClass.getMethod("setColor", DyeColor.class);
98 | setColor.invoke(signSideLike, color);
99 | } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
100 | throw new IllegalStateException("Unexpected structure of Sign-like object");
101 | }
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/CancelSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
25 | import net.deltik.mc.signedit.interactions.SignEditInteractionManager;
26 | import org.bukkit.entity.Player;
27 |
28 | import javax.inject.Inject;
29 |
30 | public class CancelSignSubcommand extends SignSubcommand {
31 | private final SignEditInteractionManager interactionManager;
32 | private final Player player;
33 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
34 |
35 | @Inject
36 | public CancelSignSubcommand(
37 | SignEditInteractionManager interactionManager,
38 | Player player,
39 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder
40 | ) {
41 | super(player);
42 | this.interactionManager = interactionManager;
43 | this.player = player;
44 | this.commsBuilder = commsBuilder;
45 | }
46 |
47 | @Override
48 | public SignEditInteraction execute() {
49 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
50 |
51 | SignEditInteraction interaction = interactionManager.removePendingInteraction(player);
52 | if (interaction == null) {
53 | comms.tell(comms.t("no_pending_action_to_cancel"));
54 | } else {
55 | interaction.cleanup();
56 | comms.tell(comms.t("cancelled_pending_action"));
57 | }
58 | return null;
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/ClearSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.ArgParser;
23 | import net.deltik.mc.signedit.LineSelectorParser;
24 | import net.deltik.mc.signedit.SignText;
25 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
26 | import org.bukkit.entity.Player;
27 |
28 | import javax.inject.Inject;
29 | import javax.inject.Provider;
30 | import java.util.Map;
31 |
32 | public class ClearSignSubcommand extends SignSubcommand {
33 | private final Map> interactions;
34 | private final ArgParser argParser;
35 | private final SignText signText;
36 |
37 | @Inject
38 | public ClearSignSubcommand(
39 | Map> interactions,
40 | Player player,
41 | ArgParser argParser,
42 | SignText signText
43 | ) {
44 | super(player);
45 | this.interactions = interactions;
46 | this.argParser = argParser;
47 | this.signText = signText;
48 | }
49 |
50 | @Override
51 | public SignEditInteraction execute() {
52 | int[] selectedLines = argParser.getLinesSelection();
53 | if (selectedLines.length <= 0) {
54 | selectedLines = LineSelectorParser.ALL_LINES_SELECTED;
55 | }
56 |
57 | for (int selectedLine : selectedLines) {
58 | signText.setLine(selectedLine, "");
59 | }
60 |
61 | return interactions.get("Set").get();
62 | }
63 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/CopySignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
23 | import org.bukkit.entity.Player;
24 |
25 | import javax.inject.Inject;
26 | import javax.inject.Provider;
27 | import java.util.Map;
28 |
29 | public class CopySignSubcommand extends SignSubcommand {
30 | private final Map> interactions;
31 |
32 | @Inject
33 | public CopySignSubcommand(
34 | Player player,
35 | Map> interactions
36 | ) {
37 | super(player);
38 | this.interactions = interactions;
39 | }
40 |
41 | @Override
42 | public SignEditInteraction execute() {
43 | return interactions.get("Copy").get();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/CutSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
23 | import org.bukkit.entity.Player;
24 |
25 | import javax.inject.Inject;
26 | import javax.inject.Provider;
27 | import java.util.Map;
28 |
29 | public class CutSignSubcommand extends SignSubcommand {
30 | private final Map> interactions;
31 |
32 | @Inject
33 | public CutSignSubcommand(
34 | Player player,
35 | Map> interactions
36 | ) {
37 | super(player);
38 | this.interactions = interactions;
39 | }
40 |
41 | @Override
42 | public SignEditInteraction execute() {
43 | return interactions.get("Cut").get();
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/PasteSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.SignTextClipboardManager;
23 | import net.deltik.mc.signedit.exceptions.NullClipboardException;
24 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
25 | import org.bukkit.entity.Player;
26 |
27 | import javax.inject.Inject;
28 | import javax.inject.Provider;
29 | import java.util.Map;
30 |
31 | public class PasteSignSubcommand extends SignSubcommand {
32 | private final Map> interactions;
33 | private final Player player;
34 | private final SignTextClipboardManager clipboardManager;
35 |
36 | @Inject
37 | public PasteSignSubcommand(
38 | Map> interactions,
39 | Player player,
40 | SignTextClipboardManager clipboardManager
41 | ) {
42 | super(player);
43 | this.interactions = interactions;
44 | this.player = player;
45 | this.clipboardManager = clipboardManager;
46 | }
47 |
48 | @Override
49 | public SignEditInteraction execute() {
50 | if (clipboardManager.getClipboard(player) == null) {
51 | throw new NullClipboardException();
52 | }
53 |
54 | return interactions.get("Paste").get();
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/PerSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import javax.inject.Scope;
23 | import java.lang.annotation.Documented;
24 | import java.lang.annotation.Retention;
25 |
26 | import static java.lang.annotation.RetentionPolicy.RUNTIME;
27 |
28 | @Scope
29 | @Documented
30 | @Retention(RUNTIME)
31 | public @interface PerSubcommand {
32 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/RedoSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
24 | import org.bukkit.entity.Player;
25 |
26 | import javax.inject.Inject;
27 |
28 | public class RedoSignSubcommand extends SignSubcommand {
29 | private final Player player;
30 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
31 | private final SignTextHistoryManager historyManager;
32 |
33 | @Inject
34 | public RedoSignSubcommand(
35 | Player player,
36 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
37 | SignTextHistoryManager historyManager
38 | ) {
39 | super(player);
40 | this.player = player;
41 | this.commsBuilder = commsBuilder;
42 | this.historyManager = historyManager;
43 | }
44 |
45 | @Override
46 | public SignEditInteraction execute() {
47 | SignTextHistory history = historyManager.getHistory(player);
48 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
49 | SignText redoneSignText = history.redo(comms);
50 | comms.compareSignText(redoneSignText);
51 | return null;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/SetSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.ArgParser;
23 | import net.deltik.mc.signedit.SignText;
24 | import net.deltik.mc.signedit.exceptions.MissingLineSelectionException;
25 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
26 | import org.bukkit.entity.Player;
27 |
28 | import javax.inject.Inject;
29 | import javax.inject.Provider;
30 | import java.util.Map;
31 |
32 | public class SetSignSubcommand extends SignSubcommand {
33 | private final Map> interactions;
34 | private final ArgParser argParser;
35 | private final SignText signText;
36 |
37 | @Inject
38 | public SetSignSubcommand(
39 | Map> interactions,
40 | Player player,
41 | ArgParser argParser,
42 | SignText signText
43 | ) {
44 | super(player);
45 | this.interactions = interactions;
46 | this.argParser = argParser;
47 | this.signText = signText;
48 | }
49 |
50 | @Override
51 | public SignEditInteraction execute() {
52 | int[] selectedLines = argParser.getLinesSelection();
53 | if (selectedLines.length <= 0) {
54 | throw new MissingLineSelectionException();
55 | }
56 |
57 | String text = String.join(" ", argParser.getRemainder());
58 |
59 | for (int selectedLine : selectedLines) {
60 | signText.setLine(selectedLine, text);
61 | }
62 |
63 | return interactions.get("Set").get();
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/SignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.commands.SignCommand;
23 | import net.deltik.mc.signedit.interactions.InteractionCommand;
24 | import org.bukkit.entity.Player;
25 |
26 | public abstract class SignSubcommand extends Subcommand implements InteractionCommand {
27 | private final Player player;
28 |
29 | protected SignSubcommand(Player player) {
30 | this.player = player;
31 | }
32 |
33 | @Override
34 | public boolean isPermitted() {
35 | return // Legacy (< 1.4) permissions
36 | player.hasPermission("signedit.use") ||
37 | // /sign
38 | player.hasPermission("signedit." + SignCommand.COMMAND_NAME + "." + getName());
39 | }
40 |
41 | /**
42 | * Get the subcommand name
43 | */
44 | private String getName() {
45 | String simpleClassName = getClass().getSimpleName();
46 | int end = simpleClassName.lastIndexOf(SignSubcommand.class.getSimpleName());
47 | if (end != -1) {
48 | return simpleClassName.substring(0, end).toLowerCase();
49 | }
50 | return simpleClassName.toLowerCase();
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/SignSubcommandComponent.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import dagger.BindsInstance;
23 | import dagger.Subcomponent;
24 | import net.deltik.mc.signedit.ArgParser;
25 | import net.deltik.mc.signedit.ArgParserArgs;
26 | import net.deltik.mc.signedit.interactions.InteractionCommand;
27 | import net.deltik.mc.signedit.interactions.SignEditInteractionModule;
28 | import org.bukkit.entity.Player;
29 |
30 | import javax.inject.Provider;
31 | import java.util.Map;
32 |
33 | @PerSubcommand
34 | @Subcomponent(modules = {SignEditInteractionModule.class})
35 | public interface SignSubcommandComponent {
36 |
37 | Map> subcommandProviders();
38 |
39 | ArgParser argParser();
40 |
41 | @Subcomponent.Builder
42 | abstract class Builder {
43 | public abstract SignSubcommandComponent build();
44 |
45 | @BindsInstance
46 | public abstract Builder player(Player player);
47 |
48 | @BindsInstance
49 | public abstract Builder commandArgs(@ArgParserArgs String[] args);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/StatusSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
24 | import net.deltik.mc.signedit.interactions.SignEditInteractionManager;
25 | import org.bukkit.entity.Player;
26 |
27 | import javax.inject.Inject;
28 |
29 | public class StatusSignSubcommand extends SignSubcommand {
30 | private final Player player;
31 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
32 | private final SignEditInteractionManager interactionManager;
33 | private final SignTextClipboardManager clipboardManager;
34 | private final SignTextHistoryManager historyManager;
35 |
36 | @Inject
37 | public StatusSignSubcommand(
38 | Player player,
39 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
40 | SignEditInteractionManager interactionManager,
41 | SignTextClipboardManager clipboardManager,
42 | SignTextHistoryManager historyManager
43 | ) {
44 | super(player);
45 | this.player = player;
46 | this.commsBuilder = commsBuilder;
47 | this.interactionManager = interactionManager;
48 | this.clipboardManager = clipboardManager;
49 | this.historyManager = historyManager;
50 | }
51 |
52 | @Override
53 | public SignEditInteraction execute() {
54 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
55 |
56 | reportHistory(comms);
57 | reportPendingAction(comms);
58 | reportClipboard(comms);
59 |
60 | return null;
61 | }
62 |
63 | private void reportPendingAction(ChatComms comms) {
64 | if (!interactionManager.isInteractionPending(player)) {
65 | comms.tell(comms.t("pending_action_section", comms.t("no_pending_action")));
66 | } else {
67 | SignEditInteraction interaction = interactionManager.getPendingInteraction(player);
68 | comms.tell(comms.t("pending_action_section", comms.t(interaction.getName())));
69 | comms.tell(interaction.getActionHint(comms));
70 | }
71 | }
72 |
73 | private void reportHistory(ChatComms comms) {
74 | SignTextHistory history = historyManager.getHistory(player);
75 | int undosRemaining = 0;
76 | int redosRemaining = 0;
77 |
78 | if (history != null) {
79 | undosRemaining = history.undosRemaining();
80 | redosRemaining = history.redosRemaining();
81 | }
82 |
83 | comms.tell(comms.t("history_section",
84 | comms.t("history_have", undosRemaining, redosRemaining)
85 | ));
86 | }
87 |
88 | private void reportClipboard(ChatComms comms) {
89 | SignText clipboard = clipboardManager.getClipboard(player);
90 | if (clipboard == null) {
91 | comms.tell(comms.t("clipboard_contents_section", comms.t("empty_clipboard")));
92 | } else {
93 | comms.tell(comms.t("clipboard_contents_section", ""));
94 | comms.dumpLines(clipboard.getLines());
95 | }
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/Subcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | public abstract class Subcommand {
23 | }
24 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/SubcommandName.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import javax.inject.Qualifier;
23 | import java.lang.annotation.Documented;
24 | import java.lang.annotation.Retention;
25 | import java.lang.annotation.RetentionPolicy;
26 |
27 | @Qualifier
28 | @Documented
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface SubcommandName {
31 | }
32 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/UiSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.Configuration;
23 | import net.deltik.mc.signedit.CraftBukkitReflector;
24 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
25 | import net.deltik.mc.signedit.interactions.SignEditInteractionModule;
26 | import org.bukkit.entity.Player;
27 |
28 | import javax.inject.Inject;
29 | import javax.inject.Provider;
30 | import java.util.Map;
31 |
32 | public class UiSignSubcommand extends SignSubcommand {
33 | /**
34 | * Bug reported for Minecraft 1.16.1: https://bugs.mojang.com/browse/MC-192263
35 | * Bug resolved in Minecraft 1.16.2: https://minecraft.gamepedia.com/Java_Edition_20w30a
36 | */
37 | private static final String QUIRKY_BUKKIT_SERVER_VERSION = "v1_16_R1";
38 |
39 | private final Configuration config;
40 | private final Map> interactions;
41 | private final CraftBukkitReflector reflector;
42 |
43 | @Inject
44 | public UiSignSubcommand(
45 | Player player,
46 | Configuration config,
47 | Map> interactions,
48 | CraftBukkitReflector reflector
49 | ) {
50 | super(player);
51 | this.config = config;
52 | this.interactions = interactions;
53 | this.reflector = reflector;
54 | }
55 |
56 | @Override
57 | public SignEditInteraction execute() {
58 | return interactions.get(getImplementationName(config, reflector)).get();
59 | }
60 |
61 | public static String getImplementationName(Configuration config, CraftBukkitReflector reflector) {
62 | String value = config.getSignUi().toLowerCase();
63 |
64 | if ("editablebook".equals(value)) {
65 | return SignEditInteractionModule.UI_EDITABLE_BOOK;
66 | } else if ("native".equals(value)) {
67 | return SignEditInteractionModule.UI_NATIVE;
68 | }
69 |
70 | // Auto mode
71 | if (QUIRKY_BUKKIT_SERVER_VERSION.compareTo(reflector.BUKKIT_SERVER_VERSION) == 0) {
72 | return SignEditInteractionModule.UI_EDITABLE_BOOK;
73 | }
74 | return SignEditInteractionModule.UI_NATIVE;
75 | }
76 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/UndoSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.*;
23 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
24 | import org.bukkit.entity.Player;
25 |
26 | import javax.inject.Inject;
27 |
28 | public class UndoSignSubcommand extends SignSubcommand {
29 | private final Player player;
30 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
31 | private final SignTextHistoryManager historyManager;
32 |
33 | @Inject
34 | public UndoSignSubcommand(
35 | Player player,
36 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
37 | SignTextHistoryManager historyManager
38 | ) {
39 | super(player);
40 | this.player = player;
41 | this.commsBuilder = commsBuilder;
42 | this.historyManager = historyManager;
43 | }
44 |
45 | @Override
46 | public SignEditInteraction execute() {
47 | SignTextHistory history = historyManager.getHistory(player);
48 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
49 | SignText undoneSignText = history.undo(comms);
50 | comms.compareSignText(undoneSignText);
51 | return null;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/UnwaxSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.SignText;
23 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
24 | import net.deltik.mc.signedit.shims.SignHelpers;
25 | import org.bukkit.entity.Player;
26 |
27 | import javax.inject.Inject;
28 | import javax.inject.Provider;
29 | import java.util.Map;
30 |
31 | public class UnwaxSignSubcommand extends SignSubcommand {
32 | private final Map> interactions;
33 | private final SignText signText;
34 |
35 | @Inject
36 | public UnwaxSignSubcommand(
37 | Map> interactions,
38 | Player player,
39 | SignText signText
40 | ) {
41 | super(player);
42 | this.interactions = interactions;
43 | this.signText = signText;
44 | }
45 |
46 | @Override
47 | public SignEditInteraction execute() {
48 | signText.setShouldBeEditable(true);
49 | return interactions.get("Wax").get();
50 | }
51 |
52 | @Override
53 | public boolean isPermitted() {
54 | if (!SignHelpers.hasWaxableFeature()) return false;
55 | return super.isPermitted();
56 | }
57 | }
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/VersionSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
25 | import org.bukkit.entity.Player;
26 | import org.bukkit.plugin.Plugin;
27 |
28 | import javax.inject.Inject;
29 |
30 | public class VersionSignSubcommand extends SignSubcommand {
31 | private final Plugin plugin;
32 | private final ChatCommsModule.ChatCommsComponent.Builder commsBuilder;
33 | private final Player player;
34 |
35 | @Inject
36 | public VersionSignSubcommand(
37 | Plugin plugin,
38 | ChatCommsModule.ChatCommsComponent.Builder commsBuilder,
39 | Player player
40 | ) {
41 | super(player);
42 | this.plugin = plugin;
43 | this.commsBuilder = commsBuilder;
44 | this.player = player;
45 | }
46 |
47 | @Override
48 | public SignEditInteraction execute() {
49 | String version = plugin.getDescription().getVersion();
50 | ChatComms comms = commsBuilder.commandSender(player).build().comms();
51 | comms.tell(comms.t("version", version));
52 | return null;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/net/deltik/mc/signedit/subcommands/WaxSignSubcommand.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.SignText;
23 | import net.deltik.mc.signedit.interactions.SignEditInteraction;
24 | import net.deltik.mc.signedit.shims.SignHelpers;
25 | import org.bukkit.entity.Player;
26 |
27 | import javax.inject.Inject;
28 | import javax.inject.Provider;
29 | import java.util.Map;
30 |
31 | public class WaxSignSubcommand extends SignSubcommand {
32 | private final Map> interactions;
33 | private final SignText signText;
34 |
35 | @Inject
36 | public WaxSignSubcommand(
37 | Map> interactions,
38 | Player player,
39 | SignText signText
40 | ) {
41 | super(player);
42 | this.interactions = interactions;
43 | this.signText = signText;
44 | }
45 |
46 | @Override
47 | public SignEditInteraction execute() {
48 | signText.setShouldBeEditable(false);
49 | return interactions.get("Wax").get();
50 | }
51 |
52 | @Override
53 | public boolean isPermitted() {
54 | if (!SignHelpers.hasWaxableFeature()) return false;
55 | return super.isPermitted();
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/resources/Comms.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2017-2025 Deltik
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Theme
23 | reset=§r
24 | primary=§6
25 | primaryDark=§7
26 | primaryLight=§e
27 | secondary=§f
28 | highlightBefore=§4
29 | highlightAfter=§2
30 | strong=§l
31 | italic=§o
32 | strike=§m
33 | error=§c
34 | # Display
35 | ## 0 - {plugin_name}
36 | ## 1 - Any message sent to the player by this plugin
37 | prefix={primaryDark}[{primary}{0}{primaryDark}]{reset} {1}
38 | ## 0 - Highlight formatting
39 | ## 1 - Sign line number
40 | ## 2 - Sign line text
41 | print_line=\\ {0}<{1,number}>{reset} {2}
42 | # General
43 | plugin_name=SignEdit
44 | ## 0 - Command and subcommand as "/command subcommand"
45 | you_cannot_use={error}You are not allowed to use {primaryLight}{0}{error}.
46 | ## 0 - {usage_page_info}
47 | usage_page_heading={secondary}-----{reset} {0}{reset} {secondary}-----
48 | ## 0 - Command
49 | ## 1 - The word "help" as a subcommand
50 | ## 2 - {usage_page_numbering}, only shown if there is more than 1 page
51 | usage_page_info={primary}/{0}{reset} {primaryLight}{1}{reset}{2}
52 | ## 0 - Current page number
53 | ## 1 - Total number of pages
54 | usage_page_numbering=\\ {secondary}{0,number}{reset} {primaryDark}of {1,number}
55 | ## 0 - Command
56 | ## 1 - Subcommand
57 | ## 2 - Subcommand arguments
58 | print_subcommand_usage={primary}/{0} {primaryLight}{1} {primaryDark}{2}
59 | ## 0 - {online_documentation_url}
60 | online_documentation={secondary}{strong}Online Help: {reset}{0}
61 | online_documentation_url=https://git.io/SignEdit-README
62 | sign_did_not_change={primary}Sign did not change
63 | ## 0 - {section_decorator}, only shown if there is something to say about the section
64 | before_section={primary}{strong}Before:{0}
65 | ## 0 - {section_decorator}, only shown if there is something to say about the section
66 | after_section={primary}{strong}After:{0}
67 | ## 0 - A notice about the section
68 | section_decorator={reset} {primaryDark}{italic}({primaryLight}{italic}{0}{primaryDark}{italic})
69 | right_click_sign_to_apply_action={primary}Right-click a sign to apply the action
70 | right_click_sign_to_apply_action_hint=\\ {italic}Right-click a sign to apply the action
71 | right_click_air_to_apply_action_hint=\\ {italic}Right-click air (nothing) to apply the action
72 | right_click_air_to_open_sign_editor={primary}Look away from the sign, then right-click to open the sign editor
73 | sign_editor_item_name=Sign Editor
74 | must_look_at_sign_to_interact={error}You must be looking at a sign to interact with it!
75 | lines_copied_section={primary}{strong}Lines copied:
76 | lines_cut_section={primary}{strong}Lines cut:
77 | cancelled_pending_action={primary}Cancelled pending action
78 | no_pending_action_to_cancel={error}No pending action to cancel!
79 | wax_removed={primary}Wax removed
80 | wax_applied={primary}Wax applied
81 | # StatusSignSubcommand
82 | no_pending_action=None
83 | empty_clipboard={primaryDark}None
84 | ## 0 - One of the "Interactions"
85 | pending_action_section={primary}{strong}Pending Action: {reset}{0}
86 | ## 0 - {history_have}
87 | history_section={primary}{strong}History: {reset}{0}
88 | ## 0 - Count of items in the undo stack
89 | ## 1 - Count of items in the redo stack
90 | history_have={primary}have {primaryLight}{0,number}{primary} undo{0,choice,0#s|1#|1
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Comms.properties provides this language.
--------------------------------------------------------------------------------
/src/resources/Comms_zh.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2017-2025 Deltik
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Theme
23 | reset=§r
24 | primary=§6
25 | primaryDark=§7
26 | primaryLight=§e
27 | secondary=§f
28 | highlightBefore=§4
29 | highlightAfter=§2
30 | strong=§l
31 | italic=§o
32 | strike=§m
33 | error=§c
34 | # Display
35 | ## 0 - {plugin_name}
36 | ## 1 - Any message sent to the player by this plugin
37 | prefix={primaryDark}[{primary}{0}{primaryDark}]{reset} {1}
38 | ## 0 - Highlight formatting
39 | ## 1 - Sign line number
40 | ## 2 - Sign line text
41 | print_line=\\ {0}<{1,number}>{reset} {2}
42 | # General
43 | plugin_name=SignEdit
44 | ## 0 - Command and subcommand as "/command subcommand"
45 | you_cannot_use={error}您没有权限使用 {primaryLight}{0}{error}。
46 | ## 0 - {usage_page_info}
47 | usage_page_heading={secondary}-----{reset} {0}{reset} {secondary}-----
48 | ## 0 - Command
49 | ## 1 - The word "help" as a subcommand
50 | ## 2 - {usage_page_numbering}, only shown if there is more than 1 page
51 | usage_page_info={primary}/{0}{reset} {primaryLight}{1}{reset}{2}
52 | ## 0 - Current page number
53 | ## 1 - Total number of pages
54 | usage_page_numbering=\\ {secondary}{0,number}{reset}{primaryDark}/{1,number}
55 | ## 0 - Command
56 | ## 1 - Subcommand
57 | ## 2 - Subcommand arguments
58 | print_subcommand_usage={primary}/{0} {primaryLight}{1} {primaryDark}{2}
59 | ## 0 - {online_documentation_url}
60 | online_documentation={secondary}{strong}在线帮助: {reset}{0}
61 | online_documentation_url=https://git.io/SignEdit-README
62 | sign_did_not_change={primary}告示牌没有变更。
63 | ## 0 - {section_decorator}, only shown if there is something to say about the section
64 | before_section={primary}{strong}变更前:{0}
65 | ## 0 - {section_decorator}, only shown if there is something to say about the section
66 | after_section={primary}{strong}变更后:{0}
67 | ## 0 - A notice about the section
68 | section_decorator={reset}{primaryDark}{italic}({primaryLight}{italic}{0}{primaryDark}{italic})
69 | right_click_sign_to_apply_action={primary}右键点击要编辑的告示牌
70 | right_click_sign_to_apply_action_hint=\\ {italic}右键点击要编辑的告示牌
71 | right_click_air_to_apply_action_hint=\\ {italic}对空气点击右键以执行动作
72 | right_click_air_to_open_sign_editor={primary}请将视线移离告示牌,然后点击右键,开启告示牌编辑器
73 | sign_editor_item_name=告示牌编辑器
74 | must_look_at_sign_to_interact={error}您必须看着一个告示牌才能编辑它!
75 | lines_copied_section={primary}{strong}已复制的行:
76 | lines_cut_section={primary}{strong}已剪下的行:
77 | cancelled_pending_action={primary}等待中的编辑动作已取消。
78 | no_pending_action_to_cancel={error}没有可以取消的编辑动作!
79 | wax_removed={primary}已给告示牌脱蜡
80 | wax_applied={primary}已给告示牌涂蜡
81 | # StatusSignSubcommand
82 | no_pending_action=无
83 | empty_clipboard={primaryDark}空白
84 | ## 0 - One of the "Interactions"
85 | pending_action_section={primary}{strong}等待中的动作:{reset}{0}
86 | ## 0 - {history_have}
87 | history_section={primary}{strong}编辑历史: {reset}{0}
88 | ## 0 - Count of items in the undo stack
89 | ## 1 - Count of items in the redo stack
90 | history_have={primary}有 {primaryLight}{0,number}{primary} 个撤销和 {primaryLight}{1,number}{primary} 个重做
91 | ## 0 - {empty_clipboard}, shown only if the clipboard is empty
92 | clipboard_contents_section={primary}{strong}剪贴板內容:{reset}{0}
93 | # Interactions
94 | copy_sign_text=复制告示牌的文字
95 | cut_sign_text=剪切告示牌的文字
96 | paste_lines_from_clipboard=粘贴剪贴板里的文字
97 | change_sign_text=更改告示牌的文字
98 | open_sign_editor=开启告示牌编辑器
99 | unwax_sign=刮除告示牌的蜜脾
100 | wax_sign=将蜜脾涂到告示牌上
101 | # VersionSignSubcommand
102 | ## 0 - Version of the plugin
103 | version={primary}版本 {secondary}{0}
104 | # Errors
105 | forbidden_sign_edit={error}有其他插件或策略阻止了告示牌的编辑
106 | forbidden_waxed_sign_edit={error}您不能编辑已涂蜡的告示牌。
107 | bypass_wax_cannot_rewax={error}无法重新涂蜡:您没有重新给告示牌涂蜡的权限!
108 | missing_line_selection_exception={error}必须至少选择一个行。
109 | ## 0 - Invalid input that the player tried to pass as a line selection
110 | number_parse_line_selection_exception={error}"{0}" 不是一个正确的行号。
111 | ## 0 - The index of the first line of a sign
112 | ## 1 - The index of the last line of a sign
113 | ## 2 - The invalid line index that the player inputted
114 | out_of_bounds_line_selection_exception={error}行号必须在 {0,number} 到 {1,number} 之间,却提供了 {2,number}。
115 | ## 0 - The invalid lower bound that the player inputted for a line range selection
116 | ## 1 - The invalid upper bound that the player inputted for a line range selection
117 | ## 2 - The invalid line range selection that the player inputted
118 | range_order_line_selection_exception={error}在选择 {2} 中,下限 {0,number} 不能高于上限 {1,number}。
119 | ## 0 - The invalid line range selection that the player inputted
120 | ## 1 - The full invalid line selection that the player inputted
121 | range_parse_line_selection_exception={error}在选择 {1} 中,"{0}" 并非有效的范围。
122 | nothing_to_undo={error}没有可以撤销的动作
123 | nothing_to_redo={error}没有可以重做的动作
124 | block_state_not_placed_exception={error}命令执行失败:告示牌已不再存在!
125 | null_clipboard_exception={error}剪贴板是空的!
126 | ## 0 - The string representation of a Java Exception
127 | uncaught_error={error}未知的错误:{0}
128 | cannot_open_sign_editor={error}{strong}无法开启告示牌编辑器!
129 | ## 0 - The guessed cause of a sign edit failure, probably {minecraft_server_api_changed}
130 | likely_cause={primaryDark}可能的原因:{reset}{0}
131 | minecraft_server_api_changed=Minecraft 服务器 API 改变了
132 | ## 0 - A message for the player to forward to the server admin
133 | to_server_admin={primaryDark}服务器管理员:{reset}{0}
134 | check_for_updates_to_this_plugin=检查这个插件的更新
135 | ## 0 - The string representation of a Java Exception
136 | error_code={primaryDark}错误代码:{reset}{0}
137 | hint_more_details_with_server_admin={error}(服务器的控制台有更多信息)
138 | # Warnings
139 | modified_by_another_plugin=已被其他插件编辑
140 |
--------------------------------------------------------------------------------
/src/resources/Comms_zh_CN.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2017-2025 Deltik
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Comms_zh.properties provides this language.
23 |
--------------------------------------------------------------------------------
/src/resources/Comms_zh_HK.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2017-2025 Deltik
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Theme
23 | reset=§r
24 | primary=§6
25 | primaryDark=§7
26 | primaryLight=§e
27 | secondary=§f
28 | highlightBefore=§4
29 | highlightAfter=§2
30 | strong=§l
31 | italic=§o
32 | strike=§m
33 | error=§c
34 | # Display
35 | ## 0 - {plugin_name}
36 | ## 1 - Any message sent to the player by this plugin
37 | prefix={primaryDark}[{primary}{0}{primaryDark}]{reset} {1}
38 | ## 0 - Highlight formatting
39 | ## 1 - Sign line number
40 | ## 2 - Sign line text
41 | print_line=\\ {0}<{1,number}>{reset} {2}
42 | # General
43 | plugin_name=SignEdit
44 | ## 0 - Command and subcommand as "/command subcommand"
45 | you_cannot_use={error}你冇權限使用 {primaryLight}{0}{error}。
46 | ## 0 - {usage_page_info}
47 | usage_page_heading={secondary}-----{reset} {0}{reset} {secondary}-----
48 | ## 0 - Command
49 | ## 1 - The word "help" as a subcommand
50 | ## 2 - {usage_page_numbering}, only shown if there is more than 1 page
51 | usage_page_info={primary}/{0}{reset} {primaryLight}{1}{reset}{2}
52 | ## 0 - Current page number
53 | ## 1 - Total number of pages
54 | usage_page_numbering=\\ {secondary}{0,number}{reset}{primaryDark}/{1,number}
55 | ## 0 - Command
56 | ## 1 - Subcommand
57 | ## 2 - Subcommand arguments
58 | print_subcommand_usage={primary}/{0} {primaryLight}{1} {primaryDark}{2}
59 | ## 0 - {online_documentation_url}
60 | online_documentation={secondary}{strong}線上説明:{reset}{0}
61 | online_documentation_url=https://git.io/SignEdit-README
62 | sign_did_not_change={primary}指示牌未有變更。
63 | ## 0 - {section_decorator}, only shown if there is something to say about the section
64 | before_section={primary}{strong}變更前:{0}
65 | ## 0 - {section_decorator}, only shown if there is something to say about the section
66 | after_section={primary}{strong}變更後:{0}
67 | ## 0 - A notice about the section
68 | section_decorator={reset}{primaryDark}{italic}({primaryLight}{italic}{0}{primaryDark}{italic})
69 | right_click_sign_to_apply_action={primary}右鍵點擊要編輯嘅指示牌
70 | right_click_sign_to_apply_action_hint=\\ {italic}右鍵點擊要編輯嘅指示牌
71 | right_click_air_to_apply_action_hint=\\ {italic}對空氣點擊右鍵以執行操作
72 | right_click_air_to_open_sign_editor={primary}請將視線移離指示牌,然後點擊右鍵,打開指示牌編輯器
73 | sign_editor_item_name=指示牌編輯器
74 | must_look_at_sign_to_interact={error}你必須睇住一個指示牌先可以編輯!
75 | lines_copied_section={primary}{strong}已複製嘅行:
76 | lines_cut_section={primary}{strong}已剪下嘅行:
77 | cancelled_pending_action={primary}等待中嘅編輯動作已取消。
78 | no_pending_action_to_cancel={error}未有可以取消嘅編輯操作!
79 | wax_removed={primary}幫指示牌除咗蠟
80 | wax_applied={primary}幫指示牌打咗蠟
81 | # StatusSignSubcommand
82 | no_pending_action=無
83 | empty_clipboard={primaryDark}空白
84 | ## 0 - One of the "Interactions"
85 | pending_action_section={primary}{strong}等待中嘅操作:{reset}{0}
86 | ## 0 - {history_have}
87 | history_section={primary}{strong}編輯歷史:{reset}{0}
88 | ## 0 - Count of items in the undo stack
89 | ## 1 - Count of items in the redo stack
90 | history_have={primary}有 {primaryLight}{0,number}{primary} 個撤銷同 {primaryLight}{1,number}{primary} 個重做
91 | ## 0 - {empty_clipboard}, shown only if the clipboard is empty
92 | clipboard_contents_section={primary}{strong}剪貼簿內容:{reset}{0}
93 | # Interactions
94 | copy_sign_text=複製指示牌嘅文字
95 | cut_sign_text=剪下指示牌嘅文字
96 | paste_lines_from_clipboard=貼上剪貼簿入邊嘅文字
97 | change_sign_text=更改指示牌嘅文字
98 | open_sign_editor=開啟指示牌編輯器
99 | unwax_sign=刮除指示牌上嘅蜂蠟
100 | wax_sign=喺指示牌塗上蜂蠟
101 | # VersionSignSubcommand
102 | ## 0 - Version of the plugin
103 | version={primary}版本 {secondary}{0}
104 | # Errors
105 | forbidden_sign_edit={error}有其他插件或策略阻止咗指示牌嘅編輯
106 | forbidden_waxed_sign_edit={error}你唔可以編輯打咗蠟嘅指示牌。
107 | bypass_wax_cannot_rewax={error}無法重新打蠟:你冇權幫指示牌重新打蠟!
108 | missing_line_selection_exception={error}必須至少選擇一個行。
109 | ## 0 - Invalid input that the player tried to pass as a line selection
110 | number_parse_line_selection_exception={error}"{0}" 唔係一個正確嘅行號。
111 | ## 0 - The index of the first line of a sign
112 | ## 1 - The index of the last line of a sign
113 | ## 2 - The invalid line index that the player inputted
114 | out_of_bounds_line_selection_exception={error}行號必須喺 {0,number} 至 {1,number} 之間,但提供咗 {2,number}。
115 | ## 0 - The invalid lower bound that the player inputted for a line range selection
116 | ## 1 - The invalid upper bound that the player inputted for a line range selection
117 | ## 2 - The invalid line range selection that the player inputted
118 | range_order_line_selection_exception={error}喺選擇 {2} 中,下限 {0,number} 唔可以高過上限 {1,number}。
119 | ## 0 - The invalid line range selection that the player inputted
120 | ## 1 - The full invalid line selection that the player inputted
121 | range_parse_line_selection_exception={error}喺選擇 {1} 中,"{0}" 並非有效嘅範圍。
122 | nothing_to_undo={error}未有可以撤銷嘅操作
123 | nothing_to_redo={error}未有可以重做嘅操作
124 | block_state_not_placed_exception={error}指令執行失敗:指示牌已不再存在!
125 | null_clipboard_exception={error}剪貼簿係空白嘅!
126 | ## 0 - The string representation of a Java Exception
127 | uncaught_error={error}不明嘅錯誤:{0}
128 | cannot_open_sign_editor={error}{strong}無法打開指示牌編輯器!
129 | ## 0 - The guessed cause of a sign edit failure, probably {minecraft_server_api_changed}
130 | likely_cause={primaryDark}可能嘅原因: {reset}{0}
131 | minecraft_server_api_changed=Minecraft 伺服器 API 改變咗
132 | ## 0 - A message for the player to forward to the server admin
133 | to_server_admin={primaryDark}伺服器管理員:{reset}{0}
134 | check_for_updates_to_this_plugin=檢查依個插件嘅更新
135 | ## 0 - The string representation of a Java Exception
136 | error_code={primaryDark}錯誤代碼:{reset}{0}
137 | hint_more_details_with_server_admin={error}(伺服器嘅控制台有更多訊息)
138 | # Warnings
139 | modified_by_another_plugin=已被其他插件編輯
140 |
--------------------------------------------------------------------------------
/src/resources/Comms_zh_TW.properties:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright (C) 2017-2025 Deltik
3 | #
4 | # This file is part of SignEdit for Bukkit.
5 | #
6 | # SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | # it under the terms of the GNU General Public License as published by
8 | # the Free Software Foundation, either version 3 of the License, or
9 | # (at your option) any later version.
10 | #
11 | # SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | # GNU General Public License for more details.
15 | #
16 | # You should have received a copy of the GNU General Public License
17 | # along with SignEdit for Bukkit. If not, see .
18 | #
19 |
20 | # ${pluginName} ${pluginVersion} locale file
21 |
22 | # Theme
23 | reset=§r
24 | primary=§6
25 | primaryDark=§7
26 | primaryLight=§e
27 | secondary=§f
28 | highlightBefore=§4
29 | highlightAfter=§2
30 | strong=§l
31 | italic=§o
32 | strike=§m
33 | error=§c
34 | # Display
35 | ## 0 - {plugin_name}
36 | ## 1 - Any message sent to the player by this plugin
37 | prefix={primaryDark}[{primary}{0}{primaryDark}]{reset} {1}
38 | ## 0 - Highlight formatting
39 | ## 1 - Sign line number
40 | ## 2 - Sign line text
41 | print_line=\\ {0}<{1,number}>{reset} {2}
42 | # General
43 | plugin_name=SignEdit
44 | ## 0 - Command and subcommand as "/command subcommand"
45 | you_cannot_use={error}您沒有權限使用 {primaryLight}{0}{error}。
46 | ## 0 - {usage_page_info}
47 | usage_page_heading={secondary}-----{reset} {0}{reset} {secondary}-----
48 | ## 0 - Command
49 | ## 1 - The word "help" as a subcommand
50 | ## 2 - {usage_page_numbering}, only shown if there is more than 1 page
51 | usage_page_info={primary}/{0}{reset} {primaryLight}{1}{reset}{2}
52 | ## 0 - Current page number
53 | ## 1 - Total number of pages
54 | usage_page_numbering=\\ {secondary}{0,number}{reset}{primaryDark}/{1,number}
55 | ## 0 - Command
56 | ## 1 - Subcommand
57 | ## 2 - Subcommand arguments
58 | print_subcommand_usage={primary}/{0} {primaryLight}{1} {primaryDark}{2}
59 | ## 0 - {online_documentation_url}
60 | online_documentation={secondary}{strong}線上說明:{reset}{0}
61 | online_documentation_url=https://git.io/SignEdit-README
62 | sign_did_not_change={primary}告示牌沒有變更。
63 | ## 0 - {section_decorator}, only shown if there is something to say about the section
64 | before_section={primary}{strong}變更前: {0}
65 | ## 0 - {section_decorator}, only shown if there is something to say about the section
66 | after_section={primary}{strong}變更後: {0}
67 | ## 0 - A notice about the section
68 | section_decorator={reset}{primaryDark}{italic}({primaryLight}{italic}{0}{primaryDark}{italic})
69 | right_click_sign_to_apply_action={primary}右鍵點擊要編輯的告示牌
70 | right_click_sign_to_apply_action_hint=\\ {italic}右鍵點擊要編輯的告示牌
71 | right_click_air_to_apply_action_hint=\\ {italic}對空氣點擊右鍵以執行操作
72 | right_click_air_to_open_sign_editor={primary}請將視線移離告示牌,然後點擊右鍵,開啟告示牌編輯器
73 | sign_editor_item_name=告示牌編輯器
74 | must_look_at_sign_to_interact={error}您必須看著一個告示牌才能編輯它!
75 | lines_copied_section={primary}{strong}已複製的行:
76 | lines_cut_section={primary}{strong}已剪下的行:
77 | cancelled_pending_action={primary}等待中的編輯操作已取消。
78 | no_pending_action_to_cancel={error}沒有可以取消的編輯操作!
79 | wax_removed={primary}已給告示牌除蠟
80 | wax_applied={primary}已給告示牌上蠟
81 | # StatusSignSubcommand
82 | no_pending_action=無
83 | empty_clipboard={primaryDark}空白
84 | ## 0 - One of the "Interactions"
85 | pending_action_section={primary}{strong}等待中的操作:{reset}{0}
86 | ## 0 - {history_have}
87 | history_section={primary}{strong}編輯歷史:{reset}{0}
88 | ## 0 - Count of items in the undo stack
89 | ## 1 - Count of items in the redo stack
90 | history_have={primary}有 {primaryLight}{0,number}{primary} 個撤銷和 {primaryLight}{1,number}{primary} 個重做
91 | ## 0 - {empty_clipboard}, shown only if the clipboard is empty
92 | clipboard_contents_section={primary}{strong}剪貼簿內容:{reset}{0}
93 | # Interactions
94 | copy_sign_text=複製告示牌的文字
95 | cut_sign_text=剪下告示牌的文字
96 | paste_lines_from_clipboard=貼上剪貼簿裡的文字
97 | change_sign_text=更改告示牌的文字
98 | open_sign_editor=開啟告示牌編輯器
99 | unwax_sign=刮除告示牌上的蜂蠟
100 | wax_sign=為告示牌塗上蜂蠟
101 | # VersionSignSubcommand
102 | ## 0 - Version of the plugin
103 | version={primary}版本 {secondary}{0}
104 | # Errors
105 | forbidden_sign_edit={error}有其他插件或策略阻止了告示牌的編輯
106 | forbidden_waxed_sign_edit={error}您不能編輯已上蠟的告示牌。
107 | bypass_wax_cannot_rewax={error}無法重新上蠟:您沒有給告示牌重新上蠟的權限!
108 | missing_line_selection_exception={error}必須至少選擇一個行。
109 | ## 0 - Invalid input that the player tried to pass as a line selection
110 | number_parse_line_selection_exception={error}"{0}" 不是一個正確的行號。
111 | ## 0 - The index of the first line of a sign
112 | ## 1 - The index of the last line of a sign
113 | ## 2 - The invalid line index that the player inputted
114 | out_of_bounds_line_selection_exception={error}行號必須在 {0,number} 至 {1,number} 之間,卻提供了 {2,number}。
115 | ## 0 - The invalid lower bound that the player inputted for a line range selection
116 | ## 1 - The invalid upper bound that the player inputted for a line range selection
117 | ## 2 - The invalid line range selection that the player inputted
118 | range_order_line_selection_exception={error}在選擇 {2} 中,下限 {0,number} 不能高於上限 {1,number}。
119 | ## 0 - The invalid line range selection that the player inputted
120 | ## 1 - The full invalid line selection that the player inputted
121 | range_parse_line_selection_exception={error}在選擇 {1} 中,"{0}" 並非有效的範圍。
122 | nothing_to_undo={error}沒有可以撤銷的操作
123 | nothing_to_redo={error}沒有可以重做的操作
124 | block_state_not_placed_exception={error}指令執行失敗: 告示牌已不再存在!
125 | null_clipboard_exception={error}剪貼簿是空的!
126 | ## 0 - The string representation of a Java Exception
127 | uncaught_error={error}不明的錯誤:{0}
128 | cannot_open_sign_editor={error}{strong}無法開啟告示牌編輯器!
129 | ## 0 - The guessed cause of a sign edit failure, probably {minecraft_server_api_changed}
130 | likely_cause={primaryDark}可能的原因:{reset}{0}
131 | minecraft_server_api_changed=Minecraft 伺服器 API 改變了
132 | ## 0 - A message for the player to forward to the server admin
133 | to_server_admin={primaryDark}伺服器管理員:{reset}{0}
134 | check_for_updates_to_this_plugin=檢查這個插件的更新
135 | ## 0 - The string representation of a Java Exception
136 | error_code={primaryDark}錯誤代碼:{reset}{0}
137 | hint_more_details_with_server_admin={error}(伺服器的控制台有更多訊息)
138 | # Warnings
139 | modified_by_another_plugin=已被其他插件編輯
140 |
--------------------------------------------------------------------------------
/src/resources/README.Comms.txt:
--------------------------------------------------------------------------------
1 | This plugin's text (colors and languages) displayed to players can be
2 | customized.
3 |
4 | To customize the text, create your own locale files in the ./overrides/ folder.
5 |
6 | Note that as the locale files are standard Java ResourceBundles, any script,
7 | region, and variants in the language tag should be delimited by underscores
8 | ("_") instead of the standard hyphen delimiter ("-"). For example, "zh-TW"
9 | should be in a file called "Comms_zh_TW.properties".
10 |
11 | The ./originals/ folder contains a read-only copy of the locale files used by
12 | this plugin. You should copy the locale files you want to customize from
13 | ./originals/ into ./overrides/ to get a full working copy of the text. Then,
14 | you can edit your copy or copies in ./overrides/ to set your own colors and
15 | translations.
16 |
17 | This file and everything in ./originals/ is managed by ${pluginName}. Any
18 | changes will be overwritten when the plugin is reloaded, so only make your
19 | changes in the ./overrides/ folder.
20 |
--------------------------------------------------------------------------------
/src/resources/config.yml.j2:
--------------------------------------------------------------------------------
1 | # ${pluginName} ${pluginVersion} configuration file
2 | #
3 | # This file is managed by ${pluginName}. The configuration option values can be changed by hand, but any comment or
4 | # spacing changes will be overwritten automatically by ${pluginName}.
5 | #
6 | # Manual changes are applied the next time ${pluginName} is loaded.
7 | ---
8 | # Sign line starts at
9 | # Possible values:
10 | # 1 - (Default) Line number 1 corresponds to the top-most line of sign blocks.
11 | # 0 - Line number 0 corresponds to the top-most line of sign blocks.
12 | line-starts-at: {{ line_starts_at }}
13 |
14 | # Sets whether a right-mouse click is required to edit a sign
15 | # Possible values:
16 | # "auto" - (Default) Behave like "false" when the player is looking at a sign.
17 | # Behave like "true" when the player is not looking at a sign.
18 | # "false" - Edit signs by looking at them and then typing a /sign command, which instantly edits the targeted sign.
19 | # "true" - Edit signs by typing a /sign command and then right-mouse clicking a sign.
20 | clicking: "{{ clicking }}"
21 |
22 | # Language presented to the player if the player's language is not supported
23 | # Can be any IETF BCP 47 language tag. Details: https://tools.ietf.org/html/bcp47
24 | # Supported values: See https://git.io/SignEdit-README#supported-locales
25 | locale: "{{ locale }}"
26 | # Overrides the player's language choice
27 | # Possible values:
28 | # false - (Default) Uses the player's language if supported; otherwise uses the language specified in the "locale" key
29 | # true - Forces all players to see the language specified in the "locale" key
30 | force-locale: {{ force_locale }}
31 |
32 | # Workarounds for bugs in Minecraft or other Bukkit plugins
33 | compatibility:
34 | # Choose whether to use the alternative sign editor graphical user interface
35 | # Possible values:
36 | # "Auto" - (Default) Only show the alternative sign editor on Minecraft 1.16.1
37 | # "EditableBook" - Always show the alternative sign editor regardless of Minecraft version
38 | # "Native" - Always show the native sign editor regardless of Minecraft version
39 | sign-ui: "{{ compatibility__sign_ui }}"
40 |
41 | # Events to send to permission validation plugins when a player edits a sign
42 | # Possible values:
43 | # "Standard" - (Default) Only send SignChangeEvent to other plugins for validation
44 | # "Extra" - Send BlockBreakEvent, BlockPlaceEvent, and SignChangeEvent to other plugins for validation
45 | # "None" - (Not recommended) Disable permission validation by not sending any Events
46 | edit-validation: "{{ compatibility__edit_validation }}"
--------------------------------------------------------------------------------
/src/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | main: ${mainClass.get()}
2 | name: ${pluginName}
3 | author: Deltik
4 | website: https://github.com/Deltik/SignEdit
5 | version: "${pluginVersion}"
6 | api-version: "1.13"
7 | description: Edit existing signs
8 | commands:
9 | sign:
10 | aliases: [signedit, editsign, se]
11 | description: Edit a targeted sign
12 | usage: |
13 | See the online documentation for additional help:
14 | https://git.io/SignEdit-README
15 |
16 | / help []
17 | Show usage syntax for every available / subcommand.
18 | Specify a number to view a specific page.
19 |
20 | / ui
21 | Open the native Minecraft sign editor on the targeted sign.
22 |
23 | / [set] []
24 | Change each of the lines of the targeted sign to .
25 | Formatting codes are parsed with `&` in place of `§`.
26 | If is blank, erase the lines .
27 | "set" can be omitted.
28 |
29 | / clear []
30 | Erase the text on the targeted sign.
31 | If is specified, only those lines are blanked out.
32 |
33 | / cancel
34 | Abort your pending sign edit action.
35 |
36 | / status
37 | Show the pending action, what is in the copy buffer, and an overview of the undo/redo history stack.
38 |
39 | / copy []
40 | Copy the targeted sign's text.
41 | If is specified, only those lines are copied.
42 |
43 | / cut []
44 | Copy the targeted sign's text and remove it from the sign.
45 | If is specified, only those lines are cut.
46 |
47 | / paste
48 | Paste the lines buffered by the previous /sign copy or /sign cut command onto the targeted sign.
49 |
50 | / undo
51 | Revert the previous sign text change. Does not affect non-text changes like waxing and dyeing.
52 |
53 | / redo
54 | Restore the most recent sign text change that was undone by /sign undo.
55 |
56 | / unwax
57 | Remove wax from the targeted sign,
58 | allowing the sign to be edited by the Minecraft 1.20+ right-click action.
59 |
60 | / wax
61 | Apply wax to the targeted sign,
62 | preventing the sign from being edited by right-clicking the sign in Minecraft 1.20+.
63 |
64 | / version
65 | Show the version of this plugin.
66 |
67 | permissions:
68 | signedit.use:
69 | description: Legacy permission granting access to all /sign subcommands
70 | signedit.sign.*:
71 | description: Allow access to all /sign subcommands
72 | children:
73 | signedit.sign.help: true
74 | signedit.sign.ui: true
75 | signedit.sign.set: true
76 | signedit.sign.clear: true
77 | signedit.sign.cancel: true
78 | signedit.sign.status: true
79 | signedit.sign.copy: true
80 | signedit.sign.cut: true
81 | signedit.sign.paste: true
82 | signedit.sign.undo: true
83 | signedit.sign.redo: true
84 | signedit.sign.unwax: true
85 | signedit.sign.wax: true
86 | signedit.sign.version: true
87 | signedit.sign.help:
88 | description: Allow /sign help
89 | signedit.sign.ui:
90 | description: Allow /sign ui
91 | signedit.sign.set:
92 | description: Allow /sign set
93 | signedit.sign.clear:
94 | description: Allow /sign clear
95 | signedit.sign.cancel:
96 | description: Allow /sign cancel
97 | signedit.sign.status:
98 | description: Allow /sign status
99 | signedit.sign.copy:
100 | description: Allow /sign copy
101 | signedit.sign.cut:
102 | description: Allow /sign cut
103 | signedit.sign.paste:
104 | description: Allow /sign paste
105 | signedit.sign.undo:
106 | description: Allow /sign undo
107 | signedit.sign.redo:
108 | description: Allow /sign redo
109 | signedit.sign.unwax:
110 | description: Allow /sign unwax; access to this command implicitly removes wax when editing with another command
111 | signedit.sign.wax:
112 | description: Allow /sign wax; access to this command implicitly reapplies wax if the sign was de-waxed for editing
113 | signedit.sign.version:
114 | description: Allow /sign version
--------------------------------------------------------------------------------
/test/net/deltik/mc/signedit/ChatCommsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.junit.jupiter.api.Test;
23 |
24 | import java.util.Locale;
25 | import java.util.ResourceBundle;
26 |
27 | import static org.junit.jupiter.api.Assertions.assertEquals;
28 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
29 |
30 | public class ChatCommsTest {
31 | @Test
32 | public void resourceBundleControlFallbackLocale() {
33 | Locale fallbackLocale = new Locale.Builder().setLanguageTag("el-GR").build();
34 | Locale badLocale = new Locale.Builder().setLanguageTag("hu-HU").build();
35 | ResourceBundle.Control control = new ChatComms.UTF8ResourceBundleControl(fallbackLocale);
36 |
37 | assertEquals(
38 | fallbackLocale,
39 | control.getFallbackLocale("Comms", badLocale)
40 | );
41 | }
42 |
43 | @Test
44 | public void resourceBundleControlFallbackLocaleNoInfiniteLoop() {
45 | Locale fallbackLocale = new Locale.Builder().setLanguageTag("en-US").build();
46 | Locale badLocale = new Locale.Builder().setLanguageTag("en-US").build();
47 | ResourceBundle.Control control = new ChatComms.UTF8ResourceBundleControl(fallbackLocale);
48 |
49 | assertNotEquals(
50 | fallbackLocale,
51 | control.getFallbackLocale("Comms", badLocale)
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/test/net/deltik/mc/signedit/UserCommsTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit;
21 |
22 | import org.junit.jupiter.api.Test;
23 | import org.junit.jupiter.api.io.TempDir;
24 |
25 | import java.io.File;
26 | import java.io.IOException;
27 | import java.nio.file.Path;
28 | import java.nio.file.Paths;
29 | import java.util.Collection;
30 | import java.util.Scanner;
31 | import java.util.regex.Pattern;
32 |
33 | import static org.junit.jupiter.api.Assertions.*;
34 |
35 | public class UserCommsTest {
36 | @TempDir
37 | Path pluginConfigFolder;
38 |
39 | @Test
40 | public void deployDirectoryStructure() throws IOException {
41 | UserComms userComms = new UserComms(pluginConfigFolder.toAbsolutePath().toString());
42 |
43 | userComms.deploy();
44 |
45 | assertTrue(Paths.get(
46 | pluginConfigFolder.toAbsolutePath().toString(), "locales", "originals"
47 | ).toFile().isDirectory());
48 | assertTrue(Paths.get(
49 | pluginConfigFolder.toAbsolutePath().toString(), "locales", "overrides"
50 | ).toFile().isDirectory());
51 | assertTrue(Paths.get(
52 | pluginConfigFolder.toAbsolutePath().toString(), "locales", "README.txt"
53 | ).toFile().length() > 0);
54 | }
55 |
56 | @Test
57 | public void deployCopiesOriginals() throws IOException {
58 | UserComms userComms = new UserComms(pluginConfigFolder.toAbsolutePath().toString());
59 |
60 | userComms.deploy();
61 |
62 | Pattern pattern;
63 | pattern = Pattern.compile(".*/Comms[_.].*");
64 | final Collection list = ResourceList.getResources(pattern);
65 | for (final String name : list) {
66 | String fileName = Paths.get(name).getFileName().toString();
67 | File file = Paths.get(
68 | pluginConfigFolder.toAbsolutePath().toString(), "locales", "originals", fileName
69 | ).toFile();
70 | assertTrue(file.isFile());
71 |
72 | Scanner scanner = new Scanner(file);
73 | Pattern contentCheckRegex = Pattern.compile("^# .* locale file$");
74 | boolean contentCheckPassed = false;
75 | while (scanner.hasNextLine()) {
76 | String line = scanner.nextLine();
77 | if (contentCheckRegex.matcher(line).matches()) {
78 | contentCheckPassed = true;
79 | break;
80 | }
81 | }
82 | if (!contentCheckPassed) {
83 | fail(file.getAbsolutePath() + " does not contain regex match: " + contentCheckRegex);
84 | }
85 | }
86 | }
87 |
88 | @SuppressWarnings("ResultOfMethodCallIgnored")
89 | @Test
90 | public void deployRemovesUnexpectedFilesFromOriginalsCopy() throws IOException {
91 | UserComms userComms = new UserComms(pluginConfigFolder.toAbsolutePath().toString());
92 | File originalsDir = Paths.get(
93 | pluginConfigFolder.toAbsolutePath().toString(), "locales", "originals"
94 | ).toFile();
95 | originalsDir.mkdirs();
96 | File garbageDir = Paths.get(originalsDir.getAbsolutePath(), "FOLDER-NONSENSE", "NEST-ME").toFile();
97 | garbageDir.mkdirs();
98 | File garbageFile = Paths.get(garbageDir.getAbsolutePath(), "REMOVE-ME").toFile();
99 | garbageFile.createNewFile();
100 | File garbageFile2 = Paths.get(originalsDir.getAbsolutePath(), "REMOVE-ME").toFile();
101 | garbageFile2.createNewFile();
102 |
103 | assertTrue(garbageFile.exists());
104 | assertTrue(garbageFile2.exists());
105 |
106 | userComms.deploy();
107 |
108 | assertFalse(garbageFile.exists());
109 | assertFalse(garbageFile2.exists());
110 | }
111 | }
112 |
--------------------------------------------------------------------------------
/test/net/deltik/mc/signedit/subcommands/VersionSignSubcommandTest.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (C) 2017-2025 Deltik
3 | *
4 | * This file is part of SignEdit for Bukkit.
5 | *
6 | * SignEdit for Bukkit is free software: you can redistribute it and/or modify
7 | * it under the terms of the GNU General Public License as published by
8 | * the Free Software Foundation, either version 3 of the License, or
9 | * (at your option) any later version.
10 | *
11 | * SignEdit for Bukkit is distributed in the hope that it will be useful,
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | * GNU General Public License for more details.
15 | *
16 | * You should have received a copy of the GNU General Public License
17 | * along with SignEdit for Bukkit. If not, see .
18 | */
19 |
20 | package net.deltik.mc.signedit.subcommands;
21 |
22 | import net.deltik.mc.signedit.ChatComms;
23 | import net.deltik.mc.signedit.ChatCommsModule;
24 | import net.deltik.mc.signedit.Configuration;
25 | import net.deltik.mc.signedit.SignEditPlugin;
26 | import net.deltik.mc.signedit.interactions.InteractionCommand;
27 | import org.bukkit.command.CommandSender;
28 | import org.bukkit.entity.Player;
29 | import org.bukkit.plugin.Plugin;
30 | import org.bukkit.plugin.PluginDescriptionFile;
31 | import org.junit.jupiter.api.Test;
32 |
33 | import java.util.Locale;
34 |
35 | import static org.mockito.ArgumentMatchers.contains;
36 | import static org.mockito.Mockito.*;
37 |
38 | public class VersionSignSubcommandTest {
39 | @Test
40 | public void signVersionShowsVersion() {
41 | String expected = "1.3.1";
42 |
43 | Player player = mock(Player.class);
44 | Configuration config = mock(Configuration.class);
45 | when(config.getLocale()).thenReturn(new Locale("en"));
46 | PluginDescriptionFile pluginDescriptionFile = mock(PluginDescriptionFile.class);
47 | Plugin plugin = mock(SignEditPlugin.class);
48 | when(plugin.getDescription()).thenReturn(pluginDescriptionFile);
49 | when(pluginDescriptionFile.getVersion()).thenReturn(expected);
50 | InteractionCommand subcommand = new VersionSignSubcommand(
51 | plugin,
52 | new ChatCommsModule.ChatCommsComponent.Builder() {
53 | ChatComms comms;
54 |
55 | @Override
56 | public ChatCommsModule.ChatCommsComponent build() {
57 | return () -> comms;
58 | }
59 |
60 | @Override
61 | public ChatCommsModule.ChatCommsComponent.Builder commandSender(CommandSender commandSender) {
62 | this.comms = new ChatComms(player, config);
63 | return this;
64 | }
65 | },
66 | player
67 | );
68 | subcommand.execute();
69 |
70 | verify(player).sendMessage(contains(expected));
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/test/resources/mockito-extensions/org.mockito.plugins.MockMaker:
--------------------------------------------------------------------------------
1 | mock-maker-inline
2 |
--------------------------------------------------------------------------------