findProtection(Block block, SearchMode searchMode);
50 |
51 | /**
52 | * Gets whether this block can be protected by a sign. This can either be
53 | * because it is itself a block that can be locked (like a chest) or because it
54 | * supports a block that is protectable (like the block below a door). Note that
55 | * this method returns false for signs, since you cannot protect a sign with
56 | * another sign. See {@link #isSignNearbyProtectable(Block)} for that case.
57 | *
58 | * @param block
59 | * The block to check.
60 | * @return True if the block is protectable, false otherwise.
61 | */
62 | boolean isProtectable(Block block);
63 |
64 | /**
65 | * Gets whether the given sign is near a block that can be protected. In
66 | * other words, this method returns true if the sign is attached to a chest,
67 | * furnace etc. or placed above a door.
68 | *
69 | *
70 | * This method doesn't care whether the block that can be protected is
71 | * actually protected.
72 | *
73 | * @param signBlock
74 | * The sign block.
75 | * @return True if the sign is placed near a block that can be protected.
76 | */
77 | boolean isSignNearbyProtectable(Block signBlock);
78 |
79 | /**
80 | * Creates a new protection sign, ignoring the content already on the sign.
81 | *
82 | *
83 | * To inspect the contents of existing signs, use
84 | * {@link #findProtection(Block)}.
85 | *
86 | * @param sign
87 | * The sign.
88 | * @param signType
89 | * Type to set the sign to.
90 | * @param onFirstLine
91 | * Person to place on the first line.
92 | * @return The new protection sign.
93 | */
94 | ProtectionSign newProtectionSign(Sign sign, SignType signType, Profile onFirstLine);
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/ProtectionSign.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import java.util.List;
4 |
5 | import org.bukkit.Location;
6 |
7 | import nl.rutgerkok.blocklocker.profile.Profile;
8 |
9 | /**
10 | * Represents the information on a protection sign in the world. Instances of
11 | * this interface must be immutable.
12 | *
13 | *
14 | * Two protection signs are considered equal when they are placed on the same
15 | * block in the same world and are of the same implementation.
16 | */
17 | public interface ProtectionSign {
18 |
19 | /**
20 | * Gets the location of this sign.
21 | *
22 | * @return The location.
23 | */
24 | Location getLocation();
25 |
26 | /**
27 | * Gets all profiles currently on the sign. The list will have one, two or
28 | * three profiles. In other words: it is always save to call
29 | * {@code getProfiles().get(0)}.
30 | *
31 | * @return All profiles.
32 | */
33 | List getProfiles();
34 |
35 | /**
36 | * Gets the type of this sign. The type of the sign depends on the header of
37 | * the sign.
38 | *
39 | * @return The type.
40 | */
41 | SignType getType();
42 |
43 | /**
44 | * Returns true if this sign is saved in an outdated way (plain text, missing
45 | * header color/wrong casing) and would require a resave.
46 | *
47 | * @return Whether the sign requires a resaves.
48 | */
49 | boolean requiresResave();
50 |
51 | /**
52 | * Creates a new protection sign object with the given profiles. Existing
53 | * profiles are erased. If this sign is not of the type
54 | * {@link SignType#MORE_USERS} the first entry of the list will become the
55 | * owner.
56 | *
57 | *
58 | * This object is immutable and will not be modified. The actual sign in the
59 | * world will not be modified too. You must save the returned
60 | * {@link ProtectionSign} using {@link SignParser#saveSign(ProtectionSign)}.
61 | *
62 | *
63 | * @param profiles
64 | * The profiles for the protection sign.
65 | * @return The new object. * @throws NullPointerException If any entry in the
66 | * list is 0.
67 | * @throws IllegalArgumentException
68 | * If the list is empty, or if the list has a size larger than 3.
69 | */
70 | ProtectionSign withProfiles(List profiles);
71 |
72 | /**
73 | * Returns a instance that requires a resave.
74 | *
75 | * @see #requiresResave()
76 | * @return An instance.
77 | */
78 | ProtectionSign withRequiringResave();
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/ProtectionType.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import nl.rutgerkok.blocklocker.protection.AttachedProtection;
4 | import nl.rutgerkok.blocklocker.protection.ContainerProtection;
5 | import nl.rutgerkok.blocklocker.protection.DoorProtection;
6 |
7 | /**
8 | * The different types of protections.
9 | *
10 | */
11 | public enum ProtectionType {
12 | /**
13 | * A container, represented by {@link ContainerProtection}.
14 | */
15 | CONTAINER,
16 | /**
17 | * A door, represented by {@link DoorProtection}.
18 | */
19 | DOOR,
20 | /**
21 | * A block where signs can also be attached to the block it is
22 | * hanging/standing on. Represented {@link AttachedProtection}.
23 | */
24 | ATTACHABLE;
25 | }
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/ProtectionUpdater.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import nl.rutgerkok.blocklocker.protection.Protection;
4 |
5 | /**
6 | * Queues protections for updates of the attached signs. In offline mode, just
7 | * the colors have to be updated, but in online mode the UUID may be looked up,
8 | * or the player name may be updated.
9 | *
10 | */
11 | public interface ProtectionUpdater {
12 |
13 | /**
14 | * Does generic cleaning for the signs on the protection at some point in the
15 | * near future. Fixes the missing UUIDs in the given protection, by looking them
16 | * up if the player is online.
17 | *
18 | * @param protection
19 | * The protection to fix. If the protection was already queued for an
20 | * update, nothing happens.
21 | * @param newProtection
22 | * True if this protection is new, false otherwise. Currently has no
23 | * effect.
24 | */
25 | void update(Protection protection, boolean newProtection);
26 |
27 | }
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/SearchMode.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | /**
4 | * The types of blocks to look out for.
5 | *
6 | * A protection consists of three block types:
7 | *
8 | * - Protection blocks, like door or chest blocks.
9 | * - Blocks supporting the protection, can be of any material. For example,
10 | * the block under the door is a supporting block.
11 | * - Signs.
12 | *
13 | */
14 | public enum SearchMode {
15 | /**
16 | * Ignores both {@link #NO_SIGNS signs} and {@link #NO_SUPPORTING_BLOCKS supporting blocks}.
17 | */
18 | MAIN_BLOCKS_ONLY,
19 | /**
20 | * Ignores blocks that are solely part of the protection because they are
21 | * supporting another block.
22 | */
23 | NO_SUPPORTING_BLOCKS,
24 | /**
25 | * Ignores protection signs.
26 | */
27 | NO_SIGNS,
28 | /**
29 | * Includes all blocks (protection blocks, supporting blocks and signs) in
30 | * the search.
31 | */
32 | ALL;
33 |
34 | /**
35 | * Gets whether supporting blocks should be searched for. If the block being
36 | * searched is a supporting block, the protection won't be found if this
37 | * method returns false.
38 | *
39 | * @return True if supporting blocks should be searched for, false
40 | * otherwise.
41 | */
42 | public boolean searchForSupportingBlocks() {
43 | return this != NO_SUPPORTING_BLOCKS && this != MAIN_BLOCKS_ONLY;
44 | }
45 |
46 | /**
47 | * Gets whether signs should be searched for. If the block being searched is
48 | * a sign, the protection won't be found if this method returns false.
49 | *
50 | * @return True if supporting blocks should be searched for, false
51 | * otherwise.
52 | */
53 | public boolean searchForSigns() {
54 | return this != NO_SIGNS && this != MAIN_BLOCKS_ONLY;
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/SecretSignEntry.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import java.util.Optional;
4 | import java.util.OptionalInt;
5 | import java.util.UUID;
6 |
7 | /**
8 | * Used to store secret extra data on a sign. This class represents a single
9 | * entry, so it can for example store one player.
10 | *
11 | */
12 | public interface SecretSignEntry {
13 |
14 | /**
15 | * Gets a boolean with the given name.
16 | *
17 | * @param key
18 | * The key, must only contain [a-z_].
19 | * @return The value, if present.
20 | */
21 | Optional getBoolean(String key);
22 |
23 | /**
24 | * Gets an integer with the given name.
25 | *
26 | * @param key
27 | * The key, must only contain [a-z_].
28 | * @return The value, if present.
29 | */
30 | OptionalInt getInteger(String key);
31 |
32 | /**
33 | * Gets a string with the given name.
34 | *
35 | * @param key
36 | * The key, must only contain [a-z_].
37 | * @return The value, if present.
38 | */
39 | Optional getString(String key);
40 |
41 | /**
42 | * Gets a unique id with the given name.
43 | *
44 | * @param key
45 | * The key, must only contain [a-z_].
46 | * @return The value, if present.
47 | */
48 | Optional getUniqueId(String key);
49 |
50 | /**
51 | * Sets a boolean with the given name.
52 | *
53 | * @param key
54 | * The key, must only contain [a-z_].
55 | * @param value
56 | * The value.
57 | */
58 | void setBoolean(String key, boolean value);
59 |
60 | /**
61 | * Sets an integer with the given name.
62 | *
63 | * @param key
64 | * The key, must only contain [a-z_].
65 | * @param value
66 | * The value.
67 | */
68 | void setInteger(String key, int value);
69 |
70 | /**
71 | * Sets a string with the given name.
72 | *
73 | * @param key
74 | * The key, must only contain [a-z_].
75 | * @param value
76 | * The value, may not be null.
77 | */
78 | void setString(String key, String value);
79 |
80 | /**
81 | * Sets a unique id with the given name.
82 | *
83 | * @param key
84 | * The key, must only contain [a-z_].
85 | * @param value
86 | * The value, may not be null.
87 | */
88 | void setUniqueId(String key, UUID value);
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/SignParser.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import java.util.Optional;
4 |
5 | import org.bukkit.block.Block;
6 | import org.bukkit.block.Sign;
7 | import org.bukkit.block.sign.Side;
8 | import org.bukkit.event.block.SignChangeEvent;
9 |
10 | /**
11 | * Parses a single sign. It essentially converts between {@link Sign} and
12 | * {@link ProtectionSign}.
13 | *
14 | */
15 | public interface SignParser {
16 |
17 | /**
18 | * Gets the text-only display lines that should be displayed on the sign at the
19 | * front.
20 | *
21 | * @param sign
22 | * The sign.
23 | * @return The display text.
24 | */
25 | String[] getDisplayLines(ProtectionSign sign);
26 |
27 | /**
28 | * Gets the type of the sign.
29 | *
30 | * @param sign
31 | * The sign.
32 | * @param side
33 | * The side of the sign to read.
34 | * @return The type of the sign.
35 | */
36 | Optional getSignType(Sign sign, Side side);
37 |
38 | /**
39 | * Gets the type of the sign from the {@link SignChangeEvent}. The event
40 | * fires before the sign in the world is updated, so trying to read from the
41 | * world will result in outdated information.
42 | *
43 | * @param event
44 | * The sign change event.
45 | * @return The type of the sign.
46 | */
47 | Optional getSignType(SignChangeEvent event);
48 |
49 | /**
50 | * Gets whether the sign header is valid. Calling this method is the same as
51 | * calling {@code getSignType(sign).isPresent()}.
52 | *
53 | * @param sign
54 | * The sign to check.
55 | * @return True if the header is valid, false otherwise.
56 | */
57 | boolean hasValidHeader(Sign sign);
58 |
59 | /**
60 | * Parses the given sign for all names on it.
61 | *
62 | * @param signBlock
63 | * The sign to parse.
64 | * @return The parsed sign.
65 | */
66 | Optional parseSign(Block signBlock);
67 |
68 | /**
69 | * Saves the contents of the given sign to the world.
70 | *
71 | * @param sign
72 | * The sign to save.
73 | */
74 | void saveSign(ProtectionSign sign);
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/SignType.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | /**
4 | * The different types of signs.
5 | *
6 | */
7 | public enum SignType {
8 | MORE_USERS, PRIVATE;
9 |
10 | /**
11 | * Gets whether this sign is a main sign: the sign type where exactly
12 | * one is required for each protection.
13 | *
14 | * @return True if this is a main sign, false otherwise.
15 | */
16 | public boolean isMainSign() {
17 | return this == PRIVATE;
18 | }
19 | }
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/Translator.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import java.util.List;
4 | import java.util.Locale;
5 |
6 | import org.bukkit.ChatColor;
7 | import org.bukkit.command.CommandSender;
8 |
9 | /**
10 | * Collection of translations.
11 | *
12 | */
13 | public abstract class Translator {
14 |
15 | public enum Translation {
16 | COMMAND_CANNOT_BE_USED_BY_CONSOLE,
17 | COMMAND_CANNOT_EDIT_OWNER,
18 | COMMAND_LINE_NUMBER_OUT_OF_BOUNDS,
19 | COMMAND_NO_PERMISSION,
20 | COMMAND_NO_SIGN_SELECTED,
21 | COMMAND_PLAYER_NAME_TOO_LONG,
22 | COMMAND_PLUGIN_RELOADED,
23 | COMMAND_SIGN_NO_LONGER_PART_OF_PROTECTION,
24 | COMMAND_UPDATED_SIGN,
25 | PROTECTION_ADD_MORE_USERS_SIGN_INSTEAD,
26 | PROTECTION_BYPASSED,
27 | PROTECTION_CANNOT_CHANGE_SIGN,
28 | PROTECTION_CHEST_HINT,
29 | PROTECTION_CLAIMED_CONTAINER,
30 | PROTECTION_CLAIMED_MANUALLY,
31 | PROTECTION_EXPIRED,
32 | PROTECTION_IN_WILDERNESS,
33 | PROTECTION_IS_CLAIMED_BY,
34 | PROTECTION_NO_ACCESS,
35 | PROTECTION_NO_PERMISSION_FOR_CLAIM,
36 | PROTECTION_NOT_NEARBY,
37 | TAG_EVERYONE,
38 | TAG_MORE_USERS,
39 | TAG_PRIVATE,
40 | TAG_REDSTONE,
41 | TAG_GOLEM,
42 | TAG_TIMER,
43 | UPDATER_MORE_INFORMATION,
44 | UPDATER_UNSUPPORTED_SERVER,
45 | UPDATER_UPDATE_AVAILABLE;
46 |
47 | /**
48 | * Gets the key used in configuration files.
49 | */
50 | @Override
51 | public String toString() {
52 | return name().replaceFirst("_", ".").toLowerCase(Locale.ROOT);
53 | }
54 | }
55 |
56 | /**
57 | * Returns the translation with the given key. If no such translation
58 | * exists, the key is returned.
59 | *
60 | * @param key
61 | * The key of the translation.
62 | * @return The translation, or the key if not found.
63 | */
64 | public abstract String get(Translation key);
65 |
66 | /**
67 | * Returns a list of all possible translations.
68 | *
69 | * @param key
70 | * The key of the translation.
71 | * @return A list of all possible translations, or the key (in a list) if not found.
72 | */
73 | public abstract List getAll(Translation key);
74 |
75 | /**
76 | * Same as {@link #getAll(Translation)}, but with
77 | * {@link ChatColor#stripColor(String)} applied.
78 | *
79 | * @param key
80 | * The key of the translation.
81 | * @return A list of all possible translations, or the key (in a list) if not found.
82 | */
83 | public abstract List getAllWithoutColor(Translation key);
84 |
85 | /**
86 | * Same as {@link #get(Translation)}, but with
87 | * {@link ChatColor#stripColor(String)} applied.
88 | *
89 | * @param key
90 | * The key of the translation.
91 | * @return The translation, or the key if not found.
92 | */
93 | public abstract String getWithoutColor(Translation key);
94 |
95 | /**
96 | * Sends the specified message translated to the given player.
97 | *
98 | * @param player
99 | * The player (or console) to the send the message to.
100 | * @param translation
101 | * The message to send.
102 | */
103 | public abstract void sendMessage(CommandSender player, Translation translation);
104 |
105 | /**
106 | * Sends the specified message translated to the given player.
107 | *
108 | * @param player
109 | * The player (or console) to the send the message to.
110 | * @param translation
111 | * The message to send.
112 | * @param parameters
113 | * Replacements for the message. {0} will be replaced by the
114 | * first parameter, etc.
115 | */
116 | public final void sendMessage(CommandSender player, Translation translation, String... parameters) {
117 | String translated = get(translation);
118 | for (int i = 0; i < parameters.length; i++) {
119 | translated = translated.replace("{" + i + "}", parameters[i]);
120 | }
121 | player.sendMessage(translated);
122 | }
123 | }
124 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/event/PlayerProtectionCreateEvent.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.event;
2 |
3 | import java.util.Objects;
4 |
5 | import org.bukkit.block.Block;
6 | import org.bukkit.entity.Player;
7 | import org.bukkit.event.Cancellable;
8 | import org.bukkit.event.HandlerList;
9 | import org.bukkit.event.player.PlayerEvent;
10 |
11 | /**
12 | * Called just before a protection is created by a player. If you cancel the
13 | * event, the sign will not be placed, or will be popped off.
14 | *
15 | *
16 | * This event is only fired if a player edits a sign to become a [Private] sign,
17 | * or if a player right-clicks a protectable block with a sign in their hand,
18 | * creating a protection. Note that people with world editing tools can bypass
19 | * this event.
20 | */
21 | public class PlayerProtectionCreateEvent extends PlayerEvent implements Cancellable {
22 | private static final HandlerList handlers = new HandlerList();
23 |
24 | public static HandlerList getHandlerList() {
25 | return handlers;
26 | }
27 |
28 | private boolean isCancelled = false;
29 | private final Block signBlock;
30 |
31 | public PlayerProtectionCreateEvent(Player player, Block signBlock) {
32 | super(Objects.requireNonNull(player, "player"));
33 | this.signBlock = Objects.requireNonNull(signBlock, "signBlock");
34 | }
35 |
36 | @Override
37 | public HandlerList getHandlers() {
38 | return handlers;
39 | }
40 |
41 | /**
42 | * Gets the block where the [Private] sign is or will be located. Note that
43 | * there are different ways to create a protection: you can right-click a chest
44 | * with a sign in your hand, or you can manually place a sign and edit that. In
45 | * the first case, no sign will exist yet at this location while in the second
46 | * case, there will already be a sign with some text on it.
47 | *
48 | * @return The block where the [Private] sign is or will be located.
49 | */
50 | public Block getSignBlock() {
51 | return this.signBlock;
52 | }
53 |
54 | @Override
55 | public boolean isCancelled() {
56 | return this.isCancelled;
57 | }
58 |
59 | @Override
60 | public void setCancelled(boolean cancel) {
61 | this.isCancelled = cancel;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/event/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Events, for consumption by other plugins.
3 | */
4 | package nl.rutgerkok.blocklocker.event;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/group/CombinedGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.group;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.List;
6 |
7 | import org.bukkit.entity.Player;
8 |
9 | import com.google.common.base.Preconditions;
10 |
11 | /**
12 | * Class that combines several group systems into one. The
13 | * {@link #isInGroup(Player, String)} method will return true if any of the
14 | * group systems returns true.
15 | *
16 | */
17 | public final class CombinedGroupSystem extends GroupSystem {
18 |
19 | private List systems;
20 |
21 | /**
22 | * Constructs an initially empty combined group system.
23 | *
24 | * @see #addSystem(GroupSystem)
25 | */
26 | public CombinedGroupSystem() {
27 | this.systems = new ArrayList<>();
28 | }
29 |
30 | /**
31 | * Adds a new group system. After calling this method, the
32 | * {@link #isInGroup(Player, String)} method on this object is guaranteed to
33 | * return true if the {@link #isInGroup(Player, String)} on the given group
34 | * system returns true too. too.
35 | *
36 | * @param system
37 | * The group system, may not be null.
38 | */
39 | public void addSystem(GroupSystem system) {
40 | this.systems.add(Preconditions.checkNotNull(system));
41 | }
42 |
43 | /**
44 | * @deprecated Just use {@link #addSystem(GroupSystem)}
45 | * @param systems The systems to add.
46 | */
47 | @Deprecated
48 | public void addSystems(Iterable systems) {
49 | for (GroupSystem system : systems) {
50 | addSystem(system);
51 | }
52 | }
53 |
54 | /**
55 | * Gets all groups that must be kept on reload.
56 | *
57 | * @return All groups that must be kept.
58 | */
59 | public Collection getReloadSurvivors() {
60 | Collection reloadSurvivors = new ArrayList<>();
61 | for (GroupSystem system : this.systems) {
62 | if (system.keepOnReload()) {
63 | reloadSurvivors.add(system);
64 | }
65 | }
66 | return reloadSurvivors;
67 | }
68 |
69 | @Override
70 | public boolean isGroupLeader(Player player, String groupName) {
71 | for (GroupSystem system : systems) {
72 | if (system.isGroupLeader(player, groupName)) {
73 | return true;
74 | }
75 | }
76 | return false;
77 | }
78 |
79 | @Override
80 | public boolean isInGroup(Player player, String groupName) {
81 | for (GroupSystem system : systems) {
82 | if (system.isInGroup(player, groupName)) {
83 | return true;
84 | }
85 | }
86 | return false;
87 | }
88 |
89 | @Override
90 | public boolean keepOnReload() {
91 | // BlockLocker will re-add the group system
92 | return false;
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/group/GroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.group;
2 |
3 | import org.bukkit.entity.Player;
4 |
5 | /**
6 | * Represents a group system on the server.
7 | *
8 | */
9 | public abstract class GroupSystem {
10 |
11 | /**
12 | * Gets whether the given player is in a group with the given name. The
13 | * implementation should make an effort to make the group name case
14 | * insensitive, but this is not strictly required.
15 | *
16 | * @param player
17 | * The player to check.
18 | * @param groupName
19 | * The name of the group.
20 | *
21 | * @return True if the player is in the given group, false otherwise.
22 | */
23 | public abstract boolean isInGroup(Player player, String groupName);
24 |
25 | /**
26 | * Gets whether the given player is a leader of the given group. The exact
27 | * definition of a leader is up to the implementation. The implementation
28 | * should make an effort to make the group name case insensitive, but this
29 | * is not strictly required.
30 | *
31 | *
32 | * The default implementation just returns false.
33 | *
34 | * @param player
35 | * The player to check.
36 | * @param groupName
37 | * The name of the group.
38 | *
39 | * @return True if the player is a leader of the given group, false
40 | * otherwise.
41 | */
42 | public boolean isGroupLeader(Player player, String groupName) {
43 | return false;
44 | }
45 |
46 | /**
47 | * Gets whether this group system must be kept when the plugin is reloaded
48 | * using the reload command of the plugin.
49 | *
50 | *
51 | * When a group system is removed on reload, it must be re-added after the
52 | * reload. For group systems provided by other plugins this is problematic,
53 | * so they must return true. On the other hand, group systems included in
54 | * BlockLocker will be loaded again by BlockLocker, so they must return
55 | * false.
56 | *
57 | * @return True if the group system must be kept on reload, false otherwise.
58 | */
59 | public boolean keepOnReload() {
60 | // "return true" is the correct option for third-party plugins
61 | return true;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/group/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Whole groups can be given access to a protection. This package represents
3 | * such groups.
4 | *
5 | */
6 | package nl.rutgerkok.blocklocker.group;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/ChestSettingsImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Calendar;
5 | import java.util.Date;
6 | import java.util.List;
7 | import java.util.Locale;
8 | import java.util.Objects;
9 | import java.util.Optional;
10 |
11 | import org.bukkit.block.Block;
12 |
13 | import nl.rutgerkok.blocklocker.AttackType;
14 | import nl.rutgerkok.blocklocker.ChestSettings;
15 | import nl.rutgerkok.blocklocker.ProtectableBlocksSettings;
16 | import nl.rutgerkok.blocklocker.ProtectionType;
17 | import nl.rutgerkok.blocklocker.SignType;
18 | import nl.rutgerkok.blocklocker.Translator;
19 | import nl.rutgerkok.blocklocker.Translator.Translation;
20 |
21 | class ChestSettingsImpl implements ChestSettings {
22 |
23 | private static final ProtectionType[] PROTECTION_TYPES = ProtectionType.values();
24 |
25 | private final Config config;
26 | private final Translator translator;
27 | private final List extraProtectables = new ArrayList<>();
28 |
29 | ChestSettingsImpl(Translator translator, Config config) {
30 | this.translator = Objects.requireNonNull(translator, "translator");
31 | this.config = Objects.requireNonNull(config, "config");
32 | }
33 |
34 | @Override
35 | public boolean allowDestroyBy(AttackType attackType) {
36 | return config.allowDestroyBy(attackType);
37 | }
38 |
39 | @Override
40 | public boolean canProtect(Block block) {
41 | if (config.canProtect(block)) {
42 | return true;
43 | }
44 | if (!this.extraProtectables.isEmpty()) {
45 | for (ProtectableBlocksSettings extra : this.extraProtectables) {
46 | if (extra.canProtect(block)) {
47 | return true;
48 | }
49 | }
50 | }
51 | return false;
52 | }
53 |
54 | @Override
55 | public boolean canProtect(ProtectionType type, Block block) {
56 | if (config.canProtect(type, block)) {
57 | return true;
58 | }
59 | if (!this.extraProtectables.isEmpty()) {
60 | for (ProtectableBlocksSettings extra : this.extraProtectables) {
61 | if (extra.canProtect(type, block)) {
62 | return true;
63 | }
64 | }
65 | }
66 | return false;
67 | }
68 |
69 | @Override
70 | public Optional getChestExpireDate() {
71 | int days = config.getAutoExpireDays();
72 | if (days <= 0) {
73 | return Optional.empty();
74 | }
75 |
76 | // Calculate the cutoff date
77 | Calendar calendar = Calendar.getInstance(Locale.US);
78 | calendar.add(Calendar.DAY_OF_MONTH, -days);
79 | Date cutoffDate = calendar.getTime();
80 |
81 | return Optional.of(cutoffDate);
82 | }
83 |
84 | @Override
85 | public boolean getConnectContainers() {
86 | return this.config.getConnectContainers();
87 | }
88 |
89 | @Override
90 | public int getDefaultDoorOpenSeconds() {
91 | return config.getDefaultDoorOpenSeconds();
92 | }
93 |
94 | @Override
95 | public List getExtraProtectables() {
96 | return this.extraProtectables;
97 | }
98 |
99 | @Override
100 | public String getFancyLocalizedHeader(SignType signType, String header) {
101 | List headers = translator.getAll(getTranslationKey(signType));
102 |
103 | for (String head : headers) {
104 | if (head.equalsIgnoreCase(header)) {
105 | return header;
106 | }
107 | }
108 |
109 | return translator.get(getTranslationKey(signType));
110 | }
111 |
112 | @Override
113 | public Optional getProtectionType(Block block) {
114 | for (ProtectionType type : PROTECTION_TYPES) {
115 | if (canProtect(type, block)) {
116 | return Optional.of(type);
117 | }
118 | }
119 | return Optional.empty();
120 | }
121 |
122 | @Override
123 | public List getSimpleLocalizedHeaders(SignType signType) {
124 | return translator.getAllWithoutColor(getTranslationKey(signType));
125 | }
126 |
127 | private Translation getTranslationKey(SignType signType) {
128 | switch (signType) {
129 | case MORE_USERS:
130 | return Translation.TAG_MORE_USERS;
131 | case PRIVATE:
132 | return Translation.TAG_PRIVATE;
133 | }
134 | throw new AssertionError("Unknown type: " + signType);
135 | }
136 |
137 | }
138 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/HopperCacheImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import org.bukkit.block.Block;
6 |
7 | import com.google.common.cache.Cache;
8 | import com.google.common.cache.CacheBuilder;
9 |
10 | import nl.rutgerkok.blocklocker.ProtectionCache;
11 |
12 | final class HopperCacheImpl implements ProtectionCache {
13 |
14 | private static final long EXPIRE_TIME_SECONDS = 10;
15 | private final Cache redstoneCache;
16 | private final Cache golemCache;
17 |
18 | HopperCacheImpl() {
19 | redstoneCache = CacheBuilder.newBuilder().initialCapacity(1000)
20 | .maximumSize(5000)
21 | .expireAfterWrite(EXPIRE_TIME_SECONDS, TimeUnit.SECONDS)
22 | .build();
23 | golemCache = CacheBuilder.newBuilder().initialCapacity(1000)
24 | .maximumSize(5000)
25 | .expireAfterWrite(EXPIRE_TIME_SECONDS, TimeUnit.SECONDS)
26 | .build();
27 | }
28 |
29 | private Cache getCache(CacheType cacheType) {
30 | return switch (cacheType) {
31 | case REDSTONE -> this.redstoneCache;
32 | case GOLEM -> this.golemCache;
33 | };
34 | }
35 |
36 | @Override
37 | public CacheFlag getAllowed(Block block, CacheType cacheType) {
38 | Boolean isAllowed = getCache(cacheType).getIfPresent(block);
39 |
40 | if (isAllowed == null) {
41 | return CacheFlag.MISS_CACHE;
42 | }
43 | if (isAllowed) {
44 | return CacheFlag.ALLOWED;
45 | } else {
46 | return CacheFlag.NOT_ALLOWED;
47 | }
48 | }
49 |
50 | @Override
51 | public void setAllowed(Block block, CacheType cacheType, boolean allowed) {
52 | getCache(cacheType).put(block, allowed);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/JsonSecretSignEntry.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.util.Objects;
4 | import java.util.Optional;
5 | import java.util.OptionalInt;
6 | import java.util.UUID;
7 |
8 | import com.google.gson.JsonElement;
9 | import com.google.gson.JsonObject;
10 |
11 | import nl.rutgerkok.blocklocker.SecretSignEntry;
12 |
13 | /**
14 | * Implements a secret sign entry on top of JSON. Useful if you need a
15 | * stand-alone implementation for testing. Also used for reading legacy data.
16 | *
17 | */
18 | public final class JsonSecretSignEntry implements SecretSignEntry {
19 |
20 | private final JsonObject object;
21 |
22 | public JsonSecretSignEntry(JsonObject object) {
23 | this.object = Objects.requireNonNull(object, "object");
24 | }
25 |
26 | @Override
27 | public Optional getBoolean(String key) {
28 | if (!object.has(key)) {
29 | return Optional.empty();
30 | }
31 | return Optional.of(object.get(key).getAsBoolean());
32 | }
33 |
34 | @Override
35 | public OptionalInt getInteger(String key) {
36 | if (!object.has(key)) {
37 | return OptionalInt.empty();
38 | }
39 | return OptionalInt.of(object.get(key).getAsNumber().intValue());
40 | }
41 |
42 | @Override
43 | public Optional getString(String key) {
44 | if (!object.has(key)) {
45 | return Optional.empty();
46 | }
47 | return Optional.of(object.get(key).getAsString());
48 | }
49 |
50 | @Override
51 | public Optional getUniqueId(String key) {
52 | JsonElement uuidObject = object.get(key);
53 |
54 | if (uuidObject == null || !uuidObject.isJsonPrimitive() || !uuidObject.getAsJsonPrimitive().isString()) {
55 | return Optional.empty();
56 | }
57 | try {
58 | UUID uuid = UUID.fromString(uuidObject.getAsString());
59 | return Optional.of(uuid);
60 | } catch (IllegalArgumentException e) {
61 | return Optional.empty();
62 | }
63 | }
64 |
65 | @Override
66 | public void setBoolean(String key, boolean bool) {
67 | object.addProperty(key, bool);
68 | }
69 |
70 | @Override
71 | public void setInteger(String key, int integer) {
72 | object.addProperty(key, integer);
73 | }
74 |
75 | @Override
76 | public void setString(String key, String value) {
77 | object.addProperty(key, value);
78 | }
79 |
80 | @Override
81 | public void setUniqueId(String key, UUID uuid) {
82 | object.addProperty(key, uuid.toString());
83 | }
84 |
85 | }
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/NbtSecretSignEntry.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.lang.ref.WeakReference;
4 | import java.util.Objects;
5 | import java.util.Optional;
6 | import java.util.OptionalInt;
7 | import java.util.UUID;
8 |
9 | import org.bukkit.NamespacedKey;
10 | import org.bukkit.persistence.PersistentDataAdapterContext;
11 | import org.bukkit.persistence.PersistentDataContainer;
12 | import org.bukkit.persistence.PersistentDataType;
13 | import org.bukkit.plugin.Plugin;
14 | import org.bukkit.plugin.java.JavaPlugin;
15 |
16 | import nl.rutgerkok.blocklocker.SecretSignEntry;
17 |
18 | /**
19 | * Implements a secret sign entry on top of NBT tags (using
20 | * {@link PersistentDataContainer}.
21 | */
22 | public final class NbtSecretSignEntry implements SecretSignEntry {
23 |
24 | private static class SecretSignTagType implements PersistentDataType {
25 |
26 | @Override
27 | public NbtSecretSignEntry fromPrimitive(PersistentDataContainer primitive,
28 | PersistentDataAdapterContext context) {
29 | return new NbtSecretSignEntry(primitive);
30 | }
31 |
32 | @Override
33 | public Class getComplexType() {
34 | return NbtSecretSignEntry.class;
35 | }
36 |
37 | @Override
38 | public Class getPrimitiveType() {
39 | return PersistentDataContainer.class;
40 | }
41 |
42 | @Override
43 | public PersistentDataContainer toPrimitive(NbtSecretSignEntry complex,
44 | PersistentDataAdapterContext context) {
45 | return complex.data;
46 | }
47 |
48 | }
49 |
50 | public static final PersistentDataType TAG_TYPE = new SecretSignTagType();
51 |
52 | private static final WeakReference PLUGIN = new WeakReference<>(
53 | JavaPlugin.getProvidingPlugin(NbtSecretSignEntry.class));
54 |
55 | static NamespacedKey key(String name) {
56 | return new NamespacedKey(PLUGIN.get(), name);
57 | }
58 |
59 | private final PersistentDataContainer data;
60 |
61 | public NbtSecretSignEntry(PersistentDataContainer data) {
62 | this.data = Objects.requireNonNull(data);
63 | }
64 |
65 | @Override
66 | public Optional getBoolean(String key) {
67 | Byte result = data.get(key(key), PersistentDataType.BYTE);
68 | if (result == null) {
69 | return Optional.empty();
70 | }
71 | if (result == 0) {
72 | return Optional.of(Boolean.FALSE);
73 | }
74 | return Optional.of(Boolean.TRUE);
75 | }
76 |
77 | @Override
78 | public OptionalInt getInteger(String key) {
79 | Integer integer = data.get(key(key), PersistentDataType.INTEGER);
80 | if (integer == null) {
81 | return OptionalInt.empty();
82 | }
83 | return OptionalInt.of(integer.intValue());
84 | }
85 |
86 | @Override
87 | public Optional getString(String key) {
88 | return Optional.ofNullable(data.get(key(key), PersistentDataType.STRING));
89 | }
90 |
91 | @Override
92 | public Optional getUniqueId(String key) {
93 | long[] array = data.get(key(key), PersistentDataType.LONG_ARRAY);
94 | if (array == null || array.length != 2) {
95 | return Optional.empty();
96 | }
97 | return Optional.of(new UUID(array[0], array[1]));
98 | }
99 |
100 | @Override
101 | public void setBoolean(String key, boolean value) {
102 | data.set(key(key), PersistentDataType.BYTE, value ? (byte) 1 : (byte) 0);
103 | }
104 |
105 | @Override
106 | public void setInteger(String key, int integer) {
107 | data.set(key(key), PersistentDataType.INTEGER, integer);
108 | }
109 |
110 | @Override
111 | public void setString(String key, String value) {
112 | data.set(key(key), PersistentDataType.STRING, value);
113 | }
114 |
115 | @Override
116 | public void setUniqueId(String key, UUID uuid) {
117 | long[] array = new long[] { uuid.getMostSignificantBits(), uuid.getLeastSignificantBits() };
118 | data.set(key(key), PersistentDataType.LONG_ARRAY, array);
119 | }
120 |
121 | }
122 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/ProtectionSignImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.util.List;
4 |
5 | import org.bukkit.Location;
6 |
7 | import com.google.common.base.Objects;
8 | import com.google.common.base.Preconditions;
9 | import com.google.common.collect.ImmutableList;
10 |
11 | import nl.rutgerkok.blocklocker.ProtectionSign;
12 | import nl.rutgerkok.blocklocker.SignType;
13 | import nl.rutgerkok.blocklocker.profile.Profile;
14 |
15 | final class ProtectionSignImpl implements ProtectionSign {
16 |
17 | private static final int MAX_PROFILES = 6;
18 | private final SignType signType;
19 | private final List profiles;
20 | private final Location location;
21 | private final boolean requiresResave;
22 |
23 | ProtectionSignImpl(Location location, SignType signType,
24 | List profiles, boolean requiresResave) {
25 | this.location = location;
26 | this.signType = Preconditions.checkNotNull(signType);
27 | this.profiles = ImmutableList.copyOf(profiles);
28 | this.requiresResave = requiresResave;
29 | if (profiles.isEmpty() || profiles.size() > MAX_PROFILES) {
30 | throw new IllegalArgumentException("Invalid size for profiles collection: " + profiles);
31 | }
32 | if (profiles.indexOf(null) != -1) {
33 | throw new IllegalArgumentException("Profiles list contains null profile: " + profiles);
34 | }
35 | }
36 |
37 | @Override
38 | public boolean equals(Object obj) {
39 | if (this == obj) {
40 | return true;
41 | }
42 | if (obj == null) {
43 | return false;
44 | }
45 | if (!(obj instanceof ProtectionSignImpl)) {
46 | return false;
47 | }
48 | ProtectionSignImpl other = (ProtectionSignImpl) obj;
49 | if (!Objects.equal(location.getWorld(), other.location.getWorld())) {
50 | return false;
51 | }
52 | if (location.getBlockX() != other.location.getBlockX()) {
53 | return false;
54 | }
55 | if (location.getBlockY() != other.location.getBlockY()) {
56 | return false;
57 | }
58 | if (location.getBlockZ() != other.location.getBlockZ()) {
59 | return false;
60 | }
61 | return true;
62 | }
63 |
64 | @Override
65 | public Location getLocation() {
66 | // Location is mutable, so always return a clone
67 | return location.clone();
68 | }
69 |
70 | @Override
71 | public List getProfiles() {
72 | return profiles;
73 | }
74 |
75 | @Override
76 | public SignType getType() {
77 | return signType;
78 | }
79 |
80 | @Override
81 | public int hashCode() {
82 | final int prime = 31;
83 | int result = 1;
84 | result = prime * result + location.getBlockX();
85 | result = prime * result + location.getBlockY();
86 | result = prime * result + location.getBlockZ();
87 | return result;
88 | }
89 |
90 | @Override
91 | public boolean requiresResave() {
92 | return this.requiresResave;
93 | }
94 |
95 | @Override
96 | public ProtectionSign withProfiles(List profiles) {
97 | return new ProtectionSignImpl(location, signType, profiles, requiresResave);
98 | }
99 |
100 | @Override
101 | public ProtectionSign withRequiringResave() {
102 | return new ProtectionSignImpl(location, signType, profiles, true);
103 | }
104 |
105 | }
106 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/ProtectionUpdaterImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 | import java.util.Objects;
6 |
7 | import javax.annotation.Nullable;
8 |
9 | import org.bukkit.Server;
10 | import org.bukkit.entity.Player;
11 |
12 | import nl.rutgerkok.blocklocker.ProfileFactory;
13 | import nl.rutgerkok.blocklocker.ProtectionSign;
14 | import nl.rutgerkok.blocklocker.ProtectionUpdater;
15 | import nl.rutgerkok.blocklocker.SignParser;
16 | import nl.rutgerkok.blocklocker.profile.PlayerProfile;
17 | import nl.rutgerkok.blocklocker.profile.Profile;
18 | import nl.rutgerkok.blocklocker.protection.Protection;
19 |
20 | public class ProtectionUpdaterImpl implements ProtectionUpdater {
21 |
22 | private final Server server;
23 | private final SignParser signParser;
24 | private final ProfileFactory profileFactory;
25 |
26 | public ProtectionUpdaterImpl(Server server, SignParser signParser, ProfileFactory profileFactory) {
27 | this.server = Objects.requireNonNull(server, "server");
28 | this.signParser = Objects.requireNonNull(signParser, "signParser");
29 | this.profileFactory = Objects.requireNonNull(profileFactory, "profileFactory");
30 | }
31 |
32 | @Nullable
33 | private PlayerProfile getUpdatedProfile(PlayerProfile profile) {
34 | if (profile.getUniqueId().isPresent()) {
35 | Player player = server.getPlayer(profile.getUniqueId().get());
36 | if (player != null && !player.getName().equals(profile.getDisplayName())) {
37 | // Found a changed name
38 | return profileFactory.fromPlayer(player);
39 | }
40 | return null;
41 | } else {
42 | // Found a missing unique id
43 | String name = profile.getDisplayName();
44 | if (name.isEmpty()) {
45 | return null; // Empty line, ignore
46 | }
47 | Player player = server.getPlayerExact(name);
48 | if (player == null) {
49 | return null; // No player online with that name, lookup failed
50 | }
51 | return profileFactory.fromPlayer(player);
52 | }
53 | }
54 |
55 | @Override
56 | public void update(Protection protection, boolean newProtection) {
57 | for (ProtectionSign protectionSign : protection.getSigns()) {
58 | updateProtectionSign(protectionSign);
59 | }
60 | }
61 |
62 | @Nullable
63 | private List updateProfiles(ProtectionSign protectionSign) {
64 | List updatedProfiles = null;
65 |
66 | int i = -1; // Will be 0 at first iteration
67 | for (Profile profile : protectionSign.getProfiles()) {
68 | i++;
69 |
70 | if (!(profile instanceof PlayerProfile)) {
71 | continue;
72 | }
73 | PlayerProfile updatedProfile = getUpdatedProfile((PlayerProfile) profile);
74 | if (updatedProfile == null) {
75 | continue; // Nothing to update
76 | }
77 |
78 | if (updatedProfiles == null) {
79 | // Need to initialize list
80 | updatedProfiles = new ArrayList<>(protectionSign.getProfiles());
81 | }
82 | updatedProfiles.set(i, updatedProfile);
83 | }
84 |
85 | return updatedProfiles;
86 | }
87 |
88 | private void updateProtectionSign(ProtectionSign protectionSign) {
89 | List updatedProfiles = updateProfiles(protectionSign);
90 |
91 | if (updatedProfiles != null) {
92 | protectionSign = protectionSign.withProfiles(updatedProfiles);
93 | }
94 |
95 | if (updatedProfiles != null || protectionSign.requiresResave()) {
96 | signParser.saveSign(protectionSign);
97 | }
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/blockfinder/ConnectedContainersBlockFinder.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.blockfinder;
2 |
3 | import java.util.ArrayList;
4 | import java.util.List;
5 |
6 | import org.bukkit.Material;
7 | import org.bukkit.block.Block;
8 | import org.bukkit.block.BlockFace;
9 |
10 | import nl.rutgerkok.blocklocker.SignParser;
11 |
12 | final class ConnectedContainersBlockFinder extends BlockFinder {
13 | private static final int MAX_SEARCH_DISTANCE = 10;
14 |
15 | ConnectedContainersBlockFinder(SignParser parser) {
16 | super(parser);
17 | }
18 |
19 | @Override
20 | public List findContainerNeighbors(Block block) {
21 | Material containerMaterial = block.getType();
22 | List blocks = new ArrayList<>();
23 | blocks.add(block);
24 |
25 | // Search above and below on the starting block
26 | searchVertical(containerMaterial, block, blocks);
27 |
28 | // Just searches in the four cardinal faces, until it hits a block
29 | // of another type. Blocks above and below of the same block type are
30 | // also searched
31 | for (BlockFace face : CARDINAL_FACES) {
32 | int distance = 0;
33 | Block atPosition = block.getRelative(face);
34 | while (distance < MAX_SEARCH_DISTANCE && atPosition.getType() == containerMaterial) {
35 | blocks.add(atPosition);
36 | searchVertical(containerMaterial, atPosition, blocks);
37 |
38 | atPosition = atPosition.getRelative(face);
39 | distance++;
40 | }
41 | }
42 |
43 | BlockFace chestNeighborFace = this.getChestNeighborFaceOrNull(block);
44 | if (chestNeighborFace != null) {
45 | // Double chest, also perform search for other chest block
46 | Block chestNeighbor = block.getRelative(chestNeighborFace);
47 | BlockFace[] searchDirections = { this.turn90Degrees(chestNeighborFace),
48 | this.turn90Degrees(chestNeighborFace).getOppositeFace() };
49 | for (BlockFace face : searchDirections) {
50 | int distance = 0;
51 | Block atPosition = chestNeighbor.getRelative(face);
52 | while (distance < MAX_SEARCH_DISTANCE && atPosition.getType() == containerMaterial) {
53 | blocks.add(atPosition);
54 | searchVertical(containerMaterial, atPosition, blocks);
55 |
56 | atPosition = atPosition.getRelative(face);
57 | distance++;
58 | }
59 | }
60 | }
61 |
62 | return blocks;
63 | }
64 |
65 | /**
66 | * Searches for blocks of the same type above and below the starting block.
67 | *
68 | * @param containerMaterial
69 | * The material {@link Block#getType() startingBlock.getType()}
70 | * returns.
71 | * @param startingBlock
72 | * The starting block.
73 | * @param blocks
74 | * All connected blocks above and below (so not the starting block
75 | * itself) of the same type will be added to this list.
76 | */
77 | private void searchVertical(Material containerMaterial, Block startingBlock, List blocks) {
78 | for (BlockFace face : VERTICAL_FACES) {
79 | int distance = 0;
80 | Block atPosition = startingBlock.getRelative(face);
81 | while (distance < MAX_SEARCH_DISTANCE && atPosition.getType() == containerMaterial) {
82 | blocks.add(atPosition);
83 |
84 | atPosition = atPosition.getRelative(face);
85 | distance++;
86 | }
87 | }
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/blockfinder/SeparateContainersBlockFinder.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.blockfinder;
2 |
3 | import java.util.Collections;
4 | import java.util.List;
5 |
6 | import com.google.common.collect.ImmutableList;
7 |
8 | import org.bukkit.block.Block;
9 | import org.bukkit.block.BlockFace;
10 |
11 | import nl.rutgerkok.blocklocker.SignParser;
12 |
13 | final class SeparateContainersBlockFinder extends BlockFinder {
14 | SeparateContainersBlockFinder(SignParser parser) {
15 | super(parser);
16 | }
17 |
18 | @Override
19 | public List findContainerNeighbors(Block block) {
20 | // Currently only chests share an inventory
21 | // Minecraft connects two chests next to each other that have the same
22 | // direction. We simply check for that condition, taking both normal
23 | // and trapped chests into account
24 | BlockFace chestNeighborFace = this.getChestNeighborFaceOrNull(block);
25 | if (chestNeighborFace == null) {
26 | return Collections.singletonList(block);
27 | }
28 | return ImmutableList.of(block, block.getRelative(chestNeighborFace));
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/blockfinder/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | */
4 | /**
5 | * @author Rutger
6 | *
7 | */
8 | package nl.rutgerkok.blocklocker.impl.blockfinder;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/event/BlockLockerCommand.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.event;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collections;
5 | import java.util.List;
6 |
7 | import org.bukkit.command.Command;
8 | import org.bukkit.command.CommandSender;
9 | import org.bukkit.command.ConsoleCommandSender;
10 | import org.bukkit.command.TabExecutor;
11 |
12 | import com.google.common.base.Preconditions;
13 |
14 | import nl.rutgerkok.blocklocker.BlockLockerPlugin;
15 | import nl.rutgerkok.blocklocker.Permissions;
16 | import nl.rutgerkok.blocklocker.Translator.Translation;
17 |
18 | public final class BlockLockerCommand implements TabExecutor {
19 |
20 | private final BlockLockerPlugin plugin;
21 |
22 | public BlockLockerCommand(BlockLockerPlugin plugin) {
23 | this.plugin = Preconditions.checkNotNull(plugin);
24 | }
25 |
26 | @Override
27 | public boolean onCommand(CommandSender sender, Command command, String label, String[] args) {
28 | if (args.length == 0) {
29 | return false;
30 | }
31 |
32 | if (args[0].equalsIgnoreCase("reload")) {
33 | return reloadCommand(sender);
34 | }
35 | return false;
36 | }
37 |
38 | @Override
39 | public List onTabComplete(CommandSender sender, Command command, String alias, String[] args) {
40 | if (args.length == 2) {
41 | return null;
42 | }
43 | if (args.length > 2) {
44 | return Collections.emptyList();
45 | }
46 | return Arrays.asList("2", "3", "4");
47 | }
48 |
49 | private boolean reloadCommand(CommandSender sender) {
50 | if (!sender.hasPermission(Permissions.CAN_RELOAD)) {
51 | plugin.getTranslator().sendMessage(sender, Translation.COMMAND_NO_PERMISSION);
52 | return true;
53 | }
54 |
55 | plugin.reload();
56 | plugin.getLogger().info(plugin.getTranslator().getWithoutColor(Translation.COMMAND_PLUGIN_RELOADED));
57 | if (!(sender instanceof ConsoleCommandSender)) {
58 | // Avoid sending message twice to the console
59 | plugin.getTranslator().sendMessage(sender, Translation.COMMAND_PLUGIN_RELOADED);
60 | }
61 | return true;
62 | }
63 |
64 |
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/event/EventListener.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.event;
2 |
3 | import java.util.Collection;
4 | import java.util.Date;
5 | import java.util.Optional;
6 |
7 | import org.apache.commons.lang.Validate;
8 | import org.bukkit.block.Block;
9 | import org.bukkit.event.Listener;
10 |
11 | import nl.rutgerkok.blocklocker.ProtectionCache;
12 | import nl.rutgerkok.blocklocker.SearchMode;
13 | import nl.rutgerkok.blocklocker.impl.BlockLockerPluginImpl;
14 | import nl.rutgerkok.blocklocker.profile.Profile;
15 | import nl.rutgerkok.blocklocker.protection.Protection;
16 |
17 | abstract class EventListener implements Listener {
18 |
19 | final BlockLockerPluginImpl plugin;
20 |
21 | EventListener(BlockLockerPluginImpl plugin) {
22 | Validate.notNull(plugin);
23 | this.plugin = plugin;
24 | }
25 |
26 | boolean anyProtected(Collection blocks) {
27 | for (Block block : blocks) {
28 | if (isProtected(block)) {
29 | return true;
30 | }
31 | }
32 | return false;
33 | }
34 |
35 | boolean isExpired(Protection protection) {
36 | Optional cutoffDate = plugin.getChestSettings().getChestExpireDate();
37 | if (cutoffDate.isPresent()) {
38 | return protection.isExpired(cutoffDate.get());
39 | }
40 | return false;
41 | }
42 |
43 | boolean isProtected(Block block) {
44 | return plugin.getProtectionFinder().findProtection(block).isPresent();
45 | }
46 |
47 | boolean isRedstoneDenied(Block block) {
48 | ProtectionCache.CacheFlag flag = plugin.getProtectionCache().getAllowed(block, ProtectionCache.CacheType.REDSTONE);
49 | if (flag != ProtectionCache.CacheFlag.MISS_CACHE) {
50 | return flag == ProtectionCache.CacheFlag.NOT_ALLOWED;
51 | } else {
52 | Optional protection = plugin.getProtectionFinder().findProtection(block, SearchMode.MAIN_BLOCKS_ONLY);
53 | if (protection.isEmpty()) {
54 | plugin.getProtectionCache().setAllowed(block, ProtectionCache.CacheType.REDSTONE,true);
55 | return false;
56 | }
57 | Profile redstone = plugin.getProfileFactory().fromRedstone();
58 | boolean allowed = protection.get().isAllowed(redstone);
59 | plugin.getProtectionCache().setAllowed(block, ProtectionCache.CacheType.REDSTONE, allowed);
60 | return !allowed;
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/event/GolemListener.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.event;
2 |
3 | import io.papermc.paper.event.entity.ItemTransportingEntityValidateTargetEvent;
4 | import nl.rutgerkok.blocklocker.AttackType;
5 | import nl.rutgerkok.blocklocker.ProtectionCache;
6 | import nl.rutgerkok.blocklocker.SearchMode;
7 | import nl.rutgerkok.blocklocker.impl.BlockLockerPluginImpl;
8 | import nl.rutgerkok.blocklocker.profile.Profile;
9 | import nl.rutgerkok.blocklocker.protection.Protection;
10 | import org.bukkit.block.Block;
11 | import org.bukkit.event.EventHandler;
12 |
13 | import java.util.Optional;
14 |
15 | /**
16 | * Listener for just golems. Separated to allow the plugin to run on older Minecraft versions. In the future, when
17 | * backwards compatibility is no longer necessary, the hopper event could be handled here too, then it would be an
18 | * ExtractListener or something.
19 | */
20 | public final class GolemListener extends EventListener {
21 |
22 | public GolemListener(BlockLockerPluginImpl plugin) {
23 | super(plugin);
24 | }
25 |
26 | @EventHandler
27 | public void onEntityContainerTarget(ItemTransportingEntityValidateTargetEvent event) {
28 | // Golem handling
29 | if (!event.isAllowed() || plugin.getChestSettings().allowDestroyBy(AttackType.GOLEM)) {
30 | return;
31 | }
32 |
33 | Block block = event.getBlock();
34 | ProtectionCache cache = this.plugin.getProtectionCache();
35 | ProtectionCache.CacheFlag cacheFlag = cache.getAllowed(block, ProtectionCache.CacheType.GOLEM);
36 | if (cacheFlag == ProtectionCache.CacheFlag.ALLOWED) {
37 | return; // Don't do anything
38 | }
39 | if (cacheFlag == ProtectionCache.CacheFlag.NOT_ALLOWED) {
40 | event.setAllowed(false); // Prevent targeting
41 | return;
42 | }
43 |
44 | // If we're here, cache miss
45 | // Retrieve the value, and store it in the cache
46 | Optional protection = plugin.getProtectionFinder().findProtection(block, SearchMode.MAIN_BLOCKS_ONLY);
47 | if (protection.isEmpty()) {
48 | cache.setAllowed(block, ProtectionCache.CacheType.GOLEM, false);
49 | return;
50 | }
51 | Profile golemProfile = plugin.getProfileFactory().fromGolem();
52 | boolean allowed = protection.get().isAllowed(golemProfile);
53 | cache.setAllowed(block, ProtectionCache.CacheType.GOLEM, allowed);
54 | if (!allowed) {
55 | event.setAllowed(false);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/event/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Classes that handle the various events, so that the containers are protected.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.impl.event;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/FactionsGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import nl.rutgerkok.blocklocker.group.GroupSystem;
4 |
5 | import org.bukkit.entity.Player;
6 | import org.bukkit.plugin.java.JavaPlugin;
7 |
8 | import com.massivecraft.factions.entity.Faction;
9 | import com.massivecraft.factions.entity.MPlayer;
10 |
11 | /**
12 | * Group system hooking into the Factions plugin by MassiveCraft.
13 | *
14 | */
15 | public final class FactionsGroupSystem extends GroupSystem {
16 |
17 | /**
18 | * Tests if the Factions plugin is installed.
19 | *
20 | * @return True if the factions plugin is installed, false otherwise.
21 | */
22 | public static boolean isAvailable() {
23 | try {
24 | JavaPlugin.getProvidingPlugin(MPlayer.class);
25 | return true;
26 | } catch (NoClassDefFoundError e) {
27 | return false;
28 | }
29 | }
30 |
31 | @Override
32 | public boolean isInGroup(Player player, String groupName) {
33 | MPlayer mPlayer = MPlayer.get(player);
34 | Faction faction = mPlayer.getFaction();
35 | return (faction != null && faction.getName().equalsIgnoreCase(groupName));
36 | }
37 |
38 | @Override
39 | public boolean keepOnReload() {
40 | // BlockLocker will re-add the group system
41 | return false;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/GuildsGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import org.bukkit.entity.Player;
4 | import org.bukkit.plugin.java.JavaPlugin;
5 |
6 | import me.glaremasters.guilds.Guilds;
7 | import me.glaremasters.guilds.api.GuildsAPI;
8 | import me.glaremasters.guilds.guild.Guild;
9 | import me.glaremasters.guilds.guild.GuildMember;
10 | import nl.rutgerkok.blocklocker.group.GroupSystem;
11 |
12 | /**
13 | * Group system hooking into the Guilds plugin.
14 | *
15 | */
16 | public final class GuildsGroupSystem extends GroupSystem {
17 |
18 | /**
19 | * Tests if the Guilds plugin is installed.
20 | *
21 | * @return True if the Guilds plugin is installed, false otherwise.
22 | */
23 | public static boolean isAvailable() {
24 | try {
25 | JavaPlugin.getProvidingPlugin(GuildsAPI.class);
26 | return true;
27 | } catch (NoClassDefFoundError e) {
28 | return false;
29 | }
30 | }
31 |
32 | @Override
33 | public boolean isGroupLeader(Player player, String groupName) {
34 | Guild guild = Guilds.getApi().getGuild(player);
35 | if (guild == null) {
36 | return false;
37 | }
38 | GuildMember master = guild.getGuildMaster();
39 | if (master == null) {
40 | // Group has no master, so player is not the group master
41 | return false;
42 | }
43 | if (!master.getUuid().equals(player.getUniqueId())) {
44 | // Player is not het group master
45 | return false;
46 | }
47 | // Player is the group master, but also check name
48 | return guild.getName().equalsIgnoreCase(groupName);
49 | }
50 |
51 | @Override
52 | public boolean isInGroup(Player player, String groupName) {
53 | Guild guild = Guilds.getApi().getGuild(player);
54 | if (guild == null) {
55 | return false;
56 | }
57 | return guild.getName().equalsIgnoreCase(groupName);
58 | }
59 |
60 | @Override
61 | public boolean keepOnReload() {
62 | // BlockLocker will re-add the group system
63 | return false;
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/PermissionsGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import nl.rutgerkok.blocklocker.Permissions;
4 | import nl.rutgerkok.blocklocker.group.GroupSystem;
5 |
6 | import org.bukkit.entity.Player;
7 |
8 | /**
9 | * Considers players with the right group permission node part of a group.
10 | *
11 | */
12 | public final class PermissionsGroupSystem extends GroupSystem {
13 |
14 | @Override
15 | public boolean isInGroup(Player player, String groupName) {
16 | return player.hasPermission(Permissions.getGroupNode(groupName));
17 | }
18 |
19 | @Override
20 | public boolean keepOnReload() {
21 | // BlockLocker will re-add the group system
22 | return false;
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/ScoreboardGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import nl.rutgerkok.blocklocker.group.GroupSystem;
4 |
5 | import org.bukkit.Bukkit;
6 | import org.bukkit.entity.Player;
7 | import org.bukkit.scoreboard.Scoreboard;
8 | import org.bukkit.scoreboard.Team;
9 |
10 | /**
11 | * Looks at the teams on the main scoreboard of the server.
12 | *
13 | */
14 | public final class ScoreboardGroupSystem extends GroupSystem {
15 |
16 | @Override
17 | public boolean isInGroup(Player player, String groupName) {
18 | Scoreboard mainScoreboard = Bukkit.getScoreboardManager().getMainScoreboard();
19 | Team team = mainScoreboard.getEntryTeam(player.getName());
20 | if (team == null) {
21 | return false;
22 | }
23 | return team.getName().equalsIgnoreCase(groupName);
24 | }
25 |
26 | @Override
27 | public boolean keepOnReload() {
28 | // BlockLocker will re-add the group system
29 | return false;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/SimpleClansGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import org.bukkit.entity.Player;
4 | import org.bukkit.plugin.java.JavaPlugin;
5 |
6 | import net.sacredlabyrinth.phaed.simpleclans.Clan;
7 | import net.sacredlabyrinth.phaed.simpleclans.ClanPlayer;
8 | import net.sacredlabyrinth.phaed.simpleclans.SimpleClans;
9 | import nl.rutgerkok.blocklocker.group.GroupSystem;
10 |
11 | /**
12 | * Group system hooking into the SimpleClans plugin.
13 | *
14 | */
15 | public final class SimpleClansGroupSystem extends GroupSystem {
16 |
17 | /**
18 | * Tests if the SimpleClans plugin is installed.
19 | *
20 | * @return True if the SimpleClans plugin is installed, false otherwise.
21 | */
22 | public static boolean isAvailable() {
23 | try {
24 | JavaPlugin.getProvidingPlugin(ClanPlayer.class);
25 | return true;
26 | } catch (NoClassDefFoundError e) {
27 | return false;
28 | }
29 | }
30 |
31 | @Override
32 | public boolean isGroupLeader(Player player, String groupName) {
33 | SimpleClans simpleClans = JavaPlugin.getPlugin(SimpleClans.class);
34 | ClanPlayer clanPlayer = simpleClans.getClanManager().getClanPlayer(player.getUniqueId());
35 | if (!clanPlayer.isLeader()) {
36 | return false;
37 | }
38 | Clan clan = clanPlayer.getClan();
39 | if (clan == null) {
40 | return false;
41 | }
42 | return clan.getName().equalsIgnoreCase(groupName);
43 | }
44 |
45 | @Override
46 | public boolean isInGroup(Player player, String groupName) {
47 | SimpleClans simpleClans = JavaPlugin.getPlugin(SimpleClans.class);
48 | ClanPlayer clanPlayer = simpleClans.getClanManager().getClanPlayer(player.getUniqueId());
49 | if (clanPlayer == null) {
50 | return false;
51 | }
52 | return clanPlayer.getClan().getName().equalsIgnoreCase(groupName);
53 | }
54 |
55 | @Override
56 | public boolean keepOnReload() {
57 | // BlockLocker will re-add the group system
58 | return false;
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/TownyGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import org.bukkit.entity.Player;
4 | import org.bukkit.plugin.java.JavaPlugin;
5 |
6 | import com.palmergames.bukkit.towny.Towny;
7 | import com.palmergames.bukkit.towny.TownyUniverse;
8 | import com.palmergames.bukkit.towny.exceptions.NotRegisteredException;
9 | import com.palmergames.bukkit.towny.object.Nation;
10 | import com.palmergames.bukkit.towny.object.Resident;
11 | import com.palmergames.bukkit.towny.object.Town;
12 |
13 | import nl.rutgerkok.blocklocker.group.GroupSystem;
14 |
15 | /**
16 | * Group system hooking into the Factions plugin by MassiveCraft.
17 | *
18 | */
19 | public final class TownyGroupSystem extends GroupSystem {
20 |
21 | /**
22 | * Tests if the Towny plugin is installed.
23 | *
24 | * @return True if the factions plugin is installed, false otherwise.
25 | */
26 | public static boolean isAvailable() {
27 | try {
28 | JavaPlugin.getProvidingPlugin(Towny.class);
29 | return true;
30 | } catch (NoClassDefFoundError e) {
31 | return false;
32 | }
33 | }
34 |
35 | @Override
36 | public boolean isGroupLeader(Player player, String groupName) {
37 | try {
38 | Resident resident = TownyUniverse.getInstance().getResident(player.getUniqueId());
39 | Town town = resident.getTown();
40 | if (town.getName().equalsIgnoreCase(groupName)) {
41 | if (town.isMayor(resident) || resident.hasTownRank("assistant")) {
42 | return true;
43 | }
44 | }
45 |
46 | Nation nation = town.getNation();
47 | if (nation.getName().equalsIgnoreCase(groupName)) {
48 | if (nation.isKing(resident) || nation.hasAssistant(resident)) {
49 | return true;
50 | }
51 | }
52 |
53 | return false;
54 | } catch (Exception e) {
55 | // Cannot use catch (NotRegisteredException e) because the class
56 | // cannot be loaded then when Towny isn't present
57 | if (e instanceof NotRegisteredException) {
58 | return false;
59 | }
60 | throw new RuntimeException(e);
61 | }
62 | }
63 |
64 | @Override
65 | public boolean isInGroup(Player player, String groupName) {
66 | try {
67 | Resident resident = TownyUniverse.getInstance().getResident(player.getName());
68 | Town town = resident.getTown();
69 | if (town.getName().equalsIgnoreCase(groupName)) {
70 | return true;
71 | }
72 |
73 | Nation nation = town.getNation();
74 | if (nation.getName().equalsIgnoreCase(groupName)) {
75 | return true;
76 | }
77 |
78 | return false;
79 | } catch (Exception e) {
80 | // Cannot use catch (NotRegisteredException e) because the class
81 | // cannot be loaded then when Towny isn't present
82 | if (e instanceof NotRegisteredException) {
83 | return false;
84 | }
85 | throw new RuntimeException(e);
86 | }
87 | }
88 |
89 | @Override
90 | public boolean keepOnReload() {
91 | // BlockLocker will re-add the group system
92 | return false;
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/mcMMOGroupSystem.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.group;
2 |
3 | import java.util.Objects;
4 |
5 | import org.bukkit.entity.Player;
6 | import org.bukkit.plugin.java.JavaPlugin;
7 |
8 | import com.gmail.nossr50.mcMMO;
9 | import com.gmail.nossr50.api.PartyAPI;
10 |
11 | import nl.rutgerkok.blocklocker.group.GroupSystem;
12 |
13 | /**
14 | * Group system hooking into the mcMMO plugin.
15 | *
16 | */
17 |
18 | public final class mcMMOGroupSystem extends GroupSystem {
19 |
20 | /**
21 | * Tests if the mcMMO plugin is installed.
22 | *
23 | * @return True if the mcMMO plugin is installed, false otherwise.
24 | */
25 | public static boolean isAvailable() {
26 | try {
27 | JavaPlugin.getProvidingPlugin(mcMMO.class);
28 | return true;
29 | } catch (NoClassDefFoundError e) {
30 | return false;
31 | }
32 | }
33 |
34 | @Override
35 | public boolean isGroupLeader(Player player, String groupName) {
36 | if (!isInGroup(player, groupName)) {
37 | return false;
38 | }
39 |
40 | String leader = PartyAPI.getPartyLeader(groupName);
41 |
42 | return Objects.equals(player.getName(), leader) ? true : false;
43 | }
44 |
45 | @Override
46 | public boolean isInGroup(Player player, String groupName) {
47 | if (!PartyAPI.inParty(player)) {
48 | // Player is not in a party
49 | return false;
50 | }
51 |
52 | String partyName = PartyAPI.getPartyName(player);
53 |
54 | // Ignore case, mcMMO is not case sensitive
55 | return partyName.equalsIgnoreCase(groupName);
56 | }
57 |
58 | @Override
59 | public boolean keepOnReload() {
60 | // BlockLocker will re-add the group system
61 | return false;
62 | }
63 |
64 | }
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/group/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Implementations of group systems.
3 | */
4 | package nl.rutgerkok.blocklocker.impl.group;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/location/TownyLocationChecker.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.location;
2 |
3 | import org.bukkit.block.Block;
4 | import org.bukkit.entity.Player;
5 | import org.bukkit.plugin.java.JavaPlugin;
6 |
7 | import com.palmergames.bukkit.towny.Towny;
8 | import com.palmergames.bukkit.towny.TownyAPI;
9 |
10 | import nl.rutgerkok.blocklocker.Translator.Translation;
11 | import nl.rutgerkok.blocklocker.location.IllegalLocationException;
12 | import nl.rutgerkok.blocklocker.location.LocationChecker;
13 |
14 | public final class TownyLocationChecker implements LocationChecker {
15 |
16 | /**
17 | * Tests if the Towny plugin is installed.
18 | *
19 | * @return True if the factions plugin is installed, false otherwise.
20 | */
21 | public static boolean isAvailable() {
22 | try {
23 | JavaPlugin.getProvidingPlugin(Towny.class);
24 | return true;
25 | } catch (NoClassDefFoundError e) {
26 | return false;
27 | }
28 | }
29 |
30 | @Override
31 | public void checkLocation(Player player, Block block) throws IllegalLocationException {
32 | if (TownyAPI.getInstance().isWilderness(block)) {
33 | throw new IllegalLocationException(Translation.PROTECTION_IN_WILDERNESS);
34 | }
35 | }
36 |
37 | @Override
38 | public boolean keepOnReload() {
39 | return false; // built-in, so it will be re-added on reload
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Internal classes, can change without warning.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.impl;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/EveryoneProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 |
5 | import org.apache.commons.lang.Validate;
6 |
7 | import nl.rutgerkok.blocklocker.SecretSignEntry;
8 | import nl.rutgerkok.blocklocker.profile.Profile;
9 |
10 | class EveryoneProfileImpl implements Profile {
11 |
12 | static final String EVERYONE_KEY = "e";
13 |
14 | private final String tag;
15 |
16 | /**
17 | * Creates a new [Everyone]-profile.
18 | *
19 | * @param translation
20 | * Usually "Everyone", may be localized.
21 | */
22 | EveryoneProfileImpl(String translation) {
23 | this.tag = translation;
24 | }
25 |
26 | /**
27 | * All instances of this object are equal.
28 | */
29 | @Override
30 | public boolean equals(Object other) {
31 | if (other == null) {
32 | return false;
33 | }
34 | if (other == this) {
35 | return true;
36 | }
37 | return getClass() == other.getClass();
38 | }
39 |
40 | @Override
41 | public String getDisplayName() {
42 | return '[' + tag + ']';
43 | }
44 |
45 | @Override
46 | public void getSaveObject(SecretSignEntry entry) {
47 | entry.setBoolean(EVERYONE_KEY, true);
48 | }
49 |
50 | /**
51 | * All instances of this object are equal.
52 | */
53 | @Override
54 | public int hashCode() {
55 | return 4;
56 | }
57 |
58 | @Override
59 | public boolean includes(Profile other) {
60 | Validate.notNull(other);
61 | return true;
62 | }
63 |
64 | @Override
65 | public boolean isExpired(Date cutoffDate) {
66 | // The [Everyone] profile never expires
67 | return false;
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return getClass().getSimpleName();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/GolemProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import com.google.common.base.Preconditions;
4 | import nl.rutgerkok.blocklocker.SecretSignEntry;
5 | import nl.rutgerkok.blocklocker.profile.Profile;
6 |
7 | import java.util.Date;
8 |
9 | class GolemProfileImpl implements Profile {
10 |
11 | static final String GOLEM_KEY = "go";
12 |
13 | private final String translatedTag;
14 |
15 | /**
16 | * Creates a new [Golem]-profile.
17 | *
18 | * @param translatedTag
19 | * Usually "Golem", may be localized.
20 | */
21 | GolemProfileImpl(String translatedTag) {
22 | this.translatedTag = translatedTag;
23 | }
24 |
25 | /**
26 | * All instances of this object are equal.
27 | */
28 | @Override
29 | public boolean equals(Object other) {
30 | if (other == null) {
31 | return false;
32 | }
33 | if (other == this) {
34 | return true;
35 | }
36 | return getClass() == other.getClass();
37 | }
38 |
39 | @Override
40 | public String getDisplayName() {
41 | return '[' + translatedTag + ']';
42 | }
43 |
44 | @Override
45 | public void getSaveObject(SecretSignEntry entry) {
46 | entry.setBoolean(GOLEM_KEY, true);
47 | }
48 |
49 | /**
50 | * All instances of this object are equal.
51 | */
52 | @Override
53 | public int hashCode() {
54 | return 4000;
55 | }
56 |
57 | @Override
58 | public boolean includes(Profile other) {
59 | Preconditions.checkNotNull(other);
60 | return other instanceof GolemProfileImpl;
61 | }
62 |
63 | @Override
64 | public boolean isExpired(Date cutoffDate) {
65 | // These never expire
66 | return false;
67 | }
68 |
69 | @Override
70 | public String toString() {
71 | return getClass().getSimpleName();
72 | }
73 |
74 | }
75 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/GroupLeaderProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 | import java.util.Locale;
5 | import java.util.Optional;
6 | import java.util.UUID;
7 |
8 | import org.bukkit.Bukkit;
9 | import org.bukkit.entity.Player;
10 |
11 | import com.google.common.base.Preconditions;
12 |
13 | import nl.rutgerkok.blocklocker.SecretSignEntry;
14 | import nl.rutgerkok.blocklocker.group.GroupSystem;
15 | import nl.rutgerkok.blocklocker.profile.PlayerProfile;
16 | import nl.rutgerkok.blocklocker.profile.Profile;
17 |
18 | /**
19 | * Implementation of {@link Profile}. Players are considered part of a group
20 | * when the {@link GroupSystem#isGroupLeader(Player, String)} method returns
21 | * true.
22 | *
23 | */
24 | class GroupLeaderProfileImpl implements Profile {
25 |
26 | static final String GROUP_LEADER_KEY = "l";
27 | private String groupName;
28 | private final GroupSystem groupSystem;
29 |
30 | GroupLeaderProfileImpl(GroupSystem groupSystem, String groupName) {
31 | this.groupSystem = Preconditions.checkNotNull(groupSystem);
32 | this.groupName = Preconditions.checkNotNull(groupName);
33 | }
34 |
35 | @Override
36 | public boolean equals(Object other) {
37 | if (other == null) {
38 | return false;
39 | }
40 | if (other == this) {
41 | return true;
42 | }
43 | if (getClass() != other.getClass()) {
44 | return false;
45 | }
46 |
47 | GroupLeaderProfileImpl otherProfile = (GroupLeaderProfileImpl) other;
48 | return groupName.equalsIgnoreCase(otherProfile.groupName);
49 | }
50 |
51 | @Override
52 | public String getDisplayName() {
53 | return "+" + groupName + "+";
54 | }
55 |
56 | @Override
57 | public void getSaveObject(SecretSignEntry entry) {
58 | entry.setString(GROUP_LEADER_KEY, groupName);
59 | }
60 |
61 | @Override
62 | public int hashCode() {
63 | // Bits are inverted to avoid hash code collision with {@link
64 | // GroupSystem}.
65 | return ~groupName.toLowerCase(Locale.ROOT).hashCode();
66 | }
67 |
68 | @Override
69 | public boolean includes(Profile other) {
70 | if (!(other instanceof PlayerProfile)) {
71 | return false;
72 | }
73 |
74 | PlayerProfile playerProfile = (PlayerProfile) other;
75 | Optional uuid = playerProfile.getUniqueId();
76 | if (!uuid.isPresent()) {
77 | return false;
78 | }
79 |
80 | Player player = Bukkit.getPlayer(uuid.get());
81 | if (player == null) {
82 | return false;
83 | }
84 |
85 | return groupSystem.isGroupLeader(player, groupName);
86 | }
87 |
88 | @Override
89 | public boolean isExpired(Date cutoffDate) {
90 | // Group leader profiles never expire
91 | return false;
92 | }
93 |
94 | @Override
95 | public String toString() {
96 | return getClass().getSimpleName() + "[name=" + groupName + "]";
97 | }
98 |
99 | }
100 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/GroupProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 | import java.util.Locale;
5 | import java.util.Optional;
6 | import java.util.UUID;
7 |
8 | import org.bukkit.Bukkit;
9 | import org.bukkit.entity.Player;
10 |
11 | import com.google.common.base.Preconditions;
12 |
13 | import nl.rutgerkok.blocklocker.SecretSignEntry;
14 | import nl.rutgerkok.blocklocker.group.GroupSystem;
15 | import nl.rutgerkok.blocklocker.profile.GroupProfile;
16 | import nl.rutgerkok.blocklocker.profile.PlayerProfile;
17 | import nl.rutgerkok.blocklocker.profile.Profile;
18 |
19 | /**
20 | * Implementation of {@link GroupProfile}. Players are considered part of a
21 | * group when the name of their scoreboard team matches this group, or when they
22 | * have the permission node for this group.
23 | *
24 | */
25 | class GroupProfileImpl implements GroupProfile {
26 |
27 | static final String GROUP_KEY = "g";
28 | private String groupName;
29 | private final GroupSystem groupSystem;
30 |
31 | GroupProfileImpl(GroupSystem groupSystem, String groupName) {
32 | this.groupSystem = Preconditions.checkNotNull(groupSystem);
33 | this.groupName = Preconditions.checkNotNull(groupName);
34 | }
35 |
36 | /**
37 | * We compare uuids or names. Objects are equal if the uuids are present in
38 | * both objects and are equal, or if the uuids are present in neither
39 | * objects and are not equal.
40 | */
41 | @Override
42 | public boolean equals(Object other) {
43 | if (other == null) {
44 | return false;
45 | }
46 | if (other == this) {
47 | return true;
48 | }
49 | if (getClass() != other.getClass()) {
50 | return false;
51 | }
52 |
53 | GroupProfileImpl otherProfile = (GroupProfileImpl) other;
54 | return groupName.equalsIgnoreCase(otherProfile.groupName);
55 | }
56 |
57 | @Override
58 | public String getDisplayName() {
59 | return "[" + groupName + "]";
60 | }
61 |
62 | @Override
63 | public void getSaveObject(SecretSignEntry entry) {
64 | entry.setString(GROUP_KEY, groupName);
65 | }
66 |
67 | @Override
68 | public int hashCode() {
69 | return groupName.toLowerCase(Locale.ROOT).hashCode();
70 | }
71 |
72 | @Override
73 | public boolean includes(Profile other) {
74 | if (!(other instanceof PlayerProfile)) {
75 | return false;
76 | }
77 |
78 | PlayerProfile playerProfile = (PlayerProfile) other;
79 | Optional uuid = playerProfile.getUniqueId();
80 | if (!uuid.isPresent()) {
81 | return false;
82 | }
83 |
84 | Player player = Bukkit.getPlayer(uuid.get());
85 | if (player == null) {
86 | return false;
87 | }
88 |
89 | return groupSystem.isInGroup(player, groupName);
90 | }
91 |
92 | @Override
93 | public boolean isExpired(Date cutoffDate) {
94 | // Group profiles never expire
95 | return false;
96 | }
97 |
98 | @Override
99 | public String toString() {
100 | return getClass().getSimpleName() + "[name=" + groupName + "]";
101 | }
102 |
103 | }
104 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/PlayerProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 | import java.util.Locale;
5 | import java.util.Optional;
6 | import java.util.UUID;
7 |
8 | import org.bukkit.Bukkit;
9 | import org.bukkit.OfflinePlayer;
10 |
11 | import nl.rutgerkok.blocklocker.SecretSignEntry;
12 | import nl.rutgerkok.blocklocker.profile.PlayerProfile;
13 | import nl.rutgerkok.blocklocker.profile.Profile;
14 |
15 | class PlayerProfileImpl implements PlayerProfile {
16 |
17 | static final String NAME_KEY = "n";
18 | static final String UUID_KEY = "u";
19 | private String displayName;
20 | private final Optional uuid;
21 |
22 | PlayerProfileImpl(String displayName, Optional uuid) {
23 | this.displayName = displayName;
24 | this.uuid = uuid;
25 | }
26 |
27 | /**
28 | * We compare uuids or names. Objects are equal if the uuids are present in
29 | * both objects and are equal, or if the uuids are present in neither
30 | * objects and are not equal.
31 | */
32 | @Override
33 | public boolean equals(Object other) {
34 | if (other == null) {
35 | return false;
36 | }
37 | if (other == this) {
38 | return true;
39 | }
40 | if (getClass() != other.getClass()) {
41 | return false;
42 | }
43 |
44 | PlayerProfileImpl otherProfile = (PlayerProfileImpl) other;
45 | if (uuid.isPresent() != otherProfile.uuid.isPresent()) {
46 | return false;
47 | }
48 |
49 | if (uuid.isPresent()) {
50 | return uuid.equals(otherProfile.uuid);
51 | } else {
52 | return displayName.equals(otherProfile.displayName);
53 | }
54 | }
55 |
56 | @Override
57 | public String getDisplayName() {
58 | return displayName;
59 | }
60 |
61 | @Override
62 | public void getSaveObject(SecretSignEntry entry) {
63 | entry.setString(NAME_KEY, displayName);
64 | if (uuid.isPresent()) {
65 | entry.setUniqueId(UUID_KEY, uuid.get());
66 | }
67 | }
68 |
69 | @Override
70 | public Optional getUniqueId() {
71 | return uuid;
72 | }
73 |
74 | @Override
75 | public int hashCode() {
76 | if (uuid.isPresent()) {
77 | return uuid.hashCode();
78 | }
79 | return displayName.toLowerCase(Locale.ROOT).hashCode();
80 | }
81 |
82 | @Override
83 | public boolean includes(Profile other) {
84 | if (!(other instanceof PlayerProfile)) {
85 | return false;
86 | }
87 |
88 | PlayerProfile otherProfile = (PlayerProfile) other;
89 | if (uuid.isPresent()) {
90 | return uuid.equals(otherProfile.getUniqueId());
91 | }
92 | return displayName.equalsIgnoreCase(otherProfile.getDisplayName());
93 | }
94 |
95 | @Override
96 | public boolean isExpired(Date cutoffDate) {
97 |
98 |
99 | if (uuid.isPresent()) {
100 | OfflinePlayer player = Bukkit.getOfflinePlayer(uuid.get());
101 |
102 | if (player.isOnline()) {
103 | return false;
104 | }
105 | if (player.getLastPlayed() > cutoffDate.getTime()) {
106 | return false;
107 | }
108 |
109 | // We know for sure: expired
110 | return true;
111 | }
112 |
113 | // No UUID, so unable to lookup last login
114 | return false;
115 | }
116 |
117 | @Override
118 | public String toString() {
119 | return getClass().getSimpleName() + "[uuid=" + uuid.orElse(null) + ",name=" + displayName + "]";
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/RedstoneProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 |
5 | import com.google.common.base.Preconditions;
6 |
7 | import nl.rutgerkok.blocklocker.SecretSignEntry;
8 | import nl.rutgerkok.blocklocker.profile.Profile;
9 |
10 | class RedstoneProfileImpl implements Profile {
11 |
12 | static final String REDSTONE_KEY = "r";
13 |
14 | private final String translatedTag;
15 |
16 | /**
17 | * Creates a new [Redstone]-profile.
18 | *
19 | * @param translatedTag
20 | * Usually "Redstone", may be localized.
21 | */
22 | RedstoneProfileImpl(String translatedTag) {
23 | this.translatedTag = translatedTag;
24 | }
25 |
26 | /**
27 | * All instances of this object are equal.
28 | */
29 | @Override
30 | public boolean equals(Object other) {
31 | if (other == null) {
32 | return false;
33 | }
34 | if (other == this) {
35 | return true;
36 | }
37 | return getClass() == other.getClass();
38 | }
39 |
40 | @Override
41 | public String getDisplayName() {
42 | return '[' + translatedTag + ']';
43 | }
44 |
45 | @Override
46 | public void getSaveObject(SecretSignEntry entry) {
47 | entry.setBoolean(REDSTONE_KEY, true);
48 | }
49 |
50 | /**
51 | * All instances of this object are equal.
52 | */
53 | @Override
54 | public int hashCode() {
55 | return 4;
56 | }
57 |
58 | @Override
59 | public boolean includes(Profile other) {
60 | Preconditions.checkNotNull(other);
61 | return other instanceof RedstoneProfileImpl;
62 | }
63 |
64 | @Override
65 | public boolean isExpired(Date cutoffDate) {
66 | // These never expire
67 | return false;
68 | }
69 |
70 | @Override
71 | public String toString() {
72 | return getClass().getSimpleName();
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/TimerProfileImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import java.util.Date;
4 |
5 | import nl.rutgerkok.blocklocker.SecretSignEntry;
6 | import nl.rutgerkok.blocklocker.profile.Profile;
7 | import nl.rutgerkok.blocklocker.profile.TimerProfile;
8 |
9 | class TimerProfileImpl implements TimerProfile {
10 |
11 | static final String TIME_KEY = "t";
12 |
13 | private final int seconds;
14 | private final String timerTag;
15 |
16 | TimerProfileImpl(String timerTag, int secondsOpen) {
17 | this.timerTag = timerTag;
18 |
19 | if (secondsOpen < 1) {
20 | secondsOpen = 1;
21 | } else if (secondsOpen > 9) {
22 | secondsOpen = 9;
23 | }
24 |
25 | this.seconds = secondsOpen;
26 | }
27 |
28 | @Override
29 | public String getDisplayName() {
30 | return "[" + timerTag + ":" + seconds + "]";
31 | }
32 |
33 | @Override
34 | public int getOpenSeconds() {
35 | return seconds;
36 | }
37 |
38 | @Override
39 | public void getSaveObject(SecretSignEntry entry) {
40 | entry.setInteger(TIME_KEY, seconds);
41 | }
42 |
43 | @Override
44 | public boolean includes(Profile other) {
45 | // Includes nobody
46 | return false;
47 | }
48 |
49 | @Override
50 | public boolean isExpired(Date cutoffDate) {
51 | // These never expire
52 | return false;
53 | }
54 |
55 | }
56 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/profile/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Implementations of profile classes.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.impl.profile;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/protection/AttachedProtectionImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.protection;
2 |
3 | import java.util.Arrays;
4 | import java.util.Collection;
5 |
6 | import org.bukkit.Sound;
7 | import org.bukkit.block.Block;
8 | import org.bukkit.block.data.BlockData;
9 | import org.bukkit.block.data.Openable;
10 |
11 | import nl.rutgerkok.blocklocker.OpenBlockSound;
12 | import nl.rutgerkok.blocklocker.ProtectionSign;
13 | import nl.rutgerkok.blocklocker.impl.blockfinder.BlockFinder;
14 | import nl.rutgerkok.blocklocker.protection.AttachedProtection;
15 | import nl.rutgerkok.blocklocker.protection.Protection;
16 |
17 | /**
18 | * Implementation of {@link AttachedProtection}.
19 | *
20 | */
21 | public final class AttachedProtectionImpl extends AbstractProtection implements AttachedProtection {
22 |
23 | /**
24 | * Gets a door protection from a door, with only a single sign looked up.
25 | *
26 | * @param sign
27 | * A hint. If it is a main sign, the owner can easily be looked
28 | * up, speeding up {@link #getOwner()}.
29 | * @param blockFinder
30 | * The block finder.
31 | * @param protectionBlock
32 | * The door.
33 | *
34 | * @return The door protection object.
35 | */
36 | public static Protection fromBlockWithSign(ProtectionSign sign, BlockFinder blockFinder, Block protectionBlock) {
37 | return new AttachedProtectionImpl(sign, blockFinder, protectionBlock);
38 | }
39 |
40 | /**
41 | * Creates a new protection for a door, with all signs looked up.
42 | *
43 | * @param signs
44 | * All signs of the protection. Collection may not be empty.
45 | * @param blockFinder
46 | * The block finder.
47 | * @param trapDoor
48 | * The door that is protected.
49 | * @return The protection.
50 | */
51 | public static Protection fromBlockWithSigns(Collection signs, BlockFinder blockFinder, Block trapDoor) {
52 | return new AttachedProtectionImpl(signs, blockFinder, trapDoor);
53 | }
54 |
55 | private static void setBlockOpen(Block block, boolean open) {
56 | BlockData blockData = block.getBlockData();
57 | if (!isFunctionalOpenable(blockData)) {
58 | return;
59 | }
60 | Openable openable = (Openable) blockData;
61 |
62 | if (openable.isOpen() == open) {
63 | return;
64 | }
65 |
66 | openable.setOpen(open);
67 | block.setBlockData(blockData);
68 | }
69 | private final BlockFinder blockFinder;
70 |
71 | private final Block protectionBlock;
72 |
73 | private AttachedProtectionImpl(Collection signs, BlockFinder blockFinder, Block trapDoor) {
74 | super(signs);
75 | this.protectionBlock = trapDoor;
76 | this.blockFinder = blockFinder;
77 | }
78 |
79 | private AttachedProtectionImpl(ProtectionSign sign, BlockFinder blockFinder, Block trapDoor) {
80 | super(sign);
81 | this.protectionBlock = trapDoor;
82 | this.blockFinder = blockFinder;
83 | }
84 |
85 | @Override
86 | public boolean canBeOpened() {
87 | return isFunctionalOpenable(protectionBlock.getBlockData());
88 | }
89 |
90 | @Override
91 | protected Collection fetchSigns() {
92 | Block supportingBlock = blockFinder.findSupportingBlock(protectionBlock);
93 | return blockFinder.findAttachedSigns(Arrays.asList(protectionBlock, supportingBlock));
94 | }
95 |
96 | @Override
97 | public Block getSomeProtectedBlock() {
98 | return protectionBlock;
99 | }
100 |
101 | @Override
102 | public boolean isOpen() {
103 | BlockData materialData = protectionBlock.getBlockData();
104 | if (isFunctionalOpenable(materialData)) {
105 | return ((Openable) materialData).isOpen();
106 | }
107 | return false;
108 | }
109 |
110 | @Override
111 | public void setOpen(boolean open, SoundCondition playSound) {
112 | setBlockOpen(protectionBlock, open);
113 | Block supportingBlock = blockFinder.findSupportingBlock(protectionBlock);
114 | setBlockOpen(supportingBlock, open);
115 |
116 | if (playSound == SoundCondition.ALWAYS && isOpen() != open) {
117 | Sound sound = OpenBlockSound.get(protectionBlock.getType(), open);
118 | protectionBlock.getWorld().playSound(protectionBlock.getLocation(), sound, 1f, 0.7f);
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/protection/ContainerProtectionImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.protection;
2 |
3 | import java.util.Collection;
4 | import java.util.List;
5 |
6 | import org.bukkit.Sound;
7 | import org.bukkit.block.Block;
8 | import org.bukkit.block.data.BlockData;
9 | import org.bukkit.block.data.Openable;
10 |
11 | import nl.rutgerkok.blocklocker.OpenBlockSound;
12 | import nl.rutgerkok.blocklocker.ProtectionSign;
13 | import nl.rutgerkok.blocklocker.impl.blockfinder.BlockFinder;
14 | import nl.rutgerkok.blocklocker.protection.ContainerProtection;
15 | import nl.rutgerkok.blocklocker.protection.Protection;
16 |
17 | public final class ContainerProtectionImpl extends AbstractProtection implements ContainerProtection {
18 |
19 | /**
20 | * Creates a new protection for the protection block. Calling this method
21 | * might make for a faster {@link #getOwner()}, as it can read the owner
22 | * from the sign if it is a main sign.
23 | *
24 | * @param sign
25 | * The sign. If it is a main sign it is used for
26 | * {@link #getOwner()}.
27 | * @param blockFinder
28 | * The sign finder.
29 | * @param blocks
30 | * The block that are protected. (Usually one block, multiple for
31 | * double chests.)
32 | *
33 | * @return The protection.
34 | */
35 | public static Protection fromBlocksWithSign(ProtectionSign sign,
36 | Collection blocks, BlockFinder blockFinder) {
37 | return new ContainerProtectionImpl(sign, blocks, blockFinder);
38 | }
39 |
40 | /**
41 | * Creates a new protection for the protection block. Calling this method
42 | * will make for a faster {@link #getAllowed()} and {@link #getOwner()}
43 | *
44 | * @param signs
45 | * All signs in the protection. Collection may not be empty.
46 | * @param blocks
47 | * The blocks that are protected. (Usually one block, multiple
48 | * for double chests.)
49 | * @param blockFinder
50 | * The sign finder.
51 | *
52 | * @return The protection.
53 | */
54 | public static Protection fromBlocksWithSigns(Collection signs,
55 | List blocks, BlockFinder blockFinder) {
56 | return new ContainerProtectionImpl(signs, blocks, blockFinder);
57 | }
58 |
59 | private final BlockFinder blockFinder;
60 | private final Collection blocks;
61 |
62 | private ContainerProtectionImpl(Collection allSigns, Collection blocks, BlockFinder blockFinder) {
63 | super(allSigns);
64 | this.blocks = blocks;
65 | this.blockFinder = blockFinder;
66 | }
67 |
68 | private ContainerProtectionImpl(ProtectionSign mainSign, Collection blocks, BlockFinder blockFinder) {
69 | super(mainSign);
70 | this.blocks = blocks;
71 | this.blockFinder = blockFinder;
72 |
73 | if (this.blocks.isEmpty()) {
74 | throw new IllegalArgumentException("Blocks list is empty");
75 | }
76 | }
77 |
78 | @Override
79 | public boolean canBeOpened() {
80 | for (Block block : blocks) {
81 | if (isFunctionalOpenable(block.getBlockData())) {
82 | return true;
83 | }
84 | // Only try first block, as all blocks should be of the same type
85 | return false;
86 | }
87 | return false;
88 | }
89 |
90 | @Override
91 | protected Collection fetchSigns() {
92 | return blockFinder.findAttachedSigns(blocks);
93 | }
94 |
95 | @Override
96 | public Block getSomeProtectedBlock() {
97 | for (Block block : this.blocks) {
98 | return block;
99 | }
100 | throw new AssertionError("Block list was empty, this should have been checked in the constructor");
101 | }
102 |
103 | @Override
104 | public boolean isOpen() {
105 | for (Block block : blocks) {
106 | BlockData materialData = block.getBlockData();
107 | if (isFunctionalOpenable(materialData)) {
108 | return ((Openable) materialData).isOpen();
109 | }
110 | }
111 | return false;
112 | }
113 |
114 | private boolean setBlockOpen(Block block, boolean open) {
115 | BlockData materialData = block.getBlockData();
116 | if (!isFunctionalOpenable(materialData)) {
117 | return false;
118 | }
119 |
120 | Openable openable = (Openable) materialData;
121 | if (openable.isOpen() == open) {
122 | return false;
123 | }
124 |
125 | // Change the state
126 | openable.setOpen(open);
127 | block.setBlockData(materialData);
128 | return true;
129 | }
130 |
131 | @Override
132 | public void setOpen(boolean open, SoundCondition playSound) {
133 | boolean changed = false;
134 | Block aBlock = null;
135 | for (Block block : blocks) {
136 | changed |= setBlockOpen(block, open);
137 | aBlock = block;
138 | }
139 | if (aBlock == null) {
140 | return;
141 | }
142 |
143 | if (changed && playSound == SoundCondition.ALWAYS) {
144 | Sound sound = OpenBlockSound.get(aBlock.getType(), open);
145 | aBlock.getWorld().playSound(aBlock.getLocation(), sound, 1, 0.7f);
146 | }
147 | }
148 |
149 | }
150 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/protection/DoorProtectionImpl.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.protection;
2 |
3 | import java.util.Collection;
4 |
5 | import org.bukkit.block.Block;
6 |
7 | import nl.rutgerkok.blocklocker.ProtectionSign;
8 | import nl.rutgerkok.blocklocker.impl.CompleteDoor;
9 | import nl.rutgerkok.blocklocker.impl.blockfinder.BlockFinder;
10 | import nl.rutgerkok.blocklocker.protection.DoorProtection;
11 | import nl.rutgerkok.blocklocker.protection.Protection;
12 |
13 | /**
14 | * Implementation of {@link DoorProtection}.
15 | *
16 | */
17 | public final class DoorProtectionImpl extends AbstractProtection implements DoorProtection {
18 |
19 | /**
20 | * Gets a door protection from a door, with only a single sign looked up.
21 | *
22 | * @param sign
23 | * A hint. If it is a main sign, the owner can easily be looked
24 | * up, speeding up {@link #getOwner()}.
25 | * @param blockFinder
26 | * The block finder.
27 | * @param door
28 | * The door.
29 | *
30 | * @return The door protection object.
31 | */
32 | public static Protection fromDoorWithSign(ProtectionSign sign, BlockFinder blockFinder, CompleteDoor door) {
33 | return new DoorProtectionImpl(sign, blockFinder, door);
34 | }
35 |
36 | /**
37 | * Creates a new protection for a door, with all signs looked up.
38 | *
39 | * @param signs
40 | * All signs of the protection. Collection may not be empty.
41 | * @param blockFinder
42 | * The block finder.
43 | * @param door
44 | * The door that is protected.
45 | * @return The protection.
46 | */
47 | public static Protection fromDoorWithSigns(Collection signs, BlockFinder blockFinder, CompleteDoor door) {
48 | return new DoorProtectionImpl(signs, blockFinder, door);
49 | }
50 |
51 | private final BlockFinder blockFinder;
52 | private final CompleteDoor door;
53 |
54 | private DoorProtectionImpl(Collection signs, BlockFinder blockFinder, CompleteDoor door) {
55 | super(signs);
56 | this.door = door;
57 | this.blockFinder = blockFinder;
58 | }
59 |
60 | private DoorProtectionImpl(ProtectionSign sign, BlockFinder blockFinder, CompleteDoor door) {
61 | super(sign);
62 | this.door = door;
63 | this.blockFinder = blockFinder;
64 | }
65 |
66 | @Override
67 | public boolean canBeOpened() {
68 | return true;
69 | }
70 |
71 | @Override
72 | protected Collection fetchSigns() {
73 | return blockFinder.findAttachedSigns(door.getBlocksForSigns());
74 | }
75 |
76 | @Override
77 | public Block getSomeProtectedBlock() {
78 | return this.door.getSomeDoorBlock();
79 | }
80 |
81 | @Override
82 | public boolean isOpen() {
83 | return door.isOpen();
84 | }
85 |
86 | @Override
87 | public void setOpen(boolean open, SoundCondition playSound) {
88 | door.setOpen(open, playSound);
89 | }
90 |
91 | }
92 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/protection/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Implementation for the protection classes.
3 | */
4 | package nl.rutgerkok.blocklocker.impl.protection;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/UpdateChecker.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.io.InputStreamReader;
6 | import java.net.HttpURLConnection;
7 | import java.net.URL;
8 | import java.net.URLEncoder;
9 |
10 | import org.bukkit.plugin.Plugin;
11 |
12 | import com.google.common.base.Charsets;
13 | import com.google.gson.JsonObject;
14 | import com.google.gson.JsonParser;
15 |
16 | /**
17 | * Checks whether an update is available.
18 | *
19 | */
20 | final class UpdateChecker {
21 |
22 | private static final String UPDATE_URL = "https://rutgerkok.nl/tools/updater/blocklocker.php";
23 |
24 | /**
25 | * Checks online for updates. Blocking method.
26 | *
27 | * @param plugin
28 | * Plugin to check for.
29 | * @return The update result.
30 | * @throws IOException
31 | * If an IO error occurs.
32 | */
33 | public UpdateCheckResult checkForUpdatesSync(Plugin plugin) throws IOException {
34 | String currentVersionEncoded = URLEncoder.encode(plugin.getDescription().getVersion(), "UTF-8");
35 | URL url = new URL(UPDATE_URL + "?version=" + currentVersionEncoded);
36 | HttpURLConnection connection = (HttpURLConnection) url.openConnection();
37 | connection.setRequestMethod("GET");
38 | connection.setRequestProperty("Content-Type", "application/json");
39 | UserAgent.setFor(plugin, connection);
40 |
41 | try (InputStream stream = connection.getInputStream()) {
42 | JsonObject object = JsonParser.parseReader(new InputStreamReader(stream, Charsets.UTF_8)).getAsJsonObject();
43 | return new UpdateCheckResult(object);
44 | } catch (IOException e) {
45 | // Just rethrow, don't wrap
46 | throw e;
47 | } catch (Exception e) {
48 | throw new IOException(e);
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/UpdateNotifier.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.net.URL;
4 | import java.util.Optional;
5 | import java.util.Set;
6 |
7 | import com.google.common.base.Joiner;
8 | import com.google.common.base.Preconditions;
9 |
10 | import org.bukkit.command.CommandSender;
11 | import org.bukkit.entity.Player;
12 | import org.bukkit.event.EventHandler;
13 | import org.bukkit.event.EventPriority;
14 | import org.bukkit.event.Listener;
15 | import org.bukkit.event.player.PlayerJoinEvent;
16 |
17 | import nl.rutgerkok.blocklocker.Permissions;
18 | import nl.rutgerkok.blocklocker.Translator;
19 | import nl.rutgerkok.blocklocker.Translator.Translation;
20 |
21 | /**
22 | * Used to notify people that an update of the plugin is out.
23 | *
24 | *
25 | * When registered as a listener, the notification will be send to all admins
26 | * that are logging in.
27 | */
28 | final class UpdateNotifier implements Listener {
29 |
30 | private final UpdateResult result;
31 | private final Translator translator;
32 |
33 | public UpdateNotifier(Translator translator, UpdateResult result) {
34 | this.result = Preconditions.checkNotNull(result);
35 | this.translator = Preconditions.checkNotNull(translator);
36 |
37 | Preconditions.checkArgument(result.hasNotification(), "result must have a notification");
38 |
39 | }
40 |
41 | @EventHandler(priority = EventPriority.HIGH)
42 | public void onPlayerJoin(PlayerJoinEvent event) {
43 | Player player = event.getPlayer();
44 | if (player.hasPermission(Permissions.CAN_BYPASS)) {
45 | sendNotification(player);
46 | }
47 | }
48 |
49 | /**
50 | * Sends a notification to the given person.
51 | *
52 | * @param sender
53 | * The person to send to.
54 | */
55 | void sendNotification(CommandSender sender) {
56 | UpdateCheckResult checkResult = result.getUpdateCheckResult();
57 | String newVersion = checkResult.getLatestVersion().orElse("?");
58 |
59 | // Show status
60 | switch (result.getStatus()) {
61 | case MANUAL_UPDATE:
62 | translator.sendMessage(sender, Translation.UPDATER_UPDATE_AVAILABLE, newVersion);
63 | break;
64 | case UNSUPPORTED_SERVER:
65 | Set mcVersions = result.getUpdateCheckResult().getMinecraftVersions();
66 | String mcVersionsString = Joiner.on(", ").join(mcVersions);
67 | translator.sendMessage(sender, Translation.UPDATER_UNSUPPORTED_SERVER, newVersion, mcVersionsString);
68 | break;
69 | default:
70 | throw new AssertionError("Umhandled case: " + result.getStatus());
71 | }
72 |
73 | // More information
74 | Optional infoUrl = checkResult.getInfoUrl();
75 | if (infoUrl.isPresent()) {
76 | translator.sendMessage(sender, Translation.UPDATER_MORE_INFORMATION, infoUrl.get().toString());
77 | }
78 | }
79 |
80 | }
81 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/UpdatePreference.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.util.Locale;
4 | import java.util.Optional;
5 |
6 | /**
7 | * The preference the user set for auto updating.
8 | *
9 | */
10 | public enum UpdatePreference {
11 | /**
12 | * Automatically check for and install updates.
13 | */
14 | AUTO_INSTALL,
15 | /**
16 | * Don't check for updates, don't install updates.
17 | */
18 | DISABLED,
19 | /**
20 | * Check for updates, do nothing else
21 | */
22 | JUST_NOTIFY;
23 |
24 | /**
25 | * Parses the update preference from the string. The string is
26 | * {@link String#trim() trimmed}, uppercased and spaces are replaced with
27 | * underscores. Then {@link #valueOf(String)} is called, and the result is
28 | * returned as an {@link Optional}.
29 | *
30 | * @param string
31 | * String to parse.
32 | * @return The update preference, or absent if parsing failed.
33 | */
34 | public static Optional parse(String string) {
35 | string = string.trim().toUpperCase(Locale.ROOT).replace(' ', '_');
36 | try {
37 | return Optional.of(valueOf(string));
38 | } catch (IllegalArgumentException e) {
39 | return Optional.empty();
40 | }
41 | }
42 |
43 | /**
44 | * Gets whether the plugin should check for new updates.
45 | *
46 | * @return True if the plugin should check for updates, false otherwise.
47 | */
48 | public boolean checkForUpdates() {
49 | return this == AUTO_INSTALL || this == JUST_NOTIFY;
50 | }
51 |
52 | /**
53 | * Gets whether updates should be downloaded and installed automatically.
54 | *
55 | * @return True if updates should be downloaded and installed automatically,
56 | * false otherwise.
57 | */
58 | public boolean installUpdates() {
59 | return this == AUTO_INSTALL;
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/UpdateResult.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.io.IOException;
4 |
5 | import com.google.common.base.Preconditions;
6 | import com.google.gson.JsonObject;
7 |
8 | /**
9 | * Result of an update attempt.
10 | *
11 | * @see Updater
12 | *
13 | */
14 | final class UpdateResult {
15 |
16 | enum Status {
17 | NO_UPDATE,
18 | MANUAL_UPDATE,
19 | CHECK_FAILED,
20 | UNSUPPORTED_SERVER;
21 |
22 | public boolean hasNotification() {
23 | return this == MANUAL_UPDATE
24 | || this == UNSUPPORTED_SERVER;
25 | }
26 | }
27 |
28 | /**
29 | * Gets an update result that indicates that the update failed.
30 | *
31 | * @return The update result.
32 | */
33 | static UpdateResult failed() {
34 | try {
35 | return new UpdateResult(Status.CHECK_FAILED, new UpdateCheckResult(new JsonObject()));
36 | } catch (IOException e) {
37 | throw new AssertionError(e);
38 | }
39 | }
40 |
41 | private final Status status;
42 | private final UpdateCheckResult checkResult;
43 |
44 | UpdateResult(Status status, UpdateCheckResult checkResult) {
45 | this.status = Preconditions.checkNotNull(status);
46 | this.checkResult = Preconditions.checkNotNull(checkResult);
47 | }
48 |
49 | /**
50 | * Gets the status of the update notification.
51 | *
52 | * @return The status.
53 | */
54 | Status getStatus() {
55 | return status;
56 | }
57 |
58 | /**
59 | * Gets the result from the update check.
60 | *
61 | * @return The result.
62 | */
63 | UpdateCheckResult getUpdateCheckResult() {
64 | return checkResult;
65 | }
66 |
67 | /**
68 | * Gets whether this update result has a notification that should be shown.
69 | *
70 | * @return True if this update result has a notification, false otherwise.
71 | */
72 | boolean hasNotification() {
73 | return status.hasNotification();
74 | }
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/Updater.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.io.IOException;
4 | import java.util.Optional;
5 | import java.util.logging.Level;
6 | import java.util.regex.Matcher;
7 | import java.util.regex.Pattern;
8 |
9 | import com.google.common.base.Preconditions;
10 | import com.google.common.collect.ImmutableSet;
11 |
12 | import nl.rutgerkok.blocklocker.Translator;
13 | import nl.rutgerkok.blocklocker.impl.BlockLockerPluginImpl;
14 | import nl.rutgerkok.blocklocker.impl.updater.UpdateResult.Status;
15 |
16 | /**
17 | * Handles the complete update procedure.
18 | *
19 | */
20 | public final class Updater {
21 |
22 | /**
23 | * Every twelve hours.
24 | */
25 | private static final long CHECK_INTERVAL = 20 * 60 * 60 * 12;
26 |
27 | private final BlockLockerPluginImpl plugin;
28 | private volatile UpdatePreference preference;
29 | private final Translator translator;
30 |
31 | public Updater(UpdatePreference preference, Translator translator, BlockLockerPluginImpl plugin) {
32 | this.preference = Preconditions.checkNotNull(preference);
33 | this.translator = Preconditions.checkNotNull(translator);
34 | this.plugin = Preconditions.checkNotNull(plugin);
35 |
36 | }
37 |
38 | private Optional getMinecraftVersion() {
39 | String serverVersion = plugin.getServer().getVersion();
40 | String regex = "MC\\: *([A-Za-z0-9\\._\\-]+)";
41 | Matcher matcher = Pattern.compile(regex).matcher(serverVersion);
42 | if (matcher.find() && matcher.groupCount() == 1) {
43 | return Optional.of(matcher.group(1));
44 | } else {
45 | return Optional.empty();
46 | }
47 | }
48 |
49 | /**
50 | * Notifies admins of the server of an updated version of the plugin. Can be
51 | * called from any thread.
52 | *
53 | * @param result
54 | * The update result.
55 | */
56 | private void notifyServer(final UpdateResult result) {
57 | if (!result.hasNotification()) {
58 | return;
59 | }
60 |
61 | // Disable further update checks
62 | preference = UpdatePreference.DISABLED;
63 |
64 | // Notify admins of existing result
65 | if (plugin.getServer().isPrimaryThread()) {
66 | notifyServerFromServerThread(result);
67 | } else {
68 | plugin.runLaterGlobally(new Runnable() {
69 | @Override
70 | public void run() {
71 | notifyServerFromServerThread(result);
72 | }
73 | }, 1);
74 | }
75 | }
76 |
77 | private void notifyServerFromServerThread(UpdateResult result) {
78 | // Must be called from notifyServer
79 | // Result must have a notification
80 |
81 | UpdateNotifier notifier = new UpdateNotifier(translator, result);
82 |
83 | // Notify players
84 | plugin.getServer().getPluginManager().registerEvents(notifier, plugin);
85 |
86 | // Notify console
87 | notifier.sendNotification(plugin.getServer().getConsoleSender());
88 | }
89 |
90 | /**
91 | * Starts the update process. Does nothing if updates have been disabled.
92 | *
93 | * @throws IllegalStateException
94 | * If this method was called earlier.
95 | */
96 | public void startUpdater() {
97 | if (!preference.checkForUpdates()) {
98 | return;
99 | }
100 | plugin.runTimerAsync(task -> {
101 | if (preference.checkForUpdates()) {
102 | updateSync();
103 | } else {
104 | task.cancel();
105 | }
106 | }, CHECK_INTERVAL);
107 | }
108 |
109 | private void notifyUpdateAvailable(UpdateCheckResult result) throws IOException {
110 | Optional minecraftVersion = getMinecraftVersion();
111 |
112 | if (minecraftVersion.isEmpty() || result.getMinecraftVersions().containsAll(ImmutableSet.of(minecraftVersion.get()))) {
113 | // Notify that an update is available
114 | notifyServer(new UpdateResult(Status.MANUAL_UPDATE, result));
115 | } else {
116 | // Server version no longer supported
117 | notifyServer(new UpdateResult(Status.UNSUPPORTED_SERVER, result));
118 | }
119 | }
120 |
121 | /**
122 | * Blocking update method, must not be called from the server thread.
123 | */
124 | private void updateSync() {
125 | try {
126 | UpdateChecker checker = new UpdateChecker();
127 | UpdateCheckResult result = checker.checkForUpdatesSync(plugin);
128 | if (result.needsUpdate()) {
129 | notifyUpdateAvailable(result);
130 | } else {
131 | notifyServer(new UpdateResult(Status.NO_UPDATE, result));
132 | }
133 | } catch (IOException e) {
134 | plugin.getLogger().log(Level.WARNING, "Error during update check"
135 | + " (you can disable automatic updates in the config file)", e);
136 | notifyServer(UpdateResult.failed());
137 | }
138 | }
139 |
140 | }
141 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/UserAgent.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.updater;
2 |
3 | import java.net.URLConnection;
4 |
5 | import org.bukkit.plugin.Plugin;
6 |
7 | /**
8 | * Sets the correct user agent.
9 | *
10 | */
11 | final class UserAgent {
12 |
13 | /**
14 | * Sets the correct user agent as used by this plugin on the request.
15 | *
16 | * @param plugin
17 | * The plugin.
18 | * @param connection
19 | * The request to set the user agent on.
20 | */
21 | static void setFor(Plugin plugin, URLConnection connection) {
22 | String agent = "Mozilla/5.0 (" + plugin.getName() + "/" + plugin.getDescription().getVersion() + ")";
23 | connection.setRequestProperty("User-Agent", agent);
24 | }
25 |
26 | private UserAgent() {
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/impl/updater/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Classes for updating the plugin.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.impl.updater;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/location/CombinedLocationChecker.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.location;
2 |
3 | import java.util.ArrayList;
4 | import java.util.Collection;
5 | import java.util.List;
6 | import java.util.Objects;
7 |
8 | import org.bukkit.block.Block;
9 | import org.bukkit.entity.Player;
10 |
11 | /**
12 | * Location checker returns false if any of the given location checkers returns
13 | * false.
14 | *
15 | */
16 | public final class CombinedLocationChecker implements LocationChecker {
17 |
18 | private final List checkers = new ArrayList<>();
19 |
20 | /**
21 | * Adds a location checker.
22 | *
23 | * @param checker
24 | * The location checker.
25 | */
26 | public void addChecker(LocationChecker checker) {
27 | this.checkers.add(Objects.requireNonNull(checker, "checker"));
28 | }
29 |
30 | @Override
31 | public void checkLocation(Player player, Block block) throws IllegalLocationException {
32 | for (LocationChecker checker : this.checkers) {
33 | checker.checkLocation(player, block);
34 | }
35 | }
36 |
37 | /**
38 | * Gets all groups that must be kept on reload.
39 | *
40 | * @return All groups that must be kept.
41 | */
42 | public Collection getReloadSurvivors() {
43 | Collection reloadSurvivors = new ArrayList<>();
44 | for (LocationChecker checker : this.checkers) {
45 | if (checker.keepOnReload()) {
46 | reloadSurvivors.add(checker);
47 | }
48 | }
49 | return reloadSurvivors;
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/location/IllegalLocationException.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.location;
2 |
3 | import java.util.Objects;
4 |
5 | import nl.rutgerkok.blocklocker.Translator;
6 | import nl.rutgerkok.blocklocker.Translator.Translation;
7 |
8 | public final class IllegalLocationException extends Exception {
9 |
10 | private static final long serialVersionUID = -8935206826802987169L;
11 |
12 | private final Translation translation;
13 |
14 | /**
15 | * Constructor used if you don't want a translated message.
16 | *
17 | * @param message
18 | * The message.
19 | */
20 | public IllegalLocationException(String message) {
21 | super(Objects.requireNonNull(message, "message"));
22 | this.translation = null;
23 | }
24 |
25 | /**
26 | * Constructor used if you want a translated message.
27 | *
28 | * @param translation
29 | * The translation.
30 | */
31 | public IllegalLocationException(Translation translation) {
32 | this.translation = Objects.requireNonNull(translation, "translation");
33 | }
34 |
35 | /**
36 | * Gets a translated message, or the original message if no translation was
37 | * specified.
38 | *
39 | * @param translator
40 | * The translator to use.
41 | * @return The message.
42 | */
43 | public String getTranslatedMessage(Translator translator) {
44 | if (this.translation != null) {
45 | return translator.get(translation);
46 | }
47 | return getLocalizedMessage();
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/location/LocationChecker.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.location;
2 |
3 | import org.bukkit.block.Block;
4 | import org.bukkit.entity.Player;
5 |
6 | import nl.rutgerkok.blocklocker.Permissions;
7 | import nl.rutgerkok.blocklocker.ProtectableBlocksSettings;
8 |
9 | /**
10 | * Used to check if protections can be created at the given location.
11 | *
12 | * @see ProtectableBlocksSettings For making a block protectable in the first
13 | * place.
14 | */
15 | public interface LocationChecker {
16 |
17 | /**
18 | * Checks whether people can protect chests here.
19 | *
20 | * @param player
21 | * The player placing the chest.
22 | * @param block
23 | * The location.
24 | * @throws IllegalLocationException
25 | * If the player is not allowed to place a chest here. The exception
26 | * should include a message why.
27 | */
28 | void checkLocation(Player player, Block block) throws IllegalLocationException;
29 |
30 | /**
31 | * Checks whether people can protect chests here. For players that have the
32 | * {@link Permissions#CAN_WILDERNESS} permission node, this is always the case.
33 | *
34 | * @param player
35 | * The player placing the chest.
36 | * @param block
37 | * The location.
38 | * @throws IllegalLocationException
39 | * If the player is not allowed to place a chest here. The exception
40 | * should include a message why.
41 | */
42 | default void checkLocationAndPermission(Player player, Block block) throws IllegalLocationException {
43 | if (player.hasPermission(Permissions.CAN_WILDERNESS)) {
44 | return;
45 | }
46 | checkLocation(player, block);
47 | }
48 |
49 | /**
50 | * Gets whether this location checker must be kept when the plugin is reloaded
51 | * using the reload command of the plugin.
52 | *
53 | *
54 | * When a location checker is removed on reload, it must be re-added after the
55 | * reload. For location checkers provided by other plugins this is problematic,
56 | * so they must return true. On the other hand, group systems included in
57 | * BlockLocker will be loaded again by BlockLocker, so they must return false.
58 | *
59 | * @return True if the group system must be kept on reload, false otherwise.
60 | */
61 | default boolean keepOnReload() {
62 | return true;
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/profile/GroupProfile.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.profile;
2 |
3 | /**
4 | * Allows a whole group to access a chest. It's up to the implementation who is
5 | * part of the group.
6 | *
7 | */
8 | public interface GroupProfile extends Profile {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/profile/PlayerProfile.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.profile;
2 |
3 | import java.util.Optional;
4 | import java.util.UUID;
5 |
6 | public interface PlayerProfile extends Profile {
7 |
8 | /**
9 | * Gets the unique id of this player, if any.
10 | *
11 | * @return The unique id.
12 | */
13 | Optional getUniqueId();
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/profile/Profile.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.profile;
2 |
3 | import java.util.Date;
4 |
5 | import nl.rutgerkok.blocklocker.SecretSignEntry;
6 |
7 | /**
8 | * Represents a profile. A profile is usually a player, but it may also be a whole group or something abstract like
9 | * "Redstone".
10 | *
11 | */
12 | public interface Profile {
13 |
14 | /**
15 | * Gets the name of the profile as it should be displayed on signs.
16 | *
17 | * @return The name of the profile.
18 | */
19 | String getDisplayName();
20 |
21 | /**
22 | * Gets the object as it should be saved.
23 | *
24 | * @param signEntry
25 | * The entry to save to.
26 | */
27 | void getSaveObject(SecretSignEntry signEntry);
28 |
29 | /**
30 | * Gets whether this profile includes another profile. For example,
31 | * "[Everyone]" includes all other profiles, and "jeb_" includes everyone
32 | * with the name jeb_.
33 | *
34 | * @param other
35 | * The other profile.
36 | * @return True if this profile includes the other profile, false otherwise.
37 | */
38 | boolean includes(Profile other);
39 |
40 | /**
41 | * Gets whether this profile is expired.
42 | *
43 | * @param cutoffDate
44 | * The cutoff date: there must be activity for this profile after
45 | * the given date, or else it's considered expired.
46 | * @return True if the profile is expired, false otherwise.
47 | */
48 | boolean isExpired(Date cutoffDate);
49 |
50 | }
51 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/profile/TimerProfile.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.profile;
2 |
3 | /**
4 | * A profile that allows nobody, but sets the time how long the door may be
5 | * open.
6 | *
7 | */
8 | public interface TimerProfile extends Profile {
9 |
10 | /**
11 | * Gets the amount of ticks the door can be open before it is closed again.
12 | *
13 | * @return The amount of ticks.
14 | */
15 | int getOpenSeconds();
16 | }
17 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/profile/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Classes representing profiles (chest owners): players, groups, etc.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.profile;
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/protection/AttachedProtection.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.protection;
2 |
3 | /**
4 | * A protection that is attached to another block; signs are searched for on
5 | * that other block.
6 | *
7 | */
8 | public interface AttachedProtection extends Protection {
9 |
10 | }
11 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/protection/ContainerProtection.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.protection;
2 |
3 | /**
4 | * Represents a protected container, like a chest or a furnace.
5 | *
6 | */
7 | public interface ContainerProtection extends Protection {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/protection/DoorProtection.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.protection;
2 |
3 |
4 | /**
5 | * Represents a protection for a door. Keep in mind that trapdoors are doors
6 | * too.
7 | *
8 | */
9 | public interface DoorProtection extends Protection {
10 |
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/protection/Protection.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.protection;
2 |
3 | import java.util.Collection;
4 | import java.util.Date;
5 | import java.util.Optional;
6 |
7 | import org.bukkit.block.Block;
8 |
9 | import nl.rutgerkok.blocklocker.ProtectionSign;
10 | import nl.rutgerkok.blocklocker.profile.Profile;
11 |
12 | /**
13 | * Represents a generic protection container with its attached signs.
14 | *
15 | */
16 | public interface Protection {
17 |
18 | /**
19 | * When to play a sound for opening a door.
20 | *
21 | */
22 | enum SoundCondition {
23 | /**
24 | * Never play a sound.
25 | */
26 | NEVER,
27 | /**
28 | * Only play a sound for doors that the Minecraft client doesn't
29 | * automatically play a sound for a player opens it.
30 | */
31 | AUTOMATIC,
32 | /**
33 | * Always play a sound.
34 | */
35 | ALWAYS
36 | }
37 |
38 | /**
39 | * Gets whether the protection can be opened as a door/gate/trapdoor.
40 | * @return True if the protection can be opened, false otherwise.
41 | */
42 | boolean canBeOpened();
43 |
44 | /**
45 | * Gets the allowed profiles in this protection. Allowed profiles can
46 | * place/take items and open doors, but cannot break the protection. This
47 | * list includes the {@link #getOwner() owner}.
48 | *
49 | * @return The allowed profiles.
50 | * @see #isAllowed(Profile)
51 | */
52 | Collection getAllowed();
53 |
54 | /**
55 | * Gets the location of the protection. Returns one of the blocks in the
56 | * protection (if there are multiple blocks), and not one of the signs.
57 | *
58 | * @return The location.
59 | */
60 | Block getSomeProtectedBlock();
61 |
62 | /**
63 | * Gets the amount of seconds the door should stay open, before closing
64 | * automatically. If no amount of seconds was specified on the door, -1 is
65 | * returned.
66 | *
67 | * @return The amount of ticks, or -1 if unspecified.
68 | */
69 | int getOpenSeconds();
70 |
71 | /**
72 | * Gets the owner of this protection. The owner is the only one allowed to
73 | * destroy this protection. All protections have an owner, unless they have
74 | * been corrupted by for example a world editor.
75 | *
76 | * @return The owner.
77 | * @see #isOwner(Profile)
78 | */
79 | Optional getOwner();
80 |
81 | /**
82 | * Gets the display name of the owner of the protection. If
83 | * {@link #getOwner()} is absent, "?" is returned.
84 | *
85 | * @return The display name.
86 | */
87 | String getOwnerDisplayName();
88 |
89 | /**
90 | * Gets all signs used in this protection. Low-level method,
91 | * {@link #getAllowed()} is preferred. Example usage is changing the
92 | * contents on the sign.
93 | *
94 | * @return All signs used by this protection.
95 | */
96 | Collection getSigns();
97 |
98 | /**
99 | * Checks if the given profile has been allowed to this protection.
100 | *
101 | * @param profile
102 | * The profile to check.
103 | * @return True if the profile is allowed, false otherwise.
104 | * @see #getAllowed()
105 | */
106 | boolean isAllowed(Profile profile);
107 |
108 | /**
109 | * Gets whether this protection is expired. As protection is expired when
110 | * the {@link #getOwner() owner profile} is considered
111 | * {@link Profile#isExpired(Date) expired}.
112 | *
113 | * @param cutoffDate
114 | * The cutoff date.
115 | * @return True if the profile is expired, false otherwise.
116 | */
117 | boolean isExpired(Date cutoffDate);
118 |
119 | /**
120 | * Gets whether the door is currently opened. If only parts of the door are
121 | * open, the result of this method is undefined.
122 | *
123 | * @return Whether the door is currently opened.
124 | */
125 | boolean isOpen();
126 |
127 | /**
128 | * Checks if the given profile is the owner of this chest.
129 | *
130 | * @param profile
131 | * The profile to check.
132 | * @return True if it is the owner, false otherwise.
133 | * @see #getOwner()
134 | */
135 | boolean isOwner(Profile profile);
136 |
137 | /**
138 | * Opens or closes the door, as specified. Plays no sound.
139 | *
140 | * @param open
141 | * True to open the door, false otherwise.
142 | * @see #setOpen(boolean, SoundCondition) Control over sound playing.
143 | */
144 | default void setOpen(boolean open) {
145 | setOpen(open, SoundCondition.NEVER);
146 | }
147 |
148 | /**
149 | * Opens or closes the door, as specified.
150 | *
151 | * @param open
152 | * True to open the door, false otherwise.
153 | * @param playSound
154 | * Whether to play a sound.
155 | */
156 | void setOpen(boolean open, SoundCondition playSound);
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/nl/rutgerkok/blocklocker/protection/package-info.java:
--------------------------------------------------------------------------------
1 | /**
2 | * Classes representing protections.
3 | *
4 | */
5 | package nl.rutgerkok.blocklocker.protection;
--------------------------------------------------------------------------------
/src/main/resources/plugin.yml:
--------------------------------------------------------------------------------
1 | name: ${project.name}
2 | version: "${project.version}"
3 | main: nl.rutgerkok.blocklocker.impl.BlockLockerPluginImpl
4 | author: Rutger Kok
5 | load: startup
6 | api-version: "1.20"
7 | softdepend: [Guilds, Factions, mcMMO, Towny]
8 | folia-supported: true
9 | permissions:
10 | blocklocker.protect:
11 | description: "Protect containers and doors."
12 | default: true
13 | blocklocker.bypass:
14 | description: "Bypass someone else's protection, but don't allow destroying it."
15 | default: op
16 | blocklocker.admin:
17 | description: "Edit someone's protection signs, or remove the protection entirely."
18 | default: op
19 | blocklocker.reload:
20 | description: "Reload the plugin using /blocklocker reload."
21 | default: op
22 | blocklocker.wilderness:
23 | description: "Place chests in the wilderness (outside of Towny claims)"
24 | default: true
25 | commands:
26 | blocklocker:
27 | description: "Administration commands for BlockLocker."
28 | permission: "blocklocker.reload"
29 | usage: "/ reload"
30 | aliases: "bl"
31 |
--------------------------------------------------------------------------------
/src/main/resources/translations-cs.yml:
--------------------------------------------------------------------------------
1 | # Translations file for the Czech language. Translations by PetyXbron.
2 | command:
3 | cannot_be_used_by_console: "Tento příkaz nelze býti použit konzolí. Promiň!"
4 | cannot_edit_owner: "&4Nemůžeš změnit majitele zabezpečení Místo toho znič ceduli."
5 | line_number_out_of_bounds: "&4Zadej prosím číslo řádku od 2 po 4."
6 | no_sign_selected: "&4Nejdříve musíš vybrat cedulku jednoho z tvých zabezpečených bloků pravým klikem na myši."
7 | no_permission: "&4Nemáš právo použít tenhle příkaz. Promiň!"
8 | player_name_too_long: "&4Jméno hráče obsahuje více než 16 znaků, což se nevejde na cedulku. Je také delší, než limit u přezdívek hráčů Mojang."
9 | plugin_reloaded: "&6Znovu-načteny konfigurační soubory!"
10 | sign_no_longer_part_of_protection: "&4Vybraná cedulka již nespadá pod zabezpečený blok."
11 | updated_sign: "&6Cedulka aktualizována!"
12 | protection:
13 | add_more_users_sign_instead: "&4Na zabezpečeném bloku může být pouze jedna [Private] cedulka. Místo toho přidej [More Users] cedulku."
14 | bypassed: "&6Právě jsi obešel zabezpečení hráče {0}."
15 | can_only_add_protection_sign: "&4Na zabezpečeném bloku může být pouze jedna [Private] a nula nebo více [More Users] cedulek. Jiné cedulky nejsou povoleny."
16 | cannot_change_sign: "&4Nemůžeš změnit cedulku poblíž zabezpečeného bloku."
17 | chest_hint: "&6Umísti na tuhle bednu cedulku k zabezpečení před ostatními hráči."
18 | claimed_container: "&6Blok zabezpečen. Nikdo jiný k ní teď nemá přístup."
19 | claimed_manually: "&6Block zabezpečen. Přístup k němu mají pouze hráči uvedeni na cedulce."
20 | expired: "&6Zabezpečení tohoto bloku vypršela kvůli nečinnosti vlastníka."
21 | in_wilderness: "&4Zde nemůžeš vytvořit zabezpečení bloku: nacházíš se v divočině."
22 | is_claimed_by: "&6Tento blok je zabezpečen hráčem {0}."
23 | no_access: "&4Tento blok nemůžeš použít, protože je zabezpečen hráčem {0}."
24 | no_permission_for_claim: "&4Nemáš oprávnění k zabezpečení bloku, promiň."
25 | not_nearby: "&4Ve tvé blízkosti se nenachází žádný zabezpečitelný blok. Použij (shift a) pravé tlačítko na myši s cedulkou v ruce k jejímu položení a zabezpečení bloku."
26 | tag:
27 | everyone:
28 | - "Everyone"
29 | - "Všichni"
30 | timer:
31 | - "Timer"
32 | - "Časovač"
33 | redstone:
34 | - "Redstone"
35 | - "Rudit"
36 | private:
37 | - "[Private]"
38 | - "[Soukromé]"
39 | more_users:
40 | - "[More Users]"
41 | - "[Více uživatelů]"
42 | updater:
43 | more_information: "&6Více informací: {0}"
44 | unsupported_server: "&4Nejnovější verze ${project.name} (verze {0}) již nepodporuje tuto verzi Minecraftu, pouze Minecraft {1}."
45 | update_available: "&6Aktualizace pro ${project.name} (verze {0}) je k dispozici pro ruční stáhnutí a instalaci."
46 | updated_automatically: "&6Je k dispozici nová aktualizace pro ${project.name} (verze {0}). Po restartování serveru se automaticky nainstaluje."
47 |
--------------------------------------------------------------------------------
/src/main/resources/translations-de.yml:
--------------------------------------------------------------------------------
1 | # Übersetzung in die deutsche Sprache
2 | command:
3 | cannot_be_used_by_console: "Dieser Befehl kann nicht über die Konsole verwendet werden!"
4 | cannot_edit_owner: "&4Du kannst den Besitzer dieses Schildes nicht ändern. Du solltest das Schild stattdessen zerstören."
5 | line_number_out_of_bounds: "&4Bitte gib eine Zeilennummer von 2 bis 4 ein."
6 | no_sign_selected: "&4Du musst zuerst ein Schild auf einem deiner geschützten Blöcke auswählen, indem du mit der rechten Maustaste darauf klickst."
7 | no_permission: "&4Du hast nicht die Berechtigung, diesen Befehl auszuführen."
8 | player_name_too_long: "&4Der Name besteht aus mehr als 16 Zeichen (länger als Mojang erlaubt), weshalb er nicht auf das Schild passt."
9 | plugin_reloaded: "&6Konfiguration neu geladen!"
10 | sign_no_longer_part_of_protection: "&4Das ausgewählte Schild gehört nicht mehr zu einem geschützten Block."
11 | updated_sign: "&6Das Schild wurde aktualisiert!"
12 | protection:
13 | add_more_users_sign_instead: "&4Es ist nur ein Schild mit [Privat] für einen Schutz möglich. Füge stattdessen ein Schild mit [Mehr Benutzer] hinzu."
14 | bypassed: "&6Du hast einen Schutz von {0} umgangen."
15 | can_only_add_protection_sign: "&4Es kann nur ein [Privat] oder [Mehr Benutzer] Schild an diesem Block platziert werden. Mehr geht nicht."
16 | cannot_change_sign: "&4Du kannst ein Schild nicht in der Nähe eines beanspruchten Behälters ändern."
17 | chest_hint: "&6Platziere ein Schild an dieser Truhe, um sie zu schützen."
18 | claimed_container: "&6Block bzw. Bereich geschützt."
19 | claimed_manually: "&6Geschützt! Nur die auf dem Schild aufgeführten Personen können darauf zugreifen."
20 | expired: "&6Der Schutz dieses Blocks wurde aufgrund von Inaktivität des Besitzers aufgehoben."
21 | in_wilderness: "&4Du befindest dich in der Wildnis, daher kannst du hier keinen Schutz erstellen."
22 | is_claimed_by: "&6Dieser Block gehört {0}."
23 | no_access: "&4Du kannst diesen Block nicht verwenden, er ist durch {0} geschützt."
24 | no_permission_for_claim: "&4Du hast nicht die Berechtigung, einen Behälter zu schützen."
25 | not_nearby: "&4Es ist kein zu schützender Block in der Nähe. (Umschalt+)Rechtsklick auf einen Behälter mit einem Schild in deiner Hand, um ihn zu schützen."
26 | selected_sign: "&6Schild ausgewählt. Gib \"/blocklocker \" ein, um das gewählte Schild zu bearbeiten. Alternativ füge Folgendes hinzu: &n[Redstone]&r&6 &n[Jeder]&r&6."
27 | tag:
28 | everyone: ["Jeder", "Everyone"]
29 | timer: "Timer"
30 | redstone: "Redstone"
31 | private: ["[Privat]", "[Private]"]
32 | more_users: ["[Mehr Benutzer]", "[More Users]"]
33 | updater:
34 | more_information: "&6Mehr Informationen: {0}"
35 | unsupported_server: "&4Die neueste Version von ${project.name} (Version {0}) unterstützt diese Minecraft-Version nicht mehr, sondern nur noch Minecraft {1}."
36 | update_available: "&6Eine Aktualisierung für ${project.name} (Version {0}) steht zum manuellen Herunterladen bereit."
37 | updated_automatically: "&6Ein Update wird beim nästen Server-Neustart installiert."
38 |
--------------------------------------------------------------------------------
/src/main/resources/translations-en.yml:
--------------------------------------------------------------------------------
1 | # Translations file for the English language
2 | command:
3 | cannot_be_used_by_console: "This command cannot be used by the console. Sorry!"
4 | cannot_edit_owner: "&4You cannot change the owner of the protection. Destroy the sign instead."
5 | line_number_out_of_bounds: "&4Please enter a line number between 2 and 4, inclusive."
6 | no_sign_selected: "&4You must select a sign on one of your protected blocks first by right-clicking it."
7 | no_permission: "&4You don't have permission to execute this command. Sorry!"
8 | player_name_too_long: "&4The player name is over 16 characters, which doesn't fit on the sign. It is also longer than Mojang allows player names to be."
9 | plugin_reloaded: "&6Reloaded the configuration files!"
10 | sign_no_longer_part_of_protection: "&4The selected sign no longer belongs to a protected block."
11 | updated_sign: "&6Updated the sign!"
12 | protection:
13 | add_more_users_sign_instead: "&4There can only be one [Private] sign on a protection. Add a [More Users] sign instead."
14 | bypassed: "&6You have just bypassed a protection of {0}."
15 | can_only_add_protection_sign: "&4There can only be one [Private] and zero or more [More Users] signs on a protection. Other signs are not allowed."
16 | cannot_change_sign: "&4You cannot change a sign nearby a claimed container."
17 | chest_hint: "&6Place a sign on this chest to protect it."
18 | claimed_container: "&6Claimed this container. Nobody else can access it."
19 | claimed_manually: "&6Created a claim. Only the people listed on the sign can access it."
20 | expired: "&6The protection of this block has expired due to inactivity of the owner."
21 | in_wilderness: "&4You cannot create a protection here: you are in the wilderness."
22 | is_claimed_by: "&6This block has been claimed by {0}."
23 | no_access: "&4You cannot use this block, it is protected by {0}."
24 | no_permission_for_claim: "&4You don't have permission to claim a container, sorry."
25 | not_nearby: "&4There is no protectable block nearby. (Shift-)right-click a container with a sign in your hand to protect it."
26 | tag:
27 | everyone: "Everyone"
28 | timer: "Timer"
29 | redstone: "Redstone"
30 | golem:
31 | - Golem
32 | - Golems
33 | private: "[Private]"
34 | more_users: "[More Users]"
35 | updater:
36 | more_information: "&6More information: {0}"
37 | unsupported_server: "&4The latest version of ${project.name} (version {0}) no longer supports this Minecraft version, only Minecraft {1}."
38 | update_available: "&6An update for ${project.name} (version {0}) is available for manual download."
39 | updated_automatically: "&6An update for ${project.name} is available (version {0}). It will automatically be installed when you restart the server."
40 |
--------------------------------------------------------------------------------
/src/main/resources/translations-es.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the Spanish language. Translations by TheCiROMG.
2 | command:
3 | cannot_be_used_by_console: Este comando no puede ser utilizado por la consola. ¡Lo siento!
4 | cannot_edit_owner: '&4No puede cambiar el propietario de la protección. Destruye el cartel en su lugar.'
5 | line_number_out_of_bounds: '&4Ingrese un número de línea entre 2 y 4, el 1 esta en uso.'
6 | no_permission: '&4No tienes permiso para ejecutar este comando. ¡Lo siento!'
7 | no_sign_selected: '&4Debe seleccionar un cartel en uno de sus bloques protegidos primero, haciendo clic derecho.'
8 | player_name_too_long: '&4El nombre del jugador tiene más de 16 caracteres, lo que no cabe en el letrero. También es más largo de lo que Mojang permite que los nombres de los jugadores sean.'
9 | plugin_reloaded: '&6¡Recargo los archivos de configuración!'
10 | sign_no_longer_part_of_protection: '&4El letrero seleccionado ya no pertenece a un bloque protegido.'
11 | updated_sign: '&6Letrero actualizado!'
12 | protection:
13 | add_more_users_sign_instead: '&4Solo puede haber un cartel [Privado] en una protección. Agregue un cartel [Más usuarios] en su lugar.'
14 | bypassed: '&6Acaba de pasar por alto una protección de {0}.'
15 | cannot_change_sign: '&4No puede cambiar un letrero en un contenedor reclamado.'
16 | chest_hint: '&6Coloque un letrero en este cofre para protegerlo.'
17 | claimed_container: '&6Reclamó este contenedor. Nadie más puede acceder.'
18 | claimed_manually: '&6Creó una proteccion. Solo las personas que figuran en el letrero pueden acceder.'
19 | expired: '&6La protección de este bloque ha expirado debido a la inactividad del propietario.'
20 | in_wilderness: '&4No puedes crear una protección aquí: estás en el desierto.'
21 | is_claimed_by: '&6Este bloque ha sido reclamado por {0}.'
22 | no_access: '&4No puedes usar este bloque, está protegido por {0}.'
23 | no_permission_for_claim: '&4No tiene permiso para reclamar un contenedor, lo siento.'
24 | not_nearby: '&4No hay bloque protector cerca. Haz clic derecho en un contenedor con un letrero en tu mano para protegerlo.'
25 | selected_sign: '&6Cartel seleccionado. Escribe "/blocklocker " para editar este cartel.'
26 | tag:
27 | everyone: Todos
28 | more_users:
29 | - '[Mas Usuarios]'
30 | - '[More Users]'
31 | private:
32 | - '[Privado]'
33 | - '[Private]'
34 | redstone: Redstone
35 | timer: Timer
36 | updater:
37 | more_information: '&6Más información: {0}'
38 | unsupported_server: '&4La última versión de BlockLocker (version {0}) ya no es compatible con esta versión de Minecraft, solo Minecraft {1}.'
39 | update_available: '&6Una actualización para BlockLocker (version {0}) está disponible para su descarga manual.'
40 |
--------------------------------------------------------------------------------
/src/main/resources/translations-fr.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the French language. Translations by Kervinou.
2 | command:
3 | cannot_be_used_by_console: "Cette commande n'est pas possible à partir de la console !"
4 | cannot_edit_owner: "&4Vous ne pouvez pas changer le propriétaire de cette protection. Détruisez la protection en premier."
5 | line_number_out_of_bounds: "&4Saisir un numéro de ligne entre 2 et 4 (inclus)."
6 | no_permission: "&4Vous n'avez pas la permission d'utiliser cette commande."
7 | no_sign_selected: "&4Vous devez choisir un panneau sur un des block protégés d'abord en cliquant droit dessus."
8 | player_name_too_long: "&4Le nom du joueur dépasse les 16 caractères, cela dépasse le panneau. C'est d'ailleurs aussi plus long que la longueur conseillée par les créateurs de Minecraft !!"
9 | plugin_reloaded: "&6La Configuration du plugin a été rechargée !"
10 | sign_no_longer_part_of_protection: "&4Le panneau sélectionné n'est pas accolé à un block protégé."
11 | updated_sign: "&6Protection mise à jour !"
12 | protection:
13 | add_more_users_sign_instead: "&4Un seul panneau nommé [Privé] est possible, ajoutez un autre panneau nommé [Ainsi que]"
14 | bypassed: "&6Vous venez de passer outre une protection appartenant à {0}."
15 | cannot_change_sign: "&4Vous ne pouvez pas changer ce panneau, trop proche d'un block protégé."
16 | chest_hint: "&6Vous pouvez mettre un panneau sur ce coffre pour le protéger."
17 | claimed_container: "&6Block protégé. Personne d'autre ne peut y avoir accès."
18 | claimed_manually: "&6Protection créée. Seuls les personnes listées sur le panneau peuvent y accéder."
19 | expired: "&6La protection de ce block a expiré à cause de l'inactivité du propriétaire."
20 | in_wilderness: "&4Vous ne pouvez pas créer une protection ici: vous êtes dans une région sauvage !"
21 | is_claimed_by: "&6Ce block appartient à {0}."
22 | no_access: "&4Intéraction non autorisée, il appartient à {0}."
23 | no_permission_for_claim: "&4Vous n'avez pas la permission de protéger ce block, désolé !"
24 | not_nearby: "&4Aucun block protégeable à proximité. Faites (Shift-)Clic-Droit sur un block avec un panneau dans la main pour le protéger."
25 | selected_sign: "&6Protection sélectionnée: écrire \"/bl \" pour éditer cette protection."
26 | tag:
27 | everyone: ToutLeMonde
28 | more_users:
29 | - "[Ainsi que]"
30 | - "[More Users]"
31 | private:
32 | - "[Privé]"
33 | - "[Private]"
34 | redstone: Redstone
35 | timer: Timer
36 | updater:
37 | more_information: "&6Pour plus de détails: {0}"
38 | unsupported_server: "&4La dernière version de BlockLocker (version {0}) ne fonctionne pas avec cette version de Minecraft, seulement Minecraft {1}."
39 | update_available: "&6Une mise à jour de BlockLocker (version {0}) est disponible pour un téléchargement manuel"
40 |
--------------------------------------------------------------------------------
/src/main/resources/translations-hu.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: Ezt a parancsot a konzol nem tudja használni. Sajnálom!
3 | cannot_edit_owner: 'A védelem tulajdonosát nem változtathatod meg. Inkább semmisítsd meg a táblát.'
4 | line_number_out_of_bounds: 'Kérlek, 2 és 4 közötti sorszámot adj meg.'
5 | no_permission: 'nincsjog'
6 | no_sign_selected: 'Először válassz ki egy olyan táblát jobb gombbal, ami egy védett blokkon van'
7 | player_name_too_long: 'A játékos neve több mint 16 karakterből áll, ami nem fér el a táblán. Hosszabb is, mint amennyit a Mojang lehetővé tesz a játékosok számára.'
8 | plugin_reloaded: 'A konfigurációs fájlok újratöltve!'
9 | sign_no_longer_part_of_protection: 'A kiválasztott tábla már nem tartozik védett blokkhoz.'
10 | updated_sign: 'A tábla frissítve!'
11 | protection:
12 | add_more_users_sign_instead: 'Csak egy [Privát] tábla lehet egy védett blokkon. További játékosokat ha szeretnél a védelemhez adni, akkor használd a [Felhasználók] feliratot a táblát.'
13 | bypassed: '{0} védelme adminisztrátori jogosulktságod miatt ignorálva.'
14 | cannot_change_sign: 'Levédet blokk közelében nem módosíthatsz táblákat.'
15 | chest_hint: 'Tegyél egy táblát erre a ládára, hogy megvédd azt.'
16 | claimed_container: 'Sikeresen levédve. Csak Te férsz hozzá mostantól.'
17 | claimed_manually: 'Sikeresen levédve. A táblán feltüntetett játékosok férnek csak hozzá.'
18 | expired: 'Ennek a blokknak a védelme a tulajdonos inaktivitása miatt lejárt.'
19 | in_wilderness: 'Itt nem hozhatsz létre védelmet.'
20 | is_claimed_by: 'A védelem tulajdonosa {0}.'
21 | no_access: 'Ezt nem használhatod. A védelem tulajdonosa {0}.'
22 | no_permission_for_claim: 'nincsjog'
23 | not_nearby: 'Nincs védett blokk a környékeden. Shift+jobb gomb egy tároló blokkra egy táblával a kezedben, hogy levédd azt.'
24 | selected_sign: 'Tábla kiválasztva. Használd a "/blocklocker " parancsot, hogy módosítsd a táblát. Ezeket is hozzáadhatod: [Vöröskő] vagy [Mindenki]'
25 | tag:
26 | everyone: Mindenki
27 | more_users:
28 | - '[Felhasználók]'
29 | - '[More Users]'
30 | private:
31 | - '[Privát]'
32 | - '[Private]'
33 | redstone:
34 | - Vöröskő
35 | - Redstone
36 | timer:
37 | - Időzítő
38 | - Timer
39 | updater:
40 | more_information: 'More information: {0}'
41 | unsupported_server: 'The latest version of BlockLocker (version {0}) no longer supports this Minecraft version, only Minecraft {1}.'
42 | update_available: 'An update for BlockLocker (version {0}) is available for manual download.'
43 |
--------------------------------------------------------------------------------
/src/main/resources/translations-id.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: Perintah ini tidak dapat digunakan oleh konsol. Maaf!
3 | cannot_edit_owner: '&4Kamu tidak dapat mengganti pemilik proteksi. Hancurkan saja sign itu.'
4 | line_number_out_of_bounds: '&4Mohon masukkan nomor baris antara 2 dan 4, inklusif.'
5 | no_permission: '&4Kamu tidak punya izin untuk mengeksekusi perintah ini. Maaf!'
6 | no_sign_selected: '&4Kamu harus memilih sebuah sign di salah satu blok yang kamu lindungi dulu
7 | dengan mengeklik kanan itu.'
8 | player_name_too_long: '&4Nama pemain lebih dari 16 karakter, dimana tidak muat pada sign. Itu juga lebih panjang dari yang diperbolekan Mojang untuk nama pemain.'
9 | plugin_reloaded: '&6Memuat ulang file konfigurasi!'
10 | sign_no_longer_part_of_protection: '&4Sign yang dipilih tidak lagi menjadi milik blok yang dilindungi.'
11 | updated_sign: '&6Memperbarui sign!'
12 | protection:
13 | add_more_users_sign_instead: '&4Hanya boleh ada satu sign [Private] pada sebuah proteksi. Tambahkan saja sign [More Users].'
14 | bypassed: '&6Kamu baru saja melewati proteksi {0}.'
15 | cannot_change_sign: '&4Kamu tidak dapat mengubah sign di dekat kontainer yang sudah diklaim.'
16 | chest_hint: '&6Tempatkan sign pada chest ini untuk melindunginya.'
17 | claimed_container: '&6Mengklaim kontainer ini. Tidak ada orang lain yang dapat mengaksesnya.'
18 | claimed_manually: '&6Berhasil membuat klaim. Hanya orang tercantum pada sign yang dapat mengaksesnya.'
19 | expired: '&6Proteksi blok ini sudah kadaluwarsa karena pemiliknya tidak aktif.'
20 | in_wilderness: '&4Kamu tidak dapat membuat proteksi disini: kamu berada di hutan belantara.'
21 | is_claimed_by: '&6Blok ini sudah diklaim oleh {0}.'
22 | no_access: '&4Kamu tidak dapat menggunakan blok ini, itu dilidungi oleh {0}.'
23 | no_permission_for_claim: '&4Kamu tidak punya izin untuk mengklaim kontainer, maaf.'
24 | not_nearby: '&4Tidak ada block yang dapat dilindungi di dekat sini. (Shift-)klik-kanan kontainer
25 | dengan sign di tangan mu untuk melindunginya.'
26 | tag:
27 | everyone: Everyone
28 | more_users: ['[More Users]', '[User Lain]']
29 | private: ['[Private]', '[Pribadi]']
30 | redstone: Redstone
31 | timer: Timer
32 | updater:
33 | more_information: '&6Informasi lebih lanjut: {0}'
34 | unsupported_server: '&4Versi terbaru BlockLocker (versi {0}) tidak lagi mendukung versi Minecraft ini, hanya Minecraft {1}.'
35 | update_available: '&6Pembaruan untuk BlockLocker (versi {0}) tersedia untuk diunduh secara manual.'
36 |
--------------------------------------------------------------------------------
/src/main/resources/translations-it.yml:
--------------------------------------------------------------------------------
1 | # Translations file for the Italian language
2 | command:
3 | cannot_be_used_by_console: "Questo comando non può essere usato dalla console. Spiacente!"
4 | cannot_edit_owner: "&4Non puoi cambiare il proprietario della protezione. Distruggi invece il cartello"
5 | line_number_out_of_bounds: "&4Per favore, utilizza un numero di linea compreso tra 2 e 4 inclusi."
6 | no_sign_selected: "&4Devi selezionare un cartello su uno dei tuoi blocchi protetti cliccando con il tasto destro su di esso."
7 | no_permission: "&4Non hai il permesso di eseguire questo comando. Spiacente!"
8 | player_name_too_long: "&4Il nome del giocatore è di oltre 16 caratteri, ciò non permette di essere inserito sul cartello. Inoltre è più lungo dei caratteri massimi del nome concessi da Mojang."
9 | plugin_reloaded: "&6Ricaricati i file di configurazione con successo!"
10 | sign_no_longer_part_of_protection: "&4Il cartello selezionato non appartiene più ad un blocco protetto."
11 | updated_sign: "&6Aggiornato il cartello!"
12 | protection:
13 | add_more_users_sign_instead: "&4Ci può essere solo una etichetta [Privato] su una protezione. Aggiungi invece l'etichetta [Più utenti]."
14 | bypassed: "&6Hai appena ignorato una protezione di {0}."
15 | can_only_add_protection_sign: "&4CI può essere solo un etichetta [Privato] e zero or più [More Users] su un cartello. Altre etichette non sono permesse."
16 | cannot_change_sign: "&4Non puoi cambiare un cartello vicino ad un contenitore reclamato."
17 | chest_hint: "&6Posiziona un cartello su questo baula per proteggerlo."
18 | claimed_container: "&6Reclamato questo contenitore. Nessun altro può accedervi."
19 | claimed_manually: "&6Reclamato con successo. Solo le persone elencate nel cartello possono accedervi."
20 | expired: "&6La protezione di questo blocco è scaduta data l'inattività del proprietario."
21 | in_wilderness: "&4Non puoi creare una protezione qui: sei in una area selvaggia."
22 | is_claimed_by: "&6Questo blocco è stato reclamato da {0}."
23 | no_access: "&4Non puoi usare questo blocco, è protetto da {0}."
24 | no_permission_for_claim: "&4Non hai il permesso di reclamare questo contenitore, spiacente."
25 | not_nearby: "&4Non è presente alcun blocco da proteggere. Utilizza (Shift-)tasto destro su un contenitore con un cartello in mano per proteggerlo."
26 | tag:
27 | everyone: "Chiunque"
28 | timer: "Timer"
29 | redstone: "Redstone"
30 | private: "[Privato]"
31 | more_users: "[Più utenti]"
32 | updater:
33 | more_information: "&6Maggiori informazioni: {0}"
34 | unsupported_server: "&4L'ultima versione di ${project.name} (version {0}) non supporta più questa versione di Minecraft, solo Minecraft {1} è supportato."
35 | update_available: "&6Un aggiornamento per ${project.name} (version {0}) è disponibile per il download manuale."
36 | updated_automatically: "&6Un aggiornamento per ${project.name} è disponibile (version {0}). Sarà automaticamente installato al prossimo riavvio del server."
37 |
--------------------------------------------------------------------------------
/src/main/resources/translations-ja.yml:
--------------------------------------------------------------------------------
1 | # Translations file for the English language
2 | command:
3 | cannot_be_used_by_console: "申し訳ありません。このコマンドはコンソールから実行することはできません。"
4 | cannot_edit_owner: "&4保護の所有者を変更できません。代わりに看板を破壊してください。"
5 | line_number_out_of_bounds: "&42から4までの行番号を入力してください。"
6 | no_sign_selected: "&4最初に、保護されたブロックの1つを右クリックしてからそのサインを選択する必要があります。"
7 | no_permission: "&4このコマンドを実行する権限がありません!"
8 | player_name_too_long: "&4プレイヤー名が16文字を超えているため看板に収まりません。また、Mojangが許可するプレイヤー名の長さよりも長くなります。"
9 | plugin_reloaded: "&6構成ファイルを再読み込みしました"
10 | sign_no_longer_part_of_protection: "&4選択された看板は保護されたブロックに付属していません。"
11 | updated_sign: "&6看板を更新しました!"
12 | protection:
13 | add_more_users_sign_instead: "&4保護には[プライベート]サインが1つだけ存在できます。代わりに[追加ユーザー]サインを追加してください。"
14 | bypassed: "&6あなたは{0}の保護をバイパスしました。"
15 | can_only_add_protection_sign: "&4保護には、[プライベート]のサインが1つだけで、[追加ユーザー]のサインが0個以上ある場合があります。 他の標識は許可されていません。"
16 | cannot_change_sign: "&4他人の保護されたブロックの看板は編集できません。"
17 | chest_hint: "&6このチェストに看板を設置することで保護することができます!"
18 | claimed_container: "&6このブロックを保護しました。誰もこれにアクセスすることはできません。"
19 | claimed_manually: "&6保護を作成しました。看板に載っているプレイヤーのみがアクセスできます。"
20 | expired: "&6このブロックの保護は、所有者が非アクティブであるために期限切れになりました。"
21 | in_wilderness: "&4ここで保護を作成することはできません。あなたは非管理区域にいます。"
22 | is_claimed_by: "&6このブロックはすでに {0} によって保護されています。"
23 | no_access: "&4このブロックは {0} によって保護されているためアクセスできません。"
24 | no_permission_for_claim: "&4このブロックを保護する権限がありません。"
25 | not_nearby: "&4近くに保護できるブロックがありません。看板を持ってしゃがみながらそのブロックに向けて右クリックしてください。"
26 | selected_sign: "&6看板を選択しました。\"/blocklocker <行番号> <名前>\"を実行することで編集できます。もしくは&n[レッドストーン]&r&6 &n[全員]&r&6を追加してください。"
27 | tag:
28 | everyone: "全員"
29 | timer: "タイマー"
30 | redstone: "レッドストーン"
31 | private: "[プライベート]"
32 | more_users: "[追加ユーザー]"
33 | updater:
34 | more_information: "&6追加の情報: {0}"
35 | unsupported_server: "&4最新のバージョンは${project.name} (バージョン {0}) です。このマインクラフトのバージョンはサポートされていません。マインクラフト {1} を使用してください"
36 | update_available: "&6新しいバージョン ${project.name} (バージョン {0}) があります。手動でダウンロードしてください。"
37 | updated_automatically: "&6新しいバージョン ${project.name}(バージョン {0}) があります。再起動時に自動的にダウンロードされます"
38 |
--------------------------------------------------------------------------------
/src/main/resources/translations-kr.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: "이 명령은 콘솔에서 사용할 수 없습니다. 죄송해요!"
3 | cannot_edit_owner: "&4이 보호의 권한 소유자를 변경할 수 없습니다. 대신 표지판을 제거하십시오."
4 | line_number_out_of_bounds: "&42 이상, 4 이하의 줄 번호를 입력하십시오."
5 | no_sign_selected: "&4우선 마우스 오른쪽 버튼을 클릭하여, 보호받는 블럭의 표지판을 선택해야 합니다."
6 | no_permission: "&4당신은 이 명령을 실행할 수 있는 권한이 없습니다. 죄송해요!"
7 | player_name_too_long: "&4플레이어의 이름이 16자를 넘어 표지판에 적을 수 없습니다. 뿐만 아니라 Mojang이 허용하고 있는 플레이어 이름의 길이보다 깁니다."
8 | plugin_reloaded: "&6구성 파일을 다시 로드했습니다!"
9 | sign_no_longer_part_of_protection: "&4선택한 표지판이 더 이상 보호받는 블럭에 있지 않습니다."
10 | updated_sign: "&6표지판을 업데이트했습니다!"
11 | protection:
12 | add_more_users_sign_instead: "&4한 보호 설정에는 하나의 [Private] 표지판만 설치 가능합니다. 대신 [More Users] 표지판을 추가하세요."
13 | bypassed: "&6방금 {0}의 보호를 무시하였습니다."
14 | can_only_add_protection_sign: "&4한 보호 설정에는 하나의 [Private] 표지판과 0개 또는 그 이상의 [More Users] 표지판만 설치 가능합니다. 다른 표지판은 허용되지 않습니다."
15 | cannot_change_sign: "&4보호 설정된 보관함의 표지판을 변경할 수 없습니다."
16 | chest_hint: "&6상자에 표지판을 설치해 보호하세요."
17 | claimed_container: "&6보관함을 보호 설정했습니다. 다른 누구도 이 보관함을 사용할 수 없습니다."
18 | claimed_manually: "&6보호 설정되었습니다. 표지판에 적힌 플레이어만 이 블럭을 사용할 수 있습니다."
19 | expired: "&6소유자가 비활성함에 따라 이 블록에 대한 보호는 만료되었습니다."
20 | in_wilderness: "&4여기에서 보호 설정을 할 수 없습니다: 당신은 황야에 있습니다."
21 | is_claimed_by: "&6이 블록은 {0}의 소유입니다."
22 | no_access: "&4이 블록은 {0}에게 소유되어있어서 당신이 사용할 수 없습니다."
23 | no_permission_for_claim: "&4당신은 보관함을 보호 설정할 권한이 없습니다. 죄송합니다."
24 | not_nearby: "&4가까이에 보호할 수 있는 블럭이 없습니다. 표지판을 손에 들고 웅크린 상태에서 보관함에 마우스 오른쪽 버튼을 클릭하여 보호 설정합니다."
25 | selected_sign: "&6표지판을 선택했습니다. 이 표지판을 수정하려면 채팅창에 \"/blocklocker <줄 번호> <닉네임>\"을 입력합니다. 또는 이들을 추가합니다: &n[Redstone]&r&6 &n[Everyone]&r&6.}"
26 | tag:
27 | everyone: "Everyone"
28 | timer: "Timer"
29 | redstone: "Redstone"
30 | private: "[Private]"
31 | more_users: "[More Users]"
32 | updater:
33 | more_information: "&6추가 정보: {0}"
34 | unsupported_server: "&4${project.name} (version {0})의 최신 버전이 이 Minecraft 버전을 지원하지 않습니다. (Minecraft {1}만)."
35 | update_available: "&6${project.name} (version {0})에 대한 업데이트를 수동으로 다운로드할 수 있습니다."
36 | updated_automatically: "&6${project.name}에 대한 업데이트가 가능합니다(version {0}). 서버를 다시 시작하면 자동으로 설치됩니다."
--------------------------------------------------------------------------------
/src/main/resources/translations-nl.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the Dutch language
2 | command:
3 | cannot_be_used_by_console: 'Dit commando kan niet door de console gebruikt worden. Sorry!'
4 | cannot_edit_owner: '&4Je kunt niet aanpassen wie de eigenaar is van de bescherming. Je kunt wel de bescherming slopen.'
5 | line_number_out_of_bounds: '&4Gebruik alsjeblieft een regelnummer van 2 t/m 4.'
6 | no_permission: '&4Je hebt geen toestemming om dit commando te gebruiken. Sorry!'
7 | no_sign_selected: '&4Selecteer eerst een bordje door te rechtklikken.'
8 | player_name_too_long: '&4De spelernaam is langer dan 16 tekens. Dit gaat niet passen. Mojang staat ook niet toe dat spelernamen langer dan 16 tekens zijn.'
9 | plugin_reloaded: '&6Configuratiebestanden zijn opnieuw geladen!'
10 | sign_no_longer_part_of_protection: '&4Het eerder geselecteerde bordje hoort niet langer bij een bescherming.'
11 | updated_sign: '&6Bordje is bijgewerkt!'
12 | protection:
13 | add_more_users_sign_instead: '&4Je mag maar één bordje met [Op slot] ophangen per bescherming. Gebruik in plaats daarvan bordjes met [More Users]..'
14 | bypassed: '&6Je hebt ingebroken bij een bescherming van {0}.'
15 | cannot_change_sign: '&4Je kunt geen bordje aanpassen aan een beschermd blok.'
16 | chest_hint: '&6Plaats een bordje tegen deze kist om de kist te beschermen.'
17 | claimed_container: '&6Deze container is nu beschermd. Alleen jij kan er nog bij.'
18 | claimed_manually: '&6Je hebt een beschermingsbordje opgehangen. Alleen spelers die staan op het bordje kunnen er nog bij.'
19 | expired: '&6The protection of this block has expired due to inactivity of the owner.'
20 | in_wilderness: '&4You cannot create a protection here: you are in the wilderness.'
21 | is_claimed_by: '&6Dit blok is beschermd door {0}.'
22 | no_access: '&4Dit blok is beschermd door {0}, je kunt er niet bij.'
23 | no_permission_for_claim: '&4Je hebt geen toestemming om beschermingsbordjes op te hangen, sorry.'
24 | not_nearby: '&4Er is hier geen blok dat beschermd kan worden. (Shift-)rechtsklik een containerblok met een bordje in je hand om het te beschermen.'
25 | tag:
26 | everyone: Everyone
27 | more_users:
28 | - '[Meer Spelers]'
29 | - '[More Users]'
30 | private:
31 | - '[Op slot]'
32 | - '[Private]'
33 | redstone: Redstone
34 | timer: Timer
35 | updater:
36 | more_information: '&6Meer informatie: {0}'
37 | unsupported_server: '&4De nieuwste versie van BlockLocker (versie {0}) ondersteunt niet langer deze Minecraftversie, maar slechts nog Minecraft {1}.'
38 | update_available: '&6Een bijgewerkte versie van BlockLocker (versie {0}) is kan handmatig gedownload worden.'
39 |
--------------------------------------------------------------------------------
/src/main/resources/translations-pl.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: Ta komenda nie może być użyta przez konsolę. Przepraszam!
3 | cannot_edit_owner: '&4Nie możesz zmienić właściciela tego zabezpieczenia. Zniszcz tabliczkę.'
4 | line_number_out_of_bounds: '&4Proszę wpisać numer wiersza z przedziału od 2 do 4 włącznie.'
5 | no_permission: '&4Nie masz uprawnień do wykonania tej komendy. Przepraszam!'
6 | no_sign_selected: '&4Musisz najpierw wybrać tabliczke na jednym z chronionych bloków klikając go prawym przyciskiem myszy.'
7 | player_name_too_long: '&4Nazwa gracza ma ponad 16 znaków, co nie mieści się na znaku. Jest też dłuższa niż zezwala na to Mojang.'
8 | plugin_reloaded: '&6Załadowano ponownie pliki konfiguracyjne!'
9 | sign_no_longer_part_of_protection: '&4Wybrana tabliczka nie należy już do chronionego bloku.'
10 | updated_sign: '&6Zaktualizowano tabliczkę!'
11 | protection:
12 | add_more_users_sign_instead: '&4Na danym zabezpieczeniu może być tylko jedna tabliczka [Prywatne]. Zamiast tego dodaj tabliczkę [Wiecej graczy].'
13 | bypassed: '&6Właśnie ominąłeś ochronę {0}.'
14 | cannot_change_sign: '&4Nie można zmienić tabliczki w pobliżu zajętego obiektu.'
15 | chest_hint: '&6Postaw tabliczkę na tej skrzyni, aby ją chronić.'
16 | claimed_container: '&6Zabezpieczono ten obiekt. Nikt inny nie ma do niego dostępu.'
17 | claimed_manually: '&6Stworzono zabezpieczenie. Dostęp do niego mają tylko osoby wymienione na tabliczce.'
18 | expired: '&6Ochrona tego bloku wygasła z powodu braku aktywności właściciela.'
19 | in_wilderness: '&4Nie możesz tu stworzyć ochrony: jesteś na pustkowiu.'
20 | is_claimed_by: '&6Ten blok został zajęty przez {0}.'
21 | no_access: '&4Nie możesz użyć tego bloku, jest on chroniony przez {0}.'
22 | no_permission_for_claim: '&4Nie masz uprawnień do zajęcia tego obiektu, przykro mi.'
23 | not_nearby: '&4W pobliżu nie ma bloku, który można ochronić. (Shift-)kliknij prawym przyciskiem myszy na obiekt z tabliczką w dłoni, aby go ochronić.'
24 | selected_sign: '&6Wybrano tabliczkę. Wpisz "/blocklocker ", aby edytować tą tabliczkę. Ewentualnie dodaj poniższe: &n[Redstone]&r&6 &n[Wszyscy]&r&6.}'
25 | tag:
26 | everyone: Wszyscy
27 | more_users: '[Wiecej graczy]'
28 | private: '[Prywatne]'
29 | redstone: Redstone
30 | timer: Licznik
31 | updater:
32 | more_information: '&6Więcej informacji: {0}'
33 | unsupported_server: '&4Najnowsza wersja BlockLockera (wersja {0}) już nie obsługuje tej wersji Minecrafta, tylko Minecrafta {1}.'
34 | update_available: '&6Aktualizacja dla pluginu BlockLocker (wersja {0}) jest dostępna do ręcznego pobrania.'
--------------------------------------------------------------------------------
/src/main/resources/translations-tr.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: "Bu komut konsol tarafından kullanılamaz. Üzgünüm!"
3 | cannot_edit_owner: "&4Korumanın sahibini değiştiremezsiniz. Bunun yerine tabelayı kırın."
4 | line_number_out_of_bounds: "&4Lütfen 2 ile 4 arasında bir satır numarası girin, dahil."
5 | no_sign_selected: "&4Önce korunan bloklardan birindeki tabelaya sağ tıklayarak seçmelisiniz."
6 | no_permission: "&4Bu komutu çalıştırmak için izniniz yok. Üzgünüm!"
7 | player_name_too_long: "&4Oyuncu adı 16 karakterden fazla, bu da tabelaya sığmıyor. Ayrıca, Mojang'ın izin verdiği oyuncu adlarından daha uzun."
8 | plugin_reloaded: "&6Yapılandırma dosyaları yeniden yüklendi!"
9 | sign_no_longer_part_of_protection: "&4Seçilen tabela artık korunan bir bloğa ait değil."
10 | updated_sign: "&6Tabela güncellendi!"
11 | protection:
12 | add_more_users_sign_instead: "&4Bir korumada yalnızca bir [Özel] tabelası olabilir. Bunun yerine bir [Ekstra Kullanıcı] tabelası ekleyin."
13 | bypassed: "&6{0} adlı korumayı atlattınız."
14 | can_only_add_protection_sign: "&4Bir korumada yalnızca bir [Özel] ve sıfır veya daha fazla [Ekstra Kullanıcı] tabelası olabilir. Diğer tabelalara izin verilmez."
15 | cannot_change_sign: "&4Bir talep edilen konteynerın yakınındaki tabelayı değiştiremezsiniz."
16 | chest_hint: "&6Bu sandığın üzerine tabela koyarak koruyun."
17 | claimed_container: "&6Bu konteynerı talep ettiniz. Başka kimse erişemez."
18 | claimed_manually: "&6Bir talep oluşturuldu. Sadece tabelada listelenen kişiler erişebilir."
19 | expired: "&6Bu bloğun koruması sahibin etkin olmaması nedeniyle süresi doldu."
20 | in_wilderness: "&4Burada bir koruma oluşturamazsınız: vahşi alandasınız."
21 | is_claimed_by: "&6Bu blok {0} tarafından talep edildi."
22 | no_access: "&4Bu bloğu kullanamazsınız, {0} tarafından korunuyor."
23 | no_permission_for_claim: "&4Bir konteynerı talep etme izniniz yok, üzgünüm."
24 | not_nearby: "&4Yakınında korunabilir bir blok yok. Bir tabela taşıyarak bir konteynera (Shift-)sağ tıklayın."
25 | tag:
26 | everyone: "Herkes"
27 | timer: "Zamanlayıcı"
28 | redstone: "Kızıltaş"
29 | private: "[Özel]"
30 | more_users: "[Ekstra Kullanıcı]"
31 | updater:
32 | more_information: "&6Daha fazla bilgi: {0}"
33 | unsupported_server: "&4${project.name} 'ın en son sürümü ({0} sürümü) artık bu Minecraft sürümünü desteklemiyor, sadece Minecraft {1}."
34 | update_available: "&6${project.name} için bir güncelleme (sürüm {0}) manuel indirme için mevcut."
35 | updated_automatically: "&6${project.name} için bir güncelleme mevcut (sürüm {0}). Sunucuyu yeniden başlattığınızda otomatik olarak yüklenecek."
36 |
--------------------------------------------------------------------------------
/src/main/resources/translations-vi.yml:
--------------------------------------------------------------------------------
1 | command:
2 | cannot_be_used_by_console: Xin lỗi!, câu lệnh này không thể sử dụng trong bảng điều khiển.
3 | cannot_edit_owner: '&4Bạn không thể thay đổi chủ sở hữu của khối được bảo vệ. Thay vào đó hãy phá hủy cái báng'
4 | line_number_out_of_bounds: '&4Xin hãy nhập số dòng giữa 2 và 4.'
5 | no_permission: '&4Xin lỗi, nhưng bạn không có quyền để thực hiên câu lệnh này.'
6 | no_sign_selected: '&4Bạn phải chọn một cái bảng trên một khối mà bạn đã bảo vệ trước bằng cách đúp chuột phải vào nó.'
7 | player_name_too_long: '&4Tên người chơi dài hơn 16 ký tự, nó không đủ chỗ ở trên bảng. Tên này cũng dài hơn giới hạn cho phép của Mojang đối với tên người chơi.'
8 | plugin_reloaded: '&6Đã tải lại tệp cài đặt'
9 | sign_no_longer_part_of_protection: '&4Bảng đã chọn không còn thuộc về khối được bảo vệ nữa.'
10 | updated_sign: '&6Đã cập nhật bảng.'
11 | protection:
12 | add_more_users_sign_instead: '&4Chỉ có thể có một bảng [Riêng tư]. Thêm bảng [Thêm Người Chơi] để thêm nhiều người hơn.'
13 | bypassed: '&6Bạn đã bỏ qua các hạn chế truy cập của {0}.'
14 | cannot_change_sign: '&4Bạn không thể thay đổi một cái bảng gần một thùng chứa đồ đã có chủ sở hữu.'
15 | chest_hint: '&6Đặt một cái bảng trên cái rương này để bảo vệ nó.'
16 | claimed_container: '&6Thùng chứa đồ này đã được bảo vệ. Không ai có thể mở được nó.'
17 | claimed_manually: '&6Thúng chứa đồ đã được bảo vệ. Chỉ có những người được liệt kê mới mở được nó.'
18 | expired: '&6Sự bảo vệ của khối này đã hết hạn vì chủ sỡ hữu của nó đã không hoạt động trong một thời gian dài.'
19 | in_wilderness: '&4Bạn không thể bảo vệ khối này: bạn đang ở vùng hoang dã.'
20 | is_claimed_by: '&6Khối này đã được sở hữu bởi {0}.'
21 | no_access: '&4Bạn không thể sử dụng khối này, nó đang được bảo vệ bởi {0}.'
22 | no_permission_for_claim: '&4Xin lỗi, bạn không có quyền sở hữu thùng chứa dồ.'
23 | not_nearby: '&4Không có khối nào ở gần có thể được bảo vệ. (Shift-)chuột phải vào một thùng chứa đồ với một cái bảng ở trên tay để bảo vệ nó.'
24 | tag:
25 | everyone: Mọi người
26 | more_users: '[Thêm Người Chơi]'
27 | private: '[Riêng Tư]'
28 | redstone: Đá đỏ
29 | timer: Thời gian
30 | updater:
31 | more_information: '&6Thông tin thêm: {0}'
32 | unsupported_server: '&4Phiên bản mới nhất của BlockLocker (version {0}) Không còn hỗ trợ phiên bản Minecraft này nữa, chỉ hỗ trợ Minecraft phiên bản {1}.'
33 | update_available: '&6Một phiên của BlockLocker (version {0}) đã có sẵn để tải thủ công.'
34 |
--------------------------------------------------------------------------------
/src/main/resources/translations-zh-hk.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the Hong Kong Traditional Chinese language. Translations by flandretw.
2 | command:
3 | cannot_be_used_by_console: '抱歉!此指令無法在控制台使用。'
4 | cannot_edit_owner: '&4你不能變更保護的擁有者。而是只能破壞掉這個告示牌。'
5 | line_number_out_of_bounds: '&4請輸入 2~4 之間的行數(包括 2 和 4)。'
6 | no_permission: '&4抱歉!你沒有執行此指令的權限。'
7 | no_sign_selected: '&4必須先對受保護方塊的告示牌點擊右鍵選擇。'
8 | player_name_too_long: '&4玩家名稱超過 16 個字元,告示牌無法容納。它也比 Mojang 允許的玩家名稱還要長。'
9 | plugin_reloaded: '&6已重新載入設定檔!'
10 | sign_no_longer_part_of_protection: '&4選擇的告示牌不再屬於被保護的方塊。'
11 | updated_sign: '&6已更新告示牌!'
12 | protection:
13 | add_more_users_sign_instead: '&4只能有一個 [私人] 告示牌。新增 [更多] 告示牌來新增更多玩家。'
14 | bypassed: '&6你剛剛繞過了 {0} 的保護。'
15 | cannot_change_sign: '&4你不能編輯已認領容器的告示牌。'
16 | chest_hint: '&6手持告示牌,並對儲物箱點擊右鍵來認領它。'
17 | claimed_container: '&6已成功認領此容器。其他人將無法使用。'
18 | claimed_manually: '&6已成功認領。只有清單上的人才能存取。'
19 | expired: '&6由於此方塊的擁有者不活躍,保護已失效。'
20 | in_wilderness: '&4你不能在這裏建立保護。'
21 | is_claimed_by: '&6這個方塊屬於 {0}。'
22 | no_access: '&4你不能使用這個方塊,它屬於 {0}。'
23 | no_permission_for_claim: '&4抱歉。你沒有認領容器的權限。'
24 | not_nearby: '&4附近沒有可被保護的方塊。手持告示牌按住 Shift 鍵,並對容器點擊右鍵來保護它。'
25 | tag:
26 | everyone:
27 | - '所有人'
28 | - 'Everyone'
29 | timer:
30 | - '計時'
31 | - 'Timer'
32 | redstone:
33 | - '紅石'
34 | - 'Redstone'
35 | private:
36 | - '[私人]'
37 | - '[Private]'
38 | more_users:
39 | - '[更多]'
40 | - '[More Users]'
41 | updater:
42 | more_information: '&6更多資訊:{0}'
43 | unsupported_server: '&4最新版本的 BlockLocker(版本 {0})不再支援此 Minecraft 版本,需要使用 Minecraft {1}。'
44 | update_available: '&6新版本的 BlockLocker(版本 {0})已可用,需要手動下載。'
45 |
--------------------------------------------------------------------------------
/src/main/resources/translations-zh-tw.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the Taiwan Traditional Chinese language. Translations by flandretw.
2 | command:
3 | cannot_be_used_by_console: '抱歉!此指令無法在控制台使用。'
4 | cannot_edit_owner: '&4你不能變更保護的擁有者。而是只能破壞掉這個告示牌。'
5 | line_number_out_of_bounds: '&4請輸入 2~4 之間的行數(包括 2 和 4)。'
6 | no_permission: '&4抱歉!你沒有執行此指令的權限。'
7 | no_sign_selected: '&4必須先對受保護方塊的告示牌點擊右鍵選擇。'
8 | player_name_too_long: '&4玩家名稱超過 16 個字元,告示牌無法容納。它也比 Mojang 允許的玩家名稱還要長。'
9 | plugin_reloaded: '&6已重新載入設定檔!'
10 | sign_no_longer_part_of_protection: '&4選擇的告示牌不再屬於被保護的方塊。'
11 | updated_sign: '&6已更新告示牌!'
12 | protection:
13 | add_more_users_sign_instead: '&4只能有一個 [私人] 告示牌。新增 [更多] 告示牌來新增更多玩家。'
14 | bypassed: '&6你剛剛繞過了 {0} 的保護。'
15 | cannot_change_sign: '&4你不能編輯已認領容器的告示牌。'
16 | chest_hint: '&6手持告示牌,並對儲物箱點擊右鍵來認領它。'
17 | claimed_container: '&6已成功認領此容器。其他人將無法使用。'
18 | claimed_manually: '&6已成功認領。只有清單上的人才能存取。'
19 | expired: '&6由於此方塊的擁有者不活躍,保護已失效。'
20 | in_wilderness: '&4你不能在這裡建立保護。'
21 | is_claimed_by: '&6這個方塊屬於 {0}。'
22 | no_access: '&4你不能使用這個方塊,它屬於 {0}。'
23 | no_permission_for_claim: '&4抱歉。你沒有認領容器的權限。'
24 | not_nearby: '&4附近沒有可被保護的方塊。手持告示牌按住 Shift 鍵,並對容器點擊右鍵來保護它。'
25 | tag:
26 | everyone:
27 | - '所有人'
28 | - 'Everyone'
29 | timer:
30 | - '計時'
31 | - 'Timer'
32 | redstone:
33 | - '紅石'
34 | - 'Redstone'
35 | private:
36 | - '[私人]'
37 | - '[私有]'
38 | - '[Private]'
39 | more_users:
40 | - '[更多]'
41 | - '[More Users]'
42 | updater:
43 | more_information: '&6更多資訊:{0}'
44 | unsupported_server: '&4最新版本的 BlockLocker(版本 {0})不再支援此 Minecraft 版本,需要使用 Minecraft {1}。'
45 | update_available: '&6新版本的 BlockLocker(版本 {0})已可用,需要手動下載。'
46 |
--------------------------------------------------------------------------------
/src/main/resources/translations-zh.yml:
--------------------------------------------------------------------------------
1 | # Translation file for the Simplified Chinese language. Translations by Halogly.
2 | command:
3 | cannot_be_used_by_console: "该命令无法通过控制台输出."
4 | cannot_edit_owner: "&4你不能编辑使用者."
5 | line_number_out_of_bounds: "&4请输入2~4之间的行数(包括2和4)."
6 | no_sign_selected: "&4你需要右键来选择告示牌."
7 | no_permission: "&4你没有权限."
8 | player_name_too_long: "&4玩家名称过长."
9 | plugin_reloaded: "&6已重新加载配置文件!"
10 | sign_no_longer_part_of_protection: "&4选择的告示牌不再属于被保护的方块."
11 | updated_sign: "&6已更新告示牌!"
12 | protection:
13 | add_more_users_sign_instead: "&4只能有一个 [私有] 标签. 添加 [更多] 标签来添加更多人."
14 | bypassed: "&6你绕过了 {0} 的访问限制."
15 | can_only_add_protection_sign: "&4只能有一个 [私有] 标签和零或多个 [更多] 标签. 不允许其他标签."
16 | cannot_change_sign: "&4你不能编辑."
17 | chest_hint: "&6手持告示牌并右键箱子来锁定箱子."
18 | claimed_container: "&6已成功上锁. 其他人将无法使用."
19 | claimed_manually: "&6已成功上锁. 只有名单上的人才能访问."
20 | expired: "&6由于该方块的拥有者不活跃, 保护已失效."
21 | in_wilderness: "&4你不能在这里创建保护."
22 | is_claimed_by: "&6这个方块属于 {0}."
23 | no_access: "&4你不能使用这个方块, 它属于 {0}."
24 | no_permission_for_claim: "&4你没有权限."
25 | not_nearby: "&4附近没有可被保护的方块, 手持告示牌按住Shift并右键容器来保护它."
26 | tag:
27 | everyone:
28 | - "所有人"
29 | - "Everyone"
30 | timer:
31 | - "定时"
32 | - "Timer"
33 | redstone:
34 | - "红石"
35 | - "Redstone"
36 | private:
37 | - "[私有]"
38 | - "[Private]"
39 | more_users:
40 | - "[更多]"
41 | - "[More Users]"
42 | updater:
43 | more_information: "&6更多信息: {0}"
44 | unsupported_server: "&4最新版本的 ${project.name} (version {0}) 不再支持这个Minecraft版本, 需要Minecraft {1} 版本."
45 | update_available: "&6新版本 ${project.name} (version {0}) 已经可用, 需要手动下载."
46 | updated_automatically: "&6${project.name} 有可用更新 (version {0}), 重启服务器以自动更新."
--------------------------------------------------------------------------------
/src/test/java/nl/rutgerkok/blocklocker/TestPlayer.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker;
2 |
3 | import java.util.Locale;
4 | import java.util.UUID;
5 |
6 | import org.bukkit.entity.Player;
7 | import org.mockito.Mockito;
8 |
9 | import com.google.common.base.Charsets;
10 |
11 | public class TestPlayer {
12 |
13 | public static Player create() {
14 | return create("TestPlayer");
15 | }
16 |
17 | public static Player create(String name) {
18 | UUID uuid = UUID.nameUUIDFromBytes(name.toLowerCase(Locale.ROOT).getBytes(Charsets.UTF_8));
19 | return create(name, uuid);
20 | }
21 |
22 | public static Player create(String name, UUID uuid) {
23 | Player player = Mockito.mock(Player.class);
24 | Mockito.when(player.getName()).thenReturn(name);
25 | Mockito.when(player.getUniqueId()).thenReturn(uuid);
26 | return player;
27 | }
28 | }
--------------------------------------------------------------------------------
/src/test/java/nl/rutgerkok/blocklocker/group/CombinedGroupSystemTest.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.group;
2 |
3 | import static org.junit.jupiter.api.Assertions.assertEquals;
4 | import static org.junit.jupiter.api.Assertions.assertFalse;
5 | import static org.junit.jupiter.api.Assertions.assertTrue;
6 |
7 | import java.util.Arrays;
8 | import java.util.Collection;
9 |
10 | import org.bukkit.entity.Player;
11 | import org.junit.jupiter.api.Assertions;
12 | import org.junit.jupiter.api.Test;
13 |
14 | import nl.rutgerkok.blocklocker.TestPlayer;
15 |
16 | public class CombinedGroupSystemTest {
17 |
18 | private class ReturnsFalseGroupSystem extends GroupSystem {
19 |
20 | @Override
21 | public boolean isInGroup(Player player, String groupName) {
22 | return false;
23 | }
24 |
25 | @Override
26 | public boolean keepOnReload() {
27 | return false;
28 | }
29 |
30 | }
31 |
32 | private class ReturnsTrueGroupSystem extends GroupSystem {
33 |
34 | @Override
35 | public boolean isInGroup(Player player, String groupName) {
36 | return true;
37 | }
38 |
39 | @Override
40 | public boolean keepOnReload() {
41 | return true;
42 | }
43 |
44 | }
45 |
46 | @Test
47 | public void testAddNullSystem() {
48 | // Null systems are not allowed
49 | Assertions.assertThrows(NullPointerException.class, () -> {
50 | new CombinedGroupSystem().addSystem(null);
51 | });
52 | }
53 |
54 | @SuppressWarnings("deprecation")
55 | @Test
56 | public void testAddNullSystems() {
57 | Assertions.assertThrows(NullPointerException.class, () -> {
58 | // Collections containing null systems are not allowed
59 | Collection containingNull = Arrays.asList(
60 | new ReturnsFalseGroupSystem(),
61 | new ReturnsTrueGroupSystem(),
62 | null);
63 | new CombinedGroupSystem().addSystems(containingNull);
64 | });
65 | }
66 |
67 | @Test
68 | public void testCombined() {
69 | CombinedGroupSystem combinedGroupSystem = new CombinedGroupSystem();
70 | combinedGroupSystem.addSystem(new ReturnsFalseGroupSystem());
71 | combinedGroupSystem.addSystem(new ReturnsTrueGroupSystem());
72 |
73 | // Must return true, because ReturnsTrueGroupSystem returns true
74 | assertTrue(combinedGroupSystem.isInGroup(TestPlayer.create(), "GroupName"));
75 | }
76 |
77 | @Test
78 | public void testEmptyGroupSystem() {
79 | assertFalse(new CombinedGroupSystem().isInGroup(TestPlayer.create(), "GroupName"));
80 | }
81 |
82 | @Test
83 | public void testReloadSurvivors() {
84 | GroupSystem keptOnReload = new ReturnsTrueGroupSystem();
85 | GroupSystem removedOnReload = new ReturnsFalseGroupSystem();
86 |
87 | // Add two systems, one surviving the reload, one not
88 | CombinedGroupSystem combinedGroupSystem = new CombinedGroupSystem();
89 | combinedGroupSystem.addSystem(keptOnReload);
90 | combinedGroupSystem.addSystem(removedOnReload);
91 |
92 | Collection survivors = combinedGroupSystem.getReloadSurvivors();
93 |
94 | // Survivors must be collection of exactly one group, the keptOnReload
95 | // group
96 | assertEquals(1, survivors.size());
97 | assertEquals(keptOnReload, survivors.iterator().next());
98 | }
99 |
100 | @Test
101 | public void testSingleReturnsFalse() {
102 | CombinedGroupSystem combinedGroupSystem = new CombinedGroupSystem();
103 | combinedGroupSystem.addSystem(new ReturnsFalseGroupSystem());
104 |
105 | assertFalse(combinedGroupSystem.isInGroup(TestPlayer.create(), "GroupName"));
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/src/test/java/nl/rutgerkok/blocklocker/impl/profile/NullTranslator.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 | import nl.rutgerkok.blocklocker.Translator;
4 |
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | import org.bukkit.command.CommandSender;
9 |
10 | /**
11 | * Simply returns the key.
12 | *
13 | */
14 | public class NullTranslator extends Translator {
15 |
16 | @Override
17 | public String get(Translation key) {
18 | return key.toString();
19 | }
20 |
21 | @Override
22 | public String getWithoutColor(Translation key) {
23 | return key.toString();
24 | }
25 |
26 | @Override
27 | public void sendMessage(CommandSender player, Translation translation) {
28 | player.sendMessage(get(translation));
29 | }
30 |
31 | @Override
32 | public List getAll(Translation key) {
33 | return Arrays.asList(key.toString());
34 | }
35 |
36 | @Override
37 | public List getAllWithoutColor(Translation key) {
38 | return Arrays.asList(key.toString());
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/src/test/java/nl/rutgerkok/blocklocker/impl/profile/TestPlayerProfile.java:
--------------------------------------------------------------------------------
1 | package nl.rutgerkok.blocklocker.impl.profile;
2 |
3 |
4 | import static org.junit.jupiter.api.Assertions.assertEquals;
5 | import static org.junit.jupiter.api.Assertions.assertFalse;
6 | import static org.junit.jupiter.api.Assertions.assertTrue;
7 |
8 | import java.util.Optional;
9 | import java.util.UUID;
10 |
11 | import org.junit.jupiter.api.Test;
12 |
13 | import com.google.gson.JsonObject;
14 |
15 | import nl.rutgerkok.blocklocker.ProfileFactory;
16 | import nl.rutgerkok.blocklocker.Translator.Translation;
17 | import nl.rutgerkok.blocklocker.group.CombinedGroupSystem;
18 | import nl.rutgerkok.blocklocker.impl.JsonSecretSignEntry;
19 | import nl.rutgerkok.blocklocker.profile.PlayerProfile;
20 | import nl.rutgerkok.blocklocker.profile.Profile;
21 |
22 | public class TestPlayerProfile {
23 |
24 | private ProfileFactoryImpl getProfileFactory() {
25 | return new ProfileFactoryImpl(new CombinedGroupSystem(), new NullTranslator());
26 | }
27 |
28 | @Test
29 | public void testIncludes() {
30 | ProfileFactoryImpl factory = getProfileFactory();
31 | UUID bobId = UUID.randomUUID();
32 | String everyoneTag = "[" + new NullTranslator().getWithoutColor(Translation.TAG_EVERYONE) + "]";
33 |
34 | Profile bob = factory.fromNameAndUniqueId("Bob", Optional.of(bobId));
35 | Profile bobRenamed = factory.fromNameAndUniqueId("Bob2", Optional.of(bobId));
36 | Profile jane = factory.fromNameAndUniqueId("Jane", Optional.of(UUID.randomUUID()));
37 | Profile janeWithoutId = factory.fromDisplayText("jane");
38 | Profile everyone = factory.fromDisplayText(everyoneTag);
39 |
40 | assertTrue(bob.includes(bobRenamed), "Same id");
41 | assertTrue(bobRenamed.includes(bob), "Same id");
42 | assertFalse(jane.includes(janeWithoutId), "Known id, not present in other");
43 | assertTrue(janeWithoutId.includes(jane), "Unknown id, same name");
44 | assertFalse(bob.includes(jane), "Different id and name");
45 | assertFalse(bob.includes(janeWithoutId), "Different id and name");
46 |
47 | // Everyone includes everyone, but is never included
48 | assertTrue(everyone.includes(bob));
49 | assertTrue(everyone.includes(jane));
50 | assertTrue(everyone.includes(janeWithoutId));
51 | assertFalse(bob.includes(everyone));
52 | assertFalse(jane.includes(everyone));
53 | assertFalse(janeWithoutId.includes(everyone));
54 | }
55 |
56 | @Test
57 | public void testNameAndId() {
58 | String name = "test";
59 | UUID uuid = UUID.randomUUID();
60 | ProfileFactory factory = getProfileFactory();
61 | Profile profile = factory.fromNameAndUniqueId(name, Optional.of(uuid));
62 |
63 | // Test object properties
64 | assertEquals(name, profile.getDisplayName());
65 | assertEquals(uuid, ((PlayerProfile) profile).getUniqueId().get());
66 | }
67 |
68 | @Test
69 | public void testNameAndIdJson() {
70 | String name = "test";
71 | UUID uuid = UUID.randomUUID();
72 | ProfileFactory factory = getProfileFactory();
73 | Profile profile = factory.fromNameAndUniqueId(name, Optional.of(uuid));
74 | JsonSecretSignEntry object = new JsonSecretSignEntry(new JsonObject());
75 | profile.getSaveObject(object);
76 |
77 | assertEquals(name, object.getString(PlayerProfileImpl.NAME_KEY).get());
78 | assertEquals(uuid, object.getUniqueId(PlayerProfileImpl.UUID_KEY).get());
79 | }
80 |
81 | @Test
82 | public void testPlayerProfileRoundtrip() {
83 | String name = "test";
84 | UUID uuid = UUID.randomUUID();
85 | ProfileFactoryImpl factory = getProfileFactory();
86 | Profile profile = factory.fromNameAndUniqueId(name, Optional.of(uuid));
87 |
88 | testRoundtrip(factory, profile);
89 | }
90 |
91 | private void testRoundtrip(ProfileFactoryImpl factory, Profile profile) {
92 | JsonSecretSignEntry object = new JsonSecretSignEntry(new JsonObject());
93 | profile.getSaveObject(object);
94 | Profile newProfile = factory.fromSavedObject(object).get();
95 | assertEquals(profile, newProfile);
96 | }
97 |
98 | @Test
99 | public void testWithoutId() {
100 | String name = "test";
101 | ProfileFactoryImpl factory = getProfileFactory();
102 | Profile profile = factory.fromDisplayText(name);
103 |
104 | assertEquals(name, profile.getDisplayName());
105 | assertFalse(((PlayerProfile) profile).getUniqueId().isPresent());
106 | }
107 |
108 | @Test
109 | public void testWithoutIdJson() {
110 | String name = "test";
111 | ProfileFactoryImpl factory = getProfileFactory();
112 | Profile profile = factory.fromDisplayText(name);
113 | JsonSecretSignEntry object = new JsonSecretSignEntry(new JsonObject());
114 | profile.getSaveObject(object);
115 |
116 | assertEquals(name, object.getString(PlayerProfileImpl.NAME_KEY).get());
117 | assertFalse(object.getUniqueId(PlayerProfileImpl.UUID_KEY).isPresent());
118 | }
119 | }
120 |
--------------------------------------------------------------------------------