001/* 002 * PlotSquared, a land and world management plugin for Minecraft. 003 * Copyright (C) IntellectualSites <https://intellectualsites.com> 004 * Copyright (C) IntellectualSites team and contributors 005 * 006 * This program is free software: you can redistribute it and/or modify 007 * it under the terms of the GNU General Public License as published by 008 * the Free Software Foundation, either version 3 of the License, or 009 * (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 014 * GNU General Public License for more details. 015 * 016 * You should have received a copy of the GNU General Public License 017 * along with this program. If not, see <https://www.gnu.org/licenses/>. 018 */ 019package com.plotsquared.core.plot.flag; 020 021import com.google.common.base.Preconditions; 022import com.plotsquared.core.configuration.caption.Caption; 023import net.kyori.adventure.text.Component; 024import org.checkerframework.checker.nullness.qual.NonNull; 025 026import java.util.Collection; 027import java.util.Collections; 028 029/** 030 * A plot flag is any property that can be assigned 031 * to a plot, that will alter its functionality in some way. 032 * These are user assignable in-game, or via configuration files. 033 * 034 * @param <T> Value contained in the flag. 035 */ 036public abstract class PlotFlag<T, F extends PlotFlag<T, F>> { 037 038 private final T value; 039 private final Caption flagCategory; 040 private final Caption flagDescription; 041 private final String flagName; 042 043 /** 044 * Construct a new flag instance. 045 * 046 * @param value Flag value 047 * @param flagCategory The flag category 048 * @param flagDescription A caption describing the flag functionality 049 */ 050 protected PlotFlag( 051 final @NonNull T value, final @NonNull Caption flagCategory, 052 final @NonNull Caption flagDescription 053 ) { 054 this.value = Preconditions.checkNotNull(value, "flag value may not be null"); 055 this.flagCategory = 056 Preconditions.checkNotNull(flagCategory, "flag category may not be null"); 057 this.flagDescription = 058 Preconditions.checkNotNull(flagDescription, "flag description may not be null"); 059 // Parse flag name 060 // noinspection unchecked 061 this.flagName = getFlagName(this.getClass()); 062 } 063 064 /** 065 * Return the name of the flag. 066 * 067 * @param flagClass Flag class 068 * @param <T> Value type 069 * @param <F> Flag type 070 * @return The name of the flag implemented by the given class 071 */ 072 public static <T, F extends PlotFlag<T, F>> String getFlagName(Class<F> flagClass) { 073 final StringBuilder flagName = new StringBuilder(); 074 final char[] chars = flagClass.getSimpleName().replace("Flag", "").toCharArray(); 075 for (int i = 0; i < chars.length; i++) { 076 if (i == 0) { 077 flagName.append(Character.toLowerCase(chars[i])); 078 } else if (Character.isUpperCase(chars[i])) { 079 flagName.append('-').append(Character.toLowerCase(chars[i])); 080 } else { 081 flagName.append(chars[i]); 082 } 083 } 084 return flagName.toString(); 085 } 086 087 /** 088 * Gets the flag name as a Kyori {@link Component} 089 * 090 * @see #getFlagName(Class) 091 * @since 7.0.0 092 */ 093 public static <T, F extends PlotFlag<T, F>> Component getFlagNameComponent(Class<F> flagClass) { 094 return Component.text(getFlagName(flagClass)); 095 } 096 097 /** 098 * Get the flag value 099 * 100 * @return Non-nullable flag value 101 */ 102 public @NonNull 103 final T getValue() { 104 return this.value; 105 } 106 107 /** 108 * Parse a string into a flag, and throw an exception in the case that the 109 * string does not represent a valid flag value. This instance won't change its 110 * state, but instead an instance holding the parsed flag value will be returned. 111 * 112 * @param input String to parse. 113 * @return Parsed value, if valid. 114 * @throws FlagParseException If the value could not be parsed. 115 */ 116 public abstract F parse(final @NonNull String input) throws FlagParseException; 117 118 /** 119 * Merge this flag's value with another value and return an instance 120 * holding the merged value. 121 * 122 * @param newValue New flag value. 123 * @return Flag containing parsed flag value. 124 */ 125 public abstract F merge(final @NonNull T newValue); 126 127 /** 128 * Returns a string representation of the flag instance, that when 129 * passed through {@link #parse(String)} will result in an equivalent 130 * instance of the flag. 131 * 132 * @return String representation of the flag 133 */ 134 public abstract String toString(); 135 136 /** 137 * Get the flag name. 138 * 139 * @return Flag name 140 */ 141 public final String getName() { 142 return this.flagName; 143 } 144 145 /** 146 * Get a simple caption that describes the flag usage. 147 * 148 * @return Flag description. 149 */ 150 public Caption getFlagDescription() { 151 return this.flagDescription; 152 } 153 154 /** 155 * Get the category this flag belongs to. Usually a caption from {@link com.plotsquared.core.configuration.caption.TranslatableCaption} 156 * <p> 157 * These categories are used to categorize the flags when outputting 158 * flag lists to players. 159 * 160 * @return Flag category 161 */ 162 public Caption getFlagCategory() { 163 return this.flagCategory; 164 } 165 166 /** 167 * Get if the flag's permission should check for values. E.g. plots.flag.set.music.VALUE 168 * 169 * @return if valued permission 170 * @since 6.0.10 171 */ 172 public boolean isValuedPermission() { 173 return true; 174 } 175 176 /** 177 * An example of a string that would parse into a valid 178 * flag value. 179 * 180 * @return An example flag value. 181 */ 182 public abstract String getExample(); 183 184 protected abstract F flagOf(@NonNull T value); 185 186 /** 187 * Create a new instance of the flag using a provided 188 * (non-null) value. 189 * 190 * @param value The flag value 191 * @return The created flag instance 192 */ 193 public final F createFlagInstance(final @NonNull T value) { 194 return flagOf(Preconditions.checkNotNull(value)); 195 } 196 197 /** 198 * Get the tab completable values associated with the flag type, or 199 * an empty collection if tab completion isn't supported. 200 * 201 * @return Collection containing tab completable flag values 202 */ 203 public Collection<String> getTabCompletions() { 204 return Collections.emptyList(); 205 } 206 207 @Override 208 public boolean equals(final Object o) { 209 if (this == o) { 210 return true; 211 } 212 if (o == null || getClass() != o.getClass()) { 213 return false; 214 } 215 final PlotFlag<?, ?> plotFlag = (PlotFlag<?, ?>) o; 216 return value.equals(plotFlag.value); 217 } 218 219 @Override 220 public int hashCode() { 221 return value.hashCode(); 222 } 223 224}