/* * This file is part of NucleusFramework for Bukkit, licensed under the MIT License (MIT). * * Copyright (c) JCThePants (www.jcwhatever.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ package com.jcwhatever.nucleus.managed.signs; import com.jcwhatever.nucleus.Nucleus; import com.jcwhatever.nucleus.mixins.INamedInsensitive; import com.jcwhatever.nucleus.mixins.IPluginOwned; import com.jcwhatever.nucleus.storage.DataPath; import com.jcwhatever.nucleus.providers.storage.DataStorage; import com.jcwhatever.nucleus.storage.IDataNode; import com.jcwhatever.nucleus.utils.PreCon; import com.jcwhatever.nucleus.utils.SignUtils; import com.jcwhatever.nucleus.utils.text.TextUtils; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import java.util.regex.Matcher; /** * Abstract sign handler for signs of a specific type. * * @see ISignManager * @see Nucleus#getSignManager * @see SignUtils#registerHandler(SignHandler) * @see SignUtils#unregisterHandler(SignHandler) */ public abstract class SignHandler implements INamedInsensitive, IPluginOwned { private final Plugin _plugin; private final String _name; private final String _searchName; private String _displayName; private SignHandlerRegistration _registration; private IDataNode _dataNode; /** * Specify the result of handling a sign change event. */ public enum SignChangeResult { /** * The sign is valid. */ VALID, /** * The sign is not valid. */ INVALID } /** * Specify the result of handling a sign click event. */ public enum SignClickResult { /** * The event was handled. */ HANDLED, /** * The event was ignored. */ IGNORED } /** * Specify the result of handling a sign break event. */ public enum SignBreakResult { /** * Allow the sign to be broken. */ ALLOW, /** * Prevent the sign from being broken. */ DENY } /** * Constructor. * * @param plugin The owning plugin. * @param name The name of the sign (Used in the sign header). Must be a valid name. * Starts with a letter, alphanumerics only. Underscores allowed. */ public SignHandler(Plugin plugin, CharSequence name) { PreCon.notNull(plugin); PreCon.validNodeName(name); _plugin = plugin; _name = name.toString(); _searchName = _name.toLowerCase(); } @Override public final Plugin getPlugin() { return _plugin; } @Override public final String getName() { return _name; } @Override public final String getSearchName() { return _searchName; } /** * Get a display name for the sign. * * <p>Returns the sign handler name with underscores converted to spaces.</p> */ public final String getDisplayName() { if (_displayName == null) { Matcher headerMatcher = TextUtils.PATTERN_UNDERSCORE.matcher(getName()); _displayName = headerMatcher.replaceAll(" "); } return _displayName; } /** * Get a prefix to append to the header of a sign. */ public abstract String getHeaderPrefix(); /** * Get a description of the sign handler. */ public abstract String getDescription(); /** * Get a string array describing sign usage. * * <p>Each element of the array represents a line on the sign. There must be exactly 4 elements * in the array.</p> */ public abstract String[] getUsage(); /** * Invoked by the internal {@link ISignManager} implementation when the handler is registered. * * @param registration The internal managers registration object. */ public final void onRegister(SignHandlerRegistration registration) { PreCon.notNull(registration); PreCon.isValid(_registration == null, "Already registered."); _registration = registration; } /** * Invoked when a sign handled by the sign handler is loaded from the * {@link ISignManager} data node. * * @param sign The loaded sign encapsulated. */ protected abstract void onSignLoad(ISignContainer sign); /** * Invoked when a sign handled by the sign handler is changed/created. * * @param player The {@link Player} who changed/created the sign. * @param sign The encapsulated {@link org.bukkit.block.Sign}. * * @return {@link SignChangeResult#VALID} if the change is valid/allowed, * otherwise {@link SignChangeResult#INVALID}. */ protected abstract SignChangeResult onSignChange(Player player, ISignContainer sign); /** * Invoked when a sign handled by the sign handler is clicked on by a * {@link Player}. * * @param player The {@link Player} who clicked the sign. * @param sign The encapsulated {@link org.bukkit.block.Sign}. * * @return {@link SignClickResult#HANDLED} if the click was valid and handled, * otherwise {@link SignClickResult#IGNORED}. */ protected abstract SignClickResult onSignClick(Player player, ISignContainer sign); /** * Invoked when a sign handled by the sign handler is broken by a {@link Player}. * * <p>Sign break is only invoked when the player is capable of breaking a sign instantly. * (i.e creative mode) The sign cannot be broken unless the player is capable of * instant break.</p> * * @param player The {@link Player} who is breaking the sign. * @param sign The encapsulated {@link org.bukkit.block.Sign}. * * @return {@link SignBreakResult#ALLOW} if the break is allowed, otherwise * {@link SignBreakResult#DENY}. */ protected abstract SignBreakResult onSignBreak(Player player, ISignContainer sign); /** * Used internally to access protected methods. */ public static class SignHandlerRegistration { public void signLoad(SignHandler handler, ISignContainer sign) { PreCon.notNull(handler); PreCon.isValid(handler._registration == this, "Invalid registration."); handler.onSignLoad(sign); } public SignChangeResult signChange(SignHandler handler, Player player, ISignContainer sign) { PreCon.notNull(handler); PreCon.isValid(handler._registration == this, "Invalid registration."); return handler.onSignChange(player, sign); } public SignClickResult signClick(SignHandler handler, Player player, ISignContainer sign) { PreCon.notNull(handler); PreCon.isValid(handler._registration == this, "Invalid registration."); return handler.onSignClick(player, sign); } public SignBreakResult signBreak(SignHandler handler, Player player, ISignContainer sign) { PreCon.notNull(handler); PreCon.isValid(handler._registration == this, "Invalid registration."); return handler.onSignBreak(player, sign); } public IDataNode getDataNode(SignHandler handler) { PreCon.notNull(handler); PreCon.isValid(handler._registration == this, "Invalid registration."); if (handler._dataNode == null) { handler._dataNode = DataStorage.get(handler.getPlugin(), new DataPath("nucleus.signs")); handler._dataNode.load(); } return handler._dataNode; } } }